From 86679ebddb861d31713c2ecc7e9a17d1fbf4abf9 Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 2 Dec 2024 11:11:48 -0500 Subject: [PATCH 01/26] typo in englightenment for stealth when mounted reported as internal#K4306: typo in englightenment for stealth when mounted --- src/insight.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/insight.c b/src/insight.c index c1e17e954..96ce1e0b8 100644 --- a/src/insight.c +++ b/src/insight.c @@ -1637,7 +1637,7 @@ attributes_enlightenment( if (Stealth) { you_are("stealthy", from_what(STEALTH)); } else if (BStealth && (HStealth || EStealth)) { - Sprintf(buf, " steathy%s", + Sprintf(buf, " stealthy%s", (BStealth == FROMOUTSIDE) ? " if not mounted" : ""); enl_msg(You_, "would be", "would have been", buf, ""); } From 13012340393b6f57772b3838cb720d3fdd7425c1 Mon Sep 17 00:00:00 2001 From: PatR Date: Mon, 2 Dec 2024 11:37:04 -0800 Subject: [PATCH 02/26] mimic feedback tuning When a mimic in door form is hit by a wand of locking or wand of opening or corresponding spell, bring it out of concealment like was recently done for being zapped while in chest form. And give some feedback rather than just changing the mimic's form to 'm'. Give more detailed feedback when bumping into a mimic while moving. --- include/extern.h | 1 + src/uhitm.c | 50 +++++++++++++++++++++++++++++------------------- src/zap.c | 26 +++++++++++++++---------- 3 files changed, 47 insertions(+), 30 deletions(-) diff --git a/include/extern.h b/include/extern.h index c3f64a34b..7de27aee2 100644 --- a/include/extern.h +++ b/include/extern.h @@ -3350,6 +3350,7 @@ extern boolean mhitm_knockback(struct monst *, struct monst *,struct attack *, extern int passive(struct monst *, struct obj *, boolean, boolean, uchar, boolean) NONNULLARG1; extern void passive_obj(struct monst *, struct obj *, struct attack *) NONNULLARG1; +extern void that_is_a_mimic(struct monst *, boolean) NONNULLARG1; extern void stumble_onto_mimic(struct monst *) NONNULLARG1; extern int flash_hits_mon(struct monst *, struct obj *) NONNULLARG12; extern void light_hits_gremlin(struct monst *, int) NONNULLARG1; diff --git a/src/uhitm.c b/src/uhitm.c index 6cc8af687..2d1715bf6 100644 --- a/src/uhitm.c +++ b/src/uhitm.c @@ -6032,20 +6032,17 @@ passive_obj( DISABLE_WARNING_FORMAT_NONLITERAL -/* Note: caller must ascertain mtmp is mimicking... */ +/* used by stuble_onto_mimic() and bhitm() cases WAN_LOCKING, WAN_OPENING */ void -stumble_onto_mimic(struct monst *mtmp) +that_is_a_mimic( + struct monst *mtmp, /* a hidden mimic (nonnull) */ + boolean reveal_it) /* True: remove its disguise */ { static char generic[] = "a monster"; - char fmt[QBUFSZ]; + char fmtbuf[BUFSZ]; const char *what = NULL; - Strcpy(fmt, "Wait! That's %s!"); - if (!u.ustuck && !mtmp->mflee && dmgtype(mtmp->data, AD_STCK) - /* must be adjacent; attack via polearm could be from farther away */ - && m_next2u(mtmp)) - set_ustuck(mtmp); - + Strcpy(fmtbuf, "Wait! That's %s!"); if (Blind) { if (!Blind_telepat) what = generic; /* with default fmt */ @@ -6055,11 +6052,9 @@ stumble_onto_mimic(struct monst *mtmp) int glyph = levl[u.ux + u.dx][u.uy + u.dy].glyph; if (glyph_is_cmap(glyph)) { - Sprintf(fmt, "%s %s actually is %%s!", - is_cmap_stairs(glyph) ? "Those" : "That", - defsyms[mtmp->mappearance].explanation); - /* BUG: this will misclassify a paralyzed mimic as sleeping */ - what = x_monnam(mtmp, ARTICLE_A, "sleeping", 0, FALSE); + /* note: defsyms[stairs] yields singular "staircase {up|down}" */ + Snprintf(fmtbuf, sizeof fmtbuf, "That %s actually is %%s!", + defsyms[mtmp->mappearance].explanation); } else if (glyph_is_object(glyph)) { boolean fakeobj; const char *otmp_name; @@ -6068,9 +6063,9 @@ stumble_onto_mimic(struct monst *mtmp) fakeobj = object_from_map(glyph, mtmp->mx, mtmp->my, &otmp); otmp_name = (otmp && otmp->otyp != STRANGE_OBJECT) ? simpleonames(otmp) : "strange object"; - Sprintf(fmt, "%s %s %s %%s!", - otmp && is_plural(otmp) ? "Those" : "That", - otmp_name, otmp ? otense(otmp, "are") : "is"); + Snprintf(fmtbuf, sizeof fmtbuf, "%s %s %s %%s!", + (otmp && is_plural(otmp)) ? "Those" : "That", + otmp_name, otmp ? otense(otmp, "are") : "is"); if (fakeobj && otmp) { otmp->where = OBJ_FREE; /* object_from_map set to OBJ_FLOOR */ dealloc_obj(otmp); @@ -6090,8 +6085,25 @@ stumble_onto_mimic(struct monst *mtmp) else what = a_monnam(mtmp); } + if (what) - pline(fmt, what); + pline(fmtbuf, what); + if (reveal_it) + seemimic(mtmp); +} + +RESTORE_WARNING_FORMAT_NONLITERAL + +/* Note: caller must ascertain mtmp is mimicking... */ +void +stumble_onto_mimic(struct monst *mtmp) +{ + that_is_a_mimic(mtmp, TRUE); + + if (!u.ustuck && !mtmp->mflee && dmgtype(mtmp->data, AD_STCK) + /* must be adjacent; attack via polearm could be from farther away */ + && m_next2u(mtmp)) + set_ustuck(mtmp); wakeup(mtmp, FALSE); /* clears mimicking */ /* if hero is blind, wakeup() won't display the monster even though @@ -6101,8 +6113,6 @@ stumble_onto_mimic(struct monst *mtmp) map_invisible(mtmp->mx, mtmp->my); } -RESTORE_WARNING_FORMAT_NONLITERAL - staticfn void nohandglow(struct monst *mon) { diff --git a/src/zap.c b/src/zap.c index 59c871edc..84cc79561 100644 --- a/src/zap.c +++ b/src/zap.c @@ -167,6 +167,15 @@ bhitm(struct monst *mtmp, struct obj *otmp) struct obj *obj; boolean disguised_mimic = (mtmp->data->mlet == S_MIMIC && M_AP_TYPE(mtmp) != M_AP_NOTHING); + /* box_or_door(): mimic appearances that have locks */ +#define box_or_door(monst) \ + ((M_AP_TYPE(monst) == M_AP_OBJECT \ + && ((monst)->mappearance == CHEST \ + || (monst)->mappearance == LARGE_BOX)) \ + || (M_AP_TYPE(monst) == M_AP_FURNITURE \ + /* is_cmap_door() tests S_symbol values, and */ \ + /* mon->mappearance for furniture contains one of those */ \ + && is_cmap_door((monst)->mappearance))) if (engulfing_u(mtmp)) reveal_invis = FALSE; @@ -355,10 +364,8 @@ bhitm(struct monst *mtmp, struct obj *otmp) } case WAN_LOCKING: case SPE_WIZARD_LOCK: - /* can't use Is_box() here */ - if (disguised_mimic && (is_obj_mappear(mtmp, CHEST) - || is_obj_mappear(mtmp, LARGE_BOX))) - seemimic(mtmp); + if (disguised_mimic && box_or_door(mtmp)) + that_is_a_mimic(mtmp, TRUE); /*seemimic()*/ wake = closeholdingtrap(mtmp, &learn_it); break; case WAN_PROBING: @@ -369,9 +376,8 @@ bhitm(struct monst *mtmp, struct obj *otmp) break; case WAN_OPENING: case SPE_KNOCK: - if (disguised_mimic && (is_obj_mappear(mtmp, CHEST) - || is_obj_mappear(mtmp, LARGE_BOX))) - seemimic(mtmp); + if (disguised_mimic && box_or_door(mtmp)) + that_is_a_mimic(mtmp, TRUE); /*seemimic()*/ wake = FALSE; /* don't want immediate counterattack */ if (mtmp == u.ustuck) { /* zapping either holder/holdee or self [zapyourself()] will @@ -541,6 +547,7 @@ bhitm(struct monst *mtmp, struct obj *otmp) if (learn_it) learnwand(otmp); return ret; +#undef box_or_door } /* hero is held by a monster or engulfed or holding a monster and has zapped @@ -1768,10 +1775,9 @@ poly_obj(struct obj *obj, int id) /* Keep chest/box traps and poisoned ammo if we may */ if (obj->otrapped && Is_box(otmp)) - otmp->otrapped = TRUE; - + otmp->otrapped = 1; if (obj->opoisoned && is_poisonable(otmp)) - otmp->opoisoned = TRUE; + otmp->opoisoned = 1; if (id == STRANGE_OBJECT && obj->otyp == CORPSE) { /* turn crocodile corpses into shoes */ From fec6320e6870d12c90f12ffaac055c2ed330e84d Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 2 Dec 2024 19:04:08 -0500 Subject: [PATCH 03/26] rename sys/windows/Makefile.mingw32 to GNUmakefile GNU make looks first for a file called GNUmakefile, ahead of looking for Makefile and then makefile. Renaming sys/windows/Makefile.mingw32 to sys/windows/GNUmakefile allows: o src/GNUmakefile (for use by GNU make) and src/Makefile (for use Microsoft nmake) to both reside in the src folder during build. o src/GNUmakefile will be used by GNU make, without having to explicitly specify "-f GNUmakefile" on the GNU make command line. o src/Makefile will be used by Microsoft nmake, without having to explicitly specify "-f Makefile" on the Microsoft nmake command line. For the gcc build, the movemement of sys/windows/GNUmakefile needs to be copied to src/GNUmakefile as part of the build process (see sys/windows/build-msys2.txt). For the Microsoft Visual Studio command line build with nmake, sys/windows/Makefile.nmake needs to be copied to src/Makefile as part of the build process (see sys/windows/build-nmake.txt). They are both copied to the src folder from their respective repository source file names when the nhsetup.bat file is used. --- azure-pipelines.yml | 8 +++--- doc/fixes3-7-0.txt | 5 ++-- doc/sound.txt | 4 +-- include/windconf.h | 5 ---- src/.gitattributes | 6 ++--- src/.gitignore | 4 +-- sys/windows/{Makefile.mingw32 => GNUmakefile} | 8 +++--- ...file.mingw32.depend => GNUmakefile.depend} | 4 +-- sys/windows/build-msys2.txt | 26 ++++++++++--------- sys/windows/nhsetup.bat | 8 +++--- win/curses/Readme.txt | 2 +- win/share/safeproc.c | 9 +++++-- 12 files changed, 45 insertions(+), 44 deletions(-) rename sys/windows/{Makefile.mingw32 => GNUmakefile} (99%) rename sys/windows/{Makefile.mingw32.depend => GNUmakefile.depend} (96%) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 2a8a4ee87..624d4a640 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -164,10 +164,10 @@ steps: export cd ../src pwd - cp ../sys/windows/Makefile.mingw32* . - mingw32-make -f Makefile.mingw32 CI_COMPILER=1 GIT=1 MSYSTEM=$MSYSTEM LUA_VERSION=$LUA_VERSION clean - mingw32-make -f Makefile.mingw32 CI_COMPILER=1 GIT=1 MSYSTEM=$MSYSTEM LUA_VERSION=$LUA_VERSION depend - mingw32-make -f Makefile.mingw32 CI_COMPILER=1 GIT=1 MSYSTEM=$MSYSTEM LUA_VERSION=$LUA_VERSION + cp ../sys/windows/GNUmakefile* . + mingw32-make -f GNUmakefile CI_COMPILER=1 GIT=1 MSYSTEM=$MSYSTEM LUA_VERSION=$LUA_VERSION clean + mingw32-make -f GNUmakefile CI_COMPILER=1 GIT=1 MSYSTEM=$MSYSTEM LUA_VERSION=$LUA_VERSION depend + mingw32-make -f GNUmakefile CI_COMPILER=1 GIT=1 MSYSTEM=$MSYSTEM LUA_VERSION=$LUA_VERSION condition: eq( variables.toolchain, 'mingw' ) workingDirectory: $(Agent.BuildDirectory)/$(netHackPath)/src displayName: 'MinGW Build' diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index 1a60a914a..5aaf97818 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -2863,9 +2863,8 @@ use %lu, not %d, in format string in timer_sanity_check() (pr #617 by argrath) bad cast making sp_lev chameleon light source (pr #625 by entrez) add Ray Chason's adaptation of nethack's Qt5 interface to work with Qt6 (issue #525 followup comment by chasonr) -mingw32 build updates and replacement of sys/windows/Makefile.gcc with new - sys/windows/Makefile.mingw32 and sys/windows/Makefile.mingw32.depend - (pr #661 by feiyunw) +mingw32 build updates to replace contents of sys/windows/GNUmakefile and new + sys/windows/GNUmakefile.depend (pr #661 by feiyunw) mark various pointers to const char as const pointers (pr #624 by argrath) function fill_special_room() in sp_lev.c was dereferencing a pointer argument prior to a subsequent check for a NULL pointer that diff --git a/doc/sound.txt b/doc/sound.txt index 6af2a9707..2f90d3334 100644 --- a/doc/sound.txt +++ b/doc/sound.txt @@ -508,8 +508,8 @@ use the following guidelines: Windows with Visual studio nmake at the command line. - sys/windows/Makefile.mingw32 - sys/windows/Makefile.mingw32.depend + sys/windows/GNUmakefile + sys/windows/GNUmakefile.depend Will require updates in order to build on Windows with mingw32 or MSYS2 using GNU make at diff --git a/include/windconf.h b/include/windconf.h index 1b5b45d92..63c58cdbc 100644 --- a/include/windconf.h +++ b/include/windconf.h @@ -107,11 +107,6 @@ extern char *windows_exepath(void); #ifdef strcasecmp #undef strcasecmp /* https://sourceforge.net/p/mingw-w64/wiki2/gnu%20printf/ */ -#ifdef __USE_MINGW_ANSI_STDIO -#undef __USE_MINGW_ANSI_STDIO -#endif -/* with UCRT, we don't define this to 1 */ -#define __USE_MINGW_ANSI_STDIO 0 #endif /* extern int getlock(void); */ #endif /* __GNUC__ */ diff --git a/src/.gitattributes b/src/.gitattributes index 1e3746cde..a618fdc82 100644 --- a/src/.gitattributes +++ b/src/.gitattributes @@ -1,8 +1,8 @@ * NH_filestag=(file%s_for_all_versions) -..files NH_filegenerated=Makefile,Makefile.mingw32,qt_kde0.moc,qt_main.moc,qt_map.moc,qt_menu.moc,qt_msg.moc,qt_plsel.moc,qt_set.moc,qt_stat.moc,qt_xcmd.moc,qt_yndlg.moc,tile.c,monstr.c +..files NH_filegenerated=Makefile,GNUmakefile,qt_kde0.moc,qt_main.moc,qt_map.moc,qt_menu.moc,qt_msg.moc,qt_plsel.moc,qt_set.moc,qt_stat.moc,qt_xcmd.moc,qt_yndlg.moc,tile.c,monstr.c -Makefile.mingw32 NH_filesgentag=(file%s_for_win32_that_are_moved_into_src_at_compile_time) -Makefile NH_filesgentag=>Makefile.mingw32 +GNUmakefile NH_filesgentag=(file%s_for_win32_that_are_moved_into_src_at_compile_time) +Makefile NH_filesgentag=>GNUmakefile qt_kde0.moc NH_filesgentag=(file%s_generated_by_'moc'_for_Qt_interface_at_compile_time) qt_main.moc NH_filesgentag=>qt_kde0.moc diff --git a/src/.gitignore b/src/.gitignore index 9343f331b..dda3abdac 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -28,6 +28,6 @@ objutil/* objlua/* objpdc/* bundle/* -Makefile.mingw32 -Makefile.mingw32.depend +GNUmakefile +GNUmakefile.depend .*.c diff --git a/sys/windows/Makefile.mingw32 b/sys/windows/GNUmakefile similarity index 99% rename from sys/windows/Makefile.mingw32 rename to sys/windows/GNUmakefile index 809b822bd..bd2d71d2b 100644 --- a/sys/windows/Makefile.mingw32 +++ b/sys/windows/GNUmakefile @@ -1,11 +1,11 @@ -# NetHack 3.7 Makefile.mingw32 +# NetHack 3.7 GNUmakefile # Copyright (c) 2022 by Feiyun Wang #-Copyright (c) 2022 by Michael Allison # NetHack may be freely redistributed. See license for details. # #============================================================================== # -# Win32 Compilers Tested with this Makefile.mingw32: +# Win32 Compilers Tested with this GNUmakefile: # mingw-w64 # from: # https://sourceforge.net/p/mingw-w64/wiki2/GeneralUsageInstructions/ @@ -430,7 +430,7 @@ CLEAN_FILE += $(LUATARGETS) $(LUAOBJS) $(OLUA)/lua.o $(OLUA)/luac.o NHLUAH = $(INCL)/nhlua.h $(NHLUAH): - echo "/* nhlua.h - generated by Makefile.mingw32 */" > $@ + echo "/* nhlua.h - generated by GNUmakefile */" > $@ @echo "#include \"$(LUASRC)/lua.h\"" >> $@ @echo "LUA_API int (lua_error) (lua_State *L) NORETURN;" >>$@ @echo "#include \"$(LUASRC)/lualib.h\"" >> $@ @@ -1296,6 +1296,6 @@ clean: @$(foreach dir, $(CLEAN_DIR), \ if [ -d $(dir) ] ; then rmdir -p --ignore $(dir) ; fi ; ) --include Makefile.mingw32.depend +-include GNUmakefile.depend -include .depend # end of file diff --git a/sys/windows/Makefile.mingw32.depend b/sys/windows/GNUmakefile.depend similarity index 96% rename from sys/windows/Makefile.mingw32.depend rename to sys/windows/GNUmakefile.depend index 71c925c67..230bf8e38 100644 --- a/sys/windows/Makefile.mingw32.depend +++ b/sys/windows/GNUmakefile.depend @@ -2,12 +2,12 @@ cce = gcc -E -MM -MT "$(@:d=o) $@" -# Copy all $(cc) commands w/ their targets from Makefile.mingw32, 3rd party code unnecessary +# Copy all $(cc) commands w/ their targets from GNUmakefile, 3rd party code unnecessary # Replace .o w/ .d, $(cc) w/ $(cce) # Check extraordinary "OBJ): " and handle them properly # Check all CLEAN_FILE lines, add obj files to $(OBJS4DEP) # Run -# mingw32-make depend +# make depend $(HL)/%.d: $(SRC)/%.c | $(HL) $(cce) $(CFLAGSU) $< -o$@ diff --git a/sys/windows/build-msys2.txt b/sys/windows/build-msys2.txt index 4ce421f2e..1258f7be9 100644 --- a/sys/windows/build-msys2.txt +++ b/sys/windows/build-msys2.txt @@ -92,9 +92,11 @@ I. Dispelling the Myths: as it looks, however it will behoove you to read this entire section through before beginning the task. - We have provided Makefile.mingw32 in - sys/windows/Makefile.mingw32, which you use from the bash Windows command - shell included with MSYS2. + We have provided GNUmakefile in sys/windows/GNUmakefile, which you use + from the bash Windows command shell included with MSYS2. It is called + GNUmakefile because that is the first name searched for by the GNU + make utility thus preventing conflict with the Makefile used by the + Microsoft nmake utility. II. To compile your copy of NetHack on a Windows machine using MSYS2: @@ -106,7 +108,7 @@ Setting Up 2. Execute the following command to place copies of the Makefiles in the src subfolder. - cp sys/windows/Makefile.mingw32* src + cp sys/windows/GNUmakefile* src 3. Change your current directory to the src subfolder of the nethack source tree. The following command assumes you are still in the @@ -120,10 +122,12 @@ Compiling Your current directory should be the NetHack src directory. - Issue these following commands: - make -f Makefile.mingw32 clean - make -f Makefile.mingw32 depend - make -f Makefile.mingw32 + Issue these following commands, which will find and use GNUmakefile + by default: + + make clean + make depend + make If all goes well, intermediate NetHack files will be placed in the binary subfolder of the NetHack tree, and the final NetHack package @@ -132,10 +136,8 @@ Compiling Notes: 1. To rebuild NetHack after changing something, change your current directory - to src and issue the appropriate command for your compiler: - - For gcc: - make -f Makefile.mingw32 + to src and issue the following command: + make 2. An alternative to MSYS2 may be MinGW-w64 - winlibs standalone build. That has not been tested by us at time of writing. diff --git a/sys/windows/nhsetup.bat b/sys/windows/nhsetup.bat index d365c1558..ed41d2361 100755 --- a/sys/windows/nhsetup.bat +++ b/sys/windows/nhsetup.bat @@ -47,10 +47,10 @@ echo ..\..\src\Makefile-orig copy /Y Makefile.nmake ..\..\src\Makefile >nul echo Microsoft nmake Makefile.nmake copy to ..\..\src\Makefile completed. -echo Copying mingw-w64 Makefile.mingw32 to ..\..\src\Makefile.mingw32 -copy /Y Makefile.mingw32 ..\..\src\Makefile.mingw32 >nul -echo Copying mingw-w64 Makefile.mingw32.depend to ..\..\src\Makefile.mingw32.depend -copy /Y Makefile.mingw32.depend ..\..\src\Makefile.mingw32.depend >nul +echo Copying mingw-w64 GNUmakefile to ..\..\src\GNUmakefile +copy /Y GNUmakefile ..\..\src\GNUmakefile >nul +echo Copying mingw-w64 GNUmakefile.depend to ..\..\src\GNUmakefile.depend +copy /Y GNUmakefile.depend ..\..\src\GNUmakefile.depend >nul echo mingw-w64 Makefile copies to ..\..\src completed. echo Done copying files. diff --git a/win/curses/Readme.txt b/win/curses/Readme.txt index 2cc207238..a9ae0be7b 100644 --- a/win/curses/Readme.txt +++ b/win/curses/Readme.txt @@ -33,7 +33,7 @@ NetHack 3.7 and above. Windows build instructions: -By default, the Makefile.msc and Makefile.mingw32 are set up to build +By default, the Makefile.nmake and GNUmakefile are set up to build curses from the submodules/pdcurses submodules folder (assumes you obtained your NetHack sources via cloning a git repository), If you obtained your NetHack by another means, such as a zip download, diff --git a/win/share/safeproc.c b/win/share/safeproc.c index 2862117ff..aa2b3c478 100644 --- a/win/share/safeproc.c +++ b/win/share/safeproc.c @@ -65,6 +65,11 @@ * *********************************************************** */ +void safe_dismiss_nhwindow(winid); +void safe_putstr(winid, int, const char *); +void win_safe_init(int); +void safe_number_pad(int); + struct window_procs safe_procs = { WPID(safestartup), (0 @@ -225,7 +230,7 @@ safe_curs(winid window UNUSED, int x UNUSED, int y UNUSED) } void -safe_putstr(winid window, int attr, const char *str) +safe_putstr(winid window UNUSED, int attr UNUSED, const char *str UNUSED) { return; } @@ -424,7 +429,7 @@ safe_get_ext_cmd(void) } void -safe_number_pad(int mode) +safe_number_pad(int mode UNUSED) { return; } From dd66009cc19608ba138a633a8e1727b3e6d2529a Mon Sep 17 00:00:00 2001 From: nhw_cron Date: Mon, 2 Dec 2024 19:24:07 -0500 Subject: [PATCH 04/26] This is cron-daily v1-Apr-1-2024. 000files updated: Files --- Files | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Files b/Files index e58c876b3..995b17ff3 100644 --- a/Files +++ b/Files @@ -428,14 +428,14 @@ vmsunix.c sys/windows: (files for Windows 7/8.x/10/11 version) -Install.windows Makefile.mingw32 Makefile.mingw32.depend -Makefile.nmake build-msys2.txt build-nmake.txt -build-vs.txt console.rc consoletty.c -fetch.cmd guitty.c nethack.def -nethackrc.template nhico.uu nhsetup.bat -porthelp sysconf.template win10.c -win10.h win32api.h windmain.c -windsys.c winos.h +GNUmakefile GNUmakefile.depend Install.windows +Makefile.nmake build-msys2.txt build-nmake.txt +build-vs.txt console.rc consoletty.c +fetch.cmd guitty.c nethack.def +nethackrc.template nhico.uu nhsetup.bat +porthelp sysconf.template win10.c +win10.h win32api.h windmain.c +windsys.c winos.h sys/windows/vs: (files for Visual Studio 2019 or 2022 Community Edition builds) @@ -668,7 +668,7 @@ pet_mark.xbm rip.xpm x11tiles src: (files for win32 that are moved into src at compile time) -Makefile Makefile.mingw32 +GNUmakefile Makefile (files generated by 'moc' for Qt interface at compile time) qt_kde0.moc qt_main.moc qt_map.moc qt_menu.moc qt_msg.moc From c434b73e942353c34f542af38f7d78b5beeae3d4 Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 2 Dec 2024 19:43:56 -0500 Subject: [PATCH 05/26] fix a comment typo --- src/uhitm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/uhitm.c b/src/uhitm.c index 2d1715bf6..04e78d20e 100644 --- a/src/uhitm.c +++ b/src/uhitm.c @@ -6032,7 +6032,7 @@ passive_obj( DISABLE_WARNING_FORMAT_NONLITERAL -/* used by stuble_onto_mimic() and bhitm() cases WAN_LOCKING, WAN_OPENING */ +/* used by stumble_onto_mimic() and bhitm() cases WAN_LOCKING, WAN_OPENING */ void that_is_a_mimic( struct monst *mtmp, /* a hidden mimic (nonnull) */ From 53f43ab00bb9ff7efe5be2d532478e9f09fc89ec Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Tue, 3 Dec 2024 19:52:08 +0200 Subject: [PATCH 06/26] Qt: show main window normally instead of maximized Sidenote: The main window size calculations are getting stupid. It would be better to find out the widget sizes and shift the splitter up, instead of letting it just take up half of the main window. Idea and part of the code by Richard Henschel --- doc/fixes3-7-0.txt | 1 + win/Qt/qt_main.cpp | 6 +++--- win/Qt/qt_menu.cpp | 3 +-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index 5aaf97818..1e546c700 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -2118,6 +2118,7 @@ Qt: with a pick-one menu containing a pre-selected entry, clicking on that instead of typing the selector letter toggled off preselected entry but failed to toggle on the explicitly selected one; clicking again after nothing was pre-selected anymore refused to toggle anything on +Qt: don't show main window and tombstone window maximized by default tty: redraw unexplored locations as S_unexplored rather than after map has been partially overwritten by popup menu or text display tty: previous change resulted in remnants of previous level being shown on diff --git a/win/Qt/qt_main.cpp b/win/Qt/qt_main.cpp index 73bade00f..14a4f51f6 100644 --- a/win/Qt/qt_main.cpp +++ b/win/Qt/qt_main.cpp @@ -886,8 +886,8 @@ NetHackQtMainWindow::NetHackQtMainWindow(NetHackQtKeyBuffer& ks) : if (qt_settings != NULL) { auto glyphs = &qt_settings->glyphs(); if (glyphs != NULL) { - maxwn = glyphs->width() * COLNO + 10; - maxhn = glyphs->height() * ROWNO * 6/4; + maxwn = glyphs->width() * (COLNO + 1); + maxhn = glyphs->height() * ROWNO * 6/4 + glyphs->height() * 10; } } @@ -1456,7 +1456,7 @@ void NetHackQtMainWindow::ShowIfReady() } else { layout(); } - showMaximized(); + showNormal(); } else if (isVisible()) { hide(); } diff --git a/win/Qt/qt_menu.cpp b/win/Qt/qt_menu.cpp index 69ab6b747..93a9064f6 100644 --- a/win/Qt/qt_menu.cpp +++ b/win/Qt/qt_menu.cpp @@ -1115,8 +1115,7 @@ void NetHackQtTextWindow::Display(bool block UNUSED) #endif int mh = screensize.height()*3/5; if ( (qt_compact_mode && lines->TotalHeight() > mh) || use_rip ) { - // big, so make it fill - showMaximized(); + showNormal(); } else { move(0, 0); adjustSize(); From 7c28fa1828c32954aefe4638156d765058fd1d25 Mon Sep 17 00:00:00 2001 From: nhmall Date: Wed, 4 Dec 2024 09:25:12 -0500 Subject: [PATCH 07/26] test newer software versions in CI --- azure-pipelines.yml | 39 ++++++++++++--------------------------- 1 file changed, 12 insertions(+), 27 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 624d4a640..83456a34f 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -4,24 +4,24 @@ strategy: imageName: 'ubuntu-latest' toolchainName: gcc9 buildTargetName: minimal - linux_jammy_clang_all: - imageName: 'ubuntu-22.04' + linux_noble_clang_all: + imageName: 'ubuntu-24.04' toolchainName: clang buildTargetName: all linux_jammy_gcc9_all: imageName: 'ubuntu-22.04' toolchainName: gcc9 buildTargetName: all - linux_jammy_gcc12_all: - imageName: 'ubuntu-22.04' - toolchainName: gcc12 + linux_noble_gcc13_all: + imageName: 'ubuntu-24.04' + toolchainName: gcc13 buildTargetName: all macOS_latest_clang_all: imageName: 'macOS-latest' toolchainName: clang buildTargetName: all - macOS_Ventura_clang13_all: - imageName: 'macOS-13' + macOS_Sequoia_clang15_all: + imageName: 'macOS-15' toolchainName: clang buildTargetName: all windows-visualstudio: @@ -36,8 +36,8 @@ strategy: imageName: 'ubuntu-20.04' toolchainName: cross buildTargetName: msdos - linux_jammy_docs: - imageName: 'ubuntu-22.04' + linux_noble_docs: + imageName: 'ubuntu-24.04' toolchainName: docs buildTargetName: all continueOnError: true @@ -60,30 +60,15 @@ variables: steps: - bash: | - if [ "$(toolchain)" == "gcc7" ] - then - echo "##vso[task.setvariable variable=CC]gcc-7" - echo "##vso[task.setvariable variable=CXX]g++-7" - fi if [ "$(toolchain)" == "gcc9" ] then echo "##vso[task.setvariable variable=CC]gcc-9" echo "##vso[task.setvariable variable=CXX]g++-9" fi - if [ "$(toolchain)" == "gcc10" ] - then - echo "##vso[task.setvariable variable=CC]gcc-10" - echo "##vso[task.setvariable variable=CXX]g++-10" - fi - if [ "$(toolchain)" == "gcc11" ] - then - echo "##vso[task.setvariable variable=CC]gcc-11" - echo "##vso[task.setvariable variable=CXX]g++-11" - fi - if [ "$(toolchain)" == "gcc12" ] + if [ "$(toolchain)" == "gcc13" ] then - echo "##vso[task.setvariable variable=CC]gcc-12" - echo "##vso[task.setvariable variable=CXX]g++-12" + echo "##vso[task.setvariable variable=CC]gcc-13" + echo "##vso[task.setvariable variable=CXX]g++-13" fi if [ "$(toolchain)" == "clang" ] then From c868119a33512f50427e068aca0136a8c0b116fb Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Wed, 4 Dec 2024 16:46:05 +0200 Subject: [PATCH 08/26] Add missing full stop --- src/end.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/end.c b/src/end.c index a6e899fa8..ace45f699 100644 --- a/src/end.c +++ b/src/end.c @@ -118,7 +118,7 @@ done2(void) if (abandon_tutorial) schedule_goto(&u.ucamefrom, UTOTYPE_ATSTAIRS, - "Resuming regular play", (char *) 0); + "Resuming regular play.", (char *) 0); return ECMD_OK; } From 6813e51945d19d6ece42395aec632e37a0a1cabb Mon Sep 17 00:00:00 2001 From: nhmall Date: Wed, 4 Dec 2024 09:51:51 -0500 Subject: [PATCH 09/26] Use newer mingw-w64 UCRT build in CI --- azure-pipelines.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 83456a34f..5dd8d32ed 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -128,12 +128,14 @@ steps: # # 64-bit #export CURLSRC=https://github.com/brechtsanders/winlibs_mingw/releases/download/11.2.0-9.0.0-ucrt-r5/winlibs-x86_64-posix-seh-gcc-11.2.0-mingw-w64ucrt-9.0.0-r5.zip + #export CURLSRC=https://github.com/brechtsanders/winlibs_mingw/releases/download/14.2.0posix-19.1.1-12.0.0-ucrt-r2/winlibs-x86_64-posix-seh-gcc-14.2.0-llvm-19.1.1-mingw-w64ucrt-12.0.0-r2.zip #export CURLDST=mingw-x64.zip #export MINGWBIN=mingw64 #export MSYSTEM=MINGW64 # # 32-bit - export CURLSRC=https://github.com/brechtsanders/winlibs_mingw/releases/download/11.2.0-9.0.0-ucrt-r5/winlibs-i686-posix-dwarf-gcc-11.2.0-mingw-w64ucrt-9.0.0-r5.zip + #export CURLSRC=https://github.com/brechtsanders/winlibs_mingw/releases/download/11.2.0-9.0.0-ucrt-r5/winlibs-i686-posix-dwarf-gcc-11.2.0-mingw-w64ucrt-9.0.0-r5.zip + export CURLSRC=https://github.com/brechtsanders/winlibs_mingw/releases/download/14.2.0posix-19.1.1-12.0.0-ucrt-r2/winlibs-i686-posix-dwarf-gcc-14.2.0-llvm-19.1.1-mingw-w64ucrt-12.0.0-r2.zip export CURLDST=mingw-x86.zip export MINGWBIN=mingw32 export MSYSTEM=MINGW32 From b96c59e9b1ef61f9fc4818422bd310503e6a38bc Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Wed, 4 Dec 2024 20:54:47 +0200 Subject: [PATCH 10/26] Angry god may remove an intrinsic --- doc/fixes3-7-0.txt | 1 + src/pray.c | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index 1e546c700..40f9c5219 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -1483,6 +1483,7 @@ when hero who is poly'd into metallivore form eats a tin, bypass "smells like along with the tin without asking digging in ice was handled inconsistently, particularly if done at the span spot in front of closed drawbridge +angry god may remove an intrinsic Fixes to 3.7.0-x General Problems Exposed Via git Repository diff --git a/src/pray.c b/src/pray.c index 47d853a11..7099cddff 100644 --- a/src/pray.c +++ b/src/pray.c @@ -754,7 +754,8 @@ angrygods(aligntyp resp_god) gods_angry(resp_god); if (!Blind && !Antimagic) pline("%s glow surrounds you.", An(hcolor(NH_BLACK))); - rndcurse(); + if (rn2(2) || !attrcurse()) + rndcurse(); break; case 7: case 8: From e120abe6963cc7a1692f6c5fba3793ed0df9d031 Mon Sep 17 00:00:00 2001 From: nhmall Date: Wed, 4 Dec 2024 14:13:44 -0500 Subject: [PATCH 11/26] switch msdos cross-compile in CI to Ubuntu 24.04 --- azure-pipelines.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 5dd8d32ed..e6fd5ab8f 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -32,8 +32,8 @@ strategy: imageName: 'windows-2019' toolchainName: mingw buildTargetName: all - linux_focal_cross_msdos: - imageName: 'ubuntu-20.04' + linux_noble_msdos: + imageName: 'ubuntu-24.04' toolchainName: cross buildTargetName: msdos linux_noble_docs: From 2d38d05c6ba6e8911835681d036fbb31cab607f5 Mon Sep 17 00:00:00 2001 From: nhmall Date: Wed, 4 Dec 2024 14:17:04 -0500 Subject: [PATCH 12/26] correct bad edit in CI yml file --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index e6fd5ab8f..31ee5c845 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -32,7 +32,7 @@ strategy: imageName: 'windows-2019' toolchainName: mingw buildTargetName: all - linux_noble_msdos: + linux_noble_cross_msdos: imageName: 'ubuntu-24.04' toolchainName: cross buildTargetName: msdos From 3a044c56a9c34d3ed866c3151b4d227101fe74ad Mon Sep 17 00:00:00 2001 From: nhmall Date: Wed, 4 Dec 2024 14:31:42 -0500 Subject: [PATCH 13/26] more CI cross compile to msdos - compiler bit --- azure-pipelines.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 31ee5c845..4bf09d340 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -77,8 +77,8 @@ steps: fi if [ "$(toolchain)" == "cross" ] then - echo "##vso[task.setvariable variable=CC]gcc-9" - echo "##vso[task.setvariable variable=CXX]g++-9" + echo "##vso[task.setvariable variable=CC]gcc-13" + echo "##vso[task.setvariable variable=CXX]g++-13" fi displayName: 'Setting variables' From b33369fc22926975827a00e418dcb42ea650d74c Mon Sep 17 00:00:00 2001 From: nhmall Date: Wed, 4 Dec 2024 14:47:04 -0500 Subject: [PATCH 14/26] cross compile to msdos in CI - fix 1 --- azure-pipelines.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 4bf09d340..fb80ed026 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -219,6 +219,7 @@ steps: displayName: 'Building mac full build' - bash: | + sudo apt -qq -y install libfl-dev export GCCVER=gcc1220 cd sys/unix sh setup.sh hints/linux.370 From f7cff6c0ebbc8003efd3f8a429bd2b63e53f00d0 Mon Sep 17 00:00:00 2001 From: nhmall Date: Wed, 4 Dec 2024 14:55:35 -0500 Subject: [PATCH 15/26] cross compile to msdos in CI - fix 2 --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index fb80ed026..6f716c7e7 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -219,7 +219,7 @@ steps: displayName: 'Building mac full build' - bash: | - sudo apt -qq -y install libfl-dev + sudo apt -qq -y install flex export GCCVER=gcc1220 cd sys/unix sh setup.sh hints/linux.370 From 0409ce01a318f9d2be7f9c189f52e54867354251 Mon Sep 17 00:00:00 2001 From: nhmall Date: Wed, 4 Dec 2024 15:01:30 -0500 Subject: [PATCH 16/26] cross compile to msdos in CI - fix 3 --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 6f716c7e7..fced2c60d 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -219,7 +219,7 @@ steps: displayName: 'Building mac full build' - bash: | - sudo apt -qq -y install flex + sudo apt -qq -y install libfl2 export GCCVER=gcc1220 cd sys/unix sh setup.sh hints/linux.370 From bdeddbe63b7d72ef92253f4df44b5b2899633f9c Mon Sep 17 00:00:00 2001 From: nhmall Date: Wed, 4 Dec 2024 15:12:27 -0500 Subject: [PATCH 17/26] update sys/msdos/Install.dos --- sys/msdos/Install.dos | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/sys/msdos/Install.dos b/sys/msdos/Install.dos index 108e117a4..780061099 100644 --- a/sys/msdos/Install.dos +++ b/sys/msdos/Install.dos @@ -145,23 +145,16 @@ Appendix B - Common Difficulties Encountered This indicates that your host system does not have the flex library installed, and the cross-compiler needs it to be. On Ubuntu systems, you can easily rectify this issue by - just installing flex, as follows: + just installing the flex shared library as follows: - sudo apt-get install flex + sudo apt install libfl2 Reading package lists... Done Building dependency tree... Done Reading state information... Done - The following additional packages will be installed: - libfl-dev libfl2 m4 - Suggested packages: - bison flex-doc m4-doc The following NEW packages will be installed: - flex libfl-dev libfl2 m4 - 0 upgraded, 4 newly installed, 0 to remove and 0 not upgraded. - Need to get 558 kB of archives. - After this operation, 1699 kB of additional disk space will be - used. Do you want to continue? [Y/n] Y + libfl2 + 0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded. Appendix D - Contacting the Development Team From 08be1bafddd0f04dbdbf17c2c1ad3b99331ad95b Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Thu, 5 Dec 2024 15:31:49 +0200 Subject: [PATCH 18/26] Explain ctrl-key combos in tutorial When tutorializing a command that uses a ^X notation, show Ctrl-X instead. Also show an explanation of the ^X nearby. The only ctrl-key combination that can currently happen in the tutorial, without rebinding keys, is the kick-command. Fixes #1327 --- dat/tut-1.lua | 98 ++++++++++++++++++++++++++++++++++----------------- 1 file changed, 66 insertions(+), 32 deletions(-) diff --git a/dat/tut-1.lua b/dat/tut-1.lua index 13e6ed3f7..06b676117 100644 --- a/dat/tut-1.lua +++ b/dat/tut-1.lua @@ -1,4 +1,31 @@ +local tut_ctrl_key = nil; +local tut_alt_key = nil; + +function tut_key(command) + local s = nh.eckey(command); + local m = s:match("^^([A-Z])$"); -- ^X is Ctrl-X + if (m ~= nil) then + tut_ctrl_key = m; + return "Ctrl-" .. m; + end + + m = s:match("^M-([A-Z])$"); -- M-X is Alt-X + if (m ~= nil) then + tut_alt_key = m; + return "Alt-" .. m; + end + + return s; +end + +function tut_key_help(x, y) + if (tut_ctrl_key ~= nil) then + des.engraving({ coord = { x,y }, type = "engrave", text = "Note: Outside the tutorial, Ctrl-key combinations are shown prefixed with a caret, like '^" .. tut_ctrl_key .. "'", degrade = false }); + tut_ctrl_key = nil; + end +end + des.level_init({ style = "solidfill", fg = " " }); des.level_flags("mazelevel", "noflip", "nomongen", "nodeathdrops", "noautosearch"); @@ -40,15 +67,15 @@ nh.parse_config("OPTIONS=mention_walls"); nh.parse_config("OPTIONS=mention_decor"); nh.parse_config("OPTIONS=lit_corridor"); -local movekeys = nh.eckey("movewest") .. " " .. - nh.eckey("movesouth") .. " " .. - nh.eckey("movenorth") .. " " .. - nh.eckey("moveeast"); +local movekeys = tut_key("movewest") .. " " .. + tut_key("movesouth") .. " " .. + tut_key("movenorth") .. " " .. + tut_key("moveeast"); -local diagmovekeys = nh.eckey("movesouthwest") .. " " .. - nh.eckey("movenortheast") .. " " .. - nh.eckey("movesoutheast") .. " " .. - nh.eckey("movenorthwest"); +local diagmovekeys = tut_key("movesouthwest") .. " " .. + tut_key("movenortheast") .. " " .. + tut_key("movesoutheast") .. " " .. + tut_key("movenorthwest"); des.engraving({ coord = { 9,3 }, type = "engrave", text = "Move around with " .. movekeys, degrade = false }); des.engraving({ coord = { 5,2 }, type = "engrave", text = "Move diagonally with " .. diagmovekeys, degrade = false }); @@ -59,7 +86,7 @@ des.engraving({ coord = { 2,4 }, type = "engrave", text = "Some actions may requ des.engraving({ coord = { 2,5 }, type = "engrave", text = "Open the door by moving into it", degrade = false }); des.door({ coord = { 2,6 }, state = "closed" }); -des.engraving({ coord = { 2,7 }, type = "engrave", text = "Close the door with '" .. nh.eckey("close") .. "'", degrade = false }); +des.engraving({ coord = { 2,7 }, type = "engrave", text = "Close the door with '" .. tut_key("close") .. "'", degrade = false }); -- @@ -69,14 +96,18 @@ des.trap({ type = "magic portal", coord = { 4,4 }, seen = true }); -- -des.engraving({ coord = { 5,9 }, type = "engrave", text = "This door is locked. Kick it with '" .. nh.eckey("kick") .. "'", degrade = false }); +des.engraving({ coord = { 5,9 }, type = "engrave", text = "This door is locked. Kick it with '" .. tut_key("kick") .. "'", degrade = false }); des.door({ coord = { 5,10 }, state = "locked" }); -des.engraving({ coord = { 5,12 }, type = "engrave", text = "Look around the map with '" .. nh.eckey("glance") .. "'", degrade = false }); +-- by default, kick is the first command that can be a ctrl-key combo +tut_key_help(6, 8); + + +des.engraving({ coord = { 5,12 }, type = "engrave", text = "Look around the map with '" .. tut_key("glance") .. "'", degrade = false }); -- -des.engraving({ coord = { 10,13 }, type = "engrave", text = "Use '" .. nh.eckey("search") .. "' to search for secret doors", degrade = false }); +des.engraving({ coord = { 10,13 }, type = "engrave", text = "Use '" .. tut_key("search") .. "' to search for secret doors", degrade = false }); -- @@ -100,17 +131,17 @@ end des.door({ coord = { 18,13 }, state = "closed" }); -des.engraving({ coord = { 19,13 }, type = "engrave", text = "Pick up items with '" .. nh.eckey("pickup") .. "'", degrade = false }); +des.engraving({ coord = { 19,13 }, type = "engrave", text = "Pick up items with '" .. tut_key("pickup") .. "'", degrade = false }); local armor = (u.role == "Monk") and "leather gloves" or "leather armor"; des.object({ id = armor, spe = 0, buc = "cursed", coord = { 19,14} }); -des.engraving({ coord = { 19,15 }, type = "engrave", text = "Wear armor with '" .. nh.eckey("wear") .. "'", degrade = false }); +des.engraving({ coord = { 19,15 }, type = "engrave", text = "Wear armor with '" .. tut_key("wear") .. "'", degrade = false }); des.object({ id = "dagger", spe = 0, buc = "not-cursed", coord = { 21,15} }); -des.engraving({ coord = { 21,14 }, type = "engrave", text = "Wield weapons with '" .. nh.eckey("wield") .. "'", degrade = false }); +des.engraving({ coord = { 21,14 }, type = "engrave", text = "Wield weapons with '" .. tut_key("wield") .. "'", degrade = false }); des.engraving({ coord = { 22,13 }, type = "engrave", text = "Hit monsters by walking into them.", degrade = false }); @@ -131,13 +162,13 @@ des.object({ id = "boulder", coord = {25,12} }); -- -des.engraving({ coord = { 27,9 }, type = "engrave", text = "Take off armor with '" .. nh.eckey("takeoff") .. "'", degrade = false }); +des.engraving({ coord = { 27,9 }, type = "engrave", text = "Take off armor with '" .. tut_key("takeoff") .. "'", degrade = false }); -- des.object({ class = "?", id = "remove curse", buc = "blessed", coord = {23,11} }) des.engraving({ coord = { 22,11 }, type = "engrave", text = "Some items have shuffled descriptions, different each game", degrade = false }); -des.engraving({ coord = { 23,11 }, type = "engrave", text = "Pick up this scroll, read it with '" .. nh.eckey("read") .. "', and try to remove the armor again", degrade = false }); +des.engraving({ coord = { 23,11 }, type = "engrave", text = "Pick up this scroll, read it with '" .. tut_key("read") .. "', and try to remove the armor again", degrade = false }); -- @@ -157,14 +188,14 @@ des.object({ coord = {14, 6}, id = "boulder" }); des.door({ coord = { 20,3 }, state = percent(50) and "open" or "closed" }); des.engraving({ coord = { 21,3 }, type = "engrave", text = "Avoid being burdened, it slows you down", degrade = false }); -des.engraving({ coord = { 22,3 }, type = "engrave", text = "Drop items with '" .. nh.eckey("drop") .. "'", degrade = false }); +des.engraving({ coord = { 22,3 }, type = "engrave", text = "Drop items with '" .. tut_key("drop") .. "'", degrade = false }); des.engraving({ coord = { 22,4 }, type = "engrave", text = "You can drop partial stacks by prefixing the item slot letter with a number", degrade = false }); -- des.monster({ id = "yellow mold", coord = { 26,2 }, waiting = true, countbirth = false }); -des.engraving({ coord = { 25,5 }, type = "engrave", text = "Throw items with '" .. nh.eckey("throw") .. "'", degrade = false }); +des.engraving({ coord = { 25,5 }, type = "engrave", text = "Throw items with '" .. tut_key("throw") .. "'", degrade = false }); des.trap({ type = "magic portal", coord = { 21,1 }, seen = true }); @@ -176,35 +207,35 @@ des.engraving({ coord = { 37,4 }, type = "engrave", text = "Missiles, such as ro des.object({ coord = { 37,3 }, id = "sling", buc = "not-cursed", spe = 9 }); des.engraving({ coord = { 37,3 }, type = "engrave", text = "Wield the sling", degrade = false }); -des.engraving({ coord = { 36,1 }, type = "engrave", text = "Use '" .. nh.eckey("fire") .. "' to fire missiles with the wielded launcher", degrade = false }); +des.engraving({ coord = { 36,1 }, type = "engrave", text = "Use '" .. tut_key("fire") .. "' to fire missiles with the wielded launcher", degrade = false }); -des.engraving({ coord = { 35,4 }, type = "engrave", text = "Firing launches items from your quiver; Use '" .. nh.eckey("quiver") .. "' to put items in it", degrade = false }); +des.engraving({ coord = { 35,4 }, type = "engrave", text = "Firing launches items from your quiver; Use '" .. tut_key("quiver") .. "' to put items in it", degrade = false }); -des.engraving({ coord = { 33,4 }, type = "engrave", text = "You can wait a turn with '" .. nh.eckey("wait") .. "'", degrade = false }); +des.engraving({ coord = { 33,4 }, type = "engrave", text = "You can wait a turn with '" .. tut_key("wait") .. "'", degrade = false }); -- des.door({ coord = { 38,6 }, state = "closed" }); -des.engraving({ coord = { 39,6 }, type = "engrave", text = "You loot containers with '" .. nh.eckey("loot") .. "'", degrade = false }); +des.engraving({ coord = { 39,6 }, type = "engrave", text = "You loot containers with '" .. tut_key("loot") .. "'", degrade = false }); des.object({ coord = { 42,6 }, id = "large box", broken = true, contents = function(obj) des.object({ id = "secret door detection", class = "/", spe = 30 }); end }); -des.engraving({ coord = { 45,6 }, type = "engrave", text = "Magic wands are used with '" .. nh.eckey("zap") .. "'", degrade = false }); +des.engraving({ coord = { 45,6 }, type = "engrave", text = "Magic wands are used with '" .. tut_key("zap") .. "'", degrade = false }); -- des.door({ coord = { 35,9 }, state = "nodoor" }); -des.engraving({ coord = { 34,9 }, type = "engrave", text = "You can run by prefixing a movement key with '" .. nh.eckey("run") .. "'", degrade = false }); +des.engraving({ coord = { 34,9 }, type = "engrave", text = "You can run by prefixing a movement key with '" .. tut_key("run") .. "'", degrade = false }); -- des.door({ coord = { 33,16 }, state = "nodoor" }); -des.engraving({ coord = { 35,15 }, type = "engrave", text = "Travel across the level with '" .. nh.eckey("travel") .. "'", degrade = false }); +des.engraving({ coord = { 35,15 }, type = "engrave", text = "Travel across the level with '" .. tut_key("travel") .. "'", degrade = false }); -- @@ -212,7 +243,7 @@ des.trap({ type = "magic portal", coord = { 27,14 }, seen = true }); -- -des.engraving({ coord = { 48,1 }, type = "burn", text = "Use '" .. nh.eckey("eat") .. "' to eat edible things", degrade = false }); +des.engraving({ coord = { 48,1 }, type = "burn", text = "Use '" .. tut_key("eat") .. "' to eat edible things", degrade = false }); des.object({ coord = { 50,3 }, id = "apple", buc = "not-cursed" }); des.object({ coord = { 50,3 }, id = "candy bar", buc = "not-cursed" }); @@ -224,11 +255,11 @@ otmp:stop_timer("rot-corpse"); des.door({ coord = { 46,11 }, state = "closed" }); -des.engraving({ coord = { 43,11 }, type = "burn", text = "Use '" .. nh.eckey("twoweapon") .. "' to use two weapons at once", degrade = false }); +des.engraving({ coord = { 43,11 }, type = "burn", text = "Use '" .. tut_key("twoweapon") .. "' to use two weapons at once", degrade = false }); des.object({ coord = { 43,13 }, id = "knife", buc = "uncursed" }); des.object({ coord = { 43,14 }, id = "dagger", buc = "blessed" }); -des.engraving({ coord = { 43,16 }, type = "burn", text = "Swap weapons quickly with '" .. nh.eckey("swap") .. "'", degrade = false }); +des.engraving({ coord = { 43,16 }, type = "burn", text = "Swap weapons quickly with '" .. tut_key("swap") .. "'", degrade = false }); des.door({ coord = { 40,15 }, state = "random" }); @@ -236,20 +267,23 @@ des.door({ coord = { 40,15 }, state = "random" }); des.object({ coord = { 48,7 }, id = "ring of levitation", buc = "not-cursed" }); -des.engraving({ coord = { 48,10 }, type = "burn", text = "Put on accessories with '" .. nh.eckey("puton") .. "'", degrade = false }); +des.engraving({ coord = { 48,10 }, type = "burn", text = "Put on accessories with '" .. tut_key("puton") .. "'", degrade = false }); -des.engraving({ coord = { 48,16 }, type = "burn", text = "Remove accessories with '" .. nh.eckey("remove") .. "'", degrade = false }); +des.engraving({ coord = { 48,16 }, type = "burn", text = "Remove accessories with '" .. tut_key("remove") .. "'", degrade = false }); des.door({ coord = { 50,16 }, state = "closed" }); -- -des.engraving({ coord = { 58,9 }, type = "burn", text = "Use '" .. nh.eckey("down") .. "' to go down the stairs", degrade = false }); +des.engraving({ coord = { 58,9 }, type = "burn", text = "Use '" .. tut_key("down") .. "' to go down the stairs", degrade = false }); des.stair({ dir = "down", coord = { 58,10 } }); -- +-- one more ctrl-key help, if needed +tut_key_help(64, 4); + des.engraving({ coord = { 65,3 }, type = "burn", text = "UNDER CONSTRUCTION", degrade = false }); des.trap({ type = "magic portal", coord = { 66,2 }, seen = true }); From b73581b7451cf152a3523238d898b08734bcbd12 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Thu, 5 Dec 2024 15:42:15 +0200 Subject: [PATCH 19/26] Looking around the map in tutorial --- dat/tut-1.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dat/tut-1.lua b/dat/tut-1.lua index 06b676117..2136056bc 100644 --- a/dat/tut-1.lua +++ b/dat/tut-1.lua @@ -103,7 +103,7 @@ des.door({ coord = { 5,10 }, state = "locked" }); tut_key_help(6, 8); -des.engraving({ coord = { 5,12 }, type = "engrave", text = "Look around the map with '" .. tut_key("glance") .. "'", degrade = false }); +des.engraving({ coord = { 5,12 }, type = "engrave", text = "Look around the map with '" .. tut_key("glance") .. "', press ESC when you're done", degrade = false }); -- From 4b15085bb19847c70ae53770dd3442c2454d5feb Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Thu, 5 Dec 2024 16:12:59 +0200 Subject: [PATCH 20/26] Avoid naming Vlad's entourage if vampires are genocided --- dat/tower1.lua | 11 ++++++++--- doc/lua.adoc | 9 +++++++++ src/nhlua.c | 23 +++++++++++++++++++++++ 3 files changed, 40 insertions(+), 3 deletions(-) diff --git a/dat/tower1.lua b/dat/tower1.lua index c968b707c..8aab0a7ad 100644 --- a/dat/tower1.lua +++ b/dat/tower1.lua @@ -37,9 +37,14 @@ des.monster("V",niches[3]) -- gave them titles rather than (or perhaps in addition to) specific names -- and we use those titles here. Marking them as 'waiting' forces them to -- start in vampire form instead of vampshifted into bat/fog/wolf form. -des.monster({ id="Vampire Lady", niches[4], name="Madame", waiting=1 }) -des.monster({ id="Vampire Lady", niches[5], name="Marquise", waiting=1 }) -des.monster({ id="Vampire Lady", niches[6], name="Countess", waiting=1 }) +local Vgenod = nh.is_genocided("vampire"); +local Vnames = { nil, nil, nil }; +if (not Vgenod) then + Vnames = { "Madame", "Marquise", "Countess" }; +end +des.monster({ id="Vampire Lady", niches[4], name=Vnames[1], waiting=1 }) +des.monster({ id="Vampire Lady", niches[5], name=Vnames[2], waiting=1 }) +des.monster({ id="Vampire Lady", niches[6], name=Vnames[3], waiting=1 }) -- The doors des.door("closed",08,03) des.door("closed",10,03) diff --git a/doc/lua.adoc b/doc/lua.adoc index 66983807d..eea32e7d7 100644 --- a/doc/lua.adoc +++ b/doc/lua.adoc @@ -249,6 +249,15 @@ Example: local str = nh.ing_suffix("foo"); +=== is_genocided + +Is specific monster type genocided? Returns a boolean value. + +Example: + + local x = nh.is_genocided("vampire"); + + === level_difficulty Returns an integer value describing the level difficulty. diff --git a/src/nhlua.c b/src/nhlua.c index becef1302..dc2c64911 100644 --- a/src/nhlua.c +++ b/src/nhlua.c @@ -64,6 +64,7 @@ staticfn int nhl_an(lua_State *); staticfn int nhl_rn2(lua_State *); staticfn int nhl_random(lua_State *); staticfn int nhl_level_difficulty(lua_State *); +staticfn int nhl_is_genocided(lua_State *); staticfn void init_nhc_data(lua_State *); staticfn int nhl_push_anything(lua_State *, int, void *); staticfn int nhl_meta_u_index(lua_State *); @@ -954,6 +955,27 @@ nhl_level_difficulty(lua_State *L) return 1; } +/* local x = nh.is_genocided("vampire") */ +staticfn int +nhl_is_genocided(lua_State *L) +{ + int argc = lua_gettop(L); + + if (argc == 1) { + const char *paramstr = luaL_checkstring(L, 1); + int mgend; + int i = name_to_mon(paramstr, &mgend); + + lua_pushboolean(L, (i != NON_PM) + && (svm.mvitals[i].mvflags & G_GENOD) + ? TRUE : FALSE); + } else { + nhl_error(L, "Wrong args"); + } + return 1; +} + + RESTORE_WARNING_UNREACHABLE_CODE /* get mandatory integer value from table */ @@ -1722,6 +1744,7 @@ static const struct luaL_Reg nhl_functions[] = { { "rn2", nhl_rn2 }, { "random", nhl_random }, { "level_difficulty", nhl_level_difficulty }, + { "is_genocided", nhl_is_genocided }, { "parse_config", nhl_parse_config }, { "get_config", nhl_get_config }, { "get_config_errors", l_get_config_errors }, From 9b4f38eebe8c08e2fa4dae583515b59913caf9b2 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Thu, 5 Dec 2024 16:44:05 +0200 Subject: [PATCH 21/26] Blessed scroll of taming increases tameness of pets --- doc/fixes3-7-0.txt | 1 + src/read.c | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index 40f9c5219..d4214446c 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -1484,6 +1484,7 @@ when hero who is poly'd into metallivore form eats a tin, bypass "smells like digging in ice was handled inconsistently, particularly if done at the span spot in front of closed drawbridge angry god may remove an intrinsic +blessed scroll of taming increases tameness of already tame creatures Fixes to 3.7.0-x General Problems Exposed Via git Repository diff --git a/src/read.c b/src/read.c index 4110894ae..e489ea092 100644 --- a/src/read.c +++ b/src/read.c @@ -1038,6 +1038,12 @@ maybe_tame(struct monst *mtmp, struct obj *sobj) not tame the target, so call it even if taming gets resisted */ if (!resist(mtmp, sobj->oclass, 0, NOTELL) || mtmp->isshk) (void) tamedog(mtmp, (struct obj *) 0, FALSE); + if (sobj->blessed && was_tame && mtmp->mtame) { + int new_tame = min(10, ACURR(A_CHA) / 2); + + if (mtmp->mtame < new_tame) + mtmp->mtame = new_tame; + } if ((!was_peaceful && mtmp->mpeaceful) || (!was_tame && mtmp->mtame)) return 1; } From e23e6ef235d1c8a6bcb5162e746878a2b6a1d1a9 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Fri, 6 Dec 2024 11:09:23 +0200 Subject: [PATCH 22/26] Blessed scroll of destroy armor asks which armor to destroy via xNetHack with some slight modifications. --- doc/fixes3-7-0.txt | 1 + include/extern.h | 2 ++ src/do_wear.c | 27 +++++++++++++++++++++++++++ src/read.c | 15 +++++++++++++++ 4 files changed, 45 insertions(+) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index d4214446c..77ed9ba7a 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -1485,6 +1485,7 @@ digging in ice was handled inconsistently, particularly if done at the span spot in front of closed drawbridge angry god may remove an intrinsic blessed scroll of taming increases tameness of already tame creatures +blessed scroll of destroy armor asks which armor to destroy Fixes to 3.7.0-x General Problems Exposed Via git Repository diff --git a/include/extern.h b/include/extern.h index 7de27aee2..c7ccd2856 100644 --- a/include/extern.h +++ b/include/extern.h @@ -732,6 +732,8 @@ extern int remarm_swapwep(void); extern int destroy_arm(struct obj *); extern void adj_abon(struct obj *, schar) NONNULLARG1; extern boolean inaccessible_equipment(struct obj *, const char *, boolean); +extern int any_worn_armor_ok(struct obj *); +extern int count_worn_armor(void); /* ### dog.c ### */ diff --git a/src/do_wear.c b/src/do_wear.c index 1b5b57dfd..289d7d743 100644 --- a/src/do_wear.c +++ b/src/do_wear.c @@ -3367,4 +3367,31 @@ takeoff_ok(struct obj *obj) return equip_ok(obj, TRUE, FALSE); } +/* getobj callback for blessed destroy armor. + suggest any worn armor, even if covered by other armor */ +int +any_worn_armor_ok(struct obj *obj) +{ + if (obj && (obj->owornmask & W_ARMOR)) + return GETOBJ_SUGGEST; + return GETOBJ_EXCLUDE; +} + +/* number of armor pieces worn by hero */ +int +count_worn_armor(void) +{ + int ret = 0; + + if (uarm) ret++; + if (uarmc) ret++; + if (uarmh) ret++; + if (uarms) ret++; + if (uarmg) ret++; + if (uarmf) ret++; + if (uarmu) ret++; + + return ret; +} + /*do_wear.c*/ diff --git a/src/read.c b/src/read.c index e489ea092..565ce90ea 100644 --- a/src/read.c +++ b/src/read.c @@ -1279,6 +1279,21 @@ seffect_destroy_armor(struct obj **sobjp) return; } if (!scursed || !otmp || !otmp->cursed) { + boolean gets_choice = (otmp && sobj && sobj->blessed + && count_worn_armor() > 1); + + if (gets_choice) { + struct obj *atmp; + + if (!objects[sobj->otyp].oc_name_known) + pline("This is %s!", an(actualoname(sobj))); + gk.known = TRUE; + atmp = getobj("destroy", any_worn_armor_ok, GETOBJ_PROMPT); + /* check the return value, if user picked non-valid obj */ + if (any_worn_armor_ok(atmp) == GETOBJ_SUGGEST) + otmp = atmp; + } + if (!destroy_arm(otmp)) { strange_feeling(sobj, "Your skin itches."); *sobjp = 0; /* useup() in strange_feeling() */ From d318d2a48942852365404a96576315dad8ba8551 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Fri, 6 Dec 2024 16:58:01 +0200 Subject: [PATCH 23/26] Code formatting nit --- win/curses/cursmesg.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/win/curses/cursmesg.c b/win/curses/cursmesg.c index c041ecde7..2709d592a 100644 --- a/win/curses/cursmesg.c +++ b/win/curses/cursmesg.c @@ -276,7 +276,8 @@ curscolor(int nhcolor, boolean *boldon) } #endif -void curses_got_input(void) +void +curses_got_input(void) { /* if messages are being suppressed, reenable them */ curs_mesg_suppress_seq = -1L; From 5eb7566ebaaab6b33b43a80c093e1d44bfdeafee Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Fri, 6 Dec 2024 17:36:31 +0200 Subject: [PATCH 24/26] Prevent two possible ways to die in the tutorial --- dat/tut-1.lua | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/dat/tut-1.lua b/dat/tut-1.lua index 2136056bc..f6a31cf82 100644 --- a/dat/tut-1.lua +++ b/dat/tut-1.lua @@ -220,7 +220,7 @@ des.door({ coord = { 38,6 }, state = "closed" }); des.engraving({ coord = { 39,6 }, type = "engrave", text = "You loot containers with '" .. tut_key("loot") .. "'", degrade = false }); -des.object({ coord = { 42,6 }, id = "large box", broken = true, +des.object({ coord = { 42,6 }, id = "large box", broken = true, trapped = false, contents = function(obj) des.object({ id = "secret door detection", class = "/", spe = 30 }); end }); @@ -248,8 +248,7 @@ des.engraving({ coord = { 48,1 }, type = "burn", text = "Use '" .. tut_key("eat" des.object({ coord = { 50,3 }, id = "apple", buc = "not-cursed" }); des.object({ coord = { 50,3 }, id = "candy bar", buc = "not-cursed" }); -local otmp = des.object({ coord = { 50,3 }, id = "corpse", montype = "newt", buc = "not-cursed" }); -otmp:stop_timer("rot-corpse"); +des.object({ coord = { 50,3 }, id = "corpse", montype = "lichen", buc = "not-cursed" }); -- From 89c4c3a72222da201cd35c4da4fa9bc213868331 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Fri, 6 Dec 2024 21:26:47 +0200 Subject: [PATCH 25/26] Tourists gain experience by seeing new types of creatures up close Experience equivalent to killing a monster is gained when starting a turn adjacent to and being able to see the monster. Breaks saves. Idea and parts of code via dNetHack --- doc/fixes3-7-0.txt | 1 + include/hack.h | 1 + include/patchlevel.h | 2 +- src/allmain.c | 24 ++++++++++++++++++++++++ 4 files changed, 27 insertions(+), 1 deletion(-) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index 77ed9ba7a..c68890634 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -2730,6 +2730,7 @@ enlightenment/attribute disclosure for saving-grace: include a line for have "X " for explore mode, or "D " for debug mode if any of the games shown in its menu weren't saved during normal play; if they're all normal play, the prefix is suppressed +tourists gain experience by seeing new types of creatures up close Platform- and/or Interface-Specific New Features diff --git a/include/hack.h b/include/hack.h index 0851da3ef..40b4d4ada 100644 --- a/include/hack.h +++ b/include/hack.h @@ -673,6 +673,7 @@ struct mvitals { uchar born; uchar died; uchar mvflags; + Bitfield(seen_close, 1); }; diff --git a/include/patchlevel.h b/include/patchlevel.h index 3f1d88e81..41708bc86 100644 --- a/include/patchlevel.h +++ b/include/patchlevel.h @@ -17,7 +17,7 @@ * Incrementing EDITLEVEL can be used to force invalidation of old bones * and save files. */ -#define EDITLEVEL 110 +#define EDITLEVEL 111 /* * Development status possibilities. diff --git a/src/allmain.c b/src/allmain.c index 253ac82a4..b8de1f7a5 100644 --- a/src/allmain.c +++ b/src/allmain.c @@ -14,6 +14,7 @@ staticfn void moveloop_preamble(boolean); staticfn void u_calc_moveamt(int); +staticfn void see_nearby_monsters(void); staticfn void maybe_do_tutorial(void); #ifdef POSITIONBAR staticfn void do_positionbar(void); @@ -154,6 +155,28 @@ u_calc_moveamt(int wtcap) u.umovement = 0; } +/* mark a monster type as seen when we see it next to us */ +staticfn void +see_nearby_monsters(void) +{ + coordxy x, y; + + if (Blind || !Role_if(PM_TOURIST)) + return; + + for (x = u.ux - 1; x <= u.ux + 1; x++) + for (y = u.uy - 1; y <= u.uy + 1; y++) + if (isok(x, y) && MON_AT(x, y)) { + struct monst *mtmp = m_at(x, y); + + if (canseemon(mtmp) && !svm.mvitals[monsndx(mtmp->data)].seen_close) { + svm.mvitals[monsndx(mtmp->data)].seen_close = TRUE; + more_experienced(experience(mtmp, 0), 0); + newexplevel(); + } + } +} + #if defined(MICRO) || defined(WIN32) static int mvl_abort_lev; #endif @@ -410,6 +433,7 @@ moveloop_core(void) else if (u.uburied) under_ground(0); + see_nearby_monsters(); } /* actual time passed */ /****************************************/ From 12228cac498f86617bb74998ed4ddae56d6c3c0d Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Fri, 6 Dec 2024 22:10:17 +0200 Subject: [PATCH 26/26] Tourists gain experience by going to new dungeon levels --- doc/fixes3-7-0.txt | 3 ++- src/do.c | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index c68890634..2e56f3f83 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -2730,7 +2730,8 @@ enlightenment/attribute disclosure for saving-grace: include a line for have "X " for explore mode, or "D " for debug mode if any of the games shown in its menu weren't saved during normal play; if they're all normal play, the prefix is suppressed -tourists gain experience by seeing new types of creatures up close +tourists gain experience by seeing new types of creatures up close, and + going to new dungeon levels Platform- and/or Interface-Specific New Features diff --git a/src/do.c b/src/do.c index fe07407c1..43376b529 100644 --- a/src/do.c +++ b/src/do.c @@ -1946,6 +1946,11 @@ goto_level( (void) describe_level(dloc, 2); livelog_printf(major ? LL_ACHIEVE : LL_DEBUG, "entered %s", dloc); + + if (Role_if(PM_TOURIST)) { + more_experienced(level_difficulty(), 0); + newexplevel(); + } } assign_level(&u.uz0, &u.uz); /* reset u.uz0 */