From 6f8c36df70065f94feb23086dfacb412c0e7f811 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 5 Oct 2024 10:54:54 -0400 Subject: [PATCH 001/791] copy_bytes() recover function The version of copy_bytes() in util/recover.c had fallen behind the internal version in files.c which had received some analyzer changes in 4bc5e260823db78bc3feeea1770d5aa564af45db from December 2022. This synchronizes them, and addresses a couple of other static analysis recommendations. --- src/files.c | 3 ++- util/recover.c | 12 ++++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/files.c b/src/files.c index e522bc4e0..d353093a1 100644 --- a/src/files.c +++ b/src/files.c @@ -4456,9 +4456,10 @@ boolean copy_bytes(int ifd, int ofd) { char buf[BUFSIZ]; - int nfrom, nto = 0; + int nfrom, nto; do { + nto = 0; nfrom = read(ifd, buf, BUFSIZ); /* read can return -1 */ if (nfrom >= 0 && nfrom <= BUFSIZ) diff --git a/util/recover.c b/util/recover.c index 08d8258c9..cd4cf80ff 100644 --- a/util/recover.c +++ b/util/recover.c @@ -201,9 +201,12 @@ copy_bytes(int ifd, int ofd) int nfrom, nto; do { + nto = 0; nfrom = read(ifd, buf, BUFSIZ); - nto = write(ofd, buf, nfrom); - if (nto != nfrom) { + /* read can return -1 */ + if (nfrom >= 0 && nfrom <= BUFSIZ) + nto = write(ofd, buf, nfrom); + if (nto != nfrom || nfrom < 0) { Fprintf(stderr, "file copy failed!\n"); exit(EXIT_FAILURE); } @@ -333,6 +336,7 @@ restore_savefile(char *basename) return -1; } + assert((size_t) pltmpsiz <= sizeof plbuf); if (write(sfd, (genericptr_t) plbuf, pltmpsiz) != pltmpsiz) { Fprintf(stderr, "Error writing %s; recovery failed (player name).\n", savename); @@ -404,8 +408,8 @@ store_formatindicator(int fd) char indicate = 'h'; /* historical */ int cmc = 0; - write(fd, (genericptr_t) &indicate, sizeof indicate); - write(fd, (genericptr_t) &cmc, sizeof cmc); + (void) write(fd, (genericptr_t) &indicate, sizeof indicate); + (void) write(fd, (genericptr_t) &cmc, sizeof cmc); } From fb70aadbb5f2757d6861665cba7e449cd2807b74 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 5 Oct 2024 15:55:20 -0400 Subject: [PATCH 002/791] improve copy_bytes() maintenance Remove the copy_bytes() function from files.c and util/recover.c and place a single copy into hacklib. --- include/hacklib.h | 2 +- src/files.c | 22 ---------- src/hacklib.c | 18 ++++++++ sys/msdos/Makefile.GCC | 4 +- sys/unix/Makefile.utl | 2 +- sys/unix/NetHack.xcodeproj/project.pbxproj | 1 + sys/windows/Makefile.mingw32 | 2 +- sys/windows/Makefile.nmake | 9 ++-- sys/windows/vs/recover/recover.vcxproj | 6 ++- util/recover.c | 49 ++++++++++------------ 10 files changed, 57 insertions(+), 58 deletions(-) diff --git a/include/hacklib.h b/include/hacklib.h index 5bea79023..2912035a4 100644 --- a/include/hacklib.h +++ b/include/hacklib.h @@ -78,7 +78,7 @@ extern void nh_snprintf_w_impossible(const char *func, int line, char *str, extern unsigned Strlen_(const char *, const char *, int) NONNULLPTRS; #endif extern int unicodeval_to_utf8str(int, uint8 *, size_t); - +extern boolean copy_bytes(int, int); #endif /* HACKLIB_H */ diff --git a/src/files.c b/src/files.c index d353093a1..2a98a2f5c 100644 --- a/src/files.c +++ b/src/files.c @@ -230,10 +230,6 @@ staticfn void wizkit_addinv(struct obj *); boolean proc_wizkit_line(char *buf); void read_wizkit(void); /* in extern.h; why here too? */ staticfn FILE *fopen_sym_file(void); - -#ifdef SELF_RECOVER -staticfn boolean copy_bytes(int, int); -#endif staticfn NHFILE *viable_nhfile(NHFILE *); /* return a file's name without its path and optionally trailing 'type' */ @@ -4452,24 +4448,6 @@ recover_savefile(void) return TRUE; } -boolean -copy_bytes(int ifd, int ofd) -{ - char buf[BUFSIZ]; - int nfrom, nto; - - do { - nto = 0; - nfrom = read(ifd, buf, BUFSIZ); - /* read can return -1 */ - if (nfrom >= 0 && nfrom <= BUFSIZ) - nto = write(ofd, buf, nfrom); - if (nto != nfrom || nfrom < 0) - return FALSE; - } while (nfrom == BUFSIZ); - return TRUE; -} - /* ---------- END INTERNAL RECOVER ----------- */ #endif /*SELF_RECOVER*/ diff --git a/src/hacklib.c b/src/hacklib.c index 8b78daff7..5b61c21ea 100644 --- a/src/hacklib.c +++ b/src/hacklib.c @@ -936,4 +936,22 @@ case_insensitive_comp(const char *s1, const char *s2) return u1 - u2; } +boolean +copy_bytes(int ifd, int ofd) +{ + char buf[BUFSIZ]; + int nfrom, nto; + + do { + nto = 0; + nfrom = read(ifd, buf, BUFSIZ); + /* read can return -1 */ + if (nfrom >= 0 && nfrom <= BUFSIZ) + nto = write(ofd, buf, nfrom); + if (nto != nfrom || nfrom < 0) + return FALSE; + } while (nfrom == BUFSIZ); + return TRUE; +} + /*hacklib.c*/ diff --git a/sys/msdos/Makefile.GCC b/sys/msdos/Makefile.GCC index 52272f5d8..6b4a7cc6f 100644 --- a/sys/msdos/Makefile.GCC +++ b/sys/msdos/Makefile.GCC @@ -702,8 +702,8 @@ $(O)hacklibu.o: $(CONFIG_H) $(SRC)/hacklib.c # Recover Utility #========================================== -$(U)recover.exe: $(RECOVOBJS) - $(LINK) $(LFLAGS) -o$@ $(O)recover.o +$(U)recover.exe: $(RECOVOBJS) $(HACKLIB) + $(LINK) $(LFLAGS) -o$@ $(O)recover.o $(HACKLIB) $(O)recover.o: $(CONFIG_H) $(U)recover.c $(CC) $(cflags) -o$@ $(U)recover.c diff --git a/sys/unix/Makefile.utl b/sys/unix/Makefile.utl index 25b1f65e8..e01949fa9 100644 --- a/sys/unix/Makefile.utl +++ b/sys/unix/Makefile.utl @@ -278,7 +278,7 @@ lintdgn: # dependencies for recover # $(TARGETPFX)recover: $(RECOVOBJS) - $(TARGET_CLINK) $(TARGET_LFLAGS) -o recover $(RECOVOBJS) $(LIBS) + $(TARGET_CLINK) $(TARGET_LFLAGS) -o recover $(RECOVOBJS) $(HACKLIB) $(LIBS) $(TARGETPFX)recover.o: recover.c $(CONFIG_H) $(TARGET_CC) $(TARGET_CFLAGS) $(CSTD) -c recover.c -o $@ diff --git a/sys/unix/NetHack.xcodeproj/project.pbxproj b/sys/unix/NetHack.xcodeproj/project.pbxproj index cc4463319..8e8caa1a5 100644 --- a/sys/unix/NetHack.xcodeproj/project.pbxproj +++ b/sys/unix/NetHack.xcodeproj/project.pbxproj @@ -1872,6 +1872,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 059660BE2C80B00400398EDE /* hacklib.c in Sources */, 31B8A45221A26A750055BD01 /* recover.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/sys/windows/Makefile.mingw32 b/sys/windows/Makefile.mingw32 index 0c9a91e34..2ac83fa5b 100644 --- a/sys/windows/Makefile.mingw32 +++ b/sys/windows/Makefile.mingw32 @@ -523,7 +523,7 @@ recover: $(RTARGETS) $(GAMEDIR)/recover.txt: $(DOC)/recover.txt | $(GAMEDIR) cp $< $@ -$(GAMEDIR)/recover.exe: $(ROBJS) | $(GAMEDIR) +$(GAMEDIR)/recover.exe: $(ROBJS) $(HLHACKLIB) | $(GAMEDIR) $(ld) $(LDFLAGS) $^ -o$@ $(OR)/recover.o: $(U)recover.c | $(OR) diff --git a/sys/windows/Makefile.nmake b/sys/windows/Makefile.nmake index 0fd85885d..a2f62bb23 100644 --- a/sys/windows/Makefile.nmake +++ b/sys/windows/Makefile.nmake @@ -9,7 +9,7 @@ # # Visual Studio Compilers Tested: # - Microsoft Visual Studio 2019 Community Edition v 16.11.38 -# - Microsoft Visual Studio 2022 Community Edition v 17.11.2 +# - Microsoft Visual Studio 2022 Community Edition v 17.11.4 # #============================================================================== # This is used for building two distinct executables of NetHack: @@ -1538,7 +1538,7 @@ binary.tag: $(DAT)\data $(DAT)\rumors $(DAT)\oracles $(DLB) \ # copy $(MSWSYS)\windsyshlp $(GAMEDIR) -recover: $(U)recover.exe +recover: $(OUTLHACKLIB) $(U)recover.exe if exist $(U)recover.exe copy $(U)recover.exe $(GAMEDIR) if exist $(DOC)\recover.txt copy $(DOC)\recover.txt $(GAMEDIR)\recover.txt @@ -1892,9 +1892,10 @@ nhdat$(NHV): $(U)dlb.exe $(DAT)\data $(DAT)\oracles $(OPTIONS_FILE) $(LUA_FILES) # Recover Utility #========================================== -$(U)recover.exe: $(RECOVOBJS) +$(U)recover.exe: $(RECOVOBJS) $(OUTLHACKLIB) @echo Linking $(@:\=/) - @$(link) $(LFLAGS) /PDB:"$(OUTL)$(@B).PDB" /MAP:"$(OUTL)$(@B).MAP" -out:$@ $(RECOVOBJS) + @$(link) $(LFLAGS) /PDB:"$(OUTL)$(@B).PDB" /MAP:"$(OUTL)$(@B).MAP" \ + -out:$@ $(RECOVOBJS) $(OUTLHACKLIB) $(OUTL)recover.o: $(CONFIG_H) $(U)recover.c $(MSWSYS)\win32api.h $(Q)$(CC) $(CFLAGS) $(TTYDEF) -Fo$@ $(U)recover.c diff --git a/sys/windows/vs/recover/recover.vcxproj b/sys/windows/vs/recover/recover.vcxproj index a3697a4b0..1e108fcfc 100644 --- a/sys/windows/vs/recover/recover.vcxproj +++ b/sys/windows/vs/recover/recover.vcxproj @@ -21,6 +21,10 @@ $(IncDir);$(SysWindDir);$(LuaDir);%(AdditionalIncludeDirectories) WIN32CON;DLB;MSWIN_GRAPHICS;HAS_STDINT_H;%(PreprocessorDefinitions) + + $(ToolsDir);%(AdditionalLibraryDirectories) + hacklib.lib;%(AdditionalDependencies) + @@ -44,4 +48,4 @@ - \ No newline at end of file + diff --git a/util/recover.c b/util/recover.c index cd4cf80ff..6619e0a70 100644 --- a/util/recover.c +++ b/util/recover.c @@ -13,6 +13,8 @@ #endif #include "config.h" +#include "hacklib.h" + #if !defined(O_WRONLY) && !defined(LSC) && !defined(AZTEC_C) #include #endif @@ -26,11 +28,12 @@ extern int vms_open(const char *, int, unsigned); #define nhUse(arg) (void)(arg) #endif +/* copy_bytes() has been moved to hacklib */ + int restore_savefile(char *); void set_levelfile_name(int); int open_levelfile(int); int create_savefile(void); -void copy_bytes(int, int); static void store_formatindicator(int); #ifndef WIN_CE @@ -194,25 +197,6 @@ create_savefile(void) return fd; } -void -copy_bytes(int ifd, int ofd) -{ - char buf[BUFSIZ]; - int nfrom, nto; - - do { - nto = 0; - nfrom = read(ifd, buf, BUFSIZ); - /* read can return -1 */ - if (nfrom >= 0 && nfrom <= BUFSIZ) - nto = write(ofd, buf, nfrom); - if (nto != nfrom || nfrom < 0) { - Fprintf(stderr, "file copy failed!\n"); - exit(EXIT_FAILURE); - } - } while (nfrom == BUFSIZ); -} - int restore_savefile(char *basename) { @@ -346,11 +330,17 @@ restore_savefile(char *basename) return -1; } - copy_bytes(lfd, sfd); + if (!copy_bytes(lfd, sfd)) { + Fprintf(stderr, "file copy failed!\n"); + exit(EXIT_FAILURE); + } Close(lfd); (void) unlink(lock); - copy_bytes(gfd, sfd); + if (!copy_bytes(gfd, sfd)) { + Fprintf(stderr, "file copy failed!\n"); + exit(EXIT_FAILURE); + } Close(gfd); set_levelfile_name(0); (void) unlink(lock); @@ -365,10 +355,14 @@ restore_savefile(char *basename) /* any or all of these may not exist */ levc = (xint8) lev; if (write(sfd, (genericptr_t) &levc, sizeof levc) - != sizeof levc) + != sizeof levc) { res = -1; - else - copy_bytes(lfd, sfd); + } else { + if (!copy_bytes(lfd, sfd)) { + Fprintf(stderr, "file copy failed!\n"); + exit(EXIT_FAILURE); + } + } Close(lfd); (void) unlink(lock); } @@ -390,7 +384,10 @@ restore_savefile(char *basename) in = open("NetHack:default.icon", O_RDONLY); out = open(iconfile, O_WRONLY | O_TRUNC | O_CREAT); if (in > -1 && out > -1) { - copy_bytes(in, out); + if (!copy_bytes(in, out)) { + Fprintf(stderr, "file copy failed!\n"); + exit(EXIT_FAILURE); + } } if (in > -1) close(in); From 575030548ab4aeaecc2a598db2f92879a5fe444c Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 5 Oct 2024 16:48:52 -0400 Subject: [PATCH 003/791] repair msdos cross-compile --- sys/unix/Makefile.utl | 5 +++-- sys/unix/hints/include/cross-post.370 | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/sys/unix/Makefile.utl b/sys/unix/Makefile.utl index e01949fa9..c2b40bd87 100644 --- a/sys/unix/Makefile.utl +++ b/sys/unix/Makefile.utl @@ -277,8 +277,9 @@ lintdgn: # dependencies for recover # -$(TARGETPFX)recover: $(RECOVOBJS) - $(TARGET_CLINK) $(TARGET_LFLAGS) -o recover $(RECOVOBJS) $(HACKLIB) $(LIBS) +$(TARGETPFX)recover: $(RECOVOBJS) $(TARGETPFX)$(HACKLIB) + $(TARGET_CLINK) $(TARGET_LFLAGS) -o recover \ + $(RECOVOBJS) $(TARGETPFX)$(HACKLIB) $(LIBS) $(TARGETPFX)recover.o: recover.c $(CONFIG_H) $(TARGET_CC) $(TARGET_CFLAGS) $(CSTD) -c recover.c -o $@ diff --git a/sys/unix/hints/include/cross-post.370 b/sys/unix/hints/include/cross-post.370 index 557b3504a..b4d8c759c 100644 --- a/sys/unix/hints/include/cross-post.370 +++ b/sys/unix/hints/include/cross-post.370 @@ -145,8 +145,9 @@ $(TARGETPFX)tileset.o : ../win/share/tileset.c $(TARGETPFX)bmptiles.o : ../win/share/bmptiles.c $(TARGETPFX)giftiles.o : ../win/share/giftiles.c $(TARGETPFX)recover.o : ../util/recover.c -$(TARGETPFX)recover.exe : $(TARGETPFX)recover.o - $(TARGET_LINK) $(TARGET_LFLAGS) $(TARGETPFX)recover.o -o $@ +$(TARGETPFX)recover.exe : $(TARGETPFX)recover.o $(TARGETPFX)hacklib.a + $(TARGET_LINK) $(TARGET_LFLAGS) \ + $(TARGETPFX)recover.o $(TARGETPFX)hacklib.a -o $@ endif # CROSS_SHARED # ifdef CROSS From b61c3e51382dcd478c5733766d5d6e43ca389b4c Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 5 Oct 2024 17:40:03 -0400 Subject: [PATCH 004/791] repair msdos cross-compile (take 2) --- sys/unix/hints/include/cross-post.370 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sys/unix/hints/include/cross-post.370 b/sys/unix/hints/include/cross-post.370 index b4d8c759c..8bbf00a5e 100644 --- a/sys/unix/hints/include/cross-post.370 +++ b/sys/unix/hints/include/cross-post.370 @@ -42,7 +42,7 @@ $(DOSFONT)/ter-u28b.psf: $(FONTTOP)/ter-u28b.bdf $(DOSFONT)/nh-u28b.bdf $(DOSFON $(DOSFONT)/ter-u32b.psf: $(FONTTOP)/ter-u32b.bdf $(DOSFONT)/nh-u32b.bdf $(DOSFONT)/makefont.lua $(LUABIN) $(LUABIN) $(DOSFONT)/makefont.lua $(FONTTOP)/ter-u32b.bdf $(DOSFONT)/nh-u32b.bdf $@ # -.PHONY: dodata dospkg dosfonts +.PHONY: dodata dospkg dosfonts recover dosfonts: $(FONTTARGETS) dospkg: dodata dosfonts $(GAMEBIN) $(TARGETPFX)recover.exe ../dat/nhtiles.bmp $(TARGET_STUBEDIT) $(GAMEBIN) minstack=2048K @@ -145,14 +145,14 @@ $(TARGETPFX)tileset.o : ../win/share/tileset.c $(TARGETPFX)bmptiles.o : ../win/share/bmptiles.c $(TARGETPFX)giftiles.o : ../win/share/giftiles.c $(TARGETPFX)recover.o : ../util/recover.c -$(TARGETPFX)recover.exe : $(TARGETPFX)recover.o $(TARGETPFX)hacklib.a - $(TARGET_LINK) $(TARGET_LFLAGS) \ - $(TARGETPFX)recover.o $(TARGETPFX)hacklib.a -o $@ endif # CROSS_SHARED # ifdef CROSS $(TARGETPFX)hacklib.a: $(TARGETPFX)hacklib.o $(TARGET_AR) $(TARGET_ARFLAGS) $@ $(TARGETPFX)hacklib.o +$(TARGETPFX)recover.exe : $(TARGETPFX)recover.o $(TARGETPFX)hacklib.a + $(TARGET_LINK) $(TARGET_LFLAGS) \ + $(TARGETPFX)recover.o $(TARGETPFX)hacklib.a -o $@ endif ifdef BUILD_TARGET_LUA # Lua lib From 5abee166f559251a8df4feb405c0d70ee9053d6b Mon Sep 17 00:00:00 2001 From: PatR Date: Sat, 5 Oct 2024 15:48:44 -0700 Subject: [PATCH 005/791] makelevel() oddity There must have been a reason once to guard against calling makelevel() when the dungeon hasn't been initialized yet, but that doesn't seem to be necessary these days. Calling Is_special() before init_dungeons() is clearly a bug, so fix that. --- src/mklev.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/mklev.c b/src/mklev.c index d4205b12a..1e8a6f703 100644 --- a/src/mklev.c +++ b/src/mklev.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 mklev.c $NHDT-Date: 1704830831 2024/01/09 20:07:11 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.175 $ */ +/* NetHack 3.7 mklev.c $NHDT-Date: 1728168518 2024/10/05 22:48:38 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.191 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Alex Smith, 2017. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1105,14 +1105,17 @@ makelevel(void) branch *branchp; stairway *prevstairs; int room_threshold; - s_level *slev = Is_special(&u.uz); + s_level *slev; int i; - if (wiz1_level.dlevel == 0) + if (wiz1_level.dlevel == 0) { + impossible("makelevel() called when dungeon not yet initialized."); init_dungeons(); + } oinit(); /* assign level dependent obj probabilities */ clear_level_structures(); + slev = Is_special(&u.uz); /* check for special levels */ if (slev && !Is_rogue_level(&u.uz)) { makemaz(slev->proto); From 0e68118c53eebaaad0d8c4e3d4b58c0f6e8a379b Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 6 Oct 2024 09:02:01 -0400 Subject: [PATCH 006/791] follow-up: Makefile_utl.vms --- sys/vms/Makefile_utl.vms | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sys/vms/Makefile_utl.vms b/sys/vms/Makefile_utl.vms index 2585b1bb4..4c845194a 100644 --- a/sys/vms/Makefile_utl.vms +++ b/sys/vms/Makefile_utl.vms @@ -193,8 +193,9 @@ panic.obj: panic.c $(CONFIG_H) # # dependencies for recover # -$(TARGETPFX)recover.exe: $(RECOVOBJS) - $(TARGET_CLINK) $(TARGET_LFLAGS) /EXE=$@ $(RECOVOBJS) $(LIBS) +$(TARGETPFX)recover.exe: $(HACKLIB) $(RECOVOBJS) + $(TARGET_CLINK) $(TARGET_LFLAGS) /EXE=$@ \ + $(RECOVOBJS),$(HACKLIB)/lib $(LIBS) $(TARGETPFX)recover.obj: recover.c $(CONFIG_H) $(TARGET_CC) $(TARGET_CFLAGS) $(CSTD) recover.c /OBJ=$@ From 19d8ec6d1213cc875daf5e8c9648af02c3e50237 Mon Sep 17 00:00:00 2001 From: nhmall Date: Tue, 8 Oct 2024 11:32:58 -0400 Subject: [PATCH 007/791] address Windows consoletty.c analyzer complaints sys/windows/consoletty.c: warning C6388: '&reserved' might not be '0': this does not adhere to the specification for the function 'WriteConsoleA'. sys/windows/consoletty.c(2514): warning C28159: Consider using 'IsWindows*' instead of 'GetVersion'. Reason: Deprecated. Use VerifyVersionInfo* or IsWindows* macros from VersionHelpers. --- sys/windows/consoletty.c | 87 +++++++++++++++++++--------------------- 1 file changed, 42 insertions(+), 45 deletions(-) diff --git a/sys/windows/consoletty.c b/sys/windows/consoletty.c index 770c0f19b..d88cb0881 100644 --- a/sys/windows/consoletty.c +++ b/sys/windows/consoletty.c @@ -24,6 +24,7 @@ #include "winos.h" #include "hack.h" #include "wintty.h" +#include #include #include #ifdef VIRTUAL_TERMINAL_SEQUENCES @@ -570,120 +571,120 @@ void emit_show_curor(void); void emit_hide_cursor(void) { - DWORD unused, reserved; + DWORD unused; static const char escseq[] = "\x1b[?25l"; WriteConsoleA(console.hConOut, (LPCSTR) escseq, (int) strlen(escseq), - &unused, &reserved); + &unused, NULL); } void emit_show_cursor(void) { - DWORD unused, reserved; + DWORD unused; static const char escseq[] = "\x1b[?25h"; WriteConsoleA(console.hConOut, (LPCSTR) escseq, (int) strlen(escseq), - &unused, &reserved); + &unused, NULL); } void emit_start_bold(void) { - DWORD unused, reserved; + DWORD unused; static const char escseq[] = "\x1b[1m"; WriteConsoleA(console.hConOut, (LPCSTR) escseq, (int) strlen(escseq), - &unused, &reserved); + &unused, NULL); } void emit_stop_bold(void) { - DWORD unused, reserved; + DWORD unused; static const char escseq[] = "\x1b[24m"; WriteConsoleA(console.hConOut, (LPCSTR) escseq, (int) strlen(escseq), - &unused, &reserved); + &unused, NULL); } #if 0 emit_start_dim(void) { - DWORD unused, reserved; + DWORD unused; static const char escseq[] = "\x1b[4m"; WriteConsoleA(console.hConOut, (LPCSTR) escseq, (int) strlen(escseq), - &unused, &reserved); + &unused, NULL); } void emit_stop_dim(void) { - DWORD unused, reserved; + DWORD unused; static const char escseq[] = "\x1b[24m"; WriteConsoleA(console.hConOut, (LPCSTR) escseq, (int) strlen(escseq), - &unused, &reserved); + &unused, NULL); } #endif void emit_start_blink(void) { - DWORD unused, reserved; + DWORD unused; static const char escseq[] = "\x1b[5m"; WriteConsoleA(console.hConOut, (LPCSTR) escseq, (int) strlen(escseq), - &unused, &reserved); + &unused, NULL); } void emit_stop_blink(void) { - DWORD unused, reserved; + DWORD unused; static const char escseq[] = "\x1b[25m"; WriteConsoleA(console.hConOut, (LPCSTR) escseq, (int) strlen(escseq), - &unused, &reserved); + &unused, NULL); } void emit_start_underline(void) { - DWORD unused, reserved; + DWORD unused; static const char escseq[] = "\x1b[4m"; WriteConsoleA(console.hConOut, (LPCSTR) escseq, (int) strlen(escseq), - &unused, &reserved); + &unused, NULL); } void emit_stop_underline(void) { - DWORD unused, reserved; + DWORD unused; static const char escseq[] = "\x1b[24m"; WriteConsoleA(console.hConOut, (LPCSTR) escseq, (int) strlen(escseq), - &unused, &reserved); + &unused, NULL); } void emit_start_inverse(void) { - DWORD unused, reserved; + DWORD unused; static const char escseq[] = "\x1b[7m"; WriteConsoleA(console.hConOut, (LPCSTR) escseq, (int) strlen(escseq), - &unused, &reserved); + &unused, NULL); } void emit_stop_inverse(void) { - DWORD unused, reserved; + DWORD unused; static const char escseq[] = "\x1b[27m"; WriteConsoleA(console.hConOut, (LPCSTR) escseq, (int) strlen(escseq), - &unused, &reserved); + &unused, NULL); } #if 0 @@ -704,17 +705,17 @@ emit_stop_inverse(void) void emit_start_256color(int u256coloridx) { - DWORD unused, reserved; + DWORD unused; static char tcolorbuf[QBUFSZ]; Snprintf(tcolorbuf, sizeof tcolorbuf, tcfmtstr256, u256coloridx); WriteConsoleA(console.hConOut, (LPCSTR) tcolorbuf, - (int) strlen(tcolorbuf), &unused, &reserved); + (int) strlen(tcolorbuf), &unused, NULL); } void emit_start_24bitcolor(long color24bit) { - DWORD unused, reserved; + DWORD unused; static char tcolorbuf[QBUFSZ]; uint32 mcolor = COLORVAL(color24bit); Snprintf(tcolorbuf, sizeof tcolorbuf, tcfmtstr24bit, @@ -722,26 +723,26 @@ emit_start_24bitcolor(long color24bit) ((mcolor >> 8) & 0xFF), /* green */ ((mcolor >> 0) & 0xFF)); /* blue */ WriteConsoleA(console.hConOut, (LPCSTR) tcolorbuf, - (int) strlen(tcolorbuf), &unused, &reserved); + (int) strlen(tcolorbuf), &unused, NULL); } void emit_default_color(void) { - DWORD unused, reserved; + DWORD unused; static char escseq[] = "\x1b[39m"; WriteConsoleA(console.hConOut, (LPCSTR) escseq, (int) strlen(escseq), - &unused, &reserved); + &unused, NULL); } void emit_return_to_default(void) { - DWORD unused, reserved; + DWORD unused; static char escseq[] = "\x1b[0m"; WriteConsoleA(console.hConOut, (LPCSTR) escseq, (int) strlen(escseq), - &unused, &reserved); + &unused, NULL); } static boolean newattr_on = TRUE; static boolean color24_on = TRUE; @@ -778,7 +779,6 @@ back_buffer_flip(void) cell_t *front = console.front_buffer; COORD pos; DWORD unused; - DWORD reserved; unsigned do_anything, did_anything; if (!console.is_ready) @@ -843,13 +843,13 @@ back_buffer_flip(void) did_anything |= did_colorseq; WriteConsoleA(console.hConOut, back->colorseq, (int) strlen(back->colorseq), &unused, - &reserved); + NULL); } if (back->bkcolorseq) { did_anything |= did_bkcolorseq; WriteConsoleA(console.hConOut, back->bkcolorseq, (int) strlen(back->bkcolorseq), &unused, - &reserved); + NULL); } if ((did_anything | (did_colorseq | did_bkcolorseq | did_color24)) == 0) { did_anything &= ~(did_bkcolorseq | did_color24); @@ -862,12 +862,12 @@ back_buffer_flip(void) if (SYMHANDLING(H_UTF8) || !console.has_unicode) { WriteConsoleA(console.hConOut, (LPCSTR) back->utf8str, (int) strlen((char *) back->utf8str), - &unused, &reserved); + &unused, NULL); did_anything |= did_utf8_content; } else { #endif WriteConsoleW(console.hConOut, &back->wcharacter, 1, - &unused, &reserved); + &unused, NULL); did_anything |= did_wide_content; #ifdef UTF8_FROM_CORE } @@ -1524,9 +1524,6 @@ raw_clear_screen(void) cell_t * front = console.front_buffer; COORD pos; DWORD unused; -#ifdef VIRTUAL_TERMINAL_SEQUENCES - DWORD reserved; -#endif #ifdef VIRTUAL_TERMINAL_SEQUENCES pos.Y = 0; @@ -1552,10 +1549,10 @@ raw_clear_screen(void) *back = clear_cell; if (console.has_unicode) WriteConsoleW(console.hConOut, &back->wcharacter, 1, - &unused, &reserved); + &unused, NULL); else WriteConsoleA(console.hConOut, (LPCSTR) back->utf8str, - (int) strlen((char *) back->utf8str), &unused, &reserved); + (int) strlen((char *) back->utf8str), &unused, NULL); #endif /* VIRTUAL_TERMINAL_SEQUENCES */ *front = *back; back++; @@ -2511,7 +2508,7 @@ void nethack_enter_consoletty(void) buffer_fill_to_end(console.back_buffer, &clear_cell, 0, 0); /* determine whether OS version has unicode support */ - console.has_unicode = ((GetVersion() & 0x80000000) == 0); + console.has_unicode = (IsWindows8OrGreater()); #ifdef VIRTUAL_TERMINAL_SEQUENCES /* store the original code page*/ @@ -2651,7 +2648,7 @@ VA_DECL(const char *, fmt) if (console.cursor.Y > console.height - 4) { xputs("Hit to continue."); while (pgetchar() != '\n') - ; + ; raw_clear_screen(); set_console_cursor(1, 0); } @@ -3333,7 +3330,7 @@ is_altseq(unsigned long shiftstate) case RIGHT_ALT_PRESSED: case RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED: - return (GetVersion() & 0x80000000) == 0; + return (IsWindows8OrGreater()); default: return 0; From a70ad42d224665f2a5c5989763708073ecf7443d Mon Sep 17 00:00:00 2001 From: nhmall Date: Tue, 8 Oct 2024 11:57:46 -0400 Subject: [PATCH 008/791] address Windows windsys.c analyzer complaints sys/windows/windsys.c(419): warning C6387: 'hMod' could be '0': this does not adhere to the specification for the function 'GetProcAddress'. sys/windows/windsys.c(437): warning C28159: Consider using 'GetTickCount64' instead of 'GetTickCount'. Reason: GetTickCount overflows roughly every 49 days. Code that does not take that into account can loop indefinitely. GetTickCount64 operates on 64 bit values and does not have that problem --- sys/windows/windsys.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/sys/windows/windsys.c b/sys/windows/windsys.c index 0634796b5..77d1881bf 100644 --- a/sys/windows/windsys.c +++ b/sys/windows/windsys.c @@ -416,12 +416,14 @@ static HWND GetConsoleHandle(void) { HMODULE hMod = GetModuleHandle("kernel32.dll"); - GETCONSOLEWINDOW pfnGetConsoleWindow = - (GETCONSOLEWINDOW) GetProcAddress(hMod, "GetConsoleWindow"); - if (pfnGetConsoleWindow) - return pfnGetConsoleWindow(); - else - return GetConsoleHwnd(); + + if (hMod) { + GETCONSOLEWINDOW pfnGetConsoleWindow = + (GETCONSOLEWINDOW) GetProcAddress(hMod, "GetConsoleWindow"); + if (pfnGetConsoleWindow) + return pfnGetConsoleWindow(); + } + return GetConsoleHwnd(); } static HWND @@ -434,7 +436,7 @@ GetConsoleHwnd(void) /* Get current window title */ GetConsoleTitle(OldTitle, sizeof OldTitle); - (void) sprintf(NewTitle, "NETHACK%ld/%ld", GetTickCount(), + (void) sprintf(NewTitle, "NETHACK%lld/%ld", GetTickCount64(), GetCurrentProcessId()); SetConsoleTitle(NewTitle); From 666b053c09ccb49facdf6999ac6aba24500986c8 Mon Sep 17 00:00:00 2001 From: SHIRAKATA Kentaro Date: Wed, 9 Oct 2024 23:00:16 +0900 Subject: [PATCH 009/791] split "dopush" on moverock_core() into a separate function --- src/hack.c | 162 +++++++++++++++++++++++++++++------------------------ 1 file changed, 89 insertions(+), 73 deletions(-) diff --git a/src/hack.c b/src/hack.c index eb4bd1423..95576d019 100644 --- a/src/hack.c +++ b/src/hack.c @@ -9,6 +9,8 @@ /* #define DEBUG */ /* uncomment for debugging */ staticfn boolean could_move_onto_boulder(coordxy, coordxy); +staticfn void dopush(coordxy, coordxy, coordxy, coordxy, struct obj *, + boolean); staticfn void cannot_push_msg(struct obj *, coordxy, coordxy); staticfn int cannot_push(struct obj *, coordxy, coordxy); staticfn void moverock_done(coordxy, coordxy); @@ -157,6 +159,87 @@ could_move_onto_boulder(coordxy sx, coordxy sy) return squeezeablylightinvent(); } +staticfn void +dopush( + coordxy sx, + coordxy sy, + coordxy rx, + coordxy ry, + struct obj *otmp, + boolean costly) +{ + struct monst *shkp; + + { + const char *what; + boolean givemesg, easypush; + /* give boulder pushing feedback if this is a different + boulder than the last one pushed or if it's been at + least 2 turns since we last pushed this boulder; + unlike with Norep(), intervening messages don't cause + it to repeat, only doing something else in the meantime */ + if (otmp->o_id != gb.bldrpush_oid) { + gb.bldrpushtime = svm.moves + 1L; + gb.bldrpush_oid = otmp->o_id; + } + givemesg = (svm.moves > gb.bldrpushtime + 2L + || svm.moves < gb.bldrpushtime); + what = givemesg ? the(xname(otmp)) : 0; + if (!u.usteed) { + easypush = throws_rocks(gy.youmonst.data); + if (givemesg) + pline("With %s effort you move %s.", + easypush ? "little" : "great", what); + if (!easypush) + exercise(A_STR, TRUE); + } else { + if (givemesg) + pline("%s moves %s.", YMonnam(u.usteed), what); + } + gb.bldrpushtime = svm.moves; + } + + /* Move the boulder *after* the message. */ + if (glyph_is_invisible(levl[rx][ry].glyph)) + unmap_object(rx, ry); + otmp->next_boulder = 0; + movobj(otmp, rx, ry); /* does newsym(rx,ry) */ + if (Blind) { + feel_location(rx, ry); + feel_location(sx, sy); + } else { + newsym(sx, sy); + } + /* maybe adjust bill if boulder was pushed across shop boundary; + normally otmp->unpaid would not apply because otmp isn't in + hero's inventory, but addtobill() sets it and subfrombill() + clears it */ + if (costly && !costly_spot(rx, ry)) { + /* pushing from inside shop to its boundary (or free spot) */ + addtobill(otmp, FALSE, FALSE, FALSE); + } else if (!costly && costly_spot(rx, ry) && otmp->unpaid + && ((shkp = shop_keeper(*in_rooms(rx, ry, SHOPBASE))) + != 0) + && onshopbill(otmp, shkp, TRUE)) { + /* this can happen if hero pushes boulder from farther inside + shop into shop's free spot (which will add it to the bill), + then teleports or Passes_walls to doorway (without exiting + the shop), and then pushes the boulder from the free spot + back into the shop; it's contingent upon the shopkeeper not + "muttering an incantation" to fracture the boulder while it + is unpaid at the free spot */ + subfrombill(otmp, shkp); + } else if (otmp->unpaid + && (shkp = find_objowner(otmp, sx, sy)) != 0 + && !strchr(in_rooms(rx, ry, SHOPBASE), + ESHK(shkp)->shoproom)) { + /* once the boulder is fully out of the shop, so that it's + * impossible to change your mind and push it back in without + * leaving and triggering Kops, switch it to stolen_value */ + stolen_value(otmp, sx, sy, TRUE, FALSE); + } +} + staticfn void cannot_push_msg(struct obj *otmp, coordxy sx, coordxy sy) { @@ -252,8 +335,7 @@ moverock_core(coordxy sx, coordxy sy) coordxy rx, ry; struct obj *otmp; struct trap *ttmp; - struct monst *mtmp, *shkp; - const char *what; + struct monst *mtmp; boolean costly, firstboulder = TRUE; while ((otmp = sobj_at(BOULDER, sx, sy)) != 0) { @@ -472,8 +554,10 @@ moverock_core(coordxy sx, coordxy sy) that if in single-level branch (Knox) or in endgame */ newlev = random_teleport_level(); /* if trap doesn't work, skip "disappears" message */ - if (newlev == depth(&u.uz)) - goto dopush; + if (newlev == depth(&u.uz)) { + dopush(sx, sy, rx, ry, otmp, costly); + continue; + } /*FALLTHRU*/ case TELEP_TRAP: if (u.usteed) @@ -513,75 +597,7 @@ moverock_core(coordxy sx, coordxy sy) remove_object(otmp); place_object(otmp, otmp->ox, otmp->oy); } - - { - boolean givemesg, easypush; - dopush: - /* give boulder pushing feedback if this is a different - boulder than the last one pushed or if it's been at - least 2 turns since we last pushed this boulder; - unlike with Norep(), intervening messages don't cause - it to repeat, only doing something else in the meantime */ - if (otmp->o_id != gb.bldrpush_oid) { - gb.bldrpushtime = svm.moves + 1L; - gb.bldrpush_oid = otmp->o_id; - } - givemesg = (svm.moves > gb.bldrpushtime + 2L - || svm.moves < gb.bldrpushtime); - what = givemesg ? the(xname(otmp)) : 0; - if (!u.usteed) { - easypush = throws_rocks(gy.youmonst.data); - if (givemesg) - pline("With %s effort you move %s.", - easypush ? "little" : "great", what); - if (!easypush) - exercise(A_STR, TRUE); - } else { - if (givemesg) - pline("%s moves %s.", YMonnam(u.usteed), what); - } - gb.bldrpushtime = svm.moves; - } - - /* Move the boulder *after* the message. */ - if (glyph_is_invisible(levl[rx][ry].glyph)) - unmap_object(rx, ry); - otmp->next_boulder = 0; - movobj(otmp, rx, ry); /* does newsym(rx,ry) */ - if (Blind) { - feel_location(rx, ry); - feel_location(sx, sy); - } else { - newsym(sx, sy); - } - /* maybe adjust bill if boulder was pushed across shop boundary; - normally otmp->unpaid would not apply because otmp isn't in - hero's inventory, but addtobill() sets it and subfrombill() - clears it */ - if (costly && !costly_spot(rx, ry)) { - /* pushing from inside shop to its boundary (or free spot) */ - addtobill(otmp, FALSE, FALSE, FALSE); - } else if (!costly && costly_spot(rx, ry) && otmp->unpaid - && ((shkp = shop_keeper(*in_rooms(rx, ry, SHOPBASE))) - != 0) - && onshopbill(otmp, shkp, TRUE)) { - /* this can happen if hero pushes boulder from farther inside - shop into shop's free spot (which will add it to the bill), - then teleports or Passes_walls to doorway (without exiting - the shop), and then pushes the boulder from the free spot - back into the shop; it's contingent upon the shopkeeper not - "muttering an incantation" to fracture the boulder while it - is unpaid at the free spot */ - subfrombill(otmp, shkp); - } else if (otmp->unpaid - && (shkp = find_objowner(otmp, sx, sy)) != 0 - && !strchr(in_rooms(rx, ry, SHOPBASE), - ESHK(shkp)->shoproom)) { - /* once the boulder is fully out of the shop, so that it's - * impossible to change your mind and push it back in without - * leaving and triggering Kops, switch it to stolen_value */ - stolen_value(otmp, sx, sy, TRUE, FALSE); - } + dopush(sx, sy, rx, ry, otmp, costly); } else { cannot_push_msg(otmp, sx, sy); return cannot_push(otmp, sx, sy); From ac3031932fb8cfac12db2d9b447feb44518be93f Mon Sep 17 00:00:00 2001 From: nhmall Date: Thu, 10 Oct 2024 18:14:57 -0400 Subject: [PATCH 010/791] update tested versions of Visual Studio 2024-10-10 --- sys/windows/Makefile.nmake | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sys/windows/Makefile.nmake b/sys/windows/Makefile.nmake index a2f62bb23..a654307ac 100644 --- a/sys/windows/Makefile.nmake +++ b/sys/windows/Makefile.nmake @@ -8,8 +8,8 @@ # MS Visual Studio Visual C++ compiler # # Visual Studio Compilers Tested: -# - Microsoft Visual Studio 2019 Community Edition v 16.11.38 -# - Microsoft Visual Studio 2022 Community Edition v 17.11.4 +# - Microsoft Visual Studio 2019 Community Edition v 16.11.41 +# - Microsoft Visual Studio 2022 Community Edition v 17.11.5 # #============================================================================== # This is used for building two distinct executables of NetHack: @@ -988,8 +988,8 @@ rc=Rc.exe # is too old or untested. # # Recently tested versions: -TESTEDVS2019 = 14.29.30154.0 -TESTEDVS2022 = 14.41.34120.0 +TESTEDVS2019 = 14.29.30156.0 +TESTEDVS2022 = 14.41.34123.0 VS2019CUR = $(TESTEDVS2019:.=) VS2022CUR = $(TESTEDVS2022:.=) From 1f36b98b8f66b66c6d25b2027b1ae0757bd363da Mon Sep 17 00:00:00 2001 From: PatR Date: Thu, 10 Oct 2024 23:14:25 -0700 Subject: [PATCH 011/791] 'selectsaved' extension Instead of a menu listing a - hero1 b - hero2 n - New game q - Quit show a - hero1-role1-race1-gend1-algn1 b - hero2-role2-race2-gend2-algn2 n - New game q - Quit or a - - hero1-role1-race1-gend1-algn1 b - X hero2-role2-race2-gend2-algn2 c - D wizard-role3-race3-gend3-algn3 n - New game q - Quit when any game in the list wasn't saved during normal play. (Those are sorted by character name; the playmode is just coincidence.) The dash for 'normal' doesn't look great but -/X/D are codes used in entries written to paniclog. The whole playmode prefix doesn't look particularly good but I suspect that most players relying on restore via menu won't see it. It should work when the character name has dashes in it but that hasn't been properly tested. The gender and alignment suffices reflect their value at the time of save rather than at the start of the game. That might be considered a bug but it was easiest. Increments EDITLEVEL; existing save and bones files are invalidated. --- doc/fixes3-7-0.txt | 6 +++ include/extern.h | 2 +- include/global.h | 2 + include/patchlevel.h | 2 +- src/files.c | 89 +++++++++++++++----------------------------- src/restore.c | 57 ++++++++++++++++++++++------ src/save.c | 23 +++++++++++- sys/vms/vmsunix.c | 5 ++- 8 files changed, 110 insertions(+), 76 deletions(-) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index b30fbb712..13910d97b 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -2710,6 +2710,12 @@ livelog/#chronicle for saving-grace: if saving-grace prevents hero's death, enlightenment/attribute disclosure for saving-grace: include a line for have or haven't been saved (game in progress) or did or didn't get saved (game over) via saving-grace +'selectsaved' lists "name-role-race-gend-algn" instead of just "name" in the + menu of save files available to be restored +'selectsaved' prefixes "name-role-race-gend-algn" with "- " for normal play, + "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 Platform- and/or Interface-Specific New Features diff --git a/include/extern.h b/include/extern.h index 91fb732a5..046045e7c 100644 --- a/include/extern.h +++ b/include/extern.h @@ -2618,7 +2618,7 @@ extern int dorecover(NHFILE *) NONNULLARG1; extern void restcemetery(NHFILE *, struct cemetery **) NONNULLARG12; extern void trickery(char *) NO_NNARGS; extern void getlev(NHFILE *, int, xint8) NONNULLARG1; -extern void get_plname_from_file(NHFILE *, char *) NONNULLARG12; +extern void get_plname_from_file(NHFILE *, char *, boolean) NONNULLARG12; #ifdef SELECTSAVED extern int restore_menu(winid); #endif diff --git a/include/global.h b/include/global.h index 0643ca13d..94e95370f 100644 --- a/include/global.h +++ b/include/global.h @@ -431,6 +431,8 @@ extern struct nomakedefs_s nomakedefs; #define PL_CSIZ 32 /* sizeof pl_character */ #define PL_FSIZ 32 /* fruit name */ #define PL_PSIZ 63 /* player-given names for pets, other monsters, objects */ +/* room for "name-role-race-gend-algn" plus 1 character playmode code */ +#define PL_NSIZ_PLUS (PL_NSIZ + 4 * (1 + 4) + 1) /* 53 */ #define MAXDUNGEON 16 /* current maximum number of dungeons */ #define MAXLEVEL 32 /* max number of levels in one dungeon */ diff --git a/include/patchlevel.h b/include/patchlevel.h index fb3d53212..1f9ae25b6 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 107 +#define EDITLEVEL 108 /* * Development status possibilities. diff --git a/src/files.c b/src/files.c index 2a98a2f5c..e4834e2ae 100644 --- a/src/files.c +++ b/src/files.c @@ -719,11 +719,7 @@ clearlocks(void) staticfn int QSORTCALLBACK strcmp_wrap(const void *p, const void *q) { -#if defined(UNIX) && defined(QT_GRAPHICS) - return strncasecmp(*(char **) p, *(char **) q, 16); -#else - return strncmpi(*(char **) p, *(char **) q, 16); -#endif + return strcmp(*(char **) p, *(char **) q); } #endif @@ -989,7 +985,7 @@ set_savefile_name(boolean regularize_it) if (strlen(gs.SAVEF) < (SAVESIZE - 1)) (void) strncat(gs.SAVEF, svp.plname, (SAVESIZE - strlen(gs.SAVEF))); #endif -#if defined(MICRO) && !defined(VMS) && !defined(WIN32) && !defined(MSDOS) +#if defined(MICRO) && !defined(WIN32) && !defined(MSDOS) if (strlen(gs.SAVEP) < (SAVESIZE - 1)) Strcpy(gs.SAVEF, gs.SAVEP); else @@ -1252,9 +1248,12 @@ check_panic_save(void) #if defined(SELECTSAVED) char * -plname_from_file(const char *filename, boolean without_wait_synch_per_file) +plname_from_file( + const char *filename, + boolean without_wait_synch_per_file) { - NHFILE *nhfp = (NHFILE *) 0; + NHFILE *nhfp; + unsigned ln; char *result = 0; Strcpy(gs.SAVEF, filename); @@ -1271,60 +1270,32 @@ plname_from_file(const char *filename, boolean without_wait_synch_per_file) nh_uncompress(gs.SAVEF); if ((nhfp = open_savefile()) != 0) { if (validate(nhfp, filename, without_wait_synch_per_file) == 0) { - char tplname[PL_NSIZ]; - - get_plname_from_file(nhfp, tplname); - result = dupstr(tplname); + /* room for "name+role+race+gend+algn X" where the space before + X is actually NUL and X is playmode: one of '-', 'X', or 'D' */ + ln = (unsigned) PL_NSIZ_PLUS; + result = memset((genericptr_t) alloc(ln), '\0', ln); + get_plname_from_file(nhfp, result, FALSE); } close_nhfile(nhfp); } nh_compress(gs.SAVEF); - - return result; -#if 0 -/* --------- obsolete - used to be ifndef STORE_PLNAME_IN_FILE ----*/ -#if defined(UNIX) && defined(QT_GRAPHICS) - /* Name not stored in save file, so we have to extract it from - the filename, which loses information - (eg. "/", "_", and "." characters are lost. */ - int k; - int uid; - char name[64]; /* more than PL_NSIZ */ -#ifdef COMPRESS_EXTENSION -#define EXTSTR COMPRESS_EXTENSION -#else -#define EXTSTR "" -#endif - - if (sscanf(filename, "%*[^/]/%d%63[^.]" EXTSTR, &uid, name) == 2) { -#undef EXTSTR - /* "_" most likely means " ", which certainly looks nicer */ - for (k = 0; name[k]; k++) - if (name[k] == '_') - name[k] = ' '; - return dupstr(name); - } else -#endif /* UNIX && QT_GRAPHICS */ - { - return 0; - } -/* --------- end of obsolete code ----*/ -#endif /* 0 - WAS STORE_PLNAME_IN_FILE*/ + return result; /* file's plname[]+playmode value */ } #endif /* defined(SELECTSAVED) */ #define SUPPRESS_WAITSYNCH_PERFILE TRUE #define ALLOW_WAITSYNCH_PERFILE FALSE +/* get list of saved games owned by current user */ char ** get_saved_games(void) { + char **result = NULL; #if defined(SELECTSAVED) #if defined(WIN32) || defined(UNIX) int n; #endif int j = 0; - char **result = 0; #ifdef WIN32 { @@ -1351,8 +1322,8 @@ get_saved_games(void) } if (n > 0) { - files = (char **) alloc((n + 1) * sizeof(char *)); /* at most */ - (void) memset((genericptr_t) files, 0, (n + 1) * sizeof(char *)); + files = (char **) alloc((n + 1) * sizeof (char *)); /* at most */ + (void) memset((genericptr_t) files, 0, (n + 1) * sizeof (char *)); if (findfirst((char *) fq_save)) { i = 0; do { @@ -1362,8 +1333,8 @@ get_saved_games(void) } if (n > 0) { - result = (char **) alloc((n + 1) * sizeof(char *)); /* at most */ - (void) memset((genericptr_t) result, 0, (n + 1) * sizeof(char *)); + result = (char **) alloc((n + 1) * sizeof (char *)); /* at most */ + (void) memset((genericptr_t) result, 0, (n + 1) * sizeof (char *)); for(i = 0; i < n; i++) { char *r; r = plname_from_file(files[i], SUPPRESS_WAITSYNCH_PERFILE); @@ -1390,7 +1361,7 @@ get_saved_games(void) if (count_failures) wait_synch(); } -#endif +#endif /* WIN32 */ #ifdef UNIX /* posixly correct version */ int myuid = getuid(); @@ -1409,7 +1380,7 @@ get_saved_games(void) (void) memset((genericptr_t) result, 0, (n + 1) * sizeof(char *)); for (i = 0, j = 0; i < n; i++) { int uid; - char name[64]; /* more than PL_NSIZ */ + char name[64]; /* more than PL_NSIZ+1 */ struct dirent *entry = readdir(dir); if (!entry) @@ -1430,7 +1401,7 @@ get_saved_games(void) closedir(dir); } } -#endif +#endif /* UNIX */ #ifdef VMS Strcpy(svp.plname, "*"); set_savefile_name(FALSE); @@ -1440,14 +1411,14 @@ get_saved_games(void) if (j > 0) { if (j > 1) qsort(result, j, sizeof (char *), strcmp_wrap); - result[j] = 0; - return result; + result[j] = (char *) NULL; } else if (result) { /* could happen if save files are obsolete */ free_saved_games(result); + result = (char **) NULL; } #endif /* SELECTSAVED */ - return 0; + return result; } #undef SUPPRESS_WAITSYNCH_PERFILE #undef ALLOW_WAITSYNCH_PERFILE @@ -1456,10 +1427,10 @@ void free_saved_games(char **saved) { if (saved) { - int i = 0; + int i; - while (saved[i]) - free((genericptr_t) saved[i++]); + for (i = 0; saved[i]; ++i) + free((genericptr_t) saved[i]); free((genericptr_t) saved); } } @@ -4260,7 +4231,7 @@ recover_savefile(void) int processed[256]; char savename[SAVESIZE], errbuf[BUFSZ], indicator; struct savefile_info sfi; - char tmpplbuf[PL_NSIZ]; + char tmpplbuf[PL_NSIZ_PLUS]; const char *savewrite_failure = (const char *) 0; for (lev = 0; lev < 256; lev++) @@ -4307,7 +4278,7 @@ recover_savefile(void) != sizeof version_data) || (read(gnhfp->fd, (genericptr_t) &sfi, sizeof sfi) != sizeof sfi) || (read(gnhfp->fd, (genericptr_t) &pltmpsiz, sizeof pltmpsiz) - != sizeof pltmpsiz) || (pltmpsiz > PL_NSIZ) + != sizeof pltmpsiz) || (pltmpsiz > PL_NSIZ_PLUS) || (read(gnhfp->fd, (genericptr_t) &tmpplbuf, pltmpsiz) != pltmpsiz)) { raw_printf("\nError reading %s -- can't recover.\n", gl.lock); diff --git a/src/restore.c b/src/restore.c index 63c038124..434cd5aaa 100644 --- a/src/restore.c +++ b/src/restore.c @@ -740,7 +740,7 @@ dorecover(NHFILE *nhfp) /* suppress map display if some part of the code tries to update that */ program_state.restoring = REST_GSTATE; - get_plname_from_file(nhfp, svp.plname); + get_plname_from_file(nhfp, svp.plname, TRUE); getlev(nhfp, 0, (xint8) 0); if (!restgamestate(nhfp)) { NHFILE tnhfp; @@ -828,7 +828,7 @@ dorecover(NHFILE *nhfp) restoreinfo.mread_flags = 0; rewind_nhfile(nhfp); /* return to beginning of file */ (void) validate(nhfp, (char *) 0, FALSE); - get_plname_from_file(nhfp, svp.plname); + get_plname_from_file(nhfp, svp.plname, TRUE); /* not 0 nor REST_GSTATE nor REST_LEVELS */ program_state.restoring = REST_CURRENT_LEVEL; @@ -1245,15 +1245,33 @@ getlev(NHFILE *nhfp, int pid, xint8 lev) program_state.in_getlev = FALSE; } +/* "name-role-race-gend-algn" occurs very early in a save file; sometimes we + want the whole thing, other times just "name" (for svp.plname[]) */ void -get_plname_from_file(NHFILE *nhfp, char *plbuf) +get_plname_from_file( + NHFILE *nhfp, + char *outbuf, /* size must be at least [PL_NSIZ_PLUS] even if name_only */ + boolean name_only) /* True: just name; False: name-role-race-gend-algn */ { + char plbuf[PL_NSIZ_PLUS]; int pltmpsiz = 0; + plbuf[0] = '\0'; if (nhfp->structlevel) { - (void) read(nhfp->fd, (genericptr_t) &pltmpsiz, sizeof(pltmpsiz)); + (void) read(nhfp->fd, (genericptr_t) &pltmpsiz, sizeof pltmpsiz); + /* pltmpsiz should now be PL_NSIZ_PLUS */ (void) read(nhfp->fd, (genericptr_t) plbuf, pltmpsiz); + /* plbuf[PL_NSIZ_PLUS-2] should be '\0'; + plbuf[PL_NSIZ_PLUS-1] should be '-' or 'X' or 'D' */ } + /* "-race-role-gend-algn" is already present except that it has been + hidden by replacing the initial dash with NUL; if we want that + information, replace the NUL with a dash */ + if (!name_only) + *eos(plbuf) = '-'; + /* not simple strcpy(); playmode is in the last slot and could (probably + will) be preceded by NULs */ + (void) memcpy((genericptr_t) outbuf, (genericptr_t) plbuf, PL_NSIZ_PLUS); return; } @@ -1418,7 +1436,8 @@ restore_menu( { winid tmpwin; anything any; - char **saved; + char **saved, *next, mode, menutext[BUFSZ]; + boolean all_normal; menu_item *chosen_game = (menu_item *) 0; int k, clet, ch = 0; /* ch: 0 => new game */ int clr = NO_COLOR; @@ -1438,19 +1457,35 @@ restore_menu( add_menu_str(tmpwin, ""); } add_menu_str(tmpwin, "Select one of your saved games"); + /* if all the save files have a playmode of '-' then we'll just list + their character name-role-race-gend-algn values, but if any are + 'X' or 'D', we'll list playmode along with name-role-&c values + for every entry; first, figure out if they're all normal play */ + for (all_normal = TRUE, k = 0; all_normal && saved[k]; ++k) { + next = saved[k]; + mode = next[PL_NSIZ_PLUS - 1]; /* fixed last char, beyond '\0' */ + if (mode != '-') + all_normal = FALSE; + } for (k = 0; saved[k]; ++k) { any.a_int = k + 1; - add_menu(tmpwin, &nul_glyphinfo, &any, 0, 0, - ATR_NONE, clr, saved[k], MENU_ITEMFLAGS_NONE); + next = saved[k]; + mode = next[PL_NSIZ_PLUS - 1]; + if (all_normal) + Sprintf(menutext, "%.*s", PL_NSIZ_PLUS - 1, next); + else + Sprintf(menutext, "%c %.*s", mode, PL_NSIZ_PLUS - 1, next); + add_menu(tmpwin, &nul_glyphinfo, &any, 0, 0, ATR_NONE, clr, + menutext, MENU_ITEMFLAGS_SKIPMENUCOLORS); } clet = (k <= 'n' - 'a') ? 'n' : 0; /* new game */ any.a_int = -1; /* not >= 0 */ - add_menu(tmpwin, &nul_glyphinfo, &any, clet, 0, ATR_NONE, - clr, "Start a new character", MENU_ITEMFLAGS_NONE); + add_menu(tmpwin, &nul_glyphinfo, &any, clet, 0, ATR_NONE, clr, + "Start a new character", MENU_ITEMFLAGS_NONE); clet = (k + 1 <= 'q' - 'a') ? 'q' : 0; /* quit */ any.a_int = -2; - add_menu(tmpwin, &nul_glyphinfo, &any, clet, 0, ATR_NONE, - clr, "Never mind (quit)", MENU_ITEMFLAGS_SELECTED); + add_menu(tmpwin, &nul_glyphinfo, &any, clet, 0, ATR_NONE, clr, + "Never mind (quit)", MENU_ITEMFLAGS_SELECTED); /* no prompt on end_menu, as we've done our own at the top */ end_menu(tmpwin, (char *) 0); if (select_menu(tmpwin, PICK_ONE, &chosen_game) > 0) { diff --git a/src/save.c b/src/save.c index 0f194ba34..09a0dedc4 100644 --- a/src/save.c +++ b/src/save.c @@ -1071,16 +1071,35 @@ savelevchn(NHFILE *nhfp) svs.sp_levchn = 0; } +/* write "name-role-race-gend-algn" into save file for menu-based restore; + the first dash is actually stored as '\0' instead of '-' */ void store_plname_in_file(NHFILE *nhfp) { - int plsiztmp = PL_NSIZ; + char hero[PL_NSIZ_PLUS]; /* [PL_NSIZ + 4*4 + 1] */ + int plsiztmp = (int) sizeof hero; + + (void) memset((genericptr_t) hero, '\0', sizeof hero); + /* augment svp.plname[]; the gender and alignment values reflect those + in effect at time of saving rather than at start of game */ + Snprintf(hero, sizeof hero, "%s-%.3s-%.3s-%.3s-%.3s", + svp.plname, gu.urole.filecode, + gu.urace.filecode, genders[flags.female].filecode, + aligns[1 - u.ualign.type].filecode); + /* replace "-role-race..." with "\0role-race..." so that we can include + or exclude the role-&c suffix easily, without worrying about whether + plname contains any dashes; but don't rely on snprintf() for this */ + hero[strlen(svp.plname)] = '\0'; + /* insert playmode into final slot of hero[]; + 'D','X','-' are the same characters as are used for paniclog entries */ + assert(hero[PL_NSIZ_PLUS - 1 - 1] == '\0'); + hero[PL_NSIZ_PLUS - 1] = wizard ? 'D' : discover ? 'X' : '-'; if (nhfp->structlevel) { bufoff(nhfp->fd); /* bwrite() before bufon() uses plain write() */ bwrite(nhfp->fd, (genericptr_t) &plsiztmp, sizeof plsiztmp); - bwrite(nhfp->fd, (genericptr_t) svp.plname, plsiztmp); + bwrite(nhfp->fd, (genericptr_t) hero, plsiztmp); bufon(nhfp->fd); } return; diff --git a/sys/vms/vmsunix.c b/sys/vms/vmsunix.c index 69e5a3929..f2c1bb0df 100644 --- a/sys/vms/vmsunix.c +++ b/sys/vms/vmsunix.c @@ -603,8 +603,9 @@ vmscond lib$find_file_end(void **); /* collect a list of character names from all save files for this player */ int -vms_get_saved_games(const char *savetemplate, /* wildcarded save file name in native VMS format */ - char ***outarray) +vms_get_saved_games( + const char *savetemplate, /* wildcarded save name in native VMS format */ + char ***outarray) { struct dsc in, out; unsigned short l; From 11a4fe42de7e3c05c85b9bfc048b06e91d1d6ce0 Mon Sep 17 00:00:00 2001 From: PatR Date: Fri, 11 Oct 2024 22:35:38 -0700 Subject: [PATCH 012/791] 'selectsaved' again - update EDITLEVEL again The role, race, gender, and alignment string values are 3 letters preceded by a dash. I was looking at "name-race-role-gend-algn" and mistakenly treated them as 4 letters preceded by a dash. Fixing that changes PL_NSIZ_PLUS and there is one item of that size written into save files, so the fix invalidates existing save files. --- include/global.h | 2 +- include/patchlevel.h | 2 +- src/save.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/global.h b/include/global.h index 94e95370f..d2651b3b8 100644 --- a/include/global.h +++ b/include/global.h @@ -432,7 +432,7 @@ extern struct nomakedefs_s nomakedefs; #define PL_FSIZ 32 /* fruit name */ #define PL_PSIZ 63 /* player-given names for pets, other monsters, objects */ /* room for "name-role-race-gend-algn" plus 1 character playmode code */ -#define PL_NSIZ_PLUS (PL_NSIZ + 4 * (1 + 4) + 1) /* 53 */ +#define PL_NSIZ_PLUS (PL_NSIZ + 4 * (1 + 3) + 1) /* 49 */ #define MAXDUNGEON 16 /* current maximum number of dungeons */ #define MAXLEVEL 32 /* max number of levels in one dungeon */ diff --git a/include/patchlevel.h b/include/patchlevel.h index 1f9ae25b6..4d107d941 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 108 +#define EDITLEVEL 109 /* * Development status possibilities. diff --git a/src/save.c b/src/save.c index 09a0dedc4..509e3c437 100644 --- a/src/save.c +++ b/src/save.c @@ -1076,7 +1076,7 @@ savelevchn(NHFILE *nhfp) void store_plname_in_file(NHFILE *nhfp) { - char hero[PL_NSIZ_PLUS]; /* [PL_NSIZ + 4*4 + 1] */ + char hero[PL_NSIZ_PLUS]; /* [PL_NSIZ + 4*(1+3) + 1] */ int plsiztmp = (int) sizeof hero; (void) memset((genericptr_t) hero, '\0', sizeof hero); From c4a1f298e8923dfc0543f51d4794bc0286d42138 Mon Sep 17 00:00:00 2001 From: PatR Date: Fri, 11 Oct 2024 23:34:26 -0700 Subject: [PATCH 013/791] lawful minions vs Demonbane Back then Demonbane was a long sword, lawful Angels and Archons could get either it or Sunsword as part of their starting equipment. After it got changed into a mace instead, they could only get Sunsword. Rather than always giving them a long sword, sometimes give them a mace so that they get back the chance to start with Demonbane. Since mace is quite a bit weaker that long sword against large opponents, provide a better enchantment for maces given to lawful minions. --- src/makemon.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/src/makemon.c b/src/makemon.c index a712b6a31..828328ab2 100644 --- a/src/makemon.c +++ b/src/makemon.c @@ -329,20 +329,27 @@ m_initweap(struct monst *mtmp) case S_ANGEL: if (humanoid(ptr)) { - /* create minion stuff; can't use mongets */ - otmp = mksobj(LONG_SWORD, FALSE, FALSE); - - /* maybe make it special */ + /* create minion stuff; can't use mongets; + weapon: long sword [rn2(5) > 1 == 60%] or mace [40%] */ + otmp = mksobj((rn2(5) > 1) ? LONG_SWORD : MACE, FALSE, FALSE); + /* maybe promote weapon to an artifact */ if ((!rn2(20) || is_lord(ptr)) && sgn(mtmp->isminion ? EMIN(mtmp)->min_align - : ptr->maligntyp) == A_LAWFUL) - /* [note: this used to have a 50:50 chance for Sunsword or - Demonbane, but Demonbane has been changed into a mace] */ - otmp = oname(otmp, artiname(ART_SUNSWORD), + : ptr->maligntyp) == A_LAWFUL) { + /* Sunsword and Demonbane both used to be long swords and + Angels always got a long sword, so might get either of + the two artifacts; Demonbane has been changed to be a + mace; this deliberately makes an independent choice of + which artifact and if it picks the wrong name for 'otmp's + type, then 'otmp' won't be upgraded into an artifact */ + otmp = oname(otmp, artiname((rn2(5) > 1) ? ART_SUNSWORD + : ART_DEMONBANE), ONAME_RANDOM); /* randomly created */ + } bless(otmp); otmp->oerodeproof = TRUE; - otmp->spe = rn2(4); + /* make long sword be +0 to +3, weaker mace be +3 to +6 */ + otmp->spe = (otmp->otyp == LONG_SWORD) ? rn2(4) : rn1(4, 3); (void) mpickobj(mtmp, otmp); otmp = mksobj(!rn2(4) || is_lord(ptr) ? SHIELD_OF_REFLECTION From e1dbad9194817620575dbe075bb9f64b310d544d Mon Sep 17 00:00:00 2001 From: PatR Date: Sat, 12 Oct 2024 00:17:58 -0700 Subject: [PATCH 014/791] monster swapping armor While testing the Demonbane change, I saw | The Angel of Crom removes a robe and puts on a robe. which looks a bit silly. Change that to be | The Angel of Crom removes a robe and puts on another robe. when the two items have the same formatted description. (The second robe evidently has a better enchantment than the first one.) --- src/worn.c | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/src/worn.c b/src/worn.c index 1f35776d4..473765764 100644 --- a/src/worn.c +++ b/src/worn.c @@ -723,7 +723,7 @@ staticfn void m_dowear_type( struct monst *mon, long flag, /* wornmask value */ - boolean creation, + boolean creation, /* no wear messages when mon is being created */ boolean racialexception) /* small monsters that are allowed for player * races (gnomes) can wear suits */ { @@ -847,14 +847,32 @@ m_dowear_type( if (!creation) { if (sawmon) { - char buf[BUFSZ]; + char buf[BUFSZ], oldarm[BUFSZ], newarm[BUFSZ]; - if (old) - Sprintf(buf, " removes %s and", distant_name(old, doname)); - else - buf[0] = '\0'; - pline("%s%s puts on %s.", Monnam(mon), buf, - distant_name(best, doname)); + /* " [removes and ]puts on ." + uses accessory verbs for armor but we can live with that */ + if (old) { + Strcpy(oldarm, distant_name(old, doname)); + Snprintf(buf, sizeof buf, " removes %s and", oldarm); + } else { + buf[0] = oldarm[0] = '\0'; + } + Strcpy(newarm, distant_name(best, doname)); + /* a monster will swap an item of the same type as the one it + is replacing when the enchantment is better; + if newarm and oldarm have identical descriptions, substitute + "another " for "a|an " */ + if (!strcmpi(newarm, oldarm)) { + if (!strncmpi(newarm, "a ", 2) + && strlen(newarm) + sizeof "another " - sizeof "a " + < sizeof newarm) + (void) strsubst(newarm, "a ", "another "); + else if (!strncmpi(newarm, "an ", 3) + && strlen(newarm) + sizeof "another " - sizeof "an " + < sizeof newarm) + (void) strsubst(newarm, "an ", "another "); + } + pline("%s%s puts on %s.", Monnam(mon), buf, newarm); if (autocurse) pline("%s %s %s %s for a moment.", s_suffix(Monnam(mon)), simpleonames(best), otense(best, "glow"), From 87af3a8cacad95426257fd147b9e8577a1a0ca0c Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 12 Oct 2024 09:28:29 -0400 Subject: [PATCH 015/791] fuzzer under Windows GUI hangs on minimize window On the Windows GUI (nethackw.exe), while running the fuzzer, if the NetHack window gets minimized, or someone minimizes all desktop windows, the NetHack window stops responding and won't even repaint itself. The NetHack process continues to use the CPU. A break in the debugger shows that it is caught in a do loop. I didn't delve into the issue of why minimizing the window triggers a condition that leads to the endless loop. This just adds a kludge to exit the loop while fuzzing. --- win/win32/mhmenu.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/win/win32/mhmenu.c b/win/win32/mhmenu.c index 89d90e2ab..dfd7a49c9 100644 --- a/win/win32/mhmenu.c +++ b/win/win32/mhmenu.c @@ -1532,6 +1532,8 @@ onListChar(HWND hWnd, HWND hwndList, WORD ch) int iter = topIndex; do { i = iter % data->menui.menu.size; + if (iflags.debug_fuzzer && iter > 1000000) + ch = data->menui.menu.items[i].accelerator; if (data->menui.menu.items[i].accelerator == ch) { if (data->how == PICK_ANY) { SelectMenuItem( From 57fc8f10a6a9c1fe3d471b67f378763a570bf2cf Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 12 Oct 2024 10:14:44 -0400 Subject: [PATCH 016/791] replace fuzzer state magic numbers --- include/flag.h | 6 ++++++ src/end.c | 2 +- src/pline.c | 2 +- src/wizcmds.c | 10 ++++++++-- 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/include/flag.h b/include/flag.h index e774a1c31..4fbfad0e7 100644 --- a/include/flag.h +++ b/include/flag.h @@ -224,6 +224,12 @@ struct accessibility_data { a11y.mon_notices_blocked = 0; \ } } while(0) +enum debug_fuzzer_states { + fuzzer_off, + fuzzer_impossible_panic, + fuzzer_impossible_continue +}; + /* * Stuff that really isn't option or platform related and does not * get saved and restored. They are set and cleared during the game diff --git a/src/end.c b/src/end.c index 519b599dc..1c10e192b 100644 --- a/src/end.c +++ b/src/end.c @@ -77,7 +77,7 @@ done1(int sig_unused UNUSED) #ifndef NO_SIGNAL (void) signal(SIGINT, SIG_IGN); #endif - iflags.debug_fuzzer = FALSE; + iflags.debug_fuzzer = fuzzer_off; if (flags.ignintr) { #ifndef NO_SIGNAL (void) signal(SIGINT, (SIG_RET_TYPE) done1); diff --git a/src/pline.c b/src/pline.c index 1e23846ce..4ca4a79a7 100644 --- a/src/pline.c +++ b/src/pline.c @@ -587,7 +587,7 @@ impossible(const char *s, ...) va_end(the_args); pbuf[BUFSZ - 1] = '\0'; /* sanity */ paniclog("impossible", pbuf); - if (iflags.debug_fuzzer == 1) + if (iflags.debug_fuzzer == fuzzer_impossible_panic) panic("%s", pbuf); gp.pline_flags = URGENT_MESSAGE; diff --git a/src/wizcmds.c b/src/wizcmds.c index 88dd27aac..12f51758c 100644 --- a/src/wizcmds.c +++ b/src/wizcmds.c @@ -551,8 +551,14 @@ wiz_fuzzer(void) pline("The fuzz tester will make NetHack execute random keypresses."); There("is no conventional way out of this mode."); } - if (paranoid_query(TRUE, "Do you want to start fuzz testing?")) - iflags.debug_fuzzer = TRUE; /* Thoth, take the reins */ + if (paranoid_query(TRUE, "Do you want to start fuzz testing?")) { + /* Thoth, take the reins */ + if (y_n("Do you want to call panic() after impossible()?") == 'n') { + iflags.debug_fuzzer = fuzzer_impossible_continue; + } else { + iflags.debug_fuzzer = fuzzer_impossible_panic; + } + } return ECMD_OK; } From 10498b15352b81a174ca47ff8a23706e71db0977 Mon Sep 17 00:00:00 2001 From: PatR Date: Sat, 12 Oct 2024 11:09:50 -0700 Subject: [PATCH 017/791] monster swapping armor simplification Slightly simplify yesterday's message adjustment made when a monster takes off a piece of armor and puts on a different instance of the same type of armor. ("a|an " -> "another ") --- src/worn.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/worn.c b/src/worn.c index 473765764..aae1611a4 100644 --- a/src/worn.c +++ b/src/worn.c @@ -847,7 +847,7 @@ m_dowear_type( if (!creation) { if (sawmon) { - char buf[BUFSZ], oldarm[BUFSZ], newarm[BUFSZ]; + char buf[BUFSZ], oldarm[BUFSZ], newarm[BUFSZ + sizeof "another "]; /* " [removes and ]puts on ." uses accessory verbs for armor but we can live with that */ @@ -863,14 +863,13 @@ m_dowear_type( if newarm and oldarm have identical descriptions, substitute "another " for "a|an " */ if (!strcmpi(newarm, oldarm)) { - if (!strncmpi(newarm, "a ", 2) - && strlen(newarm) + sizeof "another " - sizeof "a " - < sizeof newarm) + /* size of newarm[] has been overallocated to guarantee + enough room to insert "another " */ + if (!strncmpi(newarm, "a ", 2)) (void) strsubst(newarm, "a ", "another "); - else if (!strncmpi(newarm, "an ", 3) - && strlen(newarm) + sizeof "another " - sizeof "an " - < sizeof newarm) + else if (!strncmpi(newarm, "an ", 3)) (void) strsubst(newarm, "an ", "another "); + newarm[BUFSZ - 1] = '\0'; } pline("%s%s puts on %s.", Monnam(mon), buf, newarm); if (autocurse) From 67cfdf6843a735d2632c9ca8a2ca56bb019ccd8e Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 12 Oct 2024 14:56:36 -0400 Subject: [PATCH 018/791] get rid of a static analyzer warning src/pager.c(696): warning: Reading invalid data from 'def_warnsyms' --- include/display.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/display.h b/include/display.h index 24db18e91..fc52eac41 100644 --- a/include/display.h +++ b/include/display.h @@ -728,7 +728,7 @@ enum glyph_offsets { #define glyph_to_explosion(glyph) \ (glyph_is_explosion(glyph) ? (((glyph) - GLYPH_EXPLODE_OFF) % (S_expl_br - S_expl_tl + 1)) : 0) #define glyph_to_warning(glyph) \ - (glyph_is_warning(glyph) ? ((glyph) - GLYPH_WARNING_OFF) : NO_GLYPH) + (glyph_is_warning(glyph) ? ((glyph) - GLYPH_WARNING_OFF) : 0) /* * Return true if the given glyph is what we want. Note that bodies are From 3885949c5b573ab3c20af680609b7c9ca5060a98 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 12 Oct 2024 15:26:47 -0400 Subject: [PATCH 019/791] resolve a static analyzer complaint in glyphs.c src/glyphs.c(680): warning: Dereferencing NULL pointer. 'other' contains the same NULL value as 'obj_glyphs[idx].u' did. --- src/glyphs.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/glyphs.c b/src/glyphs.c index c13df781a..d95764060 100644 --- a/src/glyphs.c +++ b/src/glyphs.c @@ -675,12 +675,14 @@ shuffle_customizations(void) tmp_customcolor[i] = other_customcolor; tmp_color256idx[i] = other_color256idx; #ifdef ENHANCED_SYMBOLS - tmp_u[i] = (struct unicode_representation *) - alloc(sizeof *tmp_u[i]); - *tmp_u[i] = *other; - if (other->utf8str != NULL) { - tmp_u[i]->utf8str = (uint8 *) - dupstr((const char *) other->utf8str); + if (other) { + tmp_u[i] = (struct unicode_representation *) alloc( + sizeof *tmp_u[i]); + *tmp_u[i] = *other; + if (other->utf8str != NULL) { + tmp_u[i]->utf8str = + (uint8 *) dupstr((const char *) other->utf8str); + } } #endif } else { From 35cf7139885b3e4f98160e4491b27c089d2a7f59 Mon Sep 17 00:00:00 2001 From: PatR Date: Sat, 12 Oct 2024 14:39:48 -0700 Subject: [PATCH 020/791] fix part of #S11588 - mons eating poisoned items Prevent non-poison resistant monsters that eat items from eating poisoned items. --- src/dog.c | 2 ++ src/mon.c | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/dog.c b/src/dog.c index 11d13dcbd..deade5f5e 100644 --- a/src/dog.c +++ b/src/dog.c @@ -943,6 +943,8 @@ dogfood(struct monst *mon, struct obj *obj) starving, mblind; int fx; + if (obj->opoisoned && !resists_poison(mon)) + return POISON; if (is_quest_artifact(obj) || obj_resists(obj, 0, 95)) return obj->cursed ? TABU : APPORT; diff --git a/src/mon.c b/src/mon.c index 5d7ed1eea..fbf3bde86 100644 --- a/src/mon.c +++ b/src/mon.c @@ -1435,8 +1435,9 @@ meatmetal(struct monst *mtmp) otmp = otmp->nexthere) { /* Don't eat indigestible/choking/inappropriate objects */ if ((mtmp->data == &mons[PM_RUST_MONSTER] && !is_rustprone(otmp)) - || (otmp->otyp == AMULET_OF_STRANGULATION) - || (otmp->otyp == RIN_SLOW_DIGESTION)) + || (otmp->otyp == AMULET_OF_STRANGULATION + || otmp->otyp == RIN_SLOW_DIGESTION) + || (otmp->opoisoned && !resists_poison(mtmp))) continue; if (is_metallic(otmp) && !obj_resists(otmp, 5, 95) && touch_artifact(otmp, mtmp)) { @@ -1548,6 +1549,7 @@ meatobj(struct monst* mtmp) /* for gelatinous cubes */ included for emphasis */ || (otmp->otyp == AMULET_OF_STRANGULATION || otmp->otyp == RIN_SLOW_DIGESTION) + || (otmp->opoisoned && !resists_poison(mtmp)) /* cockatrice corpses handled above; this touch_petrifies() check catches eggs */ || (mstoning(otmp) && !resists_ston(mtmp)) From 546c1101b0d4a942fc39fa9ebb50516fbe620612 Mon Sep 17 00:00:00 2001 From: PatR Date: Sat, 12 Oct 2024 15:03:54 -0700 Subject: [PATCH 021/791] more 'selectsaved' If the saved game menu has more than 13 games, it won't be able to use 'n' for "new game" and 'q' for "quit". Switch to 'N' and 'Q' instead of just using the next letters in sequence. Only resort to next-letters if there are more than 39 games. tty and curses handle a list of many save files via menu pagination. X11 does so with one long page possessing a scroll bar. If there are more than 52 entries, selection via mouse is needed beyond 'Z'. Qt has one page without any scroll bar so won't provide access to the full set of save files when there are too many to fit on the screen. --- src/restore.c | 10 ++++++---- win/Qt/Qt-issues.txt | 6 ++++++ win/Qt/qt_svsel.cpp | 10 +++------- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/restore.c b/src/restore.c index 434cd5aaa..fcf31f3fb 100644 --- a/src/restore.c +++ b/src/restore.c @@ -1478,13 +1478,15 @@ restore_menu( add_menu(tmpwin, &nul_glyphinfo, &any, 0, 0, ATR_NONE, clr, menutext, MENU_ITEMFLAGS_SKIPMENUCOLORS); } - clet = (k <= 'n' - 'a') ? 'n' : 0; /* new game */ + clet = (k <= 'n' - 'a') ? 'n' /* new game */ + : (k <= 26 + 'N' - 'A') ? 'N' : 0; any.a_int = -1; /* not >= 0 */ - add_menu(tmpwin, &nul_glyphinfo, &any, clet, 0, ATR_NONE, clr, + add_menu(tmpwin, &nul_glyphinfo, &any, clet, 'N', ATR_NONE, clr, "Start a new character", MENU_ITEMFLAGS_NONE); - clet = (k + 1 <= 'q' - 'a') ? 'q' : 0; /* quit */ + clet = (k + 1 <= 'q' - 'a' && clet == 'n') ? 'q' /* quit */ + : (k + 1 <= 26 + 'Q' - 'A' && clet == 'N') ? 'Q' : 0; any.a_int = -2; - add_menu(tmpwin, &nul_glyphinfo, &any, clet, 0, ATR_NONE, clr, + add_menu(tmpwin, &nul_glyphinfo, &any, clet, 'Q', ATR_NONE, clr, "Never mind (quit)", MENU_ITEMFLAGS_SELECTED); /* no prompt on end_menu, as we've done our own at the top */ end_menu(tmpwin, (char *) 0); diff --git a/win/Qt/Qt-issues.txt b/win/Qt/Qt-issues.txt index a7418f984..1bac3106c 100644 --- a/win/Qt/Qt-issues.txt +++ b/win/Qt/Qt-issues.txt @@ -59,4 +59,10 @@ The status window can't be resized while hitpointbar is active. Toggling it off, resizing as desired, then toggling it back on is a viable workaround. +When choosing a saved game to restore ('selectsaved' option), the +selection dialog does not provide any way to scroll if there are more +games than will fit on the screen. Access to "New game" and "Quit" +isn't affected because those both have distinct buttons rather than +rely on fake save file entries at the end of the list. + ----- diff --git a/win/Qt/qt_svsel.cpp b/win/Qt/qt_svsel.cpp index ffe22a19c..882fabce7 100644 --- a/win/Qt/qt_svsel.cpp +++ b/win/Qt/qt_svsel.cpp @@ -23,13 +23,9 @@ // ... as many buttons as needed //---- // -// TODO? -// Character names are sorted alphabetically. It would be useful to -// be able to sort by role or by game start date or by save date. -// The core fetches character names from inside the files; it could -// obtain the information needed for alternate sorting. Simpler -// enhancement: instead of just showing the character name, show -// "name-role-race-gender-alignment". +// FIXME: +// If there are a lot of saved games available, the selection dialog +// needs vertical scrolling capability. // // Note: // The code in this file is not used if the program is built without From d2b7c2f5c52c554d63fc6b7c5974824e09452adc Mon Sep 17 00:00:00 2001 From: SHIRAKATA Kentaro Date: Wed, 18 Sep 2024 20:51:21 +0900 Subject: [PATCH 022/791] split "assess_dmg" on passiveum() into a separate function --- src/mhitu.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/src/mhitu.c b/src/mhitu.c index 38b765c9c..14b453147 100644 --- a/src/mhitu.c +++ b/src/mhitu.c @@ -19,6 +19,7 @@ staticfn int gulpmu(struct monst *, struct attack *); staticfn int explmu(struct monst *, struct attack *, boolean); staticfn void mayberem(struct monst *, const char *, struct obj *, const char *); +staticfn int assess_dmg(struct monst *, int); staticfn int passiveum(struct permonst *, struct monst *, struct attack *); #define ld() ((yyyymmdd((time_t) 0) - (getyear() * 10000L)) == 0xe5) @@ -2291,6 +2292,19 @@ mayberem(struct monst *mon, remove_worn_item(obj, TRUE); } +staticfn int +assess_dmg(struct monst *mtmp, int tmp) +{ + if ((mtmp->mhp -= tmp) <= 0) { + pline("%s dies!", Monnam(mtmp)); + xkilled(mtmp, XKILL_NOMSG); + if (!DEADMONSTER(mtmp)) + return M_ATTK_HIT; + return M_ATTK_AGR_DIED; + } + return M_ATTK_HIT; +} + /* FIXME: * sequencing issue: a monster's attack might cause poly'd hero * to revert to normal form. The messages for passive counterattack @@ -2345,7 +2359,7 @@ passiveum( erode_armor(mtmp, ERODE_CORRODE); if (!rn2(6)) acid_damage(MON_WEP(mtmp)); - goto assess_dmg; + return assess_dmg(mtmp, tmp); case AD_STON: /* cockatrice */ { long protector = attk_protection((int) mattk->aatyp), @@ -2394,7 +2408,7 @@ passiveum( You("explode!"); /* KMH, balance patch -- this is okay with unchanging */ rehumanize(); - goto assess_dmg; + return assess_dmg(mtmp, tmp); } break; case AD_PLYS: /* Floating eye */ @@ -2474,15 +2488,7 @@ passiveum( else tmp = 0; - assess_dmg: - if ((mtmp->mhp -= tmp) <= 0) { - pline("%s dies!", Monnam(mtmp)); - xkilled(mtmp, XKILL_NOMSG); - if (!DEADMONSTER(mtmp)) - return M_ATTK_HIT; - return M_ATTK_AGR_DIED; - } - return M_ATTK_HIT; + return assess_dmg(mtmp, tmp); } struct monst * From 9e4b2c121bb50b490e531a9909e5fad4d2a9d021 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Thu, 17 Oct 2024 12:34:02 +0300 Subject: [PATCH 023/791] Improve the exclusion zone code I forgot to add the code to flip the exclusion zones when implementing them. Also improve the zone coordinates so they're correct outside of map contents. --- src/sp_lev.c | 44 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 38 insertions(+), 6 deletions(-) diff --git a/src/sp_lev.c b/src/sp_lev.c index 316385c29..0796757bd 100644 --- a/src/sp_lev.c +++ b/src/sp_lev.c @@ -548,6 +548,7 @@ flip_level( timer_element *timer; boolean ball_active = FALSE, ball_fliparea = FALSE; stairway *stway; + struct exclusion_zone *ez; /* nothing to do unless (flp & 1) or (flp & 2) or both */ if ((flp & 3) == 0) @@ -872,6 +873,28 @@ flip_level( } } + /* exclusion zones */ + for (ez = sve.exclusion_zones; ez; ez = ez->next) { + if (flp & 1) { + ez->ly = FlipY(ez->ly); + ez->hy = FlipY(ez->hy); + if (ez->ly > ez->hy) { + itmp = ez->ly; + ez->ly = ez->hy; + ez->hy = itmp; + } + } + if (flp & 2) { + ez->lx = FlipX(ez->lx); + ez->hx = FlipX(ez->hx); + if (ez->lx > ez->hx) { + itmp = ez->lx; + ez->lx = ez->hx; + ez->hx = itmp; + } + } + } + if (extras) { /* for #wizfliplevel rather than during level creation */ /* flip hero location only if inside the flippable area */ if (inFlipArea(u.ux, u.uy)) { @@ -5430,18 +5453,27 @@ lspo_exclusion(lua_State *L) }; struct exclusion_zone *ez = (struct exclusion_zone *) alloc(sizeof *ez); lua_Integer x1,y1,x2,y2; + coordxy a1,b1,a2,b2; create_des_coder(); lcheck_param_table(L); ez->zonetype = ez_types2i[get_table_option(L, "type", "teleport", ez_types)]; get_table_region(L, "region", &x1, &y1, &x2, &y2, FALSE); - ez->lx = x1; - ez->ly = y1; - ez->hx = x2; - ez->hy = y2; - cvt_to_abscoord(&ez->lx, &ez->ly); - cvt_to_abscoord(&ez->hx, &ez->hy); + + a1 = x1, b1 = y1; + a2 = x2, b2 = y2; + + get_location_coord(&a1, &b1, ANY_LOC|NO_LOC_WARN, gc.coder->croom, + SP_COORD_PACK(a1, b1)); + get_location_coord(&a2, &b2, ANY_LOC|NO_LOC_WARN, gc.coder->croom, + SP_COORD_PACK(a2, b2)); + + ez->lx = a1; + ez->ly = b1; + ez->hx = a2; + ez->hy = b2; + ez->next = sve.exclusion_zones; sve.exclusion_zones = ez; return 0; From f12635ccd91b21bf8038880043a5244b3e0371d8 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Fri, 18 Oct 2024 13:26:43 +0300 Subject: [PATCH 024/791] Prevent monster generation in the sokoban trap hallway Makes Sokoban far less tedious when you don't have to worry about monsters randomly popping up in the trap hallway while you're pushing the boulder. Adds a new exclusion zone for monster generation, and the goodpos routine avoids the zones when GP_AVOID_MONPOS is used. --- dat/soko1-1.lua | 2 ++ dat/soko1-2.lua | 2 ++ dat/soko2-1.lua | 2 ++ dat/soko2-2.lua | 2 ++ dat/soko3-1.lua | 2 ++ dat/soko3-2.lua | 2 ++ dat/soko4-1.lua | 2 ++ dat/soko4-2.lua | 3 +++ doc/fixes3-7-0.txt | 3 ++- doc/lua.adoc | 5 +++-- include/dungeon.h | 3 ++- include/extern.h | 3 +++ src/makemon.c | 2 +- src/mkmaze.c | 3 +-- src/sp_lev.c | 4 ++-- src/teleport.c | 14 ++++++++++++++ 16 files changed, 45 insertions(+), 9 deletions(-) diff --git a/dat/soko1-1.lua b/dat/soko1-1.lua index bd90ecdc4..ba5a9dfd7 100644 --- a/dat/soko1-1.lua +++ b/dat/soko1-1.lua @@ -59,6 +59,8 @@ des.object("boulder", 09, 12); -- des.object("boulder", 03, 14); +-- prevent monster generation over the (filled) holes +des.exclusion({ type = "monster-generation", region = { 08,01, 23,01 } }); -- Traps des.trap("hole", 08, 01); des.trap("hole", 09, 01); diff --git a/dat/soko1-2.lua b/dat/soko1-2.lua index aff446df5..2ff3a9feb 100644 --- a/dat/soko1-2.lua +++ b/dat/soko1-2.lua @@ -60,6 +60,8 @@ des.object("boulder",10,08); des.object("boulder",12,09); des.object("boulder",11,10); +-- prevent monster generation over the (filled) holes +des.exclusion({ type = "monster-generation", region = { 05,01, 22,01 } }); -- Traps des.trap("hole",05,01) des.trap("hole",06,01) diff --git a/dat/soko2-1.lua b/dat/soko2-1.lua index 42cdcc5dd..eb66e0fbf 100644 --- a/dat/soko2-1.lua +++ b/dat/soko2-1.lua @@ -46,6 +46,8 @@ des.object("boulder",03,09) des.object("boulder",05,07) des.object("boulder",06,06) +-- prevent monster generation over the (filled) holes +des.exclusion({ type = "monster-generation", region = { 07,09, 18,09 } }); -- Traps des.trap("hole",08,09) des.trap("hole",09,09) diff --git a/dat/soko2-2.lua b/dat/soko2-2.lua index 27af1df10..1302a1b5e 100644 --- a/dat/soko2-2.lua +++ b/dat/soko2-2.lua @@ -46,6 +46,8 @@ des.object("boulder",06,09) des.object("boulder",05,10) des.object("boulder",05,11) +-- prevent monster generation over the (filled) holes +des.exclusion({ type = "monster-generation", region = { 06,11, 18,11 } }); -- Traps des.trap("hole",07,11) des.trap("hole",08,11) diff --git a/dat/soko3-1.lua b/dat/soko3-1.lua index bf14fbfad..2515ffca1 100644 --- a/dat/soko3-1.lua +++ b/dat/soko3-1.lua @@ -52,6 +52,8 @@ des.object("boulder",09,09) des.object("boulder",10,07) des.object("boulder",10,10) +-- prevent monster generation over the (filled) holes +des.exclusion({ type = "monster-generation", region = { 11,10, 27,10 } }); -- Traps des.trap("hole",12,10) des.trap("hole",13,10) diff --git a/dat/soko3-2.lua b/dat/soko3-2.lua index 855575552..1015125d6 100644 --- a/dat/soko3-2.lua +++ b/dat/soko3-2.lua @@ -47,6 +47,8 @@ des.object("boulder",07,10) des.object("boulder",10,10) des.object("boulder",03,11) +-- prevent monster generation over the (filled) holes +des.exclusion({ type = "monster-generation", region = { 12,10, 24,10 } }); -- Traps des.trap("hole",12,10) des.trap("hole",13,10) diff --git a/dat/soko4-1.lua b/dat/soko4-1.lua index 0998220f5..4c8f6d162 100644 --- a/dat/soko4-1.lua +++ b/dat/soko4-1.lua @@ -72,6 +72,8 @@ des.object("boulder",09,09) des.object("boulder",08,10) des.object("boulder",10,10) +-- prevent monster generation over the (filled) pits +des.exclusion({ type = "monster-generation", region = { 01,06, 07,11 } }); -- Traps des.trap("pit",03,06) des.trap("pit",04,06) diff --git a/dat/soko4-2.lua b/dat/soko4-2.lua index 6b994a95a..de749ad37 100644 --- a/dat/soko4-2.lua +++ b/dat/soko4-2.lua @@ -41,6 +41,9 @@ des.object("boulder",08,08) des.object("boulder",09,08) des.object("boulder",10,08) +-- prevent monster generation over the (filled) pits +des.exclusion({ type = "monster-generation", region = { 01,01, 01,09 } }); +des.exclusion({ type = "monster-generation", region = { 01,08, 07,09 } }); -- Traps des.trap("pit",01,02) des.trap("pit",01,03) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index 13910d97b..d6059729b 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -1237,7 +1237,7 @@ when a werecreature in human form attacked hero, it could transform to critter status highlighting for hit points didn't work as intended for up or down HP changes; 'up' rule was used for both, 'down' rule was ignored unhide an unseen water monster using a polymorph trap on land -allow defining random-teleport exclusion zones in lua +allow defining random-teleport or monster-generation exclusion zones in lua if Magicbane cancelled a shapeshifter, forcing it to 'unshift', subsequent messages continued to refer to the shifted form a pet that was poison resistant but not stoning resistant would eat Medusa's @@ -1473,6 +1473,7 @@ interactively setting a status highlight for hunger with 'O' and choosing use C++ regex processing but not for tty+posixregex a pet with the hides-under attribute could "move reluctantly over" a cursed object and then hide under it +prevent monster generation in the sokoban trap hallway Fixes to 3.7.0-x General Problems Exposed Via git Repository diff --git a/doc/lua.adoc b/doc/lua.adoc index 84758dc3f..66983807d 100644 --- a/doc/lua.adoc +++ b/doc/lua.adoc @@ -531,9 +531,10 @@ Example: === exclusion Exclude an area of the map from being randomly chosen target when -falling or teleporting into the level. Multiple exclusions per level are allowed. +falling or teleporting into the level, or creating a monster. +Multiple exclusions per level are allowed. -* type is one of "teleport", "teleport-up", or "teleport-down". +* type is one of "teleport", "teleport-up", "teleport-down", or "monster-generation". Example: diff --git a/include/dungeon.h b/include/dungeon.h index 09ea8dd0e..288b15b58 100644 --- a/include/dungeon.h +++ b/include/dungeon.h @@ -39,7 +39,8 @@ enum level_region_types { LR_BRANCH, LR_TELE, LR_UPTELE, - LR_DOWNTELE + LR_DOWNTELE, + LR_MONGEN, }; typedef struct dest_area { /* non-stairway level change identifier */ diff --git a/include/extern.h b/include/extern.h index 046045e7c..3b3d28f32 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1552,6 +1552,7 @@ extern void bound_digging(void); extern void mkportal(coordxy, coordxy, xint16, xint16); extern boolean bad_location(coordxy, coordxy, coordxy, coordxy, coordxy, coordxy); +extern boolean is_exclusion_zone(xint16, coordxy, coordxy); /* dungeon.c u_on_rndspot() passes NULL final arg to place_lregion() */ extern void place_lregion(coordxy, coordxy, coordxy, coordxy, coordxy, coordxy, coordxy, coordxy, xint16, d_level *) NO_NNARGS; @@ -3075,6 +3076,8 @@ extern boolean goodpos(coordxy, coordxy, struct monst *, mmflags_nht) NO_NNARGS; extern boolean enexto(coord *, coordxy, coordxy, struct permonst *) NONNULLARG1; +extern boolean enexto_gpflags(coord *, coordxy, coordxy, struct permonst *, + mmflags_nht) NONNULLARG1; extern boolean enexto_core(coord *, coordxy, coordxy, struct permonst *, mmflags_nht) NONNULLARG1; extern void teleds(coordxy, coordxy, int); diff --git a/src/makemon.c b/src/makemon.c index 828328ab2..ae32e8f39 100644 --- a/src/makemon.c +++ b/src/makemon.c @@ -129,7 +129,7 @@ m_initgrp( * are peaceful and some are not, the result will just be a * smaller group. */ - if (enexto(&mm, mm.x, mm.y, mtmp->data)) { + if (enexto_gpflags(&mm, mm.x, mm.y, mtmp->data, mmflags)) { mon = makemon(mtmp->data, mm.x, mm.y, (mmflags | MM_NOGRP)); if (mon) { mon->mpeaceful = FALSE; diff --git a/src/mkmaze.c b/src/mkmaze.c index d485dabdf..4237e00e9 100644 --- a/src/mkmaze.c +++ b/src/mkmaze.c @@ -26,7 +26,6 @@ staticfn void stolen_booty(void); staticfn boolean maze_inbounds(coordxy, coordxy); staticfn void maze_remove_deadends(xint16); staticfn void populate_maze(void); -staticfn boolean is_exclusion_zone(xint16, coordxy, coordxy); /* adjust a coordinate one step in the specified direction */ #define mz_move(X, Y, dir) \ @@ -302,7 +301,7 @@ maze0xy(coord *cc) return; } -staticfn boolean +boolean is_exclusion_zone(xint16 type, coordxy x, coordxy y) { struct exclusion_zone *ez = sve.exclusion_zones; diff --git a/src/sp_lev.c b/src/sp_lev.c index 0796757bd..5e7be44e7 100644 --- a/src/sp_lev.c +++ b/src/sp_lev.c @@ -5446,10 +5446,10 @@ int lspo_exclusion(lua_State *L) { static const char *const ez_types[] = { - "teleport", "teleport-up", "teleport-down", NULL + "teleport", "teleport-up", "teleport-down", "monster-generation", NULL }; static const int ez_types2i[] = { - LR_TELE, LR_UPTELE, LR_DOWNTELE, 0 + LR_TELE, LR_UPTELE, LR_DOWNTELE, LR_MONGEN, 0 }; struct exclusion_zone *ez = (struct exclusion_zone *) alloc(sizeof *ez); lua_Integer x1,y1,x2,y2; diff --git a/src/teleport.c b/src/teleport.c index e4aeedbe3..5b51a3a0a 100644 --- a/src/teleport.c +++ b/src/teleport.c @@ -172,6 +172,9 @@ goodpos( /* skip boulder locations for most creatures */ if (sobj_at(BOULDER, x, y) && (!mdat || !throws_rocks(mdat))) return FALSE; + /* pretend GP_AVOID_MONPOS == monster creation */ + if (avoid_monpos && is_exclusion_zone(LR_MONGEN, x, y)) + return FALSE; return TRUE; } @@ -194,6 +197,17 @@ enexto( || enexto_core(cc, xx, yy, mdat, NO_MM_FLAGS)); } +boolean +enexto_gpflags( + coord *cc, + coordxy xx, coordxy yy, + struct permonst *mdat, + mmflags_nht entflags) +{ + return (enexto_core(cc, xx, yy, mdat, GP_CHECKSCARY | entflags) + || enexto_core(cc, xx, yy, mdat, entflags)); +} + #ifdef NEW_ENEXTO boolean From c33a6e7c0b6abecae0858ee4bc6538372a7193ac Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Fri, 18 Oct 2024 14:20:24 +0300 Subject: [PATCH 025/791] Wizmode wishing for undiggable/unphaseable walls --- src/objnam.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/objnam.c b/src/objnam.c index dfb6ab11d..a76029069 100644 --- a/src/objnam.c +++ b/src/objnam.c @@ -48,6 +48,7 @@ staticfn boolean badman(const char *, boolean); staticfn boolean wishymatch(const char *, const char *, boolean); staticfn short rnd_otyp_by_wpnskill(schar); staticfn short rnd_otyp_by_namedesc(const char *, char, int); +staticfn void set_wallprop_from_str(char *) NONNULLARG1; staticfn struct obj *wizterrainwish(struct _readobjnam_data *); staticfn void dbterrainmesg(const char *, coordxy, coordxy) NONNULLARG1; staticfn void readobjnam_init(char *, struct _readobjnam_data *); @@ -3479,6 +3480,20 @@ shiny_obj(char oclass) return (int) rnd_otyp_by_namedesc("shiny", oclass, 0); } +/* set wall under hero undiggable/unphaseable from string */ +staticfn void +set_wallprop_from_str(char *bp) +{ + int wall_prop = 0; + + if (strstr(bp, "undiggable ") || strstr(bp, "nondiggable ")) + wall_prop |= W_NONDIGGABLE; + if (strstr(bp, "unphaseable ") || strstr(bp, "nonpasswall ")) + wall_prop |= W_NONPASSWALL; + if (wall_prop) + levl[u.ux][u.uy].wall_info = wall_prop; +} + /* in wizard mode, readobjnam() can accept wishes for traps and terrain */ staticfn struct obj * wizterrainwish(struct _readobjnam_data *d) @@ -3649,11 +3664,13 @@ wizterrainwish(struct _readobjnam_data *d) } else if (!BSTRCMPI(bp, p - 4, "tree")) { lev->typ = TREE; lev->looted = d->looted ? (TREE_LOOTED | TREE_SWARM) : 0; + set_wallprop_from_str(bp); pline("A tree."); madeterrain = TRUE; } else if (!BSTRCMPI(bp, p - 4, "bars")) { lev->typ = IRONBARS; lev->flags = 0; + set_wallprop_from_str(bp); /* [FIXME: if this isn't a wall or door location where 'horizontal' is already set up, that should be calculated for this spot. Unfortunately, it can be tricky; placing one in open space @@ -3750,7 +3767,7 @@ wizterrainwish(struct _readobjnam_data *d) badterrain = TRUE; } } else if (!BSTRCMPI(bp, p - 4, "wall") - && (bp == p - 4 || p[-4] == ' ')) { + && (bp == p - 4 || p[-5] == ' ')) { schar wall = HWALL; if ((isok(u.ux, u.uy-1) && IS_WALL(levl[u.ux][u.uy-1].typ)) @@ -3758,6 +3775,7 @@ wizterrainwish(struct _readobjnam_data *d) wall = VWALL; madeterrain = TRUE; lev->typ = wall; + set_wallprop_from_str(bp); fix_wall_spines(max(0,u.ux-1), max(0,u.uy-1), min(COLNO,u.ux+1), min(ROWNO,u.uy+1)); pline("A wall."); From 0530ca0758e53e4e96749816d7f08b01d78c5418 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Fri, 18 Oct 2024 16:52:23 +0300 Subject: [PATCH 026/791] Fix the undiggable/nonpasswall stuff wall_info (aka flags) is overloaded with other stuff. --- src/objnam.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/objnam.c b/src/objnam.c index a76029069..47c9eca44 100644 --- a/src/objnam.c +++ b/src/objnam.c @@ -3490,8 +3490,9 @@ set_wallprop_from_str(char *bp) wall_prop |= W_NONDIGGABLE; if (strstr(bp, "unphaseable ") || strstr(bp, "nonpasswall ")) wall_prop |= W_NONPASSWALL; + /* |= because wall_info (aka flags) is overloaded with other stuff */ if (wall_prop) - levl[u.ux][u.uy].wall_info = wall_prop; + levl[u.ux][u.uy].wall_info |= wall_prop; } /* in wizard mode, readobjnam() can accept wishes for traps and terrain */ @@ -3775,6 +3776,7 @@ wizterrainwish(struct _readobjnam_data *d) wall = VWALL; madeterrain = TRUE; lev->typ = wall; + lev->flags = 0; set_wallprop_from_str(bp); fix_wall_spines(max(0,u.ux-1), max(0,u.uy-1), min(COLNO,u.ux+1), min(ROWNO,u.uy+1)); From d35aa35c3f4d6ff9afafe9b1d5f7463fe55615a3 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Fri, 18 Oct 2024 17:53:52 +0300 Subject: [PATCH 027/791] Don't put the unknown command message into history Even with Norep, it was cluttering the message history buffer. --- src/cmd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cmd.c b/src/cmd.c index 725ce0d47..020786eab 100644 --- a/src/cmd.c +++ b/src/cmd.c @@ -3507,7 +3507,7 @@ rhack(int key) } if (bad_command) { - Norep("Unknown command '%s'.", visctrl(key)); + custompline(SUPPRESS_HISTORY, "Unknown command '%s'.", visctrl(key)); cmdq_clear(CQ_CANNED); cmdq_clear(CQ_REPEAT); } From 696af8929902c07d247b068412ad4a00f6793551 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sat, 19 Oct 2024 10:47:53 +0300 Subject: [PATCH 028/791] Change MSGHANDLER from compile-time to sysconf --- doc/Guidebook.mn | 4 ++++ doc/Guidebook.tex | 5 +++++ doc/fixes3-7-0.txt | 1 + include/config.h | 6 ------ include/sys.h | 1 + src/files.c | 11 +++++++++++ src/mdlib.c | 3 --- src/pline.c | 26 ++++++-------------------- src/sys.c | 3 +++ sys/unix/sysconf | 4 ++++ sys/windows/sysconf.template | 4 ++++ 11 files changed, 39 insertions(+), 29 deletions(-) diff --git a/doc/Guidebook.mn b/doc/Guidebook.mn index 549f9c0b7..4b9dbe4a0 100644 --- a/doc/Guidebook.mn +++ b/doc/Guidebook.mn @@ -6064,6 +6064,10 @@ escape command (!). The syntax is the same as WIZARDS. EXPLORERS\ =\ A list of users who are allowed to use the explore mode. The syntax is the same as WIZARDS. .lp +MSGHANDLER\ =\ A path and filename of executable. Whenever a message-window +message is shown, NetHack runs this program. The program will get +the message as the only parameter. +.lp MAXPLAYERS\ =\ Limit the maximum number of games that can be running at the same time. .lp diff --git a/doc/Guidebook.tex b/doc/Guidebook.tex index d71cbd330..95d7d5314 100644 --- a/doc/Guidebook.tex +++ b/doc/Guidebook.tex @@ -6703,6 +6703,11 @@ The syntax is the same as WIZARDS. A list of users who are allowed to use the explore mode. The syntax is the same as WIZARDS. %.lp +\item[\ib{MSGHANDLER}] +A path and filename of executable. Whenever a message-window +message is shown, NetHack runs this program. The program will get +the message as the only parameter. +%.lp \item[\ib{MAXPLAYERS}] Limit the maximum number of games that can be running at the same time. %.lp diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index d6059729b..08db1ae00 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -1474,6 +1474,7 @@ interactively setting a status highlight for hunger with 'O' and choosing a pet with the hides-under attribute could "move reluctantly over" a cursed object and then hide under it prevent monster generation in the sokoban trap hallway +change MSGHANDLER from compile-time to sysconf option Fixes to 3.7.0-x General Problems Exposed Via git Repository diff --git a/include/config.h b/include/config.h index 9b77a7d10..64910138b 100644 --- a/include/config.h +++ b/include/config.h @@ -641,12 +641,6 @@ typedef unsigned char uchar; * at least 28 additional rows beneath the status window on your terminal */ /* #define TTY_PERM_INVENT */ -/* NetHack will execute an external program whenever a new message-window - * message is shown. The program to execute is given in environment variable - * NETHACK_MSGHANDLER. It will get the message as the only parameter. - * Only available with POSIX_TYPES, GNU C, or WIN32 */ -/* #define MSGHANDLER */ - /* enable status highlighting via STATUS_HILITE directives in run-time config file and the 'statushilites' option */ #define STATUS_HILITES /* support hilites of status fields */ diff --git a/include/sys.h b/include/sys.h index 32d9221cc..764d7435f 100644 --- a/include/sys.h +++ b/include/sys.h @@ -15,6 +15,7 @@ struct sysopt { char *shellers; /* like wizards, for ! command (-DSHELL); also ^Z */ char *genericusers; /* usernames that prompt for user name */ char *debugfiles; /* files to show debugplines in. '*' is all. */ + char *msghandler; #ifdef DUMPLOG char *dumplogfile; /* where the dump file is saved */ #endif diff --git a/src/files.c b/src/files.c index e4834e2ae..b214c7a55 100644 --- a/src/files.c +++ b/src/files.c @@ -173,6 +173,7 @@ staticfn boolean cnf_line_catname(char *); #ifdef SYSCF staticfn boolean cnf_line_WIZARDS(char *); staticfn boolean cnf_line_SHELLERS(char *); +staticfn boolean cnf_line_MSGHANDLER(char *); staticfn boolean cnf_line_EXPLORERS(char *); staticfn boolean cnf_line_DEBUGFILES(char *); staticfn boolean cnf_line_DUMPLOGFILE(char *); @@ -2756,6 +2757,15 @@ cnf_line_SHELLERS(char *bufp) return TRUE; } +staticfn boolean +cnf_line_MSGHANDLER(char *bufp) +{ + if (sysopt.msghandler) + free((genericptr_t) sysopt.msghandler); + sysopt.msghandler = dupstr(bufp); + return TRUE; +} + staticfn boolean cnf_line_EXPLORERS(char *bufp) { @@ -3272,6 +3282,7 @@ static const struct match_config_line_stmt { #ifdef SYSCF CNFL_S(WIZARDS, 7), CNFL_S(SHELLERS, 8), + CNFL_S(MSGHANDLER, 9), CNFL_S(EXPLORERS, 7), CNFL_S(DEBUGFILES, 5), CNFL_S(DUMPLOGFILE, 7), diff --git a/src/mdlib.c b/src/mdlib.c index b6da48e33..9e7700cc8 100644 --- a/src/mdlib.c +++ b/src/mdlib.c @@ -478,9 +478,6 @@ static const char *const build_opts[] = { #ifdef HOLD_LOCKFILE_OPEN "exclusive lock on level 0 file", #endif -#ifdef MSGHANDLER - "external program as a message handler", -#endif #if defined(HANGUPHANDLING) && !defined(NO_SIGNAL) #ifdef SAFERHANGUP "deferred handling of hangup signal", diff --git a/src/pline.c b/src/pline.c index 4ca4a79a7..4cf52bc2e 100644 --- a/src/pline.c +++ b/src/pline.c @@ -11,9 +11,7 @@ staticfn void putmesg(const char *); staticfn char *You_buf(int); -#if defined(MSGHANDLER) staticfn void execplinehandler(const char *); -#endif #ifdef USER_SOUNDS extern void maybe_play_sound(const char *); #endif @@ -262,9 +260,7 @@ vpline(const char *line, va_list the_args) putmesg(line); -#if defined(MSGHANDLER) execplinehandler(line); -#endif /* this gets cleared after every pline message */ iflags.last_msg = PLNMSG_UNKNOWN; @@ -564,9 +560,7 @@ vraw_printf(const char *line, va_list the_args) pbuf[BUFSZ - 1] = '\0'; /* terminate strncpy or truncate vsprintf */ } raw_print(line); -#if defined(MSGHANDLER) execplinehandler(line); -#endif if (!program_state.beyond_savefile_load) ge.early_raw_messages++; } @@ -626,7 +620,6 @@ impossible(const char *s, ...) RESTORE_WARNING_FORMAT_NONLITERAL -#if defined(MSGHANDLER) static boolean use_pline_handler = TRUE; staticfn void @@ -636,27 +629,21 @@ execplinehandler(const char *line) int f; #endif const char *args[3]; - char *env; - if (!use_pline_handler) + if (!use_pline_handler || !sysopt.msghandler) return; - if (!(env = nh_getenv("NETHACK_MSGHANDLER"))) { - use_pline_handler = FALSE; - return; - } - #if defined(POSIX_TYPES) || defined(__GNUC__) f = fork(); if (f == 0) { /* child */ - args[0] = env; + args[0] = sysopt.msghandler; args[1] = line; args[2] = NULL; (void) setgid(getgid()); (void) setuid(getuid()); (void) execv(args[0], (char *const *) args); perror((char *) 0); - (void) fprintf(stderr, "Exec to message handler %s failed.\n", env); + (void) fprintf(stderr, "Exec to message handler %s failed.\n", sysopt.msghandler); nh_terminate(EXIT_FAILURE); } else if (f > 0) { int status; @@ -670,16 +657,15 @@ execplinehandler(const char *line) #elif defined(WIN32) { intptr_t ret; - args[0] = env; + args[0] = sysopt.msghandler; args[1] = line; args[2] = NULL; - ret = _spawnv(_P_NOWAIT, env, args); + ret = _spawnv(_P_NOWAIT, sysopt.msghandler, args); } #else -#error MSGHANDLER is not implemented on this system. + use_pline_handler = FALSE; #endif } -#endif /* MSGHANDLER */ /* * varargs handling for files.c diff --git a/src/sys.c b/src/sys.c index ad2274fbe..2cef92a87 100644 --- a/src/sys.c +++ b/src/sys.c @@ -48,6 +48,7 @@ sys_early_init(void) sysopt.shellers = (char *) 0; sysopt.explorers = (char *) 0; sysopt.genericusers = (char *) 0; + sysopt.msghandler = (char *) 0; sysopt.maxplayers = 0; /* XXX eventually replace MAX_NR_OF_PLAYERS */ sysopt.bones_pools = 0; sysopt.livelog = LL_NONE; @@ -115,6 +116,8 @@ sysopt_release(void) free((genericptr_t) sysopt.debugfiles), sysopt.debugfiles = (char *) 0; sysopt.env_dbgfl = 0; + if (sysopt.msghandler) + free((genericptr_t) sysopt.msghandler), sysopt.msghandler = (char *) 0; #ifdef DUMPLOG if (sysopt.dumplogfile) free((genericptr_t) sysopt.dumplogfile), sysopt.dumplogfile=(char *) 0; diff --git a/sys/unix/sysconf b/sys/unix/sysconf index e10b4e34c..34926903b 100644 --- a/sys/unix/sysconf +++ b/sys/unix/sysconf @@ -32,6 +32,10 @@ EXPLORERS=* # Uses the same syntax as the WIZARDS and EXPLORERS options above. #SHELLERS= +# Execute this program whenever a new message-window message is shown. +# The program will get the message text as the only parameter. +#MSGHANDLER=/usr/bin/espeak + # If the user name is found in this list, prompt for username instead. # Uses the same syntax as the WIZARDS option above. # A public server should probably disable this. diff --git a/sys/windows/sysconf.template b/sys/windows/sysconf.template index 36f3651bc..90095dc1b 100644 --- a/sys/windows/sysconf.template +++ b/sys/windows/sysconf.template @@ -15,6 +15,10 @@ WIZARDS=* # Uses the same syntax as the WIZARDS option above. #SHELLERS= +# Execute this program whenever a new message-window message is shown. +# The program will get the message text as the only parameter. +#MSGHANDLER=\path\program + # Show debugging information originating from these source files. # Use '*' for all, or list source files separated by spaces. # Only available if game has been compiled with DEBUG. From 64bb0e21440c6bdfa6049d5f7eefec9610d67cc7 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 19 Oct 2024 07:28:12 -0400 Subject: [PATCH 029/791] msghandler follow-up: fix mingw/MSYS2 build --- src/pline.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pline.c b/src/pline.c index 4cf52bc2e..879f48003 100644 --- a/src/pline.c +++ b/src/pline.c @@ -625,7 +625,7 @@ static boolean use_pline_handler = TRUE; staticfn void execplinehandler(const char *line) { -#if defined(POSIX_TYPES) || defined(__GNUC__) +#if defined(UNIX) && (defined(POSIX_TYPES) || defined(__GNUC__)) int f; #endif const char *args[3]; @@ -633,7 +633,7 @@ execplinehandler(const char *line) if (!use_pline_handler || !sysopt.msghandler) return; -#if defined(POSIX_TYPES) || defined(__GNUC__) +#if defined(UNIX) && (defined(POSIX_TYPES) || defined(__GNUC__)) f = fork(); if (f == 0) { /* child */ args[0] = sysopt.msghandler; From 945ccff1ff3ca2f3fcad301e7aa449ee9203f998 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sat, 19 Oct 2024 14:45:21 +0300 Subject: [PATCH 030/791] Allow changing command autocompletions via #optionsfull --- doc/fixes3-7-0.txt | 1 + include/extern.h | 2 ++ include/optlist.h | 2 ++ src/cmd.c | 89 ++++++++++++++++++++++++++++++++++++++++++++-- src/options.c | 22 ++++++++++++ 5 files changed, 114 insertions(+), 2 deletions(-) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index 08db1ae00..0c160a176 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -1475,6 +1475,7 @@ a pet with the hides-under attribute could "move reluctantly over" a cursed object and then hide under it prevent monster generation in the sokoban trap hallway change MSGHANDLER from compile-time to sysconf option +allow changing extended command autocompletions via #optionsfull Fixes to 3.7.0-x General Problems Exposed Via git Repository diff --git a/include/extern.h b/include/extern.h index 3b3d28f32..7eaa68e65 100644 --- a/include/extern.h +++ b/include/extern.h @@ -394,8 +394,10 @@ extern char extcmd_initiator(void); extern int doextcmd(void); extern struct ext_func_tab *extcmds_getentry(int); extern int count_bind_keys(void); +extern int count_autocompletions(void); extern void get_changed_key_binds(strbuf_t *); extern void handler_rebind_keys(void); +extern void handler_change_autocompletions(void); extern int extcmds_match(const char *, int, int **); extern const char *key2extcmddesc(uchar); extern boolean bind_specialkey(uchar, const char *); diff --git a/include/optlist.h b/include/optlist.h index 08288fd08..0a2234ed2 100644 --- a/include/optlist.h +++ b/include/optlist.h @@ -167,6 +167,8 @@ static int optfn_##a(int, int, boolean, char *, char *); NHOPTB(ascii_map, Advanced, 0, opt_in, set_in_game, ascii_map_Def, Yes, No, No, NoAlias, &iflags.wc_ascii_map, Term_False, "show map as text") + NHOPTO("autocompletions", Advanced, o_autocomplete, BUFSZ, opt_in, set_in_game, + No, Yes, No, NoAlias, "edit autocompletions") NHOPTB(autodescribe, Advanced, 0, opt_out, set_in_game, On, Yes, No, No, NoAlias, &iflags.autodescribe, Term_False, "describe terrain under cursor") diff --git a/src/cmd.c b/src/cmd.c index 020786eab..557edffd2 100644 --- a/src/cmd.c +++ b/src/cmd.c @@ -2266,6 +2266,73 @@ handler_rebind_keys(void) } } +void +handler_change_autocompletions(void) +{ + winid win; + anything any; + int i, n; + menu_item *picks = (menu_item *) 0; + int clr = NO_COLOR; + struct ext_func_tab *ec; + char buf[BUFSZ]; + + win = create_nhwindow(NHW_MENU); + start_menu(win, MENU_BEHAVE_STANDARD); + any = cg.zeroany; + + for (i = 0; i < extcmdlist_length; i++) { + ec = &extcmdlist[i]; + + if ((ec->flags & (INTERNALCMD|CMD_NOT_AVAILABLE)) != 0) + continue; + if (strlen(ec->ef_txt) < 2) + continue; + + any.a_int = (i + 1); + Sprintf(buf, "%c %s: %s", + (ec->flags & AUTOCOMP_ADJ) ? '*' : ' ', + ec->ef_txt, ec->ef_desc); + add_menu(win, &nul_glyphinfo, &any, '\0', 0, ATR_NONE, clr, buf, + (ec->flags & AUTOCOMPLETE) + ? MENU_ITEMFLAGS_SELECTED : + MENU_ITEMFLAGS_NONE); + } + + end_menu(win, "Which commands autocomplete?"); + n = select_menu(win, PICK_ANY, &picks); + if (n >= 0) { + int j; + + for (i = 0; i < extcmdlist_length; i++) { + boolean setit = FALSE; + + ec = &extcmdlist[i]; + + if ((ec->flags & (INTERNALCMD|CMD_NOT_AVAILABLE)) != 0) + continue; + if (strlen(ec->ef_txt) < 2) + continue; + + Sprintf(buf, "%s", ec->ef_txt); + + for (j = 0; j < n; ++j) { + if (ec == &extcmdlist[(picks[j].item.a_int - 1)]) { + parseautocomplete(buf, TRUE); + setit = TRUE; + break; + } + } + + if (!setit) { + parseautocomplete(buf, FALSE); + } + } + } + + destroy_nhwindow(win); +} + /* find extended command entries matching findstr. if findstr is NULL, returns all available entries. returns: number of matching extended commands, @@ -2972,8 +3039,12 @@ parseautocomplete(char *autocomplete, boolean condition) /* find and modify the extended command */ for (efp = extcmdlist; efp->ef_txt; efp++) { if (!strcmp(autocomplete, efp->ef_txt)) { - if (condition == ((efp->flags & AUTOCOMPLETE) ? FALSE : TRUE)) - efp->flags |= AUTOCOMP_ADJ; + if (condition == ((efp->flags & AUTOCOMPLETE) ? FALSE : TRUE)) { + if ((efp->flags & AUTOCOMP_ADJ)) + efp->flags &= ~AUTOCOMP_ADJ; + else + efp->flags |= AUTOCOMP_ADJ; + } if (condition) efp->flags |= AUTOCOMPLETE; else @@ -3004,6 +3075,20 @@ all_options_autocomplete(strbuf_t *sbuf) } } +/* return the number of changed autocompletions */ +int +count_autocompletions(void) +{ + struct ext_func_tab *efp; + int n = 0; + + for (efp = extcmdlist; efp->ef_txt; efp++) + if ((efp->flags & AUTOCOMP_ADJ) != 0) + n++; + + return n; +} + /* save&clear the mouse button actions, or restore the saved ones */ void lock_mouse_buttons(boolean savebtns) diff --git a/src/options.c b/src/options.c index 28eaa91c3..769f0d840 100644 --- a/src/options.c +++ b/src/options.c @@ -8164,6 +8164,28 @@ optfn_o_bind_keys( return optn_ok; } +staticfn int +optfn_o_autocomplete( + int optidx UNUSED, int req, boolean negated UNUSED, + char *opts, char *op UNUSED) +{ + if (req == do_init) { + return optn_ok; + } + if (req == do_set) { + } + if (req == get_val || req == get_cnf_val) { + if (!opts) + return optn_err; + Sprintf(opts, n_currently_set, count_autocompletions()); + return optn_ok; + } + if (req == do_handler) { + handler_change_autocompletions(); + } + return optn_ok; +} + staticfn int optfn_o_menu_colors(int optidx UNUSED, int req, boolean negated UNUSED, char *opts, char *op UNUSED) From 5eefeaf0099f4d587f1edff5afdf5ddfe85e34d7 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 19 Oct 2024 08:02:03 -0400 Subject: [PATCH 031/791] msghandler follow-up: msdos cross-compile warnings pline.c: In function 'execplinehandler': pline.c:631:17: warning: unused variable 'args' [-Wunused-variable] 631 | const char *args[3]; | ^~~~ pline.c:626:30: warning: unused parameter 'line' [-Wunused-parameter] 626 | execplinehandler(const char *line) | ~~~~~~~~~~~~^~~~ --- src/pline.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/pline.c b/src/pline.c index 879f48003..22dddcf34 100644 --- a/src/pline.c +++ b/src/pline.c @@ -664,6 +664,8 @@ execplinehandler(const char *line) } #else use_pline_handler = FALSE; + nhUse(args); + nhUse(line); #endif } From 25061dbce4615c0e44d32f32e7b99e55afa4ebb5 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Wed, 23 Oct 2024 23:41:24 +0300 Subject: [PATCH 032/791] Remove magic members from instance globals. We ought to trust compiler and we have other tools to check oob access. --- include/decl.h | 26 -------------------------- src/decl.c | 34 ---------------------------------- 2 files changed, 60 deletions(-) diff --git a/include/decl.h b/include/decl.h index 415d710b1..e7f7fd4bb 100644 --- a/include/decl.h +++ b/include/decl.h @@ -181,7 +181,6 @@ struct instance_globals_a { struct h2o_ctx acid_ctx; boolean havestate; - unsigned long magic; /* validate that structure layout is preserved */ }; struct instance_globals_b { @@ -219,7 +218,6 @@ struct instance_globals_b { boolean bot_disabled; boolean havestate; - unsigned long magic; /* validate that structure layout is preserved */ }; struct instance_globals_c { @@ -299,7 +297,6 @@ struct instance_globals_c { /* zap.c */ boolean havestate; - unsigned long magic; /* validate that structure layout is preserved */ }; struct instance_globals_d { @@ -341,7 +338,6 @@ struct instance_globals_d { boolean decor_levitate_override; boolean havestate; - unsigned long magic; /* validate that structure layout is preserved */ }; struct instance_globals_e { @@ -362,7 +358,6 @@ struct instance_globals_e { to gb.beyond_savefile_load */ boolean havestate; - unsigned long magic; /* validate that structure layout is preserved */ }; struct instance_globals_f { @@ -387,7 +382,6 @@ struct instance_globals_f { long int followmsg; /* last time of follow message */ boolean havestate; - unsigned long magic; /* validate that structure layout is preserved */ }; struct instance_globals_g { @@ -435,7 +429,6 @@ struct instance_globals_g { long glyphmap_perlevel_flags; boolean havestate; - unsigned long magic; /* validate that structure layout is preserved */ }; struct instance_globals_h { @@ -456,7 +449,6 @@ struct instance_globals_h { struct attack *hitmsg_prev; boolean havestate; - unsigned long magic; /* validate that structure layout is preserved */ }; struct instance_globals_i { @@ -490,7 +482,6 @@ struct instance_globals_i { /* new */ boolean havestate; - unsigned long magic; /* validate that structure layout is preserved */ }; struct instance_globals_j { @@ -499,7 +490,6 @@ struct instance_globals_j { int jumping_is_magic; /* current jump result of magic */ boolean havestate; - unsigned long magic; /* validate that structure layout is preserved */ }; struct instance_globals_k { @@ -513,7 +503,6 @@ struct instance_globals_k { boolean known; boolean havestate; - unsigned long magic; /* validate that structure layout is preserved */ }; struct instance_globals_l { @@ -579,7 +568,6 @@ struct instance_globals_l { char lua_copyright[LUA_COPYRIGHT_BUFSIZ]; boolean havestate; - unsigned long magic; /* validate that structure layout is preserved */ }; struct instance_globals_m { @@ -646,7 +634,6 @@ struct instance_globals_m { * POT_WATER should become discovered */ boolean havestate; - unsigned long magic; /* validate that structure layout is preserved */ }; struct instance_globals_n { @@ -696,7 +683,6 @@ struct instance_globals_n { short nocreate4; boolean havestate; - unsigned long magic; /* validate that structure layout is preserved */ }; struct instance_globals_o { @@ -755,7 +741,6 @@ struct instance_globals_o { boolean obj_zapped; boolean havestate; - unsigned long magic; /* validate that structure layout is preserved */ }; struct instance_globals_p { @@ -806,13 +791,11 @@ struct instance_globals_p { /* new stuff */ boolean havestate; - unsigned long magic; /* validate that structure layout is preserved */ }; struct instance_globals_q { boolean havestate; - unsigned long magic; /* validate that structure layout is preserved */ }; struct instance_globals_r { @@ -841,7 +824,6 @@ struct instance_globals_r { struct repo repo; boolean havestate; - unsigned long magic; /* validate that structure layout is preserved */ }; struct instance_globals_s { @@ -923,7 +905,6 @@ struct instance_globals_s { int seethru; /* 'bubble' debugging: clouds and water don't block light */ boolean havestate; - unsigned long magic; /* validate that structure layout is preserved */ }; struct instance_globals_t { @@ -974,7 +955,6 @@ struct instance_globals_t { int twohits; /* 0: single hit; 1: first of 2; 2: second of 2 */ boolean havestate; - unsigned long magic; /* validate that structure layout is preserved */ }; struct instance_globals_u { @@ -994,7 +974,6 @@ struct instance_globals_u { /* new stuff */ boolean havestate; - unsigned long magic; /* validate that structure layout is preserved */ }; struct instance_globals_v { @@ -1031,7 +1010,6 @@ struct instance_globals_v { struct sound_voice voice; boolean havestate; - unsigned long magic; /* validate that structure layout is preserved */ }; struct instance_globals_w { @@ -1056,7 +1034,6 @@ struct instance_globals_w { struct win_settings wsettings; /* wintype.h */ boolean havestate; - unsigned long magic; /* validate that structure layout is preserved */ }; struct instance_globals_x { @@ -1077,7 +1054,6 @@ struct instance_globals_x { coordxy xstart, xsize; boolean havestate; - unsigned long magic; /* validate that structure layout is preserved */ }; struct instance_globals_y { @@ -1095,7 +1071,6 @@ struct instance_globals_y { coordxy ystart, ysize; boolean havestate; - unsigned long magic; /* validate that structure layout is preserved */ }; struct instance_globals_z { @@ -1112,7 +1087,6 @@ struct instance_globals_z { * remember who zapped the wand. */ boolean havestate; - unsigned long magic; /* validate that structure layout is preserved */ }; struct instance_globals_saved_b { diff --git a/src/decl.c b/src/decl.c index 08b54e4f7..18927a8d8 100644 --- a/src/decl.c +++ b/src/decl.c @@ -146,8 +146,6 @@ NEARDATA long yn_number = 0L; const char *ARGV0; #endif -#define IVMAGIC 0xdeadbeef - static const struct Role urole_init_data = { { "Undefined", 0 }, { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, @@ -228,7 +226,6 @@ static const struct instance_globals_a g_init_a = { /* trap.c */ { 0, 0, FALSE }, /* acid_ctx */ TRUE, /* havestate*/ - IVMAGIC /* a_magic to validate that structure layout has been preserved */ }; static const struct instance_globals_b g_init_b = { @@ -261,7 +258,6 @@ static const struct instance_globals_b g_init_b = { FALSE, /* bot_disabled */ TRUE, /* havestate*/ - IVMAGIC /* b_magic to validate that structure layout has been preserved */ }; static const struct instance_globals_c g_init_c = { @@ -312,7 +308,6 @@ static const struct instance_globals_c g_init_c = { /* uhitm.c */ NON_PM, /* corpsenm_digested */ TRUE, /* havestate*/ - IVMAGIC /* c_magic to validate that structure layout has been preserved */ }; static const struct instance_globals_d g_init_d = { @@ -340,7 +335,6 @@ static const struct instance_globals_d g_init_d = { FALSE, /* decor_fumble_override */ FALSE, /* decor_levitate_override */ TRUE, /* havestate*/ - IVMAGIC /* d_magic to validate that structure layout has been preserved */ }; static const struct instance_globals_e g_init_e = { @@ -355,7 +349,6 @@ static const struct instance_globals_e g_init_e = { /* new */ 0, /* early_raw_messages */ TRUE, /* havestate*/ - IVMAGIC /* e_magic to validate that structure layout has been preserved */ }; static const struct instance_globals_f g_init_f = { @@ -374,7 +367,6 @@ static const struct instance_globals_f g_init_f = { /* shk.c */ 0L, /* followmsg */ TRUE, /* havestate*/ - IVMAGIC /* f_magic to validate that structure layout has been preserved */ }; static const struct instance_globals_g g_init_g = { @@ -411,7 +403,6 @@ static const struct instance_globals_g g_init_g = { /* per-level glyph mapping flags */ 0L, /* glyphmap_perlevel_flags */ TRUE, /* havestate*/ - IVMAGIC /* g_magic to validate that structure layout has been preserved */ }; static const struct instance_globals_h g_init_h = { @@ -430,7 +421,6 @@ static const struct instance_globals_h g_init_h = { NULL, /* hitmsg_prev */ /* save.c */ TRUE, /* havestate*/ - IVMAGIC /* h_magic to validate that structure layout has been preserved */ }; static const struct instance_globals_i g_init_i = { @@ -453,14 +443,12 @@ static const struct instance_globals_i g_init_i = { FALSE, /* in_mk_themerooms */ TRUE, /* havestate*/ - IVMAGIC /* i_magic to validate that structure layout has been preserved */ }; static const struct instance_globals_j g_init_j = { /* apply.c */ 0, /* jumping_is_magic */ TRUE, /* havestate*/ - IVMAGIC /* j_magic to validate that structure layout has been preserved */ }; static const struct instance_globals_k g_init_k = { @@ -470,7 +458,6 @@ static const struct instance_globals_k g_init_k = { /* read.c */ UNDEFINED_VALUE, /* known */ TRUE, /* havestate*/ - IVMAGIC /* k_magic to validate that structure layout has been preserved */ }; static const struct instance_globals_l g_init_l = { @@ -520,7 +507,6 @@ static const struct instance_globals_l g_init_l = { DUMMY, /* lua_ver[LUA_VER_BUFSIZ] */ DUMMY, /* lua_copyright[LUA_COPYRIGHT_BUFSIZ] */ TRUE, /* havestate*/ - IVMAGIC /* l_magic to validate that structure layout has been preserved */ }; static const struct instance_globals_m g_init_m = { @@ -569,7 +555,6 @@ static const struct instance_globals_m g_init_m = { /* trap.c */ FALSE, /* mentioned_water */ TRUE, /* havestate*/ - IVMAGIC /* m_magic to validate that structure layout has been preserved */ }; static const struct instance_globals_n g_init_n = { @@ -604,7 +589,6 @@ static const struct instance_globals_n g_init_n = { STRANGE_OBJECT, /* nocreate3 */ STRANGE_OBJECT, /* nocreate4 */ TRUE, /* havestate*/ - IVMAGIC /* n_magic to validate that structure layout has been preserved */ }; static const struct instance_globals_o g_init_o = { @@ -648,7 +632,6 @@ static const struct instance_globals_o g_init_o = { /* zap.c */ FALSE, /* obj_zapped */ TRUE, /* havestate*/ - IVMAGIC /* o_magic to validate that structure layout has been preserved */ }; static const struct instance_globals_p g_init_p = { @@ -684,12 +667,10 @@ static const struct instance_globals_p g_init_p = { /* zap.c */ UNDEFINED_VALUE, /* poly_zap */ TRUE, /* havestate*/ - IVMAGIC /* p_magic to validate that structure layout has been preserved */ }; static const struct instance_globals_q g_init_q = { TRUE, /* havestate*/ - IVMAGIC /* q_magic to validate that structure layout has been preserved */ }; static const struct instance_globals_r g_init_r = { @@ -710,7 +691,6 @@ static const struct instance_globals_r g_init_r = { /* shk.c */ UNDEFINED_VALUES, /* repo */ TRUE, /* havestate*/ - IVMAGIC /* r_magic to validate that structure layout has been preserved */ }; static const struct instance_globals_s g_init_s = { @@ -767,7 +747,6 @@ static const struct instance_globals_s g_init_s = { /* vision.c */ 0, /* seethru */ TRUE, /* havestate*/ - IVMAGIC /* s_magic to validate that structure layout has been preserved */ }; static const struct instance_globals_t g_init_t = { @@ -802,7 +781,6 @@ static const struct instance_globals_t g_init_t = { 0, /* twohits */ /**/ TRUE, /* havestate*/ - IVMAGIC /* t_magic to validate that structure layout has been preserved */ }; static const struct instance_globals_u g_init_u = { @@ -816,7 +794,6 @@ static const struct instance_globals_u g_init_u = { /* save.c */ { 0, 0 }, /* uz_save */ TRUE, /* havestate*/ - IVMAGIC /* u_magic to validate that structure layout has been preserved */ }; static const struct instance_globals_v g_init_v = { @@ -842,7 +819,6 @@ static const struct instance_globals_v g_init_v = { FALSE, /* vision_full_recalc */ UNDEFINED_VALUES, /* voice */ TRUE, /* havestate*/ - IVMAGIC /* v_magic to validate that structure layout has been preserved */ }; static const struct instance_globals_w g_init_w = { @@ -860,7 +836,6 @@ static const struct instance_globals_w g_init_w = { /* new */ { wdmode_traditional, NO_COLOR }, /* wsettings */ TRUE, /* havestate*/ - IVMAGIC /* w_magic to validate that structure layout has been preserved */ }; static const struct instance_globals_x g_init_x = { @@ -874,7 +849,6 @@ static const struct instance_globals_x g_init_x = { UNDEFINED_VALUE, /* xstart */ UNDEFINED_VALUE, /* xsize */ TRUE, /* havestate*/ - IVMAGIC /* x_magic to validate that structure layout has been preserved */ }; static const struct instance_globals_y g_init_y = { @@ -888,7 +862,6 @@ static const struct instance_globals_y g_init_y = { UNDEFINED_VALUE, /* ystart */ UNDEFINED_VALUE, /* ysize */ TRUE, /* havestate*/ - IVMAGIC /* y_magic to validate that structure layout has been preserved */ }; static const struct instance_globals_z g_init_z = { @@ -897,7 +870,6 @@ static const struct instance_globals_z g_init_z = { /* muse.c */ FALSE, /* zap_oseen */ TRUE, /* havestate*/ - IVMAGIC /* z_magic to validate that structure layout has been preserved */ }; static const struct instance_globals_saved_b init_svb = { @@ -1092,12 +1064,6 @@ const struct const_globals cg = { #define MAGICCHECK(xx) \ do { \ - if ((xx).magic != IVMAGIC) { \ - raw_printf( \ - "decl_globals_init: %s.magic in unexpected state (%lx).", \ - #xx, (xx).magic); \ - exit(1); \ - } \ if ((xx).havestate != TRUE) { \ raw_printf( \ "decl_globals_init: %s.havestate not True.", #xx); \ From 79c889502c677b7a7fc74048f1c43901690bec05 Mon Sep 17 00:00:00 2001 From: nhmall Date: Thu, 24 Oct 2024 08:40:44 -0400 Subject: [PATCH 033/791] follow-up: remove trailing whitespace --- src/hack.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/hack.c b/src/hack.c index 95576d019..4c636910d 100644 --- a/src/hack.c +++ b/src/hack.c @@ -161,11 +161,11 @@ could_move_onto_boulder(coordxy sx, coordxy sy) staticfn void dopush( - coordxy sx, - coordxy sy, - coordxy rx, - coordxy ry, - struct obj *otmp, + coordxy sx, + coordxy sy, + coordxy rx, + coordxy ry, + struct obj *otmp, boolean costly) { struct monst *shkp; From 4c49239940cc92a7171ef640baf71517f1d82ede Mon Sep 17 00:00:00 2001 From: Alex Smith Date: Fri, 25 Oct 2024 01:32:31 +0100 Subject: [PATCH 034/791] Update a comment in config.h to allow for gnome-terminal updates gnome-terminal was recently fixed to work correctly with TTY_TILES_ESCCODES (and other similar private-use terminal code sequences), and thus this isn't an incompatible combination any more. --- include/config.h | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/include/config.h b/include/config.h index 64910138b..1c728d459 100644 --- a/include/config.h +++ b/include/config.h @@ -629,11 +629,10 @@ typedef unsigned char uchar; * glyph" code, then the escape codes for color and the glyph character * itself, and then the "end glyph" code. * - * To compile NetHack with this, add tile.c to WINSRC and tile.o to WINOBJ - * in the hints file or Makefile. - * Set boolean option vt_tiledata and/or vt_sounddata in your config file - * to turn either of these on. - * Note that gnome-terminal at least doesn't work with this. */ + * To compile NetHack with this, add tile.c to WINSRC and tile.o to WINOBJ in + * the hints file or Makefile. Set boolean option vt_tiledata and/or + * vt_sounddata in your config file to turn either of these on. Note that some + * terminals (e.g. old versions of gnome-terminal) don't work with this. */ /* #define TTY_TILES_ESCCODES */ /* #define TTY_SOUND_ESCCODES */ From bb401fcb3865c3a94162fb75e8408f3e45dc9929 Mon Sep 17 00:00:00 2001 From: SHIRAKATA Kentaro Date: Fri, 25 Oct 2024 12:30:01 +0900 Subject: [PATCH 035/791] split a message of a rock disappearing into a separate function ... to prepare further refactoring --- src/hack.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/hack.c b/src/hack.c index 4c636910d..e3290da7e 100644 --- a/src/hack.c +++ b/src/hack.c @@ -13,6 +13,7 @@ staticfn void dopush(coordxy, coordxy, coordxy, coordxy, struct obj *, boolean); staticfn void cannot_push_msg(struct obj *, coordxy, coordxy); staticfn int cannot_push(struct obj *, coordxy, coordxy); +staticfn void rock_disappear_msg(struct obj *); staticfn void moverock_done(coordxy, coordxy); staticfn int moverock(void); staticfn int moverock_core(coordxy, coordxy); @@ -308,6 +309,18 @@ cannot_push(struct obj *otmp, coordxy sx, coordxy sy) } } +staticfn void +rock_disappear_msg(struct obj *otmp) +{ + if (u.usteed) + pline("%s pushes %s and suddenly it disappears!", + YMonnam(u.usteed), the(xname(otmp))); + else + You("push %s and suddenly it disappears!", + the(xname(otmp))); + +} + staticfn void moverock_done(coordxy sx, coordxy sy) { @@ -560,12 +573,7 @@ moverock_core(coordxy sx, coordxy sy) } /*FALLTHRU*/ case TELEP_TRAP: - if (u.usteed) - pline("%s pushes %s and suddenly it disappears!", - YMonnam(u.usteed), the(xname(otmp))); - else - You("push %s and suddenly it disappears!", - the(xname(otmp))); + rock_disappear_msg(otmp); otmp->next_boulder = 0; /* reset before moving it */ if (ttmp->ttyp == TELEP_TRAP) { (void) rloco(otmp); From 92942391971efd539936c20daee1e21d2860a9dd Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Fri, 25 Oct 2024 02:11:54 +0300 Subject: [PATCH 036/791] util: match fopen_datafile function prototype The prototype for fopen_datafile() is different if it is used for util/dlb. Add the missing integer parameter. --- util/dlb_main.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/util/dlb_main.c b/util/dlb_main.c index 57ea1c78a..67a485088 100644 --- a/util/dlb_main.c +++ b/util/dlb_main.c @@ -18,7 +18,7 @@ ATTRNORETURN static void xexit(int) NORETURN; ATTRNORETURN extern void panic(const char *, ...) NORETURN; -FILE *fopen_datafile(const char *, const char *); +FILE *fopen_datafile(const char *, const char *, int); #ifdef DLB #ifdef DLBLIB @@ -134,8 +134,10 @@ Write(int out, char *buf, long len) /* open_library(dlb.c) needs this (which normally comes from src/files.c) */ FILE * -fopen_datafile(const char *filename, const char *mode) +fopen_datafile(const char *filename, const char *mode, int prefix) { + prefix = !prefix; /* not needed, silence compiler */ + return fopen(filename, mode); } From fec99bfb866f6486fc42d8b24aac5a1602dab16b Mon Sep 17 00:00:00 2001 From: nhmall Date: Tue, 29 Oct 2024 19:30:09 -0400 Subject: [PATCH 037/791] follow-up: parameter UNUSED as in most of NetHack --- util/dlb_main.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/util/dlb_main.c b/util/dlb_main.c index 67a485088..27310b303 100644 --- a/util/dlb_main.c +++ b/util/dlb_main.c @@ -134,10 +134,8 @@ Write(int out, char *buf, long len) /* open_library(dlb.c) needs this (which normally comes from src/files.c) */ FILE * -fopen_datafile(const char *filename, const char *mode, int prefix) +fopen_datafile(const char *filename, const char *mode, int prefix UNUSED) { - prefix = !prefix; /* not needed, silence compiler */ - return fopen(filename, mode); } From 3f3e1cc49a8668257ffecd76e46342230d58b845 Mon Sep 17 00:00:00 2001 From: SHIRAKATA Kentaro Date: Mon, 28 Oct 2024 13:18:49 +0900 Subject: [PATCH 038/791] split calculating sacrifice value into a separate function --- src/pray.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/pray.c b/src/pray.c index 0adf67129..7676c091c 100644 --- a/src/pray.c +++ b/src/pray.c @@ -27,6 +27,7 @@ staticfn void offer_fake_amulet(struct obj *, boolean, aligntyp); staticfn void offer_different_alignment_altar(struct obj *, aligntyp); staticfn void sacrifice_your_race(struct obj *, boolean, aligntyp); staticfn int bestow_artifact(void); +staticfn int sacrifice_value(struct obj *); staticfn boolean pray_revive(void); staticfn boolean water_prayer(boolean); staticfn boolean blocked_boulder(int, int); @@ -1805,6 +1806,20 @@ bestow_artifact(void) return FALSE; } +staticfn int +sacrifice_value(struct obj *otmp) +{ + int value = 0; + + if (otmp->corpsenm == PM_ACID_BLOB + || (svm.moves <= peek_at_iced_corpse_age(otmp) + 50)) { + value = mons[otmp->corpsenm].difficulty + 1; + if (otmp->oeaten) + value = eaten_stat(value, otmp); + } + return value; +} + /* the #offer command - sacrifice something to the gods */ int dosacrifice(void) @@ -1871,12 +1886,7 @@ dosacrifice(void) if (rider_corpse_revival(otmp, FALSE)) return ECMD_TIME; - if (otmp->corpsenm == PM_ACID_BLOB - || (svm.moves <= peek_at_iced_corpse_age(otmp) + 50)) { - value = mons[otmp->corpsenm].difficulty + 1; - if (otmp->oeaten) - value = eaten_stat(value, otmp); - } + value = sacrifice_value(otmp); /* same race or former pet results apply even if the corpse is too old (value==0) */ From 70a5b06c45bd7e9e4f376846799dd5fdb0fbf82d Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 2 Nov 2024 09:15:20 -0400 Subject: [PATCH 039/791] Makefile.nmake fix for target spotless under x64 --- sys/windows/Makefile.nmake | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sys/windows/Makefile.nmake b/sys/windows/Makefile.nmake index a654307ac..b763e7858 100644 --- a/sys/windows/Makefile.nmake +++ b/sys/windows/Makefile.nmake @@ -2361,6 +2361,8 @@ spotless: clean if exist oguidirx64.tag del oguidirx64.tag if exist oluadirx64.tag del oluadirx64.tag if exist opdcdirx64.tag del opdcdirx64.tag + if exist opdccdirx64.tag del opdccdirx64.tag + if exist opdcgdirx64.tag del opdcgdirx64.tag if exist libdir.tag del libdir.tag if exist gamedir.tag del gamedir.tag if exist $(MSWIN)\mnsel.bmp del $(MSWIN)\mnsel.bmp From ce41d32c2c2f12d118fe4a0c7115c317e343305d Mon Sep 17 00:00:00 2001 From: SHIRAKATA Kentaro Date: Sun, 8 May 2022 06:56:34 +0900 Subject: [PATCH 040/791] split "got_target" on use_leash() into a separate function --- src/apply.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/apply.c b/src/apply.c index 30d0ac36e..45d0ea1c3 100644 --- a/src/apply.c +++ b/src/apply.c @@ -13,6 +13,7 @@ staticfn void use_whistle(struct obj *); staticfn void use_magic_whistle(struct obj *); staticfn void magic_whistled(struct obj *); staticfn int use_leash(struct obj *); +staticfn void use_leash_core(struct obj *, struct monst *, coord, int); staticfn boolean mleashed_next2u(struct monst *); staticfn int use_mirror(struct obj *); staticfn void use_bell(struct obj **); @@ -752,13 +753,11 @@ leashable(struct monst *mtmp) && (!nolimbs(mtmp->data) || has_head(mtmp->data))); } -/* ARGSUSED */ staticfn int use_leash(struct obj *obj) { coord cc; struct monst *mtmp; - int spotmon; if (u.uswallow) { /* if the leash isn't in use, assume we're trying to leash @@ -785,8 +784,8 @@ use_leash(struct obj *obj) if (u_at(cc.x, cc.y)) { if (u.usteed && u.dz > 0) { mtmp = u.usteed; - spotmon = 1; - goto got_target; + use_leash_core(obj, mtmp, cc, 1); + return ECMD_TIME; } pline("Leash yourself? Very funny..."); return ECMD_OK; @@ -802,9 +801,13 @@ use_leash(struct obj *obj) return ECMD_TIME; } - spotmon = canspotmon(mtmp); - got_target: + use_leash_core(obj, mtmp, cc, canspotmon(mtmp)); + return ECMD_TIME; +} +staticfn void +use_leash_core(struct obj *obj, struct monst *mtmp, coord cc, int spotmon) +{ if (!spotmon && !glyph_is_invisible(levl[cc.x][cc.y].glyph)) { /* for the unleash case, we don't verify whether this unseen monster is the creature attached to the current leash */ @@ -858,7 +861,6 @@ use_leash(struct obj *obj) spotmon ? "your " : "", l_monnam(mtmp)); } } - return ECMD_TIME; } /* assuming mtmp->mleashed has been checked */ From 9a42d70901a48cb977513e963a7058359bce99ce Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 3 Nov 2024 09:03:04 -0500 Subject: [PATCH 041/791] ranged attack in repertoire might not be used Commit 22884522, ported (from Sporkhack, Evilhack), added the ability for monsters to maintain awareness of player resistances that they observed. Since they will refrain from using a ranged attack that they deem futile, take the specific monster's seen_resistance field into consideration when choosing code paths based on the availability of ranged attacks. Resolves #1307 --- include/extern.h | 5 +++++ src/mhitu.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++ src/monmove.c | 5 +++-- 3 files changed, 64 insertions(+), 2 deletions(-) diff --git a/include/extern.h b/include/extern.h index 7eaa68e65..8422224f4 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1485,6 +1485,11 @@ extern int gazemu(struct monst *, struct attack *) NONNULLARG12; extern void mdamageu(struct monst *, int) NONNULLARG1; extern int could_seduce(struct monst *, struct monst *, struct attack *) NONNULLARG12; extern int doseduce(struct monst *) NONNULLARG1; +extern boolean mon_avoiding_this_attack(struct monst *, int) NONNULLARG1; +/* extern boolean ranged_attk_assessed(struct monst *mtmp, + boolean (*assessfunct)(struct monst *, int)) NONNULLARG1; +*/ +extern boolean ranged_attk_available(struct monst *mtmp) NONNULLARG1; /* ### minion.c ### */ diff --git a/src/mhitu.c b/src/mhitu.c index 14b453147..8a442faa1 100644 --- a/src/mhitu.c +++ b/src/mhitu.c @@ -2305,6 +2305,62 @@ assess_dmg(struct monst *mtmp, int tmp) return M_ATTK_HIT; } +#if 0 +/* returns True if monster has a range attack in its repertoire + that it will actually utilize. Caller provides the assessment + callback (optional). Callback returns 0 if the attack is + active */ + +boolean ranged_attk_assessed( +struct monst *mtmp, +boolean (*assessfunc)(struct monst *, int)) +{ + int i; + struct permonst *ptr = mtmp->data; + + for (i = 0; i < NATTK; i++) + if (DISTANCE_ATTK_TYPE(ptr->mattk[i].aatyp)) { + if (!assessfunc || (*assessfunc)(mtmp, i) == 0) + return TRUE; + } + return FALSE; +} +#endif + +/* can be used as ranged_attk_assessed() callback. + Returns TRUE if monster is avoiding use of this attack */ +boolean +mon_avoiding_this_attack(struct monst *mtmp, int attkidx) +{ + struct permonst *ptr = mtmp->data; + int typ = -1; + + if (attkidx >= 0 + && (typ = get_atkdam_type(ptr->mattk[attkidx].adtyp)) >= 0 + && m_seenres(mtmp, cvt_adtyp_to_mseenres(typ))) + return TRUE; + return FALSE; +} + +/* + * This would be equivalent to: + * ranged_attk_assessed(mtmp, mon_avoiding_this_attack) + * but without the added assessment function call overhead. + */ +boolean ranged_attk_available(struct monst *mtmp) +{ + int i, typ = -1; + struct permonst *ptr = mtmp->data; + + for (i = 0; i < NATTK; i++) { + if (DISTANCE_ATTK_TYPE(ptr->mattk[i].aatyp) + && (typ = get_atkdam_type(ptr->mattk[i].adtyp)) >= 0 + && m_seenres(mtmp, cvt_adtyp_to_mseenres(typ)) == 0) + return TRUE; + } + return FALSE; +} + /* FIXME: * sequencing issue: a monster's attack might cause poly'd hero * to revert to normal form. The messages for passive counterattack diff --git a/src/monmove.c b/src/monmove.c index a56b14fba..dc343d333 100644 --- a/src/monmove.c +++ b/src/monmove.c @@ -910,7 +910,8 @@ dochug(struct monst *mtmp) return 0; /* Monsters can move and then shoot on same turn; our hero can't. Is that fair? */ - if (!nearby && (ranged_attk(mdat) + if (!nearby + && (ranged_attk_available(mtmp) || attacktype(mdat, AT_WEAP) || find_offensive(mtmp))) break; @@ -1159,7 +1160,7 @@ m_balks_at_approaching(struct monst *mtmp) return TRUE; /* can attack from distance, and hp loss or attack not used */ - if (ranged_attk(mtmp->data) + if (ranged_attk_available(mtmp) && ((mtmp->mhp < (mtmp->mhpmax+1) / 3) || !mtmp->mspec_used)) return TRUE; From f46cd2732ab2eb1bee483122dfd9460a9fc03d30 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 3 Nov 2024 09:08:11 -0500 Subject: [PATCH 042/791] W_NONDIGGABLE collisions with overloaded rm flags fields Resolves #1308 --- src/mkmaze.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mkmaze.c b/src/mkmaze.c index 4237e00e9..0687a6c30 100644 --- a/src/mkmaze.c +++ b/src/mkmaze.c @@ -1437,7 +1437,8 @@ bound_digging(void) for (x = 0; x < COLNO; x++) for (y = 0; y < ROWNO; y++) - if (y <= ymin || y >= ymax || x <= xmin || x >= xmax) + if (IS_STWALL(levl[x][y].typ) + && (y <= ymin || y >= ymax || x <= xmin || x >= xmax)) levl[x][y].wall_info |= W_NONDIGGABLE; } From 091a709cdbc6fb9dd25259d719d9ca59a79b5f6f Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 3 Nov 2024 09:21:19 -0500 Subject: [PATCH 043/791] follow-up: NetHack typically passes ptr to coord --- src/apply.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/apply.c b/src/apply.c index 45d0ea1c3..c03a1a9cf 100644 --- a/src/apply.c +++ b/src/apply.c @@ -13,7 +13,7 @@ staticfn void use_whistle(struct obj *); staticfn void use_magic_whistle(struct obj *); staticfn void magic_whistled(struct obj *); staticfn int use_leash(struct obj *); -staticfn void use_leash_core(struct obj *, struct monst *, coord, int); +staticfn void use_leash_core(struct obj *, struct monst *, coord *, int); staticfn boolean mleashed_next2u(struct monst *); staticfn int use_mirror(struct obj *); staticfn void use_bell(struct obj **); @@ -784,7 +784,7 @@ use_leash(struct obj *obj) if (u_at(cc.x, cc.y)) { if (u.usteed && u.dz > 0) { mtmp = u.usteed; - use_leash_core(obj, mtmp, cc, 1); + use_leash_core(obj, mtmp, &cc, 1); return ECMD_TIME; } pline("Leash yourself? Very funny..."); @@ -801,20 +801,20 @@ use_leash(struct obj *obj) return ECMD_TIME; } - use_leash_core(obj, mtmp, cc, canspotmon(mtmp)); + use_leash_core(obj, mtmp, &cc, canspotmon(mtmp)); return ECMD_TIME; } staticfn void -use_leash_core(struct obj *obj, struct monst *mtmp, coord cc, int spotmon) +use_leash_core(struct obj *obj, struct monst *mtmp, coord *cc, int spotmon) { - if (!spotmon && !glyph_is_invisible(levl[cc.x][cc.y].glyph)) { + if (!spotmon && !glyph_is_invisible(levl[cc->x][cc->y].glyph)) { /* for the unleash case, we don't verify whether this unseen monster is the creature attached to the current leash */ You("fail to %sleash something.", obj->leashmon ? "un" : ""); /* trying again will work provided the monster is tame (and also that it doesn't change location by retry time) */ - map_invisible(cc.x, cc.y); + map_invisible(cc->x, cc->y); } else if (!mtmp->mtame) { pline("%s %s leashed!", Monnam(mtmp), (!obj->leashmon) ? "cannot be" : "is not"); @@ -832,7 +832,7 @@ use_leash_core(struct obj *obj, struct monst *mtmp, coord cc, int spotmon) char lmonbuf[BUFSZ]; char *lmonnam = l_monnam(mtmp); - if (cc.x != mtmp->mx || cc.y != mtmp->my) { + if (cc->x != mtmp->mx || cc->y != mtmp->my) { Sprintf(lmonbuf, "%s tail", s_suffix(lmonnam)); lmonnam = lmonbuf; } From 955c2c5faf09a406f4fbee25079aad63f190c503 Mon Sep 17 00:00:00 2001 From: SHIRAKATA Kentaro Date: Tue, 5 Nov 2024 00:40:32 +0900 Subject: [PATCH 044/791] early return on dosacrifice() ... to reduce indents and prepare further refactorings. --- src/pray.c | 156 +++++++++++++++++++++++++++-------------------------- 1 file changed, 79 insertions(+), 77 deletions(-) diff --git a/src/pray.c b/src/pray.c index 7676c091c..900c57692 100644 --- a/src/pray.c +++ b/src/pray.c @@ -1827,7 +1827,9 @@ dosacrifice(void) struct obj *otmp; boolean highaltar; aligntyp altaralign = a_align(u.ux, u.uy); - int value = 0; + int value; + struct permonst *ptr; + struct monst *mtmp; if (!on_altar() || u.uswallow) { You("are not %s an altar.", @@ -1858,6 +1860,11 @@ dosacrifice(void) return ECMD_TIME; } /* fake Amulet */ + if (otmp->otyp != CORPSE) { + pline1(nothing_happens); + return ECMD_TIME; + } + /* * Was based on nutritional value and aging behavior (< 50 moves). * Sacrificing a food ration got you max luck instantly, making the @@ -1869,88 +1876,83 @@ dosacrifice(void) */ #define MAXVALUE 24 /* Highest corpse value (besides Wiz) */ - if (otmp->otyp == CORPSE) { - struct permonst *ptr = &mons[otmp->corpsenm]; - struct monst *mtmp; + ptr = &mons[otmp->corpsenm]; - /* KMH, conduct */ - if (!u.uconduct.gnostic++) - livelog_printf(LL_CONDUCT, "rejected atheism" - " by offering %s on an altar of %s", - corpse_xname(otmp, (const char *) 0, CXN_ARTICLE), - a_gname()); + /* KMH, conduct */ + if (!u.uconduct.gnostic++) + livelog_printf(LL_CONDUCT, "rejected atheism" + " by offering %s on an altar of %s", + corpse_xname(otmp, (const char *) 0, CXN_ARTICLE), + a_gname()); - /* you're handling this corpse, even if it was killed upon the altar - */ - feel_cockatrice(otmp, TRUE); - if (rider_corpse_revival(otmp, FALSE)) - return ECMD_TIME; + /* you're handling this corpse, even if it was killed upon the altar + */ + feel_cockatrice(otmp, TRUE); + if (rider_corpse_revival(otmp, FALSE)) + return ECMD_TIME; - value = sacrifice_value(otmp); + value = sacrifice_value(otmp); - /* same race or former pet results apply even if the corpse is - too old (value==0) */ - if (your_race(ptr)) { - sacrifice_your_race(otmp, highaltar, altaralign); - return ECMD_TIME; - } else if (has_omonst(otmp) - && (mtmp = get_mtraits(otmp, FALSE)) != 0 - && mtmp->mtame) { - /* mtmp is a temporary pointer to a tame monster's attributes, - * not a real monster */ - pline("So this is how you repay loyalty?"); - adjalign(-3); - value = -1; - HAggravate_monster |= FROMOUTSIDE; - } else if (!value) { - ; /* too old; don't give undead or unicorn bonus or penalty */ - } else if (is_undead(ptr)) { /* Not demons--no demon corpses */ - /* most undead that leave a corpse yield 'human' (or other race) - corpse so won't get here; the exception is wraith; give the - bonus for wraith to chaotics too because they are sacrificing - something valuable (unless hero refuses to eat such things) */ - if (u.ualign.type != A_CHAOTIC - /* reaching this side of the 'or' means hero is chaotic */ - || (ptr == &mons[PM_WRAITH] && u.uconduct.unvegetarian)) - value += 1; - } else if (is_unicorn(ptr)) { - int unicalign = sgn(ptr->maligntyp); + /* same race or former pet results apply even if the corpse is + too old (value==0) */ + if (your_race(ptr)) { + sacrifice_your_race(otmp, highaltar, altaralign); + return ECMD_TIME; + } else if (has_omonst(otmp) + && (mtmp = get_mtraits(otmp, FALSE)) != 0 + && mtmp->mtame) { + /* mtmp is a temporary pointer to a tame monster's attributes, + * not a real monster */ + pline("So this is how you repay loyalty?"); + adjalign(-3); + value = -1; + HAggravate_monster |= FROMOUTSIDE; + } else if (!value) { + ; /* too old; don't give undead or unicorn bonus or penalty */ + } else if (is_undead(ptr)) { /* Not demons--no demon corpses */ + /* most undead that leave a corpse yield 'human' (or other race) + corpse so won't get here; the exception is wraith; give the + bonus for wraith to chaotics too because they are sacrificing + something valuable (unless hero refuses to eat such things) */ + if (u.ualign.type != A_CHAOTIC + /* reaching this side of the 'or' means hero is chaotic */ + || (ptr == &mons[PM_WRAITH] && u.uconduct.unvegetarian)) + value += 1; + } else if (is_unicorn(ptr)) { + int unicalign = sgn(ptr->maligntyp); - if (unicalign == altaralign) { - /* When same as altar, always a very bad action. - */ - pline("Such an action is an insult to %s!", - (unicalign == A_CHAOTIC) ? "chaos" - : unicalign ? "law" : "balance"); - (void) adjattrib(A_WIS, -1, TRUE); - value = -5; - } else if (u.ualign.type == altaralign) { - /* When different from altar, and altar is same as yours, - * it's a very good action. - */ - if (u.ualign.record < ALIGNLIM) - You_feel("appropriately %s.", align_str(u.ualign.type)); - else - You_feel("you are thoroughly on the right path."); - adjalign(5); - value += 3; - } else if (unicalign == u.ualign.type) { - /* When sacrificing unicorn of your alignment to altar not of - * your alignment, your god gets angry and it's a conversion. - */ - u.ualign.record = -1; - value = 1; - } else { - /* Otherwise, unicorn's alignment is different from yours - * and different from the altar's. It's an ordinary (well, - * with a bonus) sacrifice on a cross-aligned altar. - */ - value += 3; - } + if (unicalign == altaralign) { + /* When same as altar, always a very bad action. + */ + pline("Such an action is an insult to %s!", + (unicalign == A_CHAOTIC) ? "chaos" + : unicalign ? "law" : "balance"); + (void) adjattrib(A_WIS, -1, TRUE); + value = -5; + } else if (u.ualign.type == altaralign) { + /* When different from altar, and altar is same as yours, + * it's a very good action. + */ + if (u.ualign.record < ALIGNLIM) + You_feel("appropriately %s.", align_str(u.ualign.type)); + else + You_feel("you are thoroughly on the right path."); + adjalign(5); + value += 3; + } else if (unicalign == u.ualign.type) { + /* When sacrificing unicorn of your alignment to altar not of + * your alignment, your god gets angry and it's a conversion. + */ + u.ualign.record = -1; + value = 1; + } else { + /* Otherwise, unicorn's alignment is different from yours + * and different from the altar's. It's an ordinary (well, + * with a bonus) sacrifice on a cross-aligned altar. + */ + value += 3; } - } else { /* !corpse */ - ; /* value==0 which is what we want for non-corpse */ - } /* ?corpse */ + } if (value == 0) { pline1(nothing_happens); From b953625e5b48ed01ae2b7edecdb14b580622c3f5 Mon Sep 17 00:00:00 2001 From: SHIRAKATA Kentaro Date: Tue, 5 Nov 2024 15:13:52 +0900 Subject: [PATCH 045/791] early return when `value` == 0 on dosacrifice() `calc_value()` returns a non-negative value, and there is no code that sets `value` to 0 after this point. --- src/pray.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/pray.c b/src/pray.c index 900c57692..f843ddd9e 100644 --- a/src/pray.c +++ b/src/pray.c @@ -1908,7 +1908,9 @@ dosacrifice(void) value = -1; HAggravate_monster |= FROMOUTSIDE; } else if (!value) { - ; /* too old; don't give undead or unicorn bonus or penalty */ + /* too old; don't give undead or unicorn bonus or penalty */ + pline1(nothing_happens); + return ECMD_TIME; } else if (is_undead(ptr)) { /* Not demons--no demon corpses */ /* most undead that leave a corpse yield 'human' (or other race) corpse so won't get here; the exception is wraith; give the @@ -1954,11 +1956,6 @@ dosacrifice(void) } } - if (value == 0) { - pline1(nothing_happens); - return ECMD_TIME; - } - if (altaralign != u.ualign.type && highaltar) { desecrate_altar(highaltar, altaralign); } else if (value < 0) { /* don't think the gods are gonna like this... */ From ffe2dfc17cc08b6a8528b2d9e0a55679e8d6b2cb Mon Sep 17 00:00:00 2001 From: SHIRAKATA Kentaro Date: Tue, 5 Nov 2024 15:03:48 +0900 Subject: [PATCH 046/791] split offering negative valued items into a separate function --- src/pray.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/src/pray.c b/src/pray.c index f843ddd9e..f001c56a2 100644 --- a/src/pray.c +++ b/src/pray.c @@ -23,6 +23,7 @@ staticfn void gods_upset(aligntyp); staticfn void consume_offering(struct obj *); staticfn void offer_too_soon(aligntyp); staticfn void offer_real_amulet(struct obj *, aligntyp); /* NORETURN */ +staticfn void offer_negative_valued(boolean, aligntyp); staticfn void offer_fake_amulet(struct obj *, boolean, aligntyp); staticfn void offer_different_alignment_altar(struct obj *, aligntyp); staticfn void sacrifice_your_race(struct obj *, boolean, aligntyp); @@ -1572,6 +1573,16 @@ offer_real_amulet(struct obj *otmp, aligntyp altaralign) /*NOTREACHED*/ } +staticfn void +offer_negative_valued(boolean highaltar, aligntyp altaralign) +{ + if (altaralign != u.ualign.type && highaltar) { + desecrate_altar(highaltar, altaralign); + } else { + gods_upset(altaralign); + } +} + staticfn void offer_fake_amulet( struct obj *otmp, @@ -1596,12 +1607,7 @@ offer_fake_amulet( change_luck(-3); adjalign(-1); u.ugangr += 3; - /* value = -3; */ - if (altaralign != u.ualign.type && highaltar) { - desecrate_altar(highaltar, altaralign); - } else { /* value < 0 */ - gods_upset(altaralign); - } + offer_negative_valued(highaltar, altaralign); } } @@ -1905,8 +1911,9 @@ dosacrifice(void) * not a real monster */ pline("So this is how you repay loyalty?"); adjalign(-3); - value = -1; HAggravate_monster |= FROMOUTSIDE; + offer_negative_valued(highaltar, altaralign); + return ECMD_TIME; } else if (!value) { /* too old; don't give undead or unicorn bonus or penalty */ pline1(nothing_happens); @@ -1930,7 +1937,8 @@ dosacrifice(void) (unicalign == A_CHAOTIC) ? "chaos" : unicalign ? "law" : "balance"); (void) adjattrib(A_WIS, -1, TRUE); - value = -5; + offer_negative_valued(highaltar, altaralign); + return ECMD_TIME; } else if (u.ualign.type == altaralign) { /* When different from altar, and altar is same as yours, * it's a very good action. @@ -1958,8 +1966,6 @@ dosacrifice(void) if (altaralign != u.ualign.type && highaltar) { desecrate_altar(highaltar, altaralign); - } else if (value < 0) { /* don't think the gods are gonna like this... */ - gods_upset(altaralign); } else if (u.ualign.type != altaralign) { /* Sacrificing at an altar of a different alignment */ offer_different_alignment_altar(otmp, altaralign); From e863583c56f320b121bc11e59e708f55e8976765 Mon Sep 17 00:00:00 2001 From: nhmall Date: Wed, 6 Nov 2024 16:59:51 -0500 Subject: [PATCH 047/791] iterating gi.invent (github issue #1315) GitHub issue #1315 points out that it is possible for a downstream function to change an object's nobj field to point to a completely different chain. The cited example by @vultur-cadens was: for (obj = gi.invent; obj; obj = obj->nobj) if (obj->oclass != COIN_CLASS && !obj->cursed && !rn2(5)) { curse(obj); ++buc_changed; } curse() drops the weapon with drop_uswapwep(), which calls dropx(), which calls dropy(), which calls dropz(), which calls place_object(). place_object alters the nobj pointer, to point to the floor chain: otmp->nobj = fobj; fobj = otmp; The result was that the next loop iteration was then using floor objects from the floor chain. This alters several for-loops to use a more consistent approach, particularly when the obj is being handed off to a function, where a downstream function might, or might not, alter the nobj field. References: https://github.com/NetHack/NetHack/issues/1315 https://www.reddit.com/r/nethack/comments/1gkc9ub/even_if_you_drop_an_item_before_drinking_from_the/ --- src/do_wear.c | 6 ++++-- src/end.c | 5 +++-- src/fountain.c | 12 ++++++++---- src/invent.c | 12 ++++++++---- src/mhitu.c | 6 ++++-- src/pray.c | 5 +++-- src/read.c | 8 +++++--- src/steal.c | 5 +++-- src/trap.c | 21 +++++++++++++-------- src/zap.c | 6 ++++-- 10 files changed, 55 insertions(+), 31 deletions(-) diff --git a/src/do_wear.c b/src/do_wear.c index d6c52c4ae..4f20e1b40 100644 --- a/src/do_wear.c +++ b/src/do_wear.c @@ -3020,7 +3020,7 @@ menu_remarm(int retry) staticfn void wornarm_destroyed(struct obj *wornarm) { - struct obj *invobj; + struct obj *invobj, *nextobj; unsigned wornoid = wornarm->o_id; /* cancel_don() resets 'afternmv' when appropriate but doesn't reset @@ -3049,11 +3049,13 @@ wornarm_destroyed(struct obj *wornarm) scan invent instead; if already freed it shouldn't be possible to have re-used the stale memory for a new item yet but verify o_id just in case */ - for (invobj = gi.invent; invobj; invobj = invobj->nobj) + for (invobj = gi.invent; invobj; invobj = nextobj) { + nextobj = invobj->nobj; if (invobj == wornarm && invobj->o_id == wornoid) { useup(wornarm); break; } + } } /* diff --git a/src/end.c b/src/end.c index 1c10e192b..a6e899fa8 100644 --- a/src/end.c +++ b/src/end.c @@ -1236,14 +1236,15 @@ really_done(int how) display_nhwindow(WIN_MESSAGE, FALSE); if (how != PANICKED) { - struct obj *obj; + struct obj *obj, *nextobj; /* * This is needed for both inventory disclosure and dumplog. * Both are optional, so do it once here instead of duplicating * it in both of those places. */ - for (obj = gi.invent; obj; obj = obj->nobj) { + for (obj = gi.invent; obj; obj = nextobj) { + nextobj = obj->nobj; discover_object(obj->otyp, TRUE, FALSE); obj->known = obj->bknown = obj->dknown = obj->rknown = 1; set_cknown_lknown(obj); /* set flags when applicable */ diff --git a/src/fountain.c b/src/fountain.c index 848adfbfb..1d4150630 100644 --- a/src/fountain.c +++ b/src/fountain.c @@ -315,18 +315,20 @@ drinkfountain(void) dowaterdemon(); break; case 24: { /* Maybe curse some items */ - struct obj *obj; + struct obj *obj, *nextobj; int buc_changed = 0; pline("This water's no good!"); morehungry(rn1(20, 11)); exercise(A_CON, FALSE); /* this is more severe than rndcurse() */ - for (obj = gi.invent; obj; obj = obj->nobj) + for (obj = gi.invent; obj; obj = nextobj) { + nextobj = obj->nobj; if (obj->oclass != COIN_CLASS && !obj->cursed && !rn2(5)) { curse(obj); ++buc_changed; } + } if (buc_changed) update_inventory(); break; @@ -498,13 +500,14 @@ dipfountain(struct obj *obj) pline("An urge to take a bath overwhelms you."); { long money = money_cnt(gi.invent); - struct obj *otmp; + struct obj *otmp, *nextobj; if (money > 10) { /* Amount to lose. Might get rounded up as fountains don't * pay change... */ money = somegold(money) / 10; - for (otmp = gi.invent; otmp && money > 0; otmp = otmp->nobj) + for (otmp = gi.invent; otmp && money > 0; otmp = nextobj) { + nextobj = otmp->nobj; if (otmp->oclass == COIN_CLASS) { int denomination = objects[otmp->otyp].oc_cost; long coin_loss = @@ -515,6 +518,7 @@ dipfountain(struct obj *obj) if (!otmp->quan) delobj(otmp); } + } You("lost some of your gold in the fountain!"); CLEAR_FOUNTAIN_LOOTED(u.ux, u.uy); exercise(A_WIS, FALSE); diff --git a/src/invent.c b/src/invent.c index 665e2bd1d..2e696214a 100644 --- a/src/invent.c +++ b/src/invent.c @@ -2224,15 +2224,17 @@ ggetobj(const char *word, int (*fn)(OBJ_P), int mx, return 0; if (strchr(buf, 'i')) { char ailets[1+26+26+1+5+1]; /* $ + a-z + A-Z + # + slop + \0 */ - struct obj *otmp; + struct obj *otmp, *nextobj; /* applicable inventory letters; if empty, show entire invent */ ailets[0] = '\0'; if (ofilter) - for (otmp = gi.invent; otmp; otmp = otmp->nobj) + for (otmp = gi.invent; otmp; otmp = nextobj) { + nextobj = otmp->nobj; /* strchr() check: limit overflow items to one '#' */ if ((*ofilter)(otmp) && !strchr(ailets, otmp->invlet)) (void) strkitten(ailets, otmp->invlet); + } if (display_inventory(ailets, TRUE) == '\033') return 0; } else @@ -3491,7 +3493,7 @@ dispinv_with_action( boolean use_inuse_ordering, /* affects sortloot() and header labels */ const char *alt_label) /* alternate value for in-use "Accessories" */ { - struct obj *otmp; + struct obj *otmp, *nextobj; const char *save_accessories = 0; char c, save_sortloot = 0; unsigned len = lets ? (unsigned) strlen(lets) : 0U; @@ -3517,9 +3519,11 @@ dispinv_with_action( iflags.force_invmenu = save_force_invmenu; if (c && c != '\033') { - for (otmp = gi.invent; otmp; otmp = otmp->nobj) + for (otmp = gi.invent; otmp; otmp = nextobj) { + nextobj = otmp->nobj; if (otmp->invlet == c) return itemactions(otmp); + } } return ECMD_OK; } diff --git a/src/mhitu.c b/src/mhitu.c index 8a442faa1..fea0349eb 100644 --- a/src/mhitu.c +++ b/src/mhitu.c @@ -1252,7 +1252,7 @@ gulpmu(struct monst *mtmp, struct attack *mattk) struct trap *t = t_at(u.ux, u.uy); int tmp = d((int) mattk->damn, (int) mattk->damd); int tim_tmp; - struct obj *otmp2; + struct obj *otmp2, *nextobj; int i; boolean physical_damage = FALSE; @@ -1357,8 +1357,10 @@ gulpmu(struct monst *mtmp, struct attack *mattk) u.uswldtim = (unsigned) ((tim_tmp < 2) ? 2 : tim_tmp); swallowed(1); /* update the map display, shows hero swallowed */ if (!flaming(mtmp->data)) { - for (otmp2 = gi.invent; otmp2; otmp2 = otmp2->nobj) + for (otmp2 = gi.invent; otmp2; otmp2 = nextobj) { + nextobj = otmp2->nobj; (void) snuff_lit(otmp2); + } } } diff --git a/src/pray.c b/src/pray.c index f843ddd9e..82b593d20 100644 --- a/src/pray.c +++ b/src/pray.c @@ -1267,14 +1267,15 @@ pleased(aligntyp g_align) disp.botl = TRUE; break; case 4: { - struct obj *otmp; + struct obj *otmp, *nextobj; int any = 0; if (Blind) You_feel("the power of %s.", u_gname()); else You("are surrounded by %s aura.", an(hcolor(NH_LIGHT_BLUE))); - for (otmp = gi.invent; otmp; otmp = otmp->nobj) { + for (otmp = gi.invent; otmp; otmp = nextobj) { + nextobj = otmp->nobj; if (otmp->cursed && (otmp != uarmh /* [see worst_cursed_item()] */ || uarmh->otyp != HELM_OF_OPPOSITE_ALIGNMENT)) { diff --git a/src/read.c b/src/read.c index 5d1a3c92d..1e53e5a2a 100644 --- a/src/read.c +++ b/src/read.c @@ -2382,7 +2382,7 @@ litroom( boolean on, /* True: make nearby area lit; False: cursed scroll */ struct obj *obj) /* scroll, spellbook (for spell), or wand of light */ { - struct obj *otmp; + struct obj *otmp, *nextobj; boolean blessed_effect = (obj && obj->oclass == SCROLL_CLASS && obj->blessed); boolean no_op = (u.uswallow || Underwater || Is_waterlevel(&u.uz)); @@ -2400,7 +2400,8 @@ litroom( * Shouldn't this affect all lit objects in the area of effect * rather than just those carried by the hero? */ - for (otmp = gi.invent; otmp; otmp = otmp->nobj) { + for (otmp = gi.invent; otmp; otmp = nextobj) { + nextobj = otmp->nobj; if (otmp->lamplit) { if (!artifact_light(otmp)) (void) snuff_lit(otmp); @@ -2431,7 +2432,8 @@ litroom( } else { /* on */ if (blessed_effect) { /* might bless artifact lights; no effect on ordinary lights */ - for (otmp = gi.invent; otmp; otmp = otmp->nobj) { + for (otmp = gi.invent; otmp; otmp = nextobj) { + nextobj = otmp->nobj; if (otmp->lamplit && artifact_light(otmp)) /* wielded Sunsword or worn gold dragon scales/mail; maybe raise its BUC state if not already blessed */ diff --git a/src/steal.c b/src/steal.c index 08b4db982..89ac7c841 100644 --- a/src/steal.c +++ b/src/steal.c @@ -165,12 +165,13 @@ staticfn int stealarm(void) { struct monst *mtmp; - struct obj *otmp; + struct obj *otmp, *nextobj; if (!gs.stealoid || !gs.stealmid) goto botm; - for (otmp = gi.invent; otmp; otmp = otmp->nobj) { + for (otmp = gi.invent; otmp; otmp = nextobj) { + nextobj = otmp->nobj; if (otmp->o_id == gs.stealoid) { for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (mtmp->m_id == gs.stealmid) { diff --git a/src/trap.c b/src/trap.c index 9e791e1c5..b75dae7d5 100644 --- a/src/trap.c +++ b/src/trap.c @@ -1551,7 +1551,7 @@ trapeffect_rust_trap( struct trap *trap, unsigned int trflags UNUSED) { - struct obj *otmp; + struct obj *otmp, *nextobj; if (mtmp == &gy.youmonst) { seetrap(trap); @@ -1583,10 +1583,12 @@ trapeffect_rust_trap( pline("%s you!", A_gush_of_water_hits); /* note: exclude primary and secondary weapons from splashing because cases 1 and 2 target them [via water_damage()] */ - for (otmp = gi.invent; otmp; otmp = otmp->nobj) + for (otmp = gi.invent; otmp; otmp = nextobj) { + nextobj = otmp->nobj; if (otmp->lamplit && otmp != uwep && (otmp != uswapwep || !u.twoweap)) (void) splash_lit(otmp); + } if (uarmc) (void) water_damage(uarmc, cloak_simple_name(uarmc), TRUE); else if (uarm) @@ -4764,13 +4766,14 @@ emergency_disrobe(boolean *lostsome) int invc = inv_cnt(TRUE); while (near_capacity() > (Punished ? UNENCUMBERED : SLT_ENCUMBER)) { - struct obj *obj, *otmp = (struct obj *) 0; + struct obj *obj, *nextobj, *otmp = (struct obj *) 0; int i; /* Pick a random object */ if (invc > 0) { i = rn2(invc); - for (obj = gi.invent; obj; obj = obj->nobj) { + for (obj = gi.invent; obj; obj = nextobj) { + nextobj = obj->nobj; /* * Undroppables are: body armor, boots, gloves, * amulets, and rings because of the time and effort @@ -6589,7 +6592,7 @@ static const char lava_killer[] = "molten lava"; boolean lava_effects(void) { - struct obj *obj, *obj2; + struct obj *obj, *obj2, *nextobj; boolean usurvive, boil_away; unsigned protect_oid = 0; int burncount = 0, burnmesgcount = 0; @@ -6616,7 +6619,8 @@ lava_effects(void) * emergency save file created before item destruction. */ if (!usurvive) { - for (obj = gi.invent; obj; obj = obj->nobj) { + for (obj = gi.invent; obj; obj = nextobj) { + nextobj = obj->nobj; if (obj->in_use) { /* remove_worn_item() sets in_use */ /* one item can be protected from burning up [accommodates steal(AMULET_OF_FLYING) -> remove_worn_item() -> fall @@ -6952,10 +6956,11 @@ trapname( void ignite_items(struct obj *objchn) { - struct obj *obj; + struct obj *obj, *nextobj; boolean bynexthere = (objchn && objchn->where == OBJ_FLOOR); - for (obj = objchn; obj; obj = bynexthere ? obj->nexthere : obj->nobj) { + for (obj = objchn; obj; obj = bynexthere ? obj->nexthere : nextobj) { + nextobj = obj->nobj; /* ignitable items like lamps and candles will catch fire */ if (!obj->lamplit && !obj->in_use) catch_lit(obj); diff --git a/src/zap.c b/src/zap.c index fa3795560..37531eeab 100644 --- a/src/zap.c +++ b/src/zap.c @@ -2626,15 +2626,17 @@ dozap(void) staticfn void boxlock_invent(struct obj *obj) { - struct obj *otmp; + struct obj *otmp, *nextobj; boolean boxing = FALSE; /* (un)lock carried boxes */ - for (otmp = gi.invent; otmp; otmp = otmp->nobj) + for (otmp = gi.invent; otmp; otmp = nextobj) { + nextobj = otmp->nobj; if (Is_box(otmp)) { (void) boxlock(otmp, obj); boxing = TRUE; } + } if (boxing) update_inventory(); /* in case any box->lknown has changed */ } From aaf324bcb4478caf1e9751d205f80637ea8b67c3 Mon Sep 17 00:00:00 2001 From: nhmall Date: Thu, 7 Nov 2024 16:29:45 -0500 Subject: [PATCH 048/791] comment bit in polyself.c --- src/polyself.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/polyself.c b/src/polyself.c index 736c62dff..55da8a8d5 100644 --- a/src/polyself.c +++ b/src/polyself.c @@ -1128,6 +1128,15 @@ dropp(struct obj *obj) for (otmp = gi.invent; otmp; otmp = otmp->nobj) { if (otmp == obj) { dropx(obj); + /* Note that otmp->nobj is pointing at fobj now, + * as a result of: + * dropx() -> dropy() -> dropz() -> place_object(), + * and no longer pointing at the next obj in inventory. + * That would be an issue if this loop were allowed + * to continue, but the break statement that + * follows prevents the loop from continuing on with + * objects on the floor. + */ break; } } From db460a4fcfeef7cd55d25c2773abf5278ad9f11c Mon Sep 17 00:00:00 2001 From: SHIRAKATA Kentaro Date: Fri, 8 Nov 2024 22:56:30 +0900 Subject: [PATCH 049/791] split offering a corpse into a separate function --- src/pray.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/pray.c b/src/pray.c index 3fa5de2b6..fe7171ee4 100644 --- a/src/pray.c +++ b/src/pray.c @@ -29,6 +29,7 @@ staticfn void offer_different_alignment_altar(struct obj *, aligntyp); staticfn void sacrifice_your_race(struct obj *, boolean, aligntyp); staticfn int bestow_artifact(void); staticfn int sacrifice_value(struct obj *); +staticfn int offer_corpse(struct obj *, boolean, aligntyp); staticfn boolean pray_revive(void); staticfn boolean water_prayer(boolean); staticfn boolean blocked_boulder(int, int); @@ -1834,9 +1835,6 @@ dosacrifice(void) struct obj *otmp; boolean highaltar; aligntyp altaralign = a_align(u.ux, u.uy); - int value; - struct permonst *ptr; - struct monst *mtmp; if (!on_altar() || u.uswallow) { You("are not %s an altar.", @@ -1867,11 +1865,21 @@ dosacrifice(void) return ECMD_TIME; } /* fake Amulet */ - if (otmp->otyp != CORPSE) { - pline1(nothing_happens); - return ECMD_TIME; + if (otmp->otyp == CORPSE) { + return offer_corpse(otmp, highaltar, altaralign); } + pline1(nothing_happens); + return ECMD_TIME; +} + +staticfn int +offer_corpse(struct obj *otmp, boolean highaltar, aligntyp altaralign) +{ + int value; + struct permonst *ptr; + struct monst *mtmp; + /* * Was based on nutritional value and aging behavior (< 50 moves). * Sacrificing a food ration got you max luck instantly, making the From a74badd271790504686132685959a5aad94c4b74 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 9 Nov 2024 10:53:48 -0500 Subject: [PATCH 050/791] rm.h comment updates --- include/rm.h | 88 +++++++++++++++++++++++++++++++++------------------- 1 file changed, 56 insertions(+), 32 deletions(-) diff --git a/include/rm.h b/include/rm.h index 61e6f013d..acc04c0e1 100644 --- a/include/rm.h +++ b/include/rm.h @@ -148,6 +148,62 @@ enum levl_typ_types { * D_SECRET would not fit within struct rm's 5-bit 'flags' field. */ +/* + * The structure describing a coordinate position. + * Before adding fields, remember that this will significantly affect + * the size of temporary files and save files. + * + * Also remember that the run-length encoding for some ports in save.c + * must be updated to consider the field. + */ +struct rm { + int glyph; /* what the hero thinks is there */ + schar typ; /* what is really there [why is this signed?] */ + uchar seenv; /* seen vector */ + Bitfield(flags, 5); /* extra information for typ */ + Bitfield(horizontal, 1); /* wall/door/etc is horiz. (more typ info) */ + Bitfield(lit, 1); /* speed hack for lit rooms */ + Bitfield(waslit, 1); /* remember if a location was lit */ + + Bitfield(roomno, 6); /* room # for special rooms */ + Bitfield(edge, 1); /* marks boundaries for special rooms*/ + Bitfield(candig, 1); /* Exception to Can_dig_down; was a trapdoor */ +}; + +/* + * rm flags field overloads: + * + * +-------------+-------------+------------+------------+------------+ + * | bit5 | bit4 | bit3 | bit2 | bit1 | + * | 0x10 | 0x8 | 0x4 | 0x2 | 0x1 | + * +-------------+-------------+------------+------------+------------+ + * door |D_TRAPPED | D_LOCKED | D_CLOSED | D_ISOPEN | D_BROKEN | + * drawbr. |DB_FLOOR | DB_ICE | DB_LAVA | DB_DIR | DB_DIR | + * wall |W_NONPASSWALL|W_NONDIGGABLE| W_MASK | W_MASK | W_MASK | + * sink | | | S_LRING | S_LDWASHER | S_LPUDDING | + * tree | | | | TREE_SWARM | TREE_LOOTED| + * fountain| | | | F_WARNED | F_LOOTED | + * ladder | | | | LA_DOWN | LA_UP | + * pool |ICED_MOAT | ICED_POOL | | | | + * grave | | | | | emptygrave | + * altar |AM_SANCTUM | AM_SHRINE | AM_MASK | AM_MASK | AM_MASK | + * | | | | | | + * +-------------+-------------+------------+------------+------------+ + * + * + * If these get changed or expanded, make sure wizard-mode wishing becomes + * aware of the new usage + */ + +#define doormask flags /* door, sdoor (note conflict with wall_info) */ +#define altarmask flags /* alignment and maybe temple */ +#define wall_info flags /* wall, sdoor (note conflict with doormask) */ +#define ladder flags /* up or down */ +#define drawbridgemask flags /* what's underneath when the span is open */ +#define looted flags /* used for throne, tree, fountain, sink, door */ +#define icedpool flags /* used for ice (in case it melts) */ +#define emptygrave flags /* no corpse in grave */ + /* * The 5 possible states of doors. * For historical reasons they are numbered as mask bits rather than 0..4. @@ -238,28 +294,6 @@ enum levl_typ_types { #define ICED_POOL 8 #define ICED_MOAT 16 -/* - * The structure describing a coordinate position. - * Before adding fields, remember that this will significantly affect - * the size of temporary files and save files. - * - * Also remember that the run-length encoding for some ports in save.c - * must be updated to consider the field. - */ -struct rm { - int glyph; /* what the hero thinks is there */ - schar typ; /* what is really there [why is this signed?] */ - uchar seenv; /* seen vector */ - Bitfield(flags, 5); /* extra information for typ */ - Bitfield(horizontal, 1); /* wall/door/etc is horiz. (more typ info) */ - Bitfield(lit, 1); /* speed hack for lit rooms */ - Bitfield(waslit, 1); /* remember if a location was lit */ - - Bitfield(roomno, 6); /* room # for special rooms */ - Bitfield(edge, 1); /* marks boundaries for special rooms*/ - Bitfield(candig, 1); /* Exception to Can_dig_down; was a trapdoor */ -}; - /* light states for terrain replacements, for set_levltyp_lit */ #define SET_LIT_RANDOM -1 #define SET_LIT_NOCHANGE -2 @@ -346,16 +380,6 @@ struct rm { #define SV7 ((seenV) 0x80) #define SVALL ((seenV) 0xFF) -/* if these get changed or expanded, make sure wizard-mode wishing becomes - aware of the new usage */ -#define doormask flags /* door, sdoor (note conflict with wall_info) */ -#define altarmask flags /* alignment and maybe temple */ -#define wall_info flags /* wall, sdoor (note conflict with doormask) */ -#define ladder flags /* up or down */ -#define drawbridgemask flags /* what's underneath when the span is open */ -#define looted flags /* used for throne, tree, fountain, sink, door */ -#define icedpool flags /* used for ice (in case it melts) */ -#define emptygrave flags /* no corpse in grave */ /* horizontal applies to walls, doors (including sdoor); also to iron bars even though they don't have separate symbols for horizontal and vertical */ #define blessedftn horizontal /* a fountain that grants attribs */ From f1743d0e5c855da884b906f0f6e56731a73dd5d0 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 9 Nov 2024 10:58:58 -0500 Subject: [PATCH 051/791] more rm.h comment updates --- include/rm.h | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/include/rm.h b/include/rm.h index acc04c0e1..59ddf1b87 100644 --- a/include/rm.h +++ b/include/rm.h @@ -134,20 +134,6 @@ enum levl_typ_types { ? db_under_typ(levl[x][y].drawbridgemask) \ : levl[x][y].typ) -/* - * Note: secret doors (SDOOR) want to use both rm.doormask and - * rm.wall_info but those both overload rm.flags. SDOOR only - * has 2 states (closed or locked). However, it can't specify - * D_CLOSED due to that conflicting with WM_MASK (below). When - * a secret door is revealed, the door gets set to D_CLOSED iff - * it isn't set to D_LOCKED (see cvt_sdoor_to_door() in detect.c). - * - * D_LOCKED conflicts with W_NONDIGGABLE but the latter is not - * expected to be used on door locations. D_TRAPPED conflicts - * with W_NONPASSWALL but secret doors aren't trapped. - * D_SECRET would not fit within struct rm's 5-bit 'flags' field. - */ - /* * The structure describing a coordinate position. * Before adding fields, remember that this will significantly affect @@ -193,6 +179,18 @@ struct rm { * * If these get changed or expanded, make sure wizard-mode wishing becomes * aware of the new usage + * + * Note: secret doors (SDOOR) want to use both rm.doormask and + * rm.wall_info but those both overload rm.flags. SDOOR only + * has 2 states (closed or locked). However, it can't specify + * D_CLOSED due to that conflicting with WM_MASK (below). When + * a secret door is revealed, the door gets set to D_CLOSED iff + * it isn't set to D_LOCKED (see cvt_sdoor_to_door() in detect.c). + * + * D_LOCKED conflicts with W_NONDIGGABLE but the latter is not + * expected to be used on door locations. D_TRAPPED conflicts + * with W_NONPASSWALL but secret doors aren't trapped. + * D_SECRET would not fit within struct rm's 5-bit 'flags' field. */ #define doormask flags /* door, sdoor (note conflict with wall_info) */ From 1dbba0f63b0b21230b339296748b0dac2b9137bf Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 9 Nov 2024 11:12:42 -0500 Subject: [PATCH 052/791] rename IS_ROCK() macro to IS_OBSTRUCTED() It has included trees since they were added, so give it a more fitting name. --- include/rm.h | 4 ++-- src/apply.c | 4 ++-- src/ball.c | 2 +- src/dig.c | 22 +++++++++++----------- src/display.c | 4 ++-- src/dogmove.c | 2 +- src/dokick.c | 8 ++++---- src/dothrow.c | 4 ++-- src/hack.c | 28 ++++++++++++++-------------- src/mhitm.c | 4 ++-- src/mklev.c | 10 +++++----- src/mkmap.c | 4 ++-- src/mon.c | 4 ++-- src/monmove.c | 2 +- src/mthrowu.c | 4 ++-- src/muse.c | 2 +- src/pray.c | 4 ++-- src/read.c | 2 +- src/sp_lev.c | 10 +++++----- src/trap.c | 2 +- src/uhitm.c | 2 +- src/vault.c | 2 +- src/vision.c | 4 ++-- 23 files changed, 67 insertions(+), 67 deletions(-) diff --git a/include/rm.h b/include/rm.h index 59ddf1b87..14005d90a 100644 --- a/include/rm.h +++ b/include/rm.h @@ -103,9 +103,9 @@ enum levl_typ_types { */ #define IS_WALL(typ) ((typ) && (typ) <= DBWALL) #define IS_STWALL(typ) ((typ) <= DBWALL) /* STONE <= (typ) <= DBWALL */ -#define IS_ROCK(typ) ((typ) < POOL) /* absolutely nonaccessible */ +#define IS_OBSTRUCTED(typ) ((typ) < POOL) /* absolutely nonaccessible */ #define IS_DOOR(typ) ((typ) == DOOR) -#define IS_DOORJOIN(typ) (IS_ROCK(typ) || (typ) == IRONBARS) +#define IS_DOORJOIN(typ) (IS_OBSTRUCTED(typ) || (typ) == IRONBARS) #define IS_TREE(typ) \ ((typ) == TREE || (svl.level.flags.arboreal && (typ) == STONE)) #define ACCESSIBLE(typ) ((typ) >= DOOR) /* good position */ diff --git a/src/apply.c b/src/apply.c index c03a1a9cf..271a6cd18 100644 --- a/src/apply.c +++ b/src/apply.c @@ -2512,7 +2512,7 @@ figurine_location_checks(struct obj *obj, coord *cc, boolean quietly) You("cannot put the figurine there."); return FALSE; } - if (IS_ROCK(levl[x][y].typ) + if (IS_OBSTRUCTED(levl[x][y].typ) && !(passes_walls(&mons[obj->corpsenm]) && may_passwall(x, y))) { if (!quietly) You("cannot place a figurine in %s!", @@ -2829,7 +2829,7 @@ use_trap(struct obj *otmp) else if (On_stairs(u.ux, u.uy)) { stairway *stway = stairway_at(u.ux, u.uy); what = stway->isladder ? "on the ladder" : "on the stairs"; - } else if (IS_FURNITURE(levtyp) || IS_ROCK(levtyp) + } else if (IS_FURNITURE(levtyp) || IS_OBSTRUCTED(levtyp) || closed_door(u.ux, u.uy) || t_at(u.ux, u.uy)) what = "here"; else if (Is_airlevel(&u.uz) || Is_waterlevel(&u.uz)) diff --git a/src/ball.c b/src/ball.c index 1ff2cc339..c3c53c289 100644 --- a/src/ball.c +++ b/src/ball.c @@ -609,7 +609,7 @@ drag_ball(coordxy x, coordxy y, int *bc_control, (distmin(x, y, chx, chy) <= 1 \ && distmin(chx, chy, uball->ox, uball->oy) <= 1) #define IS_CHAIN_ROCK(x, y) \ - (IS_ROCK(levl[x][y].typ) \ + (IS_OBSTRUCTED(levl[x][y].typ) \ || (IS_DOOR(levl[x][y].typ) \ && (levl[x][y].doormask & (D_CLOSED | D_LOCKED)))) /* diff --git a/src/dig.c b/src/dig.c index ed0879683..bedae5cf9 100644 --- a/src/dig.c +++ b/src/dig.c @@ -56,7 +56,7 @@ mkcavepos(coordxy x, coordxy y, int dist, boolean waslit, boolean rockit) if (rockit) { struct monst *mtmp; - if (IS_ROCK(lev->typ)) + if (IS_OBSTRUCTED(lev->typ)) return; if (t_at(x, y)) return; /* don't cover the portal */ @@ -186,7 +186,7 @@ dig_typ(struct obj *otmp, coordxy x, coordxy y) ? DIGTYP_DOOR : IS_TREE(levl[x][y].typ) ? (ispick ? DIGTYP_UNDIGGABLE : DIGTYP_TREE) - : (ispick && IS_ROCK(levl[x][y].typ) + : (ispick && IS_OBSTRUCTED(levl[x][y].typ) && (!svl.level.flags.arboreal || IS_WALL(levl[x][y].typ))) ? DIGTYP_ROCK @@ -227,7 +227,7 @@ dig_check(struct monst *madeby, coordxy x, coordxy y) return DIGCHECK_FAIL_AIRLEVEL; } else if (Is_waterlevel(&u.uz)) { return DIGCHECK_FAIL_WATERLEVEL; - } else if ((IS_ROCK(levl[x][y].typ) && levl[x][y].typ != SDOOR + } else if ((IS_OBSTRUCTED(levl[x][y].typ) && levl[x][y].typ != SDOOR && (levl[x][y].wall_info & W_NONDIGGABLE) != 0)) { return DIGCHECK_FAIL_TOOHARD; } else if (ttmp && undestroyable_trap(ttmp->ttyp)) { @@ -328,7 +328,7 @@ dig(void) pline("This tree seems to be petrified."); return 0; } - if (IS_ROCK(lev->typ) && !may_dig(dpx, dpy) + if (IS_OBSTRUCTED(lev->typ) && !may_dig(dpx, dpy) && dig_typ(uwep, dpx, dpy) == DIGTYP_ROCK) { pline("This %s is too hard to %s.", is_db_wall(dpx, dpy) ? "drawbridge" : "wall", verb); @@ -561,7 +561,7 @@ dig(void) return 0; } } else if (dig_target == DIGTYP_UNDIGGABLE - || (dig_target == DIGTYP_ROCK && !IS_ROCK(lev->typ))) + || (dig_target == DIGTYP_ROCK && !IS_OBSTRUCTED(lev->typ))) return 0; /* statue or boulder got taken */ if (!gd.did_dig_msg) { @@ -913,7 +913,7 @@ dighole(boolean pit_only, boolean by_magic, coord *cc) old_typ = lev->typ; if ((ttmp && (undestroyable_trap(ttmp->ttyp) || nohole)) - || (IS_ROCK(old_typ) && old_typ != SDOOR + || (IS_OBSTRUCTED(old_typ) && old_typ != SDOOR && (lev->wall_info & W_NONDIGGABLE) != 0)) { pline_The("%s %shere is too hard to dig in.", surface(dig_x, dig_y), (dig_x != u.ux || dig_y != u.uy) ? "t" : ""); @@ -1230,7 +1230,7 @@ use_pick_axe2(struct obj *obj) (void) fire_damage(uwep, FALSE, rx, ry); } else if (IS_TREE(lev->typ)) { You("need an axe to cut down a tree."); - } else if (IS_ROCK(lev->typ)) { + } else if (IS_OBSTRUCTED(lev->typ)) { You("need a pick to dig rock."); } else if ((boulder = sobj_at(BOULDER, rx, ry)) != 0 || sobj_at(STATUE, rx, ry)) { @@ -1398,7 +1398,7 @@ watch_dig(struct monst *mtmp, coordxy x, coordxy y, boolean zap) str = "door"; else if (IS_TREE(lev->typ)) str = "tree"; - else if (IS_ROCK(lev->typ)) + else if (IS_OBSTRUCTED(lev->typ)) str = "wall"; else str = "fountain"; @@ -1452,7 +1452,7 @@ mdig_tunnel(struct monst *mtmp) newsym(mtmp->mx, mtmp->my); draft_message(FALSE); /* "You feel a draft." */ return FALSE; - } else if (!IS_ROCK(here->typ) && !IS_TREE(here->typ)) { /* no dig */ + } else if (!IS_OBSTRUCTED(here->typ) && !IS_TREE(here->typ)) { /* no dig */ return FALSE; } @@ -1709,7 +1709,7 @@ zap_dig(void) pline_The("rock glows then fades."); break; } - } else if (IS_ROCK(room->typ)) { + } else if (IS_OBSTRUCTED(room->typ)) { if (!may_dig(zx, zy)) break; if (IS_WALL(room->typ) || room->typ == SDOOR) { @@ -1727,7 +1727,7 @@ zap_dig(void) } else if (IS_TREE(room->typ)) { room->typ = ROOM, room->flags = 0; digdepth -= 2; - } else { /* IS_ROCK but not IS_WALL or SDOOR */ + } else { /* IS_OBSTRUCTED but not IS_WALL or SDOOR */ room->typ = CORR, room->flags = 0; digdepth--; } diff --git a/src/display.c b/src/display.c index fb198e97d..30eb249dd 100644 --- a/src/display.c +++ b/src/display.c @@ -783,7 +783,7 @@ feel_location(coordxy x, coordxy y) * + Room/water positions * + Everything else (hallways!) */ - if (IS_ROCK(lev->typ) + if (IS_OBSTRUCTED(lev->typ) || (IS_DOOR(lev->typ) && (lev->doormask & (D_LOCKED | D_CLOSED)))) { map_background(x, y, 1); @@ -3101,7 +3101,7 @@ check_pos(coordxy x, coordxy y, int which) if (!isok(x, y)) return which; type = levl[x][y].typ; - if (IS_ROCK(type) || type == CORR || type == SCORR) + if (IS_OBSTRUCTED(type) || type == CORR || type == SCORR) return which; return 0; } diff --git a/src/dogmove.c b/src/dogmove.c index 6e25c39c2..2c77a6487 100644 --- a/src/dogmove.c +++ b/src/dogmove.c @@ -1362,7 +1362,7 @@ can_reach_location( continue; if (dist2(i, j, fx, fy) >= dist) continue; - if (IS_ROCK(levl[i][j].typ) && !passes_walls(mon->data) + if (IS_OBSTRUCTED(levl[i][j].typ) && !passes_walls(mon->data) && (!may_dig(i, j) || !tunnels(mon->data) /* tunnelling monsters can't do that on the rogue level */ || Is_rogue_level(&u.uz))) diff --git a/src/dokick.c b/src/dokick.c index 6d3d82cd2..b9d25eaaf 100644 --- a/src/dokick.c +++ b/src/dokick.c @@ -612,9 +612,9 @@ really_kick_object(coordxy x, coordxy y) Norep("You kick %s.", !isgold ? singular(gk.kickedobj, doname) : doname(gk.kickedobj)); - if (IS_ROCK(levl[x][y].typ) || closed_door(x, y)) { + if (IS_OBSTRUCTED(levl[x][y].typ) || closed_door(x, y)) { if ((!martial() && rn2(20) > ACURR(A_DEX)) - || IS_ROCK(levl[u.ux][u.uy].typ) || closed_door(u.ux, u.uy)) { + || IS_OBSTRUCTED(levl[u.ux][u.uy].typ) || closed_door(u.ux, u.uy)) { if (Blind) pline("It doesn't come loose."); else @@ -805,7 +805,7 @@ kickstr(char *buf, const char *kickobjnam) what = "a tree"; else if (IS_STWALL(gm.maploc->typ)) what = "a wall"; - else if (IS_ROCK(gm.maploc->typ)) + else if (IS_OBSTRUCTED(gm.maploc->typ)) what = "a rock"; else if (IS_THRONE(gm.maploc->typ)) what = "a throne"; @@ -1360,7 +1360,7 @@ dokick(void) * reachable for bracing purposes * Possible extension: allow bracing against stuff on the side? */ - if (isok(xx, yy) && !IS_ROCK(levl[xx][yy].typ) + if (isok(xx, yy) && !IS_OBSTRUCTED(levl[xx][yy].typ) && !IS_DOOR(levl[xx][yy].typ) && (!Is_airlevel(&u.uz) || !OBJ_AT(xx, yy))) { You("have nothing to brace yourself against."); diff --git a/src/dothrow.c b/src/dothrow.c index 286e00f1c..ef61e7137 100644 --- a/src/dothrow.c +++ b/src/dothrow.c @@ -785,7 +785,7 @@ hurtle_step(genericptr_t arg, coordxy x, coordxy y) && (levl[x][y].doormask & D_ISOPEN) && (u.ux - x) && (u.uy - y)); - if (IS_ROCK(levl[x][y].typ) || closed_door(x, y) || odoor_diag) { + if (IS_OBSTRUCTED(levl[x][y].typ) || closed_door(x, y) || odoor_diag) { const char *s; if (odoor_diag) @@ -793,7 +793,7 @@ hurtle_step(genericptr_t arg, coordxy x, coordxy y) pline("Ouch!"); if (IS_TREE(levl[x][y].typ)) s = "bumping into a tree"; - else if (IS_ROCK(levl[x][y].typ)) + else if (IS_OBSTRUCTED(levl[x][y].typ)) s = "bumping into a wall"; else s = "bumping into a door"; diff --git a/src/hack.c b/src/hack.c index e3290da7e..de5d072ff 100644 --- a/src/hack.c +++ b/src/hack.c @@ -151,8 +151,8 @@ could_move_onto_boulder(coordxy sx, coordxy sy) /* can if a giant, unless doing so allows hero to pass into a diagonal squeeze at the same time */ if (throws_rocks(gy.youmonst.data)) - return (!u.dx || !u.dy || !(IS_ROCK(levl[u.ux][sy].typ) - && IS_ROCK(levl[sx][u.uy].typ))); + return (!u.dx || !u.dy || !(IS_OBSTRUCTED(levl[u.ux][sy].typ) + && IS_OBSTRUCTED(levl[sx][u.uy].typ))); /* can if tiny (implies carrying very little else couldn't move at all) */ if (verysmall(gy.youmonst.data)) return TRUE; @@ -427,7 +427,7 @@ moverock_core(coordxy sx, coordxy sy) pline("You're too small to push that %s.", xname(otmp)); return cannot_push(otmp, sx, sy); } - if (isok(rx, ry) && !IS_ROCK(levl[rx][ry].typ) + if (isok(rx, ry) && !IS_OBSTRUCTED(levl[rx][ry].typ) && levl[rx][ry].typ != IRONBARS && (!IS_DOOR(levl[rx][ry].typ) || !(u.dx && u.dy) || doorless_door(rx, ry)) && !sobj_at(BOULDER, rx, ry)) { @@ -632,7 +632,7 @@ still_chewing(coordxy x, coordxy y) sizeof (struct dig_info)); if (!boulder - && ((IS_ROCK(lev->typ) && !may_dig(x, y)) + && ((IS_OBSTRUCTED(lev->typ) && !may_dig(x, y)) /* may_dig() checks W_NONDIGGABLE but doesn't handle iron bars */ || (lev->typ == IRONBARS && (lev->wall_info & W_NONDIGGABLE)))) { You("hurt your teeth on the %s.", @@ -661,7 +661,7 @@ still_chewing(coordxy x, coordxy y) assign_level(&svc.context.digging.level, &u.uz); /* solid rock takes more work & time to dig through */ svc.context.digging.effort = - (IS_ROCK(lev->typ) && !IS_TREE(lev->typ) ? 30 : 60) + u.udaminc; + (IS_OBSTRUCTED(lev->typ) && !IS_TREE(lev->typ) ? 30 : 60) + u.udaminc; You("start chewing %s %s.", (boulder || IS_TREE(lev->typ) || lev->typ == IRONBARS) ? "on a" @@ -670,7 +670,7 @@ still_chewing(coordxy x, coordxy y) ? "boulder" : IS_TREE(lev->typ) ? "tree" - : IS_ROCK(lev->typ) + : IS_OBSTRUCTED(lev->typ) ? "rock" : (lev->typ == IRONBARS) ? "bar" @@ -685,7 +685,7 @@ still_chewing(coordxy x, coordxy y) ? "boulder" : IS_TREE(lev->typ) ? "tree" - : IS_ROCK(lev->typ) + : IS_OBSTRUCTED(lev->typ) ? "rock" : (lev->typ == IRONBARS) ? "bars" @@ -701,7 +701,7 @@ still_chewing(coordxy x, coordxy y) "ate for the first time, by chewing through %s", boulder ? "a boulder" : IS_TREE(lev->typ) ? "a tree" - : IS_ROCK(lev->typ) ? "rock" + : IS_OBSTRUCTED(lev->typ) ? "rock" : (lev->typ == IRONBARS) ? "iron bars" : "a door"); u.uhunger += rnd(20); @@ -717,7 +717,7 @@ still_chewing(coordxy x, coordxy y) * * [perhaps use does_block() below (from vision.c)] */ - if (IS_ROCK(lev->typ) || closed_door(x, y) + if (IS_OBSTRUCTED(lev->typ) || closed_door(x, y) || sobj_at(BOULDER, x, y)) { block_point(x, y); /* delobj will unblock the point */ /* reset dig state */ @@ -916,7 +916,7 @@ boolean bad_rock(struct permonst *mdat, coordxy x, coordxy y) { return (boolean) ((Sokoban && sobj_at(BOULDER, x, y)) - || (IS_ROCK(levl[x][y].typ) + || (IS_OBSTRUCTED(levl[x][y].typ) && (!tunnels(mdat) || needspick(mdat) || !may_dig(x, y)) && !(passes_walls(mdat) && may_passwall(x, y)))); @@ -979,7 +979,7 @@ test_move( /* * Check for physical obstacles. First, the place we are going. */ - if (IS_ROCK(tmpr->typ) || tmpr->typ == IRONBARS) { + if (IS_OBSTRUCTED(tmpr->typ) || tmpr->typ == IRONBARS) { if (Blind && mode == DO_MOVE) feel_location(x, y); if (Passes_walls && may_passwall(x, y)) { @@ -2878,7 +2878,7 @@ domove_core(void) reset_occupations(); if (svc.context.run) { if (svc.context.run < 8) - if (IS_DOOR(tmpr->typ) || IS_ROCK(tmpr->typ) + if (IS_DOOR(tmpr->typ) || IS_OBSTRUCTED(tmpr->typ) || IS_FURNITURE(tmpr->typ)) nomul(0); } @@ -3033,7 +3033,7 @@ void switch_terrain(void) { struct rm *lev = &levl[u.ux][u.uy]; - boolean blocklev = (IS_ROCK(lev->typ) || closed_door(u.ux, u.uy) + boolean blocklev = (IS_OBSTRUCTED(lev->typ) || closed_door(u.ux, u.uy) || IS_WATERWALL(lev->typ) || lev->typ == LAVAWALL), was_levitating = !!Levitation, was_flying = !!Flying; @@ -3801,7 +3801,7 @@ lookaround(void) } /* more uninteresting terrain */ - if (IS_ROCK(levl[x][y].typ) || levl[x][y].typ == ROOM + if (IS_OBSTRUCTED(levl[x][y].typ) || levl[x][y].typ == ROOM || IS_AIR(levl[x][y].typ) || levl[x][y].typ == ICE) { continue; } else if (closed_door(x, y) || (mtmp && is_door_mappear(mtmp))) { diff --git a/src/mhitm.c b/src/mhitm.c index a473fa06c..10fa8cfc8 100644 --- a/src/mhitm.c +++ b/src/mhitm.c @@ -818,7 +818,7 @@ engulf_target(struct monst *magr, struct monst *mdef) dy = (mdef == &gy.youmonst) ? u.uy : mdef->my; lev = &levl[dx][dy]; if (!(udef ? Passes_walls : passes_walls(mdef->data)) - && (IS_ROCK(lev->typ) || closed_door(dx, dy) || IS_TREE(lev->typ) + && (IS_OBSTRUCTED(lev->typ) || closed_door(dx, dy) || IS_TREE(lev->typ) /* not passes_bars(); engulfer isn't squeezing through */ || (lev->typ == IRONBARS && !is_whirly(magr->data)))) return FALSE; @@ -826,7 +826,7 @@ engulf_target(struct monst *magr, struct monst *mdef) ay = (magr == &gy.youmonst) ? u.uy : magr->my; lev = &levl[ax][ay]; if (!(uatk ? Passes_walls : passes_walls(magr->data)) - && (IS_ROCK(lev->typ) || closed_door(ax, ay) || IS_TREE(lev->typ) + && (IS_OBSTRUCTED(lev->typ) || closed_door(ax, ay) || IS_TREE(lev->typ) || (lev->typ == IRONBARS && !is_whirly(mdef->data)))) return FALSE; diff --git a/src/mklev.c b/src/mklev.c index 1e8a6f703..a209cf371 100644 --- a/src/mklev.c +++ b/src/mklev.c @@ -77,7 +77,7 @@ door_into_nonjoined(coordxy x, coordxy y) for (i = 0; i < 4; i++) { tx = x + xdir[dirs_ord[i]]; ty = y + ydir[dirs_ord[i]]; - if (!isok(tx, ty) || IS_ROCK(levl[tx][ty].typ)) + if (!isok(tx, ty) || IS_OBSTRUCTED(levl[tx][ty].typ)) continue; /* Is this connecting to a room that doesn't want joining? */ @@ -1621,10 +1621,10 @@ okdoor(coordxy x, coordxy y) boolean near_door = bydoor(x, y); return ((levl[x][y].typ == HWALL || levl[x][y].typ == VWALL) - && ((isok(x - 1, y) && !IS_ROCK(levl[x - 1][y].typ)) - || (isok(x + 1, y) && !IS_ROCK(levl[x + 1][y].typ)) - || (isok(x, y - 1) && !IS_ROCK(levl[x][y - 1].typ)) - || (isok(x, y + 1) && !IS_ROCK(levl[x][y + 1].typ))) + && ((isok(x - 1, y) && !IS_OBSTRUCTED(levl[x - 1][y].typ)) + || (isok(x + 1, y) && !IS_OBSTRUCTED(levl[x + 1][y].typ)) + || (isok(x, y - 1) && !IS_OBSTRUCTED(levl[x][y - 1].typ)) + || (isok(x, y + 1) && !IS_OBSTRUCTED(levl[x][y + 1].typ))) && !near_door); } diff --git a/src/mkmap.c b/src/mkmap.c index 32c6aef68..26c3d3836 100644 --- a/src/mkmap.c +++ b/src/mkmap.c @@ -345,8 +345,8 @@ finish_map( if (lit) { for (i = 1; i < COLNO; i++) for (j = 0; j < ROWNO; j++) - if ((!IS_ROCK(fg_typ) && levl[i][j].typ == fg_typ) - || (!IS_ROCK(bg_typ) && levl[i][j].typ == bg_typ) + if ((!IS_OBSTRUCTED(fg_typ) && levl[i][j].typ == fg_typ) + || (!IS_OBSTRUCTED(bg_typ) && levl[i][j].typ == bg_typ) || (bg_typ == TREE && levl[i][j].typ == bg_typ) || (walled && IS_WALL(levl[i][j].typ))) levl[i][j].lit = TRUE; diff --git a/src/mon.c b/src/mon.c index fbf3bde86..e3879d54b 100644 --- a/src/mon.c +++ b/src/mon.c @@ -2170,12 +2170,12 @@ mfndpos( if (nx == x && ny == y) continue; ntyp = levl[nx][ny].typ; - if (IS_ROCK(ntyp) + if (IS_OBSTRUCTED(ntyp) && !((flag & ALLOW_WALL) && may_passwall(nx, ny)) && !((IS_TREE(ntyp) ? treeok : rockok) && may_dig(nx, ny))) continue; /* intelligent peacefuls avoid digging shop/temple walls */ - if (IS_ROCK(ntyp) && rockok + if (IS_OBSTRUCTED(ntyp) && rockok && !mindless(mon->data) && (mon->mpeaceful || mon->mtame) && (*in_rooms(nx, ny, TEMPLE) || *in_rooms(nx, ny, SHOPBASE)) && !(*in_rooms(x, y, TEMPLE) || *in_rooms(x, y, SHOPBASE))) diff --git a/src/monmove.c b/src/monmove.c index dc343d333..7705a3e1a 100644 --- a/src/monmove.c +++ b/src/monmove.c @@ -1174,7 +1174,7 @@ holds_up_web(coordxy x, coordxy y) stairway *sway; if (!isok(x, y) - || IS_ROCK(levl[x][y].typ) + || IS_OBSTRUCTED(levl[x][y].typ) || ((levl[x][y].typ == STAIRS || levl[x][y].typ == LADDER) && (sway = stairway_at(x, y)) != 0 && sway->up) || levl[x][y].typ == IRONBARS) diff --git a/src/mthrowu.c b/src/mthrowu.c index b91d44435..455220098 100644 --- a/src/mthrowu.c +++ b/src/mthrowu.c @@ -528,7 +528,7 @@ ucatchgem( (/* missile hits edge of screen */ \ !isok(gb.bhitpos.x + dx, gb.bhitpos.y + dy) \ /* missile hits the wall */ \ - || IS_ROCK(levl[gb.bhitpos.x + dx][gb.bhitpos.y + dy].typ) \ + || IS_OBSTRUCTED(levl[gb.bhitpos.x + dx][gb.bhitpos.y + dy].typ) \ /* missile hit closed door */ \ || closed_door(gb.bhitpos.x + dx, gb.bhitpos.y + dy) \ /* missile might hit iron bars */ \ @@ -1080,7 +1080,7 @@ breamu(struct monst *mtmp, struct attack *mattk) staticfn boolean blocking_terrain(coordxy x, coordxy y) { - if (!isok(x, y) || IS_ROCK(levl[x][y].typ) || closed_door(x, y) + if (!isok(x, y) || IS_OBSTRUCTED(levl[x][y].typ) || closed_door(x, y) || is_waterwall(x, y) || levl[x][y].typ == LAVAWALL) return TRUE; return FALSE; diff --git a/src/muse.c b/src/muse.c index dd61a9432..cb2c72a2b 100644 --- a/src/muse.c +++ b/src/muse.c @@ -1840,7 +1840,7 @@ use_offensive(struct monst *mtmp) for (y = mmy - 1; y <= mmy + 1; y++) { /* Is this a suitable spot? */ if (isok(x, y) && !closed_door(x, y) - && !IS_ROCK(levl[x][y].typ) && !IS_AIR(levl[x][y].typ) + && !IS_OBSTRUCTED(levl[x][y].typ) && !IS_AIR(levl[x][y].typ) && (((x == mmx) && (y == mmy)) ? !is_blessed : !is_cursed) && (x != u.ux || y != u.uy)) { (void) drop_boulder_on_monster(x, y, confused, FALSE); diff --git a/src/pray.c b/src/pray.c index 3fa5de2b6..7a28fdc84 100644 --- a/src/pray.c +++ b/src/pray.c @@ -169,7 +169,7 @@ stuck_in_wall(void) continue; y = u.uy + j; if (!isok(x, y) - || (IS_ROCK(levl[x][y].typ) + || (IS_OBSTRUCTED(levl[x][y].typ) && (levl[x][y].typ != SDOOR && levl[x][y].typ != SCORR)) || (blocked_boulder(i, j) && !throws_rocks(gy.youmonst.data))) ++count; @@ -2633,7 +2633,7 @@ blocked_boulder(int dx, int dy) return TRUE; if (!isok(nx, ny)) return TRUE; - if (IS_ROCK(levl[nx][ny].typ)) + if (IS_OBSTRUCTED(levl[nx][ny].typ)) return TRUE; if (sobj_at(BOULDER, nx, ny)) return TRUE; diff --git a/src/read.c b/src/read.c index 1e53e5a2a..4110894ae 100644 --- a/src/read.c +++ b/src/read.c @@ -1850,7 +1850,7 @@ seffect_earth(struct obj **sobjp) for (y = u.uy - 1; y <= u.uy + 1; y++) { /* Is this a suitable spot? */ if (isok(x, y) && !closed_door(x, y) - && !IS_ROCK(levl[x][y].typ) + && !IS_OBSTRUCTED(levl[x][y].typ) && !IS_AIR(levl[x][y].typ) && (x != u.ux || y != u.uy)) { nboulders += diff --git a/src/sp_lev.c b/src/sp_lev.c index 5e7be44e7..a429ba10b 100644 --- a/src/sp_lev.c +++ b/src/sp_lev.c @@ -1291,7 +1291,7 @@ is_ok_location(coordxy x, coordxy y, getloc_flags_t humidity) if (humidity & ANY_LOC) return TRUE; - if ((humidity & SOLID) && IS_ROCK(typ)) + if ((humidity & SOLID) && IS_OBSTRUCTED(typ)) return TRUE; if ((humidity & (DRY|SPACELOC)) && SPACE_POS(typ)) { @@ -1758,7 +1758,7 @@ create_door(room_door *dd, struct mkroom *broom) y = broom->ly - 1; x = broom->lx + ((dpos == -1) ? rn2(1 + broom->hx - broom->lx) : dpos); - if (!isok(x, y - 1) || IS_ROCK(levl[x][y - 1].typ)) + if (!isok(x, y - 1) || IS_OBSTRUCTED(levl[x][y - 1].typ)) continue; break; case 1: @@ -1767,7 +1767,7 @@ create_door(room_door *dd, struct mkroom *broom) y = broom->hy + 1; x = broom->lx + ((dpos == -1) ? rn2(1 + broom->hx - broom->lx) : dpos); - if (!isok(x, y + 1) || IS_ROCK(levl[x][y + 1].typ)) + if (!isok(x, y + 1) || IS_OBSTRUCTED(levl[x][y + 1].typ)) continue; break; case 2: @@ -1776,7 +1776,7 @@ create_door(room_door *dd, struct mkroom *broom) x = broom->lx - 1; y = broom->ly + ((dpos == -1) ? rn2(1 + broom->hy - broom->ly) : dpos); - if (!isok(x - 1, y) || IS_ROCK(levl[x - 1][y].typ)) + if (!isok(x - 1, y) || IS_OBSTRUCTED(levl[x - 1][y].typ)) continue; break; case 3: @@ -1785,7 +1785,7 @@ create_door(room_door *dd, struct mkroom *broom) x = broom->hx + 1; y = broom->ly + ((dpos == -1) ? rn2(1 + broom->hy - broom->ly) : dpos); - if (!isok(x + 1, y) || IS_ROCK(levl[x + 1][y].typ)) + if (!isok(x + 1, y) || IS_OBSTRUCTED(levl[x + 1][y].typ)) continue; break; default: diff --git a/src/trap.c b/src/trap.c index b75dae7d5..91103153c 100644 --- a/src/trap.c +++ b/src/trap.c @@ -3383,7 +3383,7 @@ launch_obj( const char *bmsg = " as one boulder sets another in motion"; coordxy fx = x + dx, fy = y + dy; - if (!isok(fx, fy) || !dist || IS_ROCK(levl[fx][fy].typ)) + if (!isok(fx, fy) || !dist || IS_OBSTRUCTED(levl[fx][fy].typ)) bmsg = " as one boulder hits another"; Soundeffect(se_loud_crash, 80); diff --git a/src/uhitm.c b/src/uhitm.c index bda3557f0..e0a403ebb 100644 --- a/src/uhitm.c +++ b/src/uhitm.c @@ -469,7 +469,7 @@ do_attack(struct monst *mtmp) */ boolean foo = (Punished || !rn2(7) || (is_longworm(mtmp->data) && mtmp->wormno) - || (IS_ROCK(levl[u.ux][u.uy].typ) + || (IS_OBSTRUCTED(levl[u.ux][u.uy].typ) && !passes_walls(mtmp->data))), inshop = FALSE; char *p; diff --git a/src/vault.c b/src/vault.c index eca749697..44052f545 100644 --- a/src/vault.c +++ b/src/vault.c @@ -109,7 +109,7 @@ clear_fcorr(struct monst *grd, boolean forceshow) /* only give encased message if hero is still alive (might get here via paygd() -> mongone() -> grddead() when game is over; died: no message, quit: message) */ - if (IS_ROCK(levl[u.ux][u.uy].typ) && (Upolyd ? u.mh : u.uhp) > 0 + if (IS_OBSTRUCTED(levl[u.ux][u.uy].typ) && (Upolyd ? u.mh : u.uhp) > 0 && !silently) You("are encased in rock."); return TRUE; diff --git a/src/vision.c b/src/vision.c index d94c56bf4..4d4ac98cf 100644 --- a/src/vision.c +++ b/src/vision.c @@ -154,7 +154,7 @@ does_block(int x, int y, struct rm *lev) #endif /* Features that block . . */ - if (IS_ROCK(lev->typ) || lev->typ == TREE + if (IS_OBSTRUCTED(lev->typ) || lev->typ == TREE || (IS_DOOR(lev->typ) && (lev->doormask & (D_CLOSED | D_LOCKED | D_TRAPPED)))) return 1; @@ -221,7 +221,7 @@ vision_reset(void) block = TRUE; /* location (0,y) is always stone; it's !isok() */ lev = &levl[1][y]; for (x = 1; x < COLNO; x++, lev += ROWNO) - if (block != (IS_ROCK(lev->typ) || does_block(x, y, lev))) { + if (block != (IS_OBSTRUCTED(lev->typ) || does_block(x, y, lev))) { if (block) { for (i = dig_left; i < x; i++) { left_ptrs[y][i] = dig_left; From 36d8998edb7600b12d450fe9c3e649c88fd17e01 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 9 Nov 2024 11:40:09 -0500 Subject: [PATCH 053/791] try not including trees when check_pos() returns it's 3rd argument. Related to #1309 https://github.com/NetHack/NetHack/issues/1309 K2 commented: "This might help - k21971/EvilHack@afed641" A comment in there states: "Fix: sections of wall being visible when they shouldn't yet. This has been a long-standing bug for as long as I can remember, and qt appears to have figured it out. What was happening: the player would all of the sudden see a section of wall in an area that they hadn't explored yet. It was discovered that this was only occurring if that section of wall had any type of tree up against it." The fix there attempts to leave trees out of the check_pos non-zero return, so give that a shot. I didn't attempt to reproduce the situation myself, and therefore cannot confirm that this does resolve it. Feedback on effectiveness or side-effects are welcomed. If someone is able to confirm that this resolves the issue without creating new issues, we can close it, otherwise this can be reverted. --- include/rm.h | 2 ++ src/display.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/include/rm.h b/include/rm.h index 14005d90a..060a1c22f 100644 --- a/include/rm.h +++ b/include/rm.h @@ -104,6 +104,8 @@ enum levl_typ_types { #define IS_WALL(typ) ((typ) && (typ) <= DBWALL) #define IS_STWALL(typ) ((typ) <= DBWALL) /* STONE <= (typ) <= DBWALL */ #define IS_OBSTRUCTED(typ) ((typ) < POOL) /* absolutely nonaccessible */ +#define IS_CORR(typ) ((typ) == CORR || (typ) == SCORR) +#define IS_SDOOR(typ) ((typ) == SDOOR) #define IS_DOOR(typ) ((typ) == DOOR) #define IS_DOORJOIN(typ) (IS_OBSTRUCTED(typ) || (typ) == IRONBARS) #define IS_TREE(typ) \ diff --git a/src/display.c b/src/display.c index 30eb249dd..c379331e5 100644 --- a/src/display.c +++ b/src/display.c @@ -3101,7 +3101,7 @@ check_pos(coordxy x, coordxy y, int which) if (!isok(x, y)) return which; type = levl[x][y].typ; - if (IS_OBSTRUCTED(type) || type == CORR || type == SCORR) + if (IS_STWALL(type) || IS_CORR(type) || IS_SDOOR(type)) return which; return 0; } From 9c554895b1af9fd67bd7f9d6aabb2158fff4289c Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 9 Nov 2024 14:06:43 -0500 Subject: [PATCH 054/791] adjust wish for cockatrice corpse Wishing is powerful, so if you cannot safely handle a cockatrice corpse, then have a wish for one result in the corpse materializing on the floor rather than in your inventory. Resolves #1320 --- include/extern.h | 1 + include/obj.h | 1 + src/invent.c | 6 ++++++ src/pickup.c | 12 ++++++++++-- src/zap.c | 12 ++++++++++-- 5 files changed, 28 insertions(+), 4 deletions(-) diff --git a/include/extern.h b/include/extern.h index 8422224f4..ceafb5000 100644 --- a/include/extern.h +++ b/include/extern.h @@ -2363,6 +2363,7 @@ extern int loot_mon(struct monst *, int *, boolean *) NO_NNARGS; extern int dotip(void); extern struct autopickup_exception *check_autopickup_exceptions(struct obj *) NONNULLARG1; extern boolean autopick_testobj(struct obj *, boolean) NONNULLARG1; +extern boolean u_safe_from_fatal_corpse(struct obj *obj) NONNULLARG1; /* ### pline.c ### */ diff --git a/include/obj.h b/include/obj.h index abdd3c735..f43d94f81 100644 --- a/include/obj.h +++ b/include/obj.h @@ -162,6 +162,7 @@ struct obj { * 1 for others (format as "next boulder") */ int usecount; /* overloaded for various things that tally */ #define spestudied usecount /* # of times a spellbook has been studied */ +#define wishedfor usecount /* flag for hold_another_object() if from wish */ unsigned oeaten; /* nutrition left in food, if partly eaten */ long age; /* creation date */ long owornmask; /* bit mask indicating which equipment slot(s) an diff --git a/src/invent.c b/src/invent.c index 2e696214a..00ccd045c 100644 --- a/src/invent.c +++ b/src/invent.c @@ -1230,6 +1230,12 @@ hold_another_object( dropped, avoid perminv update when temporarily adding it */ obj = addinv_core0(obj, (struct obj *) 0, FALSE); goto drop_it; + } else if (obj->otyp == CORPSE + && !u_safe_from_fatal_corpse(obj) + && obj->wishedfor) { + obj->wishedfor = 0; + obj = addinv_core0(obj, (struct obj *) 0, FALSE); + goto drop_it; } else { long oquan = obj->quan; int prev_encumbr = near_capacity(); /* before addinv() */ diff --git a/src/pickup.c b/src/pickup.c index 75e685b97..b68761a39 100644 --- a/src/pickup.c +++ b/src/pickup.c @@ -261,12 +261,20 @@ query_classes( return TRUE; } +boolean +u_safe_from_fatal_corpse(struct obj *obj) +{ + if (uarmg || obj->otyp != CORPSE + || !touch_petrifies(&mons[obj->corpsenm]) || Stone_resistance) + return TRUE; + return FALSE; +} + /* check whether hero is bare-handedly touching a cockatrice corpse */ staticfn boolean fatal_corpse_mistake(struct obj *obj, boolean remotely) { - if (uarmg || remotely || obj->otyp != CORPSE - || !touch_petrifies(&mons[obj->corpsenm]) || Stone_resistance) + if (u_safe_from_fatal_corpse(obj) || remotely) return FALSE; if (poly_when_stoned(gy.youmonst.data) && polymon(PM_STONE_GOLEM)) { diff --git a/src/zap.c b/src/zap.c index 37531eeab..78baab25e 100644 --- a/src/zap.c +++ b/src/zap.c @@ -6189,14 +6189,22 @@ makewish(void) /* TODO? maybe generate a second event describing what was received since these just echo player's request rather than show actual result */ - const char *verb = ((Is_airlevel(&u.uz) || u.uinwater) ? "slip" : "drop"), + if (otmp->otyp == CORPSE && !u_safe_from_fatal_corpse(otmp)) + otmp->wishedfor = 1; + + const char *verb = ((Is_airlevel(&u.uz) || u.uinwater) + ? "slip" + : (otmp->otyp == CORPSE && otmp->wishedfor) + ? "materialize" : "drop"), *oops_msg = (u.uswallow ? "Oops! %s out of your reach!" : (Is_airlevel(&u.uz) || Is_waterlevel(&u.uz) || levl[u.ux][u.uy].typ < IRONBARS || levl[u.ux][u.uy].typ >= ICE) ? "Oops! %s away from you!" - : "Oops! %s to the floor!"); + : !(otmp->otyp == CORPSE && otmp->wishedfor) + ? "Oops! %s to the floor!" + : "Careful! %s on the floor!"); /* The(aobjnam()) is safe since otmp is unidentified -dlc */ (void) hold_another_object(otmp, oops_msg, The(aobjnam(otmp, verb)), From 5cc529efc812b59174e5a1cbc0c5df2a0d5e53f8 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 9 Nov 2024 23:49:10 -0500 Subject: [PATCH 055/791] follow-up related to #1320 This is additional groundwork related to https://github.com/NetHack/NetHack/issues/1320 This additional groundwork just puts some safeguards in place to make it rather tough to end up with an instant death from handling a cockatrice corpse in your inventory without appropriate protection. At this point, still no actual petrification will occur. --- include/extern.h | 3 ++- src/do.c | 22 +++++++++++++++++++++- src/do_wear.c | 23 +++++++++++++++++++++++ src/invent.c | 15 ++++++++++++++- src/pickup.c | 17 +++++++++++++---- src/zap.c | 2 +- 6 files changed, 74 insertions(+), 8 deletions(-) diff --git a/include/extern.h b/include/extern.h index ceafb5000..d4abee992 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1326,6 +1326,7 @@ extern void silly_thing(const char *, struct obj *) NONNULLARG1; extern void sync_perminvent(void); extern void perm_invent_toggled(boolean negated); extern void prepare_perminvent(winid window); +extern struct obj *carrying_stoning_corpse(void); /* ### ioctl.c ### */ @@ -2363,7 +2364,7 @@ extern int loot_mon(struct monst *, int *, boolean *) NO_NNARGS; extern int dotip(void); extern struct autopickup_exception *check_autopickup_exceptions(struct obj *) NONNULLARG1; extern boolean autopick_testobj(struct obj *, boolean) NONNULLARG1; -extern boolean u_safe_from_fatal_corpse(struct obj *obj) NONNULLARG1; +extern boolean u_safe_from_fatal_corpse(struct obj *obj, int) NONNULLARG1; /* ### pline.c ### */ diff --git a/src/do.c b/src/do.c index 591537f12..204643522 100644 --- a/src/do.c +++ b/src/do.c @@ -20,8 +20,9 @@ staticfn NHFILE *currentlevel_rewrite(void); staticfn void familiar_level_msg(void); staticfn void final_level(void); staticfn void temperature_change_msg(schar); +staticfn boolean better_not_try_to_drop_that(struct obj *); -/* static boolean badspot(coordxy,coordxy); */ + /* static boolean badspot(coordxy,coordxy); */ /* the #drop command: drop one inventory item */ int @@ -709,6 +710,8 @@ drop(struct obj *obj) return ECMD_FAIL; if (!canletgo(obj, "drop")) return ECMD_FAIL; + if (obj->otyp == CORPSE && better_not_try_to_drop_that(obj)) + return ECMD_FAIL; if (obj == uwep) { if (welded(uwep)) { weldmsg(obj); @@ -933,6 +936,23 @@ doddrop(void) return result; } +staticfn boolean +better_not_try_to_drop_that(struct obj *otmp) +{ + char buf[BUFSZ]; + + /* u_safe_from_fatal_corpse() with 0xF checks for gloves and stoning + * resistance before bothering to prompt you. + */ + if (otmp->otyp == CORPSE && !u_safe_from_fatal_corpse(otmp, 0xF)) { + Snprintf( + buf, sizeof buf, + "Drop the %s corpse without any protection while handling it?", + obj_pmname(otmp)); + return (paranoid_ynq(TRUE, buf, FALSE) != 'y'); + } + return FALSE; +} staticfn int /* check callers */ menudrop_split(struct obj *otmp, long cnt) { diff --git a/src/do_wear.c b/src/do_wear.c index 4f20e1b40..d6aac2a60 100644 --- a/src/do_wear.c +++ b/src/do_wear.c @@ -52,6 +52,7 @@ staticfn int takeoff_ok(struct obj *); /* maybe_destroy_armor() may return NULL */ staticfn struct obj *maybe_destroy_armor(struct obj *, struct obj *, boolean *) NONNULLARG3; +staticfn boolean better_not_take_that_off(struct obj *) NONNULLARG1; /* plural "fingers" or optionally "gloves" */ const char * @@ -2641,6 +2642,8 @@ select_off(struct obj *otmp) gloves_simple_name(uarmg)); return 0; } + if (better_not_take_that_off(otmp)) + return 0; } /* special boot checks */ if (otmp == uarmf) { @@ -2886,6 +2889,26 @@ take_off(void) return 1; /* get busy */ } +staticfn boolean +better_not_take_that_off(struct obj *otmp) +{ + struct obj *corpse = carrying_stoning_corpse(); + char buf[BUFSZ]; + + /* u_safe_from_fatal_corpse() with 0x4e instead of 0x6 + would also check for no stoning resistance before + bothering to prompt, but losing stoning resistance + later, without the gloves on could prove dangerous, + so we won't factor that in */ + if (corpse && !u_safe_from_fatal_corpse(corpse, 0x6)) { + Snprintf(buf, sizeof buf, + "Take off your %s despite carrying a dead %s?", + gloves_simple_name(otmp), obj_pmname(corpse)); + return (paranoid_ynq(TRUE, buf, FALSE) != 'y'); + } + return FALSE; +} + /* clear saved context to avoid inappropriate resumption of interrupted 'A' */ void reset_remarm(void) diff --git a/src/invent.c b/src/invent.c index 00ccd045c..fb137aabf 100644 --- a/src/invent.c +++ b/src/invent.c @@ -49,6 +49,7 @@ staticfn void ia_addmenu(winid, int, char, const char *); staticfn void itemactions_pushkeys(struct obj *, int); staticfn int itemactions(struct obj *); staticfn int dispinv_with_action(char *, boolean, const char *); +staticfn struct obj *carrying_cockatrice_corpse(void); /* enum and structs are defined in wintype.h */ static win_request_info wri_info; @@ -1231,7 +1232,7 @@ hold_another_object( obj = addinv_core0(obj, (struct obj *) 0, FALSE); goto drop_it; } else if (obj->otyp == CORPSE - && !u_safe_from_fatal_corpse(obj) + && !u_safe_from_fatal_corpse(obj, 0xF) && obj->wishedfor) { obj->wishedfor = 0; obj = addinv_core0(obj, (struct obj *) 0, FALSE); @@ -1480,6 +1481,18 @@ carrying(int type) return otmp; } +/* return inventory object of type that will petrify on touch */ +struct obj * +carrying_stoning_corpse(void) +{ + struct obj *otmp; + + for (otmp = gi.invent; otmp; otmp = otmp->nobj) + if (otmp->otyp == CORPSE && touch_petrifies(&mons[otmp->corpsenm])) + break; + return otmp; +} + /* Fictional and not-so-fictional currencies. * http://concord.wikia.com/wiki/List_of_Fictional_Currencies */ diff --git a/src/pickup.c b/src/pickup.c index b68761a39..48fe61c18 100644 --- a/src/pickup.c +++ b/src/pickup.c @@ -261,11 +261,20 @@ query_classes( return TRUE; } +/* + * tests: + * 1 = gloves + * 2 = is_corpse + * 4 = does corpse petrify + * 8 = stone resistance + */ boolean -u_safe_from_fatal_corpse(struct obj *obj) +u_safe_from_fatal_corpse(struct obj *obj, int tests) { - if (uarmg || obj->otyp != CORPSE - || !touch_petrifies(&mons[obj->corpsenm]) || Stone_resistance) + if (((tests & 1) && uarmg) + || ((tests & 2) && obj->otyp != CORPSE) + || ((tests & 4) && !touch_petrifies(&mons[obj->corpsenm])) + || ((tests & 8) && Stone_resistance)) return TRUE; return FALSE; } @@ -274,7 +283,7 @@ u_safe_from_fatal_corpse(struct obj *obj) staticfn boolean fatal_corpse_mistake(struct obj *obj, boolean remotely) { - if (u_safe_from_fatal_corpse(obj) || remotely) + if (u_safe_from_fatal_corpse(obj, 0xF) || remotely) return FALSE; if (poly_when_stoned(gy.youmonst.data) && polymon(PM_STONE_GOLEM)) { diff --git a/src/zap.c b/src/zap.c index 78baab25e..b25b80681 100644 --- a/src/zap.c +++ b/src/zap.c @@ -6189,7 +6189,7 @@ makewish(void) /* TODO? maybe generate a second event describing what was received since these just echo player's request rather than show actual result */ - if (otmp->otyp == CORPSE && !u_safe_from_fatal_corpse(otmp)) + if (otmp->otyp == CORPSE && !u_safe_from_fatal_corpse(otmp, 0xF)) otmp->wishedfor = 1; const char *verb = ((Is_airlevel(&u.uz) || u.uinwater) From e23095a8293220231e7fd16ca4e791793f4c674f Mon Sep 17 00:00:00 2001 From: SHIRAKATA Kentaro Date: Sun, 10 Nov 2024 22:46:31 +0900 Subject: [PATCH 056/791] omit return value of offer_corpse(), as it is always ECMD_TIME --- src/pray.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/pray.c b/src/pray.c index 99faf3bfa..efd934cc9 100644 --- a/src/pray.c +++ b/src/pray.c @@ -29,7 +29,7 @@ staticfn void offer_different_alignment_altar(struct obj *, aligntyp); staticfn void sacrifice_your_race(struct obj *, boolean, aligntyp); staticfn int bestow_artifact(void); staticfn int sacrifice_value(struct obj *); -staticfn int offer_corpse(struct obj *, boolean, aligntyp); +staticfn void offer_corpse(struct obj *, boolean, aligntyp); staticfn boolean pray_revive(void); staticfn boolean water_prayer(boolean); staticfn boolean blocked_boulder(int, int); @@ -1866,14 +1866,15 @@ dosacrifice(void) } /* fake Amulet */ if (otmp->otyp == CORPSE) { - return offer_corpse(otmp, highaltar, altaralign); + offer_corpse(otmp, highaltar, altaralign); + return ECMD_TIME; } pline1(nothing_happens); return ECMD_TIME; } -staticfn int +staticfn void offer_corpse(struct obj *otmp, boolean highaltar, aligntyp altaralign) { int value; @@ -1904,7 +1905,7 @@ offer_corpse(struct obj *otmp, boolean highaltar, aligntyp altaralign) */ feel_cockatrice(otmp, TRUE); if (rider_corpse_revival(otmp, FALSE)) - return ECMD_TIME; + return; value = sacrifice_value(otmp); @@ -1912,7 +1913,7 @@ offer_corpse(struct obj *otmp, boolean highaltar, aligntyp altaralign) too old (value==0) */ if (your_race(ptr)) { sacrifice_your_race(otmp, highaltar, altaralign); - return ECMD_TIME; + return; } else if (has_omonst(otmp) && (mtmp = get_mtraits(otmp, FALSE)) != 0 && mtmp->mtame) { @@ -1922,11 +1923,11 @@ offer_corpse(struct obj *otmp, boolean highaltar, aligntyp altaralign) adjalign(-3); HAggravate_monster |= FROMOUTSIDE; offer_negative_valued(highaltar, altaralign); - return ECMD_TIME; + return; } else if (!value) { /* too old; don't give undead or unicorn bonus or penalty */ pline1(nothing_happens); - return ECMD_TIME; + return; } else if (is_undead(ptr)) { /* Not demons--no demon corpses */ /* most undead that leave a corpse yield 'human' (or other race) corpse so won't get here; the exception is wraith; give the @@ -1947,7 +1948,7 @@ offer_corpse(struct obj *otmp, boolean highaltar, aligntyp altaralign) : unicalign ? "law" : "balance"); (void) adjattrib(A_WIS, -1, TRUE); offer_negative_valued(highaltar, altaralign); - return ECMD_TIME; + return; } else if (u.ualign.type == altaralign) { /* When different from altar, and altar is same as yours, * it's a very good action. @@ -1978,7 +1979,7 @@ offer_corpse(struct obj *otmp, boolean highaltar, aligntyp altaralign) } else if (u.ualign.type != altaralign) { /* Sacrificing at an altar of a different alignment */ offer_different_alignment_altar(otmp, altaralign); - return ECMD_TIME; + return; } else { int saved_anger = u.ugangr; int saved_cnt = u.ublesscnt; @@ -2043,7 +2044,7 @@ offer_corpse(struct obj *otmp, boolean highaltar, aligntyp altaralign) } } else { if (bestow_artifact()) - return ECMD_TIME; + return; change_luck((value * LUCKMAX) / (MAXVALUE * 2)); if ((int) u.uluck < 0) u.uluck = 0; @@ -2059,7 +2060,6 @@ offer_corpse(struct obj *otmp, boolean highaltar, aligntyp altaralign) } } } - return ECMD_TIME; } /* determine prayer results in advance; also used for enlightenment */ From c87a373b11d00b218b608198dda6b5d43edad9be Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 10 Nov 2024 10:06:07 -0500 Subject: [PATCH 057/791] more follow-up related to #1320 --- include/hack.h | 8 ++++++++ src/do.c | 4 ++-- src/do_wear.c | 7 +++++-- src/invent.c | 2 +- src/pickup.c | 19 ++++++++++--------- src/zap.c | 2 +- 6 files changed, 27 insertions(+), 15 deletions(-) diff --git a/include/hack.h b/include/hack.h index 088007784..0851da3ef 100644 --- a/include/hack.h +++ b/include/hack.h @@ -859,6 +859,14 @@ typedef struct strbuf { char buf[256]; } strbuf_t; +enum stoning_checks { + st_gloves = 0x1, /* wearing gloves? */ + st_corpse = 0x2, /* is it a corpse obj? */ + st_petrifies = 0x4, /* does the corpse petrify on touch? */ + st_resists = 0x8, /* do you have stoning resistance? */ + st_all = (st_gloves | st_corpse | st_petrifies | st_resists) +}; + struct trapinfo { struct obj *tobj; coordxy tx, ty; diff --git a/src/do.c b/src/do.c index 204643522..2fcf6bd40 100644 --- a/src/do.c +++ b/src/do.c @@ -941,10 +941,10 @@ better_not_try_to_drop_that(struct obj *otmp) { char buf[BUFSZ]; - /* u_safe_from_fatal_corpse() with 0xF checks for gloves and stoning + /* u_safe_from_fatal_corpse() with st_all checks for gloves and stoning * resistance before bothering to prompt you. */ - if (otmp->otyp == CORPSE && !u_safe_from_fatal_corpse(otmp, 0xF)) { + if (otmp->otyp == CORPSE && !u_safe_from_fatal_corpse(otmp, st_all)) { Snprintf( buf, sizeof buf, "Drop the %s corpse without any protection while handling it?", diff --git a/src/do_wear.c b/src/do_wear.c index d6aac2a60..652c13868 100644 --- a/src/do_wear.c +++ b/src/do_wear.c @@ -2895,12 +2895,15 @@ better_not_take_that_off(struct obj *otmp) struct obj *corpse = carrying_stoning_corpse(); char buf[BUFSZ]; - /* u_safe_from_fatal_corpse() with 0x4e instead of 0x6 + /* u_safe_from_fatal_corpse() with + (st_corpse | st_petrifies | st_resists) instead of + (st_corpse | st_petrifies) would also check for no stoning resistance before bothering to prompt, but losing stoning resistance later, without the gloves on could prove dangerous, so we won't factor that in */ - if (corpse && !u_safe_from_fatal_corpse(corpse, 0x6)) { + if (corpse + && !u_safe_from_fatal_corpse(corpse, st_corpse | st_petrifies)) { Snprintf(buf, sizeof buf, "Take off your %s despite carrying a dead %s?", gloves_simple_name(otmp), obj_pmname(corpse)); diff --git a/src/invent.c b/src/invent.c index fb137aabf..cf5d7e378 100644 --- a/src/invent.c +++ b/src/invent.c @@ -1232,7 +1232,7 @@ hold_another_object( obj = addinv_core0(obj, (struct obj *) 0, FALSE); goto drop_it; } else if (obj->otyp == CORPSE - && !u_safe_from_fatal_corpse(obj, 0xF) + && !u_safe_from_fatal_corpse(obj, st_all) && obj->wishedfor) { obj->wishedfor = 0; obj = addinv_core0(obj, (struct obj *) 0, FALSE); diff --git a/src/pickup.c b/src/pickup.c index 48fe61c18..df8896fe4 100644 --- a/src/pickup.c +++ b/src/pickup.c @@ -263,18 +263,19 @@ query_classes( /* * tests: - * 1 = gloves - * 2 = is_corpse - * 4 = does corpse petrify - * 8 = stone resistance + * st_gloves wearing gloves? + * st_corpse is it a corpse obj? + * st_petrifies does the corpse petrify on touch? + * st_resists does hero have stoning resistance? + * st_all st_gloves | st_corpse | st_petrifies | st_resists */ boolean u_safe_from_fatal_corpse(struct obj *obj, int tests) { - if (((tests & 1) && uarmg) - || ((tests & 2) && obj->otyp != CORPSE) - || ((tests & 4) && !touch_petrifies(&mons[obj->corpsenm])) - || ((tests & 8) && Stone_resistance)) + if (((tests & st_gloves) && uarmg) + || ((tests & st_corpse) && obj->otyp != CORPSE) + || ((tests & st_petrifies) && !touch_petrifies(&mons[obj->corpsenm])) + || ((tests & st_resists) && Stone_resistance)) return TRUE; return FALSE; } @@ -283,7 +284,7 @@ u_safe_from_fatal_corpse(struct obj *obj, int tests) staticfn boolean fatal_corpse_mistake(struct obj *obj, boolean remotely) { - if (u_safe_from_fatal_corpse(obj, 0xF) || remotely) + if (u_safe_from_fatal_corpse(obj, st_all) || remotely) return FALSE; if (poly_when_stoned(gy.youmonst.data) && polymon(PM_STONE_GOLEM)) { diff --git a/src/zap.c b/src/zap.c index b25b80681..2748acd77 100644 --- a/src/zap.c +++ b/src/zap.c @@ -6189,7 +6189,7 @@ makewish(void) /* TODO? maybe generate a second event describing what was received since these just echo player's request rather than show actual result */ - if (otmp->otyp == CORPSE && !u_safe_from_fatal_corpse(otmp, 0xF)) + if (otmp->otyp == CORPSE && !u_safe_from_fatal_corpse(otmp, st_all)) otmp->wishedfor = 1; const char *verb = ((Is_airlevel(&u.uz) || u.uinwater) From bbcd161e5ffd586c92cc76b4e24089ee81b85e26 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 10 Nov 2024 10:19:58 -0500 Subject: [PATCH 058/791] follow-up: prompt message bit --- src/do.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/do.c b/src/do.c index 2fcf6bd40..b3feccec2 100644 --- a/src/do.c +++ b/src/do.c @@ -947,8 +947,8 @@ better_not_try_to_drop_that(struct obj *otmp) if (otmp->otyp == CORPSE && !u_safe_from_fatal_corpse(otmp, st_all)) { Snprintf( buf, sizeof buf, - "Drop the %s corpse without any protection while handling it?", - obj_pmname(otmp)); + "Drop the %s corpse without %s protection on?", + obj_pmname(otmp), body_part(HAND)); return (paranoid_ynq(TRUE, buf, FALSE) != 'y'); } return FALSE; From 9a7dcf16a37e976f3cef54b9b808a483ef8f0acb Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 10 Nov 2024 17:49:54 -0500 Subject: [PATCH 059/791] rm.h comment update --- include/rm.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/rm.h b/include/rm.h index 060a1c22f..5cc7546b6 100644 --- a/include/rm.h +++ b/include/rm.h @@ -166,10 +166,12 @@ struct rm { * | 0x10 | 0x8 | 0x4 | 0x2 | 0x1 | * +-------------+-------------+------------+------------+------------+ * door |D_TRAPPED | D_LOCKED | D_CLOSED | D_ISOPEN | D_BROKEN | + * |D_WARNED | | | | | * drawbr. |DB_FLOOR | DB_ICE | DB_LAVA | DB_DIR | DB_DIR | * wall |W_NONPASSWALL|W_NONDIGGABLE| W_MASK | W_MASK | W_MASK | * sink | | | S_LRING | S_LDWASHER | S_LPUDDING | * tree | | | | TREE_SWARM | TREE_LOOTED| + * throne | | | | | T_LOOTED | * fountain| | | | F_WARNED | F_LOOTED | * ladder | | | | LA_DOWN | LA_UP | * pool |ICED_MOAT | ICED_POOL | | | | From d428beb8ddc3c9617a6c9766ad89877a961bf036 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 10 Nov 2024 17:58:04 -0500 Subject: [PATCH 060/791] remove an unused prototype --- src/invent.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/invent.c b/src/invent.c index cf5d7e378..1e375fc66 100644 --- a/src/invent.c +++ b/src/invent.c @@ -49,7 +49,6 @@ staticfn void ia_addmenu(winid, int, char, const char *); staticfn void itemactions_pushkeys(struct obj *, int); staticfn int itemactions(struct obj *); staticfn int dispinv_with_action(char *, boolean, const char *); -staticfn struct obj *carrying_cockatrice_corpse(void); /* enum and structs are defined in wintype.h */ static win_request_info wri_info; From e83e04dbb3300e73e29870c3a4348356e2304481 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 10 Nov 2024 22:24:45 -0500 Subject: [PATCH 061/791] fix some memory leaks --- include/extern.h | 1 + src/options.c | 40 ++++++++++++++++++++++++++++++-------- src/save.c | 5 +++++ sys/windows/Makefile.nmake | 4 +++- sys/windows/consoletty.c | 38 ++++++++++++++++++++++++++++++++++-- win/share/safeproc.c | 27 ++++++++++++++++++++++++- 6 files changed, 103 insertions(+), 12 deletions(-) diff --git a/include/extern.h b/include/extern.h index d4abee992..81c52e11d 100644 --- a/include/extern.h +++ b/include/extern.h @@ -2255,6 +2255,7 @@ extern boolean msgtype_parse_add(char *) NONNULLARG1; extern int msgtype_type(const char *, boolean) NONNULLARG1; extern void hide_unhide_msgtypes(boolean, int); extern void msgtype_free(void); +extern void options_free_window_colors(void); /* ### pager.c ### */ diff --git a/src/options.c b/src/options.c index 769f0d840..e9da50d52 100644 --- a/src/options.c +++ b/src/options.c @@ -3451,6 +3451,9 @@ optfn_roguesymset( } if (req == do_set) { if (op != empty_optstr) { + if (gs.symset[ROGUESET].name) + free((genericptr_t) gs.symset[ROGUESET].name), + gs.symset[ROGUESET].name = 0; gs.symset[ROGUESET].name = dupstr(op); if (!read_sym_file(ROGUESET)) { clear_symsetentry(ROGUESET, TRUE); @@ -4066,6 +4069,9 @@ optfn_symset( } if (req == do_set) { if (op != empty_optstr) { + if (gs.symset[PRIMARYSET].name) + free((genericptr_t) gs.symset[PRIMARYSET].name), + gs.symset[PRIMARYSET].name = 0; gs.symset[PRIMARYSET].name = dupstr(op); if (!read_sym_file(PRIMARYSET)) { clear_symsetentry(PRIMARYSET, TRUE); @@ -9821,6 +9827,16 @@ wc_set_font_name(int opttype, char *fontname) return; } +static char **fgp[] = { &iflags.wcolors[wcolor_menu].fg, + &iflags.wcolors[wcolor_message].fg, + &iflags.wcolors[wcolor_status].fg, + &iflags.wcolors[wcolor_text].fg }; +static char **bgp[] = { &iflags.wcolors[wcolor_menu].bg, + &iflags.wcolors[wcolor_message].bg, + &iflags.wcolors[wcolor_status].bg, + &iflags.wcolors[wcolor_text].bg }; +int options_set_window_colors_flag = 0; + staticfn int wc_set_window_colors(char *op) { @@ -9828,14 +9844,7 @@ wc_set_window_colors(char *op) * menu white/black message green/yellow status white/blue text * white/black */ - static char **fgp[] = { &iflags.wcolors[wcolor_menu].fg, - &iflags.wcolors[wcolor_message].fg, - &iflags.wcolors[wcolor_status].fg, - &iflags.wcolors[wcolor_text].fg }; - static char **bgp[] = { &iflags.wcolors[wcolor_menu].bg, - &iflags.wcolors[wcolor_message].bg, - &iflags.wcolors[wcolor_status].bg, - &iflags.wcolors[wcolor_text].bg }; + int j; int32 clr; char buf[BUFSZ]; @@ -9917,9 +9926,24 @@ wc_set_window_colors(char *op) wn); } } + options_set_window_colors_flag = 1; return 1; } +void +options_free_window_colors(void) +{ + int j; + + for (j = 0; j < WC_COUNT; ++j) { + if (*fgp[j]) + free((genericptr_t) *fgp[j]), *fgp[j] = 0; + if (*bgp[j]) + free((genericptr_t) *bgp[j]), *bgp[j] = 0; + } + options_set_window_colors_flag = 0; +} + /* set up for wizard mode if player or save file has requested it; called from port-specific startup code to handle `nethack -D' or OPTIONS=playmode:debug, or from dorecover()'s restgamestate() if diff --git a/src/save.c b/src/save.c index 509e3c437..b98194da7 100644 --- a/src/save.c +++ b/src/save.c @@ -1177,6 +1177,8 @@ free_dungeons(void) return; } +extern int options_set_window_colors_flag; /* options.c */ + /* free a lot of allocated memory which is ordinarily freed during save */ void freedynamicdata(void) @@ -1272,6 +1274,9 @@ freedynamicdata(void) if (VIA_WINDOWPORT()) status_finish(); + if (options_set_window_colors_flag) + options_free_window_colors(); + /* last, because it frees data that might be used by panic() to provide feedback to the user; conceivably other freeing might trigger panic */ sysopt_release(); /* SYSCF strings */ diff --git a/sys/windows/Makefile.nmake b/sys/windows/Makefile.nmake index b763e7858..2104b0afc 100644 --- a/sys/windows/Makefile.nmake +++ b/sys/windows/Makefile.nmake @@ -1972,12 +1972,14 @@ $(SRC)\tiles.bmp: $(U)tile2bmp.exe $(TILEFILES) @echo Creating 16x16 binary tile files (this may take some time) @$(U)tile2bmp $@ -$(U)tile2bmp.exe: $(OUTL)tile2bmp.o $(TEXT_IO) +$(U)tile2bmp.exe: $(OUTL)tile2bmp.o $(TEXT_IO) $(OUTL)alloc.o $(OUTL)panic.o @echo Linking $(@:\=/) @$(link) $(LFLAGS) /PDB:"$(OUTL)$(@B).PDB" /MAP:"$(OUTL)$(@B).MAP" $(OUTLHACKLIB) -out:$@ @<<$(@B).lnk $(OUTL)tile2bmp.o $(TEXT_IO:^ =^ ) + $(OUTL)alloc.o + $(OUTL)panic.o << $(U)til2bm32.exe: $(OUTL)til2bm32.o $(TEXT_IO32) diff --git a/sys/windows/consoletty.c b/sys/windows/consoletty.c index d88cb0881..be382fdd2 100644 --- a/sys/windows/consoletty.c +++ b/sys/windows/consoletty.c @@ -145,6 +145,9 @@ extern void (*ibmgraphics_mode_callback)(void); /* symbols.c */ extern void (*utf8graphics_mode_callback)(void); /* symbols.c */ #endif /* VIRTUAL_TERMINAL_SEQUENCES */ +static void init_custom_colors(void); +static void free_custom_colors(void); + /* Win32 Screen buffer,coordinate,console I/O information */ COORD ntcoord; INPUT_RECORD ir; @@ -317,8 +320,8 @@ WHITE 255,255,255 242,242,242 #ifdef VIRTUAL_TERMINAL_SEQUENCES long customcolors[CLR_MAX]; -const char *esc_seq_colors[CLR_MAX]; -const char *esc_seq_bkcolors[CLR_MAX]; +const char *esc_seq_colors[CLR_MAX] = { 0 }; +const char *esc_seq_bkcolors[CLR_MAX] = { 0 }; struct rgbvalues { int idx; @@ -551,6 +554,32 @@ init_custom_colors(void) esc_seq_bkcolors[CLR_BRIGHT_CYAN] = dupstr(bkcolorbuf); } +static void +free_custom_colors(void) +{ +#define CLR_FREE(c) \ + if (esc_seq_bkcolors[(c)] != 0) \ + free((genericptr_t) esc_seq_bkcolors[(c)]), esc_seq_bkcolors[(c)] = 0 + + CLR_FREE(CLR_BLACK); + CLR_FREE(CLR_RED); + CLR_FREE(CLR_GREEN); + CLR_FREE(CLR_YELLOW); + CLR_FREE(CLR_BLUE); + CLR_FREE(CLR_MAGENTA); + CLR_FREE(CLR_CYAN); + CLR_FREE(CLR_WHITE); + CLR_FREE(CLR_BROWN); + CLR_FREE(CLR_GRAY); + CLR_FREE(NO_COLOR); + CLR_FREE(CLR_ORANGE); + CLR_FREE(CLR_BRIGHT_GREEN); + CLR_FREE(CLR_BRIGHT_BLUE); + CLR_FREE(CLR_BRIGHT_MAGENTA); + CLR_FREE(CLR_BRIGHT_CYAN); +#undef CLR_FREE +} + void emit_start_bold(void); void emit_stop_bold(void); void emit_start_dim(void); @@ -1099,8 +1128,13 @@ consoletty_open(int mode) void consoletty_exit(void) { + /* frees some status tracking data */ + genl_status_finish(); /* go back to using the safe routines */ safe_routines(); + free_custom_colors(); + free((genericptr_t) console.localestr); + free((genericptr_t) console.orig_localestr); } int diff --git a/win/share/safeproc.c b/win/share/safeproc.c index 32dec1a5b..2862117ff 100644 --- a/win/share/safeproc.c +++ b/win/share/safeproc.c @@ -66,7 +66,32 @@ */ struct window_procs safe_procs = { - WPID(safestartup), 0L, 0L, + WPID(safestartup), + (0 +#ifdef TTY_PERM_INVENT + | WC_PERM_INVENT +#endif +#ifdef MSDOS + | WC_TILED_MAP | WC_ASCII_MAP +#endif +#if defined(WIN32CON) + | WC_MOUSE_SUPPORT +#endif + | WC_COLOR | WC_HILITE_PET | WC_INVERSE | WC_EIGHT_BIT_IN), + (0 +#if defined(SELECTSAVED) + | WC2_SELECTSAVED +#endif +#if defined(STATUS_HILITES) + | WC2_HILITE_STATUS | WC2_HITPOINTBAR | WC2_FLUSH_STATUS + | WC2_RESET_STATUS +#endif + | WC2_DARKGRAY | WC2_SUPPRESS_HIST | WC2_URGENT_MESG | WC2_STATUSLINES + | WC2_U_UTF8STR | WC2_PETATTR +#if !defined(NO_TERMS) || defined(WIN32CON) + | WC2_EXTRACOLORS +#endif + ), {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, /* color availability */ safe_init_nhwindows, safe_player_selection, safe_askname, safe_get_nh_event, From 93072b87841fec8a144c88020f02b54da6d99392 Mon Sep 17 00:00:00 2001 From: SHIRAKATA Kentaro Date: Mon, 11 Nov 2024 14:14:08 +0900 Subject: [PATCH 062/791] shrink scopes of some vars on offer_corpse() --- src/pray.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/pray.c b/src/pray.c index efd934cc9..b48dff609 100644 --- a/src/pray.c +++ b/src/pray.c @@ -1981,13 +1981,10 @@ offer_corpse(struct obj *otmp, boolean highaltar, aligntyp altaralign) offer_different_alignment_altar(otmp, altaralign); return; } else { - int saved_anger = u.ugangr; - int saved_cnt = u.ublesscnt; - int saved_luck = u.uluck; - consume_offering(otmp); /* OK, you get brownie points. */ if (u.ugangr) { + int saved_anger = u.ugangr; u.ugangr -= ((value * (u.ualign.type == A_CHAOTIC ? 2 : 3)) / MAXVALUE); if (u.ugangr < 0) @@ -2021,6 +2018,7 @@ offer_corpse(struct obj *otmp, boolean highaltar, aligntyp altaralign) adjalign(value); You_feel("partially absolved."); } else if (u.ublesscnt > 0) { + int saved_cnt = u.ublesscnt; u.ublesscnt -= ((value * (u.ualign.type == A_CHAOTIC ? 500 : 300)) / MAXVALUE); if (u.ublesscnt < 0) @@ -2043,6 +2041,7 @@ offer_corpse(struct obj *otmp, boolean highaltar, aligntyp altaralign) } } } else { + int saved_luck = u.uluck; if (bestow_artifact()) return; change_luck((value * LUCKMAX) / (MAXVALUE * 2)); From 36e8d9e6fc4a2fc7aa45546d594b8b19b09c8343 Mon Sep 17 00:00:00 2001 From: nhkeni Date: Mon, 7 Oct 2024 13:45:35 -0400 Subject: [PATCH 063/791] nhgitset version 4 To update, run "perl DEVEL/nhgitset.pl" Fixes: - "nhcommit -a" has been fixed - NHDT was hardwired in places - no longer complain about a missing dat directory outside of the NetHack source tree - make update of gitinfo atomic - Replace some hardwired directory separators with OS-dependent constructs Backwards Incompatibilities: - NH_DATESUB's DATE() is now Date() to match the other variables - MSYS2 requires an additional Perl package - the MSYS2 docs have been updated New Help System: - git nhhelp This command mirrors "git help" for nh* commands. - See git nhhelp nhsub for general help on substitution variables New Substitution Variables: -Brev() An aBREViation of $PREFIX-Branch$:$PREFIX-Revision$ - this may help get line length under control in file headers. -Assert(TYPE=VALUE) If TYPE does not match VALUE, do not substitute on this line. TYPE P checks VALUE against nethack.substprefix -Project(arg) Returns nethack.projectname if there is no arg and an uppercase version if arg is uc. Other New Features: - Add nethack.projectname - Documentation updates - see "git nhhelp nhsub" - On checkout or merge of a branch, check for nhgitset version updates and provide an optional message to the user. - Move NH_DATESUB substitutions here from cron job to keep dates in sync - PREFIX-* keywords now available in NH_DATESUB templates - Support use of nhgitset.pl from a different repo; note that update checks will be dependent on keeping the original source repo up-to-date and in the same location. --- DEVEL/Developer.txt | 9 +- DEVEL/VERSION | 40 ++ DEVEL/hooksdir/NHadd | 25 +- DEVEL/hooksdir/NHgithook.pm | 311 ++++++++--- DEVEL/hooksdir/NHsubst | 182 ++++--- DEVEL/hooksdir/NHtext | 8 +- DEVEL/hooksdir/nhhelp | 79 +++ DEVEL/hooksdir/nhsub | 879 +++++++++++++++++++----------- DEVEL/hooksdir/post-applypatch | 8 +- DEVEL/hooksdir/post-checkout | 9 +- DEVEL/hooksdir/post-commit | 11 +- DEVEL/hooksdir/post-merge | 9 +- DEVEL/hooksdir/post-rewrite | 6 +- DEVEL/hooksdir/pre-applypatch | 6 +- DEVEL/hooksdir/pre-auto-gc | 6 +- DEVEL/hooksdir/pre-commit | 6 +- DEVEL/hooksdir/pre-push | 6 +- DEVEL/hooksdir/pre-rebase | 6 +- DEVEL/hooksdir/prepare-commit-msg | 8 +- DEVEL/nhgitset.pl | 446 +++++++++------ doc/Guidebook.mn | 7 +- doc/Guidebook.tex | 2 +- doc/dlb.6 | 12 +- doc/makedefs.6 | 2 +- doc/nethack.6 | 2 +- doc/recover.6 | 2 +- sys/windows/build-msys2.txt | 2 + 27 files changed, 1412 insertions(+), 677 deletions(-) create mode 100644 DEVEL/VERSION create mode 100644 DEVEL/hooksdir/nhhelp diff --git a/DEVEL/Developer.txt b/DEVEL/Developer.txt index c7d7683c9..f43f88f43 100644 --- a/DEVEL/Developer.txt +++ b/DEVEL/Developer.txt @@ -92,10 +92,11 @@ B. Specify the prefix for variable substitution: tree you cloned from git. I use ~/nethack/GITADDDIR; for that base, create the needed directories and edit the file: ~/nethack/GITADDDIR/DOTGIT/PRE - Put this in it (if your OS is not Unix-like you may need to change - the first line): + Put this in it, adapting it to your variant (if your OS is not Unix-like + you may need to change the first line): #!/bin/sh git config nethack.substprefix MINE + git config nethack.projectname MineHack Now make it executable: chmod +x ~/nethack/GITADDDIR/DOTGIT/PRE C. Configure the repository: @@ -169,8 +170,8 @@ A. Introduction The PREFIX is the value in the git config variable nethack.substprefix. VARNAME is one of: Date - Branch (experimental) - Revision (experimental) + Branch + Revision other names will give a warning. B. Enabling variable expansion diff --git a/DEVEL/VERSION b/DEVEL/VERSION new file mode 100644 index 000000000..01a759d53 --- /dev/null +++ b/DEVEL/VERSION @@ -0,0 +1,40 @@ +4 +Fixes: +- "nhcommit -a" has been fixed +- NHDT was hardwired in places +- no longer complain about a missing dat directory outside of the + NetHack source tree +- make update of gitinfo atomic +- Replace some hardwired directory separators with OS-dependent constructs + +Backwards Incompatibilities: +- NH_DATESUB's DATE() is now Date() to match the other variables +- MSYS2 requires an additional Perl package - the MSYS2 docs have + been updated + +New Help System: +- git nhhelp + This command mirrors "git help" for nh* commands. +- See git nhhelp nhsub for general help on substitution variables + +New Substitution Variables: +-Brev() + An aBREViation of $PREFIX-Branch$:$PREFIX-Revision$ - this + may help get line length under control in file headers. +-Assert(TYPE=VALUE) + If TYPE does not match VALUE, do not substitute on this line. + TYPE P checks VALUE against nethack.substprefix +-Project(arg) + Returns nethack.projectname if there is no arg and an uppercase + version if arg is uc. + +Other New Features: +- Add nethack.projectname +- Documentation updates - see "git nhhelp nhsub" +- On checkout or merge of a branch, check for nhgitset version updates +- Move NH_DATESUB substitutions here from cron job to keep dates in sync +- PREFIX-* keywords now available in NH_DATESUB templates +- Support use of nhgitset.pl from a different repo; note that update + checks will be dependent on keeping the original source repo up-to-date + and in the same location. + diff --git a/DEVEL/hooksdir/NHadd b/DEVEL/hooksdir/NHadd index c4d6e547d..f4386c81d 100644 --- a/DEVEL/hooksdir/NHadd +++ b/DEVEL/hooksdir/NHadd @@ -12,11 +12,32 @@ die "Bad subcommand '$ARGV[0]'" unless $ok{$ARGV[0]}; # we won't fail on a failure, so just system() $rv = system('.git/hooks/nhsub',"--$ARGV[0]",@ARGV[1..$#ARGV]); if($rv){ - print "warning: nhsub failed: $rv $!\n"; + print "warning: nhsub failed: $rv $!\n"; } if(length $ENV{GIT_PREFIX}){ - chdir($ENV{GIT_PREFIX}) or die "Can't chdir $ENV{GIT_PREFIX}: $!"; + chdir($ENV{GIT_PREFIX}) or die "Can't chdir $ENV{GIT_PREFIX}: $!"; } exec "git", @ARGV or die "Can't exec git: $!"; + +__END__ +=for nhgitset nhadd Add file contents to the index with NetHack additions +=for nhgitset nhcommit Record changes to the repository with NetHack additions + +=head1 NAME + +C - NetHack internal common code for nhadd and nhcommit + +=head1 SYNOPSIS + +Cgit add optionsE> + +Cgit add optionsE> + +=head1 DESCRIPTION + +Run nhsub with the given arguments, then run C or C +with the given arguments. Note that only basic arguments for those commands +are understood; more complex situations may be handled by running C +manually before running C or C. diff --git a/DEVEL/hooksdir/NHgithook.pm b/DEVEL/hooksdir/NHgithook.pm index c7c3456f5..3f52008c0 100644 --- a/DEVEL/hooksdir/NHgithook.pm +++ b/DEVEL/hooksdir/NHgithook.pm @@ -16,9 +16,11 @@ my $tracefile = "/tmp/nhgitt.$$"; # OS hackery my $DS = quotemeta('/'); +my $PDS = '/'; if ($^O eq "MSWin32") { $DS = quotemeta('\\'); + $PDS = '\\'; } our %saved_env; @@ -26,25 +28,23 @@ our @saved_argv; our $saved_input; sub saveSTDIN { - @saved_input = ; + @saved_input = ; - if($trace){ - print TRACE "STDIN:\n"; - print TRACE $saved_input; - print TRACE "ENDSTDIN\n"; - } + if($trace){ + print TRACE "STDIN:\n"; + print TRACE $saved_input; + print TRACE "ENDSTDIN\n"; + } - tie *STDIN, 'NHIO::STDIN', @saved_input; + tie *STDIN, 'NHIO::STDIN', @saved_input; } -# XXX this needs a re-write (don't tie and untie, just set NEXT=0) -# (the sensitive thing is @foo = ) sub resetSTDIN{ - my $x = tied(*STDIN); - my %x = %$x; - my $data = @$x{DATA}; - untie *STDIN; - tie *STDIN, 'NHIO::STDIN', $data; + my $x = tied(*STDIN); + my %x = %$x; + my $data = @$x{DATA}; + untie *STDIN; + tie *STDIN, 'NHIO::STDIN', $data; } # don't need this now @@ -55,21 +55,142 @@ sub resetSTDIN{ #} sub PRE { - &do_hook("PRE"); + &do_hook("PRE"); } sub POST { - &do_hook("POST"); + &do_hook("POST"); +} + +### +### versioning for nhgitset and friends +### + +# values of nethack.setupversion and DEVEL/VERSION: +# 1 is reserved for repos checked out before versioning was added +# 2 used clean/smudge filter, poorly +# 3 was first production version +# 4 added the version file and version checking; nhhelp, NH_DATESUB support, etc. + +sub version_in_devel { + # (1) check for a non-null nethack.setuppath - this handles + # any repo that has already been set up (but NOT checking + # out =v4 since nethack.setuppath will exist but + # DEVEL/VERSION will not). + # XXX if the source repo has been removed, we'll fall back to + # the third case - hopefully that's ok. + # XXX there's no way to recover from a missing source repo + # without editing .git/config. + my $path = `git config --local nethack.setuppath`; + chomp $path; + $path =~ s/DEVEL$//; # NOP if config not set + + # (2) else check the local directory; that will be correct for NHsource. + if(0 == length $path){ + $path = `git rev-parse --show-toplevel`; + chomp $path; + $path = '' unless(-d "$path${PDS}DEVEL"); + } + # (3) If that doesn't exist, check using the invocation path; that will be + # correct for other repos during nhgitset (but will also fail for + # checking out 3 over 4). + if(0 == length $path){ + # strip out "DEVEL" + $path = ($0 =~ m!^(.*)${PDS}DEVEL${PDS}.*?(*nla:DEVEL)!)[0]; + } + # Uh oh? + if(0==length($path) or (! -d "$path${PDS}DEVEL")){ + die "Can't locate DEVEL directory in '$path'."; + } + + # Handle checking out version <4 over version >=4. If + # this seems to be the situation, don't revert the code. + return 0 if(! -f "$path${PDS}DEVEL${PDS}VERSION"); + + my $version; + my $verfile = "$path${PDS}DEVEL${PDS}VERSION"; + open VERFH,"<",$verfile or die "xCan't open $verfile: $!"; + $version = 0+; + my $message = join('',); + close VERFH; + die "Valid version not found in $verfile" unless($version >= 4); + return ($version,$message) if($version > 0); + return 0; +} + +sub version_in_git { + my $vtemp = `git config --local --get nethack.setupversion`; + chomp($vtemp); + return $vtemp if($vtemp > 0); + return 0; +} + +sub version_set_git { + my $version_new = $_[0]; + + system("git config nethack.setupversion $version_new"); + if($?){ + die "Can't set nethack.setupversion $version_new: $?,$!\n"; + } } ### ### store githash and gitbranch in dat/gitinfo.txt ### +# CAUTION! This is run not just from git hooks, but also from +# sys/unix/gitinfo.sh sub nhversioning { use strict; use warnings; + # See if we're (probably) in a "git pull", in which case we need to + # check for upgrades. + my $check_upgrade = 1 if($_[0]); + + # Check for pre-v4 source repo. + my $is_sourcerepo; + { + chomp($is_sourcerepo = `git config --type=int --get nethack.is-sourcerepo`); + if(0 == length $is_sourcerepo){ # not set - assume old repo + $is_sourcerepo = 1; + }elsif($is_sourcerepo==1){ + ; + }elsif($is_sourcerepo==0){ + ; + } + } + + # Skip the skipping tests if we're being called directly. + # NB: post-commit has no args, but that will be caught by + # the next test for non-source repos. + if($#ARGV != -1){ + # Skip this if we didn't change branches, but see if we need to warn. + if(defined($ARGV[2]) and ($ARGV[2] == 0)){ + # Because we can create an out of sync state, possibly warn. + my $ref = $ARGV[1]; + if($is_sourcerepo and (0 != 0+`git diff --name-only $ref $ref^ |grep ^DEVEL|wc -l`)){ + warn "WARNING: DEVEL directory changed. Versioning may be inconsistent\n"; + } + return + } + } + + if($check_upgrade){ + my $current_version = version_in_git(); + my($new_version,$message) = version_in_devel(); + if($new_version > $current_version){ + warn "nhgitset.pl and/or related programs have changed.\n"; + warn "Please re-run nhgitset.pl to update from version $current_version to $new_version.\n"; + if(length $message){ + warn "Additional information\n$message\n"; + } + } + } + + # Skip versioning if we aren't in a source repo. + return if(0==$is_sourcerepo); + my $git_sha = `git rev-parse HEAD`; $git_sha =~ s/\s+//g; my $git_branch = `git rev-parse --abbrev-ref HEAD`; @@ -77,7 +198,14 @@ sub nhversioning { die "git rev-parse failed" unless(length $git_sha and length $git_branch); my $exists = 0; - if (open my $fh, '<', 'dat/gitinfo.txt') { + no strict 'refs'; + no strict 'subs'; + my $file_gitinfo = "dat${PDS}gitinfo.txt"; + my $file_gittemp = "dat${PDS}TMPgitinfo.txt"; + use strict 'subs'; + use strict 'refs'; + + if (open my $fh, '<', $file_gitinfo) { $exists = 1; my $hashok = 0; my $branchok = 0; @@ -91,61 +219,71 @@ sub nhversioning { } close $fh; if ($hashok && $branchok) { - print "dat/gitinfo.txt unchanged, githash=".$git_sha."\n"; + print "$file_gitinfo unchanged, githash=".$git_sha."\n"; return; } } else { - print "WARNING: Can't find dat directory\n" unless(-d "dat"); + warn "WARNING: Can't find dat directory\n" unless(-d "dat"); + return; } - if (open my $fh, '>', 'dat/gitinfo.txt') { + if (open my $fh, '>', $file_gittemp) { my $how = ($exists ? "updated" : "created"); print $fh 'githash='.$git_sha."\n"; print $fh 'gitbranch='.$git_branch."\n"; - print "dat/gitinfo.txt ".$how.", githash=".$git_sha."\n"; + print "$file_gitinfo ".$how.", githash=".$git_sha."\n"; + if(close($fh)){ + if(rename($file_gittemp, $file_gitinfo)){ + ; # all ok + } else { + warn "WARNING: Can't rename $file_gittemp -> $file_gitinfo"; + } + } else { + warn "WARNING: Can't close temp file: $!"; + } } else { - print "WARNING: Unable to open dat/gitinfo.txt: $!\n"; + warn "WARNING: Unable to open $file_gitinfo: $!\n"; } } # PRIVATE sub do_hook { - my($p) = @_; - my $hname = $0; - $hname =~ s!^((.*$DS)|())(.*)!$1$p-$4!; - if(-x $hname){ - print TRACE "START $p: $hname\n" if($trace); + my($p) = @_; + my $hname = $0; + $hname =~ s!^((.*$DS)|())(.*)!$1$p-$4!; + if(-x $hname){ + print TRACE "START $p: $hname\n" if($trace); - open TOHOOK, "|-", $hname or die "open $hname: $!"; - print TOHOOK ; - close TOHOOK or die "close $hname: $! $?"; + open TOHOOK, "|-", $hname or die "open $hname: $!"; + print TOHOOK ; + close TOHOOK or die "close $hname: $! $?"; - print TRACE "END $p\n" if($trace); - } + print TRACE "END $p\n" if($trace); + } } sub trace_start { - return unless($trace); - my $self = shift; - open TRACE, ">>", $tracefile; - print TRACE "START CLIENT PID:$$ ARGV:\n"; - print TRACE "CWD: " . cwd() . "\n"; - print TRACE "[0] $0\n"; - my $x1; - for(my $x=0;$x $ENV{$k}\n"; - } + return unless($trace); + my $self = shift; + open TRACE, ">>", $tracefile; + print TRACE "START CLIENT PID:$$ ARGV:\n"; + print TRACE "CWD: " . cwd() . "\n"; + print TRACE "[0] $0\n"; + my $x1; + for(my $x=0;$x $ENV{$k}\n"; + } } BEGIN { - %saved_env = %ENV; - @saved_argv = @ARGV; - &trace_start; + %saved_env = %ENV; + @saved_argv = @ARGV; + &trace_start; } ### @@ -153,42 +291,41 @@ BEGIN { ### package NHIO::STDIN; sub TIEHANDLE { - my $class = shift; - my %fh; - # XXX yuck - if(ref @_[0]){ - $fh{DATA} = @_[0]; - } else { - $fh{DATA} = \@_; - } - $fh{NEXT} = 0; - return bless \%fh, $class; + my $class = shift; + my %fh; + if(ref @_[0]){ + $fh{DATA} = @_[0]; + } else { + $fh{DATA} = \@_; + } + $fh{NEXT} = 0; + return bless \%fh, $class; } sub READLINE { - my $self = shift; - return undef if($self->{EOF}); - if(wantarray){ - my $lim = $#{$self->{DATA}}; - my @ary = @{$self->{DATA}}[$self->{NEXT}..$lim]; - my @rv = @ary[$self->{NEXT}..$#ary]; - $self->{EOF} = 1; - return @rv; - } else{ - my $rv = $self->{DATA}[$self->{NEXT}]; - if(length $rv){ - $self->{NEXT}++; - return $rv; - } else { - $self->{EOF} = 1; - return undef; - } - } + my $self = shift; + return undef if($self->{EOF}); + if(wantarray){ + my $lim = $#{$self->{DATA}}; + my @ary = @{$self->{DATA}}[$self->{NEXT}..$lim]; + my @rv = @ary[$self->{NEXT}..$#ary]; + $self->{EOF} = 1; + return @rv; + } else{ + my $rv = $self->{DATA}[$self->{NEXT}]; + if(length $rv){ + $self->{NEXT}++; + return $rv; + } else { + $self->{EOF} = 1; + return undef; + } + } } sub EOF { - $self = shift; - return $self->{EOF}; + $self = shift; + return $self->{EOF}; } 1; @@ -223,11 +360,20 @@ NHgithook - common code for NetHack git hooks (and other git bits) (core hook code) &NHgithook::POST; +__END__ +=for nhgitset NHgithook Infrastructure for NetHack git hooks. + =head1 DESCRIPTION +Perl module for infrastructure of NetHack Git hooks. + Buffers call information so multiple independent actions may be coded for Git hooks and similar Git callouts. +Maintains C. + +Common routines for dealing with nethack.setupversion git config variable. + =head1 SETUP Changing the C<$trace> and C<$tracefile> variables requires editing the @@ -247,6 +393,9 @@ may be useful since multiple processes may be live at the same time. Some features not well tested, especially under Windows. +Not well documented, but almost no one needs to change (or even call) +this code. + =head1 AUTHOR Kenneth Lorber (keni@his.com) diff --git a/DEVEL/hooksdir/NHsubst b/DEVEL/hooksdir/NHsubst index 99621fc57..0c7aeb067 100755 --- a/DEVEL/hooksdir/NHsubst +++ b/DEVEL/hooksdir/NHsubst @@ -17,24 +17,24 @@ my $dbgfile = ($^O eq "MSWin32") ? "$ENV{TEMP}.$$" : "/tmp/trace.$$"; open TRACE, ">>", $rawin?"/dev/tty":(($debug==0)? $sink : $dbgfile); print TRACE "TEST TRACE\n"; if($debug){ - print TRACE "START CLIENT ARGV:\n"; - print TRACE "[0] $0\n"; - my $x1; - for(my $x=0;$x $ENV{$k}\n"; - } - print TRACE "CWD: " . `pwd`; - &dumpfile($ARGV[0], "[0O]"); - &dumpfile($ARGV[1], "[1A]"); - &dumpfile($ARGV[2], "[2B]"); - print TRACE "L=$ARGV[3]\n"; - print TRACE "END\n"; + print TRACE "START CLIENT ARGV:\n"; + print TRACE "[0] $0\n"; + my $x1; + for(my $x=0;$x $ENV{$k}\n"; + } + print TRACE "CWD: " . `pwd`; + &dumpfile($ARGV[0], "[0O]"); + &dumpfile($ARGV[1], "[1A]"); + &dumpfile($ARGV[2], "[2B]"); + print TRACE "L=$ARGV[3]\n"; + print TRACE "END\n"; } my $mark_len = $ARGV[3]; @@ -47,37 +47,37 @@ my $mark_end = '>' x $mark_len; my $PREFIX; # pick up the prefix for substitutions in this repo if($rawin){ - $PREFIX = "TEST"; + $PREFIX = "TEST"; } else { - $PREFIX = `git config --local --get nethack.substprefix`; - chomp($PREFIX); + $PREFIX = `git config --local --get nethack.substprefix`; + chomp($PREFIX); } my @out; my $cntout; if($rawin){ - @out = ; + @out = ; } else { - #system "git merge-file -p .... > temp - my $tags = "-L CURRENT -L ANCESTOR -L OTHER"; # XXX should "CURRENT" be "MINE"? - @out = `git merge-file -p $tags $ARGV[1] $ARGV[0] $ARGV[2]`; + #system "git merge-file -p .... > temp + my $tags = "-L CURRENT -L ANCESTOR -L OTHER"; # XXX should "CURRENT" be "MINE"? + @out = `git merge-file -p $tags $ARGV[1] $ARGV[0] $ARGV[2]`; #NB: we don't check the exit value because it's useless - print TRACE "MERGE-FILE START\n".join("",@out)."MERGE-FILE END\n"; + print TRACE "MERGE-FILE START\n".join("",@out)."MERGE-FILE END\n"; } ($cntout,@out) = &edit_merge(@out); if($rawin){ - print "COUNT: $cntout\n"; - print @out; + print "COUNT: $cntout\n"; + print @out; } else { - # spit @out to $ARGV[1] (careful: what about EOL character?) - open OUT, ">$ARGV[1]" or die "Can't open $ARGV[1]"; - print OUT @out; - close OUT; + # spit @out to $ARGV[1] (careful: what about EOL character?) + open OUT, ">$ARGV[1]" or die "Can't open $ARGV[1]"; + print OUT @out; + close OUT; - print TRACE "WRITING START ($ARGV[1])\n".join("",@out)."WRITING END\n"; - &dumpfile($ARGV[1], "READBACK"); + print TRACE "WRITING START ($ARGV[1])\n".join("",@out)."WRITING END\n"; + &dumpfile($ARGV[1], "READBACK"); } print TRACE "COUNT: $cntout\n"; @@ -95,37 +95,37 @@ exit( ($cntout>0) ? 1 : 0); # keep failing so we don't need to keep changing the setup while building this script sub dumpfile { - my($file, $tag) = @_; - print TRACE "FILE $tag START\n"; - print TRACE `hexdump -C $file`; - print TRACE "FILE END\n"; + my($file, $tag) = @_; + print TRACE "FILE $tag START\n"; + print TRACE `hexdump -C $file`; + print TRACE "FILE END\n"; } sub edit_merge { - my(@input) = @_; - # $::count is a bit ugly XXX - local $::count = 0; # we need the number of conflicts for exit() - my @out; + my(@input) = @_; + # $::count is a bit ugly XXX + local $::count = 0; # we need the number of conflicts for exit() + my @out; - local $_; - while($_ = shift @input){ - if(m/^$mark_start /){ - print TRACE "FOUND A CONFLICT\n"; - my @conflict; - push(@conflict, $_); - while($_ = shift @input){ - push(@conflict, $_); - if(m/^$mark_end /){ - last; - } - } - push(@out, &edit_conflict(@conflict)); - } else { - push(@out, $_); + local $_; + while($_ = shift @input){ + if(m/^$mark_start /){ + print TRACE "FOUND A CONFLICT\n"; + my @conflict; + push(@conflict, $_); + while($_ = shift @input){ + push(@conflict, $_); + if(m/^$mark_end /){ + last; } + } + push(@out, &edit_conflict(@conflict)); + } else { + push(@out, $_); } - print TRACE "RETURN count=$::count\n"; - return($::count, @out); + } + print TRACE "RETURN count=$::count\n"; + return($::count, @out); } sub edit_conflict { @@ -305,41 +305,41 @@ print TRACE "MVM: -$varname-$oursval-$theirval-\n"; package PREFIX; # Resolve the conflict of a single var's 2 values. Return undef to leave the conflict. sub Date { - my($PREFIX, $varname, $mine, $theirs) = @_; - my $m = ($mine =~ m/(\d+)/)[0]; - my $t = ($theirs =~ m/(\d+)/)[0]; - return undef unless ($m>0) && ($t>0); + my($PREFIX, $varname, $mine, $theirs) = @_; + my $m = ($mine =~ m/(\d+)/)[0]; + my $t = ($theirs =~ m/(\d+)/)[0]; + return undef unless ($m>0) && ($t>0); - return "\$$PREFIX-$varname: " . (($m>$t)?$mine:$theirs) .' $'; + return "\$$PREFIX-$varname: " . (($m>$t)?$mine:$theirs) .' $'; } #sub Header { #sub Author { sub Branch { - my($PREFIX, $varname, $mine, $theirs) = @_; - $mine =~ s/^\s+//; $mine =~ s/\s+$//; - $theirs =~ s/^\s+//; $theirs =~ s/\s+$//; - return "\$$PREFIX-$varname: $mine \$" if(length $mine); - return "\$$PREFIX-$varname: $theirs \$" if(length $theirs); - return "\$$PREFIX-$varname\$" if(length $theirs); + my($PREFIX, $varname, $mine, $theirs) = @_; + $mine =~ s/^\s+//; $mine =~ s/\s+$//; + $theirs =~ s/^\s+//; $theirs =~ s/\s+$//; + return "\$$PREFIX-$varname: $mine \$" if(length $mine); + return "\$$PREFIX-$varname: $theirs \$" if(length $theirs); + return "\$$PREFIX-$varname\$" if(length $theirs); } sub Revision { - my($PREFIX, $varname, $mine, $theirs) = @_; - my($m) = ($mine =~ m/1.(\d+)/); - my($t) = ($theirs =~ m/1.(\d+)/); - if($m > 0 && $t > 0){ - my $q = ($m > $t) ? $m : $t; - return "\$$PREFIX-$varname: 1.$q \$"; - } - if($m > 0){ - return "\$$PREFIX-$varname: 1.$m \$"; - } - if($t > 0){ - return "\$$PREFIX-$varname: 1.$t \$"; - } - return "\$$PREFIX-$varname\$"; + my($PREFIX, $varname, $mine, $theirs) = @_; + my($m) = ($mine =~ m/1.(\d+)/); + my($t) = ($theirs =~ m/1.(\d+)/); + if($m > 0 && $t > 0){ + my $q = ($m > $t) ? $m : $t; + return "\$$PREFIX-$varname: 1.$q \$"; + } + if($m > 0){ + return "\$$PREFIX-$varname: 1.$m \$"; + } + if($t > 0){ + return "\$$PREFIX-$varname: 1.$t \$"; + } + return "\$$PREFIX-$varname\$"; } __END__ @@ -396,3 +396,17 @@ TEST 8: === /* NetHack 3.7 objnam.c $TEST-Date: 1426977394 2015/03/21 22:36:34 $ $TEST-Branch: master $:$TEST-Revision: 1.108 $ */ >>> d3 + +=for nhgitset NHsubst NetHack merge driver + +=head1 NAME + +C - NetHack merge driver + +=head1 SYNOPSIS + +(called from C, do not invoke directly) + +=head1 DESCRIPTION + +This is invoked by git through .git/config. diff --git a/DEVEL/hooksdir/NHtext b/DEVEL/hooksdir/NHtext index 7128c0d31..01848675b 100755 --- a/DEVEL/hooksdir/NHtext +++ b/DEVEL/hooksdir/NHtext @@ -3,6 +3,8 @@ # Copyright (c) 2015 by Kenneth Lorber, Kensington, Maryland # NetHack may be freely redistributed. See license for details. +# Not in use as of v3, but could come back in the future. + # clean/smudge filter for handling substitutions use strict; @@ -54,9 +56,9 @@ if($ARGV[0] eq "--clean"){ exit 1; } -# XXX for now, there isn't any - if we get called, we subst. No options for now. +# XX for now, there isn't any - if we get called, we subst. No options for now. # get relevant config info -#XXX +#XX #git check-attr -a $ARGV[1] # Process stdin to stdout. @@ -109,7 +111,7 @@ sub Date { my($val, $mode, $submode) = @_; if($mode eq "c"){ if($submode==0){ - # we add this to make merge easier for now XXX + # we add this to make merge easier for now XX my $now = time; # not %s below - may not be portable # YYYY/MM/DD HH:MM:SS $val = "$now " . strftime("%Y/%m/%d %H:%M:%S", gmtime($now)); diff --git a/DEVEL/hooksdir/nhhelp b/DEVEL/hooksdir/nhhelp new file mode 100644 index 000000000..90fb7d68f --- /dev/null +++ b/DEVEL/hooksdir/nhhelp @@ -0,0 +1,79 @@ +#!/usr/bin/perl +# $NHDT-Date: 1730238507 2024/10/29 21:48:27 $ $NHDT-Brev: keni-gitset:1.0 $ +# Copyright (c) 2024 by Kenneth Lorber, Kensington, Maryland +# NetHack may be freely redistributed. See license for details. + +# This deals with a git problem: there is no way to do: +# git help alias-name +# (yes, that will show the definition of the alias, but not show an actual +# help document). +# +# So we implement this: +# nhhelp +# With no arguments, run perldoc on this file. +# nhhelp FOO +# Run perldoc on .git/hooks/FOO (if it exists). + +if($#ARGV == -1){ + system("perldoc $0")==0 or die "perldoc error: $!\n"; + exit 0; +} +if($#ARGV == 0){ + if($ARGV[0] eq "-a"){ + &listhelp; + exit 0; + } + + chomp(my $target = `git config nethack.aliashelp.$ARGV[0]`); + my $file = ".git/hooks/$target"; + if(-f $file){ + system("perldoc $file")==0 or die "perldoc error: $!\n"; + } else { + print "Unknown name '$ARGV[0]'\n"; + &usage; + } + exit 0; +} +&usage; +exit 0; + +sub usage { +print <|-a] +E_O_M +} + +sub listhelp { + print "nhhelp is available for:\n"; + my @namelist = `git config --name-only --get-regexp 'nethack.aliashelp.*'`; + print "NAMELIST $?\n" if($?); + @namelist = map { + if(m/^nethack.aliashelp.(.*)/){ + chomp(my $x = `git config 'nethack.aliasdesc.$1'`); + sprintf("%-12s %s",$1,$x); + } + } sort @namelist; + print " " . join("\n ", @namelist)."\n"; + exit 0; +} + +__END__ +=for nhgitset nhhelp Help on NetHack git commands + +=head1 NAME + +C - NetHack git command for help on NetHack git commands + +=head1 SYNOPSIS + +C + +=head1 DESCRIPTION + +With no arguments, print this message. + +With one argument matching a NetHack git command, print the +documentation for that command. + +With the argument C<-a>, show all available nhhelp topics with one line +summaries. diff --git a/DEVEL/hooksdir/nhsub b/DEVEL/hooksdir/nhsub index 7e5fdbd2f..7aa183b65 100644 --- a/DEVEL/hooksdir/nhsub +++ b/DEVEL/hooksdir/nhsub @@ -1,5 +1,5 @@ #!/usr/bin/perl -# $NHDT-Date: 1524689646 2018/04/25 20:54:06 $ Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.7 $ +# $NHDT-Date: 1524689646 2018/04/25 20:54:06 $ Branch: NetHack-3.7 $:$NHDT-Revision: 1.7 $ # Copyright (c) 2015 by Kenneth Lorber, Kensington, Maryland # NetHack may be freely redistributed. See license for details. @@ -8,9 +8,11 @@ use strict; our %opt; #cmd v n f F m (other single char, but we don't care) my $mode; # a c d f (add, commit, date, date -f) +our $count; +our $skip; if(length $ENV{GIT_PREFIX}){ - chdir($ENV{GIT_PREFIX}) or die "Can't chdir $ENV{GIT_PREFIX}: $!"; + chdir($ENV{GIT_PREFIX}) or die "Can't chdir $ENV{GIT_PREFIX}: $!"; } #SO how do we know if a file has changed? @@ -23,74 +25,78 @@ if(length $ENV{GIT_PREFIX}){ # (see "git help status" for table) # No default. Undef means something unexpected happened. my %codes = ( - 'f M'=>1, 'f D'=>1, # [MD] not updated - 'a M'=>0, 'a D'=>0, - 'd M'=>0, 'd D'=>0, - 'c M'=>0, 'c D'=>0, + # [MD] not updated + 'f M'=>1, 'f D'=>1, + 'a M'=>0, 'a D'=>0, + 'd M'=>0, 'd D'=>0, + 'c M'=>0, 'c D'=>0, - 'dM '=>0, 'dMM'=>1, 'dMD'=>0, - 'aM '=>0, 'aMM'=>1, 'aMD'=>0, - 'cM '=>0, 'cMM'=>1, 'cMD'=>0, - 'fM '=>0, 'fMM'=>1, 'fMD'=>0, - # M [ MD] updated in index + 'dM '=>0, 'dMM'=>1, 'dMD'=>0, + 'aM '=>0, 'aMM'=>1, 'aMD'=>0, + 'cM '=>0, 'cMM'=>1, 'cMD'=>0, + 'fM '=>0, 'fMM'=>1, 'fMD'=>0, + # M [ MD] updated in index - 'dA '=>1, 'dAM'=>1, 'dAD'=>1, - 'aA '=>1, 'aAM'=>1, 'aAD'=>1, - 'cA '=>1, 'cAM'=>1, 'cAD'=>1, - 'fA '=>1, 'fAM'=>1, 'fAD'=>1, - # A [ MD] added to index + 'dA '=>1, 'dAM'=>1, 'dAD'=>1, + 'aA '=>1, 'aAM'=>1, 'aAD'=>1, + 'cA '=>1, 'cAM'=>1, 'cAD'=>1, + 'fA '=>1, 'fAM'=>1, 'fAD'=>1, + # A [ MD] added to index - 'dD '=>0, 'dDM'=>0, - 'aD '=>1, 'aDM'=>1, - 'cD '=>0, 'cDM'=>0, - 'fD '=>1, 'fDM'=>1, - # D [ M] deleted from index + 'dD '=>0, 'dDM'=>0, + 'aD '=>1, 'aDM'=>1, + 'cD '=>0, 'cDM'=>0, + 'fD '=>1, 'fDM'=>1, + # D [ M] deleted from index - 'dR '=>0, 'dRM'=>1, 'dRD'=>0, - 'aR '=>0, 'aRM'=>1, 'aRD'=>0, - 'cR '=>0, 'cRM'=>1, 'cRD'=>0, - 'fR '=>0, 'fRM'=>1, 'fRD'=>0, - # R [ MD] renamed in index + 'dR '=>0, 'dRM'=>1, 'dRD'=>0, + 'aR '=>0, 'aRM'=>1, 'aRD'=>0, + 'cR '=>0, 'cRM'=>1, 'cRD'=>0, + 'fR '=>0, 'fRM'=>1, 'fRD'=>0, + # R [ MD] renamed in index - 'dC '=>0, 'dCM'=>1, 'dCD'=>0, - 'aC '=>0, 'aCM'=>1, 'aCD'=>0, - 'cC '=>0, 'cCM'=>1, 'cCD'=>0, - 'fC '=>0, 'fCM'=>1, 'fCD'=>0, - # C [ MD] copied in index + 'dC '=>0, 'dCM'=>1, 'dCD'=>0, + 'aC '=>0, 'aCM'=>1, 'aCD'=>0, + 'cC '=>0, 'cCM'=>1, 'cCD'=>0, + 'fC '=>0, 'fCM'=>1, 'fCD'=>0, + # C [ MD] copied in index - 'aM '=>1, 'aA '=>1, 'aR '=>1, 'aC '=>1, - 'fM '=>1, 'fA '=>1, 'fR '=>1, 'fC '=>1, - # [MARC] index and work tree matches + 'aM '=>1, 'aA '=>1, 'aR '=>1, 'aC '=>1, + 'fM '=>1, 'fA '=>1, 'fR '=>1, 'fC '=>1, + # [MARC] index and work tree matches - 'd M'=>1, 'dMM'=>1, 'dAM'=>1, 'dRM'=>1, 'dCM'=>1, - 'a M'=>1, 'aMM'=>1, 'aAM'=>1, 'aRM'=>1, 'aCM'=>1, - 'c M'=>1, 'cMM'=>1, 'cAM'=>1, 'cRM'=>1, 'cCM'=>1, - 'f M'=>1, 'fMM'=>1, 'fAM'=>1, 'fRM'=>1, 'fCM'=>1, - # [ MARC] M work tree changed since index + 'd M'=>1, 'dMM'=>1, 'dAM'=>1, 'dRM'=>1, 'dCM'=>1, + 'a M'=>1, 'aMM'=>1, 'aAM'=>1, 'aRM'=>1, 'aCM'=>1, + 'c M'=>1, 'cMM'=>1, 'cAM'=>1, 'cRM'=>1, 'cCM'=>1, + 'f M'=>1, 'fMM'=>1, 'fAM'=>1, 'fRM'=>1, 'fCM'=>1, + # [ MARC] M work tree changed since index - 'd D'=>0, 'dMD'=>0, 'dAD'=>0, 'dRD'=>0, 'dCD'=>0, - 'a D'=>0, 'aMD'=>0, 'aAD'=>0, 'aRD'=>0, 'aCD'=>0, - 'c D'=>0, 'cMD'=>0, 'cAD'=>0, 'cRD'=>0, 'cCD'=>0, - 'f D'=>0, 'fMD'=>0, 'fAD'=>0, 'fRD'=>0, 'fCD'=>0, - # [ MARC] D deleted in work tree + 'd D'=>0, 'dMD'=>0, 'dAD'=>0, 'dRD'=>0, 'dCD'=>0, + 'a D'=>0, 'aMD'=>0, 'aAD'=>0, 'aRD'=>0, 'aCD'=>0, + 'c D'=>0, 'cMD'=>0, 'cAD'=>0, 'cRD'=>0, 'cCD'=>0, + 'f D'=>0, 'fMD'=>0, 'fAD'=>0, 'fRD'=>0, 'fCD'=>0, + # [ MARC] D deleted in work tree - # ------------------------------------------------- - # DD unmerged, both deleted - # AU unmerged, added by us - # UD unmerged, deleted by them - # UA unmerged, added by them - # DU unmerged, deleted by us - # AA unmerged, both added - # UU unmerged, both modified - # ------------------------------------------------- - 'a??'=>1, 'f??'=>1, # ?? untracked - 'd??'=>0, 'c??'=>0, + # ------------------------------------------------- + # DD unmerged, both deleted + # AU unmerged, added by us + # UD unmerged, deleted by them + # UA unmerged, added by them + # DU unmerged, deleted by us + # AA unmerged, both added + # UU unmerged, both modified + # ------------------------------------------------- + # ?? untracked + 'a??'=>1, 'f??'=>1, + 'd??'=>0, 'c??'=>0, - 'f!!'=>1, # !! ignored - 'a!!'=>0, 'd!!'=>0, 'c!!'=>0, + # !! ignored + 'f!!'=>1, - 'f@@'=>1, # @@ internal ignored - 'a@@'=>0, 'd@@'=>0, 'c@@'=>0 + 'a!!'=>0, 'd!!'=>0, 'c!!'=>0, + + 'f@@'=>1, # @@ internal ignored + 'a@@'=>0, 'd@@'=>0, 'c@@'=>0 ); # OS hackery @@ -123,309 +129,430 @@ my @rawlist0 = &cmdparse(@ARGV); # Let's try this for all commands. my @rawlist; foreach my $e (@rawlist0){ - if($e =~ m/[?*[\\]/){ - my @rv = &lsfiles(undef, $e); - push(@rawlist, @rv) if(@rv); - if($opt{f}){ - my @rv = &lsfiles('-i', $e); - push(@rawlist, @rv) if(@rv); - } - } else { - push(@rawlist, $e); + if($e =~ m/[?*[\\]/){ + my @rv = &lsfiles(undef, $e); + push(@rawlist, @rv) if(@rv); + if($opt{f}){ + my @rv = &lsfiles('-i', $e); + push(@rawlist, @rv) if(@rv); } + } else { + push(@rawlist, $e); + } } push(@rawlist,'.') if($#rawlist == -1); # pick up the prefix for substitutions in this repo -#TEST my $PREFIX = &git_config('nethack','substprefix'); -my $PREFIX = "NHDT"; +my $PREFIX = &git_config('nethack','substprefix'); +die "nethack.substprefix not set in git config" unless(length($PREFIX) > 0); print "PREFIX: '$PREFIX'\n" if($opt{v}); while(@rawlist){ - my $raw = shift @rawlist; - if(-f $raw){ + my $raw = shift @rawlist; + if(-f $raw){ &schedule_work($raw); next; + } + if(-d $raw){ + if($raw =~ m!$PDS.git$!o){ + print "SKIP $raw\n" if($opt{v}>=2); + next; } - if(-d $raw){ - if($raw =~ m!$PDS.git$!o){ - print "SKIP $raw\n" if($opt{v}>=2); - next; - } - opendir RDIR,$raw or die "Can't opendir: $raw"; - local($_); # needed until perl 5.11.2 - while($_ = readdir RDIR){ - next if(m/^\.\.?$/); - if(m/^\./ && $opt{f}){ - print " IGNORE-f: $raw$PDS$_\n" if($opt{v}>=2); - next; - } - push(@rawlist, $raw.$PDS.$_); - } - closedir RDIR; + opendir RDIR,$raw or die "Can't opendir: $raw"; + local($_); # needed until perl 5.11.2 + while($_ = readdir RDIR){ + next if(m/^\.\.?$/); + if(m/^\./ && $opt{f}){ + print " IGNORE-f: $raw$PDS$_\n" if($opt{v}>=2); + next; + } + push(@rawlist, $raw.$PDS.$_); } + closedir RDIR; + } # ignore other file types - if(! -e $raw){ - print "warning: missing file $raw\n"; + if(! -e $raw){ + print "warning: missing file $raw\n"; + } +} + +sub checkattr { + my($kw, $file) = @_; + my $attr = `git check-attr $kw -- $file`; + if($attr =~ m/$kw:\s+(.*)/){ + # This is a bug in git. What if the value of an attribute is the + # string "unset"? Sigh. + if(! $opt{F}){ + if($1 eq "unset" || $1 eq "unspecified"){ + print " NOATTR: $attr" if($opt{v}>=2); + return 0; + } } + return 1; + } + return 0; } # XXX could batch things up - later - sub schedule_work { - my($file) = @_; - print "CHECK: '$file'\n" if($opt{v}>=2); - local($_) = `git status --porcelain --ignored -- $file`; - my $key = $mode . join('',(m/^(.)(.)/)); - if(length $key == 1){ + my($file) = @_; + print "CHECK: '$file'\n" if($opt{v}>=2); + local($_) = `git status --porcelain --ignored -- $file`; + my $key = $mode . join('',(m/^(.)(.)/)); + if(length $key == 1){ # Hack. An unmodified, tracked file produces no output from # git status. Treat as another version of 'ignored'. - $key .= '@@'; + $key .= '@@'; + } + $key =~ s/-/ /g; # for Keni's locally mod'ed git + if(!exists $codes{$key}){ + die "I'm lost.\nK='$key' F=$file\nST=$_"; + } + if($codes{$key}==0){ + if($opt{v}>=2){ + print " IGNORE: $_" if(length); + print " IGNORE: !! $file\n" if(!length); } - $key =~ s/-/ /g; # for Keni's locally mod'ed git - if(!exists $codes{$key}){ - die "I'm lost.\nK='$key' F=$file\nST=$_"; - } - if($codes{$key}==0){ - if($opt{v}>=2){ - print " IGNORE: $_" if(length); - print " IGNORE: !! $file\n" if(!length); - } + return; + } + if($opt{F}){ + my $ign = `git check-ignore $file`; + if($ign !~ m/^\s*$/){ + print " IGNORE-F: $ign" if($opt{v}>=2); return; - } - if($opt{F}){ - my $ign = `git check-ignore $file`; - if($ign !~ m/^\s*$/){ - print " IGNORE-F: $ign" if($opt{v}>=2); - return; - } - } -# FALLTHROUGH and continue -#print "ACCEPT TEST\n"; # XXXXXXXXXX TEST -#return; + } + } - my $attr = `git check-attr NHSUBST -- $file`; - if($attr =~ m/NHSUBST:\s+(.*)/){ -# XXX this is a bug in git. What if the value of an attribute is the -# string "unset"? Sigh. - if(! $opt{F}){ - if($1 eq "unset" || $1 eq "unspecified"){ - print " NOATTR: $attr" if($opt{v}>=2); - return; - } - } - &process_file($file); - return; - } - die "Can't parse check-attr return: $attr\n"; + my $do_nhsubst = &checkattr('NHSUBST', $file); + my $do_nhdatesub = &checkattr('NH_DATESUB', $file); + &process_file($file, $do_nhsubst, $do_nhdatesub); +# XXX no longer reachable - parse errors not caught properly? +# die "Can't parse check-attr return: $attr\n"; } sub process_file { - my($file) = @_; - print "DOFIL: $file\n" if($opt{v}>=1); + my($file, $do_nhsubst, $do_nhdatesub) = @_; + print "DOFIL: $file\n" if($opt{v}>=1); + $count=0; # if we don't change anything, don't re-write the file - # For speed we read in the entire file then do the substitutions. - local($_) = ''; - my $len; - open INFILE, "<", $file or die "Can't open $file: $!"; - while(1){ - # On at least some systems we only get 64K. - my $len = sysread(INFILE, $_, 999999, length($_)); - last if($len == 0); - die "read failed: $!" unless defined($len); - } - close INFILE; + # For speed we read in the entire file then do the substitutions. + local($_) = ''; + my $len; + open INFILE, "<", $file or die "Can't open $file: $!"; + while(1){ + # On at least some systems we only get 64K. + my $len = sysread(INFILE, $_, 999999, length($_)); + last if($len == 0); + die "read failed: $!" unless defined($len); + } + close INFILE; - local $::current_file = $file; # used under handlevar - # $1 - var and value (including trailing space but not $) - # $2 - var - # $4 - value or undef -#s/\$$PREFIX-(([A-Za-z][A-Za-z0-9_]*)(: ([^\N{DOLLAR SIGN}]+))?)\$/&handlevar($2,$4)/eg; -my $count = s/\$$PREFIX-(([A-Za-z][A-Za-z0-9_]*)(: ([^\x24]+))?)\$/&handlevar($2,$4)/eg; -# XXX had o modifier, why? - return unless($count>0); - return if($opt{n}); - my $mode = 0777 & (stat($file))[2]; + local $::current_file = $file; # used under handle* + if($do_nhsubst){ + # TODO: This doesn't handle PREFIX-Assert. To do that, + # we need to capture an entire line, call new sub handlevars() + # and let it iterate across all PREFIX-Foo while + # maintaining $::skip and reverting (like &handledatesub does). + # Also: capture optional arg: $NHDT-Foo(arg)$ $NHDT-Foo(arg): value $ - my $ofile = $file . ".nht"; - open(TOUT, ">", $ofile) or die "Can't open $ofile"; + # $1 - var and value (including trailing space but not $) + # $2 - var + # $4 - value or undef + # \x24 == $ + s/\$$PREFIX-(([A-Za-z][A-Za-z0-9_]*)(: ([^\x24]+) )?)\$/&handlevar($2,$4,1)/eg; + } -# die "write failed: $!" unless defined syswrite(TOUT, $_); - my $offset = 0; - my $sent; -#print STDERR "L=",length,"\n"; - while($offset < length){ - $sent = syswrite(TOUT, $_, (length($_) - $offset), $offset); - die "write failed: $!" unless defined($sent); -#print STDERR "rv=$sent\n"; - last if($sent == (length($_) - $offset)); - $offset += $sent; -#print STDERR "loop: O=$offset\n"; - } + if($do_nhdatesub){ + # e.g: + #.\"DO NOT REMOVE NH_DATESUB .TH MAKEDEFS 6 "DATE(%-d %B %Y)" NETHACK + #.TH MAKEDEFS 6 "8 February 2022" NETHACK - close TOUT or die "Can't close $ofile"; - # Do the right thing for *nix and hope for the best elsewhere: - chmod($mode, $ofile)==1 or warn "Can't set filemode on $ofile"; - rename $ofile, $file or die "Can't rename $ofile to $file"; + # locate the keyword and the rest of the line, capturing the rest of the line (the pattern) + # use zero width assertions so we can capture them but not replace them (DOES THIS WORK?) + #and grab the next line (the replaced text) + + # $1 - pattern + # $2 - the next line (the expanded pattern) + s/ + \sNH_DATESUB\s+ # our trigger + (.*)[\n\r]+ # save the pattern in $1 + \K # but don't replace it + (.*) # save the oldvalue in $2 + / + &handledatesub($2, $1) # replace oldvalue + /emxg; + + #/m so ^$ match at each line + #/x this will be a mess, so attempt to comment it + } + +#print STDERR "COUNT = $count\n"; + return unless($count>0); + return if($opt{n}); + + my $ofile = $file . ".nht"; + my $mode = 0777 & (stat($file))[2]; # save the original mode + open(TOUT, ">", $ofile) or die "Can't open $ofile"; + + my $offset = 0; + my $sent; + while($offset < length){ + $sent = syswrite(TOUT, $_, (length($_) - $offset), $offset); + die "write failed: $!" unless defined($sent); + last if($sent == (length($_) - $offset)); + $offset += $sent; + } + + close TOUT or die "Can't close $ofile"; + # Do the right thing for *nix and hope for the best elsewhere: + chmod($mode, $ofile)==1 or warn "Can't set filemode on $ofile"; + rename $ofile, $file or die "Can't rename $ofile to $file"; } -# XXX docs for --fixup and --squash are wrong in git's synopsis. --file missing -# --message --template -t sub cmdparse { - my(@in) = @_; + my(@in) = @_; - # What are we doing? - $opt{cmd} = 'date'; # really nhsub - if($in[0] eq '--add'){ - $opt{cmd} = 'add'; - shift @in; - } - if($in[0] eq '--commit'){ - $opt{cmd} = 'commit'; - shift @in; - } + # What are we doing? + $opt{cmd} = 'date'; # really nhsub + if($in[0] eq '--add'){ + $opt{cmd} = 'add'; + shift @in; + } + if($in[0] eq '--commit'){ + $opt{cmd} = 'commit'; + shift @in; + } # add: -n -v # commit: --dry-run -v # nhsub: -n -v - while($in[0] =~ m/^-/){ - local($_) = $in[0]; - if($_ eq '--'){ - shift @in; - last; - } - if(m/^--/){ - if($opt{cmd} eq 'add' && $_ eq '--dry-run'){ - exit 0; - } - if($opt{cmd} eq 'commit' && $_ eq '--dry-run'){ - exit 0; - } - if($opt{cmd} eq 'add' && $_ eq '--refresh'){ - exit 0; - } - shift @in; - next; - } -# XXX this is messy - time for a rewrite? - if(m/^-(.*)/){ - foreach my $single ( split(//,$1) ){ - # don't do -v here from add/commit - if($single ne 'v'){ - # don't use -m from add/commit - if($opt{cmd} eq 'date' || $single ne 'm'){ - $opt{$single}++; - } - } elsif($opt{cmd} eq 'date'){ - $opt{$single}++; - } + while($in[0] =~ m/^-/){ + local($_) = $in[0]; + if($_ eq '--'){ + shift @in; + last; + } + if(m/^--/){ + if($opt{cmd} eq 'add' && $_ eq '--dry-run'){ + exit 0; + } + if($opt{cmd} eq 'commit' && $_ eq '--dry-run'){ + exit 0; + } + if($opt{cmd} eq 'add' && $_ eq '--refresh'){ + exit 0; + } + shift @in; + next; + } - if($opt{cmd} eq 'add' && $single eq 'n'){ - exit 0; - } + if(m/^-(.*)/){ + foreach my $single ( split(//,$1) ){ + # don't do -v here from add/commit + if($single ne 'v'){ + # don't use -m from add/commit + if($opt{cmd} eq 'date' || $single ne 'm'){ + $opt{$single}++; + } + } elsif($opt{cmd} eq 'date'){ + $opt{$single}++; + } + + if($opt{cmd} eq 'add' && $single eq 'n'){ + exit 0; + } #need to deal with options that eat a following element (-m, -F etc etc) #add: nothing? #commit: -c -C -F -m # -u mode is optional # -S keyid is optional - if($opt{cmd} eq 'commit'){ - if($single =~ m/[uS]/){ - last; - } - if($single =~ m/[cCFm]/){ -#XXX this will be a mess if the argument is wrong, but can we tell? No. - shift @in; - last; - } - } - } + if($opt{cmd} eq 'commit'){ + if($single =~ m/[uS]/){ + last; + } + if($single =~ m/[cCFm]/){ + # This will be a mess if the argument is wrong, but can we tell? No. + shift @in; + last; + } } - shift @in; + } } + shift @in; + } - ($mode) = ($opt{cmd} =~ m/^(.)/); - $mode = 'f' if($opt{cmd} eq 'date' && ($opt{f}||$opt{F})); - $mode = 'f' if($opt{cmd} eq 'add' && $opt{f}); + ($mode) = ($opt{cmd} =~ m/^(.)/); + $mode = 'f' if($opt{cmd} eq 'date' && ($opt{f}||$opt{F})); + $mode = 'f' if($opt{cmd} eq 'add' && $opt{f}); - if($opt{cmd} eq 'add' && $#in == -1){ - exit 0; - } - if($opt{cmd} eq 'commit' && $#in == -1){ - exit 0; - } - if($opt{cmd} eq 'add' && $opt{a} && $#in != -1){ - exit 0; - } - if($opt{cmd} eq 'add' && $opt{a}){ - my $x = `git rev-parse --show-toplevel`; - $x =~ s/[\n\r]+$//; - push(@in, $x); - } - return @in; # this is our file list + if($opt{cmd} eq 'add' && $#in == -1){ + # "git nhadd" with no files has nothing to work on + exit 0; + } + if($opt{cmd} eq 'commit' && $#in == -1){ + # "git nhcommit" with no args handles files already + # added, we assume with "git nhadd" + exit 0; + } + if($opt{cmd} eq 'commit' && $opt{a} && $#in == -1){ + # "git commit -a" does multiple things; we only care + # about modigied files. +#XXX this assumes $RS is set properly for Windows - need to check that + my @x = split(/$::RS/,`git ls-files -m`); + chomp(@x); + push(@in, @x); + } + if($opt{cmd} eq 'commit' && $opt{a} && $#in != -1){ + # Let git complain about this for us. + exit 0; + } +# "git add" doesn't have a -a option +# if($opt{cmd} eq 'add' && $opt{a} && $#in != -1){ +# exit 0; +# } +# I don't know what this was trying to do, but it's wrong. +# if($opt{cmd} eq 'add' && $opt{a}){ +# my $x = `git rev-parse --show-toplevel`; +# $x =~ s/[\n\r]+$//; +# push(@in, $x); +# } + return @in; # this is our file list } sub git_config { - my($section, $var) = @_; - my $raw = `git config --local --get $section.$var`; - $raw =~ s/[\r\n]*$//g; - return $raw if(length $raw); - die "Missing config var: [$section] $var\n"; + my($section, $var) = @_; + my $raw = `git config --local --get $section.$var`; + $raw =~ s/[\r\n]*$//g; + return $raw if(length $raw); + die "Missing config var: [$section] $var\n"; } -sub handlevar { - my($var, $val) = @_; -# print "HIT '$var' '$val'\n" if($debug2); +# (oldvalue, pattern) +sub handledatesub { + my $oldval = $_[0]; # used if assert fails + $skip = 0; # one if assert fails + my $out = $_[1]; # the pattern, which we'll edit in place +#print "OLD: '$oldval;\n"; +#print "PAT: '$out'\n"; + my $newvalue = $_[1]; + $out =~ s/ + \b # don't substitute on a partial word + (Assert|Date|Branch|Revision|Brev|Project) # $1 - keyword + \( # ( + ([^)]*) # $2 - argument + \) # ) + /&onedatesub($1,$2) + /egx; - my $subname = "PREFIX::$var"; - if(defined &$subname){ - no strict; - print " SUBIN: $var '$val'\n" if($opt{v}>=3); - $val =~ s/\s+$//; - $val = &$subname($val); - print " SUBOT: $var '$val'\n" if($opt{v}>=3); - } else { - warn "No handler for \$$PREFIX-$var\n"; + { + local $::x = $_[0] ne $out; + if ($::x){ + $count += $::x; +# warn "COUNT++"; } + } +#print STDERR "OUT SKIP=$skip count=$count\n"; +#print STDERR "OUT old='$oldval'\n new='$out'\n"; + return ($skip>0 or $count==0) ? $oldval : $out; +} + +sub onedatesub { + my($kw, $arg) = @_; + my $sname = "PREFIX::$kw"; + die "internal error, '$sname' not defined" unless defined(&$sname); + + no strict; + my $rv = &$sname(undef, $arg); + return $rv; +} + +# Assert(P=prefix) +# Date(format) +# Branch() +# Revision() +# Brev() Branch:Rev (aBREViated) + +sub handlevar { + my($var, $val, $wrap) = @_; +#print "HV '$var' '$val'\n"; + my $oldval = $val; + my $subname = "PREFIX::$var"; + if(defined &$subname){ + no strict; + print " SUBIN: $var '$val'\n" if($opt{v}>=3); + $val =~ s/\s+$//; + $val = &$subname($val, undef); + print " SUBOT: $var '$val'\n" if($opt{v}>=3); + { + local $::x = ($oldval ne $val); + if ($::x){ + $count += $::x; +# warn "COUNT2++ o='$oldval' v='$val'"; + } + } + } else { + warn "No handler for \$$PREFIX-$var\n"; + } + + if($wrap){ if(length $val){ return "\$$PREFIX-$var: $val \$"; } else { return "\$$PREFIX-$var\$"; } + } else { + return $val; + } } sub lsfiles { - my ($flags, $ps) = @_; - open RV, "-|", "git ls-files $flags '$ps'" or die "Can't ls-files"; - my @rv = ; - map { s/[\r\n]+$// } @rv; - if(!close RV){ - return undef if($! == 0); - die "close ls-files failed: $!"; - } - return undef if($#rv == -1); - return @rv; + my ($flags, $ps) = @_; + open RV, "-|", "git ls-files $flags '$ps'" or die "Can't ls-files"; + my @rv = ; + map { s/[\r\n]+$// } @rv; + if(!close RV){ + return undef if($! == 0); + die "close ls-files failed: $!"; + } + return undef if($#rv == -1); + return @rv; } package PREFIX; use POSIX qw(strftime); -# On push, put in the current date because we changed the file. -# On pull, keep the current value so we can see the last change date. sub Date { - my($val) = @_; - my $now; - if($opt{m}){ - my $hash = `git log -1 '--format=format:%H' $::current_file`; - #author keni 1429884677 -0400 - chomp($now = `git cat-file -p $hash | awk '/author/{print \$4}'`); + my(undef, $val) = @_; + my $now; + +# DONE XXX after several bug fixes, this set of ifs needs some cleanup +my $hash = `git log -1 '--format=format:%H' $::current_file`; + $now = $^T; +# if($opt{m} or not defined $hash){ + + # cope with file not yet added to git + if(not defined $hash){ + if(-f $::current_file){ + $now = (stat($::current_file))[9]; } else { - $now = time; + die "Can't find file '$::current_file'\n"; } + } elsif($opt{m}) { + #author keni 1429884677 -0400 + chomp($now = `git cat-file -p $hash | awk '/author/{print \$4}'`); + } +# } else { +# } + +# DONE XXX simplify this with %s ? +# my $fmt = length $val ? $val : "%Y/%m/%d %H:%M:%S"; + my $fmt = length $val ? $val : "%s %Y/%m/%d %H:%M:%S"; # YYYY/MM/DD HH:MM:SS - $val = "$now " . strftime("%Y/%m/%d %H:%M:%S", gmtime($now)); - return $val; +# $val = ((length $val==0)?"$now ":"") . strftime($fmt, gmtime($now)); + $val = strftime($fmt, gmtime($now)); + return $val; } #sub Header { @@ -434,26 +561,84 @@ sub Date { #} # NB: the standard-ish Revision line isn't enough - you need Branch:Revision - -# but we split it into 2 so we can use the standard processing code on Revision -# and just slip Branch in. +# but we split it into 2 so we can use the standard processing code on +# Revision and just slip Branch in. +# But see new Brev below. sub Branch { - my($val) = @_; - $val = `git symbolic-ref -q --short HEAD`; - $val =~ s/[\n\r]*$//; - $val =~ s/^\*\s*//; - $val = "(unknown)" unless($val =~ m/^[[:print:]]+$/); - return $val; + my $val; + $val = `git symbolic-ref -q --short HEAD`; + $val =~ s/[\n\r]*$//; + $val =~ s/^\*\s*//; + $val = "(unknown)" unless($val =~ m/^[[:print:]]+$/); + return $val; } sub Revision { - my($val) = @_; - my @val = `git log --follow --oneline $::current_file`; - my $ver = 0+$#val; - $ver = 0 if($ver < 0); - $val = "1.$ver"; - return $val; + my $val; + my @val = `git log --follow --oneline $::current_file`; + my $ver = 0+$#val; + $ver = 0 if($ver < 0); + $val = "1.$ver"; + return $val; } + +sub Brev { + my $branch; + $branch = `git symbolic-ref -q --short HEAD`; + $branch =~ s/[\n\r]*$//; + $branch =~ s/^\*\s*//; + $branch = "(unknown)" unless($branch =~ m/^[[:print:]]+$/); + + my @val = `git log --follow --oneline $::current_file`; + my $ver = 0+$#val; + $ver = 0 if($ver < 0); + $ver = "1.$ver"; + + my $val = "$branch:$ver"; + + return $val; +} + +sub Project { + my(undef, $arg) = @_; + my $pn = &::git_config('nethack','projectname'); + if(length $arg == 0){ + ; + } elsif($arg eq 'uc'){ + $pn = uc($pn); + } else { + warn "unknown argument '$arg' to Project()\n"; + } + return $pn; +} + + +sub Assert { + my(undef, $val) = @_; + + my($key, $arg) = ($val =~ m/^(.)=(.*)/); + if(!defined $arg){ + warn "syntax error: Assert($val)\n"; + $::skip = 1; + } + my $prefix = $2; + + # P assert arg matches saved prefix + if('P' eq $key){ + my $repoid = &::git_config('nethack','substprefix'); + if($repoid ne $prefix){ + $::skip = 1 + } + return ''; + } + + warn "Unknown Assert type '$key'\n"; + + return ''; +} + __END__ +=for nhgitset nhsub Update substitution variables =head1 NAME @@ -473,9 +658,15 @@ commands. The program re-writes those files listed on the command line; if the file is actually a directory, the program recurses into that directory tree. -Not all files found are re-written; some are ignored and those with no -substitution variables are not re-written. Unless changed by the options, -files that have not changed are not affected. +Not all files found are re-written; only those with the attribute +NHSUBST (for inline substitutions) or NH_DATESUB (for template +substitution) are considered; finally those with no substitution +variables or no changes due to subtitution variables are not +re-written. Unless changed by the options, files that have not +changed are not affected. + +As a special case, a file not yet added to Git may be the target of +C. If no files are listed on the command line, the current directory is checked as if specified as C<.>. @@ -519,3 +710,83 @@ updated when last changed. (Do not use C/C after C assertions compare the current Git config variable +C +with the C and succeed if they are identical. + +=back + +=item Date(format) / PREFIX-Date + +This variable usually substitutes the current time but see C<-m> above. + +The format of the resulting date varies. For C or C with +no format, "%s %Y/%m/%d %H:%M:%S" is used. Otherwise the given strftime +format is used. + +=item Branch() / PREFIX-Branch + +This variable is replaced with the name of the currently checked out Git +branch. + +=item Revision() / PREFIX-Revision + +This variable's value emulates a RCS or CVS style revision number. +It consists of "1." followed by the number of commits affecting the +current file. + +=item Brev() / PREFIX-Brev + +This is a convenience variable that concatenates C, a colon, and +C. Short for "aBREViated". + +=item Project() + +Returns git variable nethack.projectname. If given the argument C, returns +an upper-case version of nethack.projectname. + +=back + +=head1 SUBSTITUTION STYLES + +=head2 Prefix Substitution + +If a file has the Git attribute C, any +text that looks like a RCS/CVS variable substitution will perform +that substitution. That is, either of the following forms: + + $Var$ + $Var: Value $ + +=head2 Template Substitution + +If a file has the Git attribute C, any line that has +the token C will replace the I line with the +variable expansion of everything after that token. For example: + + .\"DO NOT REMOVE NH_DATESUB .ds f2 DATE(%B %-d, %Y) + .ds f2 September 13, 2024 + +=head1 SEE ALSO + +git help gitattributes + +perldoc nhgitset.pl diff --git a/DEVEL/hooksdir/post-applypatch b/DEVEL/hooksdir/post-applypatch index ec6af70be..37170a48e 100755 --- a/DEVEL/hooksdir/post-applypatch +++ b/DEVEL/hooksdir/post-applypatch @@ -1,5 +1,5 @@ #!/usr/bin/perl -# $NHDT-Date: 1524689631 2018/04/25 20:53:51 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.1 $ +# NetHack 3.7 post-applypatch $NHDT-Date: 1524689631 2018/04/25 20:53:51 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.1 $ # Copyright (c) 2015 by Kenneth Lorber, Kensington, Maryland # NetHack may be freely redistributed. See license for details. @@ -24,7 +24,11 @@ BEGIN { chomp $gitdir; push(@INC, $gitdir.$PDS."hooks"); } -use NHgithook; +eval {use NHgithook;}; +if($@){ + warn "loading NHgithook failed: $@"; + $nogithook = 1; +} #STARTUP-END &NHgithook::PRE; diff --git a/DEVEL/hooksdir/post-checkout b/DEVEL/hooksdir/post-checkout index d7e6c5724..db8578f94 100755 --- a/DEVEL/hooksdir/post-checkout +++ b/DEVEL/hooksdir/post-checkout @@ -24,10 +24,15 @@ BEGIN { chomp $gitdir; push(@INC, $gitdir.$PDS."hooks"); } -use NHgithook; +eval {use NHgithook;}; +if($@){ + warn "loading NHgithook failed: $@"; + $nogithook = 1; +} #STARTUP-END &NHgithook::PRE; -&NHgithook::nhversioning; +eval { &NHgithook::nhversioning unless($nogithook) }; +warn "nhversioning failed: $@" if($@); &NHgithook::POST; exit 0; diff --git a/DEVEL/hooksdir/post-commit b/DEVEL/hooksdir/post-commit index cb37b3800..753cb4a04 100755 --- a/DEVEL/hooksdir/post-commit +++ b/DEVEL/hooksdir/post-commit @@ -24,10 +24,17 @@ BEGIN { chomp $gitdir; push(@INC, $gitdir.$PDS."hooks"); } -use NHgithook; +eval {use NHgithook;}; +if($@){ + warn "loading NHgithook failed: $@"; + $nogithook = 1; +} #STARTUP-END &NHgithook::PRE; -&NHgithook::nhversioning; +eval { &NHgithook::nhversioning unless($nogithook) }; +warn "nhversioning failed: $@" if($@); &NHgithook::POST; exit 0; + + diff --git a/DEVEL/hooksdir/post-merge b/DEVEL/hooksdir/post-merge index a634f51ef..ca9e45e5f 100755 --- a/DEVEL/hooksdir/post-merge +++ b/DEVEL/hooksdir/post-merge @@ -25,10 +25,15 @@ BEGIN { push(@INC, $gitdir.$PDS."hooks"); } -use NHgithook; +eval {use NHgithook;}; +if($@){ + warn "loading NHgithook failed: $@"; + $nogithook = 1; +} #STARTUP-END &NHgithook::PRE; -&NHgithook::nhversioning; +eval { &NHgithook::nhversioning(1) unless($nogithook) }; +warn "nhversioning failed: $@" if($@); &NHgithook::POST; exit 0; diff --git a/DEVEL/hooksdir/post-rewrite b/DEVEL/hooksdir/post-rewrite index 655c1a0cd..3dcc7c18c 100755 --- a/DEVEL/hooksdir/post-rewrite +++ b/DEVEL/hooksdir/post-rewrite @@ -24,7 +24,11 @@ BEGIN { chomp $gitdir; push(@INC, $gitdir.$PDS."hooks"); } -use NHgithook; +eval {use NHgithook;}; +if($@){ + warn "loading NHgithook failed: $@"; + $nogithook = 1; +} #STARTUP-END &NHgithook::saveSTDIN; diff --git a/DEVEL/hooksdir/pre-applypatch b/DEVEL/hooksdir/pre-applypatch index 3b57a6f53..2ec0588a9 100755 --- a/DEVEL/hooksdir/pre-applypatch +++ b/DEVEL/hooksdir/pre-applypatch @@ -24,7 +24,11 @@ BEGIN { chomp $gitdir; push(@INC, $gitdir.$PDS."hooks"); } -use NHgithook; +eval {use NHgithook;}; +if($@){ + warn "loading NHgithook failed: $@"; + $nogithook = 1; +} #STARTUP-END &NHgithook::PRE; diff --git a/DEVEL/hooksdir/pre-auto-gc b/DEVEL/hooksdir/pre-auto-gc index d1ab9b005..22e45b666 100755 --- a/DEVEL/hooksdir/pre-auto-gc +++ b/DEVEL/hooksdir/pre-auto-gc @@ -24,7 +24,11 @@ BEGIN { chomp $gitdir; push(@INC, $gitdir.$PDS."hooks"); } -use NHgithook; +eval {use NHgithook;}; +if($@){ + warn "loading NHgithook failed: $@"; + $nogithook = 1; +} #STARTUP-END &NHgithook::PRE; diff --git a/DEVEL/hooksdir/pre-commit b/DEVEL/hooksdir/pre-commit index bb5dbfe84..b19fc2fd4 100755 --- a/DEVEL/hooksdir/pre-commit +++ b/DEVEL/hooksdir/pre-commit @@ -24,7 +24,11 @@ BEGIN { chomp $gitdir; push(@INC, $gitdir.$PDS."hooks"); } -use NHgithook; +eval {use NHgithook;}; +if($@){ + warn "loading NHgithook failed: $@"; + $nogithook = 1; +} #STARTUP-END &NHgithook::PRE; diff --git a/DEVEL/hooksdir/pre-push b/DEVEL/hooksdir/pre-push index c2639fa2e..a578ce529 100755 --- a/DEVEL/hooksdir/pre-push +++ b/DEVEL/hooksdir/pre-push @@ -24,7 +24,11 @@ BEGIN { chomp $gitdir; push(@INC, $gitdir.$PDS."hooks"); } -use NHgithook; +eval {use NHgithook;}; +if($@){ + warn "loading NHgithook failed: $@"; + $nogithook = 1; +} #STARTUP-END &NHgithook::saveSTDIN; diff --git a/DEVEL/hooksdir/pre-rebase b/DEVEL/hooksdir/pre-rebase index 7f447a082..4c472ef63 100755 --- a/DEVEL/hooksdir/pre-rebase +++ b/DEVEL/hooksdir/pre-rebase @@ -24,7 +24,11 @@ BEGIN { chomp $gitdir; push(@INC, $gitdir.$PDS."hooks"); } -use NHgithook; +eval {use NHgithook;}; +if($@){ + warn "loading NHgithook failed: $@"; + $nogithook = 1; +} #STARTUP-END &NHgithook::PRE; diff --git a/DEVEL/hooksdir/prepare-commit-msg b/DEVEL/hooksdir/prepare-commit-msg index b6813851a..a1ff14292 100755 --- a/DEVEL/hooksdir/prepare-commit-msg +++ b/DEVEL/hooksdir/prepare-commit-msg @@ -1,5 +1,5 @@ #!/usr/bin/perl -# $NHDT-Date: 1524689633 2018/04/25 20:53:53 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.1 $ +# NetHack 3.7 prepare-commit-msg $NHDT-Date: 1524689633 2018/04/25 20:53:53 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.1 $ # Copyright (c) 2015 by Kenneth Lorber, Kensington, Maryland # NetHack may be freely redistributed. See license for details. @@ -24,7 +24,11 @@ BEGIN { chomp $gitdir; push(@INC, $gitdir.$PDS."hooks"); } -use NHgithook; +eval {use NHgithook;}; +if($@){ + warn "loading NHgithook failed: $@"; + $nogithook = 1; +} #STARTUP-END &NHgithook::PRE; diff --git a/DEVEL/nhgitset.pl b/DEVEL/nhgitset.pl index e29cae2b4..984d45a32 100755 --- a/DEVEL/nhgitset.pl +++ b/DEVEL/nhgitset.pl @@ -3,32 +3,29 @@ # Copyright (c) 2015 by Kenneth Lorber, Kensington, Maryland # NetHack may be freely redistributed. See license for details. -# value of nethack.setupversion we will end up with when this is done -# version 1 is reserved for repos checked out before versioning was added -my $version_new = 3; -my $version_old = 0; # current version, if any (0 is no entry ergo new repo) use Cwd; use Getopt::Std; # Activestate Perl doesn't include File::Spec. Grr. BEGIN { - eval "require File::Spec::Functions"; - if($@){ - die <import; + } + File::Spec::Functions->import; } exit 1 unless(getopts('nvf')); # TODO: this can probably have better output -# OS hackery -my $DS = quotemeta('/'); # Directory Separator (for regex) -my $DSP = '/'; # ... for printing +BEGIN { + # OS hackery + $DS = quotemeta('/'); # Directory Separator (for regex) + $PDS = '/'; # ... for printing # Temporarily disabled; there's something weird about msys # msys: POSIXish over a Windows filesystem (so / not \ but \r\n not \n). #if($^O eq "msys"){ @@ -37,78 +34,129 @@ my $DSP = '/'; # ... for printing # # NB: We don't need to do anything about File::Spec. It doesn't know # # about msys but it defaults to Unix, so we'll be ok. #} -if($^O eq "MSWin32"){ + if($^O eq "MSWin32"){ $DS = quotemeta('\\'); - $DSP = '\\'; + $PDS = '\\'; + } + + # Fix @INC so we can 'use NHgithook' before it's installed. + # Set $is_sourcerepo while we're at it - same logic. + { + # Special case for running nhgitset against a different repo. + # Must preceed the normal case! + # NB: we use $DEVhooksdir later in the program + $DEVhooksdir = ($0 =~ m!^(.*)$DS!)[0]; + chomp($DEVhooksdir); + $DEVhooksdir .= $PDS."hooksdir"; + push(@INC, $DEVhooksdir) if(-d $DEVhooksdir); + # This one is for the normal case (in NHsource) + my $topdir = `git rev-parse --show-toplevel`; + chomp $topdir; + $topdir .= "${PDS}DEVEL${PDS}hooksdir"; + push(@INC, $topdir) if(-d $topdir); + $is_sourcerepo = 0; + $is_sourcerepo = 1 if(-d $topdir); + } } +use NHgithook; + # current (installed) version, if any (0 is no entry ergo new repo) +my $version_old = NHgithook::version_in_git; + # version this program will install +my($version_new,$message_new) = NHgithook::version_in_devel; + +if(0==$version_new and !opt_f){ + # Edge case: this repo has been set up using version >= 4, but now we're running + # nhgitset after checking out DEVEL supporting version <4. + # Use -f to recover from broken DEVEL code. + print STDERR "DEVEL has version <4 code but version >=4 code already installed. Stopping.\n"; + print STDERR "(If you need to reinstall the old code, rerun with -f\n"; + exit 0; +} + + +die "Valid version not found in DEVEL/VERSION" unless(0==$version_new or $version_new >= 4); + # make sure we're at the top level of a repo if(! -d ".git"){ - die "This is not the top level of a git repository.\n"; + die "This is not the top level of a git repository.\n"; } -my $vtemp = `git config --local --get nethack.setupversion`; -chomp($vtemp); -if($vtemp > 0){ - $version_old = 0+$vtemp; - if($version_old != $version_new){ - print STDERR "Migrating from setup version $version_old to $version_new\n" if($opt_v); - } +if($version_old >= $version_new and !opt_f){ + print STDERR "Nothing to do.\n"; + exit 0; } -# legacy check: -if(length $vtemp == 0){ - if(`git config --get merge.NHsubst.name` =~ m/^Net/){ - $version_old = 1; - print STDERR "Migrating to setup version 1\n" if($opt_v); + +if($version_old > 0){ + if($version_old != $version_new){ + print STDERR "Migrating from setup version $version_old to $version_new\n"; + if(length $message_new){ + print STDERR "Additional information:\n$message_new\n"; } + } +} + + +# legacy check: +if(length $version_old == 0){ + if(`git config --get merge.NHsubst.name` =~ m/^Net/){ + $version_old = 1; + print STDERR "Migrating to setup version 1\n" if($opt_v); + } } my $gitadddir = `git config --get nethack.gitadddir`; chomp($gitadddir); if(length $gitadddir){ - if(! -d $gitadddir){ - die "nethack.gitadddir has invalid value '$gitadddir'\n"; - } + if(! -d $gitadddir){ + die "nethack.gitadddir has invalid value '$gitadddir'\n"; + } } print STDERR "nethack.gitadddir=$gitadddir\n" if($opt_v); # This is (relatively) safe because we know we're at R in R/DEVEL/nhgitset.pl my $srcdir = ($0 =~ m!^(.*)$DS!)[0]; +#XXX do I really want a full path for srcdir? how badly? + if(! -f catfile($srcdir, 'nhgitset.pl')){ - die "I can't find myself in '$srcdir'\n"; + die "I can't find myself in '$srcdir'\n"; } print STDERR "Copying from: $srcdir\n" if($opt_v); if($opt_f || $version_old==0){ - print STDERR "Configuring line endings\n" if($opt_v); - unlink catfile('.git','index') unless($opt_n); - system("git reset") unless($opt_n); - system("git config --local core.safecrlf true") unless($opt_n); - system("git config --local core.autocrlf false") unless($opt_n); + print STDERR "Configuring line endings\n" if($opt_v); + system("git reset") unless($opt_n); + &add_config('core.safecrlf', 'true') unless($opt_n); + &add_config('core.autocrlf', 'false') unless($opt_n); } elsif($version_old <2){ - my $xx = `git config --get --local core.safecrlf`; - if($xx !~ m/true/){ - print STDERR "\nNeed to 'rm .git${DSP}index;git reset'.\n"; - print STDERR " When ready to proceed, re-run with -f flag.\n"; - exit 2; - } + my $xx = `git config --get --local core.safecrlf`; + if($xx !~ m/true/){ + print STDERR "\nNeed to 'rm .git${PDS}index;git reset'.\n"; + print STDERR " When ready to proceed, re-run with -f flag.\n"; + exit 2; + } } - - print STDERR "Installing aliases\n" if($opt_v); $addpath = catfile(curdir(),'.git','hooks','NHadd'); &add_alias('nhadd', "!$addpath add"); + &add_help('nhadd', 'NHadd'); &add_alias('nhcommit', "!$addpath commit"); + &add_help('nhcommit', 'NHadd'); my $nhsub = catfile(curdir(),'.git','hooks','nhsub'); &add_alias('nhsub', "!$nhsub"); + &add_help('nhsub', 'nhsub'); +&add_alias('nhhelp', '!'.catfile(curdir(),'.git','hooks','nhhelp')); + &add_help('nhhelp', 'nhhelp'); + +&add_help('NHsubst', 'NHsubst'); +&add_help('NHgithook', 'NHgithook.pm'); -print STDERR "Installing filter/merge\n" if($opt_v); -# XXXX need it in NHadd to find nhsub??? # removed at version 3 +#print STDERR "Installing filter/merge\n" if($opt_v); #if($^O eq "MSWin32"){ # $cmd = '.git\\\\hooks\\\\NHtext'; #} else { @@ -117,170 +165,183 @@ print STDERR "Installing filter/merge\n" if($opt_v); #&add_config('filter.NHtext.clean', "$cmd --clean %f"); #&add_config('filter.NHtext.smudge', "$cmd --smudge %f"); if($version_old == 1 or $version_old == 2){ - print STDERR "Removing filter.NHtext\n" if($opt_v); - system('git','config','--unset','filter.NHtext.clean') unless($opt_n); - system('git','config','--unset','filter.NHtext.smudge') unless($opt_n); - system('git','config','--remove-section','filter.NHtext') unless($opt_n); + print STDERR "Removing filter.NHtext\n" if($opt_v); + system('git','config','--unset','filter.NHtext.clean') unless($opt_n); + system('git','config','--unset','filter.NHtext.smudge') unless($opt_n); + system('git','config','--remove-section','filter.NHtext') unless($opt_n); - print STDERR "Removing NHtext\n" if($opt_v); - unlink catfile(curdir(),'.git','hooks','NHtext') unless($opt_n); + print STDERR "Removing NHtext\n" if($opt_v); + unlink catfile(curdir(),'.git','hooks','NHtext') unless($opt_n); } +&add_config('nethack.setuppath',$srcdir); +&add_config('nethack.is-sourcerepo',0+$is_sourcerepo); + $cmd = catfile(curdir(),'.git','hooks','NHsubst'); &add_config('merge.NHsubst.name', 'NetHack Keyword Substitution'); &add_config('merge.NHsubst.driver', "$cmd %O %A %B %L"); print STDERR "Running directories\n" if($opt_v); -foreach my $dir ( glob("$srcdir$DS*") ){ - next unless(-d $dir); +# copy directories into .git (right now that's just hooks +my @gitadd = length($gitadddir)?glob("$gitadddir$DS*"):undef; +foreach my $dir ( (glob("$srcdir$DS*"), @gitadd) ){ + next unless(-d $dir); - my $target = catfile($dir, 'TARGET'); - next unless(-f $target); + my $target = catfile($dir, 'TARGET'); + next unless(-f $target); - open TARGET, '<', $target or die "$target: $!"; - my $targetpath = ; - # still have to eat all these line endings under msys, so instead of chomp use this: - $targetpath =~ s![\r\n]!!g; - close TARGET; - print STDERR "Directory $dir -> $targetpath\n" if($opt_v); + open TARGET, '<', $target or die "$target: $!"; + my $targetpath = ; + # still have to eat all these line endings under msys, so instead of chomp use this: + $targetpath =~ s![\r\n]!!g; + close TARGET; + print STDERR "Directory $dir -> $targetpath\n" if($opt_v); - my $enddir = $dir; - $enddir =~ s!.*$DS!!; - if(! &process_override($enddir, "INSTEAD")){ - &process_override($enddir, "PRE"); - my $fnname = "do_dir_$enddir"; - if(defined &$fnname){ - &$fnname($dir, $targetpath); - } - &process_override($enddir, "POST"); + my $enddir = $dir; + $enddir =~ s!.*$DS!!; + if(! &process_override($enddir, "INSTEAD")){ + &process_override($enddir, "PRE"); + my $fnname = "do_dir_$enddir"; + if(defined &$fnname){ + &$fnname($dir, $targetpath); } + &process_override($enddir, "POST"); + } } -&check_prefix; # for variable substitution +&check_gitvars; # for variable substitution -if($version_old != $version_new){ - print STDERR "Setting version to $version_new\n" if($opt_v); - if(! $opt_n){ - system("git config nethack.setupversion $version_new"); - if($?){ - die "Can't set nethack.setupversion $version_new: $?,$!\n"; - } - } +if($version_old != $version_new or $opt_f){ + print STDERR "Setting version to $version_new\n" if($opt_v); + NHgithook::version_set_git($version_new) if(! $opt_n); } exit 0; -sub process_override { - my($srcdir, $plname) = @_; - return 0 unless(length $gitadddir); +sub add_help { + my($cmd, $file) = @_; - my $plpath = catfile($gitadddir, $srcdir, $plname); -#print STDERR " ",catfile($srcdir, $plname),"\n"; # save this for updating docs - list of overrides - return 0 unless(-x $plpath); - - print STDERR "Running $plpath\n" if($opt_v); - # current directory is top of target repo - - unless($opt_n){ - system("$plpath $opt_v") and die "Callout $plpath failed: $?\n"; + &add_config("nethack.aliashelp.$cmd", $file); + # pull out =for nhgitset CMD description... + my $desc = ''; + open my $fh, "<", "$DEVhooksdir/$file"; + if($fh){ + while(<$fh>){ + m/^=for\s+nhgitset\s+\Q$cmd\E\s+(.*)/ && do { + $desc = $1; + last; + } } - return 1; + close $fh; + } else { + warn "Can't open: '$DEVhooksdir/$file' ($!)\n"; + } + + if(length $desc){ + &add_config("nethack.aliasdesc.$cmd", $desc); + } else { + &add_config("nethack.aliasdesc.$cmd", "(no description available)"); + } +} + +sub process_override { + my($srcdir, $plname) = @_; + return 0 unless(length $gitadddir); + + my $plpath = catfile($gitadddir, $srcdir, $plname); + return 0 unless(-x $plpath); + + print STDERR "RunningOverride $plpath\n" if($opt_v); + + # current directory is top of target repo + unless($opt_n){ + system("$plpath $opt_v") and die "Callout $plpath failed: $?\n"; + } + return 1; } sub add_alias { - my($name, $def) = @_; - &add_config("alias.$name",$def); + my($name, $def) = @_; + &add_config("alias.$name",$def); } sub add_config { - my($name, $val) = @_; - system('git', 'config', '--local', $name, $val) unless($opt_n); + my($name, $val) = @_; + system('git', 'config', '--local', $name, $val) unless($opt_n); +} + +sub check_gitvars { + &check_prefix("substprefix"); + &check_prefix("projectname"); } sub check_prefix { - my $lcl = `git config --local --get nethack.substprefix`; - chomp($lcl); - if(0==length $lcl){ - my $other = `git config --get nethack.substprefix`; - chomp($other); - if(0==length $other){ - print STDERR "ERROR: nethack.substprefix is not set anywhere. Set it and re-run.\n"; - exit 2; - } else { - &add_config('nethack.substprefix', $other); - print STDERR "Copying prefix '$other' to local repository.\n" if($opt_v); - } - $lcl = $other; # for display below + my $which = $_[0]; + my $lcl = `git config --local --get nethack.$which`; + chomp($lcl); + if(0==length $lcl){ + my $other = `git config --get nethack.$which`; + chomp($other); + if(0==length $other){ + print STDERR "ERROR: nethack.$which is not set anywhere. Set it and re-run.\n"; + exit 2; + } else { + &add_config('nethack.$which', $other); + print STDERR "Copying prefix '$other' to local repository.\n" if($opt_v); } - print "\n\nUsing prefix '$lcl' - PLEASE MAKE SURE THIS IS CORRECT\n\n"; + $lcl = $other; # for display below + } + print "Using $which '$lcl' - PLEASE MAKE SURE THIS IS CORRECT\n"; } sub do_dir_DOTGIT { -if(1){ - # We are NOT going to mess with config now. - return; -} else { - my($srcdir, $targetdir) = @_; -#warn "do_dir_DOTGIT($srcdir, $targetdir)\n"; - my $cname = "$srcdir/config"; - if(-e $cname){ - print STDERR "Appending to .git/config\n" if($opt_v); - open CONFIG, ">>.git/config" or die "open .git/config: $!"; - open IN, "<", $cname or die "open $cname: $!"; - my @data = ; - print CONFIG @data; - close IN; - close CONFIG; - } else { - print STDERR " Nothing to add to .git/config\n" if($opt_v); - } -# XXX are there other files in .git that we might want to handle? -# So just in case: - for my $file ( glob("$srcdir/*") ){ - next if( $file =~ m!.*/TARGET$! ); - next if( $file =~ m!.*/config$! ); - die "ERROR: no handler for $file\n"; - } -} + my($srcdir, $targetdir) = @_; + # not currently in use so just bail + return; + # are there other files in .git that we might want to handle? + # So just in case: + for my $file ( glob("$srcdir/*") ){ + next if( $file =~ m!.*/TARGET$! ); + next if( $file =~ m!.*/config$! ); + die "ERROR: no handler for $file\n"; + } } sub do_dir_hooksdir { - my($srcdir, $targetdir) = @_; + my($srcdir, $targetdir) = @_; - unless (-d $targetdir){ + unless (-d $targetdir){ # Older versions of git, when cloning a repo and # the expected source templates directory does not # exist, does not create .git/hooks. So do it here. - mkdir $targetdir; - print STDERR "WARNING: .git/hooks had to be created.\n"; - print STDERR " You may want to update git.\n"; + mkdir $targetdir; + print STDERR "WARNING: .git/hooks had to be created.\n"; + print STDERR " You may want to update git.\n"; + } + + for my $path ( glob("$srcdir$DS*") ){ + next if( $path =~ m!.*${DS}TARGET$! ); + + my $file = $path; + + $file =~ s!.*$DS!!; + $file = catfile($targetdir, $file); + + next if($opt_n); + + open IN, "<", $path or die "Can't open $path: $!"; + open OUT, ">", "$file" or die "Can't open $file: $!"; + while(){ + print OUT; } + close OUT; + close IN; - for my $path ( glob("$srcdir$DS*") ){ - - next if( $path =~ m!.*${DS}TARGET$! ); - - my $file = $path; - - $file =~ s!.*$DS!!; - - $file = catfile($targetdir, $file); - - next if($opt_n); - - open IN, "<", $path or die "Can't open $path: $!"; - open OUT, ">", "$file" or die "Can't open $file: $!"; - while(){ - print OUT; - } - close OUT; - close IN; - - if(! -x $file){ - chmod 0755 ,$file; - } + if(! -x $file){ + chmod 0755 ,$file; } + } } __END__ @@ -308,11 +369,29 @@ nhgitset.pl). The following options are available: -B<-f> Force. Do not use this unless the program requests it. +=over -B<-n> Make no changes. +=item B<-f> -B<-v> Verbose output. +Force. Do not use this unless the program requests it or the hooks are broken. + +=back + +=over + +=item B<-n> + +Dry-run - make no changes. + +=back + +=over + +=item B<-v> + +Verbose output. + +=back =head1 CONFIG @@ -329,8 +408,35 @@ nethack.gitadddir nethack.setupversion + The version for nhgitset.pl and friends; has no relationship + to NetHack version numbers. + nethack.substprefix + The prefix this repo uses for variable substitution. + +nethack.projectname + + The name of the game being built - see C. + +nethack.is-sourcerepo + + Does this repo contain NetHack source code? (1 = yes, 0 = no) + +nethack.setuppath + + Path to (and including) the DEVEL directory used including the + copy of nhgitset.pl used to set up this repo. + +nethack.aliashelp.* + + The last element of the variable is the name used with C + and the value is the name of a file to display with C. + +nethack.aliasdesc.* + + The last element of the variable is the name used with C + and the value is short help displayed with C. =head1 EXIT STATUS diff --git a/doc/Guidebook.mn b/doc/Guidebook.mn index 549f9c0b7..e850311e9 100644 --- a/doc/Guidebook.mn +++ b/doc/Guidebook.mn @@ -1,4 +1,4 @@ -.\" $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.574 $ $NHDT-Date: 1711040379 2024/03/21 16:59:39 $ +.\" $NHDT-Branch: keni-gitset $:$NHDT-Revision: 1.593 $ $NHDT-Date: 1730681007 2024/11/04 00:43:27 $ .\" .\" This is an excerpt from the 'roff' man page from the 'groff' package. .\"+-- @@ -46,8 +46,8 @@ .ds vr NetHack 3.7.0 .ds f0 \*(vr .ds f1 \" empty -.\"DO NOT REMOVE NH_DATESUB .ds f2 DATE(%B %-d, %Y) -.ds f2 September 13, 2024 +.\"DO NOT REMOVE NH_DATESUB .ds f2 Date(%B %-d, %Y) +.ds f2 November 4, 2024 . .\" A note on some special characters: .\" \(lq = left double quote @@ -6671,3 +6671,4 @@ Izchak Miller Mike Stephenson .sm "Brand and product names are trademarks or registered trademarks \ of their respective holders." .\"EOF +changes diff --git a/doc/Guidebook.tex b/doc/Guidebook.tex index d71cbd330..d9e2ebeb9 100644 --- a/doc/Guidebook.tex +++ b/doc/Guidebook.tex @@ -47,7 +47,7 @@ %.au \author{Original version - Eric S. Raymond\\ (Edited and expanded for 3.7.0 by Mike Stephenson and others)} -%DO NOT REMOVE NH_DATESUB \date{DATE(%B %-d, %Y)} +%DO NOT REMOVE NH_DATESUB \date{Date(%B %-d, %Y)} \date{September 13, 2024} \maketitle diff --git a/doc/dlb.6 b/doc/dlb.6 index 785120aa2..058c6b42f 100644 --- a/doc/dlb.6 +++ b/doc/dlb.6 @@ -1,16 +1,16 @@ -.\" $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.12 $ $NHDT-Date: 1693253316 2023/08/28 20:08:36 $ -.\"DO NOT REMOVE NH_DATESUB .TH DLB 6 "DATE(%-d %B %Y)" NETHACK -.TH DLB 6 "8 February 2022" NETHACK +.\" $NHDT-Branch: keni-gitset $:$NHDT-Revision: 1.13 $ $NHDT-Date: 1730949315 2024/11/06 22:15:15 $ +.\"DO NOT REMOVE NH_DATESUB .TH DLB 6 "DATE(%-d %B %Y)" Project(uc) +.TH DLB 6 "DATE(%-d %B %Y)" NETHACK .\"DO NOT REMOVE NH_DATESUB .ds Nd DATE(%Y) -.ds Nd 2022 +.ds Nd DATE(%Y) .de NB .ds Nb \\$2 .. .de NR .ds Nr \\$2 .. -.NB $NHDT-Branch: NetHack-3.7 $ -.NR $NHDT-Revision: 1.12 $ +.NB $NHDT-Branch: keni-gitset $ +.NR $NHDT-Revision: 1.13 $ .ds Na Kenneth Lorber .SH NAME dlb \- NetHack data librarian diff --git a/doc/makedefs.6 b/doc/makedefs.6 index 1c2129f7d..4c4a65dd6 100644 --- a/doc/makedefs.6 +++ b/doc/makedefs.6 @@ -1,4 +1,4 @@ -.\"DO NOT REMOVE NH_DATESUB .TH MAKEDEFS 6 "DATE(%-d %B %Y)" NETHACK +.\"DO NOT REMOVE NH_DATESUB .TH MAKEDEFS 6 "DATE(%-d %B %Y)" Project(uc) .TH MAKEDEFS 6 "8 February 2022" NETHACK .\"DO NOT REMOVE NH_DATESUB .ds Nd DATE(%Y) .ds Nd 2022 diff --git a/doc/nethack.6 b/doc/nethack.6 index 478f99f5d..735ffa46e 100644 --- a/doc/nethack.6 +++ b/doc/nethack.6 @@ -1,4 +1,4 @@ -.\"DO NOT REMOVE NH_DATESUB .TH NETHACK 6 "DATE(%-d %B %Y)" NETHACK +.\"DO NOT REMOVE NH_DATESUB .TH NETHACK 6 "DATE(%-d %B %Y)" Project(uc) .TH NETHACK 6 "21 February 2022" NETHACK .\"DO NOT REMOVE NH_DATESUB .ds Nd DATE(%Y) .ds Nd 2022 diff --git a/doc/recover.6 b/doc/recover.6 index b94efda65..9972ff6d6 100644 --- a/doc/recover.6 +++ b/doc/recover.6 @@ -1,4 +1,4 @@ -.\"DO NOT REMOVE NH_DATESUB .TH RECOVER 6 "DATE(%-d %B %Y)" NETHACK +.\"DO NOT REMOVE NH_DATESUB .TH RECOVER 6 "DATE(%-d %B %Y)" Project(uc) .TH RECOVER 6 "8 February 2022" NETHACK .\"DO NOT REMOVE NH_DATESUB .ds Nd DATE(%Y) .ds Nd 2022 diff --git a/sys/windows/build-msys2.txt b/sys/windows/build-msys2.txt index c9efc6859..4ce421f2e 100644 --- a/sys/windows/build-msys2.txt +++ b/sys/windows/build-msys2.txt @@ -11,6 +11,8 @@ Prerequisite Requirements: pacman -S make pacman -S vim (or your editor of choice) pacman -S man (otherwise "git help foo" will not work) + pacman -S perl-doc (otherwise "git nhhelp foo" will not work, + so only needed if you use nhgitset.pl) o Lua o pdcursesmod (Only required if curses interface support is desired) Instructions for obtaining these are later in this file. From fd0b67de4d0b8f07f9a8855c5385520ae93d2ff4 Mon Sep 17 00:00:00 2001 From: nhkeni Date: Mon, 11 Nov 2024 15:21:59 -0500 Subject: [PATCH 064/791] Fix leak in crashreport_init() under Windows --- src/report.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/report.c b/src/report.c index 2d4eae979..890b3fdca 100644 --- a/src/report.c +++ b/src/report.c @@ -163,6 +163,7 @@ crashreport_init(int argc UNUSED, char *argv[] UNUSED) --cnt; } *p = '\0'; + HASH_CLEANUP(ctxp); return; skip: From 7414b906b2258b6fe192e10f79bdcdb12755d44b Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 11 Nov 2024 16:50:57 -0500 Subject: [PATCH 065/791] release some memory before exit under Windows --- sys/windows/consoletty.c | 2 -- sys/windows/windmain.c | 5 +++-- sys/windows/windsys.c | 9 +++++++++ win/win32/NetHackW.c | 36 +++++++++++++++++++++++------------- 4 files changed, 35 insertions(+), 17 deletions(-) diff --git a/sys/windows/consoletty.c b/sys/windows/consoletty.c index be382fdd2..e5f6fa272 100644 --- a/sys/windows/consoletty.c +++ b/sys/windows/consoletty.c @@ -1128,8 +1128,6 @@ consoletty_open(int mode) void consoletty_exit(void) { - /* frees some status tracking data */ - genl_status_finish(); /* go back to using the safe routines */ safe_routines(); free_custom_colors(); diff --git a/sys/windows/windmain.c b/sys/windows/windmain.c index efa09ebb9..d53484edd 100644 --- a/sys/windows/windmain.c +++ b/sys/windows/windmain.c @@ -499,8 +499,9 @@ extern const char *known_restrictions[]; /* symbols.c */ DISABLE_WARNING_UNREACHABLE_CODE -#if defined(__MINGW32__) && defined(MSWIN_GRAPHICS) -#define MAIN mingw_main + +#if defined(MSWIN_GRAPHICS) +#define MAIN nethackw_main #else #define MAIN main #endif diff --git a/sys/windows/windsys.c b/sys/windows/windsys.c index 77d1881bf..7888e4385 100644 --- a/sys/windows/windsys.c +++ b/sys/windows/windsys.c @@ -483,6 +483,10 @@ get_port_id(char *buf) } #endif /* RUNTIME_PORT_ID */ +#ifdef MSWIN_GRAPHICS +extern void free_winmain_stuff(void); +#endif + void nethack_exit(int code) { @@ -506,6 +510,11 @@ nethack_exit(int code) if (iflags.window_inited) wait_synch(); } + /* frees some status tracking data */ + genl_status_finish(); +#ifdef MSWIN_GRAPHICS + free_winmain_stuff(); +#endif exit(code); } diff --git a/win/win32/NetHackW.c b/win/win32/NetHackW.c index 3103f8045..20a5f7591 100644 --- a/win/win32/NetHackW.c +++ b/win/win32/NetHackW.c @@ -82,13 +82,16 @@ static void __cdecl mswin_moveloop(void *); #pragma warning( disable : 28251) #endif +extern int nethackw_main(int argc, char *argv[]); + +static char *argv[MAX_CMDLINE_PARAM]; + int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { INITCOMMONCONTROLSEX InitCtrls; int argc; - char *argv[MAX_CMDLINE_PARAM]; size_t len; TCHAR *p; TCHAR wbuf[BUFSZ]; @@ -210,14 +213,14 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, for (argc = 1; p && argc < MAX_CMDLINE_PARAM; argc++) { len = _tcslen(p); if (len > 0) { - argv[argc] = _strdup(NH_W2A(p, buf, BUFSZ)); + argv[argc] = strdup(NH_W2A(p, buf, BUFSZ)); } else { - argv[argc] = ""; + argv[argc] = strdup(""); } p = _get_cmd_arg(NULL); } GetModuleFileName(NULL, wbuf, BUFSZ); - argv[0] = _strdup(NH_W2A(wbuf, buf, BUFSZ)); + argv[0] = strdup(NH_W2A(wbuf, buf, BUFSZ)); if (argc == 2) { TCHAR *savefile = strdup(argv[1]); @@ -232,8 +235,8 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, if (*p) { if (strcmp(p + 1, "NetHack-saved-game") == 0) { *p = '\0'; - argv[1] = "-u"; - argv[2] = _strdup(name); + argv[1] = strdup("-u"); + argv[2] = strdup(name); argc = 3; } } @@ -241,16 +244,23 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, free(savefile); } GUILaunched = 1; - /* let main do the argument processing */ -#ifndef __MINGW32__ - main(argc, argv); -#else - int mingw_main(int argc, char *argv[]); - mingw_main(argc, argv); -#endif + /* let nethackw_main do the argument processing */ + nethackw_main(argc, argv); + /* not reached */ return 0; } +void +free_winmain_stuff(void) +{ + int cnt; + + for (cnt = 0; cnt < MAX_CMDLINE_PARAM; ++cnt) { + if (argv[cnt] && argv) + free((genericptr_t) argv[cnt]); + } +} + #ifdef _MSC_VER #pragma warning( pop ) #endif From 2ee31972a56fb6fdde9ca75026b5af347e1faf84 Mon Sep 17 00:00:00 2001 From: SHIRAKATA Kentaro Date: Tue, 12 Nov 2024 14:04:30 +0900 Subject: [PATCH 066/791] unify to early return on offer_corpse() * remove redundant `else` * reduce indent --- src/pray.c | 154 +++++++++++++++++++++++++++-------------------------- 1 file changed, 79 insertions(+), 75 deletions(-) diff --git a/src/pray.c b/src/pray.c index b48dff609..e5dc55baa 100644 --- a/src/pray.c +++ b/src/pray.c @@ -1914,7 +1914,8 @@ offer_corpse(struct obj *otmp, boolean highaltar, aligntyp altaralign) if (your_race(ptr)) { sacrifice_your_race(otmp, highaltar, altaralign); return; - } else if (has_omonst(otmp) + } + if (has_omonst(otmp) && (mtmp = get_mtraits(otmp, FALSE)) != 0 && mtmp->mtame) { /* mtmp is a temporary pointer to a tame monster's attributes, @@ -1924,11 +1925,13 @@ offer_corpse(struct obj *otmp, boolean highaltar, aligntyp altaralign) HAggravate_monster |= FROMOUTSIDE; offer_negative_valued(highaltar, altaralign); return; - } else if (!value) { + } + if (!value) { /* too old; don't give undead or unicorn bonus or penalty */ pline1(nothing_happens); return; - } else if (is_undead(ptr)) { /* Not demons--no demon corpses */ + } + if (is_undead(ptr)) { /* Not demons--no demon corpses */ /* most undead that leave a corpse yield 'human' (or other race) corpse so won't get here; the exception is wraith; give the bonus for wraith to chaotics too because they are sacrificing @@ -1976,88 +1979,89 @@ offer_corpse(struct obj *otmp, boolean highaltar, aligntyp altaralign) if (altaralign != u.ualign.type && highaltar) { desecrate_altar(highaltar, altaralign); - } else if (u.ualign.type != altaralign) { + return; + } + if (u.ualign.type != altaralign) { /* Sacrificing at an altar of a different alignment */ offer_different_alignment_altar(otmp, altaralign); return; - } else { - consume_offering(otmp); - /* OK, you get brownie points. */ - if (u.ugangr) { - int saved_anger = u.ugangr; - u.ugangr -= ((value * (u.ualign.type == A_CHAOTIC ? 2 : 3)) - / MAXVALUE); - if (u.ugangr < 0) - u.ugangr = 0; - if (u.ugangr != saved_anger) { - if (u.ugangr) { - pline("%s seems %s.", u_gname(), - Hallucination ? "groovy" : "slightly mollified"); + } + consume_offering(otmp); + /* OK, you get brownie points. */ + if (u.ugangr) { + int saved_anger = u.ugangr; + u.ugangr -= ((value * (u.ualign.type == A_CHAOTIC ? 2 : 3)) + / MAXVALUE); + if (u.ugangr < 0) + u.ugangr = 0; + if (u.ugangr != saved_anger) { + if (u.ugangr) { + pline("%s seems %s.", u_gname(), + Hallucination ? "groovy" : "slightly mollified"); - if ((int) u.uluck < 0) - change_luck(1); - } else { - pline("%s seems %s.", u_gname(), - Hallucination ? "cosmic (not a new fact)" - : "mollified"); + if ((int) u.uluck < 0) + change_luck(1); + } else { + pline("%s seems %s.", u_gname(), + Hallucination ? "cosmic (not a new fact)" + : "mollified"); - if ((int) u.uluck < 0) - u.uluck = 0; - } - } else { /* not satisfied yet */ + if ((int) u.uluck < 0) + u.uluck = 0; + } + } else { /* not satisfied yet */ + if (Hallucination) + pline_The("gods seem tall."); + else + You("have a feeling of inadequacy."); + } + } else if (ugod_is_angry()) { + if (value > MAXVALUE) + value = MAXVALUE; + if (value > -u.ualign.record) + value = -u.ualign.record; + adjalign(value); + You_feel("partially absolved."); + } else if (u.ublesscnt > 0) { + int saved_cnt = u.ublesscnt; + u.ublesscnt -= ((value * (u.ualign.type == A_CHAOTIC ? 500 : 300)) + / MAXVALUE); + if (u.ublesscnt < 0) + u.ublesscnt = 0; + if (u.ublesscnt != saved_cnt) { + if (u.ublesscnt) { if (Hallucination) - pline_The("gods seem tall."); + You("realize that the gods are not like you and I."); else - You("have a feeling of inadequacy."); - } - } else if (ugod_is_angry()) { - if (value > MAXVALUE) - value = MAXVALUE; - if (value > -u.ualign.record) - value = -u.ualign.record; - adjalign(value); - You_feel("partially absolved."); - } else if (u.ublesscnt > 0) { - int saved_cnt = u.ublesscnt; - u.ublesscnt -= ((value * (u.ualign.type == A_CHAOTIC ? 500 : 300)) - / MAXVALUE); - if (u.ublesscnt < 0) - u.ublesscnt = 0; - if (u.ublesscnt != saved_cnt) { - if (u.ublesscnt) { - if (Hallucination) - You("realize that the gods are not like you and I."); - else - You("have a hopeful feeling."); - if ((int) u.uluck < 0) - change_luck(1); - } else { - if (Hallucination) - pline("Overall, there is a smell of fried onions."); - else - You("have a feeling of reconciliation."); - if ((int) u.uluck < 0) - u.uluck = 0; - } - } - } else { - int saved_luck = u.uluck; - if (bestow_artifact()) - return; - change_luck((value * LUCKMAX) / (MAXVALUE * 2)); - if ((int) u.uluck < 0) - u.uluck = 0; - if (u.uluck != saved_luck) { - if (Blind) - You("think %s brushed your %s.", something, - body_part(FOOT)); + You("have a hopeful feeling."); + if ((int) u.uluck < 0) + change_luck(1); + } else { + if (Hallucination) + pline("Overall, there is a smell of fried onions."); else - You(Hallucination - ? "see crabgrass at your %s. A funny thing in a dungeon." - : "glimpse a four-leaf clover at your %s.", - makeplural(body_part(FOOT))); + You("have a feeling of reconciliation."); + if ((int) u.uluck < 0) + u.uluck = 0; } } + } else { + int saved_luck = u.uluck; + if (bestow_artifact()) + return; + change_luck((value * LUCKMAX) / (MAXVALUE * 2)); + if ((int) u.uluck < 0) + u.uluck = 0; + if (u.uluck != saved_luck) { + if (Blind) + You("think %s brushed your %s.", something, + body_part(FOOT)); + else + You(Hallucination + ? "see crabgrass at your %s. A funny thing in a dungeon." + : "glimpse a four-leaf clover at your %s.", + makeplural(body_part(FOOT))); + } } } From 0e52eac18435ba6f771021ed00b27d9c3f8499b5 Mon Sep 17 00:00:00 2001 From: nhmall Date: Tue, 12 Nov 2024 18:00:37 -0500 Subject: [PATCH 067/791] update tested versions of Visual Studio 2024-11-12 --- sys/windows/Makefile.nmake | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sys/windows/Makefile.nmake b/sys/windows/Makefile.nmake index 2104b0afc..4df6112c2 100644 --- a/sys/windows/Makefile.nmake +++ b/sys/windows/Makefile.nmake @@ -8,8 +8,8 @@ # MS Visual Studio Visual C++ compiler # # Visual Studio Compilers Tested: -# - Microsoft Visual Studio 2019 Community Edition v 16.11.41 -# - Microsoft Visual Studio 2022 Community Edition v 17.11.5 +# - Microsoft Visual Studio 2019 Community Edition v 16.11.42 +# - Microsoft Visual Studio 2022 Community Edition v 17.12.0 # #============================================================================== # This is used for building two distinct executables of NetHack: @@ -988,8 +988,8 @@ rc=Rc.exe # is too old or untested. # # Recently tested versions: -TESTEDVS2019 = 14.29.30156.0 -TESTEDVS2022 = 14.41.34123.0 +TESTEDVS2019 = 14.29.30157.0 +TESTEDVS2022 = 14.42.34433.0 VS2019CUR = $(TESTEDVS2019:.=) VS2022CUR = $(TESTEDVS2022:.=) From 724f8f865c3b6ad6a8cfade32ae1ee2708f90c5b Mon Sep 17 00:00:00 2001 From: nhmall Date: Tue, 12 Nov 2024 18:51:04 -0500 Subject: [PATCH 068/791] more memory freeing before exit on Windows --- sys/windows/consoletty.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sys/windows/consoletty.c b/sys/windows/consoletty.c index e5f6fa272..d1cbfbbca 100644 --- a/sys/windows/consoletty.c +++ b/sys/windows/consoletty.c @@ -1131,6 +1131,8 @@ consoletty_exit(void) /* go back to using the safe routines */ safe_routines(); free_custom_colors(); + free((genericptr_t) console.front_buffer); + free((genericptr_t) console.back_buffer); free((genericptr_t) console.localestr); free((genericptr_t) console.orig_localestr); } From 277a0e4464d68a163f55d3696f3cfc69470f8015 Mon Sep 17 00:00:00 2001 From: nhmall Date: Tue, 12 Nov 2024 19:30:43 -0500 Subject: [PATCH 069/791] Windows NetHackW.c bit --- win/win32/NetHackW.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/win/win32/NetHackW.c b/win/win32/NetHackW.c index 20a5f7591..8a3144083 100644 --- a/win/win32/NetHackW.c +++ b/win/win32/NetHackW.c @@ -256,7 +256,7 @@ free_winmain_stuff(void) int cnt; for (cnt = 0; cnt < MAX_CMDLINE_PARAM; ++cnt) { - if (argv[cnt] && argv) + if (argv[cnt]) free((genericptr_t) argv[cnt]); } } From 5c28b9e987fec20433a168bc565589e7be640889 Mon Sep 17 00:00:00 2001 From: nhmall Date: Wed, 13 Nov 2024 09:07:10 -0500 Subject: [PATCH 070/791] fix another memory leak In sys_early_init(), the values for sysopt.gdbpath and sysopt.greppath were being assigned by calling dupstr() without ensuring that a value previously assigned by dupstr() were free()'d. Also, the sysopt struct definition is changed to sysopt_s, not because there's anything wrong with the original struct sysopt sysopt; but because I couldn't convince the debugger to use the correct thing when trying to track down the leak. --- include/sys.h | 4 ++-- src/sys.c | 6 +++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/include/sys.h b/include/sys.h index 764d7435f..63f7f5394 100644 --- a/include/sys.h +++ b/include/sys.h @@ -5,7 +5,7 @@ #ifndef SYS_H #define SYS_H -struct sysopt { +struct sysopt_s { char *support; /* local support contact */ char *recover; /* how to run recover - may be overridden by win port */ char *wizards; /* space-separated list of usernames */ @@ -60,7 +60,7 @@ struct sysopt { * 1: suppress it */ }; -extern struct sysopt sysopt; +extern struct sysopt_s sysopt; #define SYSOPT_SEDUCE sysopt.seduce diff --git a/src/sys.c b/src/sys.c index 2cef92a87..6c2ee1b51 100644 --- a/src/sys.c +++ b/src/sys.c @@ -15,7 +15,7 @@ at runtime by setting up a value for "DEBUGFILES" in the environment */ #endif -struct sysopt sysopt; +struct sysopt_s sysopt; void sys_early_init(void) @@ -66,7 +66,11 @@ sys_early_init(void) #ifdef PANICTRACE /* panic options */ + if (sysopt.gdbpath) + free((genericptr_t) sysopt.gdbpath), sysopt.gdbpath = 0; sysopt.gdbpath = dupstr(GDBPATH); + if (sysopt.greppath) + free((genericptr_t) sysopt.greppath), sysopt.greppath = 0; sysopt.greppath = dupstr(GREPPATH); #if (NH_DEVEL_STATUS != NH_STATUS_RELEASED) sysopt.panictrace_gdb = 1; From c85b5d3e5628731c69fdc910b777efcd037f1b61 Mon Sep 17 00:00:00 2001 From: nhmall Date: Wed, 13 Nov 2024 13:48:03 -0500 Subject: [PATCH 071/791] rearrange function layout in Windows windmain.c --- sys/windows/windmain.c | 760 +++++++++++++++++++++-------------------- 1 file changed, 383 insertions(+), 377 deletions(-) diff --git a/sys/windows/windmain.c b/sys/windows/windmain.c index d53484edd..14cc255a6 100644 --- a/sys/windows/windmain.c +++ b/sys/windows/windmain.c @@ -63,6 +63,7 @@ extern void (*utf8graphics_mode_callback)(void); #ifdef PC_LOCKING static int eraseoldlocks(void); #endif + int windows_nhgetch(void); void windows_nhbell(void); int windows_nh_poskey(int *, int *, int *); @@ -121,384 +122,31 @@ void port_help(void); #endif void windows_raw_print(const char *str); - - - -DISABLE_WARNING_UNREACHABLE_CODE - -int -get_known_folder_path( - const KNOWNFOLDERID * folder_id, - char * path - , size_t path_size) -{ - PWSTR wide_path; - if (FAILED(SHGetKnownFolderPath(folder_id, 0, NULL, &wide_path))) { - error("Unable to get known folder path"); - return FALSE; - } - - size_t converted; - errno_t err; - - err = wcstombs_s(&converted, path, path_size, wide_path, _TRUNCATE); - - CoTaskMemFree(wide_path); - - if (err == STRUNCATE || err == EILSEQ) { - // silently handle this problem - return FALSE; - } else if (err != 0) { - error("Failed folder (%lu) path string conversion, unexpected err = %d", - folder_id->Data1, err); - return FALSE; - } - - return TRUE; -} - -void -create_directory(const char * path) -{ - - BOOL dres = CreateDirectoryA(path, NULL); - - if (!dres) { - DWORD dw = GetLastError(); - - if (dw != ERROR_ALREADY_EXISTS) - error("Unable to create directory '%s'", path); - } -} - -RESTORE_WARNING_UNREACHABLE_CODE - -int -build_known_folder_path( - const KNOWNFOLDERID * folder_id, - char * path, - size_t path_size, - boolean versioned) -{ - if(!get_known_folder_path(folder_id, path, path_size)) - return FALSE; - - strcat(path, "\\NetHack\\"); - create_directory(path); - if (versioned) { - Sprintf(eos(path), "%d.%d\\", - VERSION_MAJOR, VERSION_MINOR); - create_directory(path); - } - return TRUE; -} - -void -build_environment_path( - const char * env_str, - const char * folder, - char * path, - size_t path_size) -{ - path[0] = '\0'; - - const char * root_path = nh_getenv(env_str); - - if (root_path == NULL) return; - - strcpy_s(path, path_size, root_path); - - char * colon = strchr(path, ';'); - if (colon != NULL) path[0] = '\0'; - - if (strlen(path) == 0) return; - - append_slash(path); - - if (folder != NULL) { - strcat_s(path, path_size, folder); - strcat_s(path, path_size, "\\"); - } -} - -boolean -folder_file_exists(const char * folder, const char * file_name) -{ - char path[MAX_PATH]; - - if (folder[0] == '\0') return FALSE; - - strcpy(path, folder); - strcat(path, file_name); - return file_exists(path); -} - -boolean -test_portable_config( - const char *executable_path, - char *portable_device_path, - size_t portable_device_path_size) -{ - int lth = 0; - const char *sysconf = "sysconf"; - char tmppath[MAX_PATH]; - boolean retval = FALSE, - save_initoptions_noterminate = iflags.initoptions_noterminate; - - if (portable_device_path && folder_file_exists(executable_path, "sysconf")) { - /* - There is a sysconf file (not just sysconf.template) present in - the exe path, which is not the way NetHack is initially distributed, - so assume it means that the admin/installer wants to override - something, perhaps set up for a fully-portable configuration that - leaves no traces behind elsewhere on this computer's hard drive - - delve into that... - */ - - *portable_device_path = '\0'; - lth = sizeof tmppath - strlen(sysconf); - (void) strncpy(tmppath, executable_path, lth - 1); - tmppath[lth - 1] = '\0'; - (void) strcat(tmppath, sysconf); - - iflags.initoptions_noterminate = 1; - /* assure_syscf_file(); */ - config_error_init(TRUE, tmppath, FALSE); - /* ... and _must_ parse correctly. */ - if (read_config_file(tmppath, set_in_sysconf) - && sysopt.portable_device_paths) - retval = TRUE; - (void) config_error_done(); - iflags.initoptions_noterminate = save_initoptions_noterminate; - sysopt_release(); /* the real sysconf processing comes later */ - } - if (retval) { - lth = strlen(executable_path); - if (lth <= (int) portable_device_path_size - 1) - Strcpy(portable_device_path, executable_path); - else - retval = FALSE; - } - return retval; -} - -static char portable_device_path[MAX_PATH]; - -const char *get_portable_device(void) -{ - return (const char *) portable_device_path; -} - -void -set_default_prefix_locations(const char *programPath UNUSED) -{ - static char executable_path[MAX_PATH]; - static char profile_path[MAX_PATH]; - static char versioned_profile_path[MAX_PATH]; - static char versioned_user_data_path[MAX_PATH]; - static char versioned_global_data_path[MAX_PATH]; -/* static char versioninfo[20] UNUSED; */ - - strcpy(executable_path, get_executable_path()); - append_slash(executable_path); - - if (test_portable_config(executable_path, - portable_device_path, sizeof portable_device_path)) { - gf.fqn_prefix[SYSCONFPREFIX] = executable_path; - gf.fqn_prefix[CONFIGPREFIX] = portable_device_path; - gf.fqn_prefix[HACKPREFIX] = portable_device_path; - gf.fqn_prefix[SAVEPREFIX] = portable_device_path; - gf.fqn_prefix[LEVELPREFIX] = portable_device_path; - gf.fqn_prefix[BONESPREFIX] = portable_device_path; - gf.fqn_prefix[SCOREPREFIX] = portable_device_path; - gf.fqn_prefix[LOCKPREFIX] = portable_device_path; - gf.fqn_prefix[TROUBLEPREFIX] = portable_device_path; - gf.fqn_prefix[DATAPREFIX] = executable_path; - } else { - if(!build_known_folder_path(&FOLDERID_Profile, profile_path, - sizeof(profile_path), FALSE)) - strcpy(profile_path, executable_path); - - if(!build_known_folder_path(&FOLDERID_Profile, versioned_profile_path, - sizeof(profile_path), TRUE)) - strcpy(versioned_profile_path, executable_path); - - if(!build_known_folder_path(&FOLDERID_LocalAppData, - versioned_user_data_path, sizeof(versioned_user_data_path), TRUE)) - strcpy(versioned_user_data_path, executable_path); - - if(!build_known_folder_path(&FOLDERID_ProgramData, - versioned_global_data_path, sizeof(versioned_global_data_path), TRUE)) - strcpy(versioned_global_data_path, executable_path); - - gf.fqn_prefix[SYSCONFPREFIX] = versioned_global_data_path; - gf.fqn_prefix[CONFIGPREFIX] = profile_path; - gf.fqn_prefix[HACKPREFIX] = versioned_profile_path; - gf.fqn_prefix[SAVEPREFIX] = versioned_user_data_path; - gf.fqn_prefix[LEVELPREFIX] = versioned_user_data_path; - gf.fqn_prefix[BONESPREFIX] = versioned_global_data_path; - gf.fqn_prefix[SCOREPREFIX] = versioned_global_data_path; - gf.fqn_prefix[LOCKPREFIX] = versioned_global_data_path; - gf.fqn_prefix[TROUBLEPREFIX] = versioned_profile_path; - gf.fqn_prefix[DATAPREFIX] = executable_path; - } -} - -/* copy file if destination does not exist */ -void -copy_file( - const char * dst_folder, - const char * dst_name, - const char * src_folder, - const char * src_name, - boolean copy_even_if_it_exists) -{ - char dst_path[MAX_PATH]; - strcpy(dst_path, dst_folder); - strcat(dst_path, dst_name); - - char src_path[MAX_PATH]; - strcpy(src_path, src_folder); - strcat(src_path, src_name); - - if(!file_exists(src_path)) - error("Unable to copy file '%s' as it does not exist", src_path); - - if(file_exists(dst_path) && !copy_even_if_it_exists) - return; - - BOOL success = CopyFileA(src_path, dst_path, !copy_even_if_it_exists); - if(!success) error("Failed to copy '%s' to '%s' (%d)", src_path, dst_path, errno); -} - -/* update file copying if it does not exist or src is newer then dst */ -void -update_file( - const char * dst_folder, - const char * dst_name, - const char * src_folder, - const char * src_name, - BOOL save_copy) -{ - char dst_path[MAX_PATH]; - strcpy(dst_path, dst_folder); - strcat(dst_path, dst_name); - - char src_path[MAX_PATH]; - strcpy(src_path, src_folder); - strcat(src_path, src_name); - - char save_path[MAX_PATH]; - strcpy(save_path, dst_folder); - strcat(save_path, dst_name); - strcat(save_path, ".save"); - - if(!file_exists(src_path)) - error("Unable to copy file '%s' as it does not exist", src_path); - - if (!file_newer(src_path, dst_path)) - return; - - if (file_exists(dst_path) && save_copy) - CopyFileA(dst_path, save_path, FALSE); - - BOOL success = CopyFileA(src_path, dst_path, FALSE); - if(!success) error("Failed to update '%s' to '%s'", src_path, dst_path); - -} - -void -copy_symbols_content(void) -{ - char dst_path[MAX_PATH], interim_path[MAX_PATH], orig_path[MAX_PATH]; - - boolean no_template = FALSE; - - /* Using the SYSCONFPREFIX path, lock it so that it does not change */ - fqn_prefix_locked[SYSCONFPREFIX] = TRUE; - - strcpy(orig_path, gf.fqn_prefix[DATAPREFIX]); - strcat(orig_path, SYMBOLS_TEMPLATE); - strcpy(interim_path, gf.fqn_prefix[SYSCONFPREFIX]); - strcat(interim_path, SYMBOLS_TEMPLATE); - strcpy(dst_path, gf.fqn_prefix[SYSCONFPREFIX]); - strcat(dst_path, SYMBOLS); - - if (!file_exists(orig_path)) { - char alt_orig_path[MAX_PATH]; - - strcpy(alt_orig_path, gf.fqn_prefix[DATAPREFIX]); - strcat(alt_orig_path, SYMBOLS); - if (file_exists(alt_orig_path)) { - no_template = TRUE; - /* symbols -> symbols.template */ - copy_file(gf.fqn_prefix[DATAPREFIX], SYMBOLS_TEMPLATE, - gf.fqn_prefix[DATAPREFIX], SYMBOLS, TRUE); - } - } - if (!file_exists(interim_path) || file_newer(orig_path, interim_path)) { - /* symbols.template -> symbols.template */ - copy_file(gf.fqn_prefix[SYSCONFPREFIX], SYMBOLS_TEMPLATE, - gf.fqn_prefix[DATAPREFIX], SYMBOLS_TEMPLATE, TRUE); - } - if (!file_exists(dst_path) || file_newer(interim_path, dst_path)) { - /* symbols.template -> symbols */ - copy_file(gf.fqn_prefix[SYSCONFPREFIX], SYMBOLS, - gf.fqn_prefix[SYSCONFPREFIX], SYMBOLS_TEMPLATE, TRUE); - } -} - -void copy_sysconf_content(void) -{ - /* Using the SYSCONFPREFIX path, lock it so that it does not change */ - fqn_prefix_locked[SYSCONFPREFIX] = TRUE; - - update_file(gf.fqn_prefix[SYSCONFPREFIX], SYSCF_TEMPLATE, - gf.fqn_prefix[DATAPREFIX], SYSCF_TEMPLATE, FALSE); - - /* If the required early game file does not exist, copy it */ - copy_file(gf.fqn_prefix[SYSCONFPREFIX], SYSCF_FILE, - gf.fqn_prefix[DATAPREFIX], SYSCF_TEMPLATE, FALSE); - -} - -void copy_config_content(void) -{ - /* Using the CONFIGPREFIX path, lock it so that it does not change */ - fqn_prefix_locked[CONFIGPREFIX] = TRUE; - - /* Keep templates up to date */ - update_file(gf.fqn_prefix[CONFIGPREFIX], CONFIG_TEMPLATE, - gf.fqn_prefix[DATAPREFIX], CONFIG_TEMPLATE, FALSE); - - /* If the required early game file does not exist, copy it */ - /* NOTE: We never replace .nethackrc or sysconf */ - copy_file(gf.fqn_prefix[CONFIGPREFIX], CONFIG_FILE, - gf.fqn_prefix[DATAPREFIX], CONFIG_TEMPLATE, FALSE); -} - -void -copy_hack_content(void) -{ - nhassert(fqn_prefix_locked[HACKPREFIX]); - - /* Keep Guidebook and opthelp up to date */ - update_file(gf.fqn_prefix[HACKPREFIX], GUIDEBOOK_FILE, - gf.fqn_prefix[DATAPREFIX], GUIDEBOOK_FILE, FALSE); - update_file(gf.fqn_prefix[HACKPREFIX], OPTIONFILE, - gf.fqn_prefix[DATAPREFIX], OPTIONFILE, FALSE); -} extern const char *known_handling[]; /* symbols.c */ extern const char *known_restrictions[]; /* symbols.c */ -/* - * __MINGW32__ Note - * If the graphics version is built, we don't need a main; it is skipped - * to help MinGW decide which entry point to choose. If both main and - * WinMain exist, the resulting executable won't work correctly. - */ + +/* --------------------------------------------------------------------------- */ DISABLE_WARNING_UNREACHABLE_CODE +/* + * NetHack main + * + * The following function is used in both the nongraphical nethack.exe, and + * in the graphical nethackw.exe. + * + * The function below is called main() in the non-graphical build of + * NetHack for Windows and is the primary entry point for the program. + * + * It is called nethackw_main() in the graphical build of NetHack for + * Windows, where WinMain() is the primary entry point for the program + * and this nethackw_main() is called as a sub function. + * + * The code in WinMain() (in win/win32/nethackw.c) is primarily focused + * on setting up the graphical windows environment, and leaves the + * NetHack-specific startup code to this function. + * + */ #if defined(MSWIN_GRAPHICS) #define MAIN nethackw_main @@ -574,7 +222,7 @@ _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);*/ if (getcwd(orgdir, sizeof orgdir) == (char *) 0) error("NetHack: current directory path too long"); #endif - initoptions_init(); // This allows OPTIONS in syscf on Windows. + initoptions_init(); // This allows OPTIONS in syscf on Windows. set_default_prefix_locations(argv[0]); #if defined(CHDIR) && !defined(NOCWD_ASSUMPTIONS) @@ -845,9 +493,9 @@ process_options(int argc, char * argv[]) argv++; } #if defined(CRASHREPORT) - if (argcheck(argc, argv, ARG_BIDSHOW) == 2) { - nethack_exit(EXIT_SUCCESS); - } + if (argcheck(argc, argv, ARG_BIDSHOW) == 2) { + nethack_exit(EXIT_SUCCESS); + } #endif if (argc > 1 && !strncmp(argv[1], "-d", 2) && argv[1][2] != 'e') { /* avoid matching "-dec" for DECgraphics; since the man page @@ -1025,6 +673,364 @@ nhusage(void) #undef ADD_USAGE } +DISABLE_WARNING_UNREACHABLE_CODE + +int +get_known_folder_path(const KNOWNFOLDERID *folder_id, char *path, + size_t path_size) +{ + PWSTR wide_path; + if (FAILED(SHGetKnownFolderPath(folder_id, 0, NULL, &wide_path))) { + error("Unable to get known folder path"); + return FALSE; + } + + size_t converted; + errno_t err; + + err = wcstombs_s(&converted, path, path_size, wide_path, _TRUNCATE); + + CoTaskMemFree(wide_path); + + if (err == STRUNCATE || err == EILSEQ) { + // silently handle this problem + return FALSE; + } else if (err != 0) { + error( + "Failed folder (%lu) path string conversion, unexpected err = %d", + folder_id->Data1, err); + return FALSE; + } + + return TRUE; +} + +void +create_directory(const char *path) +{ + BOOL dres = CreateDirectoryA(path, NULL); + + if (!dres) { + DWORD dw = GetLastError(); + + if (dw != ERROR_ALREADY_EXISTS) + error("Unable to create directory '%s'", path); + } +} + +RESTORE_WARNING_UNREACHABLE_CODE + +int +build_known_folder_path(const KNOWNFOLDERID *folder_id, char *path, + size_t path_size, boolean versioned) +{ + if (!get_known_folder_path(folder_id, path, path_size)) + return FALSE; + + strcat(path, "\\NetHack\\"); + create_directory(path); + if (versioned) { + Sprintf(eos(path), "%d.%d\\", VERSION_MAJOR, VERSION_MINOR); + create_directory(path); + } + return TRUE; +} + +void +build_environment_path(const char *env_str, const char *folder, char *path, + size_t path_size) +{ + path[0] = '\0'; + + const char *root_path = nh_getenv(env_str); + + if (root_path == NULL) + return; + + strcpy_s(path, path_size, root_path); + + char *colon = strchr(path, ';'); + if (colon != NULL) + path[0] = '\0'; + + if (strlen(path) == 0) + return; + + append_slash(path); + + if (folder != NULL) { + strcat_s(path, path_size, folder); + strcat_s(path, path_size, "\\"); + } +} + +boolean +folder_file_exists(const char *folder, const char *file_name) +{ + char path[MAX_PATH]; + + if (folder[0] == '\0') + return FALSE; + + strcpy(path, folder); + strcat(path, file_name); + return file_exists(path); +} + +boolean +test_portable_config(const char *executable_path, char *portable_device_path, + size_t portable_device_path_size) +{ + int lth = 0; + const char *sysconf = "sysconf"; + char tmppath[MAX_PATH]; + boolean retval = FALSE, + save_initoptions_noterminate = iflags.initoptions_noterminate; + + if (portable_device_path + && folder_file_exists(executable_path, "sysconf")) { + /* + There is a sysconf file (not just sysconf.template) present in + the exe path, which is not the way NetHack is initially + distributed, so assume it means that the admin/installer wants to + override something, perhaps set up for a fully-portable + configuration that leaves no traces behind elsewhere on this + computer's hard drive - delve into that... + */ + + *portable_device_path = '\0'; + lth = sizeof tmppath - strlen(sysconf); + (void) strncpy(tmppath, executable_path, lth - 1); + tmppath[lth - 1] = '\0'; + (void) strcat(tmppath, sysconf); + + iflags.initoptions_noterminate = 1; + /* assure_syscf_file(); */ + config_error_init(TRUE, tmppath, FALSE); + /* ... and _must_ parse correctly. */ + if (read_config_file(tmppath, set_in_sysconf) + && sysopt.portable_device_paths) + retval = TRUE; + (void) config_error_done(); + iflags.initoptions_noterminate = save_initoptions_noterminate; + sysopt_release(); /* the real sysconf processing comes later */ + } + if (retval) { + lth = strlen(executable_path); + if (lth <= (int) portable_device_path_size - 1) + Strcpy(portable_device_path, executable_path); + else + retval = FALSE; + } + return retval; +} + +static char portable_device_path[MAX_PATH]; + +const char * +get_portable_device(void) +{ + return (const char *) portable_device_path; +} + +void +set_default_prefix_locations(const char *programPath UNUSED) +{ + static char executable_path[MAX_PATH]; + static char profile_path[MAX_PATH]; + static char versioned_profile_path[MAX_PATH]; + static char versioned_user_data_path[MAX_PATH]; + static char versioned_global_data_path[MAX_PATH]; + /* static char versioninfo[20] UNUSED; */ + + strcpy(executable_path, get_executable_path()); + append_slash(executable_path); + + if (test_portable_config(executable_path, portable_device_path, + sizeof portable_device_path)) { + gf.fqn_prefix[SYSCONFPREFIX] = executable_path; + gf.fqn_prefix[CONFIGPREFIX] = portable_device_path; + gf.fqn_prefix[HACKPREFIX] = portable_device_path; + gf.fqn_prefix[SAVEPREFIX] = portable_device_path; + gf.fqn_prefix[LEVELPREFIX] = portable_device_path; + gf.fqn_prefix[BONESPREFIX] = portable_device_path; + gf.fqn_prefix[SCOREPREFIX] = portable_device_path; + gf.fqn_prefix[LOCKPREFIX] = portable_device_path; + gf.fqn_prefix[TROUBLEPREFIX] = portable_device_path; + gf.fqn_prefix[DATAPREFIX] = executable_path; + } else { + if (!build_known_folder_path(&FOLDERID_Profile, profile_path, + sizeof(profile_path), FALSE)) + strcpy(profile_path, executable_path); + + if (!build_known_folder_path(&FOLDERID_Profile, + versioned_profile_path, + sizeof(profile_path), TRUE)) + strcpy(versioned_profile_path, executable_path); + + if (!build_known_folder_path(&FOLDERID_LocalAppData, + versioned_user_data_path, + sizeof(versioned_user_data_path), TRUE)) + strcpy(versioned_user_data_path, executable_path); + + if (!build_known_folder_path( + &FOLDERID_ProgramData, versioned_global_data_path, + sizeof(versioned_global_data_path), TRUE)) + strcpy(versioned_global_data_path, executable_path); + + gf.fqn_prefix[SYSCONFPREFIX] = versioned_global_data_path; + gf.fqn_prefix[CONFIGPREFIX] = profile_path; + gf.fqn_prefix[HACKPREFIX] = versioned_profile_path; + gf.fqn_prefix[SAVEPREFIX] = versioned_user_data_path; + gf.fqn_prefix[LEVELPREFIX] = versioned_user_data_path; + gf.fqn_prefix[BONESPREFIX] = versioned_global_data_path; + gf.fqn_prefix[SCOREPREFIX] = versioned_global_data_path; + gf.fqn_prefix[LOCKPREFIX] = versioned_global_data_path; + gf.fqn_prefix[TROUBLEPREFIX] = versioned_profile_path; + gf.fqn_prefix[DATAPREFIX] = executable_path; + } +} + +/* copy file if destination does not exist */ +void +copy_file(const char *dst_folder, const char *dst_name, + const char *src_folder, const char *src_name, + boolean copy_even_if_it_exists) +{ + char dst_path[MAX_PATH]; + strcpy(dst_path, dst_folder); + strcat(dst_path, dst_name); + + char src_path[MAX_PATH]; + strcpy(src_path, src_folder); + strcat(src_path, src_name); + + if (!file_exists(src_path)) + error("Unable to copy file '%s' as it does not exist", src_path); + + if (file_exists(dst_path) && !copy_even_if_it_exists) + return; + + BOOL success = CopyFileA(src_path, dst_path, !copy_even_if_it_exists); + if (!success) + error("Failed to copy '%s' to '%s' (%d)", src_path, dst_path, errno); +} + +/* update file copying if it does not exist or src is newer then dst */ +void +update_file(const char *dst_folder, const char *dst_name, + const char *src_folder, const char *src_name, BOOL save_copy) +{ + char dst_path[MAX_PATH]; + strcpy(dst_path, dst_folder); + strcat(dst_path, dst_name); + + char src_path[MAX_PATH]; + strcpy(src_path, src_folder); + strcat(src_path, src_name); + + char save_path[MAX_PATH]; + strcpy(save_path, dst_folder); + strcat(save_path, dst_name); + strcat(save_path, ".save"); + + if (!file_exists(src_path)) + error("Unable to copy file '%s' as it does not exist", src_path); + + if (!file_newer(src_path, dst_path)) + return; + + if (file_exists(dst_path) && save_copy) + CopyFileA(dst_path, save_path, FALSE); + + BOOL success = CopyFileA(src_path, dst_path, FALSE); + if (!success) + error("Failed to update '%s' to '%s'", src_path, dst_path); +} + +void +copy_symbols_content(void) +{ + char dst_path[MAX_PATH], interim_path[MAX_PATH], orig_path[MAX_PATH]; + + boolean no_template = FALSE; + + /* Using the SYSCONFPREFIX path, lock it so that it does not change */ + fqn_prefix_locked[SYSCONFPREFIX] = TRUE; + + strcpy(orig_path, gf.fqn_prefix[DATAPREFIX]); + strcat(orig_path, SYMBOLS_TEMPLATE); + strcpy(interim_path, gf.fqn_prefix[SYSCONFPREFIX]); + strcat(interim_path, SYMBOLS_TEMPLATE); + strcpy(dst_path, gf.fqn_prefix[SYSCONFPREFIX]); + strcat(dst_path, SYMBOLS); + + if (!file_exists(orig_path)) { + char alt_orig_path[MAX_PATH]; + + strcpy(alt_orig_path, gf.fqn_prefix[DATAPREFIX]); + strcat(alt_orig_path, SYMBOLS); + if (file_exists(alt_orig_path)) { + no_template = TRUE; + /* symbols -> symbols.template */ + copy_file(gf.fqn_prefix[DATAPREFIX], SYMBOLS_TEMPLATE, + gf.fqn_prefix[DATAPREFIX], SYMBOLS, TRUE); + } + } + if (!file_exists(interim_path) || file_newer(orig_path, interim_path)) { + /* symbols.template -> symbols.template */ + copy_file(gf.fqn_prefix[SYSCONFPREFIX], SYMBOLS_TEMPLATE, + gf.fqn_prefix[DATAPREFIX], SYMBOLS_TEMPLATE, TRUE); + } + if (!file_exists(dst_path) || file_newer(interim_path, dst_path)) { + /* symbols.template -> symbols */ + copy_file(gf.fqn_prefix[SYSCONFPREFIX], SYMBOLS, + gf.fqn_prefix[SYSCONFPREFIX], SYMBOLS_TEMPLATE, TRUE); + } +} + +void +copy_sysconf_content(void) +{ + /* Using the SYSCONFPREFIX path, lock it so that it does not change */ + fqn_prefix_locked[SYSCONFPREFIX] = TRUE; + + update_file(gf.fqn_prefix[SYSCONFPREFIX], SYSCF_TEMPLATE, + gf.fqn_prefix[DATAPREFIX], SYSCF_TEMPLATE, FALSE); + + /* If the required early game file does not exist, copy it */ + copy_file(gf.fqn_prefix[SYSCONFPREFIX], SYSCF_FILE, + gf.fqn_prefix[DATAPREFIX], SYSCF_TEMPLATE, FALSE); +} + +void +copy_config_content(void) +{ + /* Using the CONFIGPREFIX path, lock it so that it does not change */ + fqn_prefix_locked[CONFIGPREFIX] = TRUE; + + /* Keep templates up to date */ + update_file(gf.fqn_prefix[CONFIGPREFIX], CONFIG_TEMPLATE, + gf.fqn_prefix[DATAPREFIX], CONFIG_TEMPLATE, FALSE); + + /* If the required early game file does not exist, copy it */ + /* NOTE: We never replace .nethackrc or sysconf */ + copy_file(gf.fqn_prefix[CONFIGPREFIX], CONFIG_FILE, + gf.fqn_prefix[DATAPREFIX], CONFIG_TEMPLATE, FALSE); +} + +void +copy_hack_content(void) +{ + nhassert(fqn_prefix_locked[HACKPREFIX]); + + /* Keep Guidebook and opthelp up to date */ + update_file(gf.fqn_prefix[HACKPREFIX], GUIDEBOOK_FILE, + gf.fqn_prefix[DATAPREFIX], GUIDEBOOK_FILE, FALSE); + update_file(gf.fqn_prefix[HACKPREFIX], OPTIONFILE, + gf.fqn_prefix[DATAPREFIX], OPTIONFILE, FALSE); +} + #ifdef WIN32CON void safe_routines(void) From fa9210aa652ef50cf806ad11695a2aec682cb5f6 Mon Sep 17 00:00:00 2001 From: nhmall Date: Wed, 13 Nov 2024 13:48:50 -0500 Subject: [PATCH 072/791] Windows: free more allocated memory before exit This gets rid of the final leak complaint on Windows as of Nov 13, 2024 --- win/win32/NetHackW.c | 16 ++++++++++++++-- win/win32/mhmain.c | 4 +++- win/win32/mhmap.c | 2 ++ win/win32/mhmenu.c | 2 ++ win/win32/mhmsgwnd.c | 2 ++ win/win32/mhrip.c | 2 ++ win/win32/mhsplash.c | 2 ++ win/win32/mhstatus.c | 2 ++ win/win32/mhtext.c | 3 +++ win/win32/mswproc.c | 23 +++++++++++++---------- win/win32/winMS.h | 14 ++++++++++++-- 11 files changed, 57 insertions(+), 15 deletions(-) diff --git a/win/win32/NetHackW.c b/win/win32/NetHackW.c index 8a3144083..00a4d1b47 100644 --- a/win/win32/NetHackW.c +++ b/win/win32/NetHackW.c @@ -131,7 +131,7 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, windowprocs.win_wait_synch = mswin_wait_synch; win10_init(); - early_init(0, NULL); /* Change as needed to support CRASHREPORT */ + /* early_init(0, NULL); */ /* Change as needed to support CRASHREPORT */ /* init application structure */ _nethack_app.hApp = hInstance; @@ -166,6 +166,8 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, _nethack_app.bNoHScroll = FALSE; _nethack_app.bNoVScroll = FALSE; + if (_nethack_app.saved_text) + free(_nethack_app.saved_text), _nethack_app.saved_text = 0; _nethack_app.saved_text = strdup(""); _nethack_app.bAutoLayout = TRUE; @@ -257,7 +259,17 @@ free_winmain_stuff(void) for (cnt = 0; cnt < MAX_CMDLINE_PARAM; ++cnt) { if (argv[cnt]) - free((genericptr_t) argv[cnt]); + free((genericptr_t) argv[cnt]), argv[cnt] = 0; + } + if (_nethack_app.saved_text) + free((genericptr_t) _nethack_app.saved_text), + _nethack_app.saved_text = 0; + for (cnt = 0; cnt < MAXWINDOWS; ++cnt) { + if (windowdata[cnt].address) { + if (!windowdata[cnt].isstatic) + free(windowdata[cnt].address); + windowdata[cnt].address = 0; + } } } diff --git a/win/win32/mhmain.c b/win/win32/mhmain.c index bd1a5be79..959917cc6 100644 --- a/win/win32/mhmain.c +++ b/win/win32/mhmain.c @@ -208,9 +208,11 @@ MainWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) data = (PNHMainWindow) malloc(sizeof(NHMainWindow)); if (!data) panic("out of memory"); + ZeroMemory(data, sizeof(NHMainWindow)); data->mapAcsiiModeSave = MAP_MODE_ASCII12x16; SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) data); + windowdata[NHW_MAIN].address = (genericptr_t) data; /* update menu items */ CheckMenuItem( @@ -509,7 +511,7 @@ MainWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) /* clean up */ free((PNHMainWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA)); SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) 0); - + windowdata[NHW_MAIN].address = 0; // PostQuitMessage(0); exit(1); break; diff --git a/win/win32/mhmap.c b/win/win32/mhmap.c index 741cea720..6a5914cc6 100644 --- a/win/win32/mhmap.c +++ b/win/win32/mhmap.c @@ -641,6 +641,7 @@ MapWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) DeleteDC(data->backBufferDC); free(data); SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) 0); + windowdata[NHW_MAP].address = 0; break; case WM_TIMER: @@ -834,6 +835,7 @@ onCreate(HWND hWnd, WPARAM wParam, LPARAM lParam) ReleaseDC(hWnd, hDC); SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) data); + windowdata[NHW_MAP].address = (genericptr_t) data; clearAll(data); diff --git a/win/win32/mhmenu.c b/win/win32/mhmenu.c index dfd7a49c9..41442cc69 100644 --- a/win/win32/mhmenu.c +++ b/win/win32/mhmenu.c @@ -298,6 +298,7 @@ MenuWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) data->bmpDC = CreateCompatibleDC(hdc); data->is_active = FALSE; SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) data); + windowdata[NHW_MENU].address = (genericptr_t) data; } /* set font for the text control */ cached_font * font = mswin_get_font(NHW_MENU, ATR_NONE, hdc, FALSE); @@ -519,6 +520,7 @@ MenuWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) } free(data); SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) 0); + windowdata[NHW_MENU].address = 0; } return TRUE; } diff --git a/win/win32/mhmsgwnd.c b/win/win32/mhmsgwnd.c index 2707facc3..864df34aa 100644 --- a/win/win32/mhmsgwnd.c +++ b/win/win32/mhmsgwnd.c @@ -171,6 +171,7 @@ NHMessageWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) data = (PNHMessageWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA); free(data); SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) 0); + windowdata[NHW_MESSAGE].address = 0; } break; case WM_SIZE: { @@ -729,6 +730,7 @@ onCreate(HWND hWnd, WPARAM wParam, LPARAM lParam) ZeroMemory(data, sizeof(NHMessageWindow)); data->max_text = MAXWINDOWTEXT; SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) data); + windowdata[NHW_MESSAGE].address = (genericptr_t) data; // for cleanup at the end /* re-calculate window size (+ font size) */ mswin_message_window_size(hWnd, &dummy); diff --git a/win/win32/mhrip.c b/win/win32/mhrip.c index 3fb9ac9ba..912bbd9db 100644 --- a/win/win32/mhrip.c +++ b/win/win32/mhrip.c @@ -56,6 +56,7 @@ mswin_init_RIP_window(void) ZeroMemory(data, sizeof(NHRIPWindow)); SetWindowLongPtr(ret, GWLP_USERDATA, (LONG_PTR) data); + windowdata[NHW_RIP].address = (genericptr_t) data; return ret; } @@ -240,6 +241,7 @@ NHRIPWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) DeleteObject(data->rip_bmp); free(data); SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) 0); + windowdata[NHW_RIP].address = 0; } break; } diff --git a/win/win32/mhsplash.c b/win/win32/mhsplash.c index 6d81bd17a..f928cbfc6 100644 --- a/win/win32/mhsplash.c +++ b/win/win32/mhsplash.c @@ -135,6 +135,8 @@ mswin_display_splash_window(BOOL show_ver) mswin_set_splash_data(hWnd, &splashData, monitorInfo.scale); SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) &splashData); + windowdata[NHW_SPLASH].address = (genericptr_t) &splashData; + windowdata[NHW_SPLASH].isstatic = 1; GetNHApp()->hPopupWnd = hWnd; diff --git a/win/win32/mhstatus.c b/win/win32/mhstatus.c index d96992c93..fffbc5100 100644 --- a/win/win32/mhstatus.c +++ b/win/win32/mhstatus.c @@ -127,6 +127,7 @@ mswin_init_status_window(void) if (!data) panic("out of memory"); + windowdata[NHW_STATUS].address = (genericptr_t) data; ZeroMemory(data, sizeof(NHStatusWindow)); SetWindowLongPtr(ret, GWLP_USERDATA, (LONG_PTR) data); @@ -253,6 +254,7 @@ StatusWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) case WM_DESTROY: free(data); SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) 0); + windowdata[NHW_STATUS].address = 0; break; case WM_SETFOCUS: diff --git a/win/win32/mhtext.c b/win/win32/mhtext.c index c51b50eb1..8463a187e 100644 --- a/win/win32/mhtext.c +++ b/win/win32/mhtext.c @@ -83,8 +83,10 @@ NHTextWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) data = (PNHTextWindow)malloc(sizeof(NHTextWindow)); if (!data) panic("out of memory"); + ZeroMemory(data, sizeof(NHTextWindow)); SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)data); + windowdata[NHW_TEXT].address = (genericptr_t) data; // for cleanup at the end HWND control = GetDlgItem(hWnd, IDC_TEXT_CONTROL); HDC hdc = GetDC(control); @@ -173,6 +175,7 @@ NHTextWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) free(data->window_text); free(data); SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) 0); + windowdata[NHW_TEXT].address = 0; } break; diff --git a/win/win32/mswproc.c b/win/win32/mswproc.c index 40bfeb7ba..42abf9a19 100644 --- a/win/win32/mswproc.c +++ b/win/win32/mswproc.c @@ -1021,6 +1021,7 @@ mswin_putstr_ex(winid wid, int attr, const char *text, int app) if (GetNHApp()->windowlist[wid].win != NULL) { MSNHMsgPutstr data; + ZeroMemory(&data, sizeof(data)); data.attr = attr; data.text = text; @@ -2110,30 +2111,32 @@ mswin_preference_update(const char *pref) } } +static PMSNHMsgGetText history_text = 0; +static char *next_message = 0; + char * mswin_getmsghistory(boolean init) { - static PMSNHMsgGetText text = 0; - static char *next_message = 0; - if (init) { - text = (PMSNHMsgGetText) malloc(sizeof(MSNHMsgGetText) + if (history_text) + free((genericptr_t) history_text), history_text = 0; + history_text = (PMSNHMsgGetText) malloc(sizeof(MSNHMsgGetText) + TEXT_BUFFER_SIZE); - if (text) { - text->max_size = + if (history_text) { + history_text->max_size = TEXT_BUFFER_SIZE - 1; /* make sure we always have 0 at the end of the buffer */ - ZeroMemory(text->buffer, TEXT_BUFFER_SIZE); + ZeroMemory(history_text->buffer, TEXT_BUFFER_SIZE); SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE), WM_MSNH_COMMAND, - (WPARAM) MSNH_MSG_GETTEXT, (LPARAM) text); + (WPARAM) MSNH_MSG_GETTEXT, (LPARAM) history_text); - next_message = text->buffer; + next_message = history_text->buffer; } } if (!(next_message && next_message[0])) { - free(text); + free(history_text), history_text = 0; next_message = 0; return (char *) 0; } else { diff --git a/win/win32/winMS.h b/win/win32/winMS.h index 9e92d92ec..6b0170e91 100644 --- a/win/win32/winMS.h +++ b/win/win32/winMS.h @@ -43,8 +43,18 @@ #define MAXWINDOWS 15 #endif -#define NHW_RIP 32 -#define NHW_INVEN 33 +struct window_tracking_data { + genericptr_t address; + int isstatic; +} windowdata[MAXWINDOWS]; + +/* these are only in MSWIN_GRAPHICS, not the core */ +enum mswin_window_types { + NHW_MAIN = (NHW_LAST_TYPE + 1), + NHW_INVEN, + NHW_RIP, + NHW_SPLASH +}; #ifndef TILE_X #define TILE_X 16 From 52a9af72780ee800348d8ba41eb7622393392849 Mon Sep 17 00:00:00 2001 From: nhmall Date: Wed, 13 Nov 2024 13:57:18 -0500 Subject: [PATCH 073/791] early_init() was being called twice on Windows GUI --- sys/windows/windmain.c | 4 +++- win/win32/NetHackW.c | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/sys/windows/windmain.c b/sys/windows/windmain.c index 14cc255a6..0cbded52d 100644 --- a/sys/windows/windmain.c +++ b/sys/windows/windmain.c @@ -179,7 +179,9 @@ MAIN(int argc, char *argv[]) safe_routines(); #endif /* WIN32CON */ - early_init(argc, argv); +#ifndef MSWIN_GRAPHICS + early_init(argc, argv); /* already in WinMain for MSWIN_GRAPHICS */ +#endif /* setting iflags.colorcount has to be after early_init() * because it zeros out all of iflags */ hwnd = GetDesktopWindow(); diff --git a/win/win32/NetHackW.c b/win/win32/NetHackW.c index 00a4d1b47..033dc797c 100644 --- a/win/win32/NetHackW.c +++ b/win/win32/NetHackW.c @@ -131,7 +131,7 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, windowprocs.win_wait_synch = mswin_wait_synch; win10_init(); - /* early_init(0, NULL); */ /* Change as needed to support CRASHREPORT */ + early_init(0, NULL); /* Change as needed to support CRASHREPORT */ /* init application structure */ _nethack_app.hApp = hInstance; From 7ff17845c6c5f7709803708935d65abc14e016e1 Mon Sep 17 00:00:00 2001 From: nhmall Date: Wed, 13 Nov 2024 16:14:49 -0500 Subject: [PATCH 074/791] Windows MSYS2 build fix --- win/win32/mhmain.c | 1 + win/win32/winMS.h | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/win/win32/mhmain.c b/win/win32/mhmain.c index 959917cc6..46a71b7d4 100644 --- a/win/win32/mhmain.c +++ b/win/win32/mhmain.c @@ -25,6 +25,7 @@ extern winid WIN_STATUS; static TCHAR szMainWindowClass[] = TEXT("MSNHMainWndClass"); static TCHAR szTitle[MAX_LOADSTRING]; +struct window_tracking_data windowdata[MAXWINDOWS]; extern void mswin_display_splash_window(BOOL); LRESULT CALLBACK MainWndProc(HWND, UINT, WPARAM, LPARAM); diff --git a/win/win32/winMS.h b/win/win32/winMS.h index 6b0170e91..1cb26aed2 100644 --- a/win/win32/winMS.h +++ b/win/win32/winMS.h @@ -46,7 +46,7 @@ struct window_tracking_data { genericptr_t address; int isstatic; -} windowdata[MAXWINDOWS]; +}; /* these are only in MSWIN_GRAPHICS, not the core */ enum mswin_window_types { @@ -55,6 +55,7 @@ enum mswin_window_types { NHW_RIP, NHW_SPLASH }; +extern struct window_tracking_data windowdata[MAXWINDOWS]; #ifndef TILE_X #define TILE_X 16 From b8083733de458d9eb5c4223879e168fcbba08b4a Mon Sep 17 00:00:00 2001 From: nhmall Date: Wed, 13 Nov 2024 17:14:47 -0500 Subject: [PATCH 075/791] some sys.c orphaned pointer prevention --- src/sys.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/sys.c b/src/sys.c index 6c2ee1b51..ba9b68b6f 100644 --- a/src/sys.c +++ b/src/sys.c @@ -22,21 +22,31 @@ sys_early_init(void) { const char *p; + /* Don't assume that these are not already set, and that it is + * safe to dupstr() without orphaning any pointers. Check them. */ + sysopt.support = (char *) 0; sysopt.recover = (char *) 0; #ifdef SYSCF sysopt.wizards = (char *) 0; #else + if (sysopt.wizards) + free((genericptr_t) sysopt.wizards), sysopt.wizards = (char *) 0; sysopt.wizards = dupstr(WIZARD_NAME); #endif if ((p = getenv("DEBUGFILES")) != 0) { + if (sysopt.debugfiles) + free((genericptr_t) sysopt.debugfiles), + sysopt.debugfiles = (char *) 0; sysopt.debugfiles = dupstr(p); sysopt.env_dbgfl = 1; /* prevent sysconf processing from overriding */ } else { #if defined(SYSCF) || !defined(DEBUGFILES) sysopt.debugfiles = (char *) 0; #else + if (sysopt.debugfiles) + free((genericptr_t) sysopt.debugfiles), sysopt.debugfiles = (char *) 0; sysopt.debugfiles = dupstr(DEBUGFILES); #endif sysopt.env_dbgfl = 0; @@ -67,10 +77,10 @@ sys_early_init(void) #ifdef PANICTRACE /* panic options */ if (sysopt.gdbpath) - free((genericptr_t) sysopt.gdbpath), sysopt.gdbpath = 0; + free((genericptr_t) sysopt.gdbpath), sysopt.gdbpath = (char *) 0; sysopt.gdbpath = dupstr(GDBPATH); if (sysopt.greppath) - free((genericptr_t) sysopt.greppath), sysopt.greppath = 0; + free((genericptr_t) sysopt.greppath), sysopt.greppath = (char *) 0; sysopt.greppath = dupstr(GREPPATH); #if (NH_DEVEL_STATUS != NH_STATUS_RELEASED) sysopt.panictrace_gdb = 1; @@ -128,7 +138,7 @@ sysopt_release(void) #endif if (sysopt.genericusers) free((genericptr_t) sysopt.genericusers), - sysopt.genericusers = (char *) 0; + sysopt.genericusers = (char *) 0; if (sysopt.gdbpath) free((genericptr_t) sysopt.gdbpath), sysopt.gdbpath = (char *) 0; if (sysopt.greppath) @@ -138,7 +148,7 @@ sysopt_release(void) none of the preceding ones are likely to trigger a controlled panic */ if (sysopt.fmtd_wizard_list) free((genericptr_t) sysopt.fmtd_wizard_list), - sysopt.fmtd_wizard_list = (char *) 0; + sysopt.fmtd_wizard_list = (char *) 0; return; } From c7591c0e0830d6fb278433a35b7b2f555326280d Mon Sep 17 00:00:00 2001 From: nhmall Date: Wed, 13 Nov 2024 17:36:47 -0500 Subject: [PATCH 076/791] remove redundant zeroing --- src/sys.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/sys.c b/src/sys.c index ba9b68b6f..41710bfbb 100644 --- a/src/sys.c +++ b/src/sys.c @@ -31,14 +31,13 @@ sys_early_init(void) sysopt.wizards = (char *) 0; #else if (sysopt.wizards) - free((genericptr_t) sysopt.wizards), sysopt.wizards = (char *) 0; + free((genericptr_t) sysopt.wizards); sysopt.wizards = dupstr(WIZARD_NAME); #endif if ((p = getenv("DEBUGFILES")) != 0) { if (sysopt.debugfiles) - free((genericptr_t) sysopt.debugfiles), - sysopt.debugfiles = (char *) 0; + free((genericptr_t) sysopt.debugfiles); sysopt.debugfiles = dupstr(p); sysopt.env_dbgfl = 1; /* prevent sysconf processing from overriding */ } else { @@ -46,7 +45,7 @@ sys_early_init(void) sysopt.debugfiles = (char *) 0; #else if (sysopt.debugfiles) - free((genericptr_t) sysopt.debugfiles), sysopt.debugfiles = (char *) 0; + free((genericptr_t) sysopt.debugfiles); sysopt.debugfiles = dupstr(DEBUGFILES); #endif sysopt.env_dbgfl = 0; @@ -77,10 +76,10 @@ sys_early_init(void) #ifdef PANICTRACE /* panic options */ if (sysopt.gdbpath) - free((genericptr_t) sysopt.gdbpath), sysopt.gdbpath = (char *) 0; + free((genericptr_t) sysopt.gdbpath); sysopt.gdbpath = dupstr(GDBPATH); if (sysopt.greppath) - free((genericptr_t) sysopt.greppath), sysopt.greppath = (char *) 0; + free((genericptr_t) sysopt.greppath); sysopt.greppath = dupstr(GREPPATH); #if (NH_DEVEL_STATUS != NH_STATUS_RELEASED) sysopt.panictrace_gdb = 1; From 62971c6f09e73402fca9e55093e1104b9dc0f9fd Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Thu, 14 Nov 2024 17:24:59 +0200 Subject: [PATCH 077/791] Qt: add support for the palette config option Depends on CHANGE_COLOR compile-time option. --- doc/fixes3-7-0.txt | 2 +- win/Qt/qt_bind.cpp | 71 ++++++++++++++++++++++++++++++++++++++++++++-- win/Qt/qt_bind.h | 3 ++ win/Qt/qt_map.cpp | 47 ++---------------------------- win/Qt/qt_menu.cpp | 62 ++-------------------------------------- 5 files changed, 77 insertions(+), 108 deletions(-) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index 0c160a176..cf880e758 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -2207,7 +2207,7 @@ curses: if user's terminal was set to 'application keypad mode' (DEC VTxxx "ESC SPC G"), nethack wasn't recognizing number pad keys curses: change petattr attributes, dropping support for curses-only ones curses: swap the grey and no-color color initialization -curses: allow changing default colors with the 'palette' config option +curses+Qt: allow changing default colors with the 'palette' config option (only if compiled with CHANGE_COLOR) curses: if messages have been issued during start-up (for instance, warnings about issues in run-time config file), prompt user to press diff --git a/win/Qt/qt_bind.cpp b/win/Qt/qt_bind.cpp index d0128cc62..d66377f3b 100644 --- a/win/Qt/qt_bind.cpp +++ b/win/Qt/qt_bind.cpp @@ -70,6 +70,8 @@ static struct key_macro_rec { { 0, 0U, (const char *) 0, (const char *) 0 } }; +static QPen *pen = (QPen *) 0; + NetHackQtBind::NetHackQtBind(int& argc, char** argv) : #ifdef KDE KApplication(argc,argv) @@ -578,6 +580,45 @@ void NetHackQtBind::qt_raw_print_bold(const char *str) qt_raw_print(str); } +const QPen NetHackQtBind::nhcolor_to_pen(uint32_t c) +{ + if (!pen) { + pen = new QPen[17]; + + pen[ 0] = QColor(64, 64, 64); // black + pen[ 1] = QColor(Qt::red); + pen[ 2] = QColor(0, 191, 0); // green + pen[ 3] = QColor(127, 127, 0); // brownish + pen[ 4] = QColor(Qt::blue); + pen[ 5] = QColor(Qt::magenta); + pen[ 6] = QColor(Qt::cyan); + pen[ 7] = QColor(Qt::gray); + // on tty, "light" variations are "bright" instead; here they're paler + pen[ 8] = QColor(Qt::white); // no color + pen[ 9] = QColor(255, 127, 0); // orange + pen[10] = QColor(127, 255, 127); // light green + pen[11] = QColor(Qt::yellow); + pen[12] = QColor(127, 127, 255); // light blue + pen[13] = QColor(255, 127, 255); // light magenta + pen[14] = QColor(127, 255, 255); // light cyan + pen[15] = QColor(Qt::white); + // ? out of range for 0..15 + pen[16] = QColor(Qt::black); + } + +#ifdef ENHANCED_SYMBOLS + if (c & 0x80000000) { + return QColor( + (c >> 16) & 0xFF, + (c >> 8) & 0xFF, + (c >> 0) & 0xFF); + } else +#endif + { + return pen[c]; + } +} + int NetHackQtBind::qt_nhgetch() { if (main) @@ -901,6 +942,28 @@ void NetHackQtBind::qt_delay_output() #endif } +#ifdef CHANGE_COLOR +void NetHackQtBind::qt_change_color(int color, long rgb, int reverse UNUSED) +{ + int r, g, b; + + r = (rgb >> 16) & 0xFF; + g = (rgb >> 8) & 0xFF; + b = rgb & 0xFF; + if (!pen) { + (void) NetHackQtBind::nhcolor_to_pen(0); /* init pen[] */ + } + pen[color % 16] = QColor(r, g, b); +} + +char * +NetHackQtBind::qt_get_color_string(void) +{ + return (char *) 0; +} + +#endif + void NetHackQtBind::qt_start_screen() { // Ignore. @@ -1158,11 +1221,13 @@ struct window_procs Qt_procs = { nethack_qt_::NetHackQtBind::qt_get_ext_cmd, nethack_qt_::NetHackQtBind::qt_number_pad, nethack_qt_::NetHackQtBind::qt_delay_output, -#ifdef CHANGE_COLOR /* only a Mac option currently */ - donull, - donull, +#ifdef CHANGE_COLOR + nethack_qt_::NetHackQtBind::qt_change_color, +#ifdef MAC /* old OS 9, not OSX */ donull, donull, +#endif + nethack_qt_::NetHackQtBind::qt_get_color_string, #endif /* other defs that really should go away (they're tty specific) */ nethack_qt_::NetHackQtBind::qt_start_screen, diff --git a/win/Qt/qt_bind.h b/win/Qt/qt_bind.h index b0b9f4f3a..6535e637b 100644 --- a/win/Qt/qt_bind.h +++ b/win/Qt/qt_bind.h @@ -71,6 +71,9 @@ public: const glyph_info *bkglyphinfo); static void qt_raw_print(const char *str); static void qt_raw_print_bold(const char *str); + static const QPen nhcolor_to_pen(uint32_t c); + static void qt_change_color(int color, long rgb, int reverse UNUSED); + static char *qt_get_color_string(void); static int qt_nhgetch(); static int qt_nh_poskey(coordxy *x, coordxy *y, int *mod); static void qt_nhbell(); diff --git a/win/Qt/qt_map.cpp b/win/Qt/qt_map.cpp index a2162504f..85817dabf 100644 --- a/win/Qt/qt_map.cpp +++ b/win/Qt/qt_map.cpp @@ -77,47 +77,6 @@ extern int qt_compact_mode; namespace nethack_qt_ { -static const QPen nhcolor_to_pen(uint32_t c) -{ - static QPen *pen = (QPen *) 0; - if (!pen) { - pen = new QPen[17]; - // - // FIXME: these are duplicated in qt_menu.cpp - // - pen[ 0] = QColor(64, 64, 64); // black - pen[ 1] = QColor(Qt::red); - pen[ 2] = QColor(0, 191, 0); // green - pen[ 3] = QColor(127, 127, 0); // brownish - pen[ 4] = QColor(Qt::blue); - pen[ 5] = QColor(Qt::magenta); - pen[ 6] = QColor(Qt::cyan); - pen[ 7] = QColor(Qt::gray); - // on tty, "light" variations are "bright" instead; here they're paler - pen[ 8] = QColor(Qt::white); // no color - pen[ 9] = QColor(255, 127, 0); // orange - pen[10] = QColor(127, 255, 127); // light green - pen[11] = QColor(Qt::yellow); - pen[12] = QColor(127, 127, 255); // light blue - pen[13] = QColor(255, 127, 255); // light magenta - pen[14] = QColor(127, 255, 255); // light cyan - pen[15] = QColor(Qt::white); - // ? out of range for 0..15 - pen[16] = QColor(Qt::black); - } - -#ifdef ENHANCED_SYMBOLS - if (c & 0x80000000) { - return QColor( - (c >> 16) & 0xFF, - (c >> 8) & 0xFF, - (c >> 0) & 0xFF); - } else -#endif - { - return pen[c]; - } -} NetHackQtMapViewport::NetHackQtMapViewport(NetHackQtClickBuffer& click_sink) : QWidget(NULL), @@ -202,7 +161,7 @@ void NetHackQtMapViewport::paintEvent(QPaintEvent* event) ch = cp437(ch); } color = Glyphcolor(i, j); - painter.setPen(nhcolor_to_pen(color)); + painter.setPen(NetHackQtBind::nhcolor_to_pen(color)); if (!DrawWalls(painter, i * gW, j * gH, gW, gH, ch)) { ushort utf16[3]; if (ch < 0x10000) { @@ -226,7 +185,7 @@ void NetHackQtMapViewport::paintEvent(QPaintEvent* event) } framecolor = GlyphFramecolor(i, j); if (framecolor != NO_COLOR) { - painter.setPen(nhcolor_to_pen(framecolor)); + painter.setPen(NetHackQtBind::nhcolor_to_pen(framecolor)); painter.drawRect(i * qt_settings->glyphs().width(), j * qt_settings->glyphs().height(), qt_settings->glyphs().width() - 1, @@ -255,7 +214,7 @@ void NetHackQtMapViewport::paintEvent(QPaintEvent* event) } framecolor = GlyphFramecolor(i, j); if (framecolor != NO_COLOR) { - painter.setPen(nhcolor_to_pen(framecolor)); + painter.setPen(NetHackQtBind::nhcolor_to_pen(framecolor)); painter.drawRect(i * qt_settings->glyphs().width(), j * qt_settings->glyphs().height(), qt_settings->glyphs().width() - 1, diff --git a/win/Qt/qt_menu.cpp b/win/Qt/qt_menu.cpp index 6a0e7a524..69ab6b747 100644 --- a/win/Qt/qt_menu.cpp +++ b/win/Qt/qt_menu.cpp @@ -483,69 +483,11 @@ void NetHackQtMenuWindow::UpdateCountColumn(long newcount) table->repaint(); } -struct qcolor { - QColor q; - const char *nm; -}; -// these match the tty colors, or better versions of same; -// [0] is used for black, and [8] (the first white) corresponds to "no color" -static const struct qcolor colors[] = { - { QColor(64, 64, 64), "64,64,64" }, // black - { QColor(Qt::red), "red" }, - { QColor(0, 191, 0), "0,191,0" }, // green - { QColor(127, 127, 0), "127,127,0" }, // brownish - { QColor(Qt::blue), "blue" }, - { QColor(Qt::magenta), "magenta" }, - { QColor(Qt::cyan), "cyan" }, - { QColor(Qt::gray), "gray" }, - // on tty, the "light" variations are "bright" instead; here they're paler - { QColor(Qt::white), "white" }, // no-color, so not rendered - { QColor(255, 127, 0), "255,127,0" }, // orange - { QColor(127, 255, 127), "127,255,127" }, // light green - { QColor(Qt::yellow), "yellow" }, - { QColor(127, 127, 255), "127,127,255" }, // light blue - { QColor(255, 127, 255), "255,127,255" }, // light magenta - { QColor(127, 255, 255), "127,255,255" }, // light cyan - { QColor(Qt::white), "white" }, -}; - -#if 0 /* available for debugging */ -static const char *color_name(const QColor q) -{ - for (int i = 0; i < SIZE(colors); ++i) - if (q == colors[i].q) - return colors[i].nm; - // these are all the enum GlobalColor values ; - // black and white have been moved in front of color0 and color1 here - const char *nm = (q == Qt::black) ? "black" - : (q == Qt::white) ? "white" - : (q == Qt::color0) ? "color0" // doesn't duplicate white? - : (q == Qt::color1) ? "color1" // does duplicate black - : (q == Qt::darkGray) ? "darkGray" - : (q == Qt::gray) ? "gray" - : (q == Qt::lightGray) ? "lightGray" - : (q == Qt::red) ? "red" - : (q == Qt::green) ? "green" - : (q == Qt::blue) ? "blue" - : (q == Qt::cyan) ? "cyan" - : (q == Qt::magenta) ? "magenta" - : (q == Qt::yellow) ? "yellow" - : (q == Qt::darkRed) ? "darkRed" - : (q == Qt::darkGreen) ? "darkGreen" - : (q == Qt::darkBlue) ? "darkBlue" - : (q == Qt::darkCyan) ? "darkCyan" - : (q == Qt::darkMagenta) ? "darkMagenta" - : (q == Qt::darkYellow) ? "darkYellow" - : (q == Qt::transparent) ? "transparent" - : "other"; - return nm; -} -#endif - void NetHackQtMenuWindow::SetTwiAttr(QTableWidgetItem *twi, int color, int attr) { if (color != NO_COLOR) { - twi->setForeground(colors[color].q); + const QPen qp = NetHackQtBind::nhcolor_to_pen(color); + twi->setForeground(qp.color()); } if (attr != ATR_NONE) { From 13db1aed0d8d22652c65408ff14f71b1d1abdcda Mon Sep 17 00:00:00 2001 From: nhmall Date: Thu, 14 Nov 2024 11:54:39 -0500 Subject: [PATCH 078/791] replace stray tabs that have crept in --- include/config.h | 2 +- src/date.c | 2 +- src/options.c | 2 +- src/report.c | 2 +- sys/libnh/libnhmain.c | 6 +++--- sys/unix/unixmain.c | 10 +++++----- sys/windows/consoletty.c | 2 +- sys/windows/win10.h | 2 +- 8 files changed, 14 insertions(+), 14 deletions(-) diff --git a/include/config.h b/include/config.h index 1c728d459..8752feb39 100644 --- a/include/config.h +++ b/include/config.h @@ -266,7 +266,7 @@ #ifdef CRASHREPORT # ifndef DUMPLOG_CORE -# define DUMPLOG_CORE // required to get ^P info +# define DUMPLOG_CORE // required to get ^P info # endif # ifdef MACOS # define PANICTRACE diff --git a/src/date.c b/src/date.c index aef985e75..f4b96fdb0 100644 --- a/src/date.c +++ b/src/date.c @@ -29,7 +29,7 @@ struct nomakedefs_s nomakedefs = { "Version 1.0, built Jul 28 13:18:57 1987.", (const char *) 0, /* git_sha */ (const char *) 0, /* git_branch */ - (const char *) 0, /* git_prefix */ + (const char *) 0, /* git_prefix */ "1.0.0-0", "NetHack Version 1.0.0-0 - last build Tue Jul 28 13:18:57 1987.", 0x01010000UL, diff --git a/src/options.c b/src/options.c index e9da50d52..84d1f7d70 100644 --- a/src/options.c +++ b/src/options.c @@ -6951,7 +6951,7 @@ initoptions_init(void) int i; boolean have_branch = (nomakedefs.git_branch && *nomakedefs.git_branch); - go.opt_phase = builtin_opt; // Did I need to move this here? + go.opt_phase = builtin_opt; /* Did I need to move this here? */ memcpy(allopt, allopt_init, sizeof(allopt)); determine_ambiguities(); diff --git a/src/report.c b/src/report.c index 890b3fdca..5be3e93dd 100644 --- a/src/report.c +++ b/src/report.c @@ -220,7 +220,7 @@ crashreport_bidshow(void) mark = uend; \ if (utmp >= urem) \ goto full; \ - memcpy(uend, str, utmp); \ + memcpy(uend, str, utmp); \ uend += utmp; urem -= utmp; \ *uend = '\0'; diff --git a/sys/libnh/libnhmain.c b/sys/libnh/libnhmain.c index d43cdc362..81ae866cb 100644 --- a/sys/libnh/libnhmain.c +++ b/sys/libnh/libnhmain.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 libnhmain.c $NHDT-Date: 1693359589 2023/08/30 01:39:49 $ $NHDT-Branch: keni-crashweb2 $:$NHDT-Revision: 1.106 $ */ +/* NetHack 3.7 libnhmain.c $NHDT-Date: 1693359589 2023/08/30 01:39:49 $ $NHDT-Branch: keni-crashweb2 $:$NHDT-Revision: 1.106 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2011. */ /* NetHack may be freely redistributed. See license for details. */ @@ -103,8 +103,8 @@ nhmain(int argc, char *argv[]) exit(EXIT_SUCCESS); #ifdef CRASHREPORT - if (argcheck(argc, argv, ARG_BIDSHOW)) - exit(EXIT_SUCCESS); + if (argcheck(argc, argv, ARG_BIDSHOW)) + exit(EXIT_SUCCESS); #endif if (argcheck(argc, argv, ARG_SHOWPATHS) == 2) { diff --git a/sys/unix/unixmain.c b/sys/unix/unixmain.c index 679f5e627..2da734fd0 100644 --- a/sys/unix/unixmain.c +++ b/sys/unix/unixmain.c @@ -644,15 +644,15 @@ early_options(int *argc_p, char ***argv_p, char **hackdir_p) ++arg; switch (arg[1]) { /* char after leading dash */ - case 'b': + case 'b': #ifdef CRASHREPORT - // --bidshow - if (argcheck(argc, argv, ARG_BIDSHOW) == 2){ + // --bidshow + if (argcheck(argc, argv, ARG_BIDSHOW) == 2){ opt_terminate(); /*NOTREACHED*/ - } + } #endif - break; + break; case 'd': if (argcheck(argc, argv, ARG_DEBUG) == 1) { consume_arg(ndx, argc_p, argv_p), consumed = 1; diff --git a/sys/windows/consoletty.c b/sys/windows/consoletty.c index d1cbfbbca..5f624bec8 100644 --- a/sys/windows/consoletty.c +++ b/sys/windows/consoletty.c @@ -300,7 +300,7 @@ static INPUT_RECORD bogus_key; /* Windows console palette: Color Name Console Legacy RGB Values New Default RGB Values -BLACK 0,0,0 12,12,12 +BLACK 0,0,0 12,12,12 DARK_BLUE 0,0,128 0,55,218 DARK_GREEN 0,128,0 19,161,14 DARK_CYAN 0,128,128 58,150,221 diff --git a/sys/windows/win10.h b/sys/windows/win10.h index 22a4c0f12..cc8a0bf48 100644 --- a/sys/windows/win10.h +++ b/sys/windows/win10.h @@ -1,5 +1,5 @@ /* NetHack 3.7 win10.h $NHDT-Date: 1596498319 2020/08/03 23:45:19 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.8 $ */ -/* Copyright (C) 2018 by Bart House */ +/* Copyright (C) 2018 by Bart House */ /* NetHack may be freely redistributed. See license for details. */ #ifndef WIN10_H From aba2bda1595ac01a54c5ce59caa7b2bb5b329b9d Mon Sep 17 00:00:00 2001 From: SHIRAKATA Kentaro Date: Sat, 16 Nov 2024 04:05:44 +0900 Subject: [PATCH 079/791] split eval_offering() into a separate function --- src/pray.c | 128 +++++++++++++++++++++++++++++++---------------------- 1 file changed, 74 insertions(+), 54 deletions(-) diff --git a/src/pray.c b/src/pray.c index e5dc55baa..501c9e293 100644 --- a/src/pray.c +++ b/src/pray.c @@ -29,6 +29,7 @@ staticfn void offer_different_alignment_altar(struct obj *, aligntyp); staticfn void sacrifice_your_race(struct obj *, boolean, aligntyp); staticfn int bestow_artifact(void); staticfn int sacrifice_value(struct obj *); +staticfn int eval_offering(struct obj *, aligntyp); staticfn void offer_corpse(struct obj *, boolean, aligntyp); staticfn boolean pray_revive(void); staticfn boolean water_prayer(boolean); @@ -1874,63 +1875,19 @@ dosacrifice(void) return ECMD_TIME; } -staticfn void -offer_corpse(struct obj *otmp, boolean highaltar, aligntyp altaralign) +staticfn int +eval_offering(struct obj *otmp, aligntyp altaralign) { - int value; struct permonst *ptr; - struct monst *mtmp; - - /* - * Was based on nutritional value and aging behavior (< 50 moves). - * Sacrificing a food ration got you max luck instantly, making the - * gods as easy to please as an angry dog! - * - * Now only accepts corpses, based on the game's evaluation of their - * toughness. Human and pet sacrifice, as well as sacrificing unicorns - * of your alignment, is strongly discouraged. - */ -#define MAXVALUE 24 /* Highest corpse value (besides Wiz) */ - - ptr = &mons[otmp->corpsenm]; - - /* KMH, conduct */ - if (!u.uconduct.gnostic++) - livelog_printf(LL_CONDUCT, "rejected atheism" - " by offering %s on an altar of %s", - corpse_xname(otmp, (const char *) 0, CXN_ARTICLE), - a_gname()); - - /* you're handling this corpse, even if it was killed upon the altar - */ - feel_cockatrice(otmp, TRUE); - if (rider_corpse_revival(otmp, FALSE)) - return; + int value; value = sacrifice_value(otmp); - /* same race or former pet results apply even if the corpse is - too old (value==0) */ - if (your_race(ptr)) { - sacrifice_your_race(otmp, highaltar, altaralign); - return; - } - if (has_omonst(otmp) - && (mtmp = get_mtraits(otmp, FALSE)) != 0 - && mtmp->mtame) { - /* mtmp is a temporary pointer to a tame monster's attributes, - * not a real monster */ - pline("So this is how you repay loyalty?"); - adjalign(-3); - HAggravate_monster |= FROMOUTSIDE; - offer_negative_valued(highaltar, altaralign); - return; - } - if (!value) { - /* too old; don't give undead or unicorn bonus or penalty */ - pline1(nothing_happens); - return; - } + if (!value) + return 0; + + ptr = &mons[otmp->corpsenm]; + if (is_undead(ptr)) { /* Not demons--no demon corpses */ /* most undead that leave a corpse yield 'human' (or other race) corpse so won't get here; the exception is wraith; give the @@ -1950,8 +1907,7 @@ offer_corpse(struct obj *otmp, boolean highaltar, aligntyp altaralign) (unicalign == A_CHAOTIC) ? "chaos" : unicalign ? "law" : "balance"); (void) adjattrib(A_WIS, -1, TRUE); - offer_negative_valued(highaltar, altaralign); - return; + return -1; } else if (u.ualign.type == altaralign) { /* When different from altar, and altar is same as yours, * it's a very good action. @@ -1976,6 +1932,70 @@ offer_corpse(struct obj *otmp, boolean highaltar, aligntyp altaralign) value += 3; } } + return value; +} + +staticfn void +offer_corpse(struct obj *otmp, boolean highaltar, aligntyp altaralign) +{ + int value; + struct permonst *ptr; + struct monst *mtmp; + + /* + * Was based on nutritional value and aging behavior (< 50 moves). + * Sacrificing a food ration got you max luck instantly, making the + * gods as easy to please as an angry dog! + * + * Now only accepts corpses, based on the game's evaluation of their + * toughness. Human and pet sacrifice, as well as sacrificing unicorns + * of your alignment, is strongly discouraged. + */ +#define MAXVALUE 24 /* Highest corpse value (besides Wiz) */ + + /* KMH, conduct */ + if (!u.uconduct.gnostic++) + livelog_printf(LL_CONDUCT, "rejected atheism" + " by offering %s on an altar of %s", + corpse_xname(otmp, (const char *) 0, CXN_ARTICLE), + a_gname()); + + /* you're handling this corpse, even if it was killed upon the altar + */ + feel_cockatrice(otmp, TRUE); + if (rider_corpse_revival(otmp, FALSE)) + return; + + ptr = &mons[otmp->corpsenm]; + + /* same race or former pet results apply even if the corpse is + too old (value==0) */ + if (your_race(ptr)) { + sacrifice_your_race(otmp, highaltar, altaralign); + return; + } + if (has_omonst(otmp) + && (mtmp = get_mtraits(otmp, FALSE)) != 0 + && mtmp->mtame) { + /* mtmp is a temporary pointer to a tame monster's attributes, + * not a real monster */ + pline("So this is how you repay loyalty?"); + adjalign(-3); + HAggravate_monster |= FROMOUTSIDE; + offer_negative_valued(highaltar, altaralign); + return; + } + + value = eval_offering(otmp, altaralign); + if (value == 0) { + /* too old; don't give undead or unicorn bonus or penalty */ + pline1(nothing_happens); + return; + } + if (value < 0) { + offer_negative_valued(highaltar, altaralign); + return; + } if (altaralign != u.ualign.type && highaltar) { desecrate_altar(highaltar, altaralign); From d493d31aeca8e8d1a4ab9efae89cb5b7cfee9a7c Mon Sep 17 00:00:00 2001 From: nhkeni Date: Fri, 15 Nov 2024 19:00:31 -0500 Subject: [PATCH 080/791] Remove "*.txt NHSUBST" from .gitattributes because it's too general. Specifically, it was marking Guidebook.txt for substitution, but it's a derived file, not a source. --- doc/.gitattributes | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/.gitattributes b/doc/.gitattributes index f4d35defc..5edfa047f 100644 --- a/doc/.gitattributes +++ b/doc/.gitattributes @@ -3,7 +3,6 @@ *.6 NHSUBST *.7 NHSUBST fixes* NHSUBST -*.txt NHSUBST config.nh NHSUBST Guidebook.txt NH_header=no tmac.n NH_header=no From 21b495f8359996c9b18733f74b8216383cdf837a Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 16 Nov 2024 10:10:10 -0500 Subject: [PATCH 081/791] Makefile.nmake build fix when no curses options Resolves #1325 --- sys/windows/Makefile.nmake | 42 +++++++++++++++++++++++++++++++------- 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/sys/windows/Makefile.nmake b/sys/windows/Makefile.nmake index 4df6112c2..93a9c5656 100644 --- a/sys/windows/Makefile.nmake +++ b/sys/windows/Makefile.nmake @@ -231,6 +231,13 @@ WANT_CURSES=Y WANT_CURSES=Y !ENDIF +!IF "$(CURSES_CONSOLE)" != "Y" +!IF "$(CURSES_GRAPHICAL)" != "Y" +WANT_CURSES=N +ADD_CURSES=N +!ENDIF +!ENDIF + # Now, pdcursesmod !IF "$(WANT_CURSES)" == "Y" PDCDIST=pdcursesmod @@ -484,7 +491,13 @@ PDCINCL = /I$(PDCURSES_TOP) /I$(PDCSRC) PDCINCLGUI = /I$(PDCWINCON) PDCINCLCON = /I$(PDCWINGUI) !ELSE -PDCDEP = +PDCDEP= +PDCCOMMONOBJS= +PDCWINCONOBJS= +PDCWINGUIOBJS= +PDCINCL= +PDINCLGUI= +PDCINCLCON= !ENDIF @@ -626,7 +639,8 @@ CURSESDEF1=-D"CURSES_GRAPHICS" -DPDC_NCMOUSE CURSESDEF2=-DCURSES_UNICODE $(PDCURSESFLAGS) !ENDIF !ELSE -!UNDEF CURSDEF +!UNDEF CURSDEF1 +!UNDEF CURSDEF2 !UNDEF CURSESLIB !UNDEF CURSESOBJ !UNDEF CURSESWINCONOBJS @@ -1298,15 +1312,17 @@ DLB = #========================================== # Rules for files in win\curses #========================================== - +!IF "$(ADD_CURSES)" == "Y" {$(WCURSES)}.c{$(OBJTTY)}.o: $(Q)$(CC) $(PDCINCL) $(CFLAGS) $(CURSESDEF1) $(CURSESDEF2) $(TTYDEF) $(GUIDEF) $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) -Fo$@ $< +!ENDIF #========================================== # Rules for files in PDCurses #========================================== # +!IF "$(ADD_CURSES)" == "Y" {$(PDCURSES_TOP)}.c{$(OBJPDC)}.o: $(Q)$(CC) /wd4244 $(PDCINCL) $(CFLAGS) $(CURSESDEF2) $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) -Fo$@ $< @@ -1318,6 +1334,7 @@ DLB = {$(PDCWINGUI)}.c{$(OBJPDCG)}.o: $(Q)$(CC) /wd4244 /wd4267 /wd4774 $(PDCINCL) $(PDCINCLGUI) $(CFLAGS) $(CURSESDEF2) $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) -Fo$@ $< +!ENDIF #========================================== # Rules for LUA files @@ -1375,11 +1392,12 @@ $(LUASRC)\lua.h: # git submodule update --remote ../submodules/lua # #aka PDCDEP +!IF "$(ADD_CURSES)" == "Y" $(PDCURSES_TOP)\curses.h: git submodule init ../submodules/$(PDCDIST) git submodule update ../submodules/$(PDCDIST) # git submodule update --remote ../submodules/$(PDCDIST) - +!ENDIF !ELSE # GIT_AVAILABLE no CURLLUASRC=http://www.lua.org/ftp/lua-5.4.6.tar.gz CURLLUADST=lua-5.4.6.tar.gz @@ -1394,6 +1412,7 @@ $(LUASRC)\lua.h: curl -L $(CURLLUASRC) -o $(CURLLUADST) tar -xvf $(CURLLUADST) cd ..\src +!IF "$(ADD_CURSES)" == "Y" $(PDCURSES_TOP)\curses.h: @if not exist $(LIBDIR)\*.* mkdir $(LIBDIR) cd $(LIBDIR) @@ -1401,10 +1420,13 @@ $(PDCURSES_TOP)\curses.h: if not exist $(PDCDIST)\*.* mkdir $(PDCDIST) tar -C $(PDCDIST) --strip-components=1 -xvf $(CURLPDCDST) cd ..\src +!ENDIF # ADD_CURSES !ENDIF # GIT_AVAILABLE !ELSE # INTERNET_AVAILABLE $(LUASRC)\lua.h: +!IF "$(ADD_CURSES)" == "Y" $(PDCURSES_TOP)\curses.h: +!ENDIF !ENDIF # INTERNET_AVAILABLE #========================================== @@ -1769,7 +1791,7 @@ pkgdir.tag: envchk.tag: cpu.tag !IFDEF TTYOBJ @echo tty window support included -! IF "$(ADD_CURSES)"=="Y" +! IF "$(ADD_CURSES)" == "Y" @echo curses window support also included ! ENDIF !ENDIF @@ -1805,6 +1827,7 @@ fetch-actual-Lua: cd ..\src @echo Lua has been fetched into $(LIBDIR)\lua-$(LUAVER) +!IF "$(ADD_CURSES)" == "Y" fetch-pdcurses: @if not exist $(LIBDIR)\*.* mkdir $(LIBDIR) cd $(LIBDIR) @@ -1818,6 +1841,7 @@ fetch-pdcurses: if exist .\$(PDCDIST).zip del .\$(PDCDIST).zip cd ..\src @echo $(PDCDIST) has been fetched into $(LIBDIR)\$(PDCDIST) +!ENDIF #========================================== # DLB utility and nhdatNNN file creation @@ -2023,14 +2047,18 @@ $(SRC)\x11tiles: $(U)tile2x11.exe $(WSHR)\monsters.txt $(WSHR)\objects.txt \ #=============================================================================== # PDCurses #=============================================================================== - +!IF "$(ADD_CURSES)" == "Y" +!IF "$(CURSES_CONSOLE)" == "Y" $(PDCWINCONLIB) : $(PDCCOMMONOBJS) $(PDCWINCONOBJS) @echo Building library $@ from $** @$(librarian) -nologo /out:$@ $(PDCCOMMONOBJS) $(PDCWINCONOBJS) +!ENDIF +!IF "$(CURSES_CONSOLE)" == "Y" $(PDCWINGUILIB) : $(PDCCOMMONOBJS) $(PDCWINGUIOBJS) @echo Building library $@ from $** @$(librarian) -nologo /out:$@ $(PDCCOMMONOBJS) $(PDCWINGUIOBJS) - +!ENDIF +!ENDIF $(OGUI)guitty.o: $(MSWSYS)\guitty.c $(WINDHDR) $(HACK_H) $(TILE_H) #=============================================================================== From 793249745006c54b9d9752bf7fc7247ae1c904c6 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 16 Nov 2024 10:45:22 -0500 Subject: [PATCH 082/791] follow-up for Makefile.nmake --- sys/windows/Makefile.nmake | 39 ++++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/sys/windows/Makefile.nmake b/sys/windows/Makefile.nmake index 93a9c5656..50775c8c0 100644 --- a/sys/windows/Makefile.nmake +++ b/sys/windows/Makefile.nmake @@ -466,8 +466,12 @@ PDCURSES_CURSES_H = $(PDCURSES_TOP)\curses.h PDCURSES_CURSPRIV_H = $(PDCURSES_TOP)\curspriv.h PDCURSES_HEADERS = $(PDCURSES_CURSES_H) $(PDCURSES_CURSPRIV_H) PDCSRC = $(PDCURSES_TOP)\pdcurses +!IF "$(CURSES_CONSOLE)" == "Y" PDCWINCON = $(PDCURSES_TOP)\wincon +!ENDIF +!IF "$(CURSES_GRAPHICAL)" == "Y" PDCWINGUI = $(PDCURSES_TOP)\wingui +!ENDIF PDCDEP = $(PDCURSES_TOP)\curses.h PDCCOMMONOBJS = $(OPDC)addch.o $(OPDC)addchstr.o $(OPDC)addstr.o $(OPDC)attr.o $(OPDC)beep.o \ @@ -481,15 +485,17 @@ PDCCOMMONOBJS = $(OPDC)addch.o $(OPDC)addchstr.o $(OPDC)addstr.o $(OPDC)attr.o $ $(OPDC)scroll.o $(OPDC)slk.o $(OPDC)termattr.o $(OPDC)touch.o \ $(OPDC)util.o $(OPDC)window.o +PDCINCL = /I$(PDCURSES_TOP) /I$(PDCSRC) +!IF "$(CURSES_CONSOLE)" == "Y" +PDCINCLCON = /I$(PDCWINCON) PDCWINCONOBJS = $(OPDCC)pdcclip.o $(OPDCC)pdcdisp.o $(OPDCC)pdcgetsc.o \ $(OPDCC)pdckbd.o $(OPDCC)pdcscrn.o $(OPDCC)pdcsetsc.o $(OPDCC)pdcutil.o - +!ENDIF +!IF "$(CURSES_GRAPHICAL)" == "Y" PDCWINGUIOBJS = $(OPDCG)pdcclip.o $(OPDCG)pdcdisp.o $(OPDCG)pdcgetsc.o \ $(OPDCG)pdckbd.o $(OPDCG)pdcscrn.o $(OPDCG)pdcsetsc.o $(OPDCG)pdcutil.o - -PDCINCL = /I$(PDCURSES_TOP) /I$(PDCSRC) PDCINCLGUI = /I$(PDCWINCON) -PDCINCLCON = /I$(PDCWINGUI) +!ENDIF !ELSE PDCDEP= PDCCOMMONOBJS= @@ -627,14 +633,14 @@ CURSESOBJ= $(OTTY)cursdial.o $(OTTY)cursinit.o $(OTTY)cursinvt.o \ !IF "$(CURSES_CONSOLE)" == "Y" CURSESWINCONOBJS = $(CURSESOBJ) PDCWINCONLIB = $(LIBDIR)\$(PDCDIST)-wincon-$(TARGET_CPU)-static.lib -CURSESDEF1=-D"CURSES_GRAPHICS" -DPDC_NCMOUSE +CURSESCONDEF1=-D"CURSES_GRAPHICS" -DPDC_NCMOUSE #CURSESDEF2=-D"CURSES_BRIEF_INCLUDE" -DCHTYPE_32 CURSESDEF2=-DCURSES_UNICODE $(PDCURSESFLAGS) !ENDIF !IF "$(CURSES_GRAPHICAL)" == "Y" CURSESWINGUIOBJS = $(CURSESOBJ) $(OGUI)guitty.o PDCWINGUILIB = $(LIBDIR)\$(PDCDIST)-wingui-$(TARGET_CPU)-static.lib -CURSESDEF1=-D"CURSES_GRAPHICS" -DPDC_NCMOUSE +CURSESGUIDEF1=-D"CURSES_GRAPHICS" -DPDC_NCMOUSE #CURSESDEF2=-D"CURSES_BRIEF_INCLUDE" -DCHTYPE_32 CURSESDEF2=-DCURSES_UNICODE $(PDCURSESFLAGS) !ENDIF @@ -661,7 +667,7 @@ OGUIHACKLIB = $(OGUI)hacklib-$(TARGET_CPU)-static.lib # - TTY # -TTYDEF= -D"_CONSOLE" -DWIN32CON $(CURSESDEF1) +TTYDEF= -D"_CONSOLE" -DWIN32CON $(CURSESCONDEF1) $(CURSESGUIDEF1) RANDOMTTY = $(OTTY)random.o MDLIBTTY = $(OTTY)mdlib.o @@ -720,7 +726,7 @@ ALLOBJTTY = $(SOBJTTY) $(DLBOBJTTY) $(OBJSTTY) $(VVOBJTTY) $(LUAOBJTTY) # - GUI # -GUIDEF= -DTILES -DMSWIN_GRAPHICS -DNOTTYGRAPHICS $(CURSESDEF1) +GUIDEF= -DTILES -DMSWIN_GRAPHICS -DNOTTYGRAPHICS $(CURSESGUIDEF1) ALL_GUIHDR = $(MSWIN)\mhaskyn.h $(MSWIN)\mhdlg.h $(MSWIN)\mhfont.h \ $(MSWIN)\mhinput.h $(MSWIN)\mhmain.h $(MSWIN)\mhmap.h $(MSWIN)\mhmenu.h \ @@ -1312,10 +1318,8 @@ DLB = #========================================== # Rules for files in win\curses #========================================== -!IF "$(ADD_CURSES)" == "Y" {$(WCURSES)}.c{$(OBJTTY)}.o: - $(Q)$(CC) $(PDCINCL) $(CFLAGS) $(CURSESDEF1) $(CURSESDEF2) $(TTYDEF) $(GUIDEF) $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) -Fo$@ $< -!ENDIF + $(Q)$(CC) $(PDCINCL) $(CFLAGS) $(CURSESCONDEF1) $(CURSESGUIDEF1) $(CURSESDEF2) $(TTYDEF) $(GUIDEF) $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) -Fo$@ $< #========================================== # Rules for files in PDCurses @@ -1329,12 +1333,16 @@ DLB = {$(PDCSRC)}.c{$(OBJPDC)}.o: $(Q)$(CC) /wd4244 /wd4267 /wd4774 $(PDCINCL) $(CFLAGS:-w44774= ) $(CURSESDEF2) $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) -Fo$@ $< +!IF "$(CURSES_CONSOLE)" == "Y" {$(PDCWINCON)}.c{$(OBJPDCC)}.o: $(Q)$(CC) /wd4244 /wd4267 /wd4774 $(PDCINCL) $(PDCINCLCON) $(CFLAGS) $(CURSESDEF2) $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) -Fo$@ $< +!ENDIF +!IF "$(CURSES_GRAPHICAL)" == "Y" {$(PDCWINGUI)}.c{$(OBJPDCG)}.o: $(Q)$(CC) /wd4244 /wd4267 /wd4774 $(PDCINCL) $(PDCINCLGUI) $(CFLAGS) $(CURSESDEF2) $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) -Fo$@ $< !ENDIF +!ENDIF #========================================== # Rules for LUA files @@ -1791,8 +1799,11 @@ pkgdir.tag: envchk.tag: cpu.tag !IFDEF TTYOBJ @echo tty window support included -! IF "$(ADD_CURSES)" == "Y" - @echo curses window support also included +! IF "$(CURSES_CONSOLE)" == "Y" + @echo curses console window support also included +! ENDIF +! IF "$(CURSES_GRAPHICAL)" == "Y" + @echo curses graphical window support also included ! ENDIF !ENDIF ! IF "$(CL)"!="" @@ -2053,7 +2064,7 @@ $(PDCWINCONLIB) : $(PDCCOMMONOBJS) $(PDCWINCONOBJS) @echo Building library $@ from $** @$(librarian) -nologo /out:$@ $(PDCCOMMONOBJS) $(PDCWINCONOBJS) !ENDIF -!IF "$(CURSES_CONSOLE)" == "Y" +!IF "$(CURSES_GRAPHICAL)" == "Y" $(PDCWINGUILIB) : $(PDCCOMMONOBJS) $(PDCWINGUIOBJS) @echo Building library $@ from $** @$(librarian) -nologo /out:$@ $(PDCCOMMONOBJS) $(PDCWINGUIOBJS) From 4f3c463d698da3769469bce098d8d12c149fa498 Mon Sep 17 00:00:00 2001 From: nhkeni Date: Sat, 16 Nov 2024 17:39:40 -0500 Subject: [PATCH 083/791] remove some testing junk that escaped --- doc/Guidebook.mn | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/Guidebook.mn b/doc/Guidebook.mn index d56a4405c..ebf6fd82d 100644 --- a/doc/Guidebook.mn +++ b/doc/Guidebook.mn @@ -6675,4 +6675,3 @@ Izchak Miller Mike Stephenson .sm "Brand and product names are trademarks or registered trademarks \ of their respective holders." .\"EOF -changes From 3e903fd79a5bd249a375d5f211d09139ddd380ce Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 17 Nov 2024 10:03:04 -0500 Subject: [PATCH 084/791] quiet warnings on recent Qt, macOS Sequoia 15.1, latest Xcode --- sys/unix/hints/include/compiler.370 | 1 + sys/unix/hints/macOS.370 | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/sys/unix/hints/include/compiler.370 b/sys/unix/hints/include/compiler.370 index 1a0c3b990..10e7d2a27 100755 --- a/sys/unix/hints/include/compiler.370 +++ b/sys/unix/hints/include/compiler.370 @@ -149,6 +149,7 @@ CCXX=clang++ -std=c++11 CLANGPPGTEQ9 := $(shell expr `$(CXX) -dumpversion | cut -f1 -d.` \>= 9) CLANGPPGTEQ11 := $(shell expr `$(CXX) -dumpversion | cut -f1 -d.` \>= 11) CLANGPPGTEQ14 := $(shell expr `$(CXX) -dumpversion | cut -f1 -d.` \>= 14) +CLANGPPGTEQ16 := $(shell expr `$(CXX) -dumpversion | cut -f1 -d.` \>= 16) CLANGPPGTEQ17 := $(shell expr `$(CXX) -dumpversion | cut -f1 -d.` \>= 17) ifeq "$(CLANGPPGTEQ9)" "1" #CCXXFLAGS+=-Wformat-overflow diff --git a/sys/unix/hints/macOS.370 b/sys/unix/hints/macOS.370 index b77ea94f1..7f2c57079 100755 --- a/sys/unix/hints/macOS.370 +++ b/sys/unix/hints/macOS.370 @@ -87,6 +87,13 @@ endif # HAVE_MACPORTS endif # QTDIR endif # WANT_WIN_QT +ifdef WANT_WIN_QT +ifeq "$(CLANGPPGTEQ16)" "1" +CXX=clang++ --std=c++20 +CCXXFLAGS +=-Wno-c++20-attribute-extensions +endif +endif + # misc.370 must come after compiler.370 # and after QTDIR is defined From 37793be6eb7d9a201cad35fd0d4e3deb0f263c8f Mon Sep 17 00:00:00 2001 From: nhmall Date: Wed, 20 Nov 2024 09:56:01 -0500 Subject: [PATCH 085/791] more quieting of Qt6 build warnings --- sys/unix/hints/include/compiler.370 | 5 +++-- sys/unix/hints/linux.370 | 3 +++ sys/unix/hints/macOS.370 | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/sys/unix/hints/include/compiler.370 b/sys/unix/hints/include/compiler.370 index 10e7d2a27..3e95e151b 100755 --- a/sys/unix/hints/include/compiler.370 +++ b/sys/unix/hints/include/compiler.370 @@ -119,6 +119,7 @@ CCXX=g++ -std=gnu++11 GPPGTEQ9 := $(shell expr `$(CXX) -dumpversion | cut -f1 -d.` \>= 9) GPPGTEQ11 := $(shell expr `$(CXX) -dumpversion | cut -f1 -d.` \>= 11) GPPGTEQ12 := $(shell expr `$(CXX) -dumpversion | cut -f1 -d.` \>= 12) +GPPGTEQ14 := $(shell expr `$(CXX) -dumpversion | cut -f1 -d.` \>= 14) ifeq "$(GPPGTEQ9)" "1" CCXXFLAGS+=-Wformat-overflow ifdef CPLUSPLUS_NEED_DEPSUPPRESS @@ -135,7 +136,7 @@ CFLAGS+=-fPIC endif # g++ version greater than or equal to 11 ifdef CPLUSPLUS_NEED17 ifeq "$(GPPGTEQ12)" "1" -CCXX=g++ -std=c++20 +CCXX=g++ -std=c++17 else # g++ version greater than or equal to 12? (no follows) CCXX=g++ -std=c++17 endif # g++ version greater than or equal to 12 @@ -171,7 +172,7 @@ ifeq "$(CLANGPPGTEQ14)" "1" CCXX=clang++ -std=c++17 endif # clang++ greater than or equal to 14 ifeq "$(CLANGPPGTEQ17)" "1" -CCXX=clang++ -std=c++20 +CCXX=clang++ -std=c++17 endif # clang++ greater than or equal to 17 endif # CPLUSPLUS_NEED17 endif # end of clang++-specific section diff --git a/sys/unix/hints/linux.370 b/sys/unix/hints/linux.370 index ce12472c7..39286e027 100755 --- a/sys/unix/hints/linux.370 +++ b/sys/unix/hints/linux.370 @@ -74,6 +74,9 @@ endif # WANT_WIN_QT5 ifdef WANT_WIN_QT6 #if your Qt6 is elsewhere, change this to match QTDIR=/usr/local/qt6 +ifeq "$(GPPGTEQ14)" "1" +CCXXFLAGS += -Wno-template-id-cdtor +endif # g++ greater than or equal to 14 endif # WANT_WIN_QT6 endif # WANT_WIN_QT diff --git a/sys/unix/hints/macOS.370 b/sys/unix/hints/macOS.370 index 7f2c57079..05042cafd 100755 --- a/sys/unix/hints/macOS.370 +++ b/sys/unix/hints/macOS.370 @@ -89,7 +89,7 @@ endif # WANT_WIN_QT ifdef WANT_WIN_QT ifeq "$(CLANGPPGTEQ16)" "1" -CXX=clang++ --std=c++20 +CXX=clang++ --std=c++17 CCXXFLAGS +=-Wno-c++20-attribute-extensions endif endif From d93704a154de4eada120d4a569079d6d12881f58 Mon Sep 17 00:00:00 2001 From: Anhijkt Date: Sat, 23 Nov 2024 19:04:12 +0200 Subject: [PATCH 086/791] change CHDIR definition conditions --- include/config.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/config.h b/include/config.h index 8752feb39..11652a7c6 100644 --- a/include/config.h +++ b/include/config.h @@ -463,7 +463,7 @@ */ #define INSURANCE /* allow crashed game recovery */ -#ifndef MAC +#if !defined(MAC) && !defined(SHIM_GRAPHICS) #define CHDIR /* delete if no chdir() available */ #endif From 1c5b29509753e64fe972f906b2d1f20875eef82e Mon Sep 17 00:00:00 2001 From: PatR Date: Tue, 26 Nov 2024 18:01:19 -0800 Subject: [PATCH 087/791] tin consumption edge cases If eating a tin killed the hero (choked, turned to stone, poly'd into a new man with new Xp too low to survive) and bones were saved, the tin remained intact in them. When hero who is poly'd into metallivore form eats a tin, give a little extra nutrition for the tin itself. Also, eat it immediately by skipping the "It smells like " message and "Eat it? [yn]" prompt. (The message while eating it also reports , so skipping the 'smells' one doesn't end up hiding anything.) --- doc/fixes3-7-0.txt | 5 ++ src/eat.c | 119 ++++++++++++++++++++++++++++++++------------- 2 files changed, 89 insertions(+), 35 deletions(-) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index cf880e758..605bc49d4 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -1476,6 +1476,11 @@ a pet with the hides-under attribute could "move reluctantly over" a cursed prevent monster generation in the sokoban trap hallway change MSGHANDLER from compile-time to sysconf option allow changing extended command autocompletions via #optionsfull +if eating a tin's contents caused the hero to choke to death or turn to stone, + resulting bones would contain the tin still intact +when hero who is poly'd into metallivore form eats a tin, bypass "smells like + " feedback and the "Eat it?" prompt; just eat the contents + along with the tin without asking Fixes to 3.7.0-x General Problems Exposed Via git Repository diff --git a/src/eat.c b/src/eat.c index 9b992e1c7..e2c369ae8 100644 --- a/src/eat.c +++ b/src/eat.c @@ -23,6 +23,7 @@ staticfn boolean temp_givit(int, struct permonst *); staticfn void givit(int, struct permonst *); staticfn void eye_of_newt_buzz(void); staticfn void cpostfx(int); +staticfn void use_up_tin(struct obj *) NONNULLARG1; staticfn void consume_tin(const char *); staticfn void start_tin(struct obj *); staticfn int eatcorpse(struct obj *); @@ -788,6 +789,10 @@ cprefx(int pm) if (!Stone_resistance && !(poly_when_stoned(gy.youmonst.data) && polymon(PM_STONE_GOLEM))) { + /* if food was a tin, use it up early to keep it out of bones */ + if (svc.context.tin.tin) + use_up_tin(svc.context.tin.tin); + Sprintf(svk.killer.name, "tasting %s meat", mons[pm].pmnames[NEUTRAL]); svk.killer.format = KILLED_BY; @@ -1232,6 +1237,14 @@ cpostfx(int pm) if (Unchanging) { You_feel("momentarily different."); /* same as poly trap */ } else { + /* polyself() is potentially fatal; if food is a tin, use it up + early to keep it out of bones */ + if (svc.context.tin.tin) { + use_up_tin(svc.context.tin.tin); + /* most tin effects end up being skipped */ + lesshungry(200 + (metallivorous(gy.youmonst.data) ? 5 : 0)); + } + You("%s.", (pm == PM_GENETIC_ENGINEER) ? "undergo a freakish metamorphosis" : "feel a change coming over you"); @@ -1486,18 +1499,34 @@ tin_variety( return r; } +/* finish consume_tin(); also potentially used by cprefx() and cpostfx() */ +staticfn void +use_up_tin(struct obj *tin) +{ + if (carried(tin)) + useup(tin); + else + useupf(tin, 1L); + /* reset tin context */ + svc.context.tin.tin = (struct obj *) NULL; + svc.context.tin.o_id = 0; +} + staticfn void consume_tin(const char *mesg) { const char *what; - int which, mnum, r; + int which, mnum, r, nutamt; + /* if you've eaten tin itself, chance to not eat contents gets bypassed */ + boolean always_eat = metallivorous(gy.youmonst.data); struct obj *tin = svc.context.tin.tin; r = tin_variety(tin, FALSE); if (tin->otrapped || (tin->cursed && r != HOMEMADE_TIN && !rn2(8))) { b_trapped("tin", NO_PART); tin = costly_tin(COST_DSTROY); - goto use_up_tin; + use_up_tin(tin); + return; } pline1(mesg); /* "You succeed in opening the tin." */ @@ -1508,7 +1537,10 @@ consume_tin(const char *mesg) pline("It turns out to be empty."); tin->dknown = tin->known = 1; tin = costly_tin(COST_OPEN); - goto use_up_tin; + use_up_tin(tin); + if (always_eat) + lesshungry(5); /* metallivorous hero ate the tin itself */ + return; } which = 0; /* 0=>plural, 1=>as-is, 2=>"the" prefix */ @@ -1530,14 +1562,17 @@ consume_tin(const char *mesg) else if (which == 2) what = the(what); - pline("It smells like %s.", what); - if (y_n("Eat it?") == 'n') { - if (flags.verbose) - You("discard the open tin."); - if (!Hallucination) - tin->dknown = tin->known = 1; - tin = costly_tin(COST_OPEN); - goto use_up_tin; + if (!always_eat) { + pline("It smells like %s.", what); + if (y_n("Eat it?") == 'n') { + if (flags.verbose) + You("discard the open tin."); + if (!Hallucination) + tin->dknown = tin->known = 1; + tin = costly_tin(COST_OPEN); + use_up_tin(tin); + return; + } } /* in case stop_occupation() was called on previous meal */ @@ -1548,31 +1583,44 @@ consume_tin(const char *mesg) eating_conducts(&mons[mnum]); tin->dknown = tin->known = 1; - cprefx(mnum); - cpostfx(mnum); - /* charge for one at pre-eating cost */ - tin = costly_tin(COST_OPEN); + tin = svc.context.tin.tin = costly_tin(COST_OPEN); + + /* cprefx() or cpostfx() might use up tin to keep it out of bones */ + cprefx(mnum); + if (svc.context.tin.tin) + cpostfx(mnum); + if (!svc.context.tin.tin) + return; if (tintxts[r].nut < 0) { /* rotten */ make_vomiting((long) rn1(15, 10), FALSE); } else { - int nutamt = tintxts[r].nut; - + nutamt = tintxts[r].nut; /* nutrition from a homemade tin (made from a single corpse) shouldn't be more than nutrition from the corresponding corpse; other tinning modes might use more than one corpse or add extra ingredients so aren't similarly restricted */ if (r == HOMEMADE_TIN && nutamt > mons[mnum].cnutrit) nutamt = mons[mnum].cnutrit; + if (always_eat) + nutamt += 5; /* metallivorous hero ate the tin itself */ + /* use up tin now; lesshungry() could be fatal and produce bones */ + use_up_tin(tin), tin = NULL; lesshungry(nutamt); } if (tintxts[r].greasy) { - /* Assume !Glib, because you can't open tins when Glib. */ - make_glib(rn1(11, 5)); /* 5..15 */ - pline("Eating %s food made your %s very slippery.", - tintxts[r].txt, fingers_or_gloves(TRUE)); + /* normal hero is !Glib, because you can't open tins when Glib, + but one poly'd into metallivorous form might already be Glib; + it's debatable whether a rock mole should have its paws made + slippery when eating a greasy tin, but we'll go with that... */ + int alreadyglib = (int) (Glib & TIMEOUT); + + make_glib(alreadyglib + rn1(11, 5)); /* 5..15 */ + pline("Eating %s food made your %s %s slippery.", + tintxts[r].txt, fingers_or_gloves(TRUE), + alreadyglib ? "even more" : "very"); } } else { /* spinach... */ @@ -1584,11 +1632,12 @@ consume_tin(const char *mesg) tin->dknown = tin->known = 1; } - if (y_n("Eat it?") == 'n') { + if (!always_eat && y_n("Eat it?") == 'n') { if (flags.verbose) You("discard the open tin."); tin = costly_tin(COST_OPEN); - goto use_up_tin; + use_up_tin(tin); + return; } /* @@ -1612,19 +1661,19 @@ consume_tin(const char *mesg) : (flags.female ? "Olive Oyl" : "Bluto")); gainstr(tin, 0, FALSE); - tin = costly_tin(COST_OPEN); - lesshungry(tin->blessed ? 600 /* blessed */ - : !tin->cursed ? (400 + rnd(200)) /* uncursed */ - : (200 + rnd(400))); /* cursed */ + tin = svc.context.tin.tin = costly_tin(COST_OPEN); + nutamt = (tin->blessed ? 600 /* blessed */ + : !tin->cursed ? (400 + rnd(200)) /* uncursed */ + : (200 + rnd(400))); /* cursed */ + if (always_eat) + nutamt += 5; /* metallivorous hero also eats the tin itself */ + /* use up tin first; lesshungry() could be fatal and produce bones */ + use_up_tin(tin), tin = NULL; + lesshungry(nutamt); } - - use_up_tin: - if (carried(tin)) - useup(tin); - else - useupf(tin, 1L); - svc.context.tin.tin = (struct obj *) 0; - svc.context.tin.o_id = 0; + if (tin) + use_up_tin(tin); + return; } /* called during each move whilst opening a tin */ From 3615b17b62153e1a39b01a33255d05bb6d9892ea Mon Sep 17 00:00:00 2001 From: PatR Date: Tue, 26 Nov 2024 19:28:30 -0800 Subject: [PATCH 088/791] 'O' feedback when toggling 'accessiblemsg' When accessiblemsg is Off, coordiates supplied for various messages stayed put after becoming stale. If you used 'mO' to toggle that option On, you could see things like (2east):'accessiblemsg' option toggled on. After that, accessibility message coordinates behaved as intended. Clear a11y.msg_loc.x,y for every pline instead of just when they are used to augment the current message. Most players who use accessiblemsg are bound to set it in their config file rather than toggle it interactively so never noticed. Misc 1: option.c doesn't need '#include ' because cstd.h includes it unconditionally. Several other src/*.c are in the same situation but I didn't touch them. Misc 2: move set_msg_dir() and set_msg_xy() out of a warning suppression block that isn't relevant to them. --- src/options.c | 13 +++++++----- src/pline.c | 56 +++++++++++++++++++++++++++------------------------ 2 files changed, 38 insertions(+), 31 deletions(-) diff --git a/src/options.c b/src/options.c index 84d1f7d70..8abfcdc59 100644 --- a/src/options.c +++ b/src/options.c @@ -3,17 +3,17 @@ /*-Copyright (c) Michael Allison, 2008. */ /* NetHack may be freely redistributed. See license for details. */ -#ifdef OPTION_LISTS_ONLY /* (AMIGA) external program for opt lists */ +#ifndef OPTION_LISTS_ONLY +#include "hack.h" +#include "tcap.h" +#else /* OPTION_LISTS_ONLY: (AMIGA) external program for opt lists */ #include "config.h" #include "objclass.h" #include "flag.h" NEARDATA struct flag flags; /* provide linkage */ NEARDATA struct instance_flags iflags; /* provide linkage */ +NEARDATA struct accessibility_data a11y; #define static -#else -#include "hack.h" -#include "tcap.h" -#include #endif #define BACKWARD_COMPAT @@ -5297,6 +5297,9 @@ optfn_boolean( case opt_rest_on_space: update_rest_on_space(); break; + case opt_accessiblemsg: + a11y.msg_loc.x = a11y.msg_loc.y = 0; + break; default: break; } diff --git a/src/pline.c b/src/pline.c index 22dddcf34..8163a1d9b 100644 --- a/src/pline.c +++ b/src/pline.c @@ -76,6 +76,23 @@ putmesg(const char *line) SoundSpeak(line); } +/* set the direction where next message happens */ +void +set_msg_dir(int dir) +{ + dtoxy(&a11y.msg_loc, dir); + a11y.msg_loc.x += u.ux; + a11y.msg_loc.y += u.uy; +} + +/* set the coordinate where next message happens */ +void +set_msg_xy(coordxy x, coordxy y) +{ + a11y.msg_loc.x = x; + a11y.msg_loc.y = y; +} + staticfn void vpline(const char *, va_list); DISABLE_WARNING_FORMAT_NONLITERAL @@ -126,23 +143,6 @@ pline_mon(struct monst *mtmp, const char *line, ...) va_end(the_args); } -/* set the direction where next message happens */ -void -set_msg_dir(int dir) -{ - dtoxy(&a11y.msg_loc, dir); - a11y.msg_loc.x += u.ux; - a11y.msg_loc.y += u.uy; -} - -/* set the coordinate where next message happens */ -void -set_msg_xy(coordxy x, coordxy y) -{ - a11y.msg_loc.x = x; - a11y.msg_loc.y = y; -} - staticfn void vpline(const char *line, va_list the_args) { @@ -151,6 +151,11 @@ vpline(const char *line, va_list the_args) int ln; int msgtyp; boolean no_repeat; + coord a11y_mesgxy; + + a11y_mesgxy = a11y.msg_loc; /* save a11y.msg_loc before reseting it */ + /* always reset a11y.msg_loc whether we end up using it or not */ + a11y.msg_loc.x = a11y.msg_loc.y = 0; if (!line || !*line) return; @@ -161,16 +166,15 @@ vpline(const char *line, va_list the_args) if (program_state.wizkit_wishing) return; - if (a11y.accessiblemsg && isok(a11y.msg_loc.x,a11y.msg_loc.y)) { - char *tmp; - char *dirstr; - static char dirstrbuf[BUFSZ]; - int g = (iflags.getpos_coords == GPCOORDS_NONE) - ? GPCOORDS_COMFULL : iflags.getpos_coords; + /* when accessiblemsg is set and a11y.msg_loc is nonzero, use the latter + to insert a location prefix in front of current message */ + if (a11y.accessiblemsg && isok(a11y_mesgxy.x, a11y_mesgxy.y)) { + char *tmp, *dirstr, dirstrbuf[QBUFSZ]; - dirstr = coord_desc(a11y.msg_loc.x, a11y.msg_loc.y, dirstrbuf, g); - a11y.msg_loc.x = a11y.msg_loc.y = 0; - tmp = (char *)alloc(strlen(line) + sizeof ": " + strlen(dirstr)); + dirstr = coord_desc(a11y_mesgxy.x, a11y_mesgxy.y, dirstrbuf, + ((iflags.getpos_coords == GPCOORDS_NONE) + ? GPCOORDS_COMFULL : iflags.getpos_coords)); + tmp = (char *) alloc(strlen(line) + sizeof ": " + strlen(dirstr)); Strcpy(tmp, dirstr); Strcat(tmp, ": "); Strcat(tmp, line); From 15e70035d079b91f5c6d406e8163349aa7ca4244 Mon Sep 17 00:00:00 2001 From: nhmall Date: Tue, 26 Nov 2024 23:27:29 -0500 Subject: [PATCH 089/791] Remove unnecessary macro that wasn't ideally named Also add a comment that states the intent. --- include/rm.h | 1 - src/display.c | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/rm.h b/include/rm.h index 5cc7546b6..001414a10 100644 --- a/include/rm.h +++ b/include/rm.h @@ -104,7 +104,6 @@ enum levl_typ_types { #define IS_WALL(typ) ((typ) && (typ) <= DBWALL) #define IS_STWALL(typ) ((typ) <= DBWALL) /* STONE <= (typ) <= DBWALL */ #define IS_OBSTRUCTED(typ) ((typ) < POOL) /* absolutely nonaccessible */ -#define IS_CORR(typ) ((typ) == CORR || (typ) == SCORR) #define IS_SDOOR(typ) ((typ) == SDOOR) #define IS_DOOR(typ) ((typ) == DOOR) #define IS_DOORJOIN(typ) (IS_OBSTRUCTED(typ) || (typ) == IRONBARS) diff --git a/src/display.c b/src/display.c index c379331e5..77dd47b47 100644 --- a/src/display.c +++ b/src/display.c @@ -3101,7 +3101,8 @@ check_pos(coordxy x, coordxy y, int which) if (!isok(x, y)) return which; type = levl[x][y].typ; - if (IS_STWALL(type) || IS_CORR(type) || IS_SDOOR(type)) + /* Everything below POOL, excluding TREE */ + if (IS_STWALL(type) || (type) == CORR || (type) == SCORR || IS_SDOOR(type)) return which; return 0; } From d32ab55b8489d37b67b7ed314dfb55f36a8f54b8 Mon Sep 17 00:00:00 2001 From: PatR Date: Tue, 26 Nov 2024 20:57:11 -0800 Subject: [PATCH 090/791] new property: BLND_RES Add enlightenment feedback for Sunsword's blocking of becoming blind from light flashes. It uses an extra property so that wizard mode can report the reason. EDITLEVEL is being incremented, so existing save and bones files are invalidated. --- include/patchlevel.h | 2 +- include/prop.h | 63 ++++++++++++++++++++++---------------------- include/youprop.h | 4 +++ src/artifact.c | 16 ++++++++++- src/attrib.c | 8 +++--- src/insight.c | 3 +++ src/mondata.c | 10 ++++++- src/polyself.c | 2 ++ src/timeout.c | 1 + 9 files changed, 72 insertions(+), 37 deletions(-) diff --git a/include/patchlevel.h b/include/patchlevel.h index 4d107d941..3f1d88e81 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 109 +#define EDITLEVEL 110 /* * Development status possibilities. diff --git a/include/prop.h b/include/prop.h index 9824d892b..16b7efd50 100644 --- a/include/prop.h +++ b/include/prop.h @@ -55,41 +55,42 @@ enum prop_types { CLAIRVOYANT = 35, INFRAVISION = 36, DETECT_MONSTERS = 37, + BLND_RES = 38, /* Appearance and behavior */ - ADORNED = 38, - INVIS = 39, - DISPLACED = 40, - STEALTH = 41, - AGGRAVATE_MONSTER = 42, - CONFLICT = 43, + ADORNED = 39, + INVIS = 40, + DISPLACED = 41, + STEALTH = 42, + AGGRAVATE_MONSTER = 43, + CONFLICT = 44, /* Transportation */ - JUMPING = 44, - TELEPORT = 45, - TELEPORT_CONTROL = 46, - LEVITATION = 47, - FLYING = 48, - WWALKING = 49, - SWIMMING = 50, - MAGICAL_BREATHING = 51, - PASSES_WALLS = 52, + JUMPING = 45, + TELEPORT = 46, + TELEPORT_CONTROL = 47, + LEVITATION = 48, + FLYING = 49, + WWALKING = 50, + SWIMMING = 51, + MAGICAL_BREATHING = 52, + PASSES_WALLS = 53, /* Physical attributes */ - SLOW_DIGESTION = 53, - HALF_SPDAM = 54, - HALF_PHDAM = 55, - REGENERATION = 56, - ENERGY_REGENERATION = 57, - PROTECTION = 58, - PROT_FROM_SHAPE_CHANGERS = 59, - POLYMORPH = 60, - POLYMORPH_CONTROL = 61, - UNCHANGING = 62, - FAST = 63, - REFLECTING = 64, - FREE_ACTION = 65, - FIXED_ABIL = 66, - LIFESAVED = 67 + SLOW_DIGESTION = 54, + HALF_SPDAM = 55, + HALF_PHDAM = 56, + REGENERATION = 57, + ENERGY_REGENERATION = 58, + PROTECTION = 59, + PROT_FROM_SHAPE_CHANGERS = 60, + POLYMORPH = 61, + POLYMORPH_CONTROL = 62, + UNCHANGING = 63, + FAST = 64, + REFLECTING = 65, + FREE_ACTION = 66, + FIXED_ABIL = 67, + LIFESAVED = 68, + LAST_PROP = LIFESAVED }; -#define LAST_PROP (LIFESAVED) /*** Where the properties come from ***/ /* Definitions were moved here from obj.h and you.h */ diff --git a/include/youprop.h b/include/youprop.h index 331d6ede1..f2c166606 100644 --- a/include/youprop.h +++ b/include/youprop.h @@ -156,6 +156,10 @@ #define Blind_telepat (HTelepat || ETelepat) #define Unblind_telepat (ETelepat) +#define HBlnd_resist u.uprops[BLND_RES].intrinsic /* from form */ +#define EBlnd_resist u.uprops[BLND_RES].extrinsic /* wielding Sunsword */ +#define Blnd_resist (HBlnd_resist || EBlnd_resist) + #define HWarning u.uprops[WARNING].intrinsic #define EWarning u.uprops[WARNING].extrinsic #define Warning (HWarning || EWarning) diff --git a/src/artifact.c b/src/artifact.c index 009dd3406..f31ec5a98 100644 --- a/src/artifact.c +++ b/src/artifact.c @@ -629,7 +629,10 @@ protects(struct obj *otmp, boolean being_worn) * unworn/unwielded/dropped. Pickup/drop only set/reset the W_ART mask. */ void -set_artifact_intrinsic(struct obj *otmp, boolean on, long wp_mask) +set_artifact_intrinsic( + struct obj *otmp, + boolean on, + long wp_mask) { long *mask = 0; const struct artifact *art, *oart = get_artifact(otmp); @@ -796,6 +799,13 @@ set_artifact_intrinsic(struct obj *otmp, boolean on, long wp_mask) && (u.uprops[oart->inv_prop].extrinsic & W_ARTI)) (void) arti_invoke(otmp); } + + if (wp_mask == W_WEP && is_art(otmp, ART_SUNSWORD)) { + if (on) + EBlnd_resist |= wp_mask; + else + EBlnd_resist &= ~wp_mask; + } } /* touch_artifact()'s return value isn't sufficient to tell whether it @@ -2210,6 +2220,10 @@ what_gives(long *abil) if ((art->spfx & spfx) == spfx && obj->owornmask) return obj; } + if (obj == uwep && abil == &EBlnd_resist + && (*abil & W_WEP) != 0L) { + return obj; /* Sunsword */ + } } } else { if (wornbits && wornbits == (wornmask & obj->owornmask)) diff --git a/src/attrib.c b/src/attrib.c index 859b5b44a..36dd9ea91 100644 --- a/src/attrib.c +++ b/src/attrib.c @@ -889,7 +889,8 @@ is_innate(int propidx) ignore innateness if equipment is going to claim responsibility */ && !u.uprops[propidx].extrinsic) return FROM_ROLE; - if (propidx == BLINDED && !haseyes(gy.youmonst.data)) + if ((propidx == BLINDED && !haseyes(gy.youmonst.data)) + || (propidx == BLND_RES && (HBlnd_resist & FROMFORM) != 0)) return FROM_FORM; return FROM_NONE; } @@ -897,7 +898,8 @@ is_innate(int propidx) DISABLE_WARNING_FORMAT_NONLITERAL char * -from_what(int propidx) /* special cases can have negative values */ +from_what( + int propidx) /* special cases can have negative values */ { static char buf[BUFSZ]; @@ -939,7 +941,7 @@ from_what(int propidx) /* special cases can have negative values */ else if (innateness == FROM_LYCN) Strcpy(buf, " due to your lycanthropy"); else if (innateness == FROM_FORM) - Strcpy(buf, " from current creature form"); + Strcpy(buf, " from your creature form"); else if (propidx == FAST && Very_fast) Sprintf(buf, because_of, ((HFast & TIMEOUT) != 0L) ? "a potion or spell" diff --git a/src/insight.c b/src/insight.c index 08fd80b6b..2b8bd27b7 100644 --- a/src/insight.c +++ b/src/insight.c @@ -1533,6 +1533,9 @@ attributes_enlightenment( /*** Vision and senses ***/ if ((HBlinded || EBlinded) && BBlinded) /* blind w/ blindness blocked */ you_can("see", from_what(-BLINDED)); /* Eyes of the Overworld */ + if (Blnd_resist && !Blind) /* skip if no eyes or blindfolded */ + you_are("not subject to light-induced blindness", + from_what(BLND_RES)); if (See_invisible) { if (!Blind) enl_msg(You_, "see", "saw", " invisible", from_what(SEE_INVIS)); diff --git a/src/mondata.c b/src/mondata.c index 28da3358a..49a887a80 100644 --- a/src/mondata.c +++ b/src/mondata.c @@ -187,7 +187,15 @@ resists_blnd(struct monst *mon) if (dmgtype_fromattack(ptr, AD_BLND, AT_EXPL) || dmgtype_fromattack(ptr, AD_BLND, AT_GAZE)) return TRUE; - return resists_blnd_by_arti(mon); + /* Sunsword */ + if (resists_blnd_by_arti(mon)) + return TRUE; + /* catchall */ + if (is_you && Blnd_resist) { + impossible("'Blnd_resist' but not resists_blnd()?"); + return TRUE; + } + return FALSE; } /* True iff monster is resistant to light-induced blindness due to worn diff --git a/src/polyself.c b/src/polyself.c index 55da8a8d5..9d619f6bb 100644 --- a/src/polyself.c +++ b/src/polyself.c @@ -103,6 +103,8 @@ set_uasmon(void) PROPSET(REGENERATION, regenerates(mdat)); PROPSET(REFLECTING, (mdat == &mons[PM_SILVER_DRAGON])); PROPSET(BLINDED, !haseyes(mdat)); + PROPSET(BLND_RES, (dmgtype_fromattack(mdat, AD_BLND, AT_EXPL) + || dmgtype_fromattack(mdat, AD_BLND, AT_GAZE))); #undef PROPSET /* whether the player is flying/floating depends on their steed, diff --git a/src/timeout.c b/src/timeout.c index 13ebb0d4e..8553320bb 100644 --- a/src/timeout.c +++ b/src/timeout.c @@ -79,6 +79,7 @@ static const struct propname { { SICK_RES, "sickness resistance" }, { ANTIMAGIC, "magic resistance" }, { HALLUC_RES, "hallucination resistance" }, + { BLND_RES, "light-induced blindness resistance" }, { FUMBLING, "fumbling" }, { HUNGER, "voracious hunger" }, { TELEPAT, "telepathic" }, From ea6cdd3f399443deaaacf1743352530050298719 Mon Sep 17 00:00:00 2001 From: PatR Date: Tue, 26 Nov 2024 21:20:30 -0800 Subject: [PATCH 091/791] Amulet_on() & Amulet_off() Fix a FIXME in Amulet_off() for removing an amulet of magical breathing when within a poison gas cloud. Redo message sequencing for both Amulet_on() and Amulet_off(). Use up an amulet of change if put on while the Unchanging attribute is active (via #wizintrinsic) instead of wearing it with no effect. Don't discover amulet of strangulation if put on while already Strangled (via #wizintrinsic). --- src/do_wear.c | 180 ++++++++++++++++++++++++++++++++------------------ 1 file changed, 116 insertions(+), 64 deletions(-) diff --git a/src/do_wear.c b/src/do_wear.c index 652c13868..72ecfd75d 100644 --- a/src/do_wear.c +++ b/src/do_wear.c @@ -30,7 +30,7 @@ staticfn int Gloves_on(void); staticfn int Shield_on(void); staticfn int Shirt_on(void); staticfn void dragon_armor_handling(struct obj *, boolean, boolean); -staticfn void Amulet_on(void); +staticfn void Amulet_on(struct obj *) NONNULLARG1; staticfn void learnring(struct obj *, boolean); staticfn void adjust_attrib(struct obj *, int, int); staticfn void Ring_off_or_gone(struct obj *, boolean); @@ -74,6 +74,15 @@ off_msg(struct obj *otmp) staticfn void on_msg(struct obj *otmp) { + /* on_msg() for rings and amulets just shows add-to-invent feedback + [after caller calls setworn(), for suffix: "(on {left|right} hand)" + or "(being worn)"]; eyewear too unless giving verbose message below */ + if ((otmp->owornmask & (W_RING | W_AMUL)) != 0L + || ((otmp->owornmask & W_TOOL) != 0L && !flags.verbose)) { + prinv((char *) NULL, otmp, 0L); + return; + } + if (flags.verbose) { char how[BUFSZ]; /* call xname() before obj_is_pname(); formatting obj's name @@ -925,16 +934,13 @@ Armor_gone(void) } staticfn void -Amulet_on(void) +Amulet_on(struct obj *amul) { - /* make sure amulet isn't wielded; can't use remove_worn_item() - here because it has already been set worn in amulet slot */ - if (uamul == uwep) - setuwep((struct obj *) 0); - else if (uamul == uswapwep) - setuswapwep((struct obj *) 0); - else if (uamul == uquiver) - setuqwep((struct obj *) 0); + boolean on_msg_done = FALSE; + + /* make sure amulet isn't wielded/alt-wielded/quivered, before wearing */ + remove_worn_item(amul, FALSE); + setworn(amul, W_AMUL); switch (uamul->otyp) { case AMULET_OF_ESP: @@ -952,8 +958,10 @@ Amulet_on(void) was_in_poison_gas = region_danger(); EMagical_breathing |= W_AMUL; if (was_in_poison_gas) { - You("are no longer bothered by the poison gas."); makeknown(AMULET_OF_MAGICAL_BREATHING); + on_msg(uamul); + on_msg_done = TRUE; + You("are no longer bothered by the poison gas."); } /* no need to check for becoming able to breathe underwater; if we are underwater, we already can or we would have drowned */ @@ -964,46 +972,58 @@ Amulet_on(void) make_slimed(0L, (char *) 0); break; case AMULET_OF_CHANGE: { + boolean call_it = FALSE; int new_sex, orig_sex = poly_gender(); - if (Unchanging) - break; - change_sex(); + /* in normal play it's not possible to put on an amulet of change + while already wearing an amulet of unchanging, but in wizard + mode the Unchanging attribute can be set via #wizintrinsic */ + if (!Unchanging) + change_sex(); + new_sex = poly_gender(); + if (new_sex != orig_sex) + makeknown(AMULET_OF_CHANGE); + on_msg(uamul); /* show 'z - amulet of change (being worn)' */ + on_msg_done = TRUE; + /* Don't use same message as polymorph */ if (new_sex != orig_sex) { - makeknown(AMULET_OF_CHANGE); + newsym(u.ux, u.uy); /* glyphmon flag and tile have changed */ + disp.botl = TRUE; /* role name or rank title might have changed */ You("are suddenly very %s!", flags.female ? "feminine" : "masculine"); - disp.botl = TRUE; - newsym(u.ux, u.uy); /* glyphmon flag and tile may have gone - * from male to female or vice versa */ } else { /* already polymorphed into single-gender monster; only changed the character's base sex */ You("don't feel like yourself."); + /* checking dknown is redundant--amulets always have dknown set */ + call_it = (uamul->dknown != 0); } livelog_newform(FALSE, orig_sex, new_sex); pline_The("amulet disintegrates!"); - if (orig_sex == poly_gender() && uamul->dknown) + if (call_it) trycall(uamul); useup(uamul); break; } case AMULET_OF_STRANGULATION: - if (can_be_strangled(&gy.youmonst)) { + /* note: might already be Strangled (via #wizintrinsic) */ + if (can_be_strangled(&gy.youmonst) && !Strangled) { makeknown(AMULET_OF_STRANGULATION); Strangled = 6L; disp.botl = TRUE; + on_msg(uamul); + on_msg_done = TRUE; pline("It constricts your throat!"); } break; case AMULET_OF_RESTFUL_SLEEP: { - long newnap = (long) rnd(100), oldnap = (HSleepy & TIMEOUT); + long newnap = (long) rnd(98) + 2L, oldnap = (HSleepy & TIMEOUT); - /* avoid clobbering FROMOUTSIDE bit, which might have - gotten set by previously eating one of these amulets */ if (newnap < oldnap || oldnap == 0L) + /* avoid clobbering FROMOUTSIDE bit, which might have + gotten set by previously eating one of these amulets */ HSleepy = (HSleepy & ~TIMEOUT) | newnap; break; } @@ -1021,6 +1041,8 @@ Amulet_on(void) if (!already_flying) { makeknown(AMULET_OF_FLYING); + on_msg(uamul); + on_msg_done = TRUE; disp.botl = TRUE; /* status: 'Fly' On */ You("are now in flight."); } @@ -1033,19 +1055,28 @@ Amulet_on(void) case AMULET_OF_YENDOR: break; } + + if (!on_msg_done) + on_msg(uamul); } void Amulet_off(void) { + struct obj *amul = uamul; /* for off_msg() after setworn(NULL,W_AMUL) */ + boolean mkn = FALSE, early_off_msg = FALSE; + svc.context.takeoff.mask &= ~W_AMUL; switch (uamul->otyp) { case AMULET_OF_ESP: /* need to update ability before calling see_monsters() */ setworn((struct obj *) 0, W_AMUL); + off_msg(amul); + early_off_msg = TRUE; + see_monsters(); - return; + break; case AMULET_OF_LIFE_SAVING: case AMULET_VERSUS_POISON: case AMULET_OF_REFLECTION: @@ -1054,21 +1085,31 @@ Amulet_off(void) case FAKE_AMULET_OF_YENDOR: break; case AMULET_OF_MAGICAL_BREATHING: + /* amulet is currently still on; take it off before calling drown() + and region_danger(); call off_msg() before specific messages */ + setworn((struct obj *) 0, W_AMUL); + off_msg(amul); /* 'uamul' has been set to Null */ + early_off_msg = TRUE; + if (Underwater) { - /* HMagical_breathing must be set off before calling drown() */ - setworn((struct obj *) 0, W_AMUL); if (!cant_drown(gy.youmonst.data) && !Swimming) { You("suddenly inhale an unhealthy amount of %s!", hliquid("water")); + mkn = TRUE; /* in case of life-saving */ (void) drown(); } - return; } - /* - * FIXME: we need a poison gas region check here - */ + if (region_danger()) { + /* "breathing": wouldn't get here otherwise */ + You("are breathing poison gas!"); + mkn = TRUE; + } break; case AMULET_OF_STRANGULATION: + setworn((struct obj *) 0, W_AMUL); + off_msg(amul); + early_off_msg = TRUE; + if (Strangled) { Strangled = 0L; disp.botl = TRUE; @@ -1076,6 +1117,7 @@ Amulet_off(void) Your("%s is no longer constricted!", body_part(NECK)); else You("can breathe more easily!"); + mkn = TRUE; } break; case AMULET_OF_RESTFUL_SLEEP: @@ -1083,20 +1125,24 @@ Amulet_off(void) /* HSleepy = 0L; -- avoid clobbering FROMOUTSIDE bit */ if (!ESleepy && !(HSleepy & ~TIMEOUT)) HSleepy &= ~TIMEOUT; /* clear timeout bits */ - return; + break; case AMULET_OF_FLYING: { boolean was_flying = !!Flying; - /* remove amulet 'early' to determine whether Flying changes */ + /* remove amulet 'early' to determine whether Flying changes; + also in case spoteffects() does something with the amulet */ setworn((struct obj *) 0, W_AMUL); + off_msg(amul); + early_off_msg = TRUE; + float_vs_flight(); /* probably not needed here */ if (was_flying && !Flying) { - makeknown(AMULET_OF_FLYING); disp.botl = TRUE; /* status: 'Fly' Off */ You("%s.", (is_pool_or_lava(u.ux, u.uy) || Is_waterlevel(&u.uz) || Is_airlevel(&u.uz)) ? "stop flying" : "land"); + mkn = TRUE; /* makeknown(AMULET_OF_FLYING) */ spoteffects(TRUE); } break; @@ -1107,7 +1153,12 @@ Amulet_off(void) case AMULET_OF_YENDOR: break; } + setworn((struct obj *) 0, W_AMUL); + if (!early_off_msg) + off_msg(amul); /* (not 'uamul'; it's Null now) */ + if (mkn) + makeknown(amul->otyp); return; } @@ -1198,7 +1249,9 @@ Ring_on(struct obj *obj) case RIN_FREE_ACTION: case RIN_SLOW_DIGESTION: case RIN_SUSTAIN_ABILITY: + break; case MEAT_RING: + /* wearing a meat ring does not affect vegan conduct */ break; case RIN_STEALTH: toggle_stealth(obj, oldprop, TRUE); @@ -1383,8 +1436,7 @@ Blindf_on(struct obj *otmp) boolean already_blind = Blind, changed = FALSE; /* blindfold might be wielded; release it for wearing */ - if (otmp->owornmask & W_WEAPONS) - remove_worn_item(otmp, FALSE); + remove_worn_item(otmp, FALSE); setworn(otmp, W_TOOL); on_msg(otmp); @@ -1469,7 +1521,7 @@ set_wear( if (!obj ? uleft != 0 : (obj == uleft)) (void) Ring_on(uleft); if (!obj ? uamul != 0 : (obj == uamul)) - (void) Amulet_on(); + (void) Amulet_on(uamul); if (!obj ? uarmu != 0 : (obj == uarmu)) (void) Shirt_on(); @@ -1606,8 +1658,8 @@ cancel_don(void) /* called by steal() during theft from hero; interrupt donning/doffing */ int -stop_donning(struct obj *stolenobj) /* no message if stolenobj is already - being doffing */ +stop_donning( + struct obj *stolenobj) /* no mesg if stolenobj is already being doffed */ { char buf[BUFSZ]; struct obj *otmp; @@ -1651,8 +1703,9 @@ static NEARDATA int Narmorpieces, Naccessories; /* assign values to Narmorpieces and Naccessories */ staticfn void -count_worn_stuff(struct obj **which, /* caller wants this when count is 1 */ - boolean accessorizing) +count_worn_stuff( + struct obj **which, /* caller wants this when count is 1 */ + boolean accessorizing) { struct obj *otmp; @@ -1736,12 +1789,12 @@ armor_or_accessory_off(struct obj *obj) off_msg(obj); Ring_off(obj); } else if (obj == uamul) { - Amulet_off(); - off_msg(obj); + Amulet_off(); /* does its own off_msg */ } else if (obj == ublindf) { Blindf_off(obj); /* does its own off_msg */ } else { - impossible("removing strange accessory?"); + impossible("removing strange accessory: %s", + safe_typename(obj->otyp)); if (obj->owornmask) remove_worn_item(obj, FALSE); } @@ -2014,12 +2067,12 @@ canwearobj(struct obj *otmp, long *mask, boolean noisy) You("have no feet..."); /* not body_part(FOOT) */ err++; } else if (Upolyd && gy.youmonst.data->mlet == S_CENTAUR) { - /* break_armor() pushes boots off for centaurs, - so don't let dowear() put them back on... */ + /* break_armor() pushes boots off for centaurs, so don't let + dowear() put them back on; + makeplural(body_part(FOOT)) would yield "rear hooves" here, + which sounds odd, so use hard-coded "hooves" */ if (noisy) - You("have too many hooves to wear %s.", - c_boots); /* makeplural(body_part(FOOT)) yields - "rear hooves" which sounds odd */ + You("have too many hooves to wear %s.", c_boots); err++; } else if (u.utrap && (u.utraptype == TT_BEARTRAP || u.utraptype == TT_INFLOOR @@ -2114,7 +2167,7 @@ staticfn int accessory_or_armor_on(struct obj *obj) { long mask = 0L; - boolean armor, ring, eyewear; + boolean armor, ring, amulet, eyewear; if (obj->owornmask & (W_ACCESSORY | W_ARMOR)) { already_wearing(c_that_); @@ -2122,6 +2175,7 @@ accessory_or_armor_on(struct obj *obj) } armor = (obj->oclass == ARMOR_CLASS); ring = (obj->oclass == RING_CLASS || obj->otyp == MEAT_RING); + amulet = (obj->oclass == AMULET_CLASS); eyewear = (obj->otyp == BLINDFOLD || obj->otyp == TOWEL || obj->otyp == LENSES); /* checks which are performed prior to actually touching the item */ @@ -2219,7 +2273,7 @@ accessory_or_armor_on(struct obj *obj) return res ? ECMD_TIME : ECMD_OK; } } - } else if (obj->oclass == AMULET_CLASS) { + } else if (amulet) { if (uamul) { already_wearing("an amulet"); return ECMD_OK; @@ -2306,26 +2360,24 @@ accessory_or_armor_on(struct obj *obj) } svc.context.takeoff.mask = svc.context.takeoff.what = 0L; } else { /* not armor */ - boolean give_feedback = FALSE; - - /* [releasing wielded accessory handled in Xxx_on()] */ if (ring) { + /* Ring_on() expects ring to already be worn as uleft or uright */ setworn(obj, mask); Ring_on(obj); - give_feedback = TRUE; - } else if (obj->oclass == AMULET_CLASS) { - setworn(obj, W_AMUL); - Amulet_on(); - /* no feedback here if amulet of change got used up */ - give_feedback = (uamul != 0); + /* is_worn(): 'obj' will always be worn here except when putting + on a ring of levitation while at a sink location */ + if (is_worn(obj)) + on_msg(obj); + } else if (amulet) { + /* setworn() and on_msg() handled by Amulet_on() */ + Amulet_on(obj); } else if (eyewear) { - /* setworn() handled by Blindf_on() */ + /* setworn() and on_msg() handled by Blindf_on() */ Blindf_on(obj); - /* message handled by Blindf_on(); leave give_feedback False */ + } else { + impossible("putting on unexpected type of accessory: %s", + safe_typename(obj->otyp)); } - /* feedback for ring or for amulet other than 'change' */ - if (give_feedback && is_worn(obj)) - prinv((char *) 0, obj, 0L); } return ECMD_TIME; } From 70284521e6a6797cb31167eb04059efb00e87586 Mon Sep 17 00:00:00 2001 From: nhmall Date: Wed, 27 Nov 2024 00:35:27 -0500 Subject: [PATCH 092/791] follow-up: paste bit --- src/display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/display.c b/src/display.c index 77dd47b47..9902040a2 100644 --- a/src/display.c +++ b/src/display.c @@ -3102,7 +3102,7 @@ check_pos(coordxy x, coordxy y, int which) return which; type = levl[x][y].typ; /* Everything below POOL, excluding TREE */ - if (IS_STWALL(type) || (type) == CORR || (type) == SCORR || IS_SDOOR(type)) + if (IS_STWALL(type) || type == CORR || type == SCORR || IS_SDOOR(type)) return which; return 0; } From 1d0b8dfca0ec388d095f3f3eea4d57aa0cd75aa9 Mon Sep 17 00:00:00 2001 From: PatR Date: Tue, 26 Nov 2024 21:40:19 -0800 Subject: [PATCH 093/791] Demonbane revisited Commit c4a1f298e8923dfc0543f51d4794bc0286d42138 two and a half months ago gave lawful Angels and Archons a chance to start with a mace instead of a long sword so that they might get Demonbane. It was a bit convulted; this redoes it to be more straightforward. --- src/makemon.c | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/src/makemon.c b/src/makemon.c index ae32e8f39..947a8884d 100644 --- a/src/makemon.c +++ b/src/makemon.c @@ -329,27 +329,24 @@ m_initweap(struct monst *mtmp) case S_ANGEL: if (humanoid(ptr)) { - /* create minion stuff; can't use mongets; - weapon: long sword [rn2(5) > 1 == 60%] or mace [40%] */ - otmp = mksobj((rn2(5) > 1) ? LONG_SWORD : MACE, FALSE, FALSE); + /* create minion stuff; bypass mongets */ + int typ = rn2(3) ? LONG_SWORD : MACE; + const char *nam = (typ == LONG_SWORD) ? "Sunsword" : "Demonbane"; + + otmp = mksobj(typ, FALSE, FALSE); /* maybe promote weapon to an artifact */ if ((!rn2(20) || is_lord(ptr)) && sgn(mtmp->isminion ? EMIN(mtmp)->min_align - : ptr->maligntyp) == A_LAWFUL) { - /* Sunsword and Demonbane both used to be long swords and - Angels always got a long sword, so might get either of - the two artifacts; Demonbane has been changed to be a - mace; this deliberately makes an independent choice of - which artifact and if it picks the wrong name for 'otmp's - type, then 'otmp' won't be upgraded into an artifact */ - otmp = oname(otmp, artiname((rn2(5) > 1) ? ART_SUNSWORD - : ART_DEMONBANE), - ONAME_RANDOM); /* randomly created */ - } + : ptr->maligntyp) == A_LAWFUL) + otmp = oname(otmp, nam, ONAME_RANDOM); /* randomly created */ + /* enhance the weapon */ bless(otmp); otmp->oerodeproof = TRUE; - /* make long sword be +0 to +3, weaker mace be +3 to +6 */ - otmp->spe = (otmp->otyp == LONG_SWORD) ? rn2(4) : rn1(4, 3); + /* make long sword be +0 to +3, mace be +3 to +6 to compensate + for being significantly weaker against large opponents */ + otmp->spe = rn2(4); + if (typ == MACE) + otmp->spe += 3; (void) mpickobj(mtmp, otmp); otmp = mksobj(!rn2(4) || is_lord(ptr) ? SHIELD_OF_REFLECTION From 1c888b3b072b2e783aab9448c59a95f43f1f855b Mon Sep 17 00:00:00 2001 From: PatR Date: Tue, 26 Nov 2024 21:51:00 -0800 Subject: [PATCH 094/791] noit_mon_nam() Change noit_mon_nam() to work as if it was noit_y_monnam() (without renaming it or adding yet another monster naming routine) to use "your " rather than "the " when is a pet that can be seen (so not the case where "it" gets replaced by "someone" or "something"). --- src/do_name.c | 15 ++++++++------- src/insight.c | 2 +- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/do_name.c b/src/do_name.c index 82c486451..aa4463cda 100644 --- a/src/do_name.c +++ b/src/do_name.c @@ -777,12 +777,12 @@ rndghostname(void) * x_monnam is the generic monster-naming function. * seen unseen detected named * mon_nam: the newt it the invisible orc Fido - * noit_mon_nam:the newt (as if detected) the invisible orc Fido + * noit_mon_nam:your newt (as if detected) your invisible orc Fido * some_mon_nam:the newt someone the invisible orc Fido * or something * l_monnam: newt it invisible orc dog called Fido * Monnam: The newt It The invisible orc Fido - * noit_Monnam: The newt (as if detected) The invisible orc Fido + * noit_Monnam: Your newt (as if detected) Your invisible orc Fido * Some_Monnam: The newt Someone The invisible orc Fido * or Something * Adjmonnam: The poor newt It The poor invisible orc The poor Fido @@ -1035,14 +1035,15 @@ mon_nam(struct monst *mtmp) (has_mgivenname(mtmp)) ? SUPPRESS_SADDLE : 0, FALSE); } -/* print the name as if mon_nam() was called, but assume that the player - * can always see the monster--used for probing and for monsters aggravating - * the player with a cursed potion of invisibility - */ +/* print the name as if mon_nam() (y_monnam() if tame) was called, but + assume that the player can always see the monster--used for probing and + for monsters aggravating the player with a cursed potion of invisibility; + also used for pet moving "reluctantly" onto cursed object when that pet + can be seen either before or after it moves */ char * noit_mon_nam(struct monst *mtmp) { - return x_monnam(mtmp, ARTICLE_THE, (char *) 0, + return x_monnam(mtmp, ARTICLE_YOUR, (char *) 0, (has_mgivenname(mtmp) ? (SUPPRESS_SADDLE | SUPPRESS_IT) : SUPPRESS_IT), FALSE); diff --git a/src/insight.c b/src/insight.c index 2b8bd27b7..7a04f4efe 100644 --- a/src/insight.c +++ b/src/insight.c @@ -3372,7 +3372,7 @@ mstatusline(struct monst *mtmp) /* avoid "Status of the invisible newt ..., invisible" */ /* and unlike a normal mon_nam, use "saddled" even if it has a name */ - Strcpy(monnambuf, x_monnam(mtmp, ARTICLE_THE, (char *) 0, + Strcpy(monnambuf, x_monnam(mtmp, ARTICLE_YOUR, (char *) 0, (SUPPRESS_IT | SUPPRESS_INVISIBLE), FALSE)); pline("Status of %s (%s, %s): Level %d HP %d(%d) AC %d%s.", From dab4784842dcae0c4a3b29362b792da975cbd975 Mon Sep 17 00:00:00 2001 From: PatR Date: Tue, 26 Nov 2024 21:52:47 -0800 Subject: [PATCH 095/791] Unix 'make spotless' - remove lev_comp + dgn_comp In case someone switches from NetHack-3.6 to NetHack-3.7 and does 'make spotless' after the switch instead of before, get rid of out of date lev_comp and dgn_comp. --- sys/unix/Makefile.utl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sys/unix/Makefile.utl b/sys/unix/Makefile.utl index c2b40bd87..2555449b0 100644 --- a/sys/unix/Makefile.utl +++ b/sys/unix/Makefile.utl @@ -441,7 +441,10 @@ clean-fixup: clean: clean-fixup -rm -f *.o +# obsolete dgn_comp and lev_comp could be left around from 3.6.x spotless: clean -rm -f makedefs recover dlb $(HACKLIB) -rm -f gif2txt txt2ppm tile2x11 tile2img.ttp xpm2img.ttp \ tilemap tileedit tile2bmp uudecode + -rm -f dgn_comp* dgn_lex.c dgn_yacc.c ../include/dgn_comp.h \ + lev_comp* lev_lex.c lev_yacc.c ../include/lev_comp.h From 6a6378d886b8b4f73476ed9247f1ab97e16165c1 Mon Sep 17 00:00:00 2001 From: PatR Date: Tue, 26 Nov 2024 22:12:05 -0800 Subject: [PATCH 096/791] some termcap.c bits Clear out the tempcap.c portion of an old stash entry. Only the combination of conditionals used for OSX has been exercised. --- win/tty/termcap.c | 48 +++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/win/tty/termcap.c b/win/tty/termcap.c index b3b141881..4cb40d4ea 100644 --- a/win/tty/termcap.c +++ b/win/tty/termcap.c @@ -403,8 +403,14 @@ tty_decgraphics_termcap_fixup(void) * Do not select NA ASCII as the primary font since people may * reasonably be using the UK character set. */ - if (SYMHANDLING(H_DEC)) + if (SYMHANDLING(H_DEC)) { xputs("\033)0"); /* "\e)0" load line drawing chars as secondary set */ + /* TI doesn't necessarily do this; explicitly switch to primary + font in case previous program (either before starting nethack + or during a shell escape) left the alternate font active */ + xputs(AE); + } + #ifdef PC9800 init_hilite(); #endif @@ -658,7 +664,7 @@ void term_clear_screen(void) { /* note: if CL is null, then termcap initialization failed, - so don't attempt screen-oriented I/O during final cleanup. + * so don't attempt screen-oriented I/O during final cleanup. */ if (CL) { xputs(CL); @@ -877,7 +883,7 @@ cl_eos(void) /* free after Robert Viduya */ about reconstructing them after the header file inclusion. */ #undef TRUE #undef FALSE -#define m_move curses_m_move /* Some curses.h decl m_move(), not used here */ +#define m_move curses_m_move /* some curses.h decl m_move(), not used here */ #include @@ -935,7 +941,7 @@ init_hilite(void) iflags.colorcount = colors; int md_len = 0; - if (colors < 8 || (MD == NULL) || (strlen(MD) == 0) + if (colors < 8 || !MD || !*MD || ((setf = tgetstr(nhStr("AF"), (char **) 0)) == (char *) 0 && (setf = tgetstr(nhStr("Sf"), (char **) 0)) == (char *) 0)) { /* Fallback when colors not available @@ -963,23 +969,16 @@ init_hilite(void) if (colors >= 16) { for (c = 0; c < SIZE(ti_map); c++) { - char *work; - /* system colors */ scratch = tparm(setf, ti_map[c].nh_color); - work = (char *) alloc(strlen(scratch) + 1); - Strcpy(work, scratch); - hilites[ti_map[c].nh_color] = work; - + hilites[ti_map[c].nh_color] = dupstr(scratch); /* bright colors */ scratch = tparm(setf, ti_map[c].nh_bright_color); - work = (char *) alloc(strlen(scratch) + 1); - Strcpy(work, scratch); - hilites[ti_map[c].nh_bright_color] = work; + hilites[ti_map[c].nh_bright_color] = dupstr(scratch); } } else { /* 8 system colors */ - md_len = strlen(MD); + md_len = (int) strlen(MD); c = 6; while (c--) { @@ -996,9 +995,8 @@ init_hilite(void) } if (colors >= 16) { - scratch = tparm(setf, COLOR_WHITE|BRIGHT); - hilites[CLR_WHITE] = (char *) alloc(strlen(scratch) + 1); - Strcpy(hilites[CLR_WHITE], scratch); + scratch = tparm(setf, COLOR_WHITE | BRIGHT); + hilites[CLR_WHITE] = dupstr(scratch); } else { scratch = tparm(setf, COLOR_WHITE); hilites[CLR_WHITE] = (char *) alloc(strlen(scratch) + md_len + 1); @@ -1012,8 +1010,7 @@ init_hilite(void) if (iflags.wc2_darkgray) { if (colors >= 16) { scratch = tparm(setf, COLOR_BLACK|BRIGHT); - hilites[CLR_BLACK] = (char *) alloc(strlen(scratch) + 1); - Strcpy(hilites[CLR_BLACK], scratch); + hilites[CLR_BLACK] = dupstr(scratch); } else { /* On many terminals, esp. those using classic PC CGA/EGA/VGA * textmode, specifying "hilight" and "black" simultaneously @@ -1043,9 +1040,11 @@ kill_hilite(void) if (hilites[CLR_BLACK] == nh_HI) return; + /* hilites[] will be set to NULL below, whether freed here or not */ + if (hilites[CLR_BLACK]) { if (hilites[CLR_BLACK] != hilites[CLR_BLUE]) - free(hilites[CLR_BLACK]); + free(hilites[CLR_BLACK]), hilites[CLR_BLACK] = NULL; } if (tgetnum(nhStr("Co")) >= 16) { if (hilites[CLR_BLUE]) @@ -1086,7 +1085,7 @@ kill_hilite(void) free(hilites[CLR_WHITE]); for (c = 0; c < CLR_MAX; c++) - hilites[c] = 0; + hilites[c] = NULL; } #else /* UNIX && TERMINFO */ @@ -1150,7 +1149,7 @@ analyze_seq(char *str, int *fg, int *bg) /* * Sets up highlighting sequences, using ANSI escape sequences (highlight code - * found in print.c). The nh_HI and nh_HE sequences (usually from SO) are + * found in wintty.c). The nh_HI and nh_HE sequences (usually from SO) are * scanned to find foreground and background colors. */ @@ -1173,6 +1172,7 @@ init_hilite(void) hilites[0] = NOCOL; for (c = 1; c < SIZE(hilites); c++) { char *foo; + foo = (char *) alloc(sizeof "\033b0"); if (tos_numcolors > 4) Sprintf(foo, "\033b%c", (c & ~BRIGHT) + '0'); @@ -1216,9 +1216,9 @@ init_hilite(void) if (c == CLR_BLUE) continue; #endif - if (c == foreg) + if (c == foreg) { hilites[c] = (char *) 0; - else if (c != hi_foreg || backg != hi_backg) { + } else if (c != hi_foreg || backg != hi_backg) { hilites[c] = (char *) alloc(sizeof "\033[%d;3%d;4%dm"); Sprintf(hilites[c], "\033[%d", !!(c & BRIGHT)); if ((c | BRIGHT) != (foreg | BRIGHT)) From 1fe23ff4d965ed9c028f47ced3260c798baa65ee Mon Sep 17 00:00:00 2001 From: PatR Date: Tue, 26 Nov 2024 22:15:41 -0800 Subject: [PATCH 097/791] vampshifters vs closed doors If a vampire in fog cloud form moves under a closed door and then before moving further gets killed and revives in vampire form, destroy the door instead of moving the vampire to a nearby open spot (which might be a distant spot if the map is crowded). If the door is trapped, explode the trap. That will damage the vampire but usually not by enough to kill it. This probably ought to be generalized to be done for any shape change at a closed location but I ran out of gas. --- src/mon.c | 66 +++++++++++++++++++++++++++++++++++++++++---------- src/monmove.c | 8 +++---- 2 files changed, 57 insertions(+), 17 deletions(-) diff --git a/src/mon.c b/src/mon.c index e3879d54b..bbfe06f4a 100644 --- a/src/mon.c +++ b/src/mon.c @@ -1937,7 +1937,7 @@ can_touch_safely(struct monst *mtmp, struct obj *otmp) * * to support the new pet behavior, this now returns the max # of objects * that a given monster could pick up from a pile. frequently this will be - * otmp->quan, but special cases for 'only one' now exist so. + * otmp->quan, but special cases for 'only one' now exist. * * this will probably cause very amusing behavior with pets and gold coins. * @@ -2812,15 +2812,20 @@ lifesaved_monster(struct monst *mtmp) } /* when a shape-shifted vampire is killed, it reverts to base form instead - of dying; moved into separate routine to unclutter mondead() */ + of dying; returns True if mtmp successfully revives, False otherwise; + "successfully revived" vampire might be killed by a booby trapped door */ staticfn boolean vamprises(struct monst *mtmp) { int mndx = mtmp->cham; + /* + * Protection from shape changers protects against this because + * the vampire will always be in normal form instead of shifted. + * So there's no need to check for that attribute being active. + */ if (ismnum(mndx) && mndx != monsndx(mtmp->data) && !(svm.mvitals[mndx].mvflags & G_GENOD)) { - coord new_xy; char action[BUFSZ]; /* alternate message phrasing for some monster types */ boolean spec_mon = (nonliving(mtmp->data) @@ -2833,30 +2838,28 @@ vamprises(struct monst *mtmp) /* construct a 'before' argument to pass to pline(); this used to construct a dynamic format string but that's overkill */ - Snprintf(action, sizeof action, "%s suddenly %s and rises as", + Snprintf(action, sizeof action, "%s%s %s%s and rises as", + Unaware ? "you dream that " : "", x_monnam(mtmp, ARTICLE_THE, spec_mon ? (char *) 0 : "seemingly dead", (SUPPRESS_INVISIBLE | AUGMENT_IT), FALSE), + Unaware ? "" : "suddenly ", spec_death ? "reconstitutes" : "transforms"); mtmp->mcanmove = 1; mtmp->mfrozen = 0; set_mon_min_mhpmax(mtmp, 10); /* mtmp->mhpmax=max(m_lev+1,10) */ mtmp->mhp = mtmp->mhpmax; - /* mtmp==u.ustuck can happen if previously a fog cloud - or poly'd hero is hugging a vampire bat */ + /* mtmp==u.ustuck can happen if previously a fog cloud or if + poly'd hero is hugging a vampire bat */ if (mtmp == u.ustuck) { if (u.uswallow) expels(mtmp, mtmp->data, FALSE); else uunstick(); } - /* if fog cloud is on a closed door space, move it to a more - appropriate spot for its intended new form */ - if (amorphous(mtmp->data) && closed_door(mtmp->mx, mtmp->my)) { - if (enexto(&new_xy, mtmp->mx, mtmp->my, &mons[mndx])) - rloc_to(mtmp, new_xy.x, new_xy.y); - } - (void) newcham(mtmp, &mons[mndx], NO_NC_FLAGS); + + if (!newcham(mtmp, &mons[mndx], NO_NC_FLAGS)) + return !DEADMONSTER(mtmp); mtmp->cham = (mtmp->data == &mons[mndx]) ? NON_PM : mndx; if (canspotmon(mtmp)) { @@ -2869,6 +2872,42 @@ vamprises(struct monst *mtmp) FALSE)); gv.vamp_rise_msg = TRUE; } + /* revived vampire is in normal shape, so can't be amorphous; if on + a closed door spot, destroy the door and if trapped, blow it up */ + if (closed_door(x, y)) { + static const char + door_smashed[] = "a door being smashed", + door_go_boom[] = "a door exploding"; + struct rm *door = &levl[x][y]; + boolean trapped = (door->doormask & D_TRAPPED) != 0, + seeit = cansee(x, y); + + set_msg_xy(x, y); /* You()/pline() will reset this */ + if (!seeit) + You_hear("%s.", trapped ? "an explosion" : door_smashed); + else if (!canspotmon(mtmp)) + You_see("%s.", trapped ? door_go_boom : door_smashed); + else if (!Unaware) + pline_The("door is smashed%s", + trapped ? " and it explodes!" : "."); + set_msg_xy(0, 0); /* in case none of the messages was delivered */ + + door->doormask = D_NODOOR; + unblock_point(x, y); + if (trapped) { + boolean trap_killed, save_verbose = flags.verbose; + + flags.verbose = FALSE; /* suppress mb_trapped() messages + * (that makes the 'seeit' arg moot) */ + trap_killed = mb_trapped(mtmp, seeit); + flags.verbose = save_verbose; + /* if the booby trap has killed the monster, mondied() will + have been called but no message about its death given yet; + mtmp was a vampire so use unconditional "destroyed" */ + if (trap_killed && canspotmon(mtmp) && !Unaware) + pline_mon(mtmp, "%s is destroyed!", Monnam(mtmp)); + } + } newsym(x, y); return TRUE; } @@ -4593,6 +4632,7 @@ hideunder(struct monst *mtmp) if (undetected && seenmon && seenobj) { if (!locomo) locomo = locomotion(mtmp->data, "hide"); + set_msg_xy(mtmp->mx, mtmp->my); /* pline() will reset this */ You_see("%s %s under %s.", seenmon, locomo, seenobj); iflags.last_msg = PLNMSG_HIDE_UNDER; gl.last_hider = mtmp->m_id; diff --git a/src/monmove.c b/src/monmove.c index 7705a3e1a..0b5cde2e1 100644 --- a/src/monmove.c +++ b/src/monmove.c @@ -1491,9 +1491,9 @@ postmov( && amorphous(ptr)) { if (flags.verbose && canseemon(mtmp)) pline_mon(mtmp, "%s %s under the door.", YMonnam(mtmp), - (ptr == &mons[PM_FOG_CLOUD] - || ptr->mlet == S_LIGHT) ? "flows" : "oozes"); - } else if (here->doormask & D_LOCKED && can_unlock) { + (ptr == &mons[PM_FOG_CLOUD] + || ptr->mlet == S_LIGHT) ? "flows" : "oozes"); + } else if ((here->doormask & D_LOCKED) != 0 && can_unlock) { /* like the vampshift hack, there are sequencing issues when the monster is moved to the door's spot first then door handling plus feedback comes after */ @@ -1532,7 +1532,7 @@ postmov( } } } - } else if (here->doormask & (D_LOCKED | D_CLOSED)) { + } else if ((here->doormask & (D_LOCKED | D_CLOSED)) != 0) { /* mfndpos guarantees this must be a doorbuster */ unsigned mask; From c1c74db90c7cf1084f75459f0d1c26d090204aa0 Mon Sep 17 00:00:00 2001 From: nhmall Date: Wed, 27 Nov 2024 09:48:35 -0500 Subject: [PATCH 098/791] update tested versions of Visual Studio 2024-11-27 --- sys/windows/Makefile.nmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sys/windows/Makefile.nmake b/sys/windows/Makefile.nmake index 50775c8c0..95b8bae17 100644 --- a/sys/windows/Makefile.nmake +++ b/sys/windows/Makefile.nmake @@ -9,7 +9,7 @@ # # Visual Studio Compilers Tested: # - Microsoft Visual Studio 2019 Community Edition v 16.11.42 -# - Microsoft Visual Studio 2022 Community Edition v 17.12.0 +# - Microsoft Visual Studio 2022 Community Edition v 17.12.2 # #============================================================================== # This is used for building two distinct executables of NetHack: @@ -1009,7 +1009,7 @@ rc=Rc.exe # # Recently tested versions: TESTEDVS2019 = 14.29.30157.0 -TESTEDVS2022 = 14.42.34433.0 +TESTEDVS2022 = 14.42.34435.0 VS2019CUR = $(TESTEDVS2019:.=) VS2022CUR = $(TESTEDVS2022:.=) From 9c0e47785ab15d8cfd39684e1d079d29fcd6f296 Mon Sep 17 00:00:00 2001 From: PatR Date: Wed, 27 Nov 2024 08:41:55 -0800 Subject: [PATCH 099/791] digging in ice If the spot in front of a closed drawbridge was ICE, digging there had issues.... --- doc/fixes3-7-0.txt | 2 ++ src/dig.c | 6 ++++-- src/do.c | 35 ++++++++++++++++++++--------------- src/mkmaze.c | 13 ++++++++----- src/trap.c | 41 ++++++++++++++++++++++++++++++----------- 5 files changed, 64 insertions(+), 33 deletions(-) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index 605bc49d4..0538b7750 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -1481,6 +1481,8 @@ if eating a tin's contents caused the hero to choke to death or turn to stone, when hero who is poly'd into metallivore form eats a tin, bypass "smells like " feedback and the "Eat it?" prompt; just eat the contents along with the tin without asking +digging in ice was handled inconsistently, particularly if done at the span + spot in front of closed drawbridge Fixes to 3.7.0-x General Problems Exposed Via git Repository diff --git a/src/dig.c b/src/dig.c index bedae5cf9..826be653a 100644 --- a/src/dig.c +++ b/src/dig.c @@ -859,8 +859,9 @@ liquid_flow( } if (ttmp) - (void) delfloortrap(ttmp); /* will untrap monster is one is here */ + (void) delfloortrap(ttmp); /* will untrap monster if one is here */ /* if any objects were frozen here, they're released now */ + obj_ice_effects(x, y, TRUE); unearth_objs(x, y); if (fillmsg) @@ -2081,7 +2082,8 @@ bury_objs(int x, int y) } } -/* move objects from buriedobjlist to fobj/nexthere lists */ +/* move objects from buriedobjlist to fobj/nexthere lists; if caller + converts terrain from ice to something, it should call obj_ice_effects() */ void unearth_objs(int x, int y) { diff --git a/src/do.c b/src/do.c index b3feccec2..f4f7c3e4d 100644 --- a/src/do.c +++ b/src/do.c @@ -48,9 +48,9 @@ dodrop(void) */ boolean boulder_hits_pool( - struct obj *otmp, - coordxy rx, coordxy ry, - boolean pushing) + struct obj *otmp, /* the object falling into a pool or water or lava */ + coordxy rx, coordxy ry, /* coordinates of the pool */ + boolean pushing) /* for a boulder, whether or not it is being pushed */ { if (!otmp || otmp->otyp != BOULDER) { impossible("Not a boulder?"); @@ -138,8 +138,9 @@ boulder_hits_pool( losehp(Maybe_Half_Phys(dmg), /* lava damage */ "molten lava", KILLED_BY); } else if (!fills_up && flags.verbose - && (pushing ? !Blind : cansee(rx, ry))) + && (pushing ? !Blind : cansee(rx, ry))) { pline("It sinks without a trace!"); + } } /* boulder is now gone */ @@ -157,7 +158,10 @@ boulder_hits_pool( * away. */ boolean -flooreffects(struct obj *obj, coordxy x, coordxy y, const char *verb) +flooreffects( + struct obj *obj, /* the object landing on the floor */ + coordxy x, coordxy y, /* map coordinates for spot where it is landing */ + const char *verb) /* "fall", "drop", "land", &c */ { struct trap *t; struct monst *mtmp; @@ -236,12 +240,10 @@ flooreffects(struct obj *obj, coordxy x, coordxy y, const char *verb) You_hear("a CRASH! beneath you."); } else if (!Blind && cansee(x, y)) { pline_The("boulder %s%s.", - (ttyp == TRAPDOOR && !tseen) - ? "triggers and " : "", - (ttyp == TRAPDOOR) - ? "plugs a trap door" - : (ttyp == HOLE) ? "plugs a hole" - : "fills a pit"); + (ttyp == TRAPDOOR && !tseen) ? "triggers and " : "", + (ttyp == TRAPDOOR) ? "plugs a trap door" + : (ttyp == HOLE) ? "plugs a hole" + : "fills a pit"); } else { Soundeffect(se_boulder_drop, 100); You_hear("a boulder %s.", verb); @@ -252,10 +254,13 @@ flooreffects(struct obj *obj, coordxy x, coordxy y, const char *verb) * || mondied) -> mondead -> m_detach -> fill_pit. */ deletedwithboulder: - if ((t = t_at(x, y)) != 0) - deltrap(t); - if (u.utrap && u_at(x, y)) - reset_utrap(FALSE); + /* creating a pit in ice results in that ice being turned into + floor so we shouldn't need any special ice handing here */ + if ((t = t_at(x, y)) != 0) { + (void) delfloortrap(t); + if (u.utrap && u_at(x, y)) + reset_utrap(FALSE); + } useupf(obj, 1L); bury_objs(x, y); newsym(x, y); diff --git a/src/mkmaze.c b/src/mkmaze.c index 0687a6c30..c1e2b6205 100644 --- a/src/mkmaze.c +++ b/src/mkmaze.c @@ -78,19 +78,22 @@ set_levltyp(coordxy x, coordxy y, schar newtyp) if (isok(x, y) && newtyp >= STONE && newtyp < MAX_TYPE) { if (CAN_OVERWRITE_TERRAIN(levl[x][y].typ)) { schar oldtyp = levl[x][y].typ; - boolean was_ice = (levl[x][y].typ == ICE); + /* typ==ICE || (typ==DRAWBRIDGE_UP && drawbridgemask==DB_ICE) */ + boolean was_ice = is_ice(x, y); levl[x][y].typ = newtyp; /* TODO? * if oldtyp used flags or horizontal differently from - * from the way newtyp will use them, clear them. + * the way newtyp will use them, clear them. */ - if (IS_LAVA(newtyp)) + if (IS_LAVA(newtyp)) /* [what about IS_LAVA(oldtyp)=>.lit = 0?] */ levl[x][y].lit = 1; - - if (was_ice && newtyp != ICE) + if (was_ice && newtyp != ICE) { + /* frozen corpses resume rotting, no more ice to melt away */ + obj_ice_effects(x, y, TRUE); spot_stop_timers(x, y, MELT_ICE_AWAY); + } if ((IS_FOUNTAIN(oldtyp) != IS_FOUNTAIN(newtyp)) || (IS_SINK(oldtyp) != IS_SINK(newtyp))) count_level_features(); /* level.flags.nfountains,nsinks */ diff --git a/src/trap.c b/src/trap.c index 91103153c..a39ba8ddc 100644 --- a/src/trap.c +++ b/src/trap.c @@ -455,7 +455,7 @@ struct trap * maketrap(coordxy x, coordxy y, int typ) { static union vlaunchinfo zero_vl; - boolean oldplace; + boolean oldplace, was_ice, clear_flags; struct trap *ttmp; struct rm *lev = &levl[x][y]; @@ -473,10 +473,10 @@ maketrap(coordxy x, coordxy y, int typ) || (u.utraptype == TT_LAVA && !is_lava(x, y)))) reset_utrap(FALSE); /* old remain valid */ - } else if (!CAN_OVERWRITE_TERRAIN(lev->typ) - || (IS_FURNITURE(lev->typ) - && (typ != PIT && typ != HOLE)) + } else if (!CAN_OVERWRITE_TERRAIN(lev->typ) /* stairs */ || is_pool_or_lava(x, y) + || (IS_FURNITURE(lev->typ) && (typ != PIT && typ != HOLE)) + || (lev->typ == DRAWBRIDGE_UP && typ == MAGIC_PORTAL) || (IS_AIR(lev->typ) && typ != MAGIC_PORTAL) || (typ == LEVEL_TELEP && single_level_branch(&u.uz))) { /* no trap on top of furniture (caller usually screens the @@ -522,22 +522,41 @@ maketrap(coordxy x, coordxy y, int typ) && (is_hole(typ) || IS_DOOR(lev->typ) || IS_WALL(lev->typ))) add_damage(x, y, /* schedule repair */ ((IS_DOOR(lev->typ) || IS_WALL(lev->typ)) - && !svc.context.mon_moving) - ? SHOP_HOLE_COST - : 0L); - lev->doormask = 0; /* subsumes altarmask, icedpool... */ - if (IS_ROOM(lev->typ)) /* && !IS_AIR(lev->typ) */ + && !svc.context.mon_moving) ? SHOP_HOLE_COST : 0L); + + clear_flags = TRUE; /* assume lev->flags needs to be reset */ + /* DRAWBRIDGE_UP passes the IS_ROOM() test so check it first; + it also needs to retain lev->drawbridgemask */ + if (lev->typ == DRAWBRIDGE_UP) { + /* bridge is closed and we're putting a hole or pit at the span + spot; this trap will be deleted if/when the bridge is opened; + terrain becomes room floor even if it was moat, lava, or ice */ + clear_flags = FALSE; /* keep lev->drawbridgemask */ + was_ice = (lev->drawbridgemask & DB_UNDER) == DB_ICE; + lev->drawbridgemask &= ~DB_UNDER; + lev->drawbridgemask |= DB_FLOOR; + if (was_ice) { + /* subset of set_levltyp() after changing ice to floor; + frozen corpses resume rotting, no more ice to melt away */ + obj_ice_effects(x, y, TRUE); + spot_stop_timers(x, y, MELT_ICE_AWAY); + } + } else if (IS_ROOM(lev->typ)) { (void) set_levltyp(x, y, ROOM); + /* * some cases which can happen when digging * down while phazing thru solid areas */ - else if (lev->typ == STONE || lev->typ == SCORR) + } else if (lev->typ == STONE || lev->typ == SCORR) { (void) set_levltyp(x, y, CORR); - else if (IS_WALL(lev->typ) || lev->typ == SDOOR) + } else if (IS_WALL(lev->typ) || lev->typ == SDOOR) { (void) set_levltyp(x, y, svl.level.flags.is_maze_lev ? ROOM : svl.level.flags.is_cavernous_lev ? CORR : DOOR); + } + if (clear_flags) + lev->flags = 0; /* set_levltyp doesn't take care of this [yet?] */ unearth_objs(x, y); break; From 5c0834e9d96f705e7e341db21cbef85cf81b30b2 Mon Sep 17 00:00:00 2001 From: PatR Date: Wed, 27 Nov 2024 10:32:09 -0800 Subject: [PATCH 100/791] hurtle_step() streamlining Eliminate some code duplication in hurtling. --- src/dothrow.c | 90 +++++++++++++++++++++------------------------------ 1 file changed, 37 insertions(+), 53 deletions(-) diff --git a/src/dothrow.c b/src/dothrow.c index ef61e7137..30af1e40b 100644 --- a/src/dothrow.c +++ b/src/dothrow.c @@ -676,14 +676,15 @@ walk_path( if (dx < 0) { x_change = -1; dx = -dx; - } else + } else { x_change = 1; + } if (dy < 0) { y_change = -1; dy = -dy; - } else + } else { y_change = 1; - + } i = err = 0; if (dx < dy) { while (i++ < dy) { @@ -767,7 +768,8 @@ hurtle_step(genericptr_t arg, coordxy x, coordxy y) struct monst *mon; boolean may_pass = TRUE, via_jumping, stopping_short; struct trap *ttmp; - int dmg = 0; + struct rm *lev; + int ltyp, dmg = 0; if (!isok(x, y)) { You_feel("the spirits holding you back."); @@ -779,69 +781,52 @@ hurtle_step(genericptr_t arg, coordxy x, coordxy y) } via_jumping = (EWwalking & I_SPECIAL) != 0L; stopping_short = (via_jumping && *range < 2); + lev = &levl[x][y]; + ltyp = lev->typ; if (!Passes_walls || !(may_pass = may_passwall(x, y))) { - boolean odoor_diag = (IS_DOOR(levl[x][y].typ) - && (levl[x][y].doormask & D_ISOPEN) - && (u.ux - x) && (u.uy - y)); - - if (IS_OBSTRUCTED(levl[x][y].typ) || closed_door(x, y) || odoor_diag) { - const char *s; + const char *why = NULL; + boolean diagonal = (u.ux - x) != 0 && (u.uy - y) != 0, + open_door = IS_DOOR(ltyp) && (lev->doormask & D_ISOPEN) != 0, + odoor_diag = open_door && diagonal; + if (IS_OBSTRUCTED(levl[x][y].typ) + || closed_door(x, y) || odoor_diag) { + why = IS_TREE(ltyp) ? "bumping into a tree" + : IS_OBSTRUCTED(ltyp) ? "bumping into a wall" + : odoor_diag ? "bumping into a door frame" + : "bumping into a closed door"; if (odoor_diag) - You("hit the door edge!"); + You("hit the door frame!"); pline("Ouch!"); - if (IS_TREE(levl[x][y].typ)) - s = "bumping into a tree"; - else if (IS_OBSTRUCTED(levl[x][y].typ)) - s = "bumping into a wall"; - else - s = "bumping into a door"; - dmg = rnd(2 + *range); - losehp(Maybe_Half_Phys(dmg), s, KILLED_BY); - wake_nearto(x,y, 10); - return FALSE; - } - if (levl[x][y].typ == IRONBARS) { + } else if (ltyp == IRONBARS) { + why = "crashing into iron bars"; You("crash into some iron bars. Ouch!"); - dmg = rnd(2 + *range); - losehp(Maybe_Half_Phys(dmg), "crashing into iron bars", - KILLED_BY); - wake_nearto(x,y, 20); - return FALSE; - } - if ((obj = sobj_at(BOULDER, x, y)) != 0) { + } else if ((obj = sobj_at(BOULDER, x, y)) != 0) { + why = "bumping into a boulder"; You("bump into a %s. Ouch!", xname(obj)); - dmg = rnd(2 + *range); - losehp(Maybe_Half_Phys(dmg), "bumping into a boulder", KILLED_BY); - wake_nearto(x,y, 10); - return FALSE; - } - if (!may_pass) { + } else if (!may_pass) { /* did we hit a no-dig non-wall position? */ + why = "touching the edge of the universe"; You("smack into something!"); - dmg = rnd(2 + *range); - losehp(Maybe_Half_Phys(dmg), "touching the edge of the universe", - KILLED_BY); - wake_nearto(x,y, 10); - return FALSE; - } - if ((u.ux - x) && (u.uy - y) && bad_rock(gy.youmonst.data, u.ux, y) - && bad_rock(gy.youmonst.data, x, u.uy)) { + } else if (diagonal + && bad_rock(gy.youmonst.data, u.ux, y) + && bad_rock(gy.youmonst.data, x, u.uy)) { boolean too_much = (gi.invent && (inv_weight() + weight_cap() > 600)); - /* Move at a diagonal. */ if (bigmonst(gy.youmonst.data) || too_much) { + why = "wedging into a narrow crevice"; You("%sget forcefully wedged into a crevice.", too_much ? "and all your belongings " : ""); - dmg = rnd(2 + *range); - losehp(Maybe_Half_Phys(dmg), "wedging into a narrow crevice", - KILLED_BY); - wake_nearto(x,y, 10); - return FALSE; } } + if (why) { + dmg = rnd(2 + *range); + losehp(Maybe_Half_Phys(dmg), why, KILLED_BY); + wake_nearto(x, y, 10); + return FALSE; + } } if ((mon = m_at(x, y)) != 0 @@ -918,7 +903,7 @@ hurtle_step(genericptr_t arg, coordxy x, coordxy y) /* if terrain type changes, levitation or flying might become blocked or unblocked; might issue message, so do this after map+vision has been updated for new location instead of right after u_on_newpos() */ - if (levl[u.ux][u.uy].typ != levl[ox][oy].typ) + if (ltyp != levl[ox][oy].typ) switch_terrain(); /* might be entering a special room (treasure zoo, thrown room, &c) that @@ -957,8 +942,7 @@ hurtle_step(genericptr_t arg, coordxy x, coordxy y) dotrap(ttmp, NO_TRAP_FLAGS); /* doesn't print messages */ } else if (ttmp->ttyp == FIRE_TRAP) { dotrap(ttmp, NO_TRAP_FLAGS); - } else if ((is_pit(ttmp->ttyp) || is_hole(ttmp->ttyp)) - && Sokoban) { + } else if ((is_pit(ttmp->ttyp) || is_hole(ttmp->ttyp)) && Sokoban) { /* air currents overcome the recoil in Sokoban; when jumping, caller performs last step and enters trap */ if (!via_jumping) From c255dc4bc44bec5e322c52d79caec21aa3e3d764 Mon Sep 17 00:00:00 2001 From: PatR Date: Wed, 27 Nov 2024 10:37:55 -0800 Subject: [PATCH 101/791] paranoid_confirm:trap when flying or levitating Avoid asking the player whether to _step_ on a trap when flying or levitating. locomotion() isn't the right routine for handling that. --- src/hack.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/hack.c b/src/hack.c index de5d072ff..1f66f813b 100644 --- a/src/hack.c +++ b/src/hack.c @@ -1776,9 +1776,14 @@ u_locomotion(const char *def) { boolean capitalize = (*def == highc(*def)); + /* regular locomotion() takes a monster type rather than a specific + monster, so can't tell whether it is operating on hero; + its is_flyer() and is_floater() tests wouldn't work on hero except + when hero is polymorphed and not wearing an amulet of flying + or boots/ring/spell of levitation */ return Levitation ? (capitalize ? "Float" : "float") - : Flying ? (capitalize ? "Fly" : "fly") - : locomotion(gy.youmonst.data, def); + : Flying ? (capitalize ? "Fly" : "fly") + : locomotion(gy.youmonst.data, def); } /* Return a simplified floor solid/liquid state based on hero's state */ @@ -1838,8 +1843,7 @@ staticfn boolean swim_move_danger(coordxy x, coordxy y) { schar newtyp = u_simple_floortyp(x, y); - boolean liquid_wall = IS_WATERWALL(newtyp) - || newtyp == LAVAWALL; + boolean liquid_wall = IS_WATERWALL(newtyp) || newtyp == LAVAWALL; if (Underwater && (is_pool(x,y) || IS_WATERWALL(newtyp))) return FALSE; @@ -2715,7 +2719,7 @@ domove_core(void) char qbuf[QBUFSZ]; Snprintf(qbuf, sizeof qbuf, "%s into that %s cloud?", - locomotion(gy.youmonst.data, "step"), + u_locomotion("step"), (reg_damg(newreg) > 0) ? "poison gas" : "vapor"); if (!paranoid_query(ParanoidConfirm, upstart(qbuf))) { nomul(0); @@ -2758,8 +2762,7 @@ domove_core(void) break; } Snprintf(qbuf, sizeof qbuf, "Really %s %s that %s?", - locomotion(gy.youmonst.data, "step"), - into ? "into" : "onto", + u_locomotion("step"), into ? "into" : "onto", defsyms[trap_to_defsym(traptype)].explanation); /* handled like paranoid_confirm:pray; when paranoid_confirm:trap isn't set, don't ask at all but if it is set (checked above), From 755b70de69c91625a7c2b57f3fa9556d71baa35e Mon Sep 17 00:00:00 2001 From: nhkeni Date: Wed, 27 Nov 2024 14:06:27 -0500 Subject: [PATCH 102/791] Make documentation of nhgitset.pl easier to find and find out about. --- DEVEL/Developer.txt | 5 ++++ DEVEL/VERSION | 44 +++-------------------------- DEVEL/nhgitset.pl | 68 ++++++++++++++++++++++++++++++--------------- 3 files changed, 54 insertions(+), 63 deletions(-) diff --git a/DEVEL/Developer.txt b/DEVEL/Developer.txt index f43f88f43..37fd69c59 100644 --- a/DEVEL/Developer.txt +++ b/DEVEL/Developer.txt @@ -58,6 +58,11 @@ NOTE: These instructions assume you are on the default branch; this _is_ NOTE: The following instructions require perl. If you do not have perl on your system, please install it before proceeding. +NOTE: More information on nhgitset.pl is available before installation via: + perldoc DEVEL/nhgitset.pl + After installation, the same information is available with: + git nhhelp nhgitset + A. If you have never set up git on this machine before: (This assumes you will only be using git for NetHack. If you are going to use it for other projects as well, think before you type.) diff --git a/DEVEL/VERSION b/DEVEL/VERSION index 01a759d53..3788cb6d5 100644 --- a/DEVEL/VERSION +++ b/DEVEL/VERSION @@ -1,40 +1,4 @@ -4 -Fixes: -- "nhcommit -a" has been fixed -- NHDT was hardwired in places -- no longer complain about a missing dat directory outside of the - NetHack source tree -- make update of gitinfo atomic -- Replace some hardwired directory separators with OS-dependent constructs - -Backwards Incompatibilities: -- NH_DATESUB's DATE() is now Date() to match the other variables -- MSYS2 requires an additional Perl package - the MSYS2 docs have - been updated - -New Help System: -- git nhhelp - This command mirrors "git help" for nh* commands. -- See git nhhelp nhsub for general help on substitution variables - -New Substitution Variables: --Brev() - An aBREViation of $PREFIX-Branch$:$PREFIX-Revision$ - this - may help get line length under control in file headers. --Assert(TYPE=VALUE) - If TYPE does not match VALUE, do not substitute on this line. - TYPE P checks VALUE against nethack.substprefix --Project(arg) - Returns nethack.projectname if there is no arg and an uppercase - version if arg is uc. - -Other New Features: -- Add nethack.projectname -- Documentation updates - see "git nhhelp nhsub" -- On checkout or merge of a branch, check for nhgitset version updates -- Move NH_DATESUB substitutions here from cron job to keep dates in sync -- PREFIX-* keywords now available in NH_DATESUB templates -- Support use of nhgitset.pl from a different repo; note that update - checks will be dependent on keeping the original source repo up-to-date - and in the same location. - +5 +Please see "git log DEVEL" for previous changes. +Make documentation of nhgitset.pl easier to find and +find out about. diff --git a/DEVEL/nhgitset.pl b/DEVEL/nhgitset.pl index 984d45a32..e235a33ce 100755 --- a/DEVEL/nhgitset.pl +++ b/DEVEL/nhgitset.pl @@ -153,6 +153,7 @@ my $nhsub = catfile(curdir(),'.git','hooks','nhsub'); &add_help('NHsubst', 'NHsubst'); &add_help('NHgithook', 'NHgithook.pm'); +&add_help('nhgitset', 'gitsetdocs', '../../DEVEL/nhgitset.pl'); # removed at version 3 @@ -183,7 +184,7 @@ $cmd = catfile(curdir(),'.git','hooks','NHsubst'); print STDERR "Running directories\n" if($opt_v); -# copy directories into .git (right now that's just hooks +# copy directories into .git (right now that's just hooks and nhgitset.pl) my @gitadd = length($gitadddir)?glob("$gitadddir$DS*"):undef; foreach my $dir ( (glob("$srcdir$DS*"), @gitadd) ){ next unless(-d $dir); @@ -209,6 +210,7 @@ foreach my $dir ( (glob("$srcdir$DS*"), @gitadd) ){ &process_override($enddir, "POST"); } } +&do_file_nhgitset(); &check_gitvars; # for variable substitution @@ -219,26 +221,31 @@ if($version_old != $version_new or $opt_f){ exit 0; +# @files: [0] is the name under .git/hooks; others are places to +# check during configuration sub add_help { - my($cmd, $file) = @_; + my($cmd, @files) = @_; - &add_config("nethack.aliashelp.$cmd", $file); + &add_config("nethack.aliashelp.$cmd", $files[0]); # pull out =for nhgitset CMD description... - my $desc = ''; - open my $fh, "<", "$DEVhooksdir/$file"; - if($fh){ - while(<$fh>){ - m/^=for\s+nhgitset\s+\Q$cmd\E\s+(.*)/ && do { - $desc = $1; - last; + my $desc; + foreach my $file (@files){ + open my $fh, "<", "$DEVhooksdir/$file"; + if($fh){ + while(<$fh>){ + m/^=for\s+nhgitset\s+\Q$cmd\E\s+(.*)/ && do { + $desc = $1; + goto found; + } } + close $fh; + } else { + warn "Can't open: '$DEVhooksdir/$file' ($!)\n"; } - close $fh; - } else { - warn "Can't open: '$DEVhooksdir/$file' ($!)\n"; } +found: - if(length $desc){ + if($desc){ &add_config("nethack.aliasdesc.$cmd", $desc); } else { &add_config("nethack.aliasdesc.$cmd", "(no description available)"); @@ -344,13 +351,25 @@ sub do_dir_hooksdir { } } +sub do_file_nhgitset { + my $infile = "DEVEL/nhgitset.pl"; + my $outfile = ".git/hooks/gitsetdocs"; + open IN, "<", $infile or die "Can't open $infile:$!"; + open OUT, ">", $outfile or die "Can't open $outfile:$!"; + my $started; + print IN "die \"DO NOT RUN THIS FILE\n\""; + while(){ + m/^__END__/ && do {$started =1; next}; + print OUT if($started); + } + close OUT; + close IN; +} + +#(can we change the .gitattributes syntax to include a comment character?) +#maybe [comment] attr.c:parse_attr_line +#grr - looks like # is the comment character __END__ -(can we change the .gitattributes syntax to include a comment character?) -maybe [comment] attr.c:parse_attr_line -grr - looks like # is the comment character - - - =head1 NAME nhgitset.pl - Setup program for NetHack git repositories @@ -363,9 +382,10 @@ nhgitset.pl - Setup program for NetHack git repositories =head1 DESCRIPTION -nhgitset.pl installs NetHack-specific setup after a C (or after -changes to the desired configuration, which are installed by re-running -nhgitset.pl). +nhgitset.pl installs NetHack-specific setup after a C or after +changes to the setup, which are installed by re-running nhgitset.pl. If +an upgrade is needed, you will be informed during a C or similar +operation. The following options are available: @@ -445,3 +465,5 @@ nethack.aliasdesc.* 1 Fail. 2 Intervention required. + +=for nhgitset nhgitset NetHack git helper installer From cbc93a05556e863972bcf3f8e368a3d59e745ed5 Mon Sep 17 00:00:00 2001 From: PatR Date: Thu, 28 Nov 2024 11:33:26 -0800 Subject: [PATCH 103/791] github issue #1312 - prot from shape changers Issue reported by youkan700: shape change anomalies. Shapechangers could change shape despite active protection-from-shape-changers if hero wore two rings of protection from shape changers and took one off. Shapechangers who migrated to a not-yet-visited level that eventually got visited with protection from shape changers in effect would be stuck in their current shape, even if the PfSC attribute got toggled off and back on. The issue included suggested fixes and those are what I've used. I noticed a third case that only applies to wizard mode: if player used #wizintrinsic to set a timed value for PfSC, monsters wouldn't resume changing shape after it timed out, unless/until it got toggled on and back off via a PfSC ring or hero left the level and returned. Fixes #1312 --- src/do_wear.c | 9 +++++---- src/dog.c | 6 ++++++ src/mon.c | 2 +- src/timeout.c | 6 ++++++ 4 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/do_wear.c b/src/do_wear.c index 72ecfd75d..e7cc1be64 100644 --- a/src/do_wear.c +++ b/src/do_wear.c @@ -1410,10 +1410,11 @@ Ring_off_or_gone(struct obj *obj, boolean gone) find_ac(); /* updates botl */ break; case RIN_PROTECTION_FROM_SHAPE_CHAN: - /* If you're no longer protected, let the chameleons - * change shape again -dgk - */ - restartcham(); + /* if you're no longer protected, let the chameleons change + shape again; however, might still be protected if wearing + 2nd ring of this type (or via #wizintrinsic) */ + if (!Protection_from_shape_changers) + restartcham(); break; } } diff --git a/src/dog.c b/src/dog.c index deade5f5e..9c4f85560 100644 --- a/src/dog.c +++ b/src/dog.c @@ -417,6 +417,12 @@ mon_arrive(struct monst *mtmp, int when) fromdlev.dnum = mtmp->mtrack[2].x; fromdlev.dlevel = mtmp->mtrack[2].y; mon_track_clear(mtmp); + /* in case Protection_from_shape_changers is different now from when + 'mtmp' went onto the migrating monsters list; that's handled in + getlev() when returning to a previously visited level and by the + special level code for monsters specified in the level, but needed + here for monsters migrating to a newly created level */ + restore_cham(mtmp); if (mtmp == u.usteed) return; /* don't place steed on the map */ diff --git a/src/mon.c b/src/mon.c index bbfe06f4a..1c2ecad07 100644 --- a/src/mon.c +++ b/src/mon.c @@ -4465,7 +4465,7 @@ get_iter_mons_xy( /* force all chameleons and mimics to become themselves and werecreatures to revert to human form; called when Protection_from_shape_changers gets - activated via wearing or eating ring or wizintrinsics */ + activated via wearing or eating ring or via #wizintrinsic */ void rescham(void) { diff --git a/src/timeout.c b/src/timeout.c index 8553320bb..cb9800994 100644 --- a/src/timeout.c +++ b/src/timeout.c @@ -930,6 +930,12 @@ nh_timeout(void) case GLIB: make_glib(0); /* might update persistent inventory */ break; + case PROT_FROM_SHAPE_CHANGERS: + /* timed Protection_from_shape_changers is via + #wizintrinsic only */ + if (!Protection_from_shape_changers) + restartcham(); + break; } } From 689f6c4c82343c18aa33413c135aaf83fd9a52c8 Mon Sep 17 00:00:00 2001 From: PatR Date: Thu, 28 Nov 2024 14:24:27 -0800 Subject: [PATCH 104/791] prayer lint --- src/pray.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/pray.c b/src/pray.c index 501c9e293..360030e65 100644 --- a/src/pray.c +++ b/src/pray.c @@ -1135,9 +1135,11 @@ pleased(aligntyp g_align) break; case 3: + /* up to 10 troubles */ fix_worst_trouble(trouble); + /*FALLTHRU*/ case 2: - /* arbitrary number of tries */ + /* up to 9 troubles */ while ((trouble = in_trouble()) > 0 && (++tryct < 10)) fix_worst_trouble(trouble); break; @@ -1145,6 +1147,7 @@ pleased(aligntyp g_align) case 1: if (trouble > 0) fix_worst_trouble(trouble); + break; case 0: break; /* your god blows you off, too bad */ } From 149cb96020c9fb6c88e3b405f2fc5637dcc2fe11 Mon Sep 17 00:00:00 2001 From: PatR Date: Fri, 29 Nov 2024 23:30:04 -0800 Subject: [PATCH 105/791] github issue #1299 - sleeping mimics Issue reported by elunna: sleeping mimics can grab the hero, and zapping a concealed mimic with a wand of sleep describes the target as a mimic but doesn't bring it out of concealment. The grab-when-asleep case is reasonable. It's a reflexive counter- attack by a magical creature. And the mimic wakes up in the process. But the mimic wasn't being brought out of concealment. Do that. Unconceal mimics hit by wand of sleep unless already sleeping. Fixes #1299 --- src/mhitm.c | 8 +++++++- src/objnam.c | 4 ++-- src/pager.c | 13 +++++++++---- src/uhitm.c | 40 +++++++++++++++++++++++++++++++++------- src/zap.c | 38 ++++++++++++++++++++++++++------------ 5 files changed, 77 insertions(+), 26 deletions(-) diff --git a/src/mhitm.c b/src/mhitm.c index 10fa8cfc8..2473c1417 100644 --- a/src/mhitm.c +++ b/src/mhitm.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 mhitm.c $NHDT-Date: 1698939796 2023/11/02 15:43:16 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.244 $ */ +/* NetHack 3.7 mhitm.c $NHDT-Date: 1732979463 2024/11/30 07:11:03 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.253 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2011. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1209,6 +1209,12 @@ paralyze_monst(struct monst *mon, int amt) int sleep_monst(struct monst *mon, int amt, int how) { + /* reveal mimic unless already asleep or paralyzed (won't be 'busy') */ + if (how >= 0 && !mon->msleeping && !mon->mfrozen + && mon->data->mlet == S_MIMIC && (M_AP_TYPE(mon) == M_AP_FURNITURE + || M_AP_TYPE(mon) == M_AP_OBJECT)) + seemimic(mon); + if (resists_sleep(mon) || defended(mon, AD_SLEE) || (how >= 0 && resist(mon, (char) how, 0, NOTELL))) { shieldeff(mon->mx, mon->my); diff --git a/src/objnam.c b/src/objnam.c index 47c9eca44..334d5b7ed 100644 --- a/src/objnam.c +++ b/src/objnam.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 objnam.c $NHDT-Date: 1711809641 2024/03/30 14:40:41 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.427 $ */ +/* NetHack 3.7 objnam.c $NHDT-Date: 1732979463 2024/11/30 07:11:03 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.439 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2011. */ /* NetHack may be freely redistributed. See license for details. */ @@ -2475,7 +2475,7 @@ static const char wrpsym[] = { WAND_CLASS, RING_CLASS, POTION_CLASS, /* return form of the verb (input plural) if xname(otmp) were the subject */ char * -otense(struct obj* otmp,const char * verb) +otense(struct obj *otmp, const char *verb) { char *buf; diff --git a/src/pager.c b/src/pager.c index 74ceeccbe..079d182a7 100644 --- a/src/pager.c +++ b/src/pager.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 pager.c $NHDT-Date: 1724094301 2024/08/19 19:05:01 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.279 $ */ +/* NetHack 3.7 pager.c $NHDT-Date: 1732979463 2024/11/30 07:11:03 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.282 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2018. */ /* NetHack may be freely redistributed. See license for details. */ @@ -280,7 +280,10 @@ mhidden_description( /* extracted from lookat(); also used by namefloorobj() */ boolean -object_from_map(int glyph, coordxy x, coordxy y, struct obj **obj_p) +object_from_map( + int glyph, + coordxy x, coordxy y, + struct obj **obj_p) { boolean fakeobj = FALSE, mimic_obj = FALSE; struct monst *mtmp; @@ -305,8 +308,10 @@ object_from_map(int glyph, coordxy x, coordxy y, struct obj **obj_p) if (!otmp || otmp->otyp != glyphotyp) { /* this used to exclude STRANGE_OBJECT; now caller deals with it */ otmp = mksobj(glyphotyp, FALSE, FALSE); - if (!otmp) - return FALSE; + /* even though we pass False for mksobj()'s 'init' arg, corpse-rot, + egg-hatch, and figurine-transform timers get initialized */ + if (otmp->timed) + obj_stop_timers(otmp); fakeobj = TRUE; if (otmp->oclass == COIN_CLASS) otmp->quan = 2L; /* to force pluralization */ diff --git a/src/uhitm.c b/src/uhitm.c index e0a403ebb..da34794a9 100644 --- a/src/uhitm.c +++ b/src/uhitm.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 uhitm.c $NHDT-Date: 1713334817 2024/04/17 06:20:17 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.444 $ */ +/* NetHack 3.7 uhitm.c $NHDT-Date: 1732979463 2024/11/30 07:11:03 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.451 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -6030,8 +6030,11 @@ DISABLE_WARNING_FORMAT_NONLITERAL void stumble_onto_mimic(struct monst *mtmp) { - const char *fmt = "Wait! That's %s!", *generic = "a monster", *what = 0; + static char generic[] = "a monster"; + char fmt[QBUFSZ]; + 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)) @@ -6045,16 +6048,39 @@ stumble_onto_mimic(struct monst *mtmp) } else { int glyph = levl[u.ux + u.dx][u.uy + u.dy].glyph; - if (glyph_is_cmap(glyph) && (glyph_to_cmap(glyph) == S_hcdoor - || glyph_to_cmap(glyph) == S_vcdoor)) - fmt = "The door actually was %s!"; - else if (glyph_is_object(glyph) && glyph_to_obj(glyph) == GOLD_PIECE) - fmt = "That gold was %s!"; + 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); + } else if (glyph_is_object(glyph)) { + boolean fakeobj; + const char *otmp_name; + struct obj *otmp = NULL; + + 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"); + if (fakeobj && otmp) { + otmp->where = OBJ_FREE; /* object_from_map set to OBJ_FLOOR */ + dealloc_obj(otmp); + } + } /* cloned Wiz starts out mimicking some other monster and might make himself invisible before being revealed */ if (mtmp->minvis && !See_invisible) what = generic; + else if (mtmp->data->mlet == S_MIMIC + && (M_AP_TYPE(mtmp) == M_AP_OBJECT + || M_AP_TYPE(mtmp) == M_AP_FURNITURE) + && (mtmp->msleeping || mtmp->mfrozen)) + /* BUG: this will misclassify a paralyzed mimic as sleeping */ + what = x_monnam(mtmp, ARTICLE_A, "sleeping", 0, FALSE); else what = a_monnam(mtmp); } diff --git a/src/zap.c b/src/zap.c index 2748acd77..dede87a0d 100644 --- a/src/zap.c +++ b/src/zap.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 zap.c $NHDT-Date: 1723946858 2024/08/18 02:07:38 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.542 $ */ +/* NetHack 3.7 zap.c $NHDT-Date: 1732979463 2024/11/30 07:11:03 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.551 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2013. */ /* NetHack may be freely redistributed. See license for details. */ @@ -148,7 +148,11 @@ learnwand(struct obj *obj) } } -/* Routines for IMMEDIATE wands and spells. */ +/* + * Routines for IMMEDIATE wands and spells. + * Also RAY or NODIR for wands that are being broken rather than zapped. + */ + /* bhitm: monster mtmp was hit by the effect of wand or spell otmp */ int bhitm(struct monst *mtmp, struct obj *otmp) @@ -350,6 +354,10 @@ 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); wake = closeholdingtrap(mtmp, &learn_it); break; case WAN_PROBING: @@ -360,6 +368,9 @@ 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); wake = FALSE; /* don't want immediate counterattack */ if (mtmp == u.ustuck) { /* zapping either holder/holdee or self [zapyourself()] will @@ -450,7 +461,8 @@ bhitm(struct monst *mtmp, struct obj *otmp) break; case WAN_SLEEP: /* (broken wand) */ /* [wakeup() doesn't rouse victims of temporary sleep, - so it's okay to leave `wake' set to TRUE here] */ + so it's okay to leave `wake' set to TRUE here; + revealing concealed mimic is handled by sleep_monst()] */ reveal_invis = TRUE; if (sleep_monst(mtmp, d(1 + otmp->spe, 12), WAND_CLASS)) slept_monst(mtmp); @@ -458,6 +470,8 @@ bhitm(struct monst *mtmp, struct obj *otmp) learn_it = TRUE; break; case SPE_STONE_TO_FLESH: + /* FIXME: mimics disguished as stone furniture or stone object + should be taken out of concealment. */ if (monsndx(mtmp->data) == PM_STONE_GOLEM) { char *name = Monnam(mtmp); @@ -3491,7 +3505,8 @@ exclam(int force) } void -hit(const char *str, /* zap text or missile name */ +hit( + const char *str, /* zap text or missile name */ struct monst *mtmp, /* target; for missile, might be hero */ const char *force) /* usually either "." or "!" via exclam() */ { @@ -3500,11 +3515,8 @@ hit(const char *str, /* zap text or missile name */ && (cansee(gb.bhitpos.x, gb.bhitpos.y) || canspotmon(mtmp) || engulfing_u(mtmp)))); - if (!verbosely) - pline("%s %s it.", The(str), vtense(str, "hit")); - else - pline("%s %s %s%s", The(str), vtense(str, "hit"), - mon_nam(mtmp), force); + pline("%s %s %s%s", The(str), vtense(str, "hit"), + verbosely ? mon_nam(mtmp) : "it", force); } void @@ -4209,7 +4221,8 @@ zhitm( tmp += destroy_items(mon, AD_COLD, orig_dmg); break; case ZT_SLEEP: - /* possibly resistance and shield effect handled by sleep_monst() */ + /* resistance and shield effect and revealing concealed mimic are + handled by sleep_monst() */ tmp = 0; (void) sleep_monst(mon, d(nd, 25), type == ZT_WAND(ZT_SLEEP) ? WAND_CLASS : '\0'); @@ -4576,8 +4589,9 @@ burn_floor_objects( /* will zap/spell/breath attack score a hit against armor class `ac'? */ staticfn int -zap_hit(int ac, - int type) /* either hero cast spell type or 0 */ +zap_hit( + int ac, + int type) /* either hero cast spell type or 0 */ { int chance = rn2(20); int spell_bonus = type ? spell_hit_bonus(type) : 0; From 52876c4798cb8368451b6c94986e54cffd6dc536 Mon Sep 17 00:00:00 2001 From: Guillaume Brunerie Date: Sat, 30 Nov 2024 14:06:13 +0100 Subject: [PATCH 106/791] WASM fixes --- include/global.h | 3 + src/role.c | 2 +- sys/libnh/libnhmain.c | 174 ++++++++++++++++++++++++-- sys/unix/hints/include/cross-pre2.370 | 9 +- win/shim/winshim.c | 70 +++++------ 5 files changed, 203 insertions(+), 55 deletions(-) diff --git a/include/global.h b/include/global.h index d2651b3b8..7a32d105f 100644 --- a/include/global.h +++ b/include/global.h @@ -482,6 +482,9 @@ extern struct nomakedefs_s nomakedefs; #if !defined(CROSS_TO_WASM) /* no popen in WASM */ #define PANICTRACE_GDB #endif +#ifdef CROSS_TO_WASM +#undef COMPRESS +#endif #endif /* Supply nethack_enter macro if not supplied by port */ diff --git a/src/role.c b/src/role.c index 7055ff5b7..3fd57d887 100644 --- a/src/role.c +++ b/src/role.c @@ -2175,7 +2175,7 @@ genl_player_selection(void) /*NOTREACHED*/ } -#if defined(TTY_GRAPHICS) || defined(CURSES_GRAPHICS) +#if defined(TTY_GRAPHICS) || defined(CURSES_GRAPHICS) || defined(SHIM_GRAPHICS) /* ['#else' far below] */ staticfn boolean reset_role_filtering(void); diff --git a/sys/libnh/libnhmain.c b/sys/libnh/libnhmain.c index 81ae866cb..56ee3cb58 100644 --- a/sys/libnh/libnhmain.c +++ b/sys/libnh/libnhmain.c @@ -12,6 +12,7 @@ #include #include #include +#include #ifndef O_RDONLY #include #endif @@ -174,6 +175,12 @@ nhmain(int argc, char *argv[]) chdirx(dir, 1); #endif +#ifdef __EMSCRIPTEN__ + js_helpers_init(); + js_constants_init(); + js_globals_init(); +#endif + #ifdef _M_UNIX check_sco_console(); #endif @@ -201,11 +208,6 @@ nhmain(int argc, char *argv[]) process_options(argc, argv); /* command line options */ #ifdef WINCHAIN commit_windowchain(); -#endif -#ifdef __EMSCRIPTEN__ - js_helpers_init(); - js_constants_init(); - js_globals_init(); #endif init_nhwindows(&argc, argv); /* now we can set up window system */ #ifdef _M_UNIX @@ -781,9 +783,9 @@ EM_JS(void, js_helpers_init, (), { globalThis.nethackGlobal = globalThis.nethackGlobal || {}; globalThis.nethackGlobal.helpers = globalThis.nethackGlobal.helpers || {}; - installHelper(displayInventory); - installHelper(getPointerValue); - installHelper(setPointerValue); + installHelper(displayInventory, "displayInventory"); + installHelper(getPointerValue, "getPointerValue"); + installHelper(setPointerValue, "setPointerValue"); // used by update_inventory function displayInventory() { @@ -804,6 +806,8 @@ EM_JS(void, js_helpers_init, (), { return getValue(ptr, "*"); case "c": // char return String.fromCharCode(getValue(ptr, "i8")); + case "b": + return getValue(ptr, "i8") == 1; case "0": /* 2^0 = 1 byte */ return getValue(ptr, "i8"); case "1": /* 2^1 = 2 bytes */ @@ -816,8 +820,8 @@ EM_JS(void, js_helpers_init, (), { return getValue(ptr, "float"); case "d": // double return getValue(ptr, "double"); - case "o": // overloaded: multiple types - return ptr; + case "v": // void + return undefined; default: throw new TypeError ("unknown type:" + type); } @@ -828,7 +832,8 @@ EM_JS(void, js_helpers_init, (), { // console.log("setPointerValue", name, "0x" + ptr.toString(16), type, value); switch (type) { case "p": - throw new Error("not implemented"); + setValue(ptr, value, "*"); + break; case "s": if(typeof value !== "string") throw new TypeError(`expected ${name} return type to be string`); @@ -841,6 +846,11 @@ EM_JS(void, js_helpers_init, (), { throw new TypeError(`expected ${name} return type to be integer`); setValue(ptr, value, "i32"); break; + case "1": + if(typeof value !== "number" || !Number.isInteger(value)) + throw new TypeError(`expected ${name} return type to be integer`); + setValue(ptr, value, "i16"); + break; case "c": if(typeof value !== "number" || value < 0 || value > 128) throw new TypeError(`expected ${name} return type to be integer representing an ASCII character`); @@ -857,6 +867,10 @@ EM_JS(void, js_helpers_init, (), { throw new TypeError(`expected ${name} return type to be double`); setValue(ptr, value, "double"); break; + case "b": + if (typeof value !== "boolean") + throw new TypeError(`expected ${name} return type to be boolean`); + setValue(ptr, value ? 1 : 0, "i8"); case "v": break; default: @@ -896,11 +910,19 @@ EM_JS(void, set_const_str, (char *scope_str, char *name_str, char *input_str), { globalThis.nethackGlobal.constants[scope] = globalThis.nethackGlobal.constants[scope] || {}; globalThis.nethackGlobal.constants[scope][name] = str; }); +#define SET_POINTER(name) set_const_ptr(#name, (void *)&name); +EM_JS(void, set_const_ptr, (char *name_str, void* ptr), { + let name = UTF8ToString(name_str); + + globalThis.nethackGlobal.pointers = globalThis.nethackGlobal.pointers || {}; + globalThis.nethackGlobal.pointers[name] = ptr; +}); void js_constants_init() { EM_ASM({ globalThis.nethackGlobal = globalThis.nethackGlobal || {}; globalThis.nethackGlobal.constants = globalThis.nethackGlobal.constants || {}; + globalThis.nethackGlobal.pointers = globalThis.nethackGlobal.pointers || {}; }); // create_nhwindow @@ -989,8 +1011,7 @@ void js_constants_init() { // copyright SET_CONSTANT_STRING("COPYRIGHT", COPYRIGHT_BANNER_A); SET_CONSTANT_STRING("COPYRIGHT", COPYRIGHT_BANNER_B); - // XXX: not set for cross-compile - //SET_CONSTANT_STRING("COPYRIGHT", COPYRIGHT_BANNER_C); + set_const_str("COPYRIGHT", "COPYRIGHT_BANNER_C", (char*) COPYRIGHT_BANNER_C); SET_CONSTANT_STRING("COPYRIGHT", COPYRIGHT_BANNER_D); // glyphs @@ -1042,6 +1063,119 @@ void js_constants_init() { SET_CONSTANT("COLOR_ATTR", HL_ATTCLR_BLINK); SET_CONSTANT("COLOR_ATTR", HL_ATTCLR_INVERSE); SET_CONSTANT("COLOR_ATTR", BL_ATTCLR_MAX); + + SET_CONSTANT("BL_MASK", BL_MASK_BAREH); + SET_CONSTANT("BL_MASK", BL_MASK_BLIND); + SET_CONSTANT("BL_MASK", BL_MASK_BUSY); + SET_CONSTANT("BL_MASK", BL_MASK_CONF); + SET_CONSTANT("BL_MASK", BL_MASK_DEAF); + SET_CONSTANT("BL_MASK", BL_MASK_ELF_IRON); + SET_CONSTANT("BL_MASK", BL_MASK_FLY); + SET_CONSTANT("BL_MASK", BL_MASK_FOODPOIS); + SET_CONSTANT("BL_MASK", BL_MASK_GLOWHANDS); + SET_CONSTANT("BL_MASK", BL_MASK_GRAB); + SET_CONSTANT("BL_MASK", BL_MASK_HALLU); + SET_CONSTANT("BL_MASK", BL_MASK_HELD); + SET_CONSTANT("BL_MASK", BL_MASK_ICY); + SET_CONSTANT("BL_MASK", BL_MASK_INLAVA); + SET_CONSTANT("BL_MASK", BL_MASK_LEV); + SET_CONSTANT("BL_MASK", BL_MASK_PARLYZ); + SET_CONSTANT("BL_MASK", BL_MASK_RIDE); + SET_CONSTANT("BL_MASK", BL_MASK_SLEEPING); + SET_CONSTANT("BL_MASK", BL_MASK_SLIME); + SET_CONSTANT("BL_MASK", BL_MASK_SLIPPERY); + SET_CONSTANT("BL_MASK", BL_MASK_STONE); + SET_CONSTANT("BL_MASK", BL_MASK_STRNGL); + SET_CONSTANT("BL_MASK", BL_MASK_STUN); + SET_CONSTANT("BL_MASK", BL_MASK_SUBMERGED); + SET_CONSTANT("BL_MASK", BL_MASK_TERMILL); + SET_CONSTANT("BL_MASK", BL_MASK_TETHERED); + SET_CONSTANT("BL_MASK", BL_MASK_TRAPPED); + SET_CONSTANT("BL_MASK", BL_MASK_UNCONSC); + SET_CONSTANT("BL_MASK", BL_MASK_WOUNDEDL); + SET_CONSTANT("BL_MASK", BL_MASK_HOLDING); + + SET_CONSTANT("ROLE_RACEMASK", MH_HUMAN); + SET_CONSTANT("ROLE_RACEMASK", MH_ELF); + SET_CONSTANT("ROLE_RACEMASK", MH_DWARF); + SET_CONSTANT("ROLE_RACEMASK", MH_GNOME); + SET_CONSTANT("ROLE_RACEMASK", MH_ORC); + + SET_CONSTANT("ROLE_GENDMASK", ROLE_MALE); + SET_CONSTANT("ROLE_GENDMASK", ROLE_FEMALE); + SET_CONSTANT("ROLE_GENDMASK", ROLE_NEUTER); + + SET_CONSTANT("ROLE_ALIGNMASK", ROLE_LAWFUL); + SET_CONSTANT("ROLE_ALIGNMASK", ROLE_NEUTRAL); + SET_CONSTANT("ROLE_ALIGNMASK", ROLE_CHAOTIC); + + SET_CONSTANT("blconditions", bl_bareh); + SET_CONSTANT("blconditions", bl_blind); + SET_CONSTANT("blconditions", bl_busy); + SET_CONSTANT("blconditions", bl_conf); + SET_CONSTANT("blconditions", bl_deaf); + SET_CONSTANT("blconditions", bl_elf_iron); + SET_CONSTANT("blconditions", bl_fly); + SET_CONSTANT("blconditions", bl_foodpois); + SET_CONSTANT("blconditions", bl_glowhands); + SET_CONSTANT("blconditions", bl_grab); + SET_CONSTANT("blconditions", bl_hallu); + SET_CONSTANT("blconditions", bl_held); + SET_CONSTANT("blconditions", bl_icy); + SET_CONSTANT("blconditions", bl_inlava); + SET_CONSTANT("blconditions", bl_lev); + SET_CONSTANT("blconditions", bl_parlyz); + SET_CONSTANT("blconditions", bl_ride); + SET_CONSTANT("blconditions", bl_sleeping); + SET_CONSTANT("blconditions", bl_slime); + SET_CONSTANT("blconditions", bl_slippery); + SET_CONSTANT("blconditions", bl_stone); + SET_CONSTANT("blconditions", bl_strngl); + SET_CONSTANT("blconditions", bl_stun); + SET_CONSTANT("blconditions", bl_submerged); + SET_CONSTANT("blconditions", bl_termill); + SET_CONSTANT("blconditions", bl_tethered); + SET_CONSTANT("blconditions", bl_trapped); + SET_CONSTANT("blconditions", bl_unconsc); + SET_CONSTANT("blconditions", bl_woundedl); + SET_CONSTANT("blconditions", bl_holding); + SET_CONSTANT("blconditions", CONDITION_COUNT); + + SET_CONSTANT("HL", HL_UNDEF); + SET_CONSTANT("HL", HL_NONE); + SET_CONSTANT("HL", HL_BOLD); + SET_CONSTANT("HL", HL_DIM); + SET_CONSTANT("HL", HL_ITALIC); + SET_CONSTANT("HL", HL_ULINE); + SET_CONSTANT("HL", HL_BLINK); + SET_CONSTANT("HL", HL_INVERSE); + + SET_CONSTANT("MG", MG_HERO); + SET_CONSTANT("MG", MG_CORPSE); + SET_CONSTANT("MG", MG_INVIS); + SET_CONSTANT("MG", MG_DETECT); + SET_CONSTANT("MG", MG_PET); + SET_CONSTANT("MG", MG_RIDDEN); + SET_CONSTANT("MG", MG_STATUE); + SET_CONSTANT("MG", MG_OBJPILE); + SET_CONSTANT("MG", MG_BW_LAVA); + SET_CONSTANT("MG", MG_BW_ICE); + SET_CONSTANT("MG", MG_BW_SINK); + SET_CONSTANT("MG", MG_BW_ENGR); + SET_CONSTANT("MG", MG_NOTHING); + SET_CONSTANT("MG", MG_UNEXPL); + SET_CONSTANT("MG", MG_MALE); + SET_CONSTANT("MG", MG_FEMALE); + + SET_POINTER(extcmdlist); + SET_POINTER(conditions); + SET_POINTER(condtests); + + /* roles/races/genders/alignments */ + SET_POINTER(roles); + SET_POINTER(races); + SET_POINTER(genders); + SET_POINTER(aligns); } /*** @@ -1073,6 +1207,20 @@ void js_globals_init() { CREATE_GLOBAL(WIN_MESSAGE, "i"); CREATE_GLOBAL(WIN_INVEN, "i"); CREATE_GLOBAL(WIN_STATUS, "i"); + + /* instance flags */ + CREATE_GLOBAL(iflags.window_inited, "b"); + CREATE_GLOBAL(iflags.wc2_hitpointbar, "b"); + CREATE_GLOBAL(iflags.wc_hilite_pet, "b"); + CREATE_GLOBAL(iflags.hilite_pile, "b"); + + /* flags */ + CREATE_GLOBAL(flags.initrole, "i"); + CREATE_GLOBAL(flags.initrace, "i"); + CREATE_GLOBAL(flags.initgend, "i"); + CREATE_GLOBAL(flags.initalign, "i"); + CREATE_GLOBAL(flags.showexp, "b"); + CREATE_GLOBAL(flags.time, "b"); } EM_JS(void, create_global, (char *name_str, void *ptr, char *type_str), { diff --git a/sys/unix/hints/include/cross-pre2.370 b/sys/unix/hints/include/cross-pre2.370 index fa5f0911c..94fce7142 100644 --- a/sys/unix/hints/include/cross-pre2.370 +++ b/sys/unix/hints/include/cross-pre2.370 @@ -216,7 +216,7 @@ ifdef CROSS_TO_WASM # originally from https://github.com/NetHack/NetHack/pull/385 #===============-================================================= # -WASM_DEBUG = 1 +#WASM_DEBUG = 1 WASM_DATA_DIR = $(TARGETPFX)wasm-data WASM_TARGET = $(TARGETPFX)nethack.js EMCC_LFLAGS = @@ -227,10 +227,13 @@ EMCC_LFLAGS += -s ALLOW_TABLE_GROWTH EMCC_LFLAGS += -s ASYNCIFY -s ASYNCIFY_IMPORTS='["local_callback"]' EMCC_LFLAGS += -O3 EMCC_LFLAGS += -s MODULARIZE -EMCC_LFLAGS += -s EXPORTED_FUNCTIONS='["_main", "_shim_graphics_set_callback", "_display_inventory"]' +EMCC_LFLAGS += -s EXPORTED_FUNCTIONS='["_main", "_shim_graphics_set_callback", "_display_inventory", "_malloc"]' EMCC_LFLAGS += -s EXPORTED_RUNTIME_METHODS='["cwrap", "ccall", "addFunction", \ - "removeFunction", "UTF8ToString", "getValue", "setValue"]' + "removeFunction", "UTF8ToString", "stringToUTF8", "getValue", \ + "setValue", "ENV", "FS", "IDBFS"]' EMCC_LFLAGS += -s ERROR_ON_UNDEFINED_SYMBOLS=0 +EMCC_LFLAGS += -s EXPORT_ES6=1 +EMCC_LFLAGS += -lidbfs.js # XXX: the "@/" at the end of "--embed-file" tells emscripten to embed the files # in the root directory, otherwise they will end up in the $(WASM_DATA_DIR) path EMCC_LFLAGS += --embed-file $(WASM_DATA_DIR)@/ diff --git a/win/shim/winshim.c b/win/shim/winshim.c index d83c62a45..dbc3ef5d7 100644 --- a/win/shim/winshim.c +++ b/win/shim/winshim.c @@ -115,7 +115,7 @@ void name fn_args { \ #endif /* __EMSCRIPTEN__ */ VDECLCB(shim_init_nhwindows,(int *argcp, char **argv), "vpp", P2V argcp, P2V argv) -VDECLCB(shim_player_selection,(void), "v") +DECLCB(boolean, shim_player_selection_or_tty,(void), "b") VDECLCB(shim_askname,(void), "v") VDECLCB(shim_get_nh_event,(void), "v") VDECLCB(shim_exit_nhwindows,(const char *str), "vs", P2V str) @@ -123,33 +123,33 @@ VDECLCB(shim_suspend_nhwindows,(const char *str), "vs", P2V str) VDECLCB(shim_resume_nhwindows,(void), "v") DECLCB(winid, shim_create_nhwindow, (int type), "ii", A2P type) VDECLCB(shim_clear_nhwindow,(winid window), "vi", A2P window) -VDECLCB(shim_display_nhwindow,(winid window, boolean blocking), "vii", A2P window, A2P blocking) +VDECLCB(shim_display_nhwindow,(winid window, boolean blocking), "vib", A2P window, A2P blocking) VDECLCB(shim_destroy_nhwindow,(winid window), "vi", A2P window) VDECLCB(shim_curs,(winid a, int x, int y), "viii", A2P a, A2P x, A2P y) VDECLCB(shim_putstr,(winid w, int attr, const char *str), "viis", A2P w, A2P attr, P2V str) -VDECLCB(shim_display_file,(const char *name, boolean complain), "vsi", P2V name, A2P complain) +VDECLCB(shim_display_file,(const char *name, boolean complain), "vsb", P2V name, A2P complain) VDECLCB(shim_start_menu,(winid window, unsigned long mbehavior), "vii", A2P window, A2P mbehavior) VDECLCB(shim_add_menu, (winid window, const glyph_info *glyphinfo, const ANY_P *identifier, char ch, char gch, int attr, int clr, const char *str, unsigned int itemflags), - "vippiiiisi", + "vipi00iisi", A2P window, P2V glyphinfo, P2V identifier, A2P ch, A2P gch, A2P attr, A2P clr, P2V str, A2P itemflags) VDECLCB(shim_end_menu,(winid window, const char *prompt), "vis", A2P window, P2V prompt) /* XXX: shim_select_menu menu_list is an output */ -DECLCB(int, shim_select_menu,(winid window, int how, MENU_ITEM_P **menu_list), "iiio", A2P window, A2P how, P2V menu_list) +DECLCB(int, shim_select_menu,(winid window, int how, MENU_ITEM_P **menu_list), "iiip", A2P window, A2P how, P2V menu_list) DECLCB(char, shim_message_menu,(char let, int how, const char *mesg), "ciis", A2P let, A2P how, P2V mesg) VDECLCB(shim_mark_synch,(void), "v") VDECLCB(shim_wait_synch,(void), "v") VDECLCB(shim_cliparound,(int x, int y), "vii", A2P x, A2P y) -VDECLCB(shim_update_positionbar,(char *posbar), "vp", P2V posbar) -VDECLCB(shim_print_glyph,(winid w, coordxy x, coordxy y, const glyph_info *glyphinfo, const glyph_info *bkglyphinfo), "viiipp", A2P w, A2P x, A2P y, P2V glyphinfo, P2V bkglyphinfo) +VDECLCB(shim_update_positionbar,(char *posbar), "vs", P2V posbar) +VDECLCB(shim_print_glyph,(winid w, coordxy x, coordxy y, const glyph_info *glyphinfo, const glyph_info *bkglyphinfo), "vi11pp", A2P w, A2P x, A2P y, P2V glyphinfo, P2V bkglyphinfo) VDECLCB(shim_raw_print,(const char *str), "vs", P2V str) VDECLCB(shim_raw_print_bold,(const char *str), "vs", P2V str) DECLCB(int, shim_nhgetch,(void), "i") -DECLCB(int, shim_nh_poskey,(coordxy *x, coordxy *y, int *mod), "iooo", P2V x, P2V y, P2V mod) +DECLCB(int, shim_nh_poskey,(coordxy *x, coordxy *y, int *mod), "ippp", P2V x, P2V y, P2V mod) VDECLCB(shim_nhbell,(void), "v") DECLCB(int, shim_doprev_message,(void),"iv") -DECLCB(char, shim_yn_function,(const char *query, const char *resp, char def), "cssi", P2V query, P2V resp, A2P def) -VDECLCB(shim_getlin,(const char *query, char *bufp), "vso", P2V query, P2V bufp) +DECLCB(char, shim_yn_function,(const char *query, const char *resp, char def), "css0", P2V query, P2V resp, A2P def) +VDECLCB(shim_getlin,(const char *query, char *bufp), "vsp", P2V query, P2V bufp) DECLCB(int,shim_get_ext_cmd,(void),"iv") VDECLCB(shim_number_pad,(int state), "vi", A2P state) VDECLCB(shim_delay_output,(void), "v") @@ -162,17 +162,17 @@ DECLCB(char *,shim_get_color_string,(void),"sv") VDECLCB(shim_start_screen, (void), "v") VDECLCB(shim_end_screen, (void), "v") VDECLCB(shim_preference_update, (const char *pref), "vp", P2V pref) -DECLCB(char *,shim_getmsghistory, (boolean init), "si", A2P init) -VDECLCB(shim_putmsghistory, (const char *msg, boolean restoring_msghist), "vsi", P2V msg, A2P restoring_msghist) +DECLCB(char *,shim_getmsghistory, (boolean init), "sb", A2P init) +VDECLCB(shim_putmsghistory, (const char *msg, boolean restoring_msghist), "vsb", P2V msg, A2P restoring_msghist) VDECLCB(shim_status_init, (void), "v") VDECLCB(shim_status_enablefield, (int fieldidx, const char *nm, const char *fmt, boolean enable), - "vippi", + "vippb", A2P fieldidx, P2V nm, P2V fmt, A2P enable) /* XXX: the second argument to shim_status_update is sometimes an integer and sometimes a pointer */ VDECLCB(shim_status_update, (int fldidx, genericptr_t ptr, int chg, int percent, int color, unsigned long *colormasks), - "vioiiip", + "vipiiip", A2P fldidx, P2V ptr, A2P chg, A2P percent, A2P color, P2V colormasks) #ifdef __EMSCRIPTEN__ @@ -183,6 +183,14 @@ void shim_update_inventory(int a1 UNUSED) { display_inventory(NULL, FALSE); } } + +void shim_player_selection() { + boolean do_genl_player_setup = shim_player_selection_or_tty(); + if (do_genl_player_setup) { + genl_player_setup(80); + } +} + win_request_info * shim_ctrl_nhwindow( winid window UNUSED, @@ -203,6 +211,7 @@ struct window_procs shim_procs = { WPID(shim), (0 | WC_ASCII_MAP + | WC_MOUSE_SUPPORT | WC_COLOR | WC_HILITE_PET | WC_INVERSE | WC_EIGHT_BIT_IN), (0 #if defined(SELECTSAVED) @@ -262,7 +271,7 @@ EM_JS(void, local_callback, (const char *cb_name, const char *shim_name, void *r // unrolling and it crashes. Thus we use Asyncify.handleSleep() and wakeUp() to make sure that async doesn't break // Asyncify. For details, see: https://emscripten.org/docs/porting/asyncify.html#optimizing Asyncify.handleSleep(wakeUp => { - // convert callback arguments to proper JavaScript varaidic arguments + // convert callback arguments to proper JavaScript variadic arguments let name = UTF8ToString(shim_name); let fmt = UTF8ToString(fmt_str); let cbName = UTF8ToString(cb_name); @@ -287,40 +296,25 @@ EM_JS(void, local_callback, (const char *cb_name, const char *shim_name, void *r // do the callback let userCallback = globalThis[cbName]; - runJsEventLoop(() => userCallback.call(this, name, ... jsArgs)).then((retVal) => { + userCallback.call(this, name, ... jsArgs).then((retVal) => { // save the return value setPointerValue(name, ret_ptr, retType, retVal); - // return - setTimeout(() => { - reentryMutexUnlock(); + reentryMutexUnlock(); + try { wakeUp(); - }, 0); + } catch (e) { + + } }); function getArg(name, ptr, type) { - return (type === "o")?ptr:getPointerValue(name, getValue(ptr, "*"), type); - } - - // setTimeout() with value of '0' is similar to setImmediate() (but setImmediate isn't standard) - // this lets the JS loop run for a tick so that other events can occur - // XXX: I also tried replacing the for(;;) in allmain.c:moveloop() with emscripten_set_main_loop() - // unfortunately that won't work -- if the simulate_infinite_loop arg is false, it falls through - // and the program ends; - // if is true, it throws an exception to break out of main(), but doesn't get caught because - // the stack isn't running under main() anymore... - // I think this is suboptimal, but we will have to live with it (for now?) - async function runJsEventLoop(cb) { - return new Promise((resolve) => { - setTimeout(() => { - resolve(cb()); - }, 0); - }); + return (type === "p") ? getValue(ptr, "*") : getPointerValue(name, getValue(ptr, "*"), type); } function reentryMutexLock(name) { globalThis.nethackGlobal = globalThis.nethackGlobal || {}; if(globalThis.nethackGlobal.shimFunctionRunning) { - throw new Error(`'${name}' attempting second call to 'local_callback' before '${globalThis.nethackGlobal.shimFunctionRunning}' has finished, will crash emscripten Asyncify. For details see: emscripten.org/docs/porting/asyncify.html#reentrancy`); + console.error(`'${name}' attempting second call to 'local_callback' before '${globalThis.nethackGlobal.shimFunctionRunning}' has finished, will crash emscripten Asyncify. For details see: emscripten.org/docs/porting/asyncify.html#reentrancy`); } globalThis.nethackGlobal.shimFunctionRunning = name; } From d6beba7b6a5947ded109aef3b9fa4565b2404c02 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 30 Nov 2024 11:57:20 -0500 Subject: [PATCH 107/791] Windows: fix hacklib subproject settings in VS --- sys/windows/vs/hacklib/hacklib.vcxproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sys/windows/vs/hacklib/hacklib.vcxproj b/sys/windows/vs/hacklib/hacklib.vcxproj index b43c429ea..2d53093eb 100644 --- a/sys/windows/vs/hacklib/hacklib.vcxproj +++ b/sys/windows/vs/hacklib/hacklib.vcxproj @@ -54,13 +54,13 @@ StaticLibrary true - v143 + $(DefaultPlatformToolset) Unicode StaticLibrary false - v143 + $(DefaultPlatformToolset) true Unicode From 0792e5fe9e3688c314533f7ff0d4f638edf486e9 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 30 Nov 2024 14:16:27 -0500 Subject: [PATCH 108/791] expand implicit fallthrough detection to non-gcc compilers gcc has recognized various "magic comments" for white-listing occurrences of implicit fallthrough in switch statements for a long time: The range and shape of "falls through" comments accepted are contingent upon the level of the warning. (The default level is =3.) -Wimplicit-fallthrough=0 disables the warning altogether. -Wimplicit-fallthrough=1 treats any kind of comment as a "falls through" comment. -Wimplicit-fallthrough=2 essentially accepts any comment that contains something that matches (case insensitively) "falls?[ \t-]*thr(ough|u)" regular expression. -Wimplicit-fallthrough=3 case sensitively matches a wide range of regular expressions, listed in the GCC manual. E.g., all of these are accepted: /* Falls through. */ /* fall-thru */ /* Else falls through. */ /* FALLTHRU */ /* ... falls through ... */ etc. -Wimplicit-fallthrough=4 also, case sensitively matches a range of regular expressions but is much more strict than level =3. -Wimplicit-fallthrough=5 doesn't recognize any comments. Plenty of other compilers did not recognize the gcc comment convention, and up until now the compiler warning for detecting unintended fallthrough had to be suppressed on other compilers. That's because the code in NetHack has been relying on the gcc approach, and only the gcc approach. The C23 standard introduces an attribute [[fallthrough]] for the functionality, when implicit fallthrough warnings have been enabled. Several popular compilers already support that, or a very similar attribute style approach, today, even ahead of their C23 support: C compiler whitelist approach --------------------------- ------------------------------------- C23 conforming compilers [[fallthrough]] clang versions supporting standards prior to C23 __attribute__((__fallthrough__)) Microsoft Visual Studio since VS 2022 17.4. The warning C5262 controls whether the implict fallthrough is detected and warned about with /std:clatest. [[fallthrough]] This adds support to NetHack for the attribute approach by inserting a macro FALLTHROUGH to the existing cases that require white-listing, so other compilers can analyze things too. The definition of the FALLTHROUGH macro is controlled in include/tradstdc.h. The gcc comment approach has also been left in place at this time. --- include/tradstdc.h | 32 ++++++++++++++++++++++----- src/allmain.c | 1 + src/apply.c | 4 ++++ src/ball.c | 3 ++- src/dbridge.c | 1 + src/display.c | 2 ++ src/do.c | 1 + src/do_name.c | 1 + src/do_wear.c | 1 + src/dog.c | 5 ++++- src/dogmove.c | 3 +++ src/dokick.c | 3 +++ src/dothrow.c | 5 +++++ src/dungeon.c | 1 + src/eat.c | 7 ++++++ src/engrave.c | 2 ++ src/fountain.c | 4 ++++ src/getpos.c | 1 + src/hack.c | 4 ++++ src/insight.c | 3 +++ src/invent.c | 5 +++++ src/makemon.c | 4 ++++ src/mcastu.c | 2 ++ src/mhitm.c | 2 ++ src/mkmaze.c | 2 ++ src/mkobj.c | 6 +++++ src/mon.c | 7 ++++-- src/monmove.c | 2 ++ src/mthrowu.c | 2 ++ src/muse.c | 6 ++++- src/music.c | 2 ++ src/nhlua.c | 2 ++ src/objnam.c | 9 ++++++-- src/options.c | 1 + src/pager.c | 1 + src/pickup.c | 2 ++ src/polyself.c | 1 + src/potion.c | 7 ++++++ src/pray.c | 20 ++++++++++++++--- src/questpgr.c | 7 ++++-- src/role.c | 1 + src/rumors.c | 1 + src/selvar.c | 1 + src/shk.c | 2 ++ src/sit.c | 12 ++++++++++ src/sounds.c | 7 ++++-- src/spell.c | 4 ++++ src/steed.c | 1 + src/timeout.c | 5 +++++ src/topten.c | 2 ++ src/trap.c | 11 +++++++++ src/uhitm.c | 6 +++++ src/weapon.c | 11 ++++++--- src/wizard.c | 5 +++-- src/wizcmds.c | 1 + src/zap.c | 7 ++++++ sys/msdos/video.c | 2 ++ sys/unix/hints/include/compiler.370 | 9 ++++++++ sys/unix/hints/include/cross-pre2.370 | 1 + sys/vms/vmsunix.c | 1 + sys/windows/Makefile.nmake | 10 +++++++++ sys/windows/consoletty.c | 5 ++++- sys/windows/windmain.c | 2 +- util/makedefs.c | 5 ++++- win/Qt/qt_bind.cpp | 2 ++ win/curses/cursdial.c | 1 + win/curses/cursinit.c | 2 ++ win/curses/cursmisc.c | 5 +++-- win/curses/cursstat.c | 2 ++ win/curses/curswins.c | 1 + win/tty/termcap.c | 5 +++++ win/tty/wintty.c | 9 ++++++++ win/win32/mhdlg.c | 6 +++-- 73 files changed, 287 insertions(+), 32 deletions(-) diff --git a/include/tradstdc.h b/include/tradstdc.h index c5a9368fb..b607d4a99 100644 --- a/include/tradstdc.h +++ b/include/tradstdc.h @@ -327,13 +327,20 @@ typedef genericptr genericptr_t; /* (void *) or (char *) */ /* * Give first priority to standard */ -#ifndef ATTRNORETURN #if defined(__STDC_VERSION__) || defined(__cplusplus) #if (__STDC_VERSION__ > 202300L) || defined(__cplusplus) +#ifndef ATTRNORETURN #define ATTRNORETURN [[noreturn]] #endif -#endif -#endif +#ifndef __has_c_attribute +#define __has_c_attribute(x) 0 +#endif /* __has_c_attribute */ +#if __has_c_attribute(fallthrough) +/* Standard attribute is available, use it. */ +#define FALLTHROUGH [[fallthrough]] +#endif /* __has_c_attribute(fallthrough) */ +#endif /* __STDC_VERSION__ gt 202300L || __cplusplus */ +#endif /* __STDC_VERSION || __cplusplus */ /* * Allow gcc2 to check parameters of printf-like calls with -Wformat; @@ -366,12 +373,21 @@ typedef genericptr genericptr_t; /* (void *) or (char *) */ #endif /* !NONNULLS_DEFINED */ /* #pragma message is available */ #define NH_PRAGMA_MESSAGE 1 -#endif -#endif +#endif /* __GNUC__ greater than or equal to 5 */ +#endif /* __GNUC__ */ -#if defined(__clang__) && !defined(DO_DEFINE_NONNULLS) +#if defined(__clang__) +#ifndef FALLTHROUGH +#if defined(__clang_major__) +#if __clang_major__ >= 9 +#define FALLTHROUGH __attribute__((fallthrough)) +#endif /* __clang_major__ greater than or equal to 9 */ +#endif /* __clang_major__ is defined */ +#endif /* FALLTHROUGH */ +#if !defined(DO_DEFINE_NONNULLS) #define DO_DEFINE_NONNULLS #endif +#endif /* __clang__ */ #if defined(DO_DEFINE_NONNULLS) && !defined(NONNULLS_DEFINED) #define NONNULL __attribute__((returns_nonnull)) @@ -405,6 +421,7 @@ typedef genericptr genericptr_t; /* (void *) or (char *) */ #define NH_PRAGMA_MESSAGE 1 #endif +/* Fallback implementations */ #ifndef PRINTF_F #define PRINTF_F(f, v) #endif @@ -414,6 +431,9 @@ typedef genericptr genericptr_t; /* (void *) or (char *) */ #ifndef UNUSED #define UNUSED #endif +#ifndef FALLTHROUGH +#define FALLTHROUGH +#endif #ifndef ATTRNORETURN #define ATTRNORETURN #endif diff --git a/src/allmain.c b/src/allmain.c index 4d281fe7f..253ac82a4 100644 --- a/src/allmain.c +++ b/src/allmain.c @@ -1040,6 +1040,7 @@ argcheck(int argc, char *argv[], enum earlyarg e_arg) extended_opt++; return windows_early_options(extended_opt); } + FALLTHROUGH; /*FALLTHRU*/ #endif default: diff --git a/src/apply.c b/src/apply.c index 271a6cd18..6f1112359 100644 --- a/src/apply.c +++ b/src/apply.c @@ -3772,6 +3772,7 @@ use_grapple(struct obj *obj) (void) thitmonst(mtmp, uwep); return ECMD_TIME; } + FALLTHROUGH; /*FALLTHRU*/ case 3: /* Surface */ if (IS_AIR(levl[cc.x][cc.y].typ) || is_pool(cc.x, cc.y)) @@ -3891,6 +3892,7 @@ do_break_wand(struct obj *obj) discard_broken_wand(); return ECMD_TIME; } + FALLTHROUGH; /*FALLTHRU*/ case WAN_WISHING: case WAN_NOTHING: @@ -3919,6 +3921,7 @@ do_break_wand(struct obj *obj) Soundeffect(se_wall_of_force, 65); pline("A wall of force smashes down around you!"); dmg = d(1 + obj->spe, 6); /* normally 2d12 */ + FALLTHROUGH; /*FALLTHRU*/ case WAN_CANCELLATION: case WAN_POLYMORPH: @@ -4304,6 +4307,7 @@ doapply(void) pline("It rings! ... But no-one answers."); break; } + FALLTHROUGH; /*FALLTHRU*/ default: /* Pole-weapons can strike at a distance */ diff --git a/src/ball.c b/src/ball.c index c3c53c289..d6ba11017 100644 --- a/src/ball.c +++ b/src/ball.c @@ -743,7 +743,8 @@ drag_ball(coordxy x, coordxy y, int *bc_control, SKIP_TO_DRAG; break; } - /* fall through */ + FALLTHROUGH; + /* FALLTHRU */ case 1: case 0: /* do nothing if possible */ diff --git a/src/dbridge.c b/src/dbridge.c index 8e2f081bd..5e739d4fa 100644 --- a/src/dbridge.c +++ b/src/dbridge.c @@ -255,6 +255,7 @@ create_drawbridge(coordxy x, coordxy y, int dir, boolean flag) break; default: impossible("bad direction in create_drawbridge"); + FALLTHROUGH; /*FALLTHRU*/ case DB_WEST: horiz = FALSE; diff --git a/src/display.c b/src/display.c index 9902040a2..0e9cca612 100644 --- a/src/display.c +++ b/src/display.c @@ -528,6 +528,7 @@ display_monster( default: impossible("display_monster: bad m_ap_type value [ = %d ]", (int) mon->m_ap_type); + FALLTHROUGH; /*FALLTHRU*/ case M_AP_NOTHING: show_glyph(x, y, mon_to_glyph(mon, newsym_rn2)); @@ -3566,6 +3567,7 @@ wall_angle(struct rm *lev) case SDOOR: if (lev->horizontal) goto horiz; + FALLTHROUGH; /*FALLTHRU*/ case VWALL: switch (lev->wall_info & WM_MASK) { diff --git a/src/do.c b/src/do.c index f4f7c3e4d..fe07407c1 100644 --- a/src/do.c +++ b/src/do.c @@ -2217,6 +2217,7 @@ revive_corpse(struct obj *corpse) fill_pit(mtmp->mx, mtmp->my); break; } + FALLTHROUGH; /*FALLTHRU*/ default: /* we should be able to handle the other cases... */ diff --git a/src/do_name.c b/src/do_name.c index aa4463cda..d1d53f36e 100644 --- a/src/do_name.c +++ b/src/do_name.c @@ -442,6 +442,7 @@ objtyp_is_callable(int i) determine which one was the real one */ if (i == AMULET_OF_YENDOR || i == FAKE_AMULET_OF_YENDOR) break; /* return FALSE */ + FALLTHROUGH; /*FALLTHRU*/ case SCROLL_CLASS: case POTION_CLASS: diff --git a/src/do_wear.c b/src/do_wear.c index e7cc1be64..1b5b57dfd 100644 --- a/src/do_wear.c +++ b/src/do_wear.c @@ -452,6 +452,7 @@ Helmet_on(void) : (uarmh->o_id % 2) ? A_CHAOTIC : A_LAWFUL, A_CG_HELM_ON); /* makeknown(HELM_OF_OPPOSITE_ALIGNMENT); -- below, after Tobjnam() */ + FALLTHROUGH; /*FALLTHRU*/ case DUNCE_CAP: if (uarmh && !uarmh->cursed) { diff --git a/src/dog.c b/src/dog.c index 9c4f85560..6134355f9 100644 --- a/src/dog.c +++ b/src/dog.c @@ -523,7 +523,9 @@ mon_arrive(struct monst *mtmp, int when) } else if (!(u.uevent.qexpelled && (Is_qstart(&u.uz0) || Is_qstart(&u.uz)))) { impossible("mon_arrive: no corresponding portal?"); - } /*FALLTHRU*/ + } + FALLTHROUGH; + /*FALLTHRU*/ default: case MIGR_RANDOM: xlocale = ylocale = 0; @@ -1076,6 +1078,7 @@ dogfood(struct monst *mon, struct obj *obj) && obj->oclass != BALL_CLASS && obj->oclass != CHAIN_CLASS) return APPORT; + FALLTHROUGH; /*FALLTHRU*/ case ROCK_CLASS: return UNDEF; diff --git a/src/dogmove.c b/src/dogmove.c index 2c77a6487..29c0d9bc1 100644 --- a/src/dogmove.c +++ b/src/dogmove.c @@ -76,6 +76,7 @@ droppables(struct monst *mon) if (pickaxe && pickaxe->otyp == PICK_AXE && pickaxe != wep && (!pickaxe->oartifact || obj->oartifact)) return pickaxe; /* drop the one we earlier decided to keep */ + FALLTHROUGH; /*FALLTHRU*/ case PICK_AXE: if (!pickaxe || (obj->oartifact && !pickaxe->oartifact)) { @@ -104,12 +105,14 @@ droppables(struct monst *mon) if (key && key->otyp == LOCK_PICK && (!key->oartifact || obj->oartifact)) return key; /* drop the one we earlier decided to keep */ + FALLTHROUGH; /*FALLTHRU*/ case LOCK_PICK: /* keep lock-pick in preference to credit card */ if (key && key->otyp == CREDIT_CARD && (!key->oartifact || obj->oartifact)) return key; + FALLTHROUGH; /*FALLTHRU*/ case CREDIT_CARD: if (!key || (obj->oartifact && !key->oartifact)) { diff --git a/src/dokick.c b/src/dokick.c index b9d25eaaf..cf8bb405b 100644 --- a/src/dokick.c +++ b/src/dokick.c @@ -1340,6 +1340,7 @@ dokick(void) pline("%s burps loudly.", Monnam(u.ustuck)); break; } + FALLTHROUGH; /*FALLTHRU*/ default: Your("feeble kick has no effect."); @@ -1484,6 +1485,7 @@ drop_to(coord *cc, schar loc, coordxy x, coordxy y) cc->y = cc->x = 0; break; } + FALLTHROUGH; /*FALLTHRU*/ case MIGR_STAIRS_UP: case MIGR_LADDER_UP: @@ -1800,6 +1802,7 @@ obj_delivery(boolean near_hero) switch (where) { case MIGR_LADDER_UP: isladder = TRUE; + FALLTHROUGH; /*FALLTHRU*/ case MIGR_STAIRS_UP: case MIGR_SSTAIRS: diff --git a/src/dothrow.c b/src/dothrow.c index 30af1e40b..7dcf043f9 100644 --- a/src/dothrow.c +++ b/src/dothrow.c @@ -67,6 +67,7 @@ multishot_class_bonus( case PM_NINJA: if (skill == -P_SHURIKEN || skill == -P_DART) multishot++; + FALLTHROUGH; /*FALLTHRU*/ case PM_SAMURAI: /* role-specific launcher and its ammo */ @@ -175,6 +176,7 @@ throw_obj(struct obj *obj, int shotlimit) switch (P_SKILL(weapon_type(obj))) { case P_EXPERT: multishot++; + FALLTHROUGH; /*FALLTHRU*/ case P_SKILLED: if (!weakmultishot) @@ -1295,6 +1297,7 @@ toss_up(struct obj *obj, boolean hitsroof) Your("%s fails to protect you.", helm_simple_name(uarmh)); goto petrify; } + FALLTHROUGH; /*FALLTHRU*/ case CREAM_PIE: case BLINDING_VENOM: @@ -2572,12 +2575,14 @@ breakmsg(struct obj *obj, boolean in_view) default: /* glass or crystal wand */ if (obj->oclass != WAND_CLASS) impossible("breaking odd object (%d)?", obj->otyp); + FALLTHROUGH; /*FALLTHRU*/ case LENSES: case MIRROR: case CRYSTAL_BALL: case EXPENSIVE_CAMERA: to_pieces = " into a thousand pieces"; + FALLTHROUGH; /*FALLTHRU*/ case POT_WATER: /* really, all potions */ if (!in_view) diff --git a/src/dungeon.c b/src/dungeon.c index e75808a31..dc8557ed4 100644 --- a/src/dungeon.c +++ b/src/dungeon.c @@ -3039,6 +3039,7 @@ count_feat_lastseentyp( } if (is_drawbridge_wall(x, y) < 0) break; + FALLTHROUGH; /*FALLTHRU*/ case DBWALL: case DRAWBRIDGE_DOWN: diff --git a/src/eat.c b/src/eat.c index e2c369ae8..a73cf2080 100644 --- a/src/eat.c +++ b/src/eat.c @@ -848,6 +848,7 @@ cprefx(int pm) make_slimed(10L, (char *) 0); delayed_killer(SLIMED, KILLED_BY_AN, ""); } + FALLTHROUGH; /* Fall through */ default: if (acidic(&mons[pm]) && Stoned) @@ -1164,19 +1165,23 @@ cpostfx(int pm) HSee_invisible |= FROMOUTSIDE; } newsym(u.ux, u.uy); + FALLTHROUGH; /*FALLTHRU*/ case PM_YELLOW_LIGHT: case PM_GIANT_BAT: make_stunned((HStun & TIMEOUT) + 30L, FALSE); + FALLTHROUGH; /*FALLTHRU*/ case PM_BAT: make_stunned((HStun & TIMEOUT) + 30L, FALSE); break; case PM_GIANT_MIMIC: tmp += 10; + FALLTHROUGH; /*FALLTHRU*/ case PM_LARGE_MIMIC: tmp += 20; + FALLTHROUGH; /*FALLTHRU*/ case PM_SMALL_MIMIC: tmp += 20; @@ -1278,6 +1283,7 @@ cpostfx(int pm) } else { pline("For some reason, that tasted bland."); } + FALLTHROUGH; /*FALLTHRU*/ default: check_intrinsics = TRUE; @@ -2143,6 +2149,7 @@ fprefx(struct obj *otmp) break; } iter_mons(garlic_breath); + FALLTHROUGH; /*FALLTHRU*/ default: if (otmp->otyp == SLIME_MOLD && !otmp->cursed diff --git a/src/engrave.c b/src/engrave.c index 8105efeec..88ac6b29e 100644 --- a/src/engrave.c +++ b/src/engrave.c @@ -606,6 +606,7 @@ doengrave_sfx_item_WAN(struct _doengrave_ctx *de) "A few ice cubes drop from the wand."); if (!de->oep || (de->oep->engr_type != BURN)) break; + FALLTHROUGH; /*FALLTHRU*/ case WAN_CANCELLATION: case WAN_MAKE_INVISIBLE: @@ -706,6 +707,7 @@ doengrave_sfx_item(struct _doengrave_ctx *de) de->type = DUST; break; } + FALLTHROUGH; /*FALLTHRU*/ /* Objects too large to engrave with */ case BALL_CLASS: diff --git a/src/fountain.c b/src/fountain.c index 1d4150630..979bb0518 100644 --- a/src/fountain.c +++ b/src/fountain.c @@ -359,6 +359,7 @@ drinkfountain(void) dofindgem(); break; } + FALLTHROUGH; /*FALLTHRU*/ case 28: /* Water Nymph */ dowaternymph(); @@ -486,6 +487,7 @@ dipfountain(struct obj *obj) dofindgem(); break; } + FALLTHROUGH; /*FALLTHRU*/ case 25: /* Water gushes forth */ dogushforth(FALSE); @@ -699,6 +701,7 @@ drinksink(void) pline("From the murky drain, a hand reaches up... --oops--"); break; } + FALLTHROUGH; /*FALLTHRU*/ default: You("take a sip of %s %s.", @@ -770,6 +773,7 @@ dipsink(struct obj *obj) try_call = TRUE; break; } + FALLTHROUGH; /* FALLTHRU */ case POT_GAIN_LEVEL: case POT_GAIN_ENERGY: diff --git a/src/getpos.c b/src/getpos.c index 0152fba53..36e9d95ea 100644 --- a/src/getpos.c +++ b/src/getpos.c @@ -465,6 +465,7 @@ gather_locs_interesting(coordxy x, coordxy y, int gloc) case GLOC_VALID: if (getpos_getvalid) return (*getpos_getvalid)(x, y); + FALLTHROUGH; /*FALLTHRU*/ case GLOC_INTERESTING: return (gather_locs_interesting(x, y, GLOC_DOOR) diff --git a/src/hack.c b/src/hack.c index 1f66f813b..6f8cce1d1 100644 --- a/src/hack.c +++ b/src/hack.c @@ -571,6 +571,7 @@ moverock_core(coordxy sx, coordxy sy) dopush(sx, sy, rx, ry, otmp, costly); continue; } + FALLTHROUGH; /*FALLTHRU*/ case TELEP_TRAP: rock_disappear_msg(otmp); @@ -2553,6 +2554,7 @@ escape_from_sticky_mon(coordxy x, coordxy y) u.ustuck->mfrozen = 1; u.ustuck->msleeping = 0; } + FALLTHROUGH; /*FALLTHRU*/ default: if (u.ustuck->mtame && !Conflict && !u.ustuck->mconf) @@ -3573,6 +3575,7 @@ check_special_room(boolean newlev) } case TEMPLE: intemple(roomno + ROOMOFFSET); + FALLTHROUGH; /*FALLTHRU*/ default: msg_given = (rt == TEMPLE || rt >= SHOPBASE); @@ -4317,6 +4320,7 @@ spot_checks(coordxy x, coordxy y, schar old_typ) switch (old_typ) { case DRAWBRIDGE_UP: db_ice_now = ((levl[x][y].drawbridgemask & DB_UNDER) == DB_ICE); + FALLTHROUGH; /*FALLTHRU*/ case ICE: if ((new_typ != old_typ) diff --git a/src/insight.c b/src/insight.c index 7a04f4efe..c1e17e954 100644 --- a/src/insight.c +++ b/src/insight.c @@ -1968,6 +1968,8 @@ attributes_enlightenment( switch (u.umortality) { case 0: impossible("dead without dying?"); + FALLTHROUGH; + /* FALLTHRU */ case 1: break; /* just "are dead" */ default: @@ -2624,6 +2626,7 @@ vanqsort_cmp( res = uniq2 - uniq1; break; } /* else both unique or neither unique */ + FALLTHROUGH; /*FALLTHRU*/ case VANQ_ALPHA_MIX: name1 = mons[indx1].pmnames[NEUTRAL]; diff --git a/src/invent.c b/src/invent.c index 1e375fc66..be0dff2cc 100644 --- a/src/invent.c +++ b/src/invent.c @@ -2463,6 +2463,7 @@ askchain( switch (sym) { case 'a': allflag = 1; + FALLTHROUGH; /*FALLTHRU*/ case 'y': tmp = (*fn)(otmp); @@ -2481,10 +2482,13 @@ askchain( cnt += tmp; if (--mx == 0) goto ret; + FALLTHROUGH; /*FALLTHRU*/ case 'n': if (nodot) dud++; + FALLTHROUGH; + /*FALLTHRU*/ default: break; case 'q': @@ -2975,6 +2979,7 @@ itemactions_pushkeys(struct obj *otmp, int act) switch (act) { default: impossible("Unknown item action"); + break; case IA_NONE: break; case IA_UNWIELD: diff --git a/src/makemon.c b/src/makemon.c index 947a8884d..e8c6bf298 100644 --- a/src/makemon.c +++ b/src/makemon.c @@ -521,6 +521,7 @@ m_initweap(struct monst *mtmp) */ if (!is_demon(ptr)) break; + FALLTHROUGH; /*FALLTHRU*/ default: /* @@ -704,12 +705,15 @@ m_initinv(struct monst *mtmp) /* MAJOR fall through ... */ case 0: (void) mongets(mtmp, WAN_MAGIC_MISSILE); + FALLTHROUGH; /*FALLTHRU*/ case 1: (void) mongets(mtmp, POT_EXTRA_HEALING); + FALLTHROUGH; /*FALLTHRU*/ case 2: (void) mongets(mtmp, POT_HEALING); + FALLTHROUGH; /*FALLTHRU*/ case 3: (void) mongets(mtmp, WAN_STRIKING); diff --git a/src/mcastu.c b/src/mcastu.c index 8c28b2507..a968d7e0a 100644 --- a/src/mcastu.c +++ b/src/mcastu.c @@ -84,6 +84,7 @@ choose_magic_spell(int spellval) case 23: if (Antimagic || Hallucination) return MGC_PSI_BOLT; + FALLTHROUGH; /*FALLTHRU*/ case 22: case 21: @@ -138,6 +139,7 @@ choose_clerical_spell(int spellnum) case 14: if (rn2(3)) return CLC_OPEN_WOUNDS; + FALLTHROUGH; /*FALLTHRU*/ case 13: return CLC_GEYSER; diff --git a/src/mhitm.c b/src/mhitm.c index 2473c1417..f54dc4ad2 100644 --- a/src/mhitm.c +++ b/src/mhitm.c @@ -405,6 +405,7 @@ mattackm( mswingsm(magr, mdef, mwep); tmp += hitval(mwep, mdef); } + FALLTHROUGH; /*FALLTHRU*/ case AT_CLAW: case AT_KICK: @@ -683,6 +684,7 @@ hitmm( Snprintf(buf, sizeof buf, "%s squeezes", magr_name); break; } + FALLTHROUGH; /*FALLTHRU*/ default: if (!weaponhit || !mwep || !mwep->oartifact) diff --git a/src/mkmaze.c b/src/mkmaze.c index c1e2b6205..2aa526ce0 100644 --- a/src/mkmaze.c +++ b/src/mkmaze.c @@ -588,6 +588,7 @@ fixup_special(void) sp = find_level(r->rname.str); lev = sp->dlevel; } + FALLTHROUGH; /*FALLTHRU*/ case LR_UPSTAIR: @@ -2073,6 +2074,7 @@ mv_bubble(struct bubble *b, coordxy dx, coordxy dy, boolean ini) break; case 3: b->dy = -b->dy; + FALLTHROUGH; /*FALLTHRU*/ case 2: b->dx = -b->dx; diff --git a/src/mkobj.c b/src/mkobj.c index 73126264e..8a9be1e0d 100644 --- a/src/mkobj.c +++ b/src/mkobj.c @@ -325,6 +325,7 @@ mkbox_cnts(struct obj *box) n = 0; break; } + FALLTHROUGH; /*FALLTHRU*/ case BAG_OF_HOLDING: n = 1; @@ -999,6 +1000,7 @@ mksobj_init(struct obj *otmp, boolean artif) case LARGE_BOX: otmp->olocked = !!(rn2(5)); otmp->otrapped = !(rn2(10)); + FALLTHROUGH; /*FALLTHRU*/ case ICE_BOX: case SACK: @@ -1184,6 +1186,7 @@ mksobj(int otyp, boolean init, boolean artif) if (svm.mvitals[otmp->corpsenm].mvflags & (G_NOCORPSE | G_GONE)) otmp->corpsenm = gu.urole.mnum; } + FALLTHROUGH; /*FALLTHRU*/ case STATUE: case FIGURINE: @@ -1197,6 +1200,7 @@ mksobj(int otyp, boolean init, boolean artif) : is_male(ptr) ? CORPSTAT_MALE : rn2(2) ? CORPSTAT_FEMALE : CORPSTAT_MALE); } + FALLTHROUGH; /*FALLTHRU*/ case EGG: /* case TIN: */ @@ -1210,6 +1214,7 @@ mksobj(int otyp, boolean init, boolean artif) break; case POT_OIL: otmp->age = MAX_OIL_IN_FLASK; /* amount of oil */ + FALLTHROUGH; /*FALLTHRU*/ case POT_WATER: /* POTION_CLASS */ otmp->fromsink = 0; /* overloads corpsenm, which was set to NON_PM */ @@ -2982,6 +2987,7 @@ objlist_sanity(struct obj *objlist, int wheretype, const char *mesg) /* note: ball and chain can also be OBJ_FREE, but not across turns so this sanity check shouldn't encounter that */ bc_ok = TRUE; + FALLTHROUGH; /*FALLTHRU*/ default: if ((obj != uchain && obj != uball) || !bc_ok) { diff --git a/src/mon.c b/src/mon.c index 1c2ecad07..69d206065 100644 --- a/src/mon.c +++ b/src/mon.c @@ -861,7 +861,6 @@ make_corpse(struct monst *mtmp, unsigned int corpseflags) case PM_PAGE: case PM_ABBOT: case PM_ACOLYTE: case PM_HUNTER: case PM_THUG: case PM_NINJA: case PM_ROSHI: case PM_GUIDE: case PM_WARRIOR: case PM_APPRENTICE: - /*FALLTHRU*/ #else default: #endif @@ -3076,7 +3075,8 @@ mondead(struct monst *mtmp) (void) makemon(mtmp->data, stway->sx, stway->sy, NO_MM_FLAGS); break; } - /* fall-through */ + FALLTHROUGH; + /* FALLTHRU */ case 2: /* randomly */ (void) makemon(mtmp->data, 0, 0, NO_MM_FLAGS); break; @@ -4791,12 +4791,14 @@ pickvampshape(struct monst *mon) if (mon_has_special(mon)) break; /* leave mndx as is */ wolfchance = 3; + FALLTHROUGH; /*FALLTHRU*/ case PM_VAMPIRE_LEADER: /* vampire lord or Vlad can become wolf */ if (!rn2(wolfchance) && !uppercase_only) { mndx = PM_WOLF; break; } + FALLTHROUGH; /*FALLTHRU*/ case PM_VAMPIRE: /* any vampire can become fog or bat */ mndx = (!rn2(4) && !uppercase_only) ? PM_FOG_CLOUD : PM_VAMPIRE_BAT; @@ -4900,6 +4902,7 @@ validvamp(struct monst *mon, int *mndx_p, int monclass) *mndx_p = PM_WOLF; break; } + FALLTHROUGH; /*FALLTHRU*/ default: *mndx_p = NON_PM; diff --git a/src/monmove.c b/src/monmove.c index 0b5cde2e1..f27f8bdee 100644 --- a/src/monmove.c +++ b/src/monmove.c @@ -887,6 +887,7 @@ dochug(struct monst *mtmp) case MMOVE_NOMOVES: if (scared) panicattk = TRUE; + FALLTHROUGH; /*FALLTHRU*/ case MMOVE_NOTHING: /* no movement, but it can still attack you */ case MMOVE_DONE: /* absolutely no movement */ @@ -1758,6 +1759,7 @@ m_move(struct monst *mtmp, int after) break; default: impossible("unknown shk/gd/pri_move return value (%d)", xm); + FALLTHROUGH; /*FALLTHRU*/ case 0: case 1: diff --git a/src/mthrowu.c b/src/mthrowu.c index 455220098..5c41ea428 100644 --- a/src/mthrowu.c +++ b/src/mthrowu.c @@ -655,6 +655,7 @@ m_throw( hitu = 0; break; } + FALLTHROUGH; /*FALLTHRU*/ case CREAM_PIE: case BLINDING_VENOM: @@ -851,6 +852,7 @@ spitmm(struct monst *mtmp, struct attack *mattk, struct monst *mtarg) break; default: impossible("bad attack type in spitmm"); + FALLTHROUGH; /*FALLTHRU*/ case AD_ACID: otmp = mksobj(ACID_VENOM, TRUE, FALSE); diff --git a/src/muse.c b/src/muse.c index cb2c72a2b..0cece8f6a 100644 --- a/src/muse.c +++ b/src/muse.c @@ -1201,6 +1201,7 @@ rnd_defensive_item(struct monst *mtmp) goto try_again; if (!rn2(3)) return WAN_TELEPORTATION; + FALLTHROUGH; /*FALLTHRU*/ case 0: case 1: @@ -1209,6 +1210,7 @@ rnd_defensive_item(struct monst *mtmp) case 10: if (!rn2(3)) return WAN_CREATE_MONSTER; + FALLTHROUGH; /*FALLTHRU*/ case 2: return SCR_CREATE_MONSTER; @@ -1968,7 +1970,9 @@ rnd_offensive_item(struct monst *mtmp) if (hard_helmet(mtmp_helmet) || amorphous(pm) || passes_walls(pm) || noncorporeal(pm) || unsolid(pm)) return SCR_EARTH; - } /* fall through */ + } + FALLTHROUGH; + /* FALLTHRU */ case 1: return WAN_STRIKING; case 2: diff --git a/src/music.c b/src/music.c index 241f53aee..82fe8abcc 100644 --- a/src/music.c +++ b/src/music.c @@ -443,6 +443,7 @@ do_earthquake(int force) unblock_point(x, y); if (cansee(x, y)) pline("A secret corridor is revealed."); + FALLTHROUGH; /*FALLTHRU*/ case CORR: case ROOM: @@ -452,6 +453,7 @@ do_earthquake(int force) cvt_sdoor_to_door(&levl[x][y]); /* .typ = DOOR */ if (cansee(x, y)) pline("A secret door is revealed."); + FALLTHROUGH; /*FALLTHRU*/ case DOOR: /* make the door collapse */ /* if already doorless, treat like room or corridor */ diff --git a/src/nhlua.c b/src/nhlua.c index 08de9cfe1..becef1302 100644 --- a/src/nhlua.c +++ b/src/nhlua.c @@ -1996,6 +1996,8 @@ nhl_pcall_handle(lua_State *L, int nargs, int nresults, const char *name, case NHLpa_panic: panic("Lua error %d:%s %s", nud->sid, nud->name ? nud->name : "(unknown)", lua_tostring(L, -1)); + /*NOTREACHED*/ + break; case NHLpa_impossible: impossible("Lua error: %d:%s %s", nud->sid, nud->name ? nud->name : "(unknown)", diff --git a/src/objnam.c b/src/objnam.c index 334d5b7ed..94315442a 100644 --- a/src/objnam.c +++ b/src/objnam.c @@ -677,6 +677,7 @@ xname_flags( case WEAPON_CLASS: if (is_poisonable(obj) && obj->opoisoned) Strcpy(buf, "poisoned "); + FALLTHROUGH; /*FALLTHRU*/ case VENOM_CLASS: case TOOL_CLASS: @@ -1391,6 +1392,7 @@ doname_base( ConcatF1(bp, 1, ", %s lit)", arti_light_description(obj)); } } + FALLTHROUGH; /*FALLTHRU*/ case WEAPON_CLASS: if (ispoisoned) @@ -5077,7 +5079,8 @@ readobjnam(char *bp, struct obj *no_wish) break; case SLIME_MOLD: d.otmp->spe = d.ftype; - /* Fall through */ + FALLTHROUGH; + /* FALLTHRU */ case SKELETON_KEY: case CHEST: case LARGE_BOX: @@ -5109,7 +5112,8 @@ readobjnam(char *bp, struct obj *no_wish) /* scroll of mail: 0: delivered in-game via external event (or randomly for fake mail); 1: from bones or wishing; 2: written with marker */ case SCR_MAIL: - /*FALLTHRU*/ + d.otmp->spe = 1; + break; #endif /* splash of venom: 0: normal, and transitory; 1: wishing */ case ACID_VENOM: @@ -5121,6 +5125,7 @@ readobjnam(char *bp, struct obj *no_wish) d.otmp->spe = (rn2(10) ? -1 : 0); break; } + FALLTHROUGH; /*FALLTHRU*/ default: d.otmp->spe = d.spe; diff --git a/src/options.c b/src/options.c index 8abfcdc59..0a9a7dc85 100644 --- a/src/options.c +++ b/src/options.c @@ -3624,6 +3624,7 @@ optfn_scores( allopt[optidx].name); return optn_silenterr; } + FALLTHROUGH; /*FALLTHRU*/ default: config_error_add("Unknown %s parameter '%s'", diff --git a/src/pager.c b/src/pager.c index 079d182a7..d067b3f87 100644 --- a/src/pager.c +++ b/src/pager.c @@ -765,6 +765,7 @@ lookat(coordxy x, coordxy y, char *buf, char *monbuf) Strcpy(buf, "stone"); break; } + FALLTHROUGH; /*FALLTHRU*/ default: Strcpy(buf, defsyms[symidx].explanation); diff --git a/src/pickup.c b/src/pickup.c index df8896fe4..a1c2ccb78 100644 --- a/src/pickup.c +++ b/src/pickup.c @@ -870,6 +870,7 @@ pickup(int what) /* should be a long */ lcount = (long) yn_number; if (lcount > obj->quan) lcount = obj->quan; + FALLTHROUGH; /*FALLTHRU*/ default: /* 'y' */ break; @@ -1478,6 +1479,7 @@ query_category( /* assert( n == 1 ); */ break; /* from switch */ } + FALLTHROUGH; /*FALLTHRU*/ case 'q': default: diff --git a/src/polyself.c b/src/polyself.c index 9d619f6bb..38f9b01ea 100644 --- a/src/polyself.c +++ b/src/polyself.c @@ -1450,6 +1450,7 @@ dospit(void) break; default: impossible("bad attack type in dospit"); + FALLTHROUGH; /*FALLTHRU*/ case AD_ACID: otmp = mksobj(ACID_VENOM, TRUE, FALSE); diff --git a/src/potion.c b/src/potion.c index 68c9d165e..25989fff5 100644 --- a/src/potion.c +++ b/src/potion.c @@ -1721,16 +1721,19 @@ potionhit(struct monst *mon, struct obj *obj, int how) switch (obj->otyp) { case POT_FULL_HEALING: cureblind = TRUE; + FALLTHROUGH; /*FALLTHRU*/ case POT_EXTRA_HEALING: if (!obj->cursed) cureblind = TRUE; + FALLTHROUGH; /*FALLTHRU*/ case POT_HEALING: if (obj->blessed) cureblind = TRUE; if (mon->data == &mons[PM_PESTILENCE]) goto do_illness; + FALLTHROUGH; /*FALLTHRU*/ case POT_RESTORE_ABILITY: case POT_GAIN_ABILITY: @@ -1960,6 +1963,7 @@ potionbreathe(struct obj *obj) if (u.uhp < u.uhpmax) u.uhp++, disp.botl = TRUE; cureblind = TRUE; + FALLTHROUGH; /*FALLTHRU*/ case POT_EXTRA_HEALING: if (Upolyd && u.mh < u.mhmax) @@ -1968,6 +1972,7 @@ potionbreathe(struct obj *obj) u.uhp++, disp.botl = TRUE; if (!obj->cursed) cureblind = TRUE; + FALLTHROUGH; /*FALLTHRU*/ case POT_HEALING: if (Upolyd && u.mh < u.mhmax) @@ -2116,6 +2121,7 @@ mixtype(struct obj *o1, struct obj *o2) case POT_HEALING: if (o2typ == POT_SPEED) return POT_EXTRA_HEALING; + FALLTHROUGH; /*FALLTHRU*/ case POT_EXTRA_HEALING: case POT_FULL_HEALING: @@ -2123,6 +2129,7 @@ mixtype(struct obj *o1, struct obj *o2) return (o1typ == POT_HEALING) ? POT_EXTRA_HEALING : (o1typ == POT_EXTRA_HEALING) ? POT_FULL_HEALING : POT_GAIN_ABILITY; + FALLTHROUGH; /*FALLTHRU*/ case UNICORN_HORN: switch (o2typ) { diff --git a/src/pray.c b/src/pray.c index 360030e65..b77c4faae 100644 --- a/src/pray.c +++ b/src/pray.c @@ -403,7 +403,8 @@ fix_worst_trouble(int trouble) break; case TROUBLE_STARVING: /* temporarily lost strength recovery now handled by init_uhunger() */ - /*FALLTHRU*/ + FALLTHROUGH; + /* FALLTHRU*/ case TROUBLE_HUNGRY: Your("%s feels content.", body_part(STOMACH)); init_uhunger(); @@ -745,7 +746,9 @@ angrygods(aligntyp resp_god) gods_angry(resp_god); punish((struct obj *) 0); break; - } /* else fall thru */ + } + FALLTHROUGH; + /* FALLTHRU */ case 4: case 5: gods_angry(resp_god); @@ -1127,6 +1130,7 @@ pleased(aligntyp g_align) switch (min(action, 5)) { case 5: pat_on_head = 1; + FALLTHROUGH; /*FALLTHRU*/ case 4: do @@ -1137,8 +1141,9 @@ pleased(aligntyp g_align) case 3: /* up to 10 troubles */ fix_worst_trouble(trouble); + FALLTHROUGH; /*FALLTHRU*/ - case 2: + case 2: /* up to 9 troubles */ while ((trouble = in_trouble()) > 0 && (++tryct < 10)) fix_worst_trouble(trouble); @@ -1234,6 +1239,7 @@ pleased(aligntyp g_align) break; } } + FALLTHROUGH; /*FALLTHRU*/ case 2: if (!Blind) @@ -1335,6 +1341,7 @@ pleased(aligntyp g_align) gcrownu(); break; } + FALLTHROUGH; /*FALLTHRU*/ case 6: give_spell(); @@ -2335,18 +2342,23 @@ maybe_turn_mon_iter(struct monst *mtmp) than zombies. */ case S_LICH: xlev += 2; + FALLTHROUGH; /*FALLTHRU*/ case S_GHOST: xlev += 2; + FALLTHROUGH; /*FALLTHRU*/ case S_VAMPIRE: xlev += 2; + FALLTHROUGH; /*FALLTHRU*/ case S_WRAITH: xlev += 2; + FALLTHROUGH; /*FALLTHRU*/ case S_MUMMY: xlev += 2; + FALLTHROUGH; /*FALLTHRU*/ case S_ZOMBIE: if (u.ulevel >= xlev && !resist(mtmp, '\0', 0, NOTELL)) { @@ -2358,6 +2370,7 @@ maybe_turn_mon_iter(struct monst *mtmp) } break; } /* else flee */ + FALLTHROUGH; /*FALLTHRU*/ default: monflee(mtmp, 0, FALSE, TRUE); @@ -2656,6 +2669,7 @@ blocked_boulder(int dx, int dy) /* this is only approximate since multiple boulders might sink */ if (is_pool_or_lava(nx, ny)) /* does its own isok() check */ break; /* still need Sokoban check below */ + FALLTHROUGH; /*FALLTHRU*/ default: /* more than one boulder--blocked after they push the top one; diff --git a/src/questpgr.c b/src/questpgr.c index 29ef494c8..9f630e05a 100644 --- a/src/questpgr.c +++ b/src/questpgr.c @@ -374,6 +374,7 @@ convert_line(char *in_line, char *out_line) /* pluralize */ case 'P': gc.cvt_buf[0] = highc(gc.cvt_buf[0]); + FALLTHROUGH; /*FALLTHRU*/ case 'p': Strcpy(gc.cvt_buf, makeplural(gc.cvt_buf)); @@ -382,6 +383,7 @@ convert_line(char *in_line, char *out_line) /* append possessive suffix */ case 'S': gc.cvt_buf[0] = highc(gc.cvt_buf[0]); + FALLTHROUGH; /*FALLTHRU*/ case 's': Strcpy(gc.cvt_buf, s_suffix(gc.cvt_buf)); @@ -403,8 +405,9 @@ convert_line(char *in_line, char *out_line) Strcat(cc, gc.cvt_buf); cc += strlen(gc.cvt_buf); break; - } /* else fall through */ - + } + FALLTHROUGH; + /* FALLTHRU */ default: *cc++ = *c; break; diff --git a/src/role.c b/src/role.c index 7055ff5b7..3d036f1cb 100644 --- a/src/role.c +++ b/src/role.c @@ -1357,6 +1357,7 @@ clearrolefilter(int which) switch (which) { case RS_filter: gr.rfilter.mask = 0; /* clear race, gender, and alignment filters */ + FALLTHROUGH; /*FALLTHRU*/ case RS_ROLE: for (i = 0; i < SIZE(roles) - 1; ++i) diff --git a/src/rumors.c b/src/rumors.c index 11545fb6d..31fb19a82 100644 --- a/src/rumors.c +++ b/src/rumors.c @@ -563,6 +563,7 @@ outrumor( return; case BY_COOKIE: pline(fortune_msg); + FALLTHROUGH; /* FALLTHRU */ case BY_PAPER: pline("It reads:"); diff --git a/src/selvar.c b/src/selvar.c index 1951edfb8..5d08ca95e 100644 --- a/src/selvar.c +++ b/src/selvar.c @@ -582,6 +582,7 @@ selection_do_gradient( switch (gtyp) { default: impossible("Unrecognized gradient type! Defaulting to radial..."); + FALLTHROUGH; /* FALLTHRU */ case SEL_GRADIENT_RADIAL: { for (dx = 0; dx < COLNO; dx++) diff --git a/src/shk.c b/src/shk.c index 0ec28f217..d9077322f 100644 --- a/src/shk.c +++ b/src/shk.c @@ -4068,6 +4068,7 @@ sellobj( switch (gs.sell_response ? gs.sell_response : nyaq(qbuf)) { case 'q': gs.sell_response = 'n'; + FALLTHROUGH; /*FALLTHRU*/ case 'n': if (container) @@ -4078,6 +4079,7 @@ sellobj( break; case 'a': gs.sell_response = 'y'; + FALLTHROUGH; /*FALLTHRU*/ case 'y': if (container) diff --git a/src/sit.c b/src/sit.c index 82fccb6e9..1f919d922 100644 --- a/src/sit.c +++ b/src/sit.c @@ -158,6 +158,7 @@ throne_sit_effect(void) default: case 2: /* more than 1 eye */ eye = makeplural(eye); + FALLTHROUGH; /*FALLTHRU*/ case 1: /* one eye (Cyclops, floating eye) */ Your("%s %s...", eye, vtense(eye, "tingle")); @@ -517,6 +518,7 @@ attrcurse(void) ret = FIRE_RES; break; } + FALLTHROUGH; /*FALLTHRU*/ case 2: if (HTeleportation & INTRINSIC) { @@ -525,6 +527,7 @@ attrcurse(void) ret = TELEPORT; break; } + FALLTHROUGH; /*FALLTHRU*/ case 3: if (HPoison_resistance & INTRINSIC) { @@ -533,6 +536,7 @@ attrcurse(void) ret = POISON_RES; break; } + FALLTHROUGH; /*FALLTHRU*/ case 4: if (HTelepat & INTRINSIC) { @@ -543,6 +547,7 @@ attrcurse(void) ret = TELEPAT; break; } + FALLTHROUGH; /*FALLTHRU*/ case 5: if (HCold_resistance & INTRINSIC) { @@ -551,6 +556,7 @@ attrcurse(void) ret = COLD_RES; break; } + FALLTHROUGH; /*FALLTHRU*/ case 6: if (HInvis & INTRINSIC) { @@ -559,6 +565,7 @@ attrcurse(void) ret = INVIS; break; } + FALLTHROUGH; /*FALLTHRU*/ case 7: if (HSee_invisible & INTRINSIC) { @@ -574,6 +581,7 @@ attrcurse(void) ret = SEE_INVIS; break; } + FALLTHROUGH; /*FALLTHRU*/ case 8: if (HFast & INTRINSIC) { @@ -582,6 +590,7 @@ attrcurse(void) ret = FAST; break; } + FALLTHROUGH; /*FALLTHRU*/ case 9: if (HStealth & INTRINSIC) { @@ -590,6 +599,7 @@ attrcurse(void) ret = STEALTH; break; } + FALLTHROUGH; /*FALLTHRU*/ case 10: /* intrinsic protection is just disabled, not set back to 0 */ @@ -599,6 +609,7 @@ attrcurse(void) ret = PROTECTION; break; } + FALLTHROUGH; /*FALLTHRU*/ case 11: if (HAggravate_monster & INTRINSIC) { @@ -607,6 +618,7 @@ attrcurse(void) ret = AGGRAVATE_MONSTER; break; } + FALLTHROUGH; /*FALLTHRU*/ default: break; diff --git a/src/sounds.c b/src/sounds.c index eac50772a..5a5e9fd66 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -264,6 +264,7 @@ dosounds(void) break; } } + FALLTHROUGH; /*FALLTHRU*/ case 0: Soundeffect(se_guards_footsteps, 30); @@ -631,7 +632,6 @@ cry_sound(struct monst *mtmp) ret = "hiss"; break; case MS_ROAR: /* baby dragons; have them growl instead of roar */ - /*FALLTHRU*/ case MS_GROWL: /* (none) */ ret = "growl"; break; @@ -870,6 +870,7 @@ domonnoise(struct monst *mtmp) } break; } + FALLTHROUGH; /*FALLTHRU*/ case MS_GROWL: Soundeffect((mtmp->mpeaceful ? se_snarl : se_growl), 80); @@ -1019,6 +1020,7 @@ domonnoise(struct monst *mtmp) } break; } + FALLTHROUGH; /*FALLTHRU*/ case MS_HUMANOID: if (!mtmp->mpeaceful) { @@ -1141,7 +1143,8 @@ domonnoise(struct monst *mtmp) (void) demon_talk(mtmp); break; } - /* fall through */ + FALLTHROUGH; + /* FALLTHRU */ case MS_CUSS: if (!mtmp->mpeaceful) cuss(mtmp); diff --git a/src/spell.c b/src/spell.c index 65ef028b1..3ef28cafa 100644 --- a/src/spell.c +++ b/src/spell.c @@ -1441,11 +1441,13 @@ spelleffects(int spell_otyp, boolean atme, boolean force) } break; } /* else */ + FALLTHROUGH; /*FALLTHRU*/ /* these spells are all duplicates of wand effects */ case SPE_FORCE_BOLT: physical_damage = TRUE; + FALLTHROUGH; /*FALLTHRU*/ case SPE_SLEEP: case SPE_MAGIC_MISSILE: @@ -1510,6 +1512,7 @@ spelleffects(int spell_otyp, boolean atme, boolean force) /* high skill yields effect equivalent to blessed scroll */ if (role_skill >= P_SKILLED) pseudo->blessed = 1; + FALLTHROUGH; /*FALLTHRU*/ case SPE_CHARM_MONSTER: case SPE_MAGIC_MAPPING: @@ -1526,6 +1529,7 @@ spelleffects(int spell_otyp, boolean atme, boolean force) /* high skill yields effect equivalent to blessed potion */ if (role_skill >= P_SKILLED) pseudo->blessed = 1; + FALLTHROUGH; /*FALLTHRU*/ case SPE_INVISIBILITY: (void) peffects(pseudo); diff --git a/src/steed.c b/src/steed.c index 2c7be9c2e..84a6e9287 100644 --- a/src/steed.c +++ b/src/steed.c @@ -589,6 +589,7 @@ dismount_steed( switch (reason) { case DISMOUNT_THROWN: verb = "are thrown"; + FALLTHROUGH; /*FALLTHRU*/ case DISMOUNT_KNOCKED: case DISMOUNT_FELL: diff --git a/src/timeout.c b/src/timeout.c index cb9800994..4ec9f9c6b 100644 --- a/src/timeout.c +++ b/src/timeout.c @@ -214,6 +214,7 @@ vomiting_dialogue(void) make_stunned((HStun & TIMEOUT) + (long) d(2, 4), FALSE); if (!Popeye(VOMITING)) stop_occupation(); + FALLTHROUGH; /*FALLTHRU*/ case 9: make_confused((HConfusion & TIMEOUT) + (long) d(2, 4), FALSE); @@ -1441,6 +1442,7 @@ burn_object(anything *arg, long timeout) switch (obj->where) { case OBJ_INVENT: need_invupdate = TRUE; + FALLTHROUGH; /*FALLTHRU*/ case OBJ_MINVENT: pline("%spotion of oil has burnt away.", whose); @@ -1504,6 +1506,7 @@ burn_object(anything *arg, long timeout) switch (obj->where) { case OBJ_INVENT: need_invupdate = TRUE; + FALLTHROUGH; /*FALLTHRU*/ case OBJ_MINVENT: if (obj->otyp == BRASS_LANTERN) @@ -1583,6 +1586,7 @@ burn_object(anything *arg, long timeout) switch (obj->where) { case OBJ_INVENT: need_invupdate = TRUE; + FALLTHROUGH; /*FALLTHRU*/ case OBJ_MINVENT: pline("%scandelabrum's flame%s.", whose, @@ -1598,6 +1602,7 @@ burn_object(anything *arg, long timeout) case OBJ_INVENT: /* no need_invupdate for update_inventory() necessary; useupall() -> freeinv() handles it */ + FALLTHROUGH; /*FALLTHRU*/ case OBJ_MINVENT: pline("%s %s consumed!", Yname2(obj), diff --git a/src/topten.c b/src/topten.c index f38de9244..cb968a726 100644 --- a/src/topten.c +++ b/src/topten.c @@ -110,11 +110,13 @@ formatkiller( switch (svk.killer.format) { default: impossible("bad killer format? (%d)", svk.killer.format); + FALLTHROUGH; /*FALLTHRU*/ case NO_KILLER_PREFIX: break; case KILLED_BY_AN: kname = an(kname); + FALLTHROUGH; /*FALLTHRU*/ case KILLED_BY: (void) strncat(buf, killed_by_prefix[how], siz - 1); diff --git a/src/trap.c b/src/trap.c index a39ba8ddc..da39e4428 100644 --- a/src/trap.c +++ b/src/trap.c @@ -513,6 +513,7 @@ maketrap(coordxy x, coordxy y, int typ) case PIT: case SPIKED_PIT: ttmp->conjoined = 0; + FALLTHROUGH; /*FALLTHRU*/ case HOLE: case TRAPDOOR: @@ -1126,10 +1127,13 @@ m_harmless_trap(struct monst *mtmp, struct trap *ttmp) return TRUE; break; case PIT: + FALLTHROUGH; /*FALLTHRU*/ case SPIKED_PIT: + FALLTHROUGH; /*FALLTHRU*/ case HOLE: + FALLTHROUGH; /*FALLTHRU*/ case TRAPDOOR: if (is_clinger(mdat) && !Sokoban) @@ -2190,6 +2194,7 @@ trapeffect_web( mtmp->mtrapped = 1; break; } + FALLTHROUGH; /*FALLTHRU*/ default: if (mptr->mlet == S_GIANT @@ -2721,6 +2726,7 @@ immune_to_trap(struct monst *mon, unsigned ttype) if (pm->msize <= MZ_SMALL || amorphous(pm) || is_whirly(pm) || unsolid(pm)) return TRAP_CLEARLY_IMMUNE; + FALLTHROUGH; /*FALLTHRU*/ case SQKY_BOARD: case LANDMINE: @@ -2809,6 +2815,7 @@ immune_to_trap(struct monst *mon, unsigned ttype) for monsters, only replicates fire trap, so fall through */ if (is_you) return TRAP_NOT_IMMUNE; + FALLTHROUGH; /*FALLTHRU*/ case FIRE_TRAP: /* can always destroy items being carried */ /* harmful if not resistant or if carrying anything that could burn */ @@ -3244,10 +3251,12 @@ launch_obj( /* use otrapped as a flag to ohitmon */ singleobj->otrapped = 1; style &= ~LAUNCH_KNOWN; + FALLTHROUGH; /*FALLTHRU*/ case ROLL: roll: delaycnt = 2; + FALLTHROUGH; /*FALLTHRU*/ default: if (!delaycnt) @@ -3352,6 +3361,7 @@ launch_obj( /* if trap doesn't work, skip "disappears" message */ if (newlev == depth(&u.uz)) break; + FALLTHROUGH; /*FALLTHRU*/ case TELEP_TRAP: if (cansee(x, y)) @@ -4050,6 +4060,7 @@ float_down( case TRAPDOOR: if (!Can_fall_thru(&u.uz) || u.ustuck) break; + FALLTHROUGH; /*FALLTHRU*/ default: if (!u.utrap) /* not already in the trap */ diff --git a/src/uhitm.c b/src/uhitm.c index da34794a9..9aaa11332 100644 --- a/src/uhitm.c +++ b/src/uhitm.c @@ -3772,6 +3772,7 @@ mhitm_ad_deth( mhm->damage = 0; return; } + FALLTHROUGH; /*FALLTHRU*/ default: /* case 16: ... case 5: */ You_feel("your life force draining away..."); @@ -5385,10 +5386,12 @@ hmonas(struct monst *mon) case AT_CLAW: if (uwep && !cantwield(gy.youmonst.data) && !weapon_used) goto use_weapon; + FALLTHROUGH; /*FALLTHRU*/ case AT_TUCH: if (uwep && gy.youmonst.data->mlet == S_LICH && !weapon_used) goto use_weapon; + FALLTHROUGH; /*FALLTHRU*/ case AT_KICK: case AT_BITE: @@ -5632,6 +5635,7 @@ hmonas(struct monst *mon) || gy.youmonst.data->mlet == S_ORC || gy.youmonst.data->mlet == S_GNOME) && !weapon_used) goto use_weapon; + FALLTHROUGH; /*FALLTHRU*/ case AT_NONE: @@ -6016,6 +6020,8 @@ passive_obj( } break; } + FALLTHROUGH; + /* FALLTHRU */ default: break; } diff --git a/src/weapon.c b/src/weapon.c index d65c64945..5234c2781 100644 --- a/src/weapon.c +++ b/src/weapon.c @@ -1466,7 +1466,9 @@ weapon_hit_bonus(struct obj *weapon) } else if (type <= P_LAST_WEAPON) { switch (P_SKILL(type)) { default: - impossible(bad_skill, P_SKILL(type)); /* fall through */ + impossible(bad_skill, P_SKILL(type)); + FALLTHROUGH; + /* FALLTHRU */ case P_ISRESTRICTED: case P_UNSKILLED: bonus = -4; @@ -1487,7 +1489,9 @@ weapon_hit_bonus(struct obj *weapon) skill = P_SKILL(wep_type); switch (skill) { default: - impossible(bad_skill, skill); /* fall through */ + impossible(bad_skill, skill); + FALLTHROUGH; + /* FALLTHRU */ case P_ISRESTRICTED: case P_UNSKILLED: bonus = -9; @@ -1561,7 +1565,8 @@ weapon_dam_bonus(struct obj *weapon) switch (P_SKILL(type)) { default: impossible("weapon_dam_bonus: bad skill %d", P_SKILL(type)); - /* fall through */ + FALLTHROUGH; + /* FALLTHRU */ case P_ISRESTRICTED: case P_UNSKILLED: bonus = -2; diff --git a/src/wizard.c b/src/wizard.c index aefba556d..8db22f060 100644 --- a/src/wizard.c +++ b/src/wizard.c @@ -284,8 +284,8 @@ strategy(struct monst *mtmp) case 1: /* the wiz is less cautious */ if (mtmp->data != &mons[PM_WIZARD_OF_YENDOR]) return (unsigned long) STRAT_HEAL; - /* else fall through */ - + FALLTHROUGH; + /* FALLTHRU */ case 2: dstrat = STRAT_HEAL; break; @@ -399,6 +399,7 @@ tactics(struct monst *mtmp) mtmp->mhp += rnd(8); return 1; } + FALLTHROUGH; /*FALLTHRU*/ case STRAT_NONE: /* harass */ diff --git a/src/wizcmds.c b/src/wizcmds.c index 12f51758c..c7cdd707e 100644 --- a/src/wizcmds.c +++ b/src/wizcmds.c @@ -1065,6 +1065,7 @@ wiz_intrinsic(void) so needs more than simple incr_itimeout() but we want the pline() issued with that */ make_glib((int) newtimeout); + FALLTHROUGH; /*FALLTHRU*/ default: def_feedback: diff --git a/src/zap.c b/src/zap.c index dede87a0d..59c871edc 100644 --- a/src/zap.c +++ b/src/zap.c @@ -177,6 +177,7 @@ bhitm(struct monst *mtmp, struct obj *otmp) switch (otyp) { case WAN_STRIKING: zap_type_text = "wand"; + FALLTHROUGH; /*FALLTHRU*/ case SPE_FORCE_BOLT: reveal_invis = TRUE; @@ -1096,6 +1097,7 @@ revive(struct obj *corpse, boolean by_hero) obfree(corpse, (struct obj *) 0); break; } + FALLTHROUGH; /*FALLTHRU*/ case OBJ_FREE: case OBJ_MIGRATING: @@ -2056,6 +2058,7 @@ stone_to_flesh_obj(struct obj *obj) /* nonnull */ smell = TRUE; break; case WEAPON_CLASS: /* crysknife */ + FALLTHROUGH; /*FALLTHRU*/ default: res = 0; @@ -2869,6 +2872,7 @@ zapyourself(struct obj *obj, boolean ordinary) case WAN_LIGHT: /* (broken wand) */ /* assert( !ordinary ); */ damage = d(obj->spe, 25); + FALLTHROUGH; /*FALLTHRU*/ case EXPENSIVE_CAMERA: if (!damage) @@ -3243,6 +3247,7 @@ zap_updown(struct obj *obj) /* wand or spell, nonnull */ case WAN_STRIKING: case SPE_FORCE_BOLT: striking = TRUE; + FALLTHROUGH; /*FALLTHRU*/ case WAN_LOCKING: case SPE_WIZARD_LOCK: @@ -4924,6 +4929,7 @@ dobuzz( switch (bounce) { case 0: dx = -dx; + FALLTHROUGH; /*FALLTHRU*/ case 1: dy = -dy; @@ -5256,6 +5262,7 @@ zap_over_floor( break; case ZT_LIGHTNING: + FALLTHROUGH; /*FALLTHRU*/ case ZT_ACID: if (lev->typ == IRONBARS) { diff --git a/sys/msdos/video.c b/sys/msdos/video.c index e172513ee..6397fa8d8 100644 --- a/sys/msdos/video.c +++ b/sys/msdos/video.c @@ -293,6 +293,7 @@ term_end_attr(int attr) switch (attr) { case ATR_INVERSE: inversed = 0; + FALLTHROUGH; /*FALLTHRU*/ case ATR_ULINE: case ATR_BOLD: @@ -341,6 +342,7 @@ term_start_attr(int attr) break; case ATR_INVERSE: inversed = 1; + FALLTHROUGH; /*FALLTHRU*/ default: g_attribute = iflags.grmode ? attrib_gr_normal : attrib_text_normal; diff --git a/sys/unix/hints/include/compiler.370 b/sys/unix/hints/include/compiler.370 index 3e95e151b..ae3dc8d19 100755 --- a/sys/unix/hints/include/compiler.370 +++ b/sys/unix/hints/include/compiler.370 @@ -78,20 +78,29 @@ CXX=g++ -std=gnu++11 GCCGTEQ9 := $(shell expr `$(CC) -dumpversion | cut -f1 -d.` \>= 9) GCCGTEQ11 := $(shell expr `$(CC) -dumpversion | cut -f1 -d.` \>= 11) GCCGTEQ12 := $(shell expr `$(CC) -dumpversion | cut -f1 -d.` \>= 12) +GCCGTEQ14 := $(shell expr `$(CC) -dumpversion | cut -f1 -d.` \>= 14) ifeq "$(GCCGTEQ9)" "1" # flags present in gcc version greater than or equal to 9 can go here CFLAGS+=-Wformat-overflow CFLAGS+=-Wmissing-parameter-type endif # GCC greater than or equal to 9 #ifeq "$(GCCGTEQ11)" "1" +CFLAGS+=-Wimplicit-fallthrough #endif #ifeq "$(GCCGTEQ12)" "1" #endif +#ifeq "$(GCCGTEQ14)" "1" +CFLAGS+=-std=gnu23 +#endif # end of gcc-specific else # gcc or clang? CXX=clang++ -std=gnu++11 # clang-specific follows +CLANGGTEQ12 := $(shell expr `$(CC) -dumpversion | cut -f1 -d.` \>= 12) CLANGGTEQ14 := $(shell expr `$(CC) -dumpversion | cut -f1 -d.` \>= 14) +ifeq "$(CLANGGTEQ12)" "1" +CFLAGS+=-Wimplicit-fallthrough +endif ifeq "$(CLANGGTEQ14)" "1" ifneq "$(VIEWDEPRECATIONS)" "1" CFLAGS+=-Wno-deprecated-declarations diff --git a/sys/unix/hints/include/cross-pre2.370 b/sys/unix/hints/include/cross-pre2.370 index fa5f0911c..8a7142985 100644 --- a/sys/unix/hints/include/cross-pre2.370 +++ b/sys/unix/hints/include/cross-pre2.370 @@ -142,6 +142,7 @@ MSDOS_TARGET_CFLAGS = -c -O -I../include -I../sys/msdos -I../win/share \ -Wall -Wextra -Wno-missing-field-initializers -Wreturn-type -Wunused \ -Wformat -Wswitch -Wshadow -Wwrite-strings \ -Wimplicit -Wimplicit-function-declaration -Wimplicit-int \ + -Wimplicit-fallthrough \ -Wmissing-parameter-type -Wold-style-definition -Wstrict-prototypes MSDOS_TARGET_CXXFLAGS = -c -O -I../include -I../sys/msdos -I../win/share \ $(LUAINCL) -DDLB $(PDCURSESDEF) \ diff --git a/sys/vms/vmsunix.c b/sys/vms/vmsunix.c index f2c1bb0df..090ce9e64 100644 --- a/sys/vms/vmsunix.c +++ b/sys/vms/vmsunix.c @@ -241,6 +241,7 @@ vms_define(const char *name, const char *value, int flag) switch (flag) { case ENV_JOB: /* job logical name */ tbl_dsc.len = strlen(tbl_dsc.adr = "LNM$JOB"); + FALLTHROUGH; /*FALLTHRU*/ case ENV_SUP: /* supervisor-mode process logical name */ result = lib$set_logical(&nam_dsc, &val_dsc, &tbl_dsc); diff --git a/sys/windows/Makefile.nmake b/sys/windows/Makefile.nmake index 95b8bae17..07646b7f0 100644 --- a/sys/windows/Makefile.nmake +++ b/sys/windows/Makefile.nmake @@ -1131,10 +1131,18 @@ scall = # 4777 format string requires an argument of type 'type', # but variadic argument 'position' has type 'type' # 4820 padding in struct +# 5262 enable fallthrough warnings that lack [[fallthrough]] +# ctmpflags = $(ctmpflags:-W3=-W4) -wd4100 -wd4244 -wd4245 -wd4310 -wd4706 -w44777 -wd4820 !IF ($(VSVER) >= 2019) ctmpflags = $(ctmpflags) -w44774 !ENDIF +!IF ($(VSVER) >= 2022) +!IF ($(MAKEVERSION) >= 1440338120) +# warning 5262 became available starting in Visual Studio 2022 version 17.4. +ctmpflags = $(ctmpflags) -w45262 /std:clatest +!ENDIF +!ENDIF !ENDIF #More verbose warning output options below @@ -2880,6 +2888,8 @@ $(OTTY)sfstruct.o: sfstruct.c $(HACK_H) $(OTTY)shk.o: shk.c $(HACK_H) $(OTTY)shknam.o: shknam.c $(HACK_H) $(OTTY)sit.o: sit.c $(HACK_H) $(INCL)\artifact.h + $(Q)$(CC) $(CFLAGS) /EP $(@B).c > $(OTTY)$(@B).c.preproc + $(Q)$(CC) $(CFLAGS) -Fo$@ $(@B).c $(OTTY)sounds.o: sounds.c $(HACK_H) $(OTTY)sp_lev.o: sp_lev.c $(HACK_H) $(INCL)\sp_lev.h $(OTTY)spell.o: spell.c $(HACK_H) diff --git a/sys/windows/consoletty.c b/sys/windows/consoletty.c index 5f624bec8..30fe4cff7 100644 --- a/sys/windows/consoletty.c +++ b/sys/windows/consoletty.c @@ -1087,6 +1087,7 @@ CtrlHandler(DWORD ctrltype) /* case CTRL_C_EVENT: */ case CTRL_BREAK_EVENT: term_clear_screen(); + FALLTHROUGH; case CTRL_CLOSE_EVENT: case CTRL_LOGOFF_EVENT: case CTRL_SHUTDOWN_EVENT: @@ -1335,7 +1336,8 @@ xputc_core(int ch) case '\n': if (console.cursor.Y < console.height - 1) console.cursor.Y++; - /* fall through */ + FALLTHROUGH; + /* FALLTHRU */ case '\r': console.cursor.X = 1; break; @@ -1879,6 +1881,7 @@ toggle_mouse_support(void) #endif /* VIRTUAL_TERMINAL_SEQUENCES */ break; case 0: + FALLTHROUGH; /*FALLTHRU*/ default: #ifndef VIRTUAL_TERMINAL_SEQUENCES diff --git a/sys/windows/windmain.c b/sys/windows/windmain.c index 0cbded52d..df7e009b1 100644 --- a/sys/windows/windmain.c +++ b/sys/windows/windmain.c @@ -630,7 +630,7 @@ process_options(int argc, char * argv[]) break; } else raw_printf("\nUnknown switch: %s", argv[0]); - /* FALL THROUGH */ + FALLTHROUGH; case '?': nhusage(); nethack_exit(EXIT_SUCCESS); diff --git a/util/makedefs.c b/util/makedefs.c index 6dfb582f2..cbb466848 100644 --- a/util/makedefs.c +++ b/util/makedefs.c @@ -846,7 +846,8 @@ do_grep_control(char *buf) break; case '!': /* if not ID */ isif = 0; - /* FALLTHROUGH */ + FALLTHROUGH; + /* FALLTHRU */ case '?': /* if ID */ if (grep_sp == GREP_STACK_SIZE - 2) { Fprintf(stderr, "stack overflow at line %d.", grep_lineno); @@ -2302,6 +2303,7 @@ do_objs(void) n_glass_gems++; break; } + FALLTHROUGH; /*FALLTHRU*/ case VENOM_CLASS: /* fall-through from gem class is ok; objects[] used to have @@ -2311,6 +2313,7 @@ do_objs(void) so strip the extra "splash of " off to keep same macros */ if (!strncmp(objnam, "SPLASH_OF_", 10)) objnam += 10; + FALLTHROUGH; /*FALLTHRU*/ default: Fprintf(ofp, "#define\t"); diff --git a/win/Qt/qt_bind.cpp b/win/Qt/qt_bind.cpp index d66377f3b..e6546447c 100644 --- a/win/Qt/qt_bind.cpp +++ b/win/Qt/qt_bind.cpp @@ -271,6 +271,7 @@ void NetHackQtBind::qt_askname() // success; handle plname[] verification below prior to returning break; } + FALLTHROUGH; /*FALLTHRU*/ case -2: // Quit @@ -726,6 +727,7 @@ char NetHackQtBind::qt_more() switch (ch) { case '\0': // hypothetical ch = '\033'; + FALLTHROUGH; /*FALLTHRU*/ case ' ': case '\n': diff --git a/win/curses/cursdial.c b/win/curses/cursdial.c index 5dbe9d796..a0e93d093 100644 --- a/win/curses/cursdial.c +++ b/win/curses/cursdial.c @@ -1556,6 +1556,7 @@ menu_get_selections(WINDOW *win, nhmenu *menu, int how) break; } } + FALLTHROUGH; /*FALLTHRU*/ default: if (curletter > 0 && curletter < 256 diff --git a/win/curses/cursinit.c b/win/curses/cursinit.c index de1811e7f..fcf13ec19 100644 --- a/win/curses/cursinit.c +++ b/win/curses/cursinit.c @@ -114,6 +114,7 @@ curses_create_main_windows(void) case 3: noperminv_borders = TRUE; + FALLTHROUGH; /*FALLTHRU*/ case 1: /* On */ borders = TRUE; @@ -121,6 +122,7 @@ curses_create_main_windows(void) case 4: noperminv_borders = TRUE; + FALLTHROUGH; /*FALLTHRU*/ case 2: /* Auto */ borders = (term_cols >= 80 + 2 && term_rows >= 24 + 2); diff --git a/win/curses/cursmisc.c b/win/curses/cursmisc.c index 73a939f2a..71b9f31f6 100644 --- a/win/curses/cursmisc.c +++ b/win/curses/cursmisc.c @@ -291,7 +291,7 @@ curses_break_str(const char *str, int width, int line_num) char *retstr; int curline = 0; int strsize = (int) strlen(str) + 1; -#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L +#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) && !defined(_MSC_VER) char substr[strsize]; char curstr[strsize]; char tmpstr[strsize]; @@ -363,7 +363,7 @@ curses_str_remainder(const char *str, int width, int line_num) char *retstr; int curline = 0; int strsize = strlen(str) + 1; -#if __STDC_VERSION__ >= 199901L +#if (__STDC_VERSION__ >= 199901L) && !defined(_MSC_VER) char substr[strsize]; char tmpstr[strsize]; @@ -801,6 +801,7 @@ curses_convert_keys(int key) a value for ^H greater than 255 is passed back to core's readchar() and stripping the value down to 0..255 yields ^G! */ ret = C('H'); + FALLTHROUGH; /*FALLTHRU*/ default: if (modifiers_available) diff --git a/win/curses/cursstat.c b/win/curses/cursstat.c index 15168f845..90a9d93c9 100644 --- a/win/curses/cursstat.c +++ b/win/curses/cursstat.c @@ -415,6 +415,7 @@ draw_horizontal(boolean border) w -= (t - 30); /* '+= strlen()' below will add 't'; * functional result being 'w += 30' */ } + FALLTHROUGH; /*FALLTHRU*/ case BL_ALIGN: case BL_LEVELDESC: @@ -1231,6 +1232,7 @@ curs_vert_status_vals(int win_width) if (fld_width < hp_width + 3) /* +3: " " gap and "("...")" */ Sprintf(leadingspace, "%*s", (hp_width + 3) - fld_width, " "); + FALLTHROUGH; /*FALLTHRU*/ case BL_VERS: case BL_EXP: diff --git a/win/curses/curswins.c b/win/curses/curswins.c index fa99b58c4..19c6c380a 100644 --- a/win/curses/curswins.c +++ b/win/curses/curswins.c @@ -98,6 +98,7 @@ curses_create_window(int wid, int width, int height, orient orientation) switch (orientation) { default: impossible("curses_create_window: Bad orientation"); + FALLTHROUGH; /*FALLTHRU*/ case CENTER: startx = (term_cols / 2) - (width / 2); diff --git a/win/tty/termcap.c b/win/tty/termcap.c index 4cb40d4ea..2c6a5bd88 100644 --- a/win/tty/termcap.c +++ b/win/tty/termcap.c @@ -1341,6 +1341,7 @@ s_atr2str(int n) /* if italic isn't available, fall through to underline */ if (ZH && *ZH) return ZH; + FALLTHROUGH; /*FALLTHRU*/ case ATR_BLINK: case ATR_ULINE: @@ -1351,6 +1352,7 @@ s_atr2str(int n) if (nh_US && *nh_US) return nh_US; } + FALLTHROUGH; /*FALLTHRU*/ case ATR_BOLD: if (MD && *MD) @@ -1378,15 +1380,18 @@ e_atr2str(int n) /* send ZR unless we didn't have ZH and substituted US */ if (ZR && *ZR && ZH && *ZH) return ZR; + FALLTHROUGH; /*FALLTHRU*/ case ATR_ULINE: if (nh_UE && *nh_UE) return nh_UE; + FALLTHROUGH; /*FALLTHRU*/ case ATR_BOLD: case ATR_BLINK: if (nh_HE && *nh_HE) return nh_HE; + FALLTHROUGH; /*FALLTHRU*/ case ATR_DIM: case ATR_INVERSE: diff --git a/win/tty/wintty.c b/win/tty/wintty.c index 17dcd1cc2..693592fbb 100644 --- a/win/tty/wintty.c +++ b/win/tty/wintty.c @@ -665,6 +665,7 @@ tty_askname(void) case -1: bail("Until next time then..."); /* quit */ /*NOTREACHED*/ + break; case 0: break; /* no game chosen; start new game */ case 1: @@ -1084,6 +1085,7 @@ tty_clear_nhwindow(winid window) case NHW_MAP: /* cheap -- clear the whole thing and tell nethack to redraw botl */ disp.botlx = TRUE; + FALLTHROUGH; /*FALLTHRU*/ case NHW_BASE: /* if erasing_tty_screen is True, calling sequence is @@ -1721,6 +1723,7 @@ process_menu_window(winid window, struct WinDesc *cw) break; case MENU_EXPLICIT_CHOICE: morc = really_morc; + FALLTHROUGH; /*FALLTHRU*/ default: if (cw->how == PICK_NONE || !strchr(resp, morc)) { @@ -1878,12 +1881,14 @@ tty_display_nhwindow( tty_display_nhwindow(WIN_MESSAGE, TRUE); return; } + FALLTHROUGH; /*FALLTHRU*/ case NHW_BASE: (void) fflush(stdout); break; case NHW_TEXT: cw->maxcol = ttyDisplay->cols; /* force full-screen mode */ + FALLTHROUGH; /*FALLTHRU*/ case NHW_MENU: cw->active = 1; @@ -1951,6 +1956,7 @@ tty_dismiss_nhwindow(winid window) if (ttyDisplay->toplin != TOPLINE_EMPTY) tty_display_nhwindow(WIN_MESSAGE, TRUE); nhassert(ttyDisplay->toplin == TOPLINE_EMPTY); + FALLTHROUGH; /*FALLTHRU*/ case NHW_STATUS: case NHW_BASE: @@ -4438,6 +4444,7 @@ tty_status_update( switch (fldidx) { case BL_RESET: reset_state = FORCE_RESET; + FALLTHROUGH; /*FALLTHRU*/ case BL_FLUSH: if (make_things_fit(reset_state) || truncation_expected) { @@ -4458,6 +4465,7 @@ tty_status_update( break; case BL_GOLD: text = decode_mixed(goldbuf, text); + FALLTHROUGH; /*FALLTHRU*/ default: attrmask = (color >> 8) & 0x00FF; @@ -4506,6 +4514,7 @@ tty_status_update( break; case BL_LEVELDESC: dlvl_shrinklvl = 0; /* caller is passing full length string */ + FALLTHROUGH; /*FALLTHRU*/ case BL_HUNGER: /* The core sends trailing blanks for some fields. diff --git a/win/win32/mhdlg.c b/win/win32/mhdlg.c index afa55c1c9..f190f000d 100644 --- a/win/win32/mhdlg.c +++ b/win/win32/mhdlg.c @@ -146,7 +146,8 @@ GetlinDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) (WPARAM) sizeof(wbuf2), (LPARAM) wbuf2); NH_W2A(wbuf2, data->result, data->result_size); - /* Fall through. */ + FALLTHROUGH; + /* FALLTHRU */ /* cancel button was pressed */ case IDCANCEL: @@ -246,7 +247,8 @@ ExtCmdDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) hWnd, IDC_EXTCMD_LIST, LB_GETCURSEL, (WPARAM) 0, (LPARAM) 0); if (*data->selection == LB_ERR) *data->selection = -1; - /* Fall through. */ + FALLTHROUGH; + /* FALLTHRU */ /* CANCEL button ws clicked */ case IDCANCEL: From 88301902f8a34bc76360ea33790e3b462dba26d7 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 30 Nov 2024 14:47:04 -0500 Subject: [PATCH 109/791] remove a left-over piece of a test --- sys/unix/hints/include/compiler.370 | 1 - 1 file changed, 1 deletion(-) diff --git a/sys/unix/hints/include/compiler.370 b/sys/unix/hints/include/compiler.370 index ae3dc8d19..62486d3ad 100755 --- a/sys/unix/hints/include/compiler.370 +++ b/sys/unix/hints/include/compiler.370 @@ -90,7 +90,6 @@ CFLAGS+=-Wimplicit-fallthrough #ifeq "$(GCCGTEQ12)" "1" #endif #ifeq "$(GCCGTEQ14)" "1" -CFLAGS+=-std=gnu23 #endif # end of gcc-specific else # gcc or clang? From d94f728a9f50c0cd538c90ebf13983eef6a66121 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 30 Nov 2024 15:42:06 -0500 Subject: [PATCH 110/791] Windows visual studio: lualib as separate entity --- sys/windows/vs/NetHack.sln | 15 + sys/windows/vs/NetHack/NetHack.vcxproj | 22 +- sys/windows/vs/NetHackW/NetHackW.vcxproj | 18 +- sys/windows/vs/dlb/dlb.vcxproj | 6 +- sys/windows/vs/hacklib/hacklib.vcxproj | 12 +- sys/windows/vs/lualib/lualib.vcxproj | 487 +++++++++++++++++++++++ sys/windows/vs/makedefs/makedefs.vcxproj | 9 +- sys/windows/vs/recover/recover.vcxproj | 2 + sys/windows/vs/tile2bmp/tile2bmp.vcxproj | 22 +- sys/windows/vs/tilemap/tilemap.vcxproj | 20 +- sys/windows/vs/uudecode/uudecode.vcxproj | 7 +- 11 files changed, 559 insertions(+), 61 deletions(-) create mode 100644 sys/windows/vs/lualib/lualib.vcxproj diff --git a/sys/windows/vs/NetHack.sln b/sys/windows/vs/NetHack.sln index 732d87c12..3bb69f828 100644 --- a/sys/windows/vs/NetHack.sln +++ b/sys/windows/vs/NetHack.sln @@ -12,6 +12,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NetHackW", "NetHackW\NetHac {63F9B82B-F589-4082-ABE5-D4F0682050AB} = {63F9B82B-F589-4082-ABE5-D4F0682050AB} {642BC75D-ABAF-403E-8224-7C725FD4CB42} = {642BC75D-ABAF-403E-8224-7C725FD4CB42} {93F10526-209E-41D7-BBEA-775787876895} = {93F10526-209E-41D7-BBEA-775787876895} + {B6B3CC8A-75FD-479C-AB1C-D80FFF0F5037} = {B6B3CC8A-75FD-479C-AB1C-D80FFF0F5037} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dlb", "dlb\dlb.vcxproj", "{0303A585-3F83-4BB7-AF6B-1E12C8FB54AC}" @@ -60,6 +61,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NetHack", "NetHack\NetHack. {096FD6BB-256A-4E68-9B09-2ACA7C606FF3} = {096FD6BB-256A-4E68-9B09-2ACA7C606FF3} {503AE687-C33A-45ED-93AA-83967E176D67} = {503AE687-C33A-45ED-93AA-83967E176D67} {63F9B82B-F589-4082-ABE5-D4F0682050AB} = {63F9B82B-F589-4082-ABE5-D4F0682050AB} + {B6B3CC8A-75FD-479C-AB1C-D80FFF0F5037} = {B6B3CC8A-75FD-479C-AB1C-D80FFF0F5037} {BAA70D0F-3EC7-4D10-91F0-974F1F49308B} = {BAA70D0F-3EC7-4D10-91F0-974F1F49308B} EndProjectSection EndProject @@ -101,6 +103,11 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "package", "package\package. {CEC5D360-8804-454F-8591-002184C23499} = {CEC5D360-8804-454F-8591-002184C23499} EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lualib", "lualib\lualib.vcxproj", "{B6B3CC8A-75FD-479C-AB1C-D80FFF0F5037}" + ProjectSection(ProjectDependencies) = postProject + {503AE687-C33A-45ED-93AA-83967E176D67} = {503AE687-C33A-45ED-93AA-83967E176D67} + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -213,6 +220,14 @@ Global {0B53AF9B-E1A4-478B-9246-43A39E8B4027}.Release|Win32.Build.0 = Release|Win32 {0B53AF9B-E1A4-478B-9246-43A39E8B4027}.Release|x64.ActiveCfg = Release|x64 {0B53AF9B-E1A4-478B-9246-43A39E8B4027}.Release|x64.Build.0 = Release|x64 + {B6B3CC8A-75FD-479C-AB1C-D80FFF0F5037}.Debug|Win32.ActiveCfg = Debug|Win32 + {B6B3CC8A-75FD-479C-AB1C-D80FFF0F5037}.Debug|Win32.Build.0 = Debug|Win32 + {B6B3CC8A-75FD-479C-AB1C-D80FFF0F5037}.Debug|x64.ActiveCfg = Debug|x64 + {B6B3CC8A-75FD-479C-AB1C-D80FFF0F5037}.Debug|x64.Build.0 = Debug|x64 + {B6B3CC8A-75FD-479C-AB1C-D80FFF0F5037}.Release|Win32.ActiveCfg = Release|Win32 + {B6B3CC8A-75FD-479C-AB1C-D80FFF0F5037}.Release|Win32.Build.0 = Release|Win32 + {B6B3CC8A-75FD-479C-AB1C-D80FFF0F5037}.Release|x64.ActiveCfg = Release|x64 + {B6B3CC8A-75FD-479C-AB1C-D80FFF0F5037}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/sys/windows/vs/NetHack/NetHack.vcxproj b/sys/windows/vs/NetHack/NetHack.vcxproj index b777fb0b0..b18e4a771 100644 --- a/sys/windows/vs/NetHack/NetHack.vcxproj +++ b/sys/windows/vs/NetHack/NetHack.vcxproj @@ -40,16 +40,24 @@ - /Gs /Oi- /w44774 %(AdditionalOptions) + /Gs /Oi- /w44774 /w45262 %(AdditionalOptions) Disabled Default Speed true $(WinWin32Dir);$(IncDir);$(SysWindDir);$(SysShareDir);$(WinShareDir);$(LuaDir);%(AdditionalIncludeDirectories) WIN32CON;NO_TILE_C;DLB;SAFEPROCS;SND_LIB_WINDSOUND;USER_SOUNDS;_LIB;HAS_STDINT_H;%(PreprocessorDefinitions) + stdclatest + stdclatest + stdclatest + stdclatest + /Gs /Oi- /w44774 /w45262 %(AdditionalOptions) + /Gs /Oi- /w44774 /w45262 %(AdditionalOptions) + /Gs /Oi- /w44774 /w45262 %(AdditionalOptions) + /Gs /Oi- /w44774 /w45262 %(AdditionalOptions) - hacklib.lib;kernel32.lib;dbghelp.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;winmm.lib;Winmm.lib;bcrypt.lib;%(AdditionalDependencies) + hacklib.lib;lualib.lib;kernel32.lib;dbghelp.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;winmm.lib;Winmm.lib;bcrypt.lib;%(AdditionalDependencies) $(SndWavDir);%(AdditionalIncludeDirectories) @@ -65,12 +73,6 @@ - - 4701;4702;4244;4310;4774 - %(AdditionalOptions) /wd4774 - 4701;4702;4244;4310;4774;4324 - 4701;4702;4244;4310;4774;4324 - @@ -243,6 +245,8 @@ + + @@ -308,4 +312,4 @@ - \ No newline at end of file + diff --git a/sys/windows/vs/NetHackW/NetHackW.vcxproj b/sys/windows/vs/NetHackW/NetHackW.vcxproj index 091dbb94e..97980d2d7 100644 --- a/sys/windows/vs/NetHackW/NetHackW.vcxproj +++ b/sys/windows/vs/NetHackW/NetHackW.vcxproj @@ -53,6 +53,14 @@ true $(WinWin32Dir);$(IncDir);$(SysWindDir);$(SysShareDir);$(WinShareDir);$(LuaDir);%(AdditionalIncludeDirectories) TILES;_WINDOWS;DLB;MSWIN_GRAPHICS;SAFEPROCS;NOTTYGRAPHICS;SND_LIB_WINDSOUND;USER_SOUNDS;HAS_STDINT_H;PDC_WIDE;%(PreprocessorDefinitions) + stdclatest + stdclatest + stdclatest + stdclatest + /Gs /Oi- /w44774 /w45262 %(AdditionalOptions) + /Gs /Oi- /w44774 /w45262 %(AdditionalOptions) + /Gs /Oi- /w44774 /w45262 %(AdditionalOptions) + /Gs /Oi- /w44774 /w45262 %(AdditionalOptions) 4820;4706;4244;4245;4100;4310;6001 4820;4706;4244;4245;4100;4310 @@ -66,7 +74,7 @@ Windows - hacklib.lib;dbghelp.lib;comctl32.lib;winmm.lib;bcrypt.lib;%(AdditionalDependencies) + hacklib.lib;lualib.lib;dbghelp.lib;comctl32.lib;winmm.lib;bcrypt.lib;%(AdditionalDependencies) $(WinWin32Dir)NethackW.exe.manifest;%(AdditionalManifestFiles) @@ -74,12 +82,6 @@ - - 4701;4702;4244;4310;4774 - %(AdditionalOptions) /wd4774 - 4701;4702;4244;4310;4774;4324;6011;6297;6305;6385;6386;6387;28182 - 4701;4702;4244;4310;4774;4324 - @@ -372,4 +374,4 @@ - \ No newline at end of file + diff --git a/sys/windows/vs/dlb/dlb.vcxproj b/sys/windows/vs/dlb/dlb.vcxproj index d54510ff0..71b96d823 100644 --- a/sys/windows/vs/dlb/dlb.vcxproj +++ b/sys/windows/vs/dlb/dlb.vcxproj @@ -28,6 +28,10 @@ $(IncDir);$(SysWindDir);$(SysShareDir);$(LuaDir);%(AdditionalIncludeDirectories) WIN32CON;DLB;MSWIN_GRAPHICS;HAS_STDINT_H;%(PreprocessorDefinitions) + stdclatest + stdclatest + stdclatest + stdclatest $(ToolsDir);%(AdditionalLibraryDirectories) @@ -64,4 +68,4 @@ - \ No newline at end of file + diff --git a/sys/windows/vs/hacklib/hacklib.vcxproj b/sys/windows/vs/hacklib/hacklib.vcxproj index 2d53093eb..4ec744f5c 100644 --- a/sys/windows/vs/hacklib/hacklib.vcxproj +++ b/sys/windows/vs/hacklib/hacklib.vcxproj @@ -102,7 +102,9 @@ WIN32;_DEBUG;_LIB;WIN32CON;DLB;MSWIN_GRAPHICS;ENUM_PM;HAS_STDINT_H;%(PreprocessorDefinitions) true $(IncDir);$(SysWindDir);$(LuaDir);%(AdditionalIncludeDirectories) - + stdclatest + /w45262 %(AdditionalOptions) + @@ -118,6 +120,8 @@ WIN32;NDEBUG;_LIB;WIN32CON;DLB;MSWIN_GRAPHICS;ENUM_PM;HAS_STDINT_H;%(PreprocessorDefinitions) true $(IncDir);$(SysWindDir);$(LuaDir);%(AdditionalIncludeDirectories) + stdclatest + /w45262 %(AdditionalOptions) @@ -134,6 +138,8 @@ _DEBUG;_LIB;WIN32CON;DLB;MSWIN_GRAPHICS;ENUM_PM;HAS_STDINT_H;%(PreprocessorDefinitions) true $(IncDir);$(SysWindDir);$(LuaDir);%(AdditionalIncludeDirectories) + stdclatest + /w45262 %(AdditionalOptions) @@ -150,6 +156,8 @@ NDEBUG;_LIB;WIN32CON;DLB;MSWIN_GRAPHICS;ENUM_PM;HAS_STDINT_H;%(PreprocessorDefinitions) true $(IncDir);$(SysWindDir);$(LuaDir);%(AdditionalIncludeDirectories) + stdclatest + /w45262 %(AdditionalOptions) @@ -171,4 +179,4 @@ - \ No newline at end of file + diff --git a/sys/windows/vs/lualib/lualib.vcxproj b/sys/windows/vs/lualib/lualib.vcxproj new file mode 100644 index 000000000..6d3f25bbc --- /dev/null +++ b/sys/windows/vs/lualib/lualib.vcxproj @@ -0,0 +1,487 @@ + + + + + + + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + + + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + + + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + + + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + + + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + + + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + + + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + + + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + + + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + + + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + + + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + + + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + + + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + + + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + + + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + + + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + + + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + + + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + + + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + + + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + + + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + + + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + + + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + + + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + + + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + + + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + + + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + + + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + + + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + + + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + + + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + + + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + 4701;4702;4244;4310;4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + %(AdditionalOptions) /wd4774 + + + + + + 17.0 + Win32Proj + {B6B3CC8A-75FD-479C-AB1C-D80FFF0F5037} + lualib + 10.0 + + + + StaticLibrary + true + $(DefaultPlatformToolset) + Unicode + + + StaticLibrary + false + $(DefaultPlatformToolset) + true + Unicode + + + StaticLibrary + true + v143 + Unicode + + + StaticLibrary + false + v143 + true + Unicode + + + + + + + + + + + + + + + + + + + + + + Level3 + true + WIN32;_DEBUG;_LIB;WIN32CON;DLB;MSWIN_GRAPHICS;ENUM_PM;HAS_STDINT_H;%(PreprocessorDefinitions) + true + $(IncDir);$(SysWindDir);$(LuaDir);%(AdditionalIncludeDirectories) + stdclatest + /Gs /Oi- /w44774 /w45262 %(AdditionalOptions) + + + + + true + + + + + Level3 + true + true + true + WIN32;NDEBUG;_LIB;WIN32CON;DLB;MSWIN_GRAPHICS;ENUM_PM;HAS_STDINT_H;%(PreprocessorDefinitions) + true + $(IncDir);$(SysWindDir);$(LuaDir);%(AdditionalIncludeDirectories) + stdclatest + /Gs /Oi- /w44774 /w45262 %(AdditionalOptions) + + + + + true + true + true + + + + + Level3 + true + _DEBUG;_LIB;WIN32CON;DLB;MSWIN_GRAPHICS;ENUM_PM;HAS_STDINT_H;%(PreprocessorDefinitions) + true + $(IncDir);$(SysWindDir);$(LuaDir);%(AdditionalIncludeDirectories) + stdclatest + /Gs /Oi- /w44774 /w45262 %(AdditionalOptions) + + + + + true + + + + + Level3 + true + true + true + NDEBUG;_LIB;WIN32CON;DLB;MSWIN_GRAPHICS;ENUM_PM;HAS_STDINT_H;%(PreprocessorDefinitions) + true + $(IncDir);$(SysWindDir);$(LuaDir);%(AdditionalIncludeDirectories) + stdclatest + /Gs /Oi- /w44774 /w45262 %(AdditionalOptions) + + + + + true + true + true + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/sys/windows/vs/makedefs/makedefs.vcxproj b/sys/windows/vs/makedefs/makedefs.vcxproj index 9c3abce14..c5bd6c0dd 100644 --- a/sys/windows/vs/makedefs/makedefs.vcxproj +++ b/sys/windows/vs/makedefs/makedefs.vcxproj @@ -28,13 +28,12 @@ $(IncDir);$(SysWindDir);$(LuaDir);%(AdditionalIncludeDirectories) WIN32CON;DLB;MSWIN_GRAPHICS;ENUM_PM;HAS_STDINT_H;%(PreprocessorDefinitions) + stdclatest + /w45262 %(AdditionalOptions) - $(ToolsDir);%(AdditionalLibraryDirectories) + $(ToolsDir);%(AdditionalLibraryDirectories) hacklib.lib;%(AdditionalDependencies) - $(ToolsDir);%(AdditionalLibraryDirectories) - $(ToolsDir);%(AdditionalLibraryDirectories) - $(ToolsDir);%(AdditionalLibraryDirectories) @@ -69,4 +68,4 @@ - \ No newline at end of file + diff --git a/sys/windows/vs/recover/recover.vcxproj b/sys/windows/vs/recover/recover.vcxproj index 1e108fcfc..66fd134d0 100644 --- a/sys/windows/vs/recover/recover.vcxproj +++ b/sys/windows/vs/recover/recover.vcxproj @@ -20,6 +20,8 @@ $(IncDir);$(SysWindDir);$(LuaDir);%(AdditionalIncludeDirectories) WIN32CON;DLB;MSWIN_GRAPHICS;HAS_STDINT_H;%(PreprocessorDefinitions) + stdclatest + /w45262 %(AdditionalOptions) $(ToolsDir);%(AdditionalLibraryDirectories) diff --git a/sys/windows/vs/tile2bmp/tile2bmp.vcxproj b/sys/windows/vs/tile2bmp/tile2bmp.vcxproj index 113567b86..8207ebceb 100644 --- a/sys/windows/vs/tile2bmp/tile2bmp.vcxproj +++ b/sys/windows/vs/tile2bmp/tile2bmp.vcxproj @@ -28,23 +28,13 @@ $(IncDir);$(SysWindDir);$(SysShareDir);$(LuaDir);%(AdditionalIncludeDirectories) WIN32CON;DLB;MSWIN_GRAPHICS;HAS_STDINT_H;%(PreprocessorDefinitions) + stdclatest + /w45262 %(AdditionalOptions) - $(ToolsDir);%(AdditionalLibraryDirectories) - hacklib.lib;%(AdditionalDependencies) - - - $(ToolsDir);%(AdditionalLibraryDirectories) - hacklib.lib;%(AdditionalDependencies) - - - $(ToolsDir);%(AdditionalLibraryDirectories) - hacklib.lib;%(AdditionalDependencies) - - - $(ToolsDir);%(AdditionalLibraryDirectories) - hacklib.lib;%(AdditionalDependencies) - + $(ToolsDir);%(AdditionalLibraryDirectories) + hacklib.lib;%(AdditionalDependencies) + @@ -66,4 +56,4 @@ - \ No newline at end of file + diff --git a/sys/windows/vs/tilemap/tilemap.vcxproj b/sys/windows/vs/tilemap/tilemap.vcxproj index ee79ffc68..aa34626e5 100644 --- a/sys/windows/vs/tilemap/tilemap.vcxproj +++ b/sys/windows/vs/tilemap/tilemap.vcxproj @@ -30,22 +30,12 @@ $(IncDir);$(SysWindDir);$(SysShareDir);$(LuaDir);%(AdditionalIncludeDirectories) WIN32CON;DLB;MSWIN_GRAPHICS;HAS_STDINT_H;%(PreprocessorDefinitions) + stdclatest + /w45262 %(AdditionalOptions) - $(ToolsDir);%(AdditionalLibraryDirectories) - hacklib.lib;%(AdditionalDependencies) - - - $(ToolsDir);%(AdditionalLibraryDirectories) - hacklib.lib;%(AdditionalDependencies) - - - $(ToolsDir);%(AdditionalLibraryDirectories) - hacklib.lib;%(AdditionalDependencies) - - - $(ToolsDir);%(AdditionalLibraryDirectories) - hacklib.lib;%(AdditionalDependencies) + $(ToolsDir);%(AdditionalLibraryDirectories) + hacklib.lib;%(AdditionalDependencies) @@ -105,4 +95,4 @@ - \ No newline at end of file + diff --git a/sys/windows/vs/uudecode/uudecode.vcxproj b/sys/windows/vs/uudecode/uudecode.vcxproj index f99aa84b1..5b85f9979 100644 --- a/sys/windows/vs/uudecode/uudecode.vcxproj +++ b/sys/windows/vs/uudecode/uudecode.vcxproj @@ -31,10 +31,7 @@ - 4820;4702;4706;4244;4245;4100;4310 - 4820;4702;4706;4244;4245;4100;4310 - 4820;4702;4706;4244;4245;4100;4310 - 4820;4702;4706;4244;4245;4100;4310 + 4820;4702;4706;4244;4245;4100;4310 @@ -47,4 +44,4 @@ - \ No newline at end of file + From 36227fcb6d7319bc14b3a24e058aa7f18afcbf4b Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 30 Nov 2024 15:47:40 -0500 Subject: [PATCH 111/791] follow-up: build fix when using VS 2019 --- sys/windows/vs/lualib/lualib.vcxproj | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/sys/windows/vs/lualib/lualib.vcxproj b/sys/windows/vs/lualib/lualib.vcxproj index 6d3f25bbc..b16d0fccb 100644 --- a/sys/windows/vs/lualib/lualib.vcxproj +++ b/sys/windows/vs/lualib/lualib.vcxproj @@ -407,8 +407,7 @@ WIN32;_DEBUG;_LIB;WIN32CON;DLB;MSWIN_GRAPHICS;ENUM_PM;HAS_STDINT_H;%(PreprocessorDefinitions) true $(IncDir);$(SysWindDir);$(LuaDir);%(AdditionalIncludeDirectories) - stdclatest - /Gs /Oi- /w44774 /w45262 %(AdditionalOptions) + /Gs /Oi- /w44774 %(AdditionalOptions) @@ -425,8 +424,7 @@ WIN32;NDEBUG;_LIB;WIN32CON;DLB;MSWIN_GRAPHICS;ENUM_PM;HAS_STDINT_H;%(PreprocessorDefinitions) true $(IncDir);$(SysWindDir);$(LuaDir);%(AdditionalIncludeDirectories) - stdclatest - /Gs /Oi- /w44774 /w45262 %(AdditionalOptions) + /Gs /Oi- /w44774 %(AdditionalOptions) @@ -444,7 +442,7 @@ true $(IncDir);$(SysWindDir);$(LuaDir);%(AdditionalIncludeDirectories) stdclatest - /Gs /Oi- /w44774 /w45262 %(AdditionalOptions) + /Gs /Oi- /w44774 %(AdditionalOptions) @@ -462,7 +460,7 @@ true $(IncDir);$(SysWindDir);$(LuaDir);%(AdditionalIncludeDirectories) stdclatest - /Gs /Oi- /w44774 /w45262 %(AdditionalOptions) + /Gs /Oi- /w44774 %(AdditionalOptions) @@ -484,4 +482,4 @@ - \ No newline at end of file + From df86614318deed52c7ca47c2f193263ef39df45f Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 30 Nov 2024 15:51:30 -0500 Subject: [PATCH 112/791] Windows Visual Studio: another follow-up Missed a couple of configuration options in previous fix --- sys/windows/vs/lualib/lualib.vcxproj | 2 -- 1 file changed, 2 deletions(-) diff --git a/sys/windows/vs/lualib/lualib.vcxproj b/sys/windows/vs/lualib/lualib.vcxproj index b16d0fccb..52d96e5cb 100644 --- a/sys/windows/vs/lualib/lualib.vcxproj +++ b/sys/windows/vs/lualib/lualib.vcxproj @@ -441,7 +441,6 @@ _DEBUG;_LIB;WIN32CON;DLB;MSWIN_GRAPHICS;ENUM_PM;HAS_STDINT_H;%(PreprocessorDefinitions) true $(IncDir);$(SysWindDir);$(LuaDir);%(AdditionalIncludeDirectories) - stdclatest /Gs /Oi- /w44774 %(AdditionalOptions) @@ -459,7 +458,6 @@ NDEBUG;_LIB;WIN32CON;DLB;MSWIN_GRAPHICS;ENUM_PM;HAS_STDINT_H;%(PreprocessorDefinitions) true $(IncDir);$(SysWindDir);$(LuaDir);%(AdditionalIncludeDirectories) - stdclatest /Gs /Oi- /w44774 %(AdditionalOptions) From 8f2b979f3240c1df308f8c9f73f488ad867079d2 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 30 Nov 2024 17:05:23 -0500 Subject: [PATCH 113/791] Windows: nmake lualib build bit --- sys/windows/Makefile.nmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/windows/Makefile.nmake b/sys/windows/Makefile.nmake index 07646b7f0..6ecb58bec 100644 --- a/sys/windows/Makefile.nmake +++ b/sys/windows/Makefile.nmake @@ -1357,7 +1357,7 @@ DLB = #========================================== {$(LUASRC)}.c{$(OBJLUA)}.o: - $(Q)$(CC) $(CFLAGS) -wd4701 -wd4702 -wd4774 -wd4324 $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) -Fo$@ $< + $(Q)$(CC) $(CFLAGS) -wd4701 -wd4702 -wd4774 -wd4324 -wd5262 $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) -Fo$@ $< #=============================================================================== # Rules for integrated sound files in sound/wav From bc88266081e15036261dc9ad2a96d603d76e65a1 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 30 Nov 2024 17:08:54 -0500 Subject: [PATCH 114/791] NetHack's regex function prototypes into nhregex.h There was an issue with Windows mingw build because the function prototypes were not available. Place them into a distinct header file nhregex.h and include it from extern.h, and available for cppregex.cpp to include without the rest of extern.h (which can give some problems with c++). --- include/extern.h | 7 +------ include/nhregex.h | 17 +++++++++++++++++ sys/share/cppregex.cpp | 2 +- 3 files changed, 19 insertions(+), 7 deletions(-) create mode 100644 include/nhregex.h diff --git a/include/extern.h b/include/extern.h index 81c52e11d..8fa5aa9b3 100644 --- a/include/extern.h +++ b/include/extern.h @@ -2074,12 +2074,7 @@ extern void tutorial(boolean); #endif /* MAKEDEFS_C MDLIB_C CPPREGEX_C */ /* ### {cpp,pmatch,posix}regex.c ### */ - -extern struct nhregex *regex_init(void); -extern boolean regex_compile(const char *, struct nhregex *) NONNULLARG1; -extern char *regex_error_desc(struct nhregex *, char *) NONNULLARG2; -extern boolean regex_match(const char *, struct nhregex *) NO_NNARGS; -extern void regex_free(struct nhregex *) NONNULLARG1; +#include "nhregex.h" #if !defined(MAKEDEFS_C) && !defined(MDLIB_C) && !defined(CPPREGEX_C) diff --git a/include/nhregex.h b/include/nhregex.h new file mode 100644 index 000000000..6dc989213 --- /dev/null +++ b/include/nhregex.h @@ -0,0 +1,17 @@ +/* NetHack 3.7 nhregex.h $NHDT-Date: $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: $ */ +/* NetHack may be freely redistributed. See license for details. */ + +#ifndef NHREGEX_H +#define NHREGEX_H + +/* ### {cpp,pmatch,posix}regex.c ### */ + +extern struct nhregex *regex_init(void); +extern boolean regex_compile(const char *, struct nhregex *) NONNULLARG1; +extern char *regex_error_desc(struct nhregex *, char *) NONNULLARG2; +extern boolean regex_match(const char *, struct nhregex *) NO_NNARGS; +extern void regex_free(struct nhregex *) NONNULLARG1; + +#endif /* NHREGEX_H */ + +/*extern.h*/ diff --git a/sys/share/cppregex.cpp b/sys/share/cppregex.cpp index 4d45928c7..9835a1f5c 100644 --- a/sys/share/cppregex.cpp +++ b/sys/share/cppregex.cpp @@ -10,7 +10,7 @@ extern "C" { #include "config.h" #define CPPREGEX_C -//#include "extern.h" +#include "nhregex.h" } // extern "C" From 92d931f1909dde97190a406811b47247b3eea83d Mon Sep 17 00:00:00 2001 From: Michael Meyer Date: Tue, 12 Nov 2024 17:34:23 -0500 Subject: [PATCH 115/791] Refresh worm segments when (un)taming Because newsym() would be called only on the head position of the worm, if hilite_pet was on, the segments and head of a long worm would have mismatched highlighting in the immediate aftermath of taming or untaming. --- include/extern.h | 1 + src/dog.c | 8 +++++++- src/worm.c | 11 +++++++++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/include/extern.h b/include/extern.h index 4a36834d0..338f19940 100644 --- a/include/extern.h +++ b/include/extern.h @@ -3766,6 +3766,7 @@ extern boolean worm_cross(int, int, int, int); extern int wseg_at(struct monst *, int, int) NO_NNARGS; extern void flip_worm_segs_vertical(struct monst *, int, int) NONNULLARG1; extern void flip_worm_segs_horizontal(struct monst *, int, int) NONNULLARG1; +extern void redraw_worm(struct monst *); /* ### worn.c ### */ diff --git a/src/dog.c b/src/dog.c index a856c4a05..edb747189 100644 --- a/src/dog.c +++ b/src/dog.c @@ -1180,6 +1180,8 @@ tamedog(struct monst *mtmp, struct obj *obj, boolean givemsg) Hallucination ? "approachable" : "friendly"); newsym(mtmp->mx, mtmp->my); + if (mtmp->wormno) + redraw_worm(mtmp); if (attacktype(mtmp->data, AT_WEAP)) { mtmp->weapon_check = NEED_HTH_WEAPON; (void) mon_wield_item(mtmp); @@ -1288,8 +1290,12 @@ abuse_dog(struct monst *mtmp) else growl(mtmp); /* give them a moment's worry */ - if (!mtmp->mtame) + if (!mtmp->mtame) { newsym(mtmp->mx, mtmp->my); + if (mtmp->wormno) { + redraw_worm(mtmp); + } + } } } diff --git a/src/worm.c b/src/worm.c index 479c9d75e..86f1aef4c 100644 --- a/src/worm.c +++ b/src/worm.c @@ -988,4 +988,15 @@ flip_worm_segs_horizontal(struct monst *worm, int minx, int maxx) } } +void +redraw_worm(struct monst *worm) +{ + struct wseg *curr = wtails[worm->wormno]; + + while (curr) { + newsym(curr->wx, curr->wy); + curr = curr->nseg; + } +} + /*worm.c*/ From b89e7928735726538ff6cd7ab152a23235c1caee Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 30 Nov 2024 19:06:05 -0500 Subject: [PATCH 116/791] Some Windows gcc fixes --- include/windconf.h | 7 ++++--- sound/windsound/windsound.c | 25 +++++++++++++------------ sys/windows/Makefile.mingw32 | 14 +++++++++----- sys/windows/windmain.c | 20 +++++++++++++++----- win/win32/mhmain.c | 3 ++- win/win32/mhmenu.c | 8 +++++--- win/win32/mswproc.c | 5 +++-- win/win32/winMS.h | 2 ++ 8 files changed, 53 insertions(+), 31 deletions(-) diff --git a/include/windconf.h b/include/windconf.h index ebfac1e8b..1b5b45d92 100644 --- a/include/windconf.h +++ b/include/windconf.h @@ -98,7 +98,7 @@ extern char *windows_exepath(void); *=============================================== */ -#ifdef __MINGW32__ +#ifdef __GNUC__ #define MD_USE_TMPFILE_S # #ifdef strncasecmp @@ -110,10 +110,11 @@ extern char *windows_exepath(void); #ifdef __USE_MINGW_ANSI_STDIO #undef __USE_MINGW_ANSI_STDIO #endif -#define __USE_MINGW_ANSI_STDIO 1 +/* with UCRT, we don't define this to 1 */ +#define __USE_MINGW_ANSI_STDIO 0 #endif /* extern int getlock(void); */ -#endif /* __MINGW32__ */ +#endif /* __GNUC__ */ #ifdef _MSC_VER #define MD_USE_TMPFILE_S diff --git a/sound/windsound/windsound.c b/sound/windsound/windsound.c index 8ccfe9f65..0dc486f18 100644 --- a/sound/windsound/windsound.c +++ b/sound/windsound/windsound.c @@ -55,14 +55,13 @@ windsound_init_nhsound(void) } static void -windsound_exit_nhsound(const char *reason) +windsound_exit_nhsound(const char *reason UNUSED) { } static void -windsound_achievement(schar ach1, schar ach2, int32_t repeat) +windsound_achievement(schar ach1, schar ach2, int32_t repeat UNUSED) { - int reslt = 0; const char *filename; char resourcename[120], buf[PATHLEN]; int findsound_approach = sff_base_only; @@ -108,27 +107,27 @@ windsound_achievement(schar ach1, schar ach2, int32_t repeat) filename = base_soundname_to_filename(resourcename, buf, sizeof buf, findsound_approach); if (filename) { - reslt = PlaySound(filename, NULL, fdwsound); + (void) PlaySound(filename, NULL, fdwsound); } } static void -windsound_ambience(int32_t ambienceid, int32_t ambience_action, - int32_t hero_proximity) +windsound_ambience(int32_t ambienceid UNUSED, int32_t ambience_action UNUSED, + int32_t hero_proximity UNUSED) { } static void -windsound_verbal(char *text, int32_t gender, int32_t tone, - int32_t vol, int32_t moreinfo) +windsound_verbal(char *text UNUSED, int32_t gender UNUSED, int32_t tone UNUSED, + int32_t vol UNUSED, int32_t moreinfo UNUSED) { } static void -windsound_soundeffect(char *desc, int32_t seid, int32_t volume) +windsound_soundeffect(char *desc UNUSED, int32_t seid, int32_t volume UNUSED) { #ifdef SND_SOUNDEFFECTS_AUTOMAP - int reslt = 0; +/* int reslt = 0; */ int32_t findsound_approach = sff_base_only; char buf[PATHLEN]; const char *filename; @@ -147,7 +146,7 @@ windsound_soundeffect(char *desc, int32_t seid, int32_t volume) } if (filename) { - reslt = PlaySound(filename, NULL, fdwsound); + (void) PlaySound(filename, NULL, fdwsound); } #endif } @@ -155,7 +154,7 @@ windsound_soundeffect(char *desc, int32_t seid, int32_t volume) #define WAVEMUSIC_SOUNDS static void -windsound_hero_playnotes(int32_t instrument, const char *str, int32_t volume) +windsound_hero_playnotes(int32_t instrument, const char *str, int32_t volume UNUSED) { #ifdef WAVEMUSIC_SOUNDS int reslt = 0; @@ -239,6 +238,8 @@ windsound_hero_playnotes(int32_t instrument, const char *str, int32_t volume) /* the final, or only, one is played ASYNC */ maybe_preinsert_directory(findsound_approach, exedir, buf, sizeof buf); reslt = PlaySound(buf, NULL, fdwsound); + nhUse(filename); + nhUse(reslt); #endif } diff --git a/sys/windows/Makefile.mingw32 b/sys/windows/Makefile.mingw32 index 2ac83fa5b..809b822bd 100644 --- a/sys/windows/Makefile.mingw32 +++ b/sys/windows/Makefile.mingw32 @@ -334,15 +334,19 @@ else DLBFLG = endif + ifeq "$(GCC_EXTRA_WARNINGS)" "Y" # # These match the warnings enabled on the linux.370 and macOS.370 hints builds # -CFLAGSXTRA = -Wall -Wextra -Wno-missing-field-initializers -Wreturn-type \ - -Wunused -Wformat -Wswitch -Wshadow -Wwrite-strings -pedantic \ - -Wmissing-declarations -Wformat-nonliteral -Wunreachable-code \ - -Wimplicit -Wimplicit-function-declaration -Wimplicit-int \ - -Wmissing-prototypes -Wold-style-definition -Wstrict-prototypes +CFLAGSXTRA = -Wall -Wextra -Wreturn-type -Wunused -Wformat -Wswitch -Wshadow \ + -Wwrite-strings -pedantic -Wmissing-declarations \ + -Wformat-nonliteral -Wunreachable-code -Wimplicit \ + -Wimplicit-function-declaration -Wimplicit-int \ + -Wmissing-prototypes -Wold-style-definition \ + -Wstrict-prototypes -Wnonnull -Wformat-overflow \ + -Wmissing-parameter-type -Wimplicit-fallthrough + CPPFLAGSXTRA = -Wall -Wextra -Wno-missing-field-initializers -Wreturn-type \ -Wunused -Wformat -Wswitch -Wshadow -Wwrite-strings -pedantic \ -Wmissing-declarations -Wformat-nonliteral -Wunreachable-code diff --git a/sys/windows/windmain.c b/sys/windows/windmain.c index df7e009b1..cd1bdf9bd 100644 --- a/sys/windows/windmain.c +++ b/sys/windows/windmain.c @@ -69,7 +69,7 @@ void windows_nhbell(void); int windows_nh_poskey(int *, int *, int *); void windows_raw_print(const char *); char windows_yn_function(const char *, const char *, char); -static void windows_getlin(const char *, char *); +/* static void windows_getlin(const char *, char *); */ #ifdef WIN32CON extern int windows_console_custom_nhgetch(void); @@ -116,6 +116,11 @@ void copy_sysconf_content(void); void copy_config_content(void); void copy_hack_content(void); void copy_symbols_content(void); +void copy_file(const char *, const char *, + const char *, const char *, boolean); +void update_file(const char *, const char *, + const char *, const char *, BOOL); +void windows_raw_print_bold(const char *); #ifdef PORT_HELP void port_help(void); @@ -150,6 +155,7 @@ DISABLE_WARNING_UNREACHABLE_CODE #if defined(MSWIN_GRAPHICS) #define MAIN nethackw_main +int nethackw_main(int, char **); #else #define MAIN main #endif @@ -369,7 +375,7 @@ _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);*/ (void) fname_encode( "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_-.", '%', fnamebuf, encodedfnamebuf, BUFSZ); - Sprintf(gl.lock, "%s", encodedfnamebuf); + Snprintf(gl.lock, sizeof gl.lock, "%s", encodedfnamebuf); /* regularize(lock); */ /* we encode now, rather than substitute */ if ((getlock_result = getlock()) == 0) nethack_exit(EXIT_SUCCESS); @@ -631,6 +637,7 @@ process_options(int argc, char * argv[]) } else raw_printf("\nUnknown switch: %s", argv[0]); FALLTHROUGH; + /* FALLTHRU */ case '?': nhusage(); nethack_exit(EXIT_SUCCESS); @@ -989,6 +996,7 @@ copy_symbols_content(void) copy_file(gf.fqn_prefix[SYSCONFPREFIX], SYMBOLS, gf.fqn_prefix[SYSCONFPREFIX], SYMBOLS_TEMPLATE, TRUE); } + nhUse(no_template); } void @@ -1107,10 +1115,10 @@ boolean fakeconsole(void) { if (!hStdOut) { - HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); - HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE); + HANDLE fkhStdOut = GetStdHandle(STD_OUTPUT_HANDLE); + HANDLE fkhStdIn = GetStdHandle(STD_INPUT_HANDLE); - if (!hStdOut && !hStdIn) { + if (!fkhStdOut && !fkhStdIn) { /* Bool rval; */ AllocConsole(); AttachConsole(GetCurrentProcessId()); @@ -1277,11 +1285,13 @@ windows_yn_function(const char *query UNUSED, const char *resp UNUSED, } /*ARGSUSED*/ +#if 0 static void windows_getlin(const char *prompt UNUSED, char *outbuf) { Strcpy(outbuf, "\033"); } +#endif #ifdef PC_LOCKING static int diff --git a/win/win32/mhmain.c b/win/win32/mhmain.c index 46a71b7d4..053324db8 100644 --- a/win/win32/mhmain.c +++ b/win/win32/mhmain.c @@ -1022,7 +1022,8 @@ onWMCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) pFile = _tfopen(filename, TEXT("wt+,ccs=UTF-8")); if (!pFile) { TCHAR buf[4096]; - _stprintf(buf, TEXT("Cannot open %s for writing!"), filename); + nh_stprintf(buf, sizeof buf, + TEXT("Cannot open %s for writing!"), filename); NHMessageBox(hWnd, buf, MB_OK | MB_ICONERROR); if (text) free(text); diff --git a/win/win32/mhmenu.c b/win/win32/mhmenu.c index 41442cc69..0899bc747 100644 --- a/win/win32/mhmenu.c +++ b/win/win32/mhmenu.c @@ -1188,10 +1188,12 @@ onDrawItem(HWND hWnd, WPARAM wParam, LPARAM lParam) && data->menui.menu.items[lpdis->itemID].count != 0 && item->glyphinfo.glyph != NO_GLYPH) { if (data->menui.menu.items[lpdis->itemID].count == -1) { - _stprintf(wbuf, TEXT("Count: All")); + nh_stprintf(wbuf, sizeof wbuf, + TEXT("Count: All")); } else { - _stprintf(wbuf, TEXT("Count: %d"), - data->menui.menu.items[lpdis->itemID].count); + nh_stprintf(wbuf, sizeof wbuf, + TEXT("Count: %d"), + data->menui.menu.items[lpdis->itemID].count); } /* TODO: add blinking for blink text */ diff --git a/win/win32/mswproc.c b/win/win32/mswproc.c index 42abf9a19..cf4f63a44 100644 --- a/win/win32/mswproc.c +++ b/win/win32/mswproc.c @@ -1061,8 +1061,9 @@ mswin_display_file(const char *filename, boolean must_exist) if (!f) { if (must_exist) { TCHAR message[90]; - _stprintf(message, TEXT("Warning! Could not find file: %s\n"), - NH_A2W(filename, wbuf, sizeof(wbuf))); + nh_stprintf(message, sizeof message, + TEXT("Warning! Could not find file: %s\n"), + NH_A2W(filename, wbuf, sizeof(wbuf))); NHMessageBox(GetNHApp()->hMainWnd, message, MB_OK | MB_ICONEXCLAMATION); } diff --git a/win/win32/winMS.h b/win/win32/winMS.h index 1cb26aed2..ed7e24e8f 100644 --- a/win/win32/winMS.h +++ b/win/win32/winMS.h @@ -249,12 +249,14 @@ extern COLORREF message_fg_color; /* unicode stuff */ #define NH_CODEPAGE (SYMHANDLING(H_IBM) ? GetOEMCP() : GetACP()) #ifdef _UNICODE +#define nh_stprintf swprintf #define NH_W2A(w, a, cb) \ (WideCharToMultiByte(NH_CODEPAGE, 0, (w), -1, (a), (cb), NULL, NULL), (a)) #define NH_A2W(a, w, cb) \ (MultiByteToWideChar(NH_CODEPAGE, 0, (a), -1, (w), (cb)), (w)) #else +#define nh_stprintf snprintf #define NH_W2A(w, a, cb) (strncpy((a), (w), (cb))) #define NH_A2W(a, w, cb) (strncpy((w), (a), (cb))) From cd032881ad1cabcd4cab6b7aae47ff0b287d7be3 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 30 Nov 2024 19:19:54 -0500 Subject: [PATCH 117/791] Windows pdcurses: suppress fallthrough warnings Avoid warning about issues in 3rd party code --- sys/windows/Makefile.nmake | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sys/windows/Makefile.nmake b/sys/windows/Makefile.nmake index 6ecb58bec..5da031bec 100644 --- a/sys/windows/Makefile.nmake +++ b/sys/windows/Makefile.nmake @@ -1336,19 +1336,19 @@ DLB = # !IF "$(ADD_CURSES)" == "Y" {$(PDCURSES_TOP)}.c{$(OBJPDC)}.o: - $(Q)$(CC) /wd4244 $(PDCINCL) $(CFLAGS) $(CURSESDEF2) $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) -Fo$@ $< + $(Q)$(CC) /wd4244 $(PDCINCL) $(CFLAGS) $(CURSESDEF2) /wd5262 $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) -Fo$@ $< {$(PDCSRC)}.c{$(OBJPDC)}.o: - $(Q)$(CC) /wd4244 /wd4267 /wd4774 $(PDCINCL) $(CFLAGS:-w44774= ) $(CURSESDEF2) $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) -Fo$@ $< + $(Q)$(CC) /wd4244 /wd4267 /wd4774 $(PDCINCL) $(CFLAGS:-w44774= ) $(CURSESDEF2) /wd5262 $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) -Fo$@ $< !IF "$(CURSES_CONSOLE)" == "Y" {$(PDCWINCON)}.c{$(OBJPDCC)}.o: - $(Q)$(CC) /wd4244 /wd4267 /wd4774 $(PDCINCL) $(PDCINCLCON) $(CFLAGS) $(CURSESDEF2) $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) -Fo$@ $< + $(Q)$(CC) /wd4244 /wd4267 /wd4774 $(PDCINCL) $(PDCINCLCON) $(CFLAGS) $(CURSESDEF2) /wd5262 $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) -Fo$@ $< !ENDIF !IF "$(CURSES_GRAPHICAL)" == "Y" {$(PDCWINGUI)}.c{$(OBJPDCG)}.o: - $(Q)$(CC) /wd4244 /wd4267 /wd4774 $(PDCINCL) $(PDCINCLGUI) $(CFLAGS) $(CURSESDEF2) $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) -Fo$@ $< + $(Q)$(CC) /wd4244 /wd4267 /wd4774 $(PDCINCL) $(PDCINCLGUI) $(CFLAGS) $(CURSESDEF2) /wd5262 $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) -Fo$@ $< !ENDIF !ENDIF From c2c2e84485620ff93fa945e3e612ad54f893d33f Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 30 Nov 2024 19:35:25 -0500 Subject: [PATCH 118/791] remove some tabs that snuck in unintentionally --- src/ball.c | 2 +- src/mon.c | 2 +- src/objnam.c | 2 +- src/pray.c | 6 +++--- src/questpgr.c | 4 ++-- src/uhitm.c | 4 ++-- src/wizard.c | 2 +- 7 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/ball.c b/src/ball.c index d6ba11017..ebacb7e83 100644 --- a/src/ball.c +++ b/src/ball.c @@ -743,7 +743,7 @@ drag_ball(coordxy x, coordxy y, int *bc_control, SKIP_TO_DRAG; break; } - FALLTHROUGH; + FALLTHROUGH; /* FALLTHRU */ case 1: case 0: diff --git a/src/mon.c b/src/mon.c index 69d206065..a87241014 100644 --- a/src/mon.c +++ b/src/mon.c @@ -3075,7 +3075,7 @@ mondead(struct monst *mtmp) (void) makemon(mtmp->data, stway->sx, stway->sy, NO_MM_FLAGS); break; } - FALLTHROUGH; + FALLTHROUGH; /* FALLTHRU */ case 2: /* randomly */ (void) makemon(mtmp->data, 0, 0, NO_MM_FLAGS); diff --git a/src/objnam.c b/src/objnam.c index 94315442a..14227bc5c 100644 --- a/src/objnam.c +++ b/src/objnam.c @@ -5113,7 +5113,7 @@ readobjnam(char *bp, struct obj *no_wish) for fake mail); 1: from bones or wishing; 2: written with marker */ case SCR_MAIL: d.otmp->spe = 1; - break; + break; #endif /* splash of venom: 0: normal, and transitory; 1: wishing */ case ACID_VENOM: diff --git a/src/pray.c b/src/pray.c index b77c4faae..47d853a11 100644 --- a/src/pray.c +++ b/src/pray.c @@ -404,7 +404,7 @@ fix_worst_trouble(int trouble) case TROUBLE_STARVING: /* temporarily lost strength recovery now handled by init_uhunger() */ FALLTHROUGH; - /* FALLTHRU*/ + /* FALLTHRU*/ case TROUBLE_HUNGRY: Your("%s feels content.", body_part(STOMACH)); init_uhunger(); @@ -747,8 +747,8 @@ angrygods(aligntyp resp_god) punish((struct obj *) 0); break; } - FALLTHROUGH; - /* FALLTHRU */ + FALLTHROUGH; + /* FALLTHRU */ case 4: case 5: gods_angry(resp_god); diff --git a/src/questpgr.c b/src/questpgr.c index 9f630e05a..707846e90 100644 --- a/src/questpgr.c +++ b/src/questpgr.c @@ -406,8 +406,8 @@ convert_line(char *in_line, char *out_line) cc += strlen(gc.cvt_buf); break; } - FALLTHROUGH; - /* FALLTHRU */ + FALLTHROUGH; + /* FALLTHRU */ default: *cc++ = *c; break; diff --git a/src/uhitm.c b/src/uhitm.c index 9aaa11332..6cc8af687 100644 --- a/src/uhitm.c +++ b/src/uhitm.c @@ -6020,8 +6020,8 @@ passive_obj( } break; } - FALLTHROUGH; - /* FALLTHRU */ + FALLTHROUGH; + /* FALLTHRU */ default: break; } diff --git a/src/wizard.c b/src/wizard.c index 8db22f060..ce064615c 100644 --- a/src/wizard.c +++ b/src/wizard.c @@ -285,7 +285,7 @@ strategy(struct monst *mtmp) if (mtmp->data != &mons[PM_WIZARD_OF_YENDOR]) return (unsigned long) STRAT_HEAL; FALLTHROUGH; - /* FALLTHRU */ + /* FALLTHRU */ case 2: dstrat = STRAT_HEAL; break; From 079da0fcba6788cb35fb77ddd97eb7cf0d14a13e Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 30 Nov 2024 19:38:44 -0500 Subject: [PATCH 119/791] update Files --- Files | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/Files b/Files index 16bcaecf4..e58c876b3 100644 --- a/Files +++ b/Files @@ -12,8 +12,8 @@ Porting README azure-pipelines.yml DEVEL: (files for people developing changes to NetHack) -Developer.txt code_features.txt code_style.txt git_recipes.txt -gitinfo.pl nhgitset.pl +Developer.txt VERSION code_features.txt code_style.txt +git_recipes.txt gitinfo.pl nhgitset.pl DEVEL/DOTGIT: (file for people developing changes to NetHack) @@ -23,11 +23,11 @@ DEVEL/hooksdir: (files for people developing changes to NetHack) NHadd NHgithook.pm NHsubst NHtext TARGET applypatch-msg -commit-msg nhsub post-applypatch -post-checkout post-commit post-merge -post-rewrite pre-applypatch pre-auto-gc -pre-commit pre-push pre-rebase -prepare-commit-msg +commit-msg nhhelp nhsub +post-applypatch post-checkout post-commit +post-merge post-rewrite pre-applypatch +pre-auto-gc pre-commit pre-push +pre-rebase prepare-commit-msg dat: (files for all versions) @@ -93,15 +93,15 @@ dlb.h dungeon.h engrave.h extern.h flag.h fnamesiz.h func_tab.h global.h hack.h hacklib.h integer.h isaac64.h lint.h mail.h mextra.h mfndpos.h micro.h mkroom.h monattk.h mondata.h -monflag.h monst.h monsters.h nhmd4.h obj.h -objclass.h objects.h optlist.h patchlevel.h pcconf.h -permonst.h prop.h quest.h rect.h region.h -rm.h seffects.h selvar.h skills.h sndprocs.h -sp_lev.h spell.h stairs.h sym.h sys.h -tcap.h tileset.h timeout.h tradstdc.h trap.h -unixconf.h vision.h vmsconf.h warnings.h winami.h -wincurs.h windconf.h winprocs.h wintype.h you.h -youprop.h +monflag.h monst.h monsters.h nhmd4.h nhregex.h +obj.h objclass.h objects.h optlist.h patchlevel.h +pcconf.h permonst.h prop.h quest.h rect.h +region.h rm.h seffects.h selvar.h skills.h +sndprocs.h sp_lev.h spell.h stairs.h sym.h +sys.h tcap.h tileset.h timeout.h tradstdc.h +trap.h unixconf.h vision.h vmsconf.h warnings.h +winami.h wincurs.h windconf.h winprocs.h wintype.h +you.h youprop.h (file for tty versions) wintty.h @@ -532,6 +532,10 @@ sys/windows/vs/hacklib: (file for Visual Studio 2019 or 2022 Community Edition builds) hacklib.vcxproj +sys/windows/vs/lualib: +(file for Visual Studio 2019 or 2022 Community Edition builds) +lualib.vcxproj + sys/windows/vs/makedefs: (files for Visual Studio 2019 or 2022 Community Edition builds) aftermakedefs.proj makedefs.vcxproj From 211178d0843393f80249a245005532184411e661 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 30 Nov 2024 21:06:16 -0500 Subject: [PATCH 120/791] fixes3-7-0.txt entry: WASM pull request 1331 The pull request was: https://github.com/NetHack/NetHack/pull/1331 by @guillaumebrunerie The text by @guillaumebrunerie that accompanied the pull request was: I have been working on a browser/mobile port of NetHack 3.7 using cross-compilation to WebAssembly (it is very playable already, you can try it at https://guillaumebrunerie.github.io/nethack/). [screen shot] The existing code for compiling to WebAssembly was a great help, although it wasn't fully up to date and was missing a number of things in order to be able to create a proper window port (for instance there was no way to set 'iflags.window_inited' to true, 'print_glyph' was not working properly as its signature changed, and various other things). This pull request contains various fixes and additions that I found were needed/helpful. Changes: * export more constants/pointers/globals. * fix various types that are incorrect. * disable compression of save files, as it uses fork which isn't supported in WebAssembly. * include 'genl_player_setup' when 'SHIM_GRAPHICS' is defined, in order to make it possible to reuse the existing player selection code. * move initialization of JavaScript global constants up, as I was running in some issue when 'raw_print' was being called before initialization. * change various compilation options for Emscripten, in particular it now generates an ES6 module (easier to use in a modern Javascript project) and exports more methods from Emscripten (for instance to be able to use the virtual file system when saving). * simplify the implementation of the main loop to avoid 'setTimeout' which can be pretty slow in the browser when called many times. * change the way pointer arguments are being sent to JavaScript in 'getArg' (they were being sent as a pointer to the pointer itself on the stack, which doesn't really make sense, now the pointer itself is sent). --- doc/fixes3-7-0.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index 0538b7750..1a60a914a 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -2922,6 +2922,8 @@ split "cannot_push" on moverock_done() into a separate function (pr #1282 by argrath) split making pits on do_earthquake() into a separate function and eliminate some gotos on do_earthquake() (pr #1287 by argrath) +update the WASM cross-compile to work with the current + code (pr #1331 by guillaumebrunerie) Code Cleanup and Reorganization From 763ed61af7faeed347322fd7e9e94ac6ee4a2f41 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 30 Nov 2024 22:07:18 -0500 Subject: [PATCH 121/791] a pair of analyzer bits --- sys/windows/consoletty.c | 2 +- win/curses/cursmesg.c | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/sys/windows/consoletty.c b/sys/windows/consoletty.c index 30fe4cff7..772079deb 100644 --- a/sys/windows/consoletty.c +++ b/sys/windows/consoletty.c @@ -98,7 +98,7 @@ cell_t undefined_cell = { CONSOLE_UNDEFINED_CHARACTER, CONSOLE_UNDEFINED_ATTRIBUTE }; #else /* VIRTUAL_TERMINAL_SEQUENCES */ cell_t clear_cell = { { CONSOLE_CLEAR_CHARACTER, 0, 0, 0, 0, 0, 0 }, - CONSOLE_CLEAR_CHARACTER, 0, 0L, 0, "\x1b[0m" }; + CONSOLE_CLEAR_CHARACTER, 0, 0L, 0, "\x1b[0m", 0 }; cell_t undefined_cell = { { CONSOLE_UNDEFINED_CHARACTER, 0, 0, 0, 0, 0, 0 }, CONSOLE_UNDEFINED_CHARACTER, 0, 0L, 0, (const char *) 0 }; static const uint8 empty_utf8str[MAX_UTF8_SEQUENCE] = { 0 }; diff --git a/win/curses/cursmesg.c b/win/curses/cursmesg.c index 894a33721..c041ecde7 100644 --- a/win/curses/cursmesg.c +++ b/win/curses/cursmesg.c @@ -1069,11 +1069,12 @@ curses_putmsghistory(const char *msg, boolean restoring_msghist) however, we aren't only called when restoring history; core uses putmsghistory() for other stuff during play and those messages should have a normal turn value */ - if (last_mesg) /* appease static analyzer */ + if (last_mesg) { /* appease static analyzer */ last_mesg->turn = restoring_msghist ? (1L << 3) : gh.hero_seq; #ifdef DUMPLOG_CORE - dumplogmsg(last_mesg->str); + dumplogmsg(last_mesg->str); #endif + } } else if (stash_count) { nhprev_mesg *mesg; long mesg_turn; From c81af23c8c59e5a8d8d465ad44c57a03aab31182 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 1 Dec 2024 09:10:33 -0500 Subject: [PATCH 122/791] place MIPS cross-compile game in targets subfolder --- sys/unix/hints/include/cross-pre2.370 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sys/unix/hints/include/cross-pre2.370 b/sys/unix/hints/include/cross-pre2.370 index 24f3a4d17..5d2f415a4 100644 --- a/sys/unix/hints/include/cross-pre2.370 +++ b/sys/unix/hints/include/cross-pre2.370 @@ -359,6 +359,7 @@ CFLAGS += -DCROSSCOMPILE override TARGET_CC = mipsel-linux-gnu-gcc override TARGET_CXX = CXX=mipsel-linux-gnu-g++ override TARGET_AR = mipsel-linux-gnu-ar +MIPS_TARGET = $(TARGETPFX)nethack #override TARGET_LINK = mipsel-linux-gnu-ld MIPS_TARGET_CFLAGS = -c -O -I../include -I../sys/unix -I../win/share \ $(LUAINCL) -DDLB \ @@ -390,7 +391,7 @@ override WINLIB = $(NCURSESLIB) override LUALIB= override LUALIBS= override TOPLUALIB= -#override GAMEBIN= +override GAMEBIN=$(MIPS_TARGET) #override PACKAGE= override PREGAME += mkdir -p $(TARGETDIR) ; override CLEANMORE += rm -f -r $(TARGETDIR) ; From dda5d03d916cd7863003a2fb731b5e4fe925b09e Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 1 Dec 2024 09:13:21 -0500 Subject: [PATCH 123/791] update Cross-compiling documentation 2024-12-01 --- Cross-compiling | 45 ++++++++++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/Cross-compiling b/Cross-compiling index a1d294555..6a03fe8bf 100644 --- a/Cross-compiling +++ b/Cross-compiling @@ -361,41 +361,44 @@ Using the cross-compiler, build the following targets: cross-compile and link with these compiler switches: -DCROSSCOMPILE and -DCROSSCOMPILE_TARGET - core sources (2019): src/allmain.c, src/alloc.c, src/apply.c, + core sources (2024): src/allmain.c, src/alloc.c, src/apply.c, src/artifact.c, src/attrib.c, src/ball.c, - src/bones.c, src/botl.c, src/cmd.c, src/dbridge.c, + src/bones.c, src/botl.c, src/calendar.c, + src/coloratt.c, src/cmd.c, src/dbridge.c, src/decl.c, src/detect.c, src/dig.c, src/display.c, src/dlb.c, src/do.c, src/do_name.c, src/do_wear.c, src/dog.c, src/dogmove.c, src/dokick.c, src/dothrow.c, src/drawing.c, src/dungeon.c, src/eat.c, src/end.c, src/engrave.c, src/exper.c, src/explode.c, src/extralev.c, src/files.c, - src/fountain.c, src/hack.c, src/hacklib.c, - src/insight.c, src/invent.c, src/isaac64.c, - src/light.c, src/lock.c, src/mail.c, - src/makemon.c, src/mcastu.c, + src/fountain.c, src/getpos.c, src/glyphs.c, + src/hack.c, src/hacklib.c, src/insight.c, + src/invent.c, src/isaac64.c, src/light.c, + src/lock.c, src/mail.c, src/makemon.c, src/mcastu.c, src/mdlib.c, src/mhitm.c, src/mhitu.c, src/minion.c, src/mklev.c, src/mkmap.c, src/mkmaze.c, src/mkobj.c, src/mkroom.c, src/mon.c, src/mondata.c, src/monmove.c, src/monst.c, src/mplayer.c, src/mthrowu.c, src/muse.c, src/music.c, - src/nhlsel.c, src/nhlua.c, src/nhlobj.c, - src/o_init.c, src/objects.c, src/objnam.c, - src/options.c, src/pager.c, src/pickup.c, - src/pline.c, src/polyself.c, src/potion.c, - src/pray.c, src/priest.c, src/quest.c, + src/nhlua.c, src/nhlsel.c, src/nhlobj.c, + src/nhmd4.c, src/objects.c, src/o_init.c, + src/objnam.c, src/options.c, src/pager.c, + src/pickup.c, src/pline.c, src/polyself.c, + src/potion.c, src/pray.c, src/priest.c, src/quest.c, src/questpgr.c, src/read.c, src/rect.c, - src/region.c, src/restore.c, src/rip.c, src/rnd.c, - src/role.c, src/rumors.c, src/save.c, src/sfstruct.c, - src/shk.c, src/shknam.c, src/sit.c, src/sounds.c, - src/sp_lev.c, src/spell.c, src/steal.c, src/steed.c, + src/region.c, src/report.c, src/restore.c,src/rip.c, + src/rnd.c, src/role.c, src/rumors.c, src/save.c, + src/selvar.c, src/sfstruct.c, src/shk.c, + src/shknam.c, src/sit.c, src/sounds.c, src/sp_lev.c, + src/spell.c, src/stairs.c, src/steal.c, src/steed.c, src/symbols.c, src/sys.c, src/teleport.c, src/timeout.c, src/topten.c, src/track.c, - src/trap.c, src/u_init.c, src/uhitm.c, src/vault.c, - src/version.c, src/vision.c, - src/weapon.c, src/were.c, src/wield.c, src/windows.c, - src/wizard.c, src/worm.c, src/worn.c, src/write.c, - src/zap.c, sys/share/cppregex.cpp + src/trap.c, src/u_init.c, src/uhitm.c, + src/utf8map.c, src/vault.c, src/version.c, + src/vision.c, src/weapon.c, src/were.c, src/wield.c, + src/windows.c, src/wizard.c, src/wizcmds.c, + src/worm.c, src/worn.c, src/write.c, src/zap.c, + sys/share/cppregex.cpp tty sources: win/tty/getline.c, win/tty/termcap.c, win/tty/topl.c, win/tty/wintty.c @@ -695,7 +698,7 @@ Cross-compiler url: https://emscripten.org/docs/getting_started/downloads.html +--------------------------------+ - | B7. Case sample: mips | + | B7. Case sample: mips | +--------------------------------+ Cross-compiler used: gcc-mipsel-linux-gnu, g++-mipsel-linux-gnu From 8b08244c9bb8fc93f539ed5e3e1f7592b7a79a54 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 1 Dec 2024 13:24:30 -0500 Subject: [PATCH 124/791] Cross-compile build fixes recover was not being built correctly under cross compilation --- sys/unix/Makefile.top | 4 ++- sys/unix/Makefile.utl | 12 +++---- sys/unix/hints/include/cross-post.370 | 48 +++++++++++++++++++++++---- sys/unix/hints/include/cross-pre2.370 | 6 ++-- 4 files changed, 53 insertions(+), 17 deletions(-) diff --git a/sys/unix/Makefile.top b/sys/unix/Makefile.top index c7bb4b524..45cd7330a 100644 --- a/sys/unix/Makefile.top +++ b/sys/unix/Makefile.top @@ -118,6 +118,8 @@ DAT = $(DATNODLB) $(DATDLB) # $(CHGRP) $(GAMEGRP) $(INSTDIR)/sysconf && \ # chmod $(VARFILEPERM) $(INSTDIR)/sysconf; fi ); +RECOVERBIN = recover + # Lua LUAHEADERS = lib/lua-$(LUA_VERSION)/src LUATESTTARGET = $(LUAHEADERS)/lua.h @@ -283,7 +285,7 @@ package: $(GAME) recover $(VARDAT) spec_levs # recover can be used when INSURANCE is defined in include/config.h # and the checkpoint option is true recover: $(GAME) - ( cd util ; $(MAKE) recover ) + ( cd util ; $(MAKE) $(RECOVERBIN) ) dofiles: target=`sed -n \ diff --git a/sys/unix/Makefile.utl b/sys/unix/Makefile.utl index 2555449b0..ebe974cc1 100644 --- a/sys/unix/Makefile.utl +++ b/sys/unix/Makefile.utl @@ -200,7 +200,7 @@ HACKLIBOBJ = $(OBJDIR)/hacklib.o panic.o MAKEOBJS = makedefs.o $(OMONOBJ) $(ODATE) $(OALLOC) # object files for recovery utility -RECOVOBJS = $(TARGETPFX)recover.o +RECOVOBJS = recover.o # object files for the data librarian DLBOBJS = dlb_main.o $(OBJDIR)/dlb.o $(OALLOC) @@ -277,12 +277,12 @@ lintdgn: # dependencies for recover # -$(TARGETPFX)recover: $(RECOVOBJS) $(TARGETPFX)$(HACKLIB) - $(TARGET_CLINK) $(TARGET_LFLAGS) -o recover \ - $(RECOVOBJS) $(TARGETPFX)$(HACKLIB) $(LIBS) +recover: $(RECOVOBJS) $(HACKLIB) + $(CLINK) $(LFLAGS) -o recover \ + $(RECOVOBJS) $(HACKLIB) $(LIBS) -$(TARGETPFX)recover.o: recover.c $(CONFIG_H) - $(TARGET_CC) $(TARGET_CFLAGS) $(CSTD) -c recover.c -o $@ +recover.o: recover.c $(CONFIG_H) + $(CC) $(CFLAGS) $(CSTD) -c recover.c -o $@ # dependencies for dlb diff --git a/sys/unix/hints/include/cross-post.370 b/sys/unix/hints/include/cross-post.370 index 8bbf00a5e..a509aae6f 100644 --- a/sys/unix/hints/include/cross-post.370 +++ b/sys/unix/hints/include/cross-post.370 @@ -42,7 +42,7 @@ $(DOSFONT)/ter-u28b.psf: $(FONTTOP)/ter-u28b.bdf $(DOSFONT)/nh-u28b.bdf $(DOSFON $(DOSFONT)/ter-u32b.psf: $(FONTTOP)/ter-u32b.bdf $(DOSFONT)/nh-u32b.bdf $(DOSFONT)/makefont.lua $(LUABIN) $(LUABIN) $(DOSFONT)/makefont.lua $(FONTTOP)/ter-u32b.bdf $(DOSFONT)/nh-u32b.bdf $@ # -.PHONY: dodata dospkg dosfonts recover +.PHONY: dodata dospkg dosfonts dosfonts: $(FONTTARGETS) dospkg: dodata dosfonts $(GAMEBIN) $(TARGETPFX)recover.exe ../dat/nhtiles.bmp $(TARGET_STUBEDIT) $(GAMEBIN) minstack=2048K @@ -107,12 +107,17 @@ $(TARGETPFX)unixtty.o : ../sys/share/unixtty.c $(HACK_H) $(TARGETPFX)winshim.o : ../win/shim/winshim.c $(HACK_H) $(TARGETPFX)libnhmain.o : ../sys/libnh/libnhmain.c $(HACK_H) endif # CROSS_TO_WASM + # ifdef CROSS_TO_MIPS -$(MIPS_TARGET): pregame $(TARGETPFX)date.o $(HOSTOBJ) $(HOBJ) $(LUACROSSLIB) $(MIPS_DATA_DIR) +$(MIPS_TARGET): pregame $(TARGETPFX)date.o $(HOSTOBJ) $(HOBJ) $(LUACROSSLIB) \ + $(TARGETPFX)ncurses/lib/libncurses.a \ + $(MIPS_DATA_DIR) -rm $@ - $(TARGET_CC) $(TARGET_LFLAGS) $(TARGET_CFLAGS) -o $@ \ - $(HOBJ) $(TARGETPFX)date.o $(TARGET_LIBS) + $(TARGET_LINK) $(TARGET_LFLAGS) -o $@ \ + $(HOBJ) $(TARGETPFX)date.o $(TARGETPFX)$(HACKLIB) \ + $(TARGETPFX)ncurses/lib/libncurses.a \ + $(TARGET_LIBS) $(MIPS_DATA_DIR): $(MIPS_DATA_DIR)/nhdat touch $(MIPS_DATA_DIR)/perm @@ -131,9 +136,28 @@ $(TARGETPFX)unixres.o : ../sys/unix/unixres.c $(HACK_H) $(TARGETPFX)unixunix.o : ../sys/unix/unixunix.c $(HACK_H) $(TARGETPFX)ioctl.o : ../sys/share/ioctl.c $(HACK_H) $(TARGETPFX)unixtty.o : ../sys/share/unixtty.c $(HACK_H) -endif # CROSS_TO_MIPS -# +$(LUABIN): + ( cd .. && make luabin && cd src) +dodata: + ( cd .. && make dlb && cd src) + +mipsrecover: $(TARGETPFX)recover +.PHONY: mipspkg +mipspkg: dodata $(GAMEBIN) $(TARGETPFX)recover + mkdir -p $(TARGETPFX)pkg + cp $(GAMEBIN) $(TARGETPFX)pkg/nethack + cp $(TARGETPFX)recover $(TARGETPFX)pkg/recover + cp ../dat/nhdat $(TARGETPFX)pkg/nhdat + cp ../dat/license $(TARGETPFX)pkg/license + cp ../dat/symbols $(TARGETPFX)pkg/symbols + cp ../sys/share/NetHack.cnf $(TARGETPFX)pkg/.nethackrc + cp ../sys/msdos/sysconf $(TARGETPFX)pkg/sysconf + cp ../doc/nethack.txt $(TARGETPFX)pkg/nethack.txt + -touch $(TARGETPFX)pkg/record + cd $(TARGETPFX)pkg ; zip -9 ../nh370mips.zip * ; cd ../../.. + @echo MIPS package zip file $(TARGETPFX)nh370mips.zip +endif # CROSS_TO_MIPS ifdef CROSS_SHARED # shared file dependencies @@ -144,16 +168,26 @@ $(TARGETPFX)pcunix.o : ../sys/share/pcunix.c $(HACK_H) $(TARGETPFX)tileset.o : ../win/share/tileset.c $(TARGETPFX)bmptiles.o : ../win/share/bmptiles.c $(TARGETPFX)giftiles.o : ../win/share/giftiles.c -$(TARGETPFX)recover.o : ../util/recover.c endif # CROSS_SHARED # ifdef CROSS $(TARGETPFX)hacklib.a: $(TARGETPFX)hacklib.o $(TARGET_AR) $(TARGET_ARFLAGS) $@ $(TARGETPFX)hacklib.o +ifdef MAKEFILE_UTL +$(TARGETPFX)recover.o: recover.c $(CONFIG_H) + $(TARGET_CC) $(TARGET_CFLAGS) $(CSTD) -c recover.c -o $@ +ifdef CROSS_TO_MSDOS $(TARGETPFX)recover.exe : $(TARGETPFX)recover.o $(TARGETPFX)hacklib.a $(TARGET_LINK) $(TARGET_LFLAGS) \ $(TARGETPFX)recover.o $(TARGETPFX)hacklib.a -o $@ +else +$(TARGETPFX)recover : $(TARGETPFX)recover.o $(TARGETPFX)hacklib.a + $(TARGET_LINK) $(TARGET_LFLAGS) \ + $(TARGETPFX)recover.o $(TARGETPFX)hacklib.a -o $@ endif +endif # MAKEFILE_UTL +endif # CROSS + ifdef BUILD_TARGET_LUA # Lua lib $(LUACROSSLIB): $(LUALIBOBJS) diff --git a/sys/unix/hints/include/cross-pre2.370 b/sys/unix/hints/include/cross-pre2.370 index 5d2f415a4..bc38efa62 100644 --- a/sys/unix/hints/include/cross-pre2.370 +++ b/sys/unix/hints/include/cross-pre2.370 @@ -84,8 +84,6 @@ PDCOBJS = $(TARGETPFX)pdcclip.o $(TARGETPFX)pdcdisp.o \ $(TARGETPFX)pdcscrn.o $(TARGETPFX)pdcsetsc.o \ $(TARGETPFX)pdcutil.o override TARGET_LIBS += $(PDCLIB) -ifdef CROSS_TO_MSDOS -endif override BUILDMORE += $(PDCLIB) override CLEANMORE += rm -f $(PDCLIB) ; else #WANT_WIN_CURSES @@ -193,6 +191,7 @@ override LUALIB= override LUALIBS= override TOPLUALIB= override GAMEBIN = $(TARGETPFX)nethack.exe +override RECOVERBIN = $(TARGETPFX)recover.exe override PACKAGE = dospkg override PREGAME += mkdir -p $(TARGETDIR) ; make $(TARGETPFX)exceptn.o ; override CLEANMORE += rm -f -r $(TARGETDIR) ; rm -f -r $(FONTTARGETS) ; @@ -392,7 +391,8 @@ override LUALIB= override LUALIBS= override TOPLUALIB= override GAMEBIN=$(MIPS_TARGET) -#override PACKAGE= +override RECOVERBIN = $(TARGETPFX)recover +override PACKAGE = mipspkg override PREGAME += mkdir -p $(TARGETDIR) ; override CLEANMORE += rm -f -r $(TARGETDIR) ; # Rule for file in sys/unix From 9777e7785ad2a70f0fe2c5de43d43b0e7608c135 Mon Sep 17 00:00:00 2001 From: Keni Date: Sun, 1 Dec 2024 11:25:16 -0800 Subject: [PATCH 125/791] rename local ctxp -> contextp to avoid global ctxp --- sys/windows/windsys.c | 86 +++++++++++++++++++++---------------------- 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/sys/windows/windsys.c b/sys/windows/windsys.c index 7888e4385..5f1a2a5ab 100644 --- a/sys/windows/windsys.c +++ b/sys/windows/windsys.c @@ -799,7 +799,7 @@ struct CRctxt *ctxp = &ctxp_; // XXX should this now be in gc.* ? #define win32err(fn) errname = fn; goto error int -win32_cr_helper(char cmd, struct CRctxt *ctxp, void *p, int d){ +win32_cr_helper(char cmd, struct CRctxt *contextp, void *p, int d){ char *errname = "unknown"; switch (cmd) { default: @@ -815,77 +815,77 @@ win32_cr_helper(char cmd, struct CRctxt *ctxp, void *p, int d){ return MessageBoxW(NULL, lbidstr, L"bidshow", MB_SETFOREGROUND); } break; - case 'i': /* HASH_INIT(ctxp) */ + case 'i': /* HASH_INIT(contextp) */ if (!IsWindowsVistaOrGreater()) return 1; // CNG not available. - ctxp->bah = NULL; - ctxp->bhh = NULL; - ctxp->pbhashobj = NULL; - ctxp->cbhashobj = 0; - ctxp->cbhash = 0; - ctxp->cbdata = 0; - ctxp->pbhash = NULL; - ctxp->st = 0; + contextp->bah = NULL; + contextp->bhh = NULL; + contextp->pbhashobj = NULL; + contextp->cbhashobj = 0; + contextp->cbhash = 0; + contextp->cbdata = 0; + contextp->pbhash = NULL; + contextp->st = 0; // win32err("test"); // TESTING - FAKE AN ERROR - if (0 > (ctxp->st = BCryptOpenAlgorithmProvider( - &ctxp->bah, BCRYPT_MD4_ALGORITHM, NULL, 0))) { + if (0 > (contextp->st = BCryptOpenAlgorithmProvider( + &contextp->bah, BCRYPT_MD4_ALGORITHM, NULL, 0))) { win32err("BCryptOpenAlgorithmProvider"); }; - if (0 > (ctxp->st = - BCryptGetProperty(ctxp->bah, BCRYPT_OBJECT_LENGTH, - (unsigned char *) &ctxp->cbhashobj, - sizeof(DWORD), &ctxp->cbdata, 0))) { + if (0 > (contextp->st = + BCryptGetProperty(contextp->bah, BCRYPT_OBJECT_LENGTH, + (unsigned char *) &contextp->cbhashobj, + sizeof(DWORD), &contextp->cbdata, 0))) { win32err("BCryptGetProperty1"); }; if (0 - == (ctxp->pbhashobj = - HeapAlloc(GetProcessHeap(), 0, ctxp->cbhashobj))) { + == (contextp->pbhashobj = + HeapAlloc(GetProcessHeap(), 0, contextp->cbhashobj))) { win32err("HeapAlloc1"); }; - if (0 > (ctxp->st = BCryptGetProperty( - ctxp->bah, BCRYPT_HASH_LENGTH, (PBYTE) &ctxp->cbhash, - sizeof(DWORD), &ctxp->cbdata, 0))) { + if (0 > (contextp->st = BCryptGetProperty( + contextp->bah, BCRYPT_HASH_LENGTH, (PBYTE) &contextp->cbhash, + sizeof(DWORD), &contextp->cbdata, 0))) { win32err("BCryptGetProperty2"); } if (0 - == (ctxp->pbhash = - HeapAlloc(GetProcessHeap(), 0, ctxp->cbhash))) { + == (contextp->pbhash = + HeapAlloc(GetProcessHeap(), 0, contextp->cbhash))) { win32err("HeapAlloc2\n"); } - if (0 > BCryptCreateHash(ctxp->bah, &ctxp->bhh, ctxp->pbhashobj, - ctxp->cbhashobj, NULL, 0, 0)) { + if (0 > BCryptCreateHash(contextp->bah, &contextp->bhh, contextp->pbhashobj, + contextp->cbhashobj, NULL, 0, 0)) { win32err("BCryptCreateHash"); } break; - case 'u': /* HASH_UPDATE(ctxp, ptr, len) */ - if (0 > (ctxp->st = BCryptHashData(ctxp->bhh, p, d, 0))) { + case 'u': /* HASH_UPDATE(contextp, ptr, len) */ + if (0 > (contextp->st = BCryptHashData(contextp->bhh, p, d, 0))) { win32err("BCryptHashData"); } break; - case 'f': /* HASH_FINISH(ctxp) */ - if (0 > BCryptFinishHash(ctxp->bhh, ctxp->pbhash, ctxp->cbhash, 0)) { + case 'f': /* HASH_FINISH(contextp) */ + if (0 > BCryptFinishHash(contextp->bhh, contextp->pbhash, contextp->cbhash, 0)) { win32err("BCryptFinishHash"); } break; - case 'c': /* HASH_CLEANUP(ctxp) */ - if (ctxp->bah) { - BCryptCloseAlgorithmProvider(ctxp->bah, 0); + case 'c': /* HASH_CLEANUP(contextp) */ + if (contextp->bah) { + BCryptCloseAlgorithmProvider(contextp->bah, 0); } - if (ctxp->bhh) { - BCryptDestroyHash(ctxp->bhh); + if (contextp->bhh) { + BCryptDestroyHash(contextp->bhh); } - if (ctxp->pbhashobj) { - HeapFree(GetProcessHeap(), 0, ctxp->pbhashobj); + if (contextp->pbhashobj) { + HeapFree(GetProcessHeap(), 0, contextp->pbhashobj); } - if (ctxp->pbhash) { - HeapFree(GetProcessHeap(), 0, ctxp->pbhash); + if (contextp->pbhash) { + HeapFree(GetProcessHeap(), 0, contextp->pbhash); } break; - case 's': /* HASH_RESULT_SIZE(ctxp) */ - return ctxp->cbhash; - case 'r': /* HASH_RESULT(ctxp, resp) */ - *(unsigned char **)p = ctxp->pbhash; + case 's': /* HASH_RESULT_SIZE(contextp) */ + return contextp->cbhash; + case 'r': /* HASH_RESULT(contextp, resp) */ + *(unsigned char **)p = contextp->pbhash; break; case 'b': /* HASH_BINFILE(NULL,&binfile,0) */ // XXX This buffer should be allocated, not static (and freed in @@ -906,7 +906,7 @@ win32_cr_helper(char cmd, struct CRctxt *ctxp, void *p, int d){ return 0; /* ok */ error: raw_printf("WIN32 function %s failed: status=%" PRIx64 "\n", - errname, (uint64)ctxp->st); + errname, (uint64)contextp->st); return 1; /* fail */ } #undef win32err From 86679ebddb861d31713c2ecc7e9a17d1fbf4abf9 Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 2 Dec 2024 11:11:48 -0500 Subject: [PATCH 126/791] 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 127/791] 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 128/791] 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 129/791] 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 130/791] 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 131/791] 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 132/791] 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" ] + if [ "$(toolchain)" == "gcc13" ] 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" ] - 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 133/791] 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 134/791] 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 135/791] 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 136/791] 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 137/791] 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 138/791] 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 139/791] 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 140/791] 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 141/791] 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 142/791] 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 143/791] 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 144/791] 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 145/791] 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 146/791] 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 147/791] 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 148/791] 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 149/791] 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 150/791] 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 151/791] 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 */ From 863d455e1d2b36e69bd230346939bab73d418c8d Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sat, 7 Dec 2024 11:18:13 +0200 Subject: [PATCH 152/791] Tourists gain experience by using camera flash on monsters This counts as seeing the monster up close, so the tourist doesn't need to get next to the monster --- include/extern.h | 2 ++ src/allmain.c | 23 ----------------------- src/apply.c | 5 ++++- src/mon.c | 33 +++++++++++++++++++++++++++++++++ 4 files changed, 39 insertions(+), 24 deletions(-) diff --git a/include/extern.h b/include/extern.h index c7ccd2856..6aaec4e26 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1778,6 +1778,8 @@ extern void dealloc_mextra(struct monst *); extern boolean usmellmon(struct permonst *); extern void mimic_hit_msg(struct monst *, short); extern void adj_erinys(unsigned); +extern void see_monster_closeup(struct monst *) NONNULLARG1; +extern void see_nearby_monsters(void); /* ### mondata.c ### */ diff --git a/src/allmain.c b/src/allmain.c index b8de1f7a5..c10446417 100644 --- a/src/allmain.c +++ b/src/allmain.c @@ -14,7 +14,6 @@ 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); @@ -155,28 +154,6 @@ 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 diff --git a/src/apply.c b/src/apply.c index 6f1112359..c585afa7e 100644 --- a/src/apply.c +++ b/src/apply.c @@ -63,8 +63,11 @@ do_blinding_ray(struct obj *obj) (int (*) (OBJ_P, OBJ_P)) 0, &obj); obj->ox = u.ux, obj->oy = u.uy; /* flash_hits_mon() wants this */ - if (mtmp) + if (mtmp) { (void) flash_hits_mon(mtmp, obj); + if (obj->otyp == EXPENSIVE_CAMERA) + see_monster_closeup(mtmp); + } /* normally bhit() would do this but for FLASHED_LIGHT we want it to be deferred until after flash_hits_mon() */ transient_light_cleanup(); diff --git a/src/mon.c b/src/mon.c index a87241014..795d8ef0f 100644 --- a/src/mon.c +++ b/src/mon.c @@ -5805,4 +5805,37 @@ adj_erinys(unsigned abuse) pm->difficulty = min(10 + (u.ualign.abuse / 3), 25); } +/* mark monster type as seen from close-up */ +void +see_monster_closeup(struct monst *mtmp) +{ + if (!svm.mvitals[monsndx(mtmp->data)].seen_close) { + svm.mvitals[monsndx(mtmp->data)].seen_close = TRUE; + if (Role_if(PM_TOURIST)) { + more_experienced(experience(mtmp, 0), 0); + newexplevel(); + } + } +} + +/* mark a monster type as seen clse-up when we see it next to us */ +void +see_nearby_monsters(void) +{ + coordxy x, y; + + /* currently used only for tourists ... */ + 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)) + see_monster_closeup(mtmp); + } +} + /*mon.c*/ From 9d68d171fb76c49cc9423acfe2e1bace0df0e4c3 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sat, 7 Dec 2024 11:37:15 +0200 Subject: [PATCH 153/791] Typofix --- src/mon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mon.c b/src/mon.c index 795d8ef0f..4767920d7 100644 --- a/src/mon.c +++ b/src/mon.c @@ -5818,7 +5818,7 @@ see_monster_closeup(struct monst *mtmp) } } -/* mark a monster type as seen clse-up when we see it next to us */ +/* mark a monster type as seen close-up when we see it next to us */ void see_nearby_monsters(void) { From a3f0b54aea1670cfd6cf51b39837c65696570e71 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sat, 7 Dec 2024 12:50:52 +0200 Subject: [PATCH 154/791] Healers gain experience by healing pets --- doc/fixes3-7-0.txt | 1 + src/zap.c | 18 +++++++++++++----- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index 2e56f3f83..4154520b9 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -2732,6 +2732,7 @@ enlightenment/attribute disclosure for saving-grace: include a line for have normal play, the prefix is suppressed tourists gain experience by seeing new types of creatures up close, and going to new dungeon levels +healers gain experience by healing pets Platform- and/or Interface-Specific New Features diff --git a/src/zap.c b/src/zap.c index 84cc79561..00120647a 100644 --- a/src/zap.c +++ b/src/zap.c @@ -426,11 +426,15 @@ bhitm(struct monst *mtmp, struct obj *otmp) } break; case SPE_HEALING: - case SPE_EXTRA_HEALING: + case SPE_EXTRA_HEALING: { + int healamt = d(6, otyp == SPE_EXTRA_HEALING ? 8 : 4); + reveal_invis = TRUE; if (mtmp->data != &mons[PM_PESTILENCE]) { + int delta = mtmp->mhpmax - mtmp->mhp; + wake = FALSE; /* wakeup() makes the target angry */ - mtmp->mhp += d(6, otyp == SPE_EXTRA_HEALING ? 8 : 4); + mtmp->mhp += healamt; if (mtmp->mhp > mtmp->mhpmax) mtmp->mhp = mtmp->mhpmax; /* plain healing must be blessed to cure blindness; extra @@ -451,15 +455,19 @@ bhitm(struct monst *mtmp, struct obj *otmp) pline("%s looks%s better.", Monnam(mtmp), otyp == SPE_EXTRA_HEALING ? " much" : ""); } + if (mtmp->mtame && Role_if(PM_HEALER) && (delta > 0)) { + more_experienced(min(delta, healamt), 0); + newexplevel(); + } if (mtmp->mtame || mtmp->mpeaceful) { adjalign(Role_if(PM_HEALER) ? 1 : sgn(u.ualign.type)); } } else { /* Pestilence */ - /* Pestilence will always resist; damage is half of 3d{4,8} */ - (void) resist(mtmp, otmp->oclass, - d(3, otyp == SPE_EXTRA_HEALING ? 8 : 4), TELL); + /* Pestilence will always resist; damage is half of (healamt/2) */ + (void) resist(mtmp, otmp->oclass, healamt / 2, TELL); } break; + } case WAN_LIGHT: /* (broken wand) */ if (flash_hits_mon(mtmp, otmp)) { learn_it = TRUE; From 13b8725ac2c871b0454e16d5d81dc5ab59ebb260 Mon Sep 17 00:00:00 2001 From: PatR Date: Sat, 7 Dec 2024 19:38:01 -0800 Subject: [PATCH 155/791] combine taming of already tame monsters Merge the recent change in the effect of blessed scroll of taming on already tame monsters with the earlier change of any taming on already tame monsters. Non-blessed has a chance of boosting monst->mtame by 1 when it is less than 10, more likely the lower the current value is. For blessed, boost by 2 after that, so possibly by 3 if it is very low. Make spell of charm monster when skilled or expert in enchantment spells behave the same as blessed scroll of taming. [I'm not too sure about this; it may make the spell too powerful.] --- doc/fixes3-7-0.txt | 1 - src/dog.c | 26 +++++++++++++++++++++----- src/read.c | 22 ++++++++++------------ src/spell.c | 2 +- 4 files changed, 32 insertions(+), 19 deletions(-) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index 4154520b9..78feef0e9 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -1484,7 +1484,6 @@ 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 blessed scroll of destroy armor asks which armor to destroy diff --git a/src/dog.c b/src/dog.c index 21d18d89f..607f2cdf8 100644 --- a/src/dog.c +++ b/src/dog.c @@ -1092,8 +1092,18 @@ dogfood(struct monst *mon, struct obj *obj) * on the original mtmp. It now returns TRUE if the taming succeeded. */ boolean -tamedog(struct monst *mtmp, struct obj *obj, boolean givemsg) +tamedog( + struct monst *mtmp, + struct obj *obj, /* food or scroll/spell */ + boolean givemsg) { + boolean blessed_scroll = FALSE; + + if (obj && (obj->oclass == SCROLL_CLASS || obj->oclass == SPBOOK_CLASS)) { + blessed_scroll = obj->blessed ? TRUE : FALSE; + /* the rest of this routine assumes 'obj' represents food */ + obj = (struct obj *) NULL; + } /* reduce timed sleep or paralysis, leaving mtmp->mcanmove as-is (note: if mtmp is donning armor, this will reduce its busy time) */ if (mtmp->mfrozen) @@ -1159,11 +1169,17 @@ tamedog(struct monst *mtmp, struct obj *obj, boolean givemsg) return FALSE; } - /* if already tame, taming magic might make it become tamer */ - if (mtmp->mtame) { - /* maximum tameness is 20, only reachable via eating */ - if (rnd(10) > mtmp->mtame) + /* maximum tameness is 20, only reachable via eating; if already tame but + less than 10, taming magic might make it become tamer; blessed scroll + or skilled spell raises low tameness by 2 or 3, uncursed by 0 or 1 */ + if (mtmp->mtame && mtmp->mtame < 10) { + if (mtmp->mtame < rnd(10)) mtmp->mtame++; + if (blessed_scroll) { + mtmp->mtame += 2; + if (mtmp->mtame > 10) + mtmp->mtame = 10; + } return FALSE; /* didn't just get tamed */ } /* pacify angry shopkeeper but don't tame him/her/it/them */ diff --git a/src/read.c b/src/read.c index 565ce90ea..b3c265d38 100644 --- a/src/read.c +++ b/src/read.c @@ -490,11 +490,13 @@ doread(void) pline("This %s has no label.", singular(scroll, xname)); return ECMD_OK; } else if (otyp == MAGIC_MARKER) { + static const int red_mons[] = { + PM_FIRE_ANT, PM_PYROLISK, PM_HELL_HOUND, PM_IMP, + PM_LARGE_MIMIC, PM_LEOCROTTA, PM_SCORPION, PM_XAN, + PM_GIANT_BAT, PM_WATER_MOCCASIN, PM_FLESH_GOLEM, + PM_BARBED_DEVIL, PM_MARILITH, PM_PIRANHA + }; char buf[BUFSZ]; - const int red_mons[] = { PM_FIRE_ANT, PM_PYROLISK, PM_HELL_HOUND, - PM_IMP, PM_LARGE_MIMIC, PM_LEOCROTTA, PM_SCORPION, PM_XAN, - PM_GIANT_BAT, PM_WATER_MOCCASIN, PM_FLESH_GOLEM, PM_BARBED_DEVIL, - PM_MARILITH, PM_PIRANHA }; struct permonst *pm = &mons[red_mons[scroll->o_id % SIZE(red_mons)]]; if (Blind) { @@ -1037,14 +1039,9 @@ maybe_tame(struct monst *mtmp, struct obj *sobj) /* for a shopkeeper, tamedog() will call make_happy_shk() but 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); + (void) tamedog(mtmp, sobj, FALSE); - if (mtmp->mtame < new_tame) - mtmp->mtame = new_tame; - } - if ((!was_peaceful && mtmp->mpeaceful) || (!was_tame && mtmp->mtame)) + if ((!was_peaceful && mtmp->mpeaceful) || was_tame != mtmp->mtame) return 1; } return 0; @@ -2103,7 +2100,8 @@ seffect_mail(struct obj **sobjp) /* scroll effects; return 1 if we use up the scroll and possibly make it become discovered, 0 if caller should take care of those side-effects */ int -seffects(struct obj *sobj) /* sobj - scroll or fake spellbook for spell */ +seffects( + struct obj *sobj) /* sobj - scroll or fake spellbook for spell */ { int otyp = sobj->otyp; diff --git a/src/spell.c b/src/spell.c index 3ef28cafa..3acdb3e1c 100644 --- a/src/spell.c +++ b/src/spell.c @@ -1509,12 +1509,12 @@ spelleffects(int spell_otyp, boolean atme, boolean force) case SPE_DETECT_FOOD: case SPE_CAUSE_FEAR: case SPE_IDENTIFY: + case SPE_CHARM_MONSTER: /* high skill yields effect equivalent to blessed scroll */ if (role_skill >= P_SKILLED) pseudo->blessed = 1; FALLTHROUGH; /*FALLTHRU*/ - case SPE_CHARM_MONSTER: case SPE_MAGIC_MAPPING: case SPE_CREATE_MONSTER: (void) seffects(pseudo); From 78289a7f83c7d502a82284dd0cce071c3731c402 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sun, 8 Dec 2024 16:17:35 +0200 Subject: [PATCH 156/791] Archeologists' fedora is lucky --- doc/fixes3-7-0.txt | 1 + src/do_wear.c | 6 ++++++ src/timeout.c | 3 +++ 3 files changed, 10 insertions(+) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index 78feef0e9..f9b3fe283 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 destroy armor asks which armor to destroy +archeologists' fedora is lucky Fixes to 3.7.0-x General Problems Exposed Via git Repository diff --git a/src/do_wear.c b/src/do_wear.c index 289d7d743..977b51846 100644 --- a/src/do_wear.c +++ b/src/do_wear.c @@ -420,6 +420,9 @@ Helmet_on(void) { switch (uarmh->otyp) { case FEDORA: + if (Role_if(PM_ARCHEOLOGIST)) + change_luck(1); + break; case HELMET: case DENTED_POT: case ELVEN_LEATHER_HELM: @@ -503,6 +506,9 @@ Helmet_off(void) switch (uarmh->otyp) { case FEDORA: + if (Role_if(PM_ARCHEOLOGIST)) + change_luck(-1); + break; case HELMET: case DENTED_POT: case ELVEN_LEATHER_HELM: diff --git a/src/timeout.c b/src/timeout.c index 4ec9f9c6b..443a84cc7 100644 --- a/src/timeout.c +++ b/src/timeout.c @@ -599,6 +599,9 @@ nh_timeout(void) if (svq.quest_status.killed_leader) baseluck -= 4; + if (Role_if(PM_ARCHEOLOGIST) && uarmh && uarmh->otyp == FEDORA) + baseluck += 1; + if (u.uluck != baseluck && svm.moves % ((u.uhave.amulet || u.ugangr) ? 300 : 600) == 0) { /* Cursed luckstones stop bad luck from timing out; blessed luckstones From dafd8549931ab809a191bc062e3e5e0566dcb2ed Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sun, 8 Dec 2024 17:57:59 +0200 Subject: [PATCH 157/791] Gelatinous cubes eat organic objects inside them --- doc/fixes3-7-0.txt | 1 + src/monmove.c | 30 ++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index f9b3fe283..13d11bcca 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -1486,6 +1486,7 @@ digging in ice was handled inconsistently, particularly if done at the span angry god may remove an intrinsic blessed scroll of destroy armor asks which armor to destroy archeologists' fedora is lucky +gelatinous cubes eat organic objects inside them Fixes to 3.7.0-x General Problems Exposed Via git Repository diff --git a/src/monmove.c b/src/monmove.c index f27f8bdee..61afc0d35 100644 --- a/src/monmove.c +++ b/src/monmove.c @@ -409,6 +409,32 @@ bee_eat_jelly(struct monst *mon, struct obj *obj) return -1; /* a queen is already present; ordinary bee hasn't moved yet */ } +/* gelatinous cube eats something from its inventory */ +static int +gelcube_digests(struct monst *mtmp) +{ + struct obj *otmp = mtmp->minvent; + + if (mtmp->meating || !mtmp->minvent) + return -1; + + while (otmp) { + if (is_organic(otmp) && !otmp->oartifact + && !is_mines_prize(otmp) && !is_soko_prize(otmp)) + break; + otmp = otmp->nobj; + } + + if (!otmp) + return -1; + + mtmp->meating = eaten_stat(mtmp->meating, otmp); + extract_from_minvent(mtmp, otmp, TRUE, TRUE); + m_consume_obj(mtmp, otmp); + return 0; /* used a move */ +} + + /* FIXME: gremlins don't flee from monsters wielding Sunsword or wearing gold dragon scales/mail, nor from gold dragons, only from the hero */ #define flees_light(mon) \ @@ -846,6 +872,10 @@ dochug(struct monst *mtmp) && (res = bee_eat_jelly(mtmp, otmp)) >= 0) return res; + if (mdat == &mons[PM_GELATINOUS_CUBE] + && (res = gelcube_digests(mtmp)) >= 0) + return res; + /* A monster that passes the following checks has the opportunity to move. Movement itself is handled by the m_move() function. */ if (!nearby || mtmp->mflee || scared || mtmp->mconf || mtmp->mstun From 57abae29e8721a2bdf3d280faffe7b8615d311c0 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sun, 8 Dec 2024 22:18:27 +0200 Subject: [PATCH 158/791] Don't switch away from polearm if monster in range Using 'f', if hero is wielding a polearm, and a monster is in range, don't switch away even if we do have ammo in quiver and a launcher in the inventory. --- include/extern.h | 1 + src/apply.c | 89 +++++++++++++++++++++++++++++++++--------------- src/dothrow.c | 2 ++ 3 files changed, 65 insertions(+), 27 deletions(-) diff --git a/include/extern.h b/include/extern.h index 6aaec4e26..9b596197a 100644 --- a/include/extern.h +++ b/include/extern.h @@ -126,6 +126,7 @@ extern void use_unicorn_horn(struct obj **); extern boolean tinnable(struct obj *) NONNULLPTRS; extern void reset_trapset(void); extern int use_whip(struct obj *) NONNULLPTRS; +extern boolean could_pole_mon(void); extern int use_pole(struct obj *, boolean) NONNULLPTRS; extern void fig_transform(union any *, long) NONNULLARG1; extern int unfixable_trouble_count(boolean); diff --git a/src/apply.c b/src/apply.c index c585afa7e..7e4c85c1c 100644 --- a/src/apply.c +++ b/src/apply.c @@ -32,6 +32,7 @@ staticfn int touchstone_ok(struct obj *); staticfn int use_stone(struct obj *); staticfn int set_trap(void); /* occupation callback */ staticfn void display_polearm_positions(boolean); +staticfn void calc_pole_range(int *, int *); staticfn int use_cream_pie(struct obj *); staticfn int jelly_ok(struct obj *); staticfn int use_royal_jelly(struct obj **); @@ -3341,12 +3342,71 @@ display_polearm_positions(boolean on_off) } } +/* + * Calculate allowable range (pole's reach is always 2 steps): + * unskilled and basic: orthogonal direction, 4..4; + * skilled: as basic, plus knight's jump position, 4..5; + * expert: as skilled, plus diagonal, 4..8. + * ...9... + * .85458. + * .52125. + * 9410149 + * .52125. + * .85458. + * ...9... + * (Note: no roles in NetHack can become expert or better + * for polearm skill; Yeoman in slash'em can become expert.) + */ +staticfn void +calc_pole_range(int *min_range, int *max_range) +{ + int typ = uwep_skill_type(); + + *min_range = 4; + if (typ == P_NONE || P_SKILL(typ) <= P_BASIC) + *max_range = 4; + else if (P_SKILL(typ) == P_SKILLED) + *max_range = 5; + else + *max_range = 8; /* (P_SKILL(typ) >= P_EXPERT) */ + + gp.polearm_range_min = *min_range; + gp.polearm_range_max = *max_range; + +} + +/* return TRUE if hero is wielding a polearm and there's + at least one monster they could hit with it */ +boolean +could_pole_mon(void) +{ + int min_range, max_range; + coord cc; + struct monst *hitm = svc.context.polearm.hitmon; + + if (!uwep || !is_pole(uwep)) + return FALSE; + + calc_pole_range(&min_range, &max_range); + + cc.x = u.ux; + cc.y = u.uy; + if (!find_poleable_mon(&cc, min_range, max_range)) { + if (hitm && !DEADMONSTER(hitm) && sensemon(hitm) + && mdistu(hitm) <= max_range && mdistu(hitm) >= min_range) + return TRUE; + } else { + return TRUE; + } + return FALSE; +} + /* Distance attacks by pole-weapons */ int use_pole(struct obj *obj, boolean autohit) { const char thump[] = "Thump! Your blow bounces harmlessly off the %s."; - int res = ECMD_OK, typ, max_range, min_range, glyph; + int res = ECMD_OK, max_range, min_range, glyph; coord cc; struct monst *mtmp; struct monst *hitm = svc.context.polearm.hitmon; @@ -3366,32 +3426,7 @@ use_pole(struct obj *obj, boolean autohit) } /* assert(obj == uwep); */ - /* - * Calculate allowable range (pole's reach is always 2 steps): - * unskilled and basic: orthogonal direction, 4..4; - * skilled: as basic, plus knight's jump position, 4..5; - * expert: as skilled, plus diagonal, 4..8. - * ...9... - * .85458. - * .52125. - * 9410149 - * .52125. - * .85458. - * ...9... - * (Note: no roles in NetHack can become expert or better - * for polearm skill; Yeoman in slash'em can become expert.) - */ - min_range = 4; - typ = uwep_skill_type(); - if (typ == P_NONE || P_SKILL(typ) <= P_BASIC) - max_range = 4; - else if (P_SKILL(typ) == P_SKILLED) - max_range = 5; - else - max_range = 8; /* (P_SKILL(typ) >= P_EXPERT) */ - - gp.polearm_range_min = min_range; - gp.polearm_range_max = max_range; + calc_pole_range(&min_range, &max_range); /* Prompt for a location */ if (!autohit) diff --git a/src/dothrow.c b/src/dothrow.c index 7dcf043f9..5ce3570a2 100644 --- a/src/dothrow.c +++ b/src/dothrow.c @@ -553,6 +553,8 @@ dofire(void) if (uquiver && is_ammo(uquiver) && iflags.fireassist) { struct obj *olauncher; + if (uwep && is_pole(uwep) && could_pole_mon()) + return use_pole(uwep, TRUE); /* Try to find a launcher */ if (ammo_and_launcher(uquiver, uwep)) { obj = uquiver; From cbb0f9079d1b65f4fbb5ba4c41d2da7ac577cbc7 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Mon, 9 Dec 2024 14:36:11 +0200 Subject: [PATCH 159/791] Wand of striking strikes the ground ... if dropped while levitating/flying. --- src/dothrow.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/dothrow.c b/src/dothrow.c index 5ce3570a2..fc154773c 100644 --- a/src/dothrow.c +++ b/src/dothrow.c @@ -609,6 +609,7 @@ hitfloor( if (IS_ALTAR(levl[u.ux][u.uy].typ)) { doaltarobj(obj); } else if (verbosely) { + const char *verb = (obj->otyp == WAN_STRIKING) ? "strike" : "hit"; const char *surf = surface(u.ux, u.uy); struct trap *t = t_at(u.ux, u.uy); @@ -630,7 +631,7 @@ hitfloor( break; } } - pline("%s %s the %s.", Doname2(obj), otense(obj, "hit"), surf); + pline("%s %s the %s.", Doname2(obj), otense(obj, verb), surf); } if (hero_breaks(obj, u.ux, u.uy, BRK_FROM_INV)) From 02259dd1d06a4db14357a043f98fa1e83ca86e29 Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 9 Dec 2024 15:52:29 -0500 Subject: [PATCH 160/791] light source troubleshooting I don't think this solves the recent light source reports, but it changes a couple of things in an attempt to get more information. 1. Having gy.youmonst.m_id field always be zero makes it tough to distinguish it from uninitialized memory, or a random memory value. This changes the m_id for the hero's gy.youmonst.m_id to always hold the identifier 1, instead of 0. 2. write_ls was taking the stashed pointer in the light source, and using it to immediately extract the m_id field and search for that m_id. This changes the approach slightly, to actually try and locate the stashed pointer itself in one of the monster chains. Only if the monster pointer is located, do we dereference it to obtain the m_id field. 3. For the interim, mark the saved ls with another set bit when there has been a failure to locate the monst. At this time, no code is acting on that bit, but it can be seen in a debug session. Hopefully, the next report will provide enough information to understand the scenario a little better. --- include/hack.h | 5 ++-- src/allmain.c | 2 +- src/light.c | 79 +++++++++++++++++++++++++++++++++++++++++++------- src/mkobj.c | 2 +- src/polyself.c | 7 +++-- 5 files changed, 77 insertions(+), 18 deletions(-) diff --git a/include/hack.h b/include/hack.h index 40b4d4ada..09e41407e 100644 --- a/include/hack.h +++ b/include/hack.h @@ -1256,11 +1256,12 @@ typedef uint32_t mmflags_nht; /* makemon MM_ flags */ /* flag for suppressing perm_invent update when name gets assigned */ #define ONAME_SKIP_INVUPD 0x0200U /* don't call update_inventory() */ -/* Flags to control find_mid() */ +/* Flags to control find_mid() and whereis_mon() */ #define FM_FMON 0x01 /* search the fmon chain */ #define FM_MIGRATE 0x02 /* search the migrating monster chain */ #define FM_MYDOGS 0x04 /* search gm.mydogs */ -#define FM_EVERYWHERE (FM_FMON | FM_MIGRATE | FM_MYDOGS) +#define FM_YOU 0x08 /* check for gy.youmonst */ +#define FM_EVERYWHERE (FM_YOU | FM_FMON | FM_MIGRATE | FM_MYDOGS) /* Flags to control pick_[race,role,gend,align] routines in role.c */ #define PICK_RANDOM 0 diff --git a/src/allmain.c b/src/allmain.c index c10446417..852904683 100644 --- a/src/allmain.c +++ b/src/allmain.c @@ -731,7 +731,7 @@ newgame(void) /* make sure welcome messages are given before noticing monsters */ notice_mon_off(); disp.botlx = TRUE; - svc.context.ident = 1; + svc.context.ident = 2; /* id 1 is reserved for gy.youmonst */ svc.context.warnlevel = 1; svc.context.next_attrib_check = 600L; /* arbitrary first setting */ svc.context.tribute.enabled = TRUE; /* turn on 3.6 tributes */ diff --git a/src/light.c b/src/light.c index 5ab517177..6675e0d86 100644 --- a/src/light.c +++ b/src/light.c @@ -13,8 +13,8 @@ * Light sources are "things" that have a physical position and range. * They have a type, which gives us information about them. Currently * they are only attached to objects and monsters. Note well: the - * polymorphed-player handling assumes that both gy.youmonst.m_id and - * gy.youmonst.mx will always remain 0. + * polymorphed-player handling assumes that gy.youmonst.m_id will + * always remain 1 and gy.youmonst.mx will always remain 0. * * Light sources, like timers, either follow game play (RANGE_GLOBAL) or * stay on a level (RANGE_LEVEL). Light sources are unique by their @@ -38,8 +38,9 @@ */ /* flags */ -#define LSF_SHOW 0x1 /* display the light source */ -#define LSF_NEEDS_FIXUP 0x2 /* need oid fixup */ +#define LSF_SHOW 0x1 /* display the light source */ +#define LSF_NEEDS_FIXUP 0x2 /* need oid fixup */ +#define LSF_IS_PROBLEMATIC 0x4 /* impossible situation encountered */ staticfn light_source *new_light_core(coordxy, coordxy, int, int, anything *) NONNULLPTRS; @@ -47,6 +48,7 @@ staticfn void delete_ls(light_source *); staticfn void discard_flashes(void); staticfn void write_ls(NHFILE *, light_source *); staticfn int maybe_write_ls(NHFILE *, int, boolean); +staticfn unsigned whereis_mon(struct monst *, unsigned); /* imported from vision.c, for small circles */ extern const coordxy circle_data[]; @@ -374,7 +376,7 @@ find_mid(unsigned nid, unsigned fmflags) { struct monst *mtmp; - if (!nid) + if ((fmflags & FM_YOU) && nid == 1) return &gy.youmonst; if (fmflags & FM_FMON) for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) @@ -391,6 +393,28 @@ find_mid(unsigned nid, unsigned fmflags) return (struct monst *) 0; } +staticfn unsigned +whereis_mon(struct monst *mon, unsigned fmflags) +{ + struct monst *mtmp; + + if ((fmflags & FM_YOU) && mon == &gy.youmonst) + return FM_YOU; + if (fmflags & FM_FMON) + for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) + if (mtmp == mon) + return FM_FMON; + if (fmflags & FM_MIGRATE) + for (mtmp = gm.migrating_mons; mtmp; mtmp = mtmp->nmon) + if (mtmp == mon) + return FM_MIGRATE; + if (fmflags & FM_MYDOGS) + for (mtmp = gm.mydogs; mtmp; mtmp = mtmp->nmon) + if (mtmp == mon) + return FM_MYDOGS; + return 0; +} + /* Save all light sources of the given range. */ void save_light_sources(NHFILE *nhfp, int range) @@ -624,22 +648,55 @@ write_ls(NHFILE *nhfp, light_source *ls) otmp = ls->id.a_obj; ls->id = cg.zeroany; ls->id.a_uint = otmp->o_id; - if (find_oid((unsigned) ls->id.a_uint) != otmp) + if (find_oid((unsigned) ls->id.a_uint) != otmp) { impossible("write_ls: can't find obj #%u!", ls->id.a_uint); + ls->flags |= LSF_IS_PROBLEMATIC; + } } else { /* ls->type == LS_MONSTER */ + unsigned monloc = 0; + mtmp = (struct monst *) ls->id.a_monst; - ls->id = cg.zeroany; - ls->id.a_uint = mtmp->m_id; - if (find_mid((unsigned) ls->id.a_uint, FM_EVERYWHERE) != mtmp) - impossible("write_ls: can't find mon #%u!", - ls->id.a_uint); + + /* The monster pointer has been stashed in the light source + * for a while and while there is code meant to clean-up the + * light source aspects if a monster goes away, there have + * been some reports of light source issues, such as when + * going to the planes. + * + * Verify that the stashed monst pointer is still present + * in one of the monster chains before pulling subfield + * values such as m_id from it, to avoid any attempt to + * pull random m_id value from (now) freed memory. + * + * find_mid() disregards a DEADMONSTER, but whereis_mon() + * does not. */ + + if ((monloc = whereis_mon(mtmp, FM_EVERYWHERE)) != 0) { + ls->id = cg.zeroany; + ls->id.a_uint = mtmp->m_id; + if (find_mid((unsigned) ls->id.a_uint, monloc) != mtmp) { + impossible("write_ls: can't find mon #%u%s!", + DEADMONSTER(mtmp) ? " because it's dead" + : "", + ls->id.a_uint); + ls->flags |= LSF_IS_PROBLEMATIC; + } + } else { + impossible( + "write_ls: stashed monst ptr not in any chain"); + ls->flags |= LSF_IS_PROBLEMATIC; + } + } + if (ls->flags & LSF_IS_PROBLEMATIC) { + /* TODO: cleanup this ls, or skip writing it */ } ls->flags |= LSF_NEEDS_FIXUP; if (nhfp->structlevel) bwrite(nhfp->fd, (genericptr_t) ls, sizeof(light_source)); ls->id = arg_save; ls->flags &= ~LSF_NEEDS_FIXUP; + ls->flags &= ~LSF_IS_PROBLEMATIC; } } else { impossible("write_ls: bad type (%d)", ls->type); diff --git a/src/mkobj.c b/src/mkobj.c index 8a9be1e0d..79e088cff 100644 --- a/src/mkobj.c +++ b/src/mkobj.c @@ -522,7 +522,7 @@ next_ident(void) uses 16-bit 'int'), just live with that and hope no o_id conflicts between objects or m_id conflicts between monsters arise */ if (!svc.context.ident) - svc.context.ident = rnd(2); + svc.context.ident = rnd(2) + 1; /* id 1 is reserved */ return res; } diff --git a/src/polyself.c b/src/polyself.c index 38f9b01ea..623bf1976 100644 --- a/src/polyself.c +++ b/src/polyself.c @@ -5,9 +5,9 @@ /* * Polymorph self routine. * - * Note: the light source handling code assumes that both gy.youmonst.m_id - * and gy.youmonst.mx will always remain 0 when it handles the case of the - * player polymorphed into a light-emitting monster. + * Note: the light source handling code assumes that gy.youmonst.m_id + * always remains 1 and gy.youmonst.mx will always remain 0 when it handles + * the case of the player polymorphed into a light-emitting monster. * * Transformation sequences: * /-> polymon poly into monster form @@ -41,6 +41,7 @@ set_uasmon(void) boolean was_vampshifter = valid_vampshiftform(gy.youmonst.cham, u.umonnum); set_mon_data(&gy.youmonst, mdat); + gy.youmonst.m_id = 1; if (Protection_from_shape_changers) gy.youmonst.cham = NON_PM; From b744ad41d92955b215b3097a7bb2c338de2583ea Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 9 Dec 2024 16:07:27 -0500 Subject: [PATCH 161/791] follow-up correct ordering of impossible() fmt --- src/light.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/light.c b/src/light.c index 6675e0d86..e89c316ca 100644 --- a/src/light.c +++ b/src/light.c @@ -676,7 +676,7 @@ write_ls(NHFILE *nhfp, light_source *ls) ls->id = cg.zeroany; ls->id.a_uint = mtmp->m_id; if (find_mid((unsigned) ls->id.a_uint, monloc) != mtmp) { - impossible("write_ls: can't find mon #%u%s!", + impossible("write_ls: can't find mon%s #%u!", DEADMONSTER(mtmp) ? " because it's dead" : "", ls->id.a_uint); From 1f8b75b8c6e1af2ed28871b6b6650501b06f1d48 Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 9 Dec 2024 16:21:31 -0500 Subject: [PATCH 162/791] different ls content values, so bump EDITLEVEL --- include/patchlevel.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/patchlevel.h b/include/patchlevel.h index 41708bc86..661160f1c 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 111 +#define EDITLEVEL 112 /* * Development status possibilities. From 64d41e10de20ed438d12a41212e2df2106f449ac Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 9 Dec 2024 21:14:14 -0500 Subject: [PATCH 163/791] update #migratemons for debugging purposes For the wizard-mode command #migratemons at the "How many random monsters to migrate to next level? [0]" prompt, allow a negative number to cause it to use existing monsters already on the level for the forced migration, up until the absolute value of the number, instead of random new monsters as it does for a positive number. For example, specify -20 to force-migrate 20 existing monsters already on the map. --- src/wizcmds.c | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/src/wizcmds.c b/src/wizcmds.c index c7cdd707e..c752d89da 100644 --- a/src/wizcmds.c +++ b/src/wizcmds.c @@ -1807,6 +1807,7 @@ wiz_migrate_mons(void) char inbuf[BUFSZ]; struct permonst *ptr; struct monst *mtmp; + boolean use_existing_map_mon = FALSE; #endif d_level tolevel; @@ -1830,17 +1831,32 @@ wiz_migrate_mons(void) return ECMD_OK; mcount = atoi(inbuf); + if (mcount < 0) { + use_existing_map_mon = TRUE; + mcount *= -1; + } if (mcount < 1) mcount = 0; else if (mcount > ((COLNO - 1) * ROWNO)) mcount = (COLNO - 1) * ROWNO; while (mcount > 0) { - ptr = rndmonst(); - mtmp = makemon(ptr, 0, 0, MM_NOMSG); - if (mtmp) - migrate_to_level(mtmp, ledger_no(&tolevel), MIGR_RANDOM, - (coord *) 0); + if (!use_existing_map_mon) { + ptr = rndmonst(); + mtmp = makemon(ptr, 0, 0, MM_NOMSG); + if (mtmp) + migrate_to_level(mtmp, ledger_no(&tolevel), MIGR_RANDOM, + (coord *) 0); + } else { + struct monst *nextmon; + + for (mtmp = fmon; mtmp; mtmp = nextmon) { + nextmon = mtmp->nmon; + migrate_to_level(mtmp, ledger_no(&tolevel), MIGR_RANDOM, + (coord *) 0); + break; + } + } mcount--; } #endif /* DEBUG_MIGRATING_MONS */ From d99a24843b4fbb9ab7f1b5b493d04e7350d2d5af Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 9 Dec 2024 21:41:26 -0500 Subject: [PATCH 164/791] deal with light sources in discard_migrations() Otherwise, when discard_migrations() purges monsters, their stale monster pointers can be left inside the light source data structure. --- src/dog.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/dog.c b/src/dog.c index 607f2cdf8..c4e4b60e7 100644 --- a/src/dog.c +++ b/src/dog.c @@ -914,6 +914,8 @@ discard_migrations(void) mtmp->nmon = 0; discard_minvent(mtmp, FALSE); /* bypass mongone() and its call to m_detach() plus dmonsfree() */ + if (emits_light(mtmp->data)) + del_light_source(LS_MONSTER, monst_to_any(mtmp)); dealloc_monst(mtmp); } } From c897f3a95039b91bc975c3904c4c5cdaab42b9a9 Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 9 Dec 2024 22:59:56 -0500 Subject: [PATCH 165/791] a comment for the obj side of discard_migrations() --- src/dog.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/dog.c b/src/dog.c index c4e4b60e7..e14513fdb 100644 --- a/src/dog.c +++ b/src/dog.c @@ -938,6 +938,12 @@ discard_migrations(void) otmp->where = OBJ_FREE; otmp->owornmask = 0L; /* overloaded for destination usage; * obfree() will complain if nonzero */ + /* + * obfree(otmp,) + * -> dealloc_obj(otmp) + * -> obj_stop_timers(otmp) + * -> del_light_source(LS_OBJECT, obj_to_any(otmp)) + */ obfree(otmp, (struct obj *) 0); /* releases any contents too */ } } From ce8cef7906deda275a2ca9bc3f1e2005e25a0aeb Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 9 Dec 2024 23:29:38 -0500 Subject: [PATCH 166/791] get rid of spurious warning on Microsoft compiler --- src/wizcmds.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/wizcmds.c b/src/wizcmds.c index c752d89da..575eff1d8 100644 --- a/src/wizcmds.c +++ b/src/wizcmds.c @@ -1798,6 +1798,8 @@ wiz_mon_diff(void) } #endif /* (NH_DEVEL_STATUS != NH_STATUS_RELEASED) || defined(DEBUG) */ +DISABLE_WARNING_UNREACHABLE_CODE + /* #migratemons command */ int wiz_migrate_mons(void) @@ -1839,7 +1841,6 @@ wiz_migrate_mons(void) mcount = 0; else if (mcount > ((COLNO - 1) * ROWNO)) mcount = (COLNO - 1) * ROWNO; - while (mcount > 0) { if (!use_existing_map_mon) { ptr = rndmonst(); @@ -1848,7 +1849,7 @@ wiz_migrate_mons(void) migrate_to_level(mtmp, ledger_no(&tolevel), MIGR_RANDOM, (coord *) 0); } else { - struct monst *nextmon; + struct monst *nextmon = (struct monst *) 0; for (mtmp = fmon; mtmp; mtmp = nextmon) { nextmon = mtmp->nmon; @@ -1862,6 +1863,7 @@ wiz_migrate_mons(void) #endif /* DEBUG_MIGRATING_MONS */ return ECMD_OK; } +RESTORE_WARNING_UNREACHABLE_CODE /* #wizcustom command to see glyphmap customizations */ int From 548c021049e2e48e367a4c030249549a2693fc2b Mon Sep 17 00:00:00 2001 From: nhmall Date: Tue, 10 Dec 2024 13:32:57 -0500 Subject: [PATCH 167/791] freedynamicdata() adjustment The location of the call to dobjsfree() in freedynamicdata() appears to have been non-ideal. After getting complaints from a leak-sensing tool after #quit, the source of the leaks was investigated. The call to dobjsfree() had been placed immediately following a call to dmonsfree(), and it did clear out the go.objs_deleted chain at that point. Further investigation revealed that the following functions later on in freedynamicdata() were then adding more deleted objects to the go.objs_deleted chain: free_current_level(); freeobjchn(gi.invent); freeobjchn(gm.migrating_objs); Move the call to dobjsfree() to a location after those listed above. --- src/save.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/save.c b/src/save.c index b98194da7..1497c4d5b 100644 --- a/src/save.c +++ b/src/save.c @@ -1213,7 +1213,6 @@ freedynamicdata(void) /* move-specific data */ dmonsfree(); /* release dead monsters */ - dobjsfree(); alloc_itermonarr(0U); /* a request of 0 releases existing allocation */ /* level-specific data */ @@ -1226,6 +1225,8 @@ freedynamicdata(void) free_light_sources(RANGE_GLOBAL); freeobjchn(gi.invent); freeobjchn(gm.migrating_objs); + if (go.objs_deleted) + dobjsfree(); /* really free deleted objects */ freemonchn(gm.migrating_mons); freemonchn(gm.mydogs); /* ascension or dungeon escape */ /* freelevchn(); -- [folded into free_dungeons()] */ From 175260807b0db7a83cc4f45899f9779ee10388e5 Mon Sep 17 00:00:00 2001 From: nhmall Date: Tue, 10 Dec 2024 13:39:55 -0500 Subject: [PATCH 168/791] wiz mode teleport starting destination selection Ensure that the destination selection for intentional teleport begins at the hero, rather than starting at a place on the map stored from a prior travel command. --- src/teleport.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/teleport.c b/src/teleport.c index 5b51a3a0a..422a087ac 100644 --- a/src/teleport.c +++ b/src/teleport.c @@ -1110,12 +1110,14 @@ dotele( } if (next_to_u()) { - if (trap && trap_once) + if (trap && trap_once) { vault_tele(); - else if (trap && isok(trap->teledest.x, trap->teledest.y)) + } else if (trap && isok(trap->teledest.x, trap->teledest.y)) { teleds(trap->teledest.x, trap->teledest.y, TELEDS_TELEPORT); - else + } else { + iflags.travelcc.x = iflags.travelcc.y = 0; tele(); + } (void) next_to_u(); } else { You("%s", shudder_for_moment); From 323359ed839a431b18bc0e8ff5c05b530305fb9f Mon Sep 17 00:00:00 2001 From: nhmall Date: Tue, 10 Dec 2024 14:01:10 -0500 Subject: [PATCH 169/791] rework a #migratemons change from yesterday --- src/wizcmds.c | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/src/wizcmds.c b/src/wizcmds.c index 575eff1d8..fd0d9858b 100644 --- a/src/wizcmds.c +++ b/src/wizcmds.c @@ -1798,8 +1798,6 @@ wiz_mon_diff(void) } #endif /* (NH_DEVEL_STATUS != NH_STATUS_RELEASED) || defined(DEBUG) */ -DISABLE_WARNING_UNREACHABLE_CODE - /* #migratemons command */ int wiz_migrate_mons(void) @@ -1809,7 +1807,7 @@ wiz_migrate_mons(void) char inbuf[BUFSZ]; struct permonst *ptr; struct monst *mtmp; - boolean use_existing_map_mon = FALSE; + boolean use_random_mon = TRUE; #endif d_level tolevel; @@ -1834,36 +1832,29 @@ wiz_migrate_mons(void) mcount = atoi(inbuf); if (mcount < 0) { - use_existing_map_mon = TRUE; + use_random_mon = FALSE; mcount *= -1; } if (mcount < 1) mcount = 0; else if (mcount > ((COLNO - 1) * ROWNO)) mcount = (COLNO - 1) * ROWNO; + while (mcount > 0) { - if (!use_existing_map_mon) { + if (use_random_mon) { ptr = rndmonst(); mtmp = makemon(ptr, 0, 0, MM_NOMSG); - if (mtmp) - migrate_to_level(mtmp, ledger_no(&tolevel), MIGR_RANDOM, - (coord *) 0); } else { - struct monst *nextmon = (struct monst *) 0; - - for (mtmp = fmon; mtmp; mtmp = nextmon) { - nextmon = mtmp->nmon; - migrate_to_level(mtmp, ledger_no(&tolevel), MIGR_RANDOM, - (coord *) 0); - break; - } + mtmp = fmon; } + if (mtmp) + migrate_to_level(mtmp, ledger_no(&tolevel), MIGR_RANDOM, + (coord *) 0); mcount--; } #endif /* DEBUG_MIGRATING_MONS */ return ECMD_OK; } -RESTORE_WARNING_UNREACHABLE_CODE /* #wizcustom command to see glyphmap customizations */ int From e08bd9ef8a208ad74283984db0d2c03b5dfaad88 Mon Sep 17 00:00:00 2001 From: nhmall Date: Tue, 10 Dec 2024 14:49:56 -0500 Subject: [PATCH 170/791] Windows NetHackW memory leak bit --- win/win32/NetHackW.c | 3 +++ win/win32/mhmain.c | 2 +- win/win32/mhmenu.c | 12 ++++++++++++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/win/win32/NetHackW.c b/win/win32/NetHackW.c index 033dc797c..2eee75939 100644 --- a/win/win32/NetHackW.c +++ b/win/win32/NetHackW.c @@ -252,6 +252,8 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, return 0; } +extern void free_menu_data(void); + void free_winmain_stuff(void) { @@ -271,6 +273,7 @@ free_winmain_stuff(void) windowdata[cnt].address = 0; } } + free_menu_data(); } #ifdef _MSC_VER diff --git a/win/win32/mhmain.c b/win/win32/mhmain.c index 053324db8..c0a6cd0b1 100644 --- a/win/win32/mhmain.c +++ b/win/win32/mhmain.c @@ -27,7 +27,7 @@ static TCHAR szMainWindowClass[] = TEXT("MSNHMainWndClass"); static TCHAR szTitle[MAX_LOADSTRING]; struct window_tracking_data windowdata[MAXWINDOWS]; extern void mswin_display_splash_window(BOOL); - +extern void free_menu_data(void); /* mhmenu.c */ LRESULT CALLBACK MainWndProc(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK About(HWND, UINT, WPARAM, LPARAM); static LRESULT onWMCommand(HWND hWnd, WPARAM wParam, LPARAM lParam); diff --git a/win/win32/mhmenu.c b/win/win32/mhmenu.c index 0899bc747..121704b0d 100644 --- a/win/win32/mhmenu.c +++ b/win/win32/mhmenu.c @@ -95,6 +95,8 @@ static void SelectMenuItem(HWND hwndList, PNHMenuWindow data, int item, int count); static void reset_menu_count(HWND hwndList, PNHMenuWindow data); static BOOL onListChar(HWND hWnd, HWND hwndList, WORD ch); +static genericptr_t menu_data_to_free; +void free_menu_data(void); /*-----------------------------------------------------------------------------*/ HWND @@ -627,6 +629,8 @@ onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) data->menui.menu.items, data->menui.menu.allocated * sizeof(NHMenuItem)); if (!data->menui.menu.items) free(was); + else + menu_data_to_free = (genericptr_t) data->menui.menu.items; } if (data->menui.menu.items) { @@ -719,6 +723,14 @@ onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) } } + +void +free_menu_data(void) +{ + if (menu_data_to_free != 0) + free(menu_data_to_free), menu_data_to_free = 0; +} + /*-----------------------------------------------------------------------------*/ void LayoutMenu(HWND hWnd) From aedb24d343b7920058a6e6b98a829c86b05892f2 Mon Sep 17 00:00:00 2001 From: PatR Date: Wed, 11 Dec 2024 12:38:28 -0800 Subject: [PATCH 171/791] partly fix issue #1336 - pets vs floating eyes Issue reported by ars3niy: pets with reflection or ranged attacks would only attack floating eyes when rolling the 10% random chance that other pets have even though they could have always safely attacked. This fixes the situation for melee attacks by pets who have reflection. dog_move() is too complicated for my feeble brain to cope with the ranged attack aspect. Pets still won't use ranged attacks against floating eyes. With the fix for reflection, I discovered that silver dragons would be subjected to floating eyes' passive paralysis even when their breath attack was suppressed. (It wouldn't impact them, due to reflection, but the message about the floating eye being hit by its reflected gaze was being delivered without being preceded by any message since no attack had taken place yet.) This fixes that. \#1336 is still open --- doc/fixes3-7-0.txt | 5 +++-- src/dogmove.c | 31 +++++++++++++++++++++++-------- src/mhitm.c | 32 +++++++++++++++----------------- 3 files changed, 41 insertions(+), 27 deletions(-) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index 13d11bcca..362cd6c7e 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -1484,9 +1484,8 @@ 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 destroy armor asks which armor to destroy -archeologists' fedora is lucky gelatinous cubes eat organic objects inside them +pets with reflection were unwilling to attack floating eyes Fixes to 3.7.0-x General Problems Exposed Via git Repository @@ -2734,6 +2733,8 @@ enlightenment/attribute disclosure for saving-grace: include a line for have tourists gain experience by seeing new types of creatures up close, and going to new dungeon levels healers gain experience by healing pets +blessed scroll of destroy armor asks which armor to destroy +archeologists' fedora is lucky Platform- and/or Interface-Specific New Features diff --git a/src/dogmove.c b/src/dogmove.c index 29c0d9bc1..1694eb8a6 100644 --- a/src/dogmove.c +++ b/src/dogmove.c @@ -968,7 +968,7 @@ dog_move( struct obj *obj = (struct obj *) 0; xint16 otyp; boolean cursemsg[9], do_eat = FALSE; - boolean better_with_displacing = FALSE; + boolean better_with_displacing = FALSE, ranged_only; coordxy nix, niy; /* position mtmp is (considering) moving to */ coordxy nx, ny; /* temporary coordinates */ xint16 cnt, uncursedcnt, chcnt; @@ -1081,6 +1081,8 @@ dog_move( if (!edog && (j = distu(nx, ny)) > 16 && j >= udist) continue; + ranged_only = FALSE; + if ((info[i] & ALLOW_M) && MON_AT(nx, ny)) { int mstatus; struct monst *mtmp2 = m_at(nx, ny); @@ -1101,16 +1103,28 @@ dog_move( int balk = mtmp->m_lev + ((5 * mtmp->mhp) / mtmp->mhpmax) - 2; if ((int) mtmp2->m_lev >= balk - || (mtmp2->data == &mons[PM_FLOATING_EYE] && rn2(10) - && mtmp->mcansee && haseyes(mtmp->data) && mtmp2->mcansee - && (perceives(mtmp->data) || !mtmp2->minvis)) - || (mtmp2->data == &mons[PM_GELATINOUS_CUBE] && rn2(10)) + || (mtmp2->mtame && mtmp->mtame && !Conflict) || (max_passive_dmg(mtmp2, mtmp) >= mtmp->mhp) || ((mtmp->mhp * 4 < mtmp->mhpmax || mtmp2->data->msound == MS_GUARDIAN - || mtmp2->data->msound == MS_LEADER) && mtmp2->mpeaceful - && !Conflict) - || (touch_petrifies(mtmp2->data) && !resists_ston(mtmp))) + || mtmp2->data->msound == MS_LEADER) + && mtmp2->mpeaceful && !Conflict)) { + continue; + } + if ((mtmp2->data == &mons[PM_FLOATING_EYE] && rn2(10) + && mtmp->mcansee && haseyes(mtmp->data) && mtmp2->mcansee + && (!mtmp2->minvis || perceives(mtmp->data)) + && !mon_reflects(mtmp, (char *) NULL)) + || (mtmp2->data == &mons[PM_GELATINOUS_CUBE] && rn2(10)) + || (touch_petrifies(mtmp2->data) && !resists_ston(mtmp))) { + /* only skip this foe if a ranged attack isn't viable */ + if (dist2(mtmp->mx, mtmp->my, mtmp2->mx, mtmp2->my) <= 2 + || best_target(mtmp) != mtmp2) + continue; + ranged_only = TRUE; + } + /** FIXME: 'ranged_only' isn't used as intended yet **/ + if (ranged_only) continue; if (after) @@ -1183,6 +1197,7 @@ dog_move( /* (minion isn't interested; `cursemsg' stays FALSE) */ if (edog) { boolean can_reach_food = could_reach_item(mtmp, nx, ny); + for (obj = svl.level.objects[nx][ny]; obj; obj = obj->nexthere) { if (obj->cursed) { cursemsg[i] = TRUE; diff --git a/src/mhitm.c b/src/mhitm.c index f54dc4ad2..3ea3b3643 100644 --- a/src/mhitm.c +++ b/src/mhitm.c @@ -485,7 +485,7 @@ mattackm( case AT_EXPL: /* D: Prevent explosions from a distance */ - if (distmin(magr->mx,magr->my,mdef->mx,mdef->my) > 1) + if (distmin(magr->mx, magr->my, mdef->mx, mdef->my) > 1) continue; res[i] = explmm(magr, mdef, mattk); @@ -525,25 +525,20 @@ mattackm( break; case AT_BREA: - if (!monnear(magr, mdef->mx, mdef->my)) { - strike = (breamm(magr, mattk, mdef) == M_ATTK_MISS) ? 0 : 1; - - /* We don't really know if we hit or not; pretend we did. */ - if (strike) - res[i] |= M_ATTK_HIT; - if (DEADMONSTER(mdef)) - res[i] = M_ATTK_DEF_DIED; - if (DEADMONSTER(magr)) - res[i] |= M_ATTK_AGR_DIED; - } - else - strike = 0; - break; - case AT_SPIT: + /* + * Ranged attacks aren't allowed at point blank range. + * + * That impacts pet use of ranged attacks. It's rather arbitrary + * but various parts of the code assume it to be the case, not to + * mention a part of player strategy when fighting dragons. + */ if (!monnear(magr, mdef->mx, mdef->my)) { - strike = (spitmm(magr, mattk, mdef) == M_ATTK_MISS) ? 0 : 1; + int mmtmp = ((mattk->aatyp == AT_BREA) + ? breamm(magr, mattk, mdef) + : spitmm(magr, mattk, mdef)); + strike = (mmtmp == M_ATTK_MISS) ? 0 : 1; /* We don't really know if we hit or not; pretend we did. */ if (strike) res[i] |= M_ATTK_HIT; @@ -551,6 +546,9 @@ mattackm( res[i] = M_ATTK_DEF_DIED; if (DEADMONSTER(magr)) res[i] |= M_ATTK_AGR_DIED; + } else { + strike = 0; + attk = 0; } break; From d87cadaf73f8ebbfbeb04c1b64249ff6d966d2d6 Mon Sep 17 00:00:00 2001 From: Alex Smith Date: Thu, 12 Dec 2024 03:14:47 +0000 Subject: [PATCH 172/791] Artifact and #offer rebalance, part 1: sacrifice gifts In 3.6, artifact gifts are often either a) entirely useless or b) gamebreaking, neither of which is really ideal from a balance perspective. This commit aims to make artifact gifts more useful in the early game by greatly increasing the chance for situational artifacts to generate positively enchanted. However, the most powerful artifacts will now only be gifted if you offer a high-value corpse, meaning that they are only likely to be accessible later in the game. The selection of which artifact to gift has become more complicated in order to a) increase the chance that it fits the character and b) reduce cheese strategies (e.g. it is no longer possible for elves to force the gifting of Stormbringer as the first sacrifice gift). --- doc/fixes3-7-0.txt | 4 ++ include/artifact.h | 2 + include/artilist.h | 152 +++++++++++++++++++++++++++------------------ include/extern.h | 2 +- src/artifact.c | 53 +++++++++++++--- src/mkobj.c | 6 +- src/mplayer.c | 2 +- src/pray.c | 25 +++++--- 8 files changed, 163 insertions(+), 83 deletions(-) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index 362cd6c7e..3ff0cb864 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -1486,6 +1486,10 @@ digging in ice was handled inconsistently, particularly if done at the span angry god may remove an intrinsic gelatinous cubes eat organic objects inside them pets with reflection were unwilling to attack floating eyes +artifact gifts are rebalanced (easier to obtain; higher-value sacrifices are + needed for higher-value artifacts; lower-value artifacts are usually + gifted enchanted; unaligned artifacts are possible but rare even on + the first gift; artifacts you can't use well are less likely) Fixes to 3.7.0-x General Problems Exposed Via git Repository diff --git a/include/artifact.h b/include/artifact.h index c564eba66..4199a7feb 100644 --- a/include/artifact.h +++ b/include/artifact.h @@ -49,6 +49,8 @@ struct artifact { aligntyp alignment; /* alignment of bequeathing gods */ short role; /* character role associated with */ short race; /* character race associated with */ + schar gen_spe; /* bias to spe when gifted or randomly generated */ + uchar gift_value; /* minimum sacrifice value to be gifted this */ long cost; /* price when sold to hero (default 100 x base cost) */ char acolor; /* color to use if artifact 'glows' */ }; diff --git a/include/artilist.h b/include/artilist.h index 735ee95a2..df49ba865 100644 --- a/include/artilist.h +++ b/include/artilist.h @@ -7,28 +7,28 @@ /* in makedefs.c, all we care about is the list of names */ #define A(nam, typ, s1, s2, mt, atk, dfn, cry, inv, al, cl, rac, \ - cost, clr, bn) nam + gs, gv, cost, clr, bn) nam static const char *const artifact_names[] = { #elif defined(ARTI_ENUM) #define A(nam, typ, s1, s2, mt, atk, dfn, cry, inv, al, cl, rac, \ - cost, clr, bn) \ + gs, gv, cost, clr, bn) \ ART_##bn #elif defined(DUMP_ARTI_ENUM) #define A(nam, typ, s1, s2, mt, atk, dfn, cry, inv, al, cl, rac, \ - cost, clr, bn) \ + gs, gv, cost, clr, bn) \ { ART_##bn, "ART_" #bn } #else /* in artifact.c, set up the actual artifact list structure; color field is for an artifact when it glows, not for the item itself */ #define A(nam, typ, s1, s2, mt, atk, dfn, cry, inv, al, cl, rac, \ - cost, clr, bn) \ + gs, gv, cost, clr, bn) \ { \ typ, nam, s1, s2, mt, atk, dfn, cry, inv, al, cl, rac, \ - cost, clr \ + gs, gv, cost, clr \ } /* clang-format off */ @@ -52,24 +52,47 @@ static NEARDATA struct artifact artilist[] = { * 1. The more useful the artifact, the better its cost. * 2. Quest artifacts are highly valued. * 3. Chaotic artifacts are inflated due to scarcity (and balance). + * + * Artifact gen_spe rationale: + * 1. If the artifact is useful against most enemies, +0. + * 2. If the artifact is useful against only a few enemies, usually +2. + * This gives the artifact use to early-game characters who receive + * it as a gift or find it on the ground. + * 3. Role gift gen_spe is chosen to balance against the role's + * default starting weapon (it should be better, but need not be + * much better). + * 4. This can be modified as required for special cases. + * (In some cases, like Excalibur, the value is irrelevant.) + * 5. Nonweapon spe may have a special meaning, so gen_spe for + * nonweapons must always be 0. + * + * Artifact gift_value is chosen so that "endgame-quality" artifacts are + * not gifted in the early game (so that characters don't grind on an + * altar early-game until they have their endgame weapon, then use it to + * carry them through the game). Those artifacts have values ranging from + * around 8 to 10, based on how good the artifact is. Less powerful + * artifacts have values in the 1 to 5 range. Values in between are used + * for conditionally good artifacts. (Note that the value of a gift is + * normally 1 higher than the difficulty of the monster.) */ /* dummy element #0, so that all interesting indices are non-zero */ A("", STRANGE_OBJECT, 0, 0, 0, NO_ATTK, NO_DFNS, NO_CARY, 0, A_NONE, - NON_PM, NON_PM, 0L, NO_COLOR, NONARTIFACT), + NON_PM, NON_PM, + 0, 0, 0L, NO_COLOR, NONARTIFACT), A("Excalibur", LONG_SWORD, (SPFX_NOGEN | SPFX_RESTR | SPFX_SEEK | SPFX_DEFN | SPFX_INTEL | SPFX_SEARCH), 0, 0, PHYS(5, 10), DRLI(0, 0), NO_CARY, 0, A_LAWFUL, PM_KNIGHT, NON_PM, - 4000L, NO_COLOR, EXCALIBUR), + 0, 10, 4000L, NO_COLOR, EXCALIBUR), /* * Stormbringer only has a 2 because it can drain a level, * providing 8 more. */ A("Stormbringer", RUNESWORD, (SPFX_RESTR | SPFX_ATTK | SPFX_DEFN | SPFX_INTEL | SPFX_DRLI), 0, 0, - DRLI(5, 2), DRLI(0, 0), NO_CARY, 0, A_CHAOTIC, NON_PM, NON_PM, 8000L, - NO_COLOR, STORMBRINGER), + DRLI(5, 2), DRLI(0, 0), NO_CARY, 0, A_CHAOTIC, NON_PM, NON_PM, + 0, 9, 8000L, NO_COLOR, STORMBRINGER), /* * Mjollnir can be thrown when wielded if hero has 25 Strength * (usually via gauntlets of power but possible with rings of @@ -84,10 +107,12 @@ static NEARDATA struct artifact artilist[] = { */ A("Mjollnir", WAR_HAMMER, /* Mjo:llnir */ (SPFX_RESTR | SPFX_ATTK), 0, 0, ELEC(5, 24), NO_DFNS, NO_CARY, 0, - A_NEUTRAL, PM_VALKYRIE, NON_PM, 4000L, NO_COLOR, MJOLLNIR), + A_NEUTRAL, PM_VALKYRIE, NON_PM, + 0, 8, 4000L, NO_COLOR, MJOLLNIR), A("Cleaver", BATTLE_AXE, SPFX_RESTR, 0, 0, PHYS(3, 6), NO_DFNS, NO_CARY, - 0, A_NEUTRAL, PM_BARBARIAN, NON_PM, 1500L, NO_COLOR, CLEAVER), + 0, A_NEUTRAL, PM_BARBARIAN, NON_PM, + 0, 8, 1500L, NO_COLOR, CLEAVER), /* * Grimtooth glows in warning when elves are present, but its @@ -96,7 +121,8 @@ static NEARDATA struct artifact artilist[] = { */ A("Grimtooth", ORCISH_DAGGER, (SPFX_RESTR | SPFX_WARN | SPFX_DFLAG2), 0, M2_ELF, PHYS(2, 6), NO_DFNS, - NO_CARY, 0, A_CHAOTIC, NON_PM, PM_ORC, 300L, CLR_RED, GRIMTOOTH), + NO_CARY, 0, A_CHAOTIC, NON_PM, PM_ORC, + 0, 5, 300L, CLR_RED, GRIMTOOTH), /* * Orcrist and Sting have same alignment as elves. * @@ -105,56 +131,56 @@ static NEARDATA struct artifact artilist[] = { * Sting and Orcrist will warn of M2_ORC monsters. */ A("Orcrist", ELVEN_BROADSWORD, (SPFX_WARN | SPFX_DFLAG2), 0, M2_ORC, - PHYS(5, 0), NO_DFNS, NO_CARY, 0, A_CHAOTIC, NON_PM, PM_ELF, 2000L, - CLR_BRIGHT_BLUE, ORCRIST), /* bright blue is actually light blue */ + PHYS(5, 0), NO_DFNS, NO_CARY, 0, A_CHAOTIC, NON_PM, PM_ELF, + 3, 4, 2000L, CLR_BRIGHT_BLUE, ORCRIST), /* actually light blue */ A("Sting", ELVEN_DAGGER, (SPFX_WARN | SPFX_DFLAG2), 0, M2_ORC, - PHYS(5, 0), NO_DFNS, NO_CARY, 0, A_CHAOTIC, NON_PM, PM_ELF, 800L, - CLR_BRIGHT_BLUE, STING), + PHYS(5, 0), NO_DFNS, NO_CARY, 0, A_CHAOTIC, NON_PM, PM_ELF, + 3, 1, 800L, CLR_BRIGHT_BLUE, STING), /* * Magicbane is a bit different! Its magic fanfare * unbalances victims in addition to doing some damage. */ A("Magicbane", ATHAME, (SPFX_RESTR | SPFX_ATTK | SPFX_DEFN), 0, 0, STUN(3, 4), DFNS(AD_MAGM), NO_CARY, 0, A_NEUTRAL, PM_WIZARD, NON_PM, - 3500L, NO_COLOR, MAGICBANE), + 0, 7, 3500L, NO_COLOR, MAGICBANE), A("Frost Brand", LONG_SWORD, (SPFX_RESTR | SPFX_ATTK | SPFX_DEFN), 0, 0, - COLD(5, 0), COLD(0, 0), NO_CARY, 0, A_NONE, NON_PM, NON_PM, 3000L, - NO_COLOR, FROST_BRAND), + COLD(5, 0), COLD(0, 0), NO_CARY, 0, A_NONE, NON_PM, NON_PM, + 0, 9, 3000L, NO_COLOR, FROST_BRAND), A("Fire Brand", LONG_SWORD, (SPFX_RESTR | SPFX_ATTK | SPFX_DEFN), 0, 0, - FIRE(5, 0), FIRE(0, 0), NO_CARY, 0, A_NONE, NON_PM, NON_PM, 3000L, - NO_COLOR, FIRE_BRAND), + FIRE(5, 0), FIRE(0, 0), NO_CARY, 0, A_NONE, NON_PM, NON_PM, + 0, 5, 3000L, NO_COLOR, FIRE_BRAND), A("Dragonbane", BROADSWORD, (SPFX_RESTR | SPFX_DCLAS | SPFX_REFLECT), 0, S_DRAGON, - PHYS(5, 0), NO_DFNS, NO_CARY, 0, A_NONE, NON_PM, NON_PM, 500L, - NO_COLOR, DRAGONBANE), + PHYS(5, 0), NO_DFNS, NO_CARY, 0, A_NONE, NON_PM, NON_PM, + 2, 5, 500L, NO_COLOR, DRAGONBANE), A("Demonbane", MACE, (SPFX_RESTR | SPFX_DFLAG2), 0, M2_DEMON, PHYS(5, 0), NO_DFNS, NO_CARY, BANISH, A_LAWFUL, PM_CLERIC, NON_PM, - 2500L, NO_COLOR, DEMONBANE), + 1, 3, 2500L, NO_COLOR, DEMONBANE), A("Werebane", SILVER_SABER, (SPFX_RESTR | SPFX_DFLAG2), 0, M2_WERE, - PHYS(5, 0), DFNS(AD_WERE), NO_CARY, 0, A_NONE, NON_PM, NON_PM, 1500L, - NO_COLOR, WEREBANE), + PHYS(5, 0), DFNS(AD_WERE), NO_CARY, 0, A_NONE, NON_PM, NON_PM, + 1, 4, 1500L, NO_COLOR, WEREBANE), A("Grayswandir", SILVER_SABER, (SPFX_RESTR | SPFX_HALRES), 0, 0, - PHYS(5, 0), NO_DFNS, NO_CARY, 0, A_LAWFUL, NON_PM, NON_PM, 8000L, - NO_COLOR, GRAYSWANDIR), + PHYS(5, 0), NO_DFNS, NO_CARY, 0, A_LAWFUL, NON_PM, NON_PM, + 0, 10, 8000L, NO_COLOR, GRAYSWANDIR), A("Giantslayer", LONG_SWORD, (SPFX_RESTR | SPFX_DFLAG2), 0, M2_GIANT, - PHYS(5, 0), NO_DFNS, NO_CARY, 0, A_NEUTRAL, NON_PM, NON_PM, 200L, - NO_COLOR, GIANTSLAYER), + PHYS(5, 0), NO_DFNS, NO_CARY, 0, A_NEUTRAL, NON_PM, NON_PM, + 2, 4, 200L, NO_COLOR, GIANTSLAYER), A("Ogresmasher", WAR_HAMMER, (SPFX_RESTR | SPFX_DCLAS), 0, S_OGRE, - PHYS(5, 0), NO_DFNS, NO_CARY, 0, A_NONE, NON_PM, NON_PM, 200L, - NO_COLOR, OGRESMASHER), + PHYS(5, 0), NO_DFNS, NO_CARY, 0, A_NONE, NON_PM, NON_PM, + 2, 1, 200L, NO_COLOR, OGRESMASHER), A("Trollsbane", MORNING_STAR, (SPFX_RESTR | SPFX_DCLAS), 0, S_TROLL, - PHYS(5, 0), NO_DFNS, NO_CARY, 0, A_NONE, NON_PM, NON_PM, 200L, - NO_COLOR, TROLLSBANE), + PHYS(5, 0), NO_DFNS, NO_CARY, 0, A_NONE, NON_PM, NON_PM, + 2, 1, 200L, NO_COLOR, TROLLSBANE), /* * Two problems: 1) doesn't let trolls regenerate heads, @@ -162,8 +188,8 @@ static NEARDATA struct artifact artilist[] = { * allowing those at all causes more problems than worth the effort). */ A("Vorpal Blade", LONG_SWORD, (SPFX_RESTR | SPFX_BEHEAD), 0, 0, - PHYS(5, 1), NO_DFNS, NO_CARY, 0, A_NEUTRAL, NON_PM, NON_PM, 4000L, - NO_COLOR, VORPAL_BLADE), + PHYS(5, 1), NO_DFNS, NO_CARY, 0, A_NEUTRAL, NON_PM, NON_PM, + 1, 5, 4000L, NO_COLOR, VORPAL_BLADE), /* * Ah, never shall I forget the cry, @@ -174,33 +200,38 @@ static NEARDATA struct artifact artilist[] = { * (From Sir W.S. Gilbert's "The Mikado") */ A("Snickersnee", KATANA, SPFX_RESTR, 0, 0, PHYS(0, 8), NO_DFNS, NO_CARY, - 0, A_LAWFUL, PM_SAMURAI, NON_PM, 1200L, NO_COLOR, SNICKERSNEE), + 0, A_LAWFUL, PM_SAMURAI, NON_PM, + 0, 8, 1200L, NO_COLOR, SNICKERSNEE), /* Sunsword emits light when wielded (handled in the core rather than via artifact fields), but that light has no particular color */ A("Sunsword", LONG_SWORD, (SPFX_RESTR | SPFX_DFLAG2), 0, M2_UNDEAD, PHYS(5, 0), DFNS(AD_BLND), NO_CARY, BLINDING_RAY, A_LAWFUL, NON_PM, - NON_PM, 1500L, NO_COLOR, SUNSWORD), + NON_PM, + 0, 6, 1500L, NO_COLOR, SUNSWORD), /* * The artifacts for the quest dungeon, all self-willed. + * gen_spe should be 0; gift_value irrelevant and set to 12. */ A("The Orb of Detection", CRYSTAL_BALL, (SPFX_NOGEN | SPFX_RESTR | SPFX_INTEL), (SPFX_ESP | SPFX_HSPDAM), 0, NO_ATTK, NO_DFNS, CARY(AD_MAGM), INVIS, A_LAWFUL, PM_ARCHEOLOGIST, - NON_PM, 2500L, NO_COLOR, ORB_OF_DETECTION), + NON_PM, + 0, 12, 2500L, NO_COLOR, ORB_OF_DETECTION), A("The Heart of Ahriman", LUCKSTONE, (SPFX_NOGEN | SPFX_RESTR | SPFX_INTEL), SPFX_STLTH, 0, /* this stone does double damage if used as a projectile weapon */ PHYS(5, 0), NO_DFNS, NO_CARY, LEVITATION, A_NEUTRAL, PM_BARBARIAN, - NON_PM, 2500L, NO_COLOR, HEART_OF_AHRIMAN), + NON_PM, + 0, 12, 2500L, NO_COLOR, HEART_OF_AHRIMAN), A("The Sceptre of Might", MACE, (SPFX_NOGEN | SPFX_RESTR | SPFX_INTEL | SPFX_DALIGN), 0, 0, PHYS(5, 0), DFNS(AD_MAGM), NO_CARY, CONFLICT, A_LAWFUL, PM_CAVE_DWELLER, NON_PM, - 2500L, NO_COLOR, SCEPTRE_OF_MIGHT), + 0, 12, 2500L, NO_COLOR, SCEPTRE_OF_MIGHT), #if 0 /* OBSOLETE -- from 3.1.0 to 3.2.x, this was quest artifact for the * Elf role; in 3.3.0 elf became a race available to several roles @@ -209,35 +240,37 @@ static NEARDATA struct artifact artilist[] = { A("The Palantir of Westernesse", CRYSTAL_BALL, (SPFX_NOGEN | SPFX_RESTR | SPFX_INTEL), (SPFX_ESP | SPFX_REGEN | SPFX_HSPDAM), 0, - NO_ATTK, NO_DFNS, NO_CARY, TAMING, A_CHAOTIC, NON_PM, PM_ELF, 8000L, - NO_COLOR, PALANTIR_OF_WESTERNESSE), + NO_ATTK, NO_DFNS, NO_CARY, TAMING, A_CHAOTIC, NON_PM, PM_ELF, + 0, 12, 8000L, NO_COLOR, PALANTIR_OF_WESTERNESSE), #endif A("The Staff of Aesculapius", QUARTERSTAFF, (SPFX_NOGEN | SPFX_RESTR | SPFX_ATTK | SPFX_INTEL | SPFX_DRLI | SPFX_REGEN), 0, 0, DRLI(0, 0), DRLI(0, 0), NO_CARY, HEALING, A_NEUTRAL, PM_HEALER, - NON_PM, 5000L, NO_COLOR, STAFF_OF_AESCULAPIUS), + NON_PM, + 0, 12, 5000L, NO_COLOR, STAFF_OF_AESCULAPIUS), A("The Magic Mirror of Merlin", MIRROR, (SPFX_NOGEN | SPFX_RESTR | SPFX_INTEL | SPFX_SPEAK), SPFX_ESP, 0, - NO_ATTK, NO_DFNS, CARY(AD_MAGM), 0, A_LAWFUL, PM_KNIGHT, NON_PM, 1500L, - NO_COLOR, MAGIC_MIRROR_OF_MERLIN), + NO_ATTK, NO_DFNS, CARY(AD_MAGM), 0, A_LAWFUL, PM_KNIGHT, NON_PM, + 0, 12, 1500L, NO_COLOR, MAGIC_MIRROR_OF_MERLIN), A("The Eyes of the Overworld", LENSES, (SPFX_NOGEN | SPFX_RESTR | SPFX_INTEL | SPFX_XRAY), 0, 0, NO_ATTK, DFNS(AD_MAGM), NO_CARY, ENLIGHTENING, A_NEUTRAL, PM_MONK, NON_PM, - 2500L, NO_COLOR, EYES_OF_THE_OVERWORLD), + 0, 12, 2500L, NO_COLOR, EYES_OF_THE_OVERWORLD), A("The Mitre of Holiness", HELM_OF_BRILLIANCE, (SPFX_NOGEN | SPFX_RESTR | SPFX_DFLAG2 | SPFX_INTEL | SPFX_PROTECT), 0, M2_UNDEAD, NO_ATTK, NO_DFNS, CARY(AD_FIRE), ENERGY_BOOST, A_LAWFUL, - PM_CLERIC, NON_PM, 2000L, NO_COLOR, MITRE_OF_HOLINESS), + PM_CLERIC, NON_PM, + 0, 12, 2000L, NO_COLOR, MITRE_OF_HOLINESS), A("The Longbow of Diana", BOW, (SPFX_NOGEN | SPFX_RESTR | SPFX_INTEL | SPFX_REFLECT), SPFX_ESP, 0, PHYS(5, 0), NO_DFNS, NO_CARY, CREATE_AMMO, A_CHAOTIC, PM_RANGER, NON_PM, - 4000L, NO_COLOR, LONGBOW_OF_DIANA), + 0, 12, 4000L, NO_COLOR, LONGBOW_OF_DIANA), /* MKoT has an additional carry property if the Key is not cursed (for rogues) or blessed (for non-rogues): #untrap of doors and chests @@ -245,38 +278,39 @@ static NEARDATA struct artifact artilist[] = { A("The Master Key of Thievery", SKELETON_KEY, (SPFX_NOGEN | SPFX_RESTR | SPFX_INTEL | SPFX_SPEAK), (SPFX_WARN | SPFX_TCTRL | SPFX_HPHDAM), 0, NO_ATTK, NO_DFNS, NO_CARY, - UNTRAP, A_CHAOTIC, PM_ROGUE, NON_PM, 3500L, NO_COLOR, - MASTER_KEY_OF_THIEVERY), + UNTRAP, A_CHAOTIC, PM_ROGUE, NON_PM, + 0, 12, 3500L, NO_COLOR, MASTER_KEY_OF_THIEVERY), A("The Tsurugi of Muramasa", TSURUGI, (SPFX_NOGEN | SPFX_RESTR | SPFX_INTEL | SPFX_BEHEAD | SPFX_LUCK | SPFX_PROTECT), 0, 0, PHYS(0, 8), NO_DFNS, NO_CARY, 0, A_LAWFUL, PM_SAMURAI, NON_PM, - 4500L, NO_COLOR, TSURUGI_OF_MURAMASA), + 0, 12, 4500L, NO_COLOR, TSURUGI_OF_MURAMASA), A("The Platinum Yendorian Express Card", CREDIT_CARD, (SPFX_NOGEN | SPFX_RESTR | SPFX_INTEL | SPFX_DEFN), (SPFX_ESP | SPFX_HSPDAM), 0, NO_ATTK, NO_DFNS, CARY(AD_MAGM), - CHARGE_OBJ, A_NEUTRAL, PM_TOURIST, NON_PM, 7000L, NO_COLOR, - YENDORIAN_EXPRESS_CARD), + CHARGE_OBJ, A_NEUTRAL, PM_TOURIST, NON_PM, + 0, 12, 7000L, NO_COLOR, YENDORIAN_EXPRESS_CARD), A("The Orb of Fate", CRYSTAL_BALL, (SPFX_NOGEN | SPFX_RESTR | SPFX_INTEL | SPFX_LUCK), (SPFX_WARN | SPFX_HSPDAM | SPFX_HPHDAM), 0, NO_ATTK, NO_DFNS, NO_CARY, - LEV_TELE, A_NEUTRAL, PM_VALKYRIE, NON_PM, 3500L, NO_COLOR, - ORB_OF_FATE), + LEV_TELE, A_NEUTRAL, PM_VALKYRIE, NON_PM, + 0, 12, 3500L, NO_COLOR, ORB_OF_FATE), A("The Eye of the Aethiopica", AMULET_OF_ESP, (SPFX_NOGEN | SPFX_RESTR | SPFX_INTEL), (SPFX_EREGEN | SPFX_HSPDAM), 0, NO_ATTK, DFNS(AD_MAGM), NO_CARY, CREATE_PORTAL, A_NEUTRAL, PM_WIZARD, - NON_PM, 4000L, NO_COLOR, EYE_OF_THE_AETHIOPICA), + NON_PM, + 0, 12, 4000L, NO_COLOR, EYE_OF_THE_AETHIOPICA), #if !defined(ARTI_ENUM) && !defined(DUMP_ARTI_ENUM) /* * terminator; otyp must be zero */ - A(0, 0, 0, 0, 0, NO_ATTK, NO_DFNS, NO_CARY, 0, A_NONE, NON_PM, NON_PM, 0L, - NO_COLOR, TERMINATOR) + A(0, 0, 0, 0, 0, NO_ATTK, NO_DFNS, NO_CARY, 0, A_NONE, NON_PM, NON_PM, + 0, 0, 0L, NO_COLOR, TERMINATOR) }; /* artilist[] (or artifact_names[]) */ #endif diff --git a/include/extern.h b/include/extern.h index 9b596197a..931bc1456 100644 --- a/include/extern.h +++ b/include/extern.h @@ -137,7 +137,7 @@ extern void init_artifacts(void); extern void save_artifacts(NHFILE *); extern void restore_artifacts(NHFILE *); extern const char *artiname(int); -extern struct obj *mk_artifact(struct obj *, aligntyp); +extern struct obj *mk_artifact(struct obj *, aligntyp, uchar); extern const char *artifact_name(const char *, short *, boolean) NONNULLARG1; extern boolean exist_artifact(int, const char *) NONNULLPTRS; extern void artifact_exists(struct obj *, const char *, boolean, unsigned) ; diff --git a/src/artifact.c b/src/artifact.c index f31ec5a98..b7cc8b3dc 100644 --- a/src/artifact.c +++ b/src/artifact.c @@ -142,13 +142,16 @@ artiname(int artinum) If no alignment is given, then 'otmp' is converted into an artifact of matching type, or returned as-is if that's not possible. - For the 2nd case, caller should use ``obj = mk_artifact(obj, A_NONE);'' - for the 1st, ``obj = mk_artifact((struct obj *) 0, some_alignment);''. + For the 2nd case, caller should use ``obj = mk_artifact(obj, A_NONE, 99);'' + For the 1st, ``obj = mk_artifact((struct obj *) 0, some_alignment, ...);''. + The max_giftvalue is the value of the sacrifice, for an artifact obtained + by sacrificing, or 99 otherwise. */ struct obj * mk_artifact( - struct obj *otmp, /* existing object; ignored if alignment specified */ - aligntyp alignment) /* target alignment, or A_NONE */ + struct obj *otmp, /* existing object; ignored if alignment specified */ + aligntyp alignment, /* target alignment, or A_NONE */ + uchar max_giftvalue) /* cap on generated giftvalue */ { const struct artifact *a; int m, n, altn; @@ -156,6 +159,7 @@ mk_artifact( short o_typ = (by_align || !otmp) ? 0 : otmp->otyp; boolean unique = !by_align && otmp && objects[o_typ].oc_unique; short eligible[NROFARTIFACTS]; + xint16 skill_compatibility; n = altn = 0; /* no candidates found yet */ eligible[0] = 0; /* lint suppression */ @@ -165,6 +169,8 @@ mk_artifact( continue; if ((a->spfx & SPFX_NOGEN) || unique) continue; + if (a->gift_value > max_giftvalue) + continue; if (!by_align) { /* looking for a particular type of item; not producing a @@ -186,17 +192,33 @@ mk_artifact( n = 1; break; /* skip all other candidates */ } + + /* check if this is skill-compatible */ + skill_compatibility = P_SKILLED; + if (objects[a->otyp].oc_class == WEAPON_CLASS) { + schar skill = objects[a->otyp].oc_skill; + if (skill < 0) + skill_compatibility = P_MAX_SKILL(-skill); + else + skill_compatibility = P_MAX_SKILL(skill); + } + /* found something to consider for random selection */ - if (a->alignment != A_NONE || u.ugifts > 0) { + if ((a->alignment != A_NONE || u.ugifts > 0 || !rn2(3)) && + (!rn2(4) || skill_compatibility >= P_SKILLED || + (skill_compatibility >= P_BASIC && rn2(2)))) { /* right alignment, or non-aligned with at least 1 - previous gift bestowed, makes this one viable */ + previous gift bestowed, makes this one viable; + unaligned artifacts are possible even as the first + gift, but less likely; if it's a bad weapon type + for the role that also makes it less likely */ eligible[n++] = m; } else { - /* non-aligned with no previous gifts; - if no candidates have been found yet, record + /* if no candidates have been found yet, record this one as a[nother] fallback possibility in case all aligned candidates have been used up - (via wishing, naming, bones, random generation) */ + (via wishing, naming, bones, random generation) + or failed the randomized compatibility checks */ if (!n) eligible[altn++] = m; /* [once a regular candidate is found, the list @@ -215,9 +237,20 @@ mk_artifact( a = &artilist[m]; /* make an appropriate object if necessary, then christen it */ - if (by_align) + if (by_align) { + int new_spe; + otmp = mksobj((int) a->otyp, TRUE, FALSE); + /* Adjust otmp->spe by a->gen_spe. (This is a no-op for + non-weapons, which always have a gen_spe of 0, and for many + weapons, too.) The result is clamped into the "normal" range to + prevent an outside chance of +12 artifacts generating. */ + new_spe = (int)otmp->spe + a->gen_spe; + if (new_spe >= -10 && new_spe < 10) + otmp->spe = new_spe; + } + if (otmp) { /* prevent erosion from generating */ otmp->oeroded = otmp->oeroded2 = 0; diff --git a/src/mkobj.c b/src/mkobj.c index 79e088cff..ae26c4430 100644 --- a/src/mkobj.c +++ b/src/mkobj.c @@ -880,7 +880,7 @@ mksobj_init(struct obj *otmp, boolean artif) otmp->opoisoned = 1; if (artif && !rn2(20 + (10 * nartifact_exist()))) - otmp = mk_artifact(otmp, (aligntyp) A_NONE); + otmp = mk_artifact(otmp, (aligntyp) A_NONE, 99); break; case FOOD_CLASS: otmp->oeaten = 0; @@ -1084,7 +1084,7 @@ mksobj_init(struct obj *otmp, boolean artif) } else blessorcurse(otmp, 10); if (artif && !rn2(40 + (10 * nartifact_exist()))) - otmp = mk_artifact(otmp, (aligntyp) A_NONE); + otmp = mk_artifact(otmp, (aligntyp) A_NONE, 99); /* simulate lacquered armor for samurai */ if (Role_if(PM_SAMURAI) && otmp->otyp == SPLINT_MAIL && (svm.moves <= 1 || In_quest(&u.uz))) { @@ -1230,7 +1230,7 @@ mksobj(int otyp, boolean init, boolean artif) /* unique objects may have an associated artifact entry */ if (objects[otyp].oc_unique && !otmp->oartifact) - otmp = mk_artifact(otmp, (aligntyp) A_NONE); + otmp = mk_artifact(otmp, (aligntyp) A_NONE, 99); otmp->owt = weight(otmp); return otmp; } diff --git a/src/mplayer.c b/src/mplayer.c index a422de3ca..acccaf31c 100644 --- a/src/mplayer.c +++ b/src/mplayer.c @@ -262,7 +262,7 @@ mk_mplayer(struct permonst *ptr, coordxy x, coordxy y, boolean special) else if (!rn2(2)) otmp->greased = 1; if (special && rn2(2)) - otmp = mk_artifact(otmp, A_NONE); + otmp = mk_artifact(otmp, A_NONE, 99); /* usually increase stack size if stackable weapon */ if (objects[otmp->otyp].oc_merge && !otmp->oartifact && monmightthrowwep(otmp)) diff --git a/src/pray.c b/src/pray.c index 7099cddff..2fde3727f 100644 --- a/src/pray.c +++ b/src/pray.c @@ -27,7 +27,7 @@ staticfn void offer_negative_valued(boolean, aligntyp); staticfn void offer_fake_amulet(struct obj *, boolean, aligntyp); staticfn void offer_different_alignment_altar(struct obj *, aligntyp); staticfn void sacrifice_your_race(struct obj *, boolean, aligntyp); -staticfn int bestow_artifact(void); +staticfn int bestow_artifact(uchar); staticfn int sacrifice_value(struct obj *); staticfn int eval_offering(struct obj *, aligntyp); staticfn void offer_corpse(struct obj *, boolean, aligntyp); @@ -1777,17 +1777,24 @@ sacrifice_your_race( } staticfn int -bestow_artifact(void) +bestow_artifact(uchar max_giftvalue) { int nartifacts = nartifact_exist(); + boolean do_bestow = u.ulevel > 2 && u.uluck >= 0; + if (do_bestow) { + /* you were already in pretty good standing */ + /* The player can gain an artifact */ + /* The chance goes down as the number of artifacts goes up */ + if (wizard) + do_bestow = y_n("Gift an artifact?"); + else + do_bestow = !rn2(6 + (2 * u.ugifts * nartifacts)); + } - /* you were already in pretty good standing */ - /* The player can gain an artifact */ - /* The chance goes down as the number of artifacts goes up */ - if (u.ulevel > 2 && u.uluck >= 0 - && !rn2(10 + (2 * u.ugifts * nartifacts))) { + if (do_bestow) { struct obj *otmp; - otmp = mk_artifact((struct obj *) 0, a_align(u.ux, u.uy)); + otmp = mk_artifact((struct obj *) 0, a_align(u.ux, u.uy), + max_giftvalue); if (otmp) { char buf[BUFSZ]; @@ -2078,7 +2085,7 @@ offer_corpse(struct obj *otmp, boolean highaltar, aligntyp altaralign) } } else { int saved_luck = u.uluck; - if (bestow_artifact()) + if (bestow_artifact(value)) return; change_luck((value * LUCKMAX) / (MAXVALUE * 2)); if ((int) u.uluck < 0) From c2c797fa357bef663fa3d962850196350a9cdb3b Mon Sep 17 00:00:00 2001 From: Alex Smith Date: Thu, 12 Dec 2024 03:37:02 +0000 Subject: [PATCH 173/791] Artifact and #offer rebalance, part 2: luck from sacrificing Luck from sacrificing is now limited by the value of the sacrifice. This fixes two exploits, both of which rely on getting luck up to maximum as soon as you have an altar, a luckstone, and a few rations, via altar-camping until you accumulate enough luck. One of them is to use the resulting luck to throw off the balance of combat via using it to make hit chance calculations irrelevant. The other is to use it to get crowned early in the game; in particular, getting crowned pre-Sokoban is often viable and, especially for chaotic characters, solves most of the game's difficulty at that point (because the intrinisics and weapon are enough to carry a character to the Castle given even mediocre luck with finding armor). After this commit, becoming crowned very early in the game is more difficult (likely requiring unicorns and identified gems), and the hit chance gain from luck becomes a more gradual gain over the course of the game rather than all happening immediately upon finding the altar and luckstone. In addition to making the game more balanced, this also discourages grinding by reducing the incentive for altar-camping, so it will hopefully make it more fun as well. --- doc/fixes3-7-0.txt | 1 + src/pray.c | 20 +++++++++++++++++--- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index 3ff0cb864..13c61a938 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -1490,6 +1490,7 @@ artifact gifts are rebalanced (easier to obtain; higher-value sacrifices are needed for higher-value artifacts; lower-value artifacts are usually gifted enchanted; unaligned artifacts are possible but rare even on the first gift; artifacts you can't use well are less likely) +luck gains from sacrificing are limited by the value of the sacrifice Fixes to 3.7.0-x General Problems Exposed Via git Repository diff --git a/src/pray.c b/src/pray.c index 2fde3727f..f9312daf2 100644 --- a/src/pray.c +++ b/src/pray.c @@ -2084,13 +2084,27 @@ offer_corpse(struct obj *otmp, boolean highaltar, aligntyp altaralign) } } } else { - int saved_luck = u.uluck; + int orig_luck, luck_increase; + if (bestow_artifact(value)) return; - change_luck((value * LUCKMAX) / (MAXVALUE * 2)); + + orig_luck = u.uluck; + luck_increase = (value * LUCKMAX) / (MAXVALUE * 2); + + /* sacrificing can't increase non-bonus Luck to above the value of the + sacrifice; this prevents players immediately maxing their Luck as + soon as they find an altar and a few rations via sacrificing lots + of low-valued corpses, which can unbalance the early game */ + if (orig_luck > value) + luck_increase = 0; + else if (orig_luck + luck_increase > value) + luck_increase = value - orig_luck; + + change_luck(luck_increase); if ((int) u.uluck < 0) u.uluck = 0; - if (u.uluck != saved_luck) { + if (u.uluck != orig_luck) { if (Blind) You("think %s brushed your %s.", something, body_part(FOOT)); From 9768677f91126013582e63dce57aa39fbe1fd717 Mon Sep 17 00:00:00 2001 From: PatR Date: Wed, 11 Dec 2024 20:53:08 -0800 Subject: [PATCH 174/791] comment tweak --- src/mhitm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mhitm.c b/src/mhitm.c index 3ea3b3643..c92cb7d40 100644 --- a/src/mhitm.c +++ b/src/mhitm.c @@ -531,7 +531,7 @@ mattackm( * * That impacts pet use of ranged attacks. It's rather arbitrary * but various parts of the code assume it to be the case, not to - * mention a part of player strategy when fighting dragons. + * mention a part of player tactics when fighting dragons. */ if (!monnear(magr, mdef->mx, mdef->my)) { int mmtmp = ((mattk->aatyp == AT_BREA) From 3d8081c748fbfc4b5628a1af6f19432a53bc269f Mon Sep 17 00:00:00 2001 From: Alex Smith Date: Thu, 12 Dec 2024 06:58:43 +0000 Subject: [PATCH 175/791] Bugfixes for the recent artifact gifting changes --- src/artifact.c | 2 +- src/pray.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/artifact.c b/src/artifact.c index b7cc8b3dc..9537df732 100644 --- a/src/artifact.c +++ b/src/artifact.c @@ -169,7 +169,7 @@ mk_artifact( continue; if ((a->spfx & SPFX_NOGEN) || unique) continue; - if (a->gift_value > max_giftvalue) + if (a->gift_value > max_giftvalue && !Role_if(a->role)) continue; if (!by_align) { diff --git a/src/pray.c b/src/pray.c index f9312daf2..c47e42f6d 100644 --- a/src/pray.c +++ b/src/pray.c @@ -1786,7 +1786,7 @@ bestow_artifact(uchar max_giftvalue) /* The player can gain an artifact */ /* The chance goes down as the number of artifacts goes up */ if (wizard) - do_bestow = y_n("Gift an artifact?"); + do_bestow = y_n("Gift an artifact?") == 'y'; else do_bestow = !rn2(6 + (2 * u.ugifts * nartifacts)); } From 3491535548f03813014b294a575470707a4733fd Mon Sep 17 00:00:00 2001 From: Alex Smith Date: Thu, 12 Dec 2024 07:35:50 +0000 Subject: [PATCH 176/791] More bugfixes for the recent artifact gifting changes --- include/extern.h | 2 +- src/artifact.c | 9 +++++---- src/mkobj.c | 6 +++--- src/mplayer.c | 2 +- src/pray.c | 2 +- 5 files changed, 11 insertions(+), 10 deletions(-) diff --git a/include/extern.h b/include/extern.h index 931bc1456..8eeaf7010 100644 --- a/include/extern.h +++ b/include/extern.h @@ -137,7 +137,7 @@ extern void init_artifacts(void); extern void save_artifacts(NHFILE *); extern void restore_artifacts(NHFILE *); extern const char *artiname(int); -extern struct obj *mk_artifact(struct obj *, aligntyp, uchar); +extern struct obj *mk_artifact(struct obj *, aligntyp, uchar, boolean); extern const char *artifact_name(const char *, short *, boolean) NONNULLARG1; extern boolean exist_artifact(int, const char *) NONNULLPTRS; extern void artifact_exists(struct obj *, const char *, boolean, unsigned) ; diff --git a/src/artifact.c b/src/artifact.c index 9537df732..446e4ab95 100644 --- a/src/artifact.c +++ b/src/artifact.c @@ -151,7 +151,8 @@ struct obj * mk_artifact( struct obj *otmp, /* existing object; ignored if alignment specified */ aligntyp alignment, /* target alignment, or A_NONE */ - uchar max_giftvalue) /* cap on generated giftvalue */ + uchar max_giftvalue, /* cap on generated giftvalue */ + boolean adjust_spe) /* whether to add spe to situational artifacts */ { const struct artifact *a; int m, n, altn; @@ -237,10 +238,10 @@ mk_artifact( a = &artilist[m]; /* make an appropriate object if necessary, then christen it */ - if (by_align) { - int new_spe; + otmp = mksobj((int) a->otyp, TRUE, FALSE); - otmp = mksobj((int) a->otyp, TRUE, FALSE); + if (adjust_spe) { + int new_spe; /* Adjust otmp->spe by a->gen_spe. (This is a no-op for non-weapons, which always have a gen_spe of 0, and for many diff --git a/src/mkobj.c b/src/mkobj.c index ae26c4430..e332502bd 100644 --- a/src/mkobj.c +++ b/src/mkobj.c @@ -880,7 +880,7 @@ mksobj_init(struct obj *otmp, boolean artif) otmp->opoisoned = 1; if (artif && !rn2(20 + (10 * nartifact_exist()))) - otmp = mk_artifact(otmp, (aligntyp) A_NONE, 99); + otmp = mk_artifact(otmp, (aligntyp) A_NONE, 99, TRUE); break; case FOOD_CLASS: otmp->oeaten = 0; @@ -1084,7 +1084,7 @@ mksobj_init(struct obj *otmp, boolean artif) } else blessorcurse(otmp, 10); if (artif && !rn2(40 + (10 * nartifact_exist()))) - otmp = mk_artifact(otmp, (aligntyp) A_NONE, 99); + otmp = mk_artifact(otmp, (aligntyp) A_NONE, 99, TRUE); /* simulate lacquered armor for samurai */ if (Role_if(PM_SAMURAI) && otmp->otyp == SPLINT_MAIL && (svm.moves <= 1 || In_quest(&u.uz))) { @@ -1230,7 +1230,7 @@ mksobj(int otyp, boolean init, boolean artif) /* unique objects may have an associated artifact entry */ if (objects[otyp].oc_unique && !otmp->oartifact) - otmp = mk_artifact(otmp, (aligntyp) A_NONE, 99); + otmp = mk_artifact(otmp, (aligntyp) A_NONE, 99, FALSE); otmp->owt = weight(otmp); return otmp; } diff --git a/src/mplayer.c b/src/mplayer.c index acccaf31c..9e839b8fd 100644 --- a/src/mplayer.c +++ b/src/mplayer.c @@ -262,7 +262,7 @@ mk_mplayer(struct permonst *ptr, coordxy x, coordxy y, boolean special) else if (!rn2(2)) otmp->greased = 1; if (special && rn2(2)) - otmp = mk_artifact(otmp, A_NONE, 99); + otmp = mk_artifact(otmp, A_NONE, 99, FALSE); /* usually increase stack size if stackable weapon */ if (objects[otmp->otyp].oc_merge && !otmp->oartifact && monmightthrowwep(otmp)) diff --git a/src/pray.c b/src/pray.c index c47e42f6d..827b03226 100644 --- a/src/pray.c +++ b/src/pray.c @@ -1794,7 +1794,7 @@ bestow_artifact(uchar max_giftvalue) if (do_bestow) { struct obj *otmp; otmp = mk_artifact((struct obj *) 0, a_align(u.ux, u.uy), - max_giftvalue); + max_giftvalue, TRUE); if (otmp) { char buf[BUFSZ]; From 1b607d1757d7a7255543b56b9c4bcb302fe2cb56 Mon Sep 17 00:00:00 2001 From: nhmall Date: Thu, 12 Dec 2024 17:02:37 -0500 Subject: [PATCH 177/791] deal with some MSYS2 warnings --- src/pline.c | 1 + sys/windows/GNUmakefile | 5 +++-- sys/windows/windsys.c | 30 +++++++++++++++++++++--------- 3 files changed, 25 insertions(+), 11 deletions(-) diff --git a/src/pline.c b/src/pline.c index 8163a1d9b..bb9e3c4c0 100644 --- a/src/pline.c +++ b/src/pline.c @@ -665,6 +665,7 @@ execplinehandler(const char *line) args[1] = line; args[2] = NULL; ret = _spawnv(_P_NOWAIT, sysopt.msghandler, args); + nhUse(ret); /* -Wunused-but-set-variable */ } #else use_pline_handler = FALSE; diff --git a/sys/windows/GNUmakefile b/sys/windows/GNUmakefile index bd2d71d2b..be037485a 100644 --- a/sys/windows/GNUmakefile +++ b/sys/windows/GNUmakefile @@ -339,13 +339,14 @@ ifeq "$(GCC_EXTRA_WARNINGS)" "Y" # # These match the warnings enabled on the linux.370 and macOS.370 hints builds # -CFLAGSXTRA = -Wall -Wextra -Wreturn-type -Wunused -Wformat -Wswitch -Wshadow \ +CFLAGSXTRA = -Wall -Wextra -Wreturn-type -Wunused -Wswitch -Wshadow \ -Wwrite-strings -pedantic -Wmissing-declarations \ -Wformat-nonliteral -Wunreachable-code -Wimplicit \ -Wimplicit-function-declaration -Wimplicit-int \ -Wmissing-prototypes -Wold-style-definition \ -Wstrict-prototypes -Wnonnull -Wformat-overflow \ - -Wmissing-parameter-type -Wimplicit-fallthrough + -Wmissing-parameter-type -Wimplicit-fallthrough \ + -Wno-cast-function-type CPPFLAGSXTRA = -Wall -Wextra -Wno-missing-field-initializers -Wreturn-type \ -Wunused -Wformat -Wswitch -Wshadow -Wwrite-strings -pedantic \ diff --git a/sys/windows/windsys.c b/sys/windows/windsys.c index 5f1a2a5ab..93d7f5f58 100644 --- a/sys/windows/windsys.c +++ b/sys/windows/windsys.c @@ -53,10 +53,11 @@ int redirect_stdout; #ifdef WIN32CON typedef HWND(WINAPI *GETCONSOLEWINDOW)(void); -#ifdef WIN32CON +#if 0 static HWND GetConsoleHandle(void); static HWND GetConsoleHwnd(void); -#endif +#endif /* 0 */ +#endif /* WIN32CON */ #if !defined(TTY_GRAPHICS) extern void backsp(void); #endif @@ -78,7 +79,6 @@ static int max_filename(void); int def_kbhit(void); int (*nt_kbhit)(void) = def_kbhit; -#endif /* WIN32CON */ #ifndef WIN32CON /* this is used as a printf() replacement when the window @@ -92,7 +92,7 @@ VA_DECL(const char *, fmt) VA_END(); return; } -#endif +#endif /* WIN32CON */ char switchar(void) @@ -328,6 +328,7 @@ interject_assistance(int num, int interjection_type, genericptr_t ptr1, genericp } } break; } + nhUse(interjection_type); } void @@ -412,6 +413,7 @@ void port_insert_pastebuf(char *buf) } #ifdef WIN32CON +#if 0 static HWND GetConsoleHandle(void) { @@ -451,8 +453,9 @@ GetConsoleHwnd(void) /* printf("%d iterations\n", iterations); */ return hwndFound; } +#endif /* 0 */ #endif /* WIN32CON */ -#endif +#endif /* RUNTIME_PASTEBUF_SUPPORT */ #ifdef RUNTIME_PORT_ID /* @@ -748,7 +751,7 @@ sys_random_seed(void) time_t datetime = 0; const char *emsg; - if (status == STATUS_NOT_FOUND) + if (status == (NTSTATUS) STATUS_NOT_FOUND) emsg = "BCRYPT_RNG_ALGORITHM not avail, falling back"; else emsg = "Other failure than algorithm not avail"; @@ -796,11 +799,11 @@ struct CRctxt { } ctxp_ = { NULL, NULL, NULL, 0, 0, 0, NULL, 0 }; struct CRctxt *ctxp = &ctxp_; // XXX should this now be in gc.* ? -#define win32err(fn) errname = fn; goto error +#define win32err(fn) errname = (char *) fn; goto error int win32_cr_helper(char cmd, struct CRctxt *contextp, void *p, int d){ - char *errname = "unknown"; + char *errname = (char *) "unknown"; switch (cmd) { default: /* Not panic - we don't want to upgrade an impossible to a @@ -960,8 +963,17 @@ printf("E2: M=%s e=%d\n",msg,errnum); } #endif +#ifdef USE_BACKTRACE +#define USED_IF_BACKTRACE +#else +#define USED_IF_BACKTRACE UNUSED +#endif + int -win32_cr_gettrace(int maxframes, char *out, int outsize){ +win32_cr_gettrace(int maxframes USED_IF_BACKTRACE, + char *out USED_IF_BACKTRACE, + int outsize USED_IF_BACKTRACE) +{ #ifdef USE_BACKTRACE userstate.error_count = 0; userstate.good_count = 0; From 8bb764e624aa228ce2a5374739408ed81b77d40e Mon Sep 17 00:00:00 2001 From: nhmall Date: Thu, 12 Dec 2024 17:06:12 -0500 Subject: [PATCH 178/791] follow-up: leading tab to spaces --- src/pline.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pline.c b/src/pline.c index bb9e3c4c0..2e0257284 100644 --- a/src/pline.c +++ b/src/pline.c @@ -665,7 +665,7 @@ execplinehandler(const char *line) args[1] = line; args[2] = NULL; ret = _spawnv(_P_NOWAIT, sysopt.msghandler, args); - nhUse(ret); /* -Wunused-but-set-variable */ + nhUse(ret); /* -Wunused-but-set-variable */ } #else use_pline_handler = FALSE; From c7276bcf6747a8449b4219cabf511ec469e97ce0 Mon Sep 17 00:00:00 2001 From: nhmall Date: Thu, 12 Dec 2024 22:35:38 -0500 Subject: [PATCH 179/791] more MSYS2 warning clean-up --- sys/windows/GNUmakefile | 4 +- sys/windows/consoletty.c | 217 +++++++++++++++++++++++---------------- win/win32/NetHackW.c | 4 +- win/win32/mhdlg.c | 14 ++- win/win32/mhdlg.h | 2 +- win/win32/mhmain.c | 14 ++- win/win32/mhmap.c | 1 + win/win32/mhmenu.c | 5 +- win/win32/mhmsgwnd.c | 4 +- win/win32/mhrip.c | 1 + win/win32/mhsplash.c | 1 + win/win32/mhstatus.c | 8 +- win/win32/mhstatus.h | 2 + win/win32/mswproc.c | 93 +++++++++-------- win/win32/winMS.h | 13 ++- 15 files changed, 227 insertions(+), 156 deletions(-) diff --git a/sys/windows/GNUmakefile b/sys/windows/GNUmakefile index be037485a..f38aaf4f6 100644 --- a/sys/windows/GNUmakefile +++ b/sys/windows/GNUmakefile @@ -341,12 +341,12 @@ ifeq "$(GCC_EXTRA_WARNINGS)" "Y" # CFLAGSXTRA = -Wall -Wextra -Wreturn-type -Wunused -Wswitch -Wshadow \ -Wwrite-strings -pedantic -Wmissing-declarations \ - -Wformat-nonliteral -Wunreachable-code -Wimplicit \ + -Wunreachable-code -Wimplicit \ -Wimplicit-function-declaration -Wimplicit-int \ -Wmissing-prototypes -Wold-style-definition \ -Wstrict-prototypes -Wnonnull -Wformat-overflow \ -Wmissing-parameter-type -Wimplicit-fallthrough \ - -Wno-cast-function-type + -Wno-cast-function-type -Wno-format CPPFLAGSXTRA = -Wall -Wextra -Wno-missing-field-initializers -Wreturn-type \ -Wunused -Wformat -Wswitch -Wshadow -Wwrite-strings -pedantic \ diff --git a/sys/windows/consoletty.c b/sys/windows/consoletty.c index 772079deb..32892f864 100644 --- a/sys/windows/consoletty.c +++ b/sys/windows/consoletty.c @@ -97,11 +97,27 @@ cell_t clear_cell = { CONSOLE_CLEAR_CHARACTER, CONSOLE_CLEAR_ATTRIBUTE }; cell_t undefined_cell = { CONSOLE_UNDEFINED_CHARACTER, CONSOLE_UNDEFINED_ATTRIBUTE }; #else /* VIRTUAL_TERMINAL_SEQUENCES */ -cell_t clear_cell = { { CONSOLE_CLEAR_CHARACTER, 0, 0, 0, 0, 0, 0 }, - CONSOLE_CLEAR_CHARACTER, 0, 0L, 0, "\x1b[0m", 0 }; -cell_t undefined_cell = { { CONSOLE_UNDEFINED_CHARACTER, 0, 0, 0, 0, 0, 0 }, - CONSOLE_UNDEFINED_CHARACTER, 0, 0L, 0, (const char *) 0 }; +cell_t clear_cell = { + { CONSOLE_CLEAR_CHARACTER, 0, 0, 0, 0, 0, 0 }, + CONSOLE_CLEAR_CHARACTER, /* wcharacter */ + 0, /* attr */ + 0L, /* color24 */ + 0, /* color256idx */ + "\x1b[0m", /* bkcolorseq */ + 0 /* colorseq */ +}; +cell_t undefined_cell = { + { CONSOLE_UNDEFINED_CHARACTER, 0, 0, 0, 0, 0, 0 }, + CONSOLE_UNDEFINED_CHARACTER, /* wcharacter */ + 0, /* attr */ + 0L, /* color24 */ + 0, /* color256idx */ + (const char *) 0, /* bkcolorseq */ + (const char *) 0 /* colorseq */ +}; +#if 0 static const uint8 empty_utf8str[MAX_UTF8_SEQUENCE] = { 0 }; +#endif #endif /* VIRTUAL_TERMINAL_SEQUENCES */ /* @@ -135,7 +151,9 @@ int process_keystroke(INPUT_RECORD *, boolean *, boolean numberpad, static void init_ttycolor(void); static void really_move_cursor(void); static void check_and_set_font(void); +#ifndef VIRTUAL_TERMINAL_SEQUENCES static boolean check_font_widths(void); +#endif static void set_known_good_console_font(void); static void restore_original_console_font(void); extern void safe_routines(void); @@ -150,7 +168,7 @@ static void free_custom_colors(void); /* Win32 Screen buffer,coordinate,console I/O information */ COORD ntcoord; -INPUT_RECORD ir; +INPUT_RECORD gbl_ir; static boolean orig_QuickEdit; /* Support for changing console font if existing glyph widths are too wide */ @@ -213,11 +231,11 @@ struct console_t { 0, /* current_nhcolor */ 0, /* current_nhbkcolor */ 0, /* current_colorflags */ - {FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE}, - {0, 0}, /* cursor */ + { FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, + { 0, 0 }, /* cursor */ NULL, /* hConOut*/ NULL, /* hConIn */ - { 0 }, /* cbsi */ + { { 0, 0}, { 0, 0}, 0, { 0, 0, 0, 0 }, { 0, 0 } }, /* cbsi */ 0, /* width */ 0, /* height */ FALSE, /* has_unicode */ @@ -242,7 +260,9 @@ struct console_t { #endif /* VIRTUAL_TERMINAL_SEQUENCES */ }; +#if 0 static const char default_name[] = "default"; +#endif const char *const legal_key_handling[] = { "none", "default", @@ -282,7 +302,10 @@ struct keyboard_handling_t { default_checkinput }; -static DWORD ccount, acount; +static DWORD ccount; +#if 0 +static DWORD acount; +#endif #ifndef CLR_MAX #define CLR_MAX 16 #endif @@ -292,7 +315,9 @@ int ttycolors_inv[CLR_MAX]; #define MAX_OVERRIDES 256 unsigned char key_overrides[MAX_OVERRIDES]; +#if 0 static char nullstr[] = ""; +#endif char erase_char, kill_char; #define DEFTEXTCOLOR ttycolors[7] static INPUT_RECORD bogus_key; @@ -470,7 +495,17 @@ struct rgbvalues { { 138, "white", "#FFFFFF", 255, 255, 255 }, }; -long +void buffer_fill_to_end(cell_t * buffer, cell_t * fill, int x, int y); +void buffer_write(cell_t * buffer, cell_t * cell, COORD pos); +static long rgbtable_to_long(struct rgbvalues *); +void term_start_256color(int idx); +void set_cp_map(void); +#ifdef PORT_DEBUG +void win32con_debug_keystrokes(void); +void win32con_toggle_cursor_info(void); +#endif + +static long rgbtable_to_long(struct rgbvalues *tbl) { long rgblong = (tbl->r << 0) | (tbl->gn << 8) | (tbl->b << 16); @@ -595,7 +630,7 @@ void emit_start_256color(int u256coloridx); void emit_default_color(void); void emit_return_to_default(void); void emit_hide_cursor(void); -void emit_show_curor(void); +void emit_show_cursor(void); void emit_hide_cursor(void) @@ -730,7 +765,7 @@ emit_stop_inverse(void) #define tcfmtstr24bit "\x1b[38:2:%ld:%ld:%ldm" #define tcfmtstr256 "\x1b[38:5:%dm" #endif - + void emit_start_256color(int u256coloridx) { @@ -773,12 +808,14 @@ emit_return_to_default(void) WriteConsoleA(console.hConOut, (LPCSTR) escseq, (int) strlen(escseq), &unused, NULL); } +#if 0 static boolean newattr_on = TRUE; +#endif static boolean color24_on = TRUE; /* for debugging */ WORD what_is_there_now; -BOOL success; +//BOOL success; DWORD error_result; #endif /* VIRTUAL_TERMINAL_SEQUENCES */ @@ -880,7 +917,7 @@ back_buffer_flip(void) (int) strlen(back->bkcolorseq), &unused, NULL); } - if ((did_anything | (did_colorseq | did_bkcolorseq | did_color24)) == 0) { + if ((did_anything & (did_colorseq | did_bkcolorseq | did_color24)) == 0) { did_anything &= ~(did_bkcolorseq | did_color24); did_anything |= did_colorseq; emit_default_color(); @@ -1050,7 +1087,7 @@ tty_startup(int *wid, int *hgt) } void -tty_number_pad(int state) +tty_number_pad(int state UNUSED) { // do nothing } @@ -1088,6 +1125,7 @@ CtrlHandler(DWORD ctrltype) case CTRL_BREAK_EVENT: term_clear_screen(); FALLTHROUGH; + /* FALLTHRU */ case CTRL_CLOSE_EVENT: case CTRL_LOGOFF_EVENT: case CTRL_SHUTDOWN_EVENT: @@ -1106,7 +1144,7 @@ CtrlHandler(DWORD ctrltype) /* called by pcmain() and process_options() */ void -consoletty_open(int mode) +consoletty_open(int mode UNUSED) { int debugvar; @@ -1124,6 +1162,7 @@ consoletty_open(int mode) CO = console.width; really_move_cursor(); + nhUse(debugvar); } void @@ -1165,7 +1204,7 @@ process_keystroke( int consoletty_kbhit(void) { - return keyboard_handling.pNHkbhit(console.hConIn, &ir); + return keyboard_handling.pNHkbhit(console.hConIn, &gbl_ir); } int @@ -1174,20 +1213,20 @@ tgetch(void) int mod; coord cc; DWORD count; - boolean numpad = iflags.num_pad; + uchar numberpad = iflags.num_pad; really_move_cursor(); if (iflags.debug_fuzzer) return randomkey(); #ifdef QWERTZ_SUPPORT if (gc.Cmd.swap_yz) - numpad |= 0x10; + numberpad |= 0x10; #endif return (program_state.done_hup) ? '\033' : keyboard_handling.pCheckInput( - console.hConIn, &ir, &count, numpad, 0, &mod, &cc); + console.hConIn, &gbl_ir, &count, numberpad, 0, &mod, &cc); } int @@ -1196,7 +1235,7 @@ console_poskey(coordxy *x, coordxy *y, int *mod) int ch; coord cc = { 0, 0 }; DWORD count; - boolean numpad = iflags.num_pad; + boolean numberpad = iflags.num_pad; really_move_cursor(); if (iflags.debug_fuzzer) { @@ -1210,14 +1249,14 @@ console_poskey(coordxy *x, coordxy *y, int *mod) } #ifdef QWERTZ_SUPPORT if (gc.Cmd.swap_yz) - numpad |= 0x10; + numberpad |= 0x10; #endif ch = (program_state.done_hup) ? '\033' : keyboard_handling.pCheckInput( - console.hConIn, &ir, &count, numpad, 1, mod, &cc); + console.hConIn, &gbl_ir, &count, numberpad, 1, mod, &cc); #ifdef QWERTZ_SUPPORT - numpad &= ~0x10; + numberpad &= ~0x10; #endif if (!ch) { *x = cc.x; @@ -1245,9 +1284,11 @@ really_move_cursor(void) if (GetConsoleTitle(oldtitle, BUFSZ)) { oldtitle[39] = '\0'; } - Sprintf(newtitle, "%-55s tty=(%02d,%02d) consoletty=(%02d,%02d)", oldtitle, - ttyDisplay->curx, ttyDisplay->cury, - console.cursor.X, console.cursor.Y); + Snprintf(newtitle, sizeof newtitle, + "%-55s tty=(%02d,%02d) consoletty=(%02d,%02d)", + oldtitle, + ttyDisplay->curx, ttyDisplay->cury, + console.cursor.X, console.cursor.Y); (void) SetConsoleTitle(newtitle); } #endif @@ -1315,7 +1356,7 @@ xputc(int ch) #ifndef VIRTUAL_TERMINAL_SEQUENCES void -xputc_core(char ch) +xputc_core(char ch) #else void xputc_core(int ch) @@ -1423,27 +1464,25 @@ xputc_core(int ch) void g_putch(int in_ch) { + unsigned char ch; + cell_t cell; #ifndef VIRTUAL_TERMINAL_SEQUENCES boolean inverse = FALSE; #else /* VIRTUAL_TERMINAL_SEQUENCES */ - int ccount = 0; + ccount = 0; WCHAR wch[2]; + boolean usemap = (in_ch >= 0 && in_ch < SIZE(console.cpMap)); #endif /* VIRTUAL_TERMINAL_SEQUENCES */ - unsigned char ch = (unsigned char) in_ch; + ch = (unsigned char) in_ch; set_console_cursor(ttyDisplay->curx, ttyDisplay->cury); #ifndef VIRTUAL_TERMINAL_SEQUENCES - inverse = (console.current_nhattr[ATR_INVERSE] && iflags.wc_inverse); console.attr = (console.current_nhattr[ATR_INVERSE] && iflags.wc_inverse) ? ttycolors_inv[console.current_nhcolor] : ttycolors[console.current_nhcolor]; if (console.current_nhattr[ATR_BOLD]) console.attr |= (inverse) ? BACKGROUND_INTENSITY : FOREGROUND_INTENSITY; - -#endif /* ! VIRTUAL_TERMINAL_SEQUENCES */ - cell_t cell; -#ifndef VIRTUAL_TERMINAL_SEQUENCES cell.attribute = console.attr; cell.character = (console.has_unicode ? cp437[ch] : ch); #else @@ -1454,7 +1493,7 @@ g_putch(int in_ch) cell.color256idx = 0; wch[1] = 0; if (console.has_unicode) { - wch[0] = (ch >= 0 && ch < SIZE(console.cpMap)) ? console.cpMap[ch] : ch; + wch[0] = (usemap) ? console.cpMap[ch] : ch; #ifdef UTF8_FROM_CORE if (SYMHANDLING(H_UTF8)) { /* we have to convert it to UTF-8 for cell.utf8str */ @@ -1476,7 +1515,7 @@ g_putch(int in_ch) cell.utf8str[1] = 0; ccount = 2; } -#endif +#endif /* VIRTUAL_TERMINAL_SEQUENCES */ buffer_write(console.back_buffer, &cell, console.cursor); } @@ -1522,10 +1561,10 @@ term_start_extracolor(uint32 nhcolor, uint16 color256idx) term_start_color(console.current_nhcolor); #ifdef VIRTUAL_TERMINAL_SEQUENCES } -#endif +#endif } -void term_start_256color(int idx) +void term_start_256color(int idx UNUSED) { } @@ -1542,7 +1581,7 @@ term_end_extracolor(void) void cl_end(void) { - if (ttyDisplay->curx < console.width + if (ttyDisplay->curx < console.width && ttyDisplay->cury < console.height) { set_console_cursor(ttyDisplay->curx, ttyDisplay->cury); buffer_clear_to_end_of_line(console.back_buffer, console.cursor.X, @@ -1652,6 +1691,7 @@ tty_delay_output(void) while (goal > clock()) { k = junk; /* Do nothing */ } + nhUse(k); } /* @@ -2044,9 +2084,9 @@ win32con_debug_keystrokes(void) xputs("\n"); while (!valid || ch != 27) { nocmov(ttyDisplay->curx, ttyDisplay->cury); - ReadConsoleInput(console.hConIn, &ir, 1, &count); - if ((ir.EventType == KEY_EVENT) && ir.Event.KeyEvent.bKeyDown) - ch = process_keystroke(&ir, &valid, iflags.num_pad, 1); + ReadConsoleInput(console.hConIn, &gbl_ir, 1, &count); + if ((gbl_ir.EventType == KEY_EVENT) && gbl_ir.Event.KeyEvent.bKeyDown) + ch = process_keystroke(&gbl_ir, &valid, iflags.num_pad, 1); } (void) doredraw(); } @@ -2090,7 +2130,7 @@ map_subkeyvalue(char *op) key_overrides[idx] = val; } - +#if 0 /* fatal error */ /*VARARGS1*/ void consoletty_error @@ -2109,6 +2149,7 @@ VA_DECL(const char *, s) VA_END(); exit(EXIT_FAILURE); } +#endif void synch_cursor(void) @@ -2116,13 +2157,16 @@ synch_cursor(void) really_move_cursor(); } +#ifndef VIRTUAL_TERMINAL_SEQUENCES static int CALLBACK EnumFontCallback( - const LOGFONTW * lf, const TEXTMETRICW * tm, DWORD fontType, LPARAM lParam) + const LOGFONTW * lf, const TEXTMETRICW * tm UNUSED, + DWORD fontType UNUSED, LPARAM lParam) { LOGFONTW * lf_ptr = (LOGFONTW *) lParam; *lf_ptr = *lf; return 0; } +#endif /* check_and_set_font ensures that the current font will render the symbols * that are currently being used correctly. If they will not be rendered @@ -2147,15 +2191,12 @@ check_and_set_font(void) #endif } +#ifndef VIRTUAL_TERMINAL_SEQUENCES /* check_font_widths returns TRUE if all glyphs in current console font * fit within the width of a single console cell. */ boolean -#ifndef VIRTUAL_TERMINAL_SEQUENCES check_font_widths(void) -#else /* VIRTUAL_TERMINAL_SEQUENCES */ -check_font_widths(void) -#endif /* VIRTUAL_TERMINAL_SEQUENCES */ { CONSOLE_FONT_INFOEX console_font_info; console_font_info.cbSize = sizeof(console_font_info); @@ -2223,7 +2264,7 @@ check_font_widths(void) int wcUsedCount = 0; wchar_t wcUsed[256]; - for (int i = 0; i < sizeof(used); i++) + for (int i = 0; i < (int) sizeof(used); i++) if (used[i]) wcUsed[wcUsedCount++] = cp437[i]; @@ -2252,6 +2293,7 @@ clean_up: return all_glyphs_fit; } +#endif /* set_known_good_console_font sets the code page and font used by the console * to settings know to work well with NetHack. It also saves the original @@ -2465,7 +2507,7 @@ void nethack_enter_consoletty(void) { #ifdef VIRTUAL_TERMINAL_SEQUENCES char buf[BUFSZ], *bp, *localestr; - BOOL success; + BOOL apisuccess; #endif /* VIRTUAL_TERMINAL_SEQUENCES */ #if 0 /* set up state needed by early_raw_print() */ @@ -2559,7 +2601,7 @@ void nethack_enter_consoletty(void) /* store the original font */ console.orig_font_info.cbSize = sizeof(console.orig_font_info); - success = GetCurrentConsoleFontEx(console.hConOut, + apisuccess = GetCurrentConsoleFontEx(console.hConOut, FALSE, &console.orig_font_info); console.font_info = console.orig_font_info; @@ -2576,9 +2618,9 @@ void nethack_enter_consoletty(void) console.code_page = console.orig_code_page; if (console.has_unicode) { if (console.code_page != 437) - success = SetConsoleOutputCP(437); + apisuccess = SetConsoleOutputCP(437); } else if (console.code_page != 1252) { - success = SetConsoleOutputCP(1252); + apisuccess = SetConsoleOutputCP(1252); } console.code_page = GetConsoleOutputCP(); #endif /* VIRTUAL_TERMINAL_SEQUENCES */ @@ -2660,6 +2702,7 @@ void nethack_enter_consoletty(void) #endif /* VIRTUAL_TERMINAL_SEQUENCES */ console.current_nhcolor = NO_COLOR; console.is_ready = TRUE; + nhUse(apisuccess); } #endif /* TTY_GRAPHICS */ @@ -2718,7 +2761,7 @@ VA_DECL(const char *, fmt) #ifdef QWERTZ_SUPPORT /* when 'numberpad' is 0 and Cmd.swap_yz is True - (signaled by setting 0x10 on boolean numpad argument) + (signaled by setting 0x10 on uchar numberpad argument) treat keypress of numpad 7 as 'z' rather than 'y' */ static boolean qwertz = FALSE; #endif @@ -2939,7 +2982,7 @@ set_keyhandling_via_option(void) int default_processkeystroke( - HANDLE hConIn, + HANDLE hConIn UNUSED, INPUT_RECORD *ir, boolean *valid, boolean numberpad, @@ -3104,12 +3147,12 @@ default_kbhit(HANDLE hConIn, INPUT_RECORD *ir) return retval; } -int +int default_checkinput( HANDLE hConIn, INPUT_RECORD *ir, DWORD *count, - boolean numpad, + uchar numberpad, int mode, int *mod, coord *cc) @@ -3121,8 +3164,8 @@ default_checkinput( boolean valid = 0, done = 0; #ifdef QWERTZ_SUPPORT - if (numpad & 0x10) { - numpad &= ~0x10; + if (numberpad & 0x10) { + numberpad &= ~0x10; qwertz = TRUE; } else { qwertz = FALSE; @@ -3139,21 +3182,21 @@ default_checkinput( ReadConsoleInput(hConIn, ir, 1, count); if (mode == 0) { if ((ir->EventType == KEY_EVENT) && ir->Event.KeyEvent.bKeyDown) { - ch = default_processkeystroke(hConIn, ir, &valid, numpad, 0); + ch = default_processkeystroke(hConIn, ir, &valid, numberpad, 0); done = valid; } } else { - if (count > 0) { + if (*count > 0) { if (ir->EventType == KEY_EVENT && ir->Event.KeyEvent.bKeyDown) { #ifdef QWERTZ_SUPPORT if (qwertz) - numpad |= 0x10; + numberpad |= 0x10; #endif - ch = default_processkeystroke(hConIn, ir, &valid, numpad, 0); + ch = default_processkeystroke(hConIn, ir, &valid, numberpad, 0); #ifdef QWERTZ_SUPPORT - numpad &= ~0x10; -#endif + numberpad &= ~0x10; +#endif if (valid) return ch; } else if (ir->EventType == MOUSE_EVENT) { @@ -3565,7 +3608,7 @@ ray_checkinput( HANDLE hConIn, INPUT_RECORD *ir, DWORD *count, - boolean numpad, + uchar numberpad, int mode, int *mod, coord *cc) @@ -3577,8 +3620,8 @@ ray_checkinput( boolean valid = 0, done = 0; #ifdef QWERTZ_SUPPORT - if (numpad & 0x10) { - numpad &= ~0x10; + if (numberpad & 0x10) { + numberpad &= ~0x10; qwertz = TRUE; } else { qwertz = FALSE; @@ -3600,22 +3643,22 @@ ray_checkinput( ReadConsoleInput(hConIn, ir, 1, count); } else { ch = 0; - if (count > 0) { + if (*count > 0) { if (ir->EventType == KEY_EVENT && ir->Event.KeyEvent.bKeyDown) { #ifdef QWERTZ_SUPPORT if (qwertz) - numpad |= 0x10; + numberpad |= 0x10; #endif - ch = ray_processkeystroke(hConIn, ir, &valid, numpad, + ch = ray_processkeystroke(hConIn, ir, &valid, numberpad, #ifdef PORTDEBUG 1); #else 0); #endif #ifdef QWERTZ_SUPPORT - numpad &= ~0x10; -#endif + numberpad &= ~0x10; +#endif if (valid) return ch; } else { @@ -3635,7 +3678,7 @@ ray_checkinput( else if (ir->Event.MouseEvent.dwButtonState & RIGHTBUTTON) *mod = CLICK_2; -#if 0 /* middle button */ +#if 0 /* middle button */ else if (ir->Event.MouseEvent.dwButtonState & MIDBUTTON) *mod = CLICK_3; #endif @@ -3733,12 +3776,12 @@ ray_kbhit( * shift values below. */ -int +int nh340_processkeystroke( - HANDLE hConIn, + HANDLE hConIn UNUSED, INPUT_RECORD *ir, boolean *valid, - boolean numberpad, + uchar numberpad, int portdebug) { int keycode, vk; @@ -3884,7 +3927,7 @@ nh340_checkinput( HANDLE hConIn, INPUT_RECORD *ir, DWORD *count, - boolean numpad, + uchar numberpad, int mode, int *mod, coord *cc) @@ -3896,8 +3939,8 @@ nh340_checkinput( boolean valid = 0, done = 0; #ifdef QWERTZ_SUPPORT - if (numpad & 0x10) { - numpad &= ~0x10; + if (numberpad & 0x10) { + numberpad &= ~0x10; qwertz = TRUE; } else { qwertz = FALSE; @@ -3916,19 +3959,19 @@ nh340_checkinput( if ((ir->EventType == KEY_EVENT) && ir->Event.KeyEvent.bKeyDown) { #ifdef QWERTZ_SUPPORT if (qwertz) - numpad |= 0x10; + numberpad |= 0x10; #endif - ch = nh340_processkeystroke(hConIn, ir, &valid, numpad, 0); + ch = nh340_processkeystroke(hConIn, ir, &valid, numberpad, 0); #ifdef QWERTZ_SUPPORT - numpad &= ~0x10; -#endif + numberpad &= ~0x10; +#endif done = valid; } } else { - if (count > 0) { + if (*count > 0) { if (ir->EventType == KEY_EVENT && ir->Event.KeyEvent.bKeyDown) { - ch = nh340_processkeystroke(hConIn, ir, &valid, numpad, 0); + ch = nh340_processkeystroke(hConIn, ir, &valid, numberpad, 0); if (valid) return ch; } else if (ir->EventType == MOUSE_EVENT) { diff --git a/win/win32/NetHackW.c b/win/win32/NetHackW.c index 2eee75939..02b537cbd 100644 --- a/win/win32/NetHackW.c +++ b/win/win32/NetHackW.c @@ -73,7 +73,7 @@ int GUILaunched = TRUE; /* We tell shared startup code in windmain.c // Forward declarations of functions included in this code module: extern boolean main(int, char **); -static void __cdecl mswin_moveloop(void *); +//static void __cdecl mswin_moveloop(void *); #define MAX_CMDLINE_PARAM 255 @@ -327,7 +327,7 @@ _get_cmd_arg(TCHAR *pCmdLine) } else { pArgs = NULL; } - + nhUse(bQuoted); return pRetArg; } diff --git a/win/win32/mhdlg.c b/win/win32/mhdlg.c index f190f000d..94a7ecf3e 100644 --- a/win/win32/mhdlg.c +++ b/win/win32/mhdlg.c @@ -12,7 +12,10 @@ #include "mhdlg.h" #include - +int list_view_height(HWND hWnd, int count); +void get_rect_size(RECT *rect, SIZE *size); +void center_dialog(HWND dialog); +void size_dialog(HWND dialog, SIZE new_client_size); /*---------------------------------------------------------------*/ /* data for getlin dialog */ @@ -346,6 +349,11 @@ INT_PTR CALLBACK PlayerSelectorDlgProc(HWND, UINT, WPARAM, LPARAM); static void plselAdjustSelections(HWND hWnd); static boolean plselRandomize(plsel_data_t * data); static BOOL plselDrawItem(HWND hWnd, WPARAM wParam, LPARAM lParam); +void calculate_player_selector_layout(plsel_data_t * data); +void move_controls(control_t * controls, int count); +void do_player_selector_layout(plsel_data_t * data); +void plselInitDialog(struct plsel_data * data); +int plselFinalSelection(HWND hWnd); boolean mswin_player_selection_window(void) @@ -874,7 +882,7 @@ plselAdjustSelections(HWND hWnd) /* player made up his mind - get final selection here */ int -plselFinalSelection(HWND hWnd) +plselFinalSelection(HWND hWnd UNUSED) { int role, race, gender, alignment; @@ -984,7 +992,7 @@ plselDrawItem(HWND hWnd, WPARAM wParam, LPARAM lParam) struct plsel_data * data = (plsel_data_t *) GetWindowLongPtr(hWnd, GWLP_USERDATA); /* If there are no list box items, skip this message. */ - if (lpdis->itemID < 0) + if (lpdis->itemID == (UINT) -1) return FALSE; HWND control = GetDlgItem(hWnd, (int) wParam); diff --git a/win/win32/mhdlg.h b/win/win32/mhdlg.h index 0b08e8fcb..7eb0b8eb9 100644 --- a/win/win32/mhdlg.h +++ b/win/win32/mhdlg.h @@ -12,6 +12,6 @@ int mswin_getlin_window(const char *question, char *result, size_t result_size); int mswin_ext_cmd_window(int *selection); -boolean mswin_player_selection_window(); +boolean mswin_player_selection_window(void); #endif /* MSWINDlgWindow_h */ diff --git a/win/win32/mhmain.c b/win/win32/mhmain.c index c0a6cd0b1..f3eae350c 100644 --- a/win/win32/mhmain.c +++ b/win/win32/mhmain.c @@ -544,6 +544,7 @@ onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) mswin_select_map_mode(iflags.wc_map_mode); child = GetNHApp()->windowlist[msg_param->wid].win; + nhUse(child); } break; case MSNH_MSG_RANDOM_INPUT: { @@ -753,14 +754,18 @@ mswin_layout_main_window(HWND changed_child) } if (IsWindow(changed_child)) SetForegroundWindow(changed_child); + nhUse(data); } +VOID CALLBACK FuzzTimerProc( _In_ HWND hwnd, + _In_ UINT uMsg, _In_ UINT_PTR idEvent, + _In_ DWORD dwTime); + VOID CALLBACK FuzzTimerProc( _In_ HWND hwnd, - _In_ UINT uMsg, - _In_ UINT_PTR idEvent, - _In_ DWORD dwTime - ) + _In_ UINT uMsg UNUSED, + _In_ UINT_PTR idEvent UNUSED, + _In_ DWORD dwTime UNUSED) { INPUT input[16]; int i_pos = 0; @@ -1114,6 +1119,7 @@ onWMCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) default: return 1; } + nhUse(wmEvent); return 0; } diff --git a/win/win32/mhmap.c b/win/win32/mhmap.c index 6a5914cc6..a3f46c39d 100644 --- a/win/win32/mhmap.c +++ b/win/win32/mhmap.c @@ -764,6 +764,7 @@ onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) msg_data->buffer[index++] = '\r'; msg_data->buffer[index++] = '\n'; } + nhUse(mgch); } break; #ifdef ENHANCED_SYMBOLS diff --git a/win/win32/mhmenu.c b/win/win32/mhmenu.c index 121704b0d..d39bdc1b4 100644 --- a/win/win32/mhmenu.c +++ b/win/win32/mhmenu.c @@ -923,7 +923,7 @@ SetMenuListType(HWND hWnd, int how) for (i = 0; i < data->menui.menu.size; i++) { LVITEM lvitem; ZeroMemory(&lvitem, sizeof(lvitem)); - sprintf(buf, "%c - %s", max(data->menui.menu.items[i].accelerator, ' '), + Snprintf(buf, sizeof buf, "%c - %s", max(data->menui.menu.items[i].accelerator, ' '), data->menui.menu.items[i].str); lvitem.mask = LVIF_PARAM | LVIF_STATE | LVIF_TEXT; @@ -940,6 +940,7 @@ SetMenuListType(HWND hWnd, int how) } if (data->is_active) SetFocus(control); + nhUse(nItem); } /*-----------------------------------------------------------------------------*/ HWND @@ -1036,7 +1037,7 @@ onDrawItem(HWND hWnd, WPARAM wParam, LPARAM lParam) lpdis = (LPDRAWITEMSTRUCT) lParam; /* If there are no list box items, skip this message. */ - if (lpdis->itemID == -1) + if (lpdis->itemID == (UINT) -1) return FALSE; data = (PNHMenuWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA); diff --git a/win/win32/mhmsgwnd.c b/win/win32/mhmsgwnd.c index 864df34aa..e4d62b5ab 100644 --- a/win/win32/mhmsgwnd.c +++ b/win/win32/mhmsgwnd.c @@ -481,8 +481,8 @@ onMSNH_VScroll(HWND hWnd, WPARAM wParam, LPARAM lParam) // of the scroll box, and update the window. UpdateWindow // sends the WM_PAINT message. - if (yInc = max(MSG_VISIBLE_LINES - data->yPos, - min(yInc, data->yMax - data->yPos))) { + if ((yInc = max(MSG_VISIBLE_LINES - data->yPos, + min(yInc, data->yMax - data->yPos)))) { data->yPos += yInc; /* ScrollWindowEx(hWnd, 0, -data->yChar * yInc, (CONST RECT *) NULL, (CONST RECT *) NULL, diff --git a/win/win32/mhrip.c b/win/win32/mhrip.c index 912bbd9db..28036307b 100644 --- a/win/win32/mhrip.c +++ b/win/win32/mhrip.c @@ -297,6 +297,7 @@ onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) break; } + nhUse(InRipText); } void diff --git a/win/win32/mhsplash.c b/win/win32/mhsplash.c index f928cbfc6..5c5ef6328 100644 --- a/win/win32/mhsplash.c +++ b/win/win32/mhsplash.c @@ -259,6 +259,7 @@ NHSplashWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) DrawText(hdc, VersionString, strlen(VersionString), &rt, DT_LEFT | DT_NOPREFIX); EndPaint(hWnd, &ps); + nhUse(OldFont); } break; case WM_COMMAND: diff --git a/win/win32/mhstatus.c b/win/win32/mhstatus.c index fffbc5100..eee9047f8 100644 --- a/win/win32/mhstatus.c +++ b/win/win32/mhstatus.c @@ -19,7 +19,6 @@ extern COLORREF nhcolor_to_RGB(int c); /* from mhmap */ - typedef struct back_buffer { HWND hWnd; HDC hdc; @@ -29,6 +28,11 @@ typedef struct back_buffer { int height; } back_buffer_t; +void back_buffer_free(back_buffer_t * back_buffer); +void back_buffer_allocate(back_buffer_t * back_buffer, int width, int height); +void back_buffer_size(back_buffer_t * back_buffer, int width, int height); +void back_buffer_init(back_buffer_t * back_buffer, HWND hWnd, int width, int height); + void back_buffer_free(back_buffer_t * back_buffer) { if (back_buffer->bm != NULL) { @@ -274,7 +278,7 @@ StatusWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) } static LRESULT -onWMPaint(HWND hWnd, WPARAM wParam, LPARAM lParam) +onWMPaint(HWND hWnd, WPARAM wParam UNUSED, LPARAM lParam UNUSED) { SIZE sz; WCHAR wbuf[BUFSZ]; diff --git a/win/win32/mhstatus.h b/win/win32/mhstatus.h index a70a90f6e..ec3473334 100644 --- a/win/win32/mhstatus.h +++ b/win/win32/mhstatus.h @@ -17,7 +17,9 @@ static const int fieldorder2[] = { BL_LEVELDESC, BL_GOLD, BL_HP, BL_HPMAX BL_ENE, BL_ENEMAX, BL_AC, BL_XP, BL_EXP, BL_HD, BL_TIME, BL_HUNGER, BL_CAP, BL_CONDITION, -1 }; +#ifdef MSWPROC_C static const int *fieldorders[] = { fieldorder1, fieldorder2, NULL }; +#endif static const int fieldcounts[NHSW_LINES] = { SIZE(fieldorder1) - 1, SIZE(fieldorder2) - 1}; #define MSWIN_MAX_LINE1_STRINGS (SIZE(fieldorder1) - 1) diff --git a/win/win32/mswproc.c b/win/win32/mswproc.c index cf4f63a44..1103233c2 100644 --- a/win/win32/mswproc.c +++ b/win/win32/mswproc.c @@ -7,6 +7,7 @@ * code in the mswin port and the rest of the nethack game engine. */ +#define MSWPROC_C #include "hack.h" #include "color.h" #include "dlb.h" @@ -28,6 +29,7 @@ #include "mhmain.h" #include "mhfont.h" #include "resource.h" +#undef MSWPROC_C #define LLEN 128 @@ -371,14 +373,15 @@ prompt_for_player_selection(void) /* tty_putsym(BASE_WINDOW, (int)strlen(prompt)+1, echoline, * pick4u); */ /* tty_putstr(BASE_WINDOW, 0, ""); */ - } else + } else { /* Otherwise it's hard to tell where to echo, and things are * wrapping a bit messily anyway, so (try to) make sure the next * question shows up well and doesn't get wrapped at the * bottom of the window. */ - /* tty_clear_nhwindow(BASE_WINDOW) */; - + /* tty_clear_nhwindow(BASE_WINDOW) */ + ; + } if (pick4u != 'y' && pick4u != 'n') { give_up: /* Quit */ if (selected) @@ -450,7 +453,7 @@ prompt_for_player_selection(void) any.a_int = i + 1; /* must be non-zero */ add_menu(win, &nul_glyphinfo, &any, 'q', 0, ATR_NONE, clr, "Quit", MENU_ITEMFLAGS_NONE); - Sprintf(pbuf, "Pick a role for your %s", plbuf); + Snprintf(pbuf, sizeof pbuf, "Pick a role for your %s", plbuf); end_menu(win, pbuf); n = select_menu(win, PICK_ONE, &selected); destroy_nhwindow(win); @@ -524,7 +527,7 @@ prompt_for_player_selection(void) any.a_int = i + 1; /* must be non-zero */ add_menu(win, &nul_glyphinfo, &any, 'q', 0, ATR_NONE, clr, "Quit", MENU_ITEMFLAGS_NONE); - Sprintf(pbuf, "Pick the race of your %s", plbuf); + Snprintf(pbuf, sizeof pbuf, "Pick the race of your %s", plbuf); end_menu(win, pbuf); n = select_menu(win, PICK_ONE, &selected); destroy_nhwindow(win); @@ -599,7 +602,7 @@ prompt_for_player_selection(void) any.a_int = i + 1; /* must be non-zero */ add_menu(win, &nul_glyphinfo, &any, 'q', 0, ATR_NONE, clr, "Quit", MENU_ITEMFLAGS_NONE); - Sprintf(pbuf, "Pick the gender of your %s", plbuf); + Snprintf(pbuf, sizeof pbuf, "Pick the gender of your %s", plbuf); end_menu(win, pbuf); n = select_menu(win, PICK_ONE, &selected); destroy_nhwindow(win); @@ -673,7 +676,7 @@ prompt_for_player_selection(void) any.a_int = i + 1; /* must be non-zero */ add_menu(win, &nul_glyphinfo, &any, 'q', 0, ATR_NONE, clr, "Quit", MENU_ITEMFLAGS_NONE); - Sprintf(pbuf, "Pick the alignment of your %s", plbuf); + Snprintf(pbuf, sizeof pbuf, "Pick the alignment of your %s", plbuf); end_menu(win, pbuf); n = select_menu(win, PICK_ONE, &selected); destroy_nhwindow(win); @@ -1260,7 +1263,7 @@ mswin_update_inventory(int arg) win_request_info * mswin_ctrl_nhwindow( - winid window, + winid window UNUSED, int request, win_request_info *wri) { @@ -1365,10 +1368,12 @@ mswin_print_glyph(winid wid, coordxy x, coordxy y, * mswin_raw_print_accumulate() accumulate the given text into * raw_print_strbuf. */ +void mswin_raw_print_accumulate(const char * str, boolean bold); + void mswin_raw_print_accumulate(const char * str, boolean bold) { - bold; // ignored for now + nhUse(bold); // ignored for now if (raw_print_strbuf.str != NULL) strbuf_append(&raw_print_strbuf, "\n"); strbuf_append(&raw_print_strbuf, str); @@ -1704,7 +1709,7 @@ mswin_yn_function(const char *question, const char *choices, char def) res_ch[1] = '\x0'; mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, res_ch, 1); } - + nhUse(yn_esc_map); return ch; } @@ -1916,7 +1921,7 @@ char * mswin_get_color_string(void) { logDebug("mswin_get_color_string()\n"); - return (""); + return (char *) ""; } /* @@ -2557,7 +2562,7 @@ mswin_write_reg(void) if (RegOpenKeyEx(HKEY_CURRENT_USER, keystring, 0, KEY_WRITE, &key) != ERROR_SUCCESS) { - RegCreateKeyEx(HKEY_CURRENT_USER, keystring, 0, "", + RegCreateKeyEx(HKEY_CURRENT_USER, keystring, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &key, &disposition); } @@ -2694,7 +2699,7 @@ static color_table_value color_table[] = { }; typedef struct ctbv { - char *colorstring; + const char *colorstring; int syscolorvalue; } color_table_brush_value; @@ -2729,7 +2734,7 @@ mswin_color_from_string(char *colorstring, HBRUSH *brushptr, color_table_value *ctv_ptr = color_table; color_table_brush_value *ctbv_ptr = color_table_brush; int red_value, blue_value, green_value; - static char *hexadecimals = "0123456789abcdef"; + static const char *hexadecimals = "0123456789abcdef"; if (colorstring == NULL) return; @@ -2880,36 +2885,36 @@ static mswin_status_string _condition_strings[CONDITION_COUNT]; static mswin_status_field _status_fields[MAXBLSTATS]; static mswin_condition_field _condition_fields[CONDITION_COUNT] = { - { BL_MASK_BAREH, "Bare" }, - { BL_MASK_BLIND, "Blind" }, - { BL_MASK_BUSY, "Busy" }, - { BL_MASK_CONF, "Conf" }, - { BL_MASK_DEAF, "Deaf" }, - { BL_MASK_ELF_IRON, "Iron" }, - { BL_MASK_FLY, "Fly" }, - { BL_MASK_FOODPOIS, "FoodPois" }, - { BL_MASK_GLOWHANDS, "Glow" }, - { BL_MASK_GRAB, "Grab" }, - { BL_MASK_HALLU, "Hallu" }, - { BL_MASK_HELD, "Held" }, - { BL_MASK_ICY, "Icy" }, - { BL_MASK_INLAVA, "Lava" }, - { BL_MASK_LEV, "Lev" }, - { BL_MASK_PARLYZ, "Parlyz" }, - { BL_MASK_RIDE, "Ride" }, - { BL_MASK_SLEEPING, "Zzz" }, - { BL_MASK_SLIME, "Slime" }, - { BL_MASK_SLIPPERY, "Slip" }, - { BL_MASK_STONE, "Stone" }, - { BL_MASK_STRNGL, "Strngl" }, - { BL_MASK_STUN, "Stun" }, - { BL_MASK_SUBMERGED, "Sub" }, - { BL_MASK_TERMILL, "TermIll" }, - { BL_MASK_TETHERED, "Teth" }, - { BL_MASK_TRAPPED, "Trap" }, - { BL_MASK_UNCONSC, "Out" }, - { BL_MASK_WOUNDEDL, "Legs" }, - { BL_MASK_HOLDING, "Uhold" }, + { BL_MASK_BAREH, "Bare", 0}, + { BL_MASK_BLIND, "Blind", 0 }, + { BL_MASK_BUSY, "Busy", 0 }, + { BL_MASK_CONF, "Conf", 0 }, + { BL_MASK_DEAF, "Deaf", 0 }, + { BL_MASK_ELF_IRON, "Iron", 0 }, + { BL_MASK_FLY, "Fly", 0 }, + { BL_MASK_FOODPOIS, "FoodPois", 0 }, + { BL_MASK_GLOWHANDS, "Glow", 0 }, + { BL_MASK_GRAB, "Grab", 0 }, + { BL_MASK_HALLU, "Hallu", 0 }, + { BL_MASK_HELD, "Held", 0 }, + { BL_MASK_ICY, "Icy", 0 }, + { BL_MASK_INLAVA, "Lava", 0 }, + { BL_MASK_LEV, "Lev", 0 }, + { BL_MASK_PARLYZ, "Parlyz", 0 }, + { BL_MASK_RIDE, "Ride", 0 }, + { BL_MASK_SLEEPING, "Zzz", 0 }, + { BL_MASK_SLIME, "Slime", 0 }, + { BL_MASK_SLIPPERY, "Slip", 0 }, + { BL_MASK_STONE, "Stone", 0 }, + { BL_MASK_STRNGL, "Strngl", 0 }, + { BL_MASK_STUN, "Stun", 0 }, + { BL_MASK_SUBMERGED, "Sub", 0 }, + { BL_MASK_TERMILL, "TermIll", 0 }, + { BL_MASK_TETHERED, "Teth", 0 }, + { BL_MASK_TRAPPED, "Trap", 0 }, + { BL_MASK_UNCONSC, "Out", 0 }, + { BL_MASK_WOUNDEDL, "Legs", 0 }, + { BL_MASK_HOLDING, "Uhold", 0 }, }; extern winid WIN_STATUS; diff --git a/win/win32/winMS.h b/win/win32/winMS.h index ed7e24e8f..682fbc3ee 100644 --- a/win/win32/winMS.h +++ b/win/win32/winMS.h @@ -142,12 +142,9 @@ typedef struct mswin_nhwindow_app { LPTRANSPARENTBLT lpfnTransparentBlt; /* transparent blt function */ } NHWinApp, *PNHWinApp; -#define E extern - -E PNHWinApp GetNHApp(void); -E struct window_procs mswin_procs; - -#undef E +extern PNHWinApp GetNHApp(void); +extern struct window_procs mswin_procs; +extern void free_winmain_stuff(void); /* Some prototypes */ void mswin_init_nhwindows(int *argc, char **argv); @@ -179,7 +176,7 @@ void mswin_print_glyph(winid wid, coordxy x, coordxy y, const glyph_info *glyph, const glyph_info *bkglyph); void mswin_raw_print(const char *str); void mswin_raw_print_bold(const char *str); -void mswin_raw_print_flush(); +void mswin_raw_print_flush(void); int mswin_nhgetch(void); int mswin_nh_poskey(coordxy *x, coordxy *y, int *mod); void mswin_nhbell(void); @@ -224,6 +221,8 @@ void mswin_get_window_placement(int type, LPRECT rt); void mswin_update_window_placement(int type, LPRECT rt); void mswin_apply_window_style(HWND hwnd); +//boolean mswin_player_selection_window(void); + int NHMessageBox(HWND hWnd, LPCTSTR text, UINT type); extern HBRUSH menu_bg_brush; From c7739171a27c0025954e4fce239ed619b6744aa6 Mon Sep 17 00:00:00 2001 From: nhmall Date: Thu, 12 Dec 2024 22:46:44 -0500 Subject: [PATCH 180/791] follow-up: consoletty.c --- sys/windows/consoletty.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/sys/windows/consoletty.c b/sys/windows/consoletty.c index 32892f864..0ffe4f8dc 100644 --- a/sys/windows/consoletty.c +++ b/sys/windows/consoletty.c @@ -146,7 +146,7 @@ static void xputc_core(int); #endif /* VIRTUAL_TERMINAL_SEQUENCES */ void cmov(int, int); void nocmov(int, int); -int process_keystroke(INPUT_RECORD *, boolean *, boolean numberpad, +int process_keystroke(INPUT_RECORD *, boolean *, uchar numberpad, int portdebug); static void init_ttycolor(void); static void really_move_cursor(void); @@ -273,27 +273,27 @@ const char *const legal_key_handling[] = { enum windows_key_handling keyh[] = { no_keyhandling, default_keyhandling, ray_keyhandling, nh340_keyhandling }; -int default_processkeystroke(HANDLE, INPUT_RECORD *, boolean *, boolean, int); +int default_processkeystroke(HANDLE, INPUT_RECORD *, boolean *, uchar, int); int default_kbhit(HANDLE, INPUT_RECORD *); -int default_checkinput(HANDLE, INPUT_RECORD *, DWORD *, boolean, +int default_checkinput(HANDLE, INPUT_RECORD *, DWORD *, uchar, int, int *, coord *); -int ray_processkeystroke(HANDLE, INPUT_RECORD *, boolean *, boolean, int); +int ray_processkeystroke(HANDLE, INPUT_RECORD *, boolean *, uchar, int); int ray_kbhit(HANDLE, INPUT_RECORD *); -int ray_checkinput(HANDLE, INPUT_RECORD *, DWORD *, boolean, +int ray_checkinput(HANDLE, INPUT_RECORD *, DWORD *, uchar, int, int *, coord *); -int nh340_processkeystroke(HANDLE, INPUT_RECORD *, boolean *, boolean, int); +int nh340_processkeystroke(HANDLE, INPUT_RECORD *, boolean *, uchar, int); int nh340_kbhit(HANDLE, INPUT_RECORD *); -int nh340_checkinput(HANDLE, INPUT_RECORD *, DWORD *, boolean, +int nh340_checkinput(HANDLE, INPUT_RECORD *, DWORD *, uchar, int, int *, coord *); struct keyboard_handling_t { enum windows_key_handling khid; int (*pProcessKeystroke)(HANDLE, INPUT_RECORD *, boolean *, - boolean, int); + uchar, int); int (*pNHkbhit)(HANDLE, INPUT_RECORD *); - int (*pCheckInput)(HANDLE, INPUT_RECORD *, DWORD *, boolean, + int (*pCheckInput)(HANDLE, INPUT_RECORD *, DWORD *, uchar, int, int *, coord *); } keyboard_handling = { no_keyhandling, @@ -1181,7 +1181,7 @@ int process_keystroke( INPUT_RECORD *ir, boolean *valid, - boolean numberpad, + uchar numberpad, int portdebug) { int ch; @@ -2086,7 +2086,7 @@ win32con_debug_keystrokes(void) nocmov(ttyDisplay->curx, ttyDisplay->cury); ReadConsoleInput(console.hConIn, &gbl_ir, 1, &count); if ((gbl_ir.EventType == KEY_EVENT) && gbl_ir.Event.KeyEvent.bKeyDown) - ch = process_keystroke(&gbl_ir, &valid, iflags.num_pad, 1); + ch = process_keystroke(&gbl_ir, &valid, (uchar) iflags.num_pad, 1); } (void) doredraw(); } @@ -2985,7 +2985,7 @@ default_processkeystroke( HANDLE hConIn UNUSED, INPUT_RECORD *ir, boolean *valid, - boolean numberpad, + uchar numberpad, int portdebug) { int k = 0; @@ -3421,7 +3421,7 @@ int ray_processkeystroke( HANDLE hConIn, INPUT_RECORD *ir, boolean *valid, - boolean numberpad, + uchar numberpad, int portdebug) { int keycode, vk; From bbb4bfa93880fb178756689ca413be31b3f4c829 Mon Sep 17 00:00:00 2001 From: PatR Date: Fri, 13 Dec 2024 12:30:48 -0800 Subject: [PATCH 181/791] fix issue #1337 - 'fireassist' vs 'f'iring aklys Issue reported by elunna: if the 'fireassist' option is on and the quiver contains ammo, 'f' while wielding an aklys switches to the ammo's launcher instead of throwing the aklys. Fixes #1337 --- doc/fixes3-7-0.txt | 2 ++ src/dothrow.c | 11 +++++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index 13c61a938..892fa0dd0 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -2069,6 +2069,8 @@ non-fireproof water walking boots wouldn't be burnt up if fire resistant hero at wall locations if a pile of objects had plain arrow(s) on top, map location classification got confused and reported 'unexplored area' +when the 'fireassist' option was on, 'f' would choose uquiver over wielded + throw-and-return uwep Fixes to 3.7.0-x Platform and/or Interface Problems Exposed Via git Repository diff --git a/src/dothrow.c b/src/dothrow.c index fc154773c..57dd5757c 100644 --- a/src/dothrow.c +++ b/src/dothrow.c @@ -472,7 +472,8 @@ dofire(void) on its caller to make sure hero is strong enough to throw that */ boolean uwep_Throw_and_Return = (uwep && AutoReturn(uwep, uwep->owornmask) && (uwep->oartifact != ART_MJOLLNIR - || ACURR(A_STR) >= STR19(25))); + || ACURR(A_STR) >= STR19(25))), + skip_fireassist = FALSE; int altres, res = ECMD_OK; /* @@ -502,6 +503,7 @@ dofire(void) throwing Mjollnir if quiver contains daggers] */ if (uwep_Throw_and_Return && (!obj || is_ammo(obj))) { obj = uwep; + skip_fireassist = TRUE; } else if (!obj) { if (!flags.autoquiver) { @@ -550,7 +552,8 @@ dofire(void) obj = uquiver; } - if (uquiver && is_ammo(uquiver) && iflags.fireassist) { + if (uquiver && is_ammo(uquiver) && iflags.fireassist + && !skip_fireassist) { struct obj *olauncher; if (uwep && is_pole(uwep) && could_pole_mon()) @@ -2074,7 +2077,7 @@ thitmonst( /* ...or any special item, if you've made him angry */ || !mon->mpeaceful) { /* give an explanation for keeping the item only if leader is - not doing it out of anger */ + not doing it out of anger */ if (mon->mpeaceful && !Deaf) { /* just in case, identify the object so its name will appear in the message */ @@ -2090,7 +2093,7 @@ thitmonst( (void) mpickobj(mon, obj); } else { /* under normal circumstances, leader will say something and - then return the item to the hero */ + then return the item to the hero */ boolean next2u = monnear(mon, u.ux, u.uy); finish_quest(obj); /* acknowledge quest completion */ From b2b9b685c5a837e0619a7dbd787e691223b41a28 Mon Sep 17 00:00:00 2001 From: PatR Date: Fri, 13 Dec 2024 22:48:32 -0800 Subject: [PATCH 182/791] fix issue #1305 - failed #untrap from doorway Issue reported by loggersviii: attempting #untrap from an adjacent doorway can move the hero diagonally out of the doorway. A followup comment by elunna pointed out that a monster's attack that results in knockback can produce similar result. Fixes #1305 --- include/extern.h | 2 ++ src/hack.c | 19 +++---------------- src/trap.c | 33 ++++++++++++++++++++++++++++++--- src/uhitm.c | 27 ++++++++++++++++++++------- 4 files changed, 55 insertions(+), 26 deletions(-) diff --git a/include/extern.h b/include/extern.h index 8eeaf7010..879fcc7dd 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1173,6 +1173,7 @@ extern boolean in_town(coordxy, coordxy); extern void check_special_room(boolean); extern int dopickup(void); extern void lookaround(void); +extern boolean doorless_door(coordxy, coordxy); extern boolean crawl_destination(coordxy, coordxy); extern int monster_nearby(void); extern void end_running(boolean); @@ -3218,6 +3219,7 @@ extern void drain_en(int, boolean); extern int dountrap(void); extern int could_untrap(boolean, boolean); extern void cnv_trap_obj(int, int, struct trap *, boolean) NONNULLARG3; +extern boolean into_vs_onto(int); extern int untrap(boolean, coordxy, coordxy, struct obj *) NO_NNARGS; extern boolean openholdingtrap(struct monst *, boolean *) NO_NNARGS; extern boolean closeholdingtrap(struct monst *, boolean *) NO_NNARGS; diff --git a/src/hack.c b/src/hack.c index 6f8cce1d1..538a9b699 100644 --- a/src/hack.c +++ b/src/hack.c @@ -47,7 +47,6 @@ staticfn struct monst *monstinroom(struct permonst *, int) NONNULLARG1; staticfn boolean furniture_present(int, int); staticfn void move_update(boolean); staticfn int pickup_checks(void); -staticfn boolean doorless_door(coordxy, coordxy); staticfn void maybe_wail(void); staticfn boolean water_turbulence(coordxy *, coordxy *); @@ -963,7 +962,7 @@ invocation_pos(coordxy x, coordxy y) && x == svi.inv_pos.x && y == svi.inv_pos.y); } -/* return TRUE if (dx,dy) is an OK place to move; +/* return TRUE if (ux+dx,ux+dy) is an OK place to move; mode is one of DO_MOVE, TEST_MOVE, TEST_TRAV, or TEST_TRAP */ boolean test_move( @@ -2749,20 +2748,8 @@ domove_core(void) || Hallucination)) { char qbuf[QBUFSZ]; int traptype = (Hallucination ? rnd(TRAPNUM - 1) : (int) trap->ttyp); - boolean into = FALSE; /* "onto" the trap vs "into" */ + boolean into = into_vs_onto(traptype); - switch (traptype) { - case BEAR_TRAP: - case PIT: - case SPIKED_PIT: - case HOLE: - case TELEP_TRAP: - case LEVEL_TELEP: - case MAGIC_PORTAL: - case WEB: - into = TRUE; - break; - } Snprintf(qbuf, sizeof qbuf, "Really %s %s that %s?", u_locomotion("step"), into ? "into" : "onto", defsyms[trap_to_defsym(traptype)].explanation); @@ -3910,7 +3897,7 @@ lookaround(void) } /* check for a doorway which lacks its door (NODOOR or BROKEN) */ -staticfn boolean +boolean doorless_door(coordxy x, coordxy y) { struct rm *lev_p = &levl[x][y]; diff --git a/src/trap.c b/src/trap.c index da39e4428..64e185d32 100644 --- a/src/trap.c +++ b/src/trap.c @@ -5267,6 +5267,24 @@ cnv_trap_obj( deltrap(ttmp); } +/* whether moving to a trap location is moving "into" the trap or "onto" it */ +boolean +into_vs_onto(int traptype) +{ + switch (traptype) { + case BEAR_TRAP: + case PIT: + case SPIKED_PIT: + case HOLE: + case TELEP_TRAP: + case LEVEL_TELEP: + case MAGIC_PORTAL: + case WEB: + return TRUE; + } + return FALSE; +} + /* while attempting to disarm an adjacent trap, we've fallen into it */ staticfn void move_into_trap(struct trap *ttmp) @@ -5276,9 +5294,13 @@ move_into_trap(struct trap *ttmp) boolean unused; bx = by = cx = cy = 0; /* lint suppression */ - /* we know there's no monster in the way, and we're not trapped */ - if (!Punished - || drag_ball(x, y, &bc, &bx, &by, &cx, &cy, &unused, TRUE)) { + /* we know there's no monster in the way and we're not trapped, but + need to make sure the move is not diagonally into or out of a + doorway; the sgn() calls are redundant since ttmp is adjacent */ + if (test_move(u.ux, u.uy, sgn(x - u.ux), sgn(y - u.uy), TEST_MOVE) + && (!Punished + || drag_ball(x, y, &bc, &bx, &by, &cx, &cy, &unused, TRUE))) { + /* move hero and update map */ u.ux0 = u.ux, u.uy0 = u.uy; /* set u.ux,u.uy and u.usteed->mx,my plus handle CLIPPING */ u_on_newpos(x, y); @@ -5303,6 +5325,11 @@ move_into_trap(struct trap *ttmp) if ((ttmp = t_at(u.ux, u.uy)) != 0) ttmp->tseen = 1; exercise(A_WIS, FALSE); + } else { + /* caller has just printed "Whoops..." so if hero is prevented from + moving, a followup message is needed */ + pline("Fortunately, you don't move %s it.", + into_vs_onto(ttmp->ttyp) ? "into" : "onto"); } } diff --git a/src/uhitm.c b/src/uhitm.c index 04e78d20e..82b50deda 100644 --- a/src/uhitm.c +++ b/src/uhitm.c @@ -5140,6 +5140,26 @@ mhitm_knockback( if (rn2(6)) return FALSE; + /* decide where the first step will place the target; not accurate + for being knocked out of saddle but doesn't need to be; used for + test_move() and for message before actual hurtle */ + defx = u_def ? u.ux : mdef->mx; + defy = u_def ? u.uy : mdef->my; + dx = sgn(defx - (u_agr ? u.ux : magr->mx)); + dy = sgn(defy - (u_agr ? u.uy : magr->my)); + + /* can't move most targets into or out of a doorway diagonally */ + if (u_def) { + if (!test_move(defx, defy, dx, dy, TEST_MOVE)) + return FALSE; + } else { + /* subset of test_move() */ + if (IS_DOOR(levl[defx][defy].typ) + && (defx - magr->mx && defy - magr->my) + && !doorless_door(defx, defy)) + return FALSE; + } + /* if hero is stuck to a cursed saddle, knock the steed back */ if (u_def && u.usteed) { if ((otmp = which_armor(u.usteed, W_SADDLE)) != 0 && otmp->cursed) { @@ -5191,13 +5211,6 @@ mhitm_knockback( return FALSE; } - /* decide where the first step will place the target; not accurate - for being knocked out of saddle but doesn't need to be; used for - message before actual hurtle */ - defx = u_def ? u.ux : mdef->mx; - defy = u_def ? u.uy : mdef->my; - dx = sgn(defx - (u_agr ? u.ux : magr->mx)); - dy = sgn(defy - (u_agr ? u.uy : magr->my)); /* subtly vary the message text if monster won't actually move */ knockedhow = dismount ? "out of your saddle" : will_hurtle(mdef, defx + dx, defy + dy) ? "backward" From fd234639417970e20a3deb6821224ff0cbee5f86 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sat, 14 Dec 2024 14:34:19 +0200 Subject: [PATCH 183/791] Sparkle shield effect and accessibility When sparkle is turned off, there are some places where a monster resisting the effect did not give any message. This fixes some of those. --- include/extern.h | 1 + src/mhitm.c | 2 +- src/mon.c | 11 +++++++++++ src/trap.c | 2 +- src/zap.c | 10 ++++------ 5 files changed, 18 insertions(+), 8 deletions(-) diff --git a/include/extern.h b/include/extern.h index 879fcc7dd..84d61a8e1 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1782,6 +1782,7 @@ extern void mimic_hit_msg(struct monst *, short); extern void adj_erinys(unsigned); extern void see_monster_closeup(struct monst *) NONNULLARG1; extern void see_nearby_monsters(void); +extern void shieldeff_mon(struct monst *) NONNULLARG1; /* ### mondata.c ### */ diff --git a/src/mhitm.c b/src/mhitm.c index c92cb7d40..a65ed98d7 100644 --- a/src/mhitm.c +++ b/src/mhitm.c @@ -1137,7 +1137,7 @@ mon_poly(struct monst *magr, struct monst *mdef, int dmg) if (resists_magm(mdef)) { /* Magic resistance */ if (gv.vis) - shieldeff(mdef->mx, mdef->my); + shieldeff_mon(mdef); } else if (resist(mdef, WAND_CLASS, 0, TELL)) { /* general resistance to magic... */ ; diff --git a/src/mon.c b/src/mon.c index 4767920d7..cf77dd8c6 100644 --- a/src/mon.c +++ b/src/mon.c @@ -5838,4 +5838,15 @@ see_nearby_monsters(void) } } +/* monster resists something. + make a shield effect at monster's location and give a message */ +void +shieldeff_mon(struct monst *mtmp) +{ + shieldeff(mtmp->mx, mtmp->my); + /* does not depend on seeing the monster; the shield effect is visible */ + if (cansee(mtmp->mx, mtmp->my)) + pline_xy(mtmp->mx, mtmp->my, "%s resists!", Monnam(mtmp)); +} + /*mon.c*/ diff --git a/src/trap.c b/src/trap.c index 64e185d32..d1be7d9b5 100644 --- a/src/trap.c +++ b/src/trap.c @@ -2444,7 +2444,7 @@ trapeffect_poly_trap( boolean in_sight = canseemon(mtmp) || (mtmp == u.usteed); if (resists_magm(mtmp)) { - shieldeff(mtmp->mx, mtmp->my); + shieldeff_mon(mtmp); } else if (!resist(mtmp, WAND_CLASS, 0, NOTELL)) { (void) newcham(mtmp, (struct permonst *) 0, NC_SHOW_MSG); if (in_sight) diff --git a/src/zap.c b/src/zap.c index 00120647a..23fdac1be 100644 --- a/src/zap.c +++ b/src/zap.c @@ -265,7 +265,7 @@ bhitm(struct monst *mtmp, struct obj *otmp) } else if (resists_magm(mtmp)) { /* magic resistance protects from polymorph traps, so make it guard against involuntary polymorph attacks too... */ - shieldeff(mtmp->mx, mtmp->my); + shieldeff_mon(mtmp); } else if (!resist(mtmp, otmp->oclass, 0, NOTELL)) { boolean polyspot = (otyp != POT_POLYMORPH), give_msg = (!Hallucination @@ -510,7 +510,7 @@ bhitm(struct monst *mtmp, struct obj *otmp) if (otyp == SPE_DRAIN_LIFE) dmg = spell_damage_bonus(dmg); if (resists_drli(mtmp)) { - shieldeff(mtmp->mx, mtmp->my); + shieldeff_mon(mtmp); } else if (!resist(mtmp, otmp->oclass, dmg, NOTELL) && !DEADMONSTER(mtmp)) { mtmp->mhp -= dmg; @@ -6068,10 +6068,8 @@ resist(struct monst *mtmp, char oclass, int damage, int tell) resisted = rn2(100 + alev - dlev) < mtmp->data->mr; if (resisted) { - if (tell) { - shieldeff(mtmp->mx, mtmp->my); - pline("%s resists!", Monnam(mtmp)); - } + if (tell) + shieldeff_mon(mtmp); damage = (damage + 1) / 2; } From 4f37795f96a5969aebdfbc356eef15714c04179f Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sat, 14 Dec 2024 15:00:43 +0200 Subject: [PATCH 184/791] Accessibility: pet message locations --- src/dog.c | 26 +++++++++++++++----------- src/dogmove.c | 16 +++++++++------- 2 files changed, 24 insertions(+), 18 deletions(-) diff --git a/src/dog.c b/src/dog.c index e14513fdb..6c7849f0b 100644 --- a/src/dog.c +++ b/src/dog.c @@ -791,8 +791,9 @@ keepdogs( mdrop_special_objs(mtmp); /* drop Amulet */ } else if (mtmp->meating || mtmp->mtrapped) { if (canseemon(mtmp)) - pline("%s is still %s.", Monnam(mtmp), - mtmp->meating ? "eating" : "trapped"); + pline_xy(mtmp->mx, mtmp->my, + "%s is still %s.", Monnam(mtmp), + mtmp->meating ? "eating" : "trapped"); stay_behind = TRUE; } else if (mon_has_amulet(mtmp)) { if (canseemon(mtmp)) @@ -1127,7 +1128,7 @@ tamedog( /* worst case, at least it'll be peaceful. */ if (givemsg && !mtmp->mpeaceful && canspotmon(mtmp)) { - pline("%s seems %s.", Monnam(mtmp), + pline_xy(mtmp->mx, mtmp->my, "%s seems %s.", Monnam(mtmp), Hallucination ? "really chill" : "more amiable"); givemsg = FALSE; /* don't give another message below */ } @@ -1162,8 +1163,9 @@ tamedog( boolean big_corpse = (obj->otyp == CORPSE && ismnum(obj->corpsenm) && mons[obj->corpsenm].msize > mtmp->data->msize); - pline("%s catches %s%s", Monnam(mtmp), the(xname(obj)), - !big_corpse ? "." : ", or vice versa!"); + pline_xy(mtmp->mx, mtmp->my, + "%s catches %s%s", Monnam(mtmp), the(xname(obj)), + !big_corpse ? "." : ", or vice versa!"); } else if (cansee(mtmp->mx, mtmp->my)) pline("%s.", Tobjnam(obj, "stop")); /* dog_eat expects a floor object */ @@ -1223,7 +1225,7 @@ tamedog( } if (givemsg && canspotmon(mtmp)) - pline("%s seems quite %s.", Monnam(mtmp), + pline_xy(mtmp->mx, mtmp->my, "%s seems quite %s.", Monnam(mtmp), Hallucination ? "approachable" : "friendly"); newsym(mtmp->mx, mtmp->my); @@ -1270,11 +1272,13 @@ wary_dog(struct monst *mtmp, boolean was_dead) if (!quietly && cansee(mtmp->mx, mtmp->my)) { if (haseyes(gy.youmonst.data)) { if (haseyes(mtmp->data)) - pline("%s %s to look you in the %s.", Monnam(mtmp), - mtmp->mpeaceful ? "seems unable" : "refuses", - body_part(EYE)); + pline_xy(mtmp->mx, mtmp->my, + "%s %s to look you in the %s.", Monnam(mtmp), + mtmp->mpeaceful ? "seems unable" : "refuses", + body_part(EYE)); else - pline("%s avoids your gaze.", Monnam(mtmp)); + pline_xy(mtmp->mx, mtmp->my, + "%s avoids your gaze.", Monnam(mtmp)); } } } else { @@ -1286,7 +1290,7 @@ wary_dog(struct monst *mtmp, boolean was_dead) if (!mtmp->mtame) { if (!quietly && canspotmon(mtmp)) - pline("%s %s.", Monnam(mtmp), + pline_xy(mtmp->mx, mtmp->my, "%s %s.", Monnam(mtmp), mtmp->mpeaceful ? "is no longer tame" : "has become feral"); newsym(mtmp->mx, mtmp->my); /* a life-saved monster might be leashed; diff --git a/src/dogmove.c b/src/dogmove.c index 1694eb8a6..a6ff8bce0 100644 --- a/src/dogmove.c +++ b/src/dogmove.c @@ -283,9 +283,9 @@ dog_eat(struct monst *mtmp, result won't be printed */ obj_name = distant_name(obj, doname); if (tunnels(mtmp->data)) - pline("%s digs in.", noit_Monnam(mtmp)); + pline_xy(mtmp->mx, mtmp->my, "%s digs in.", noit_Monnam(mtmp)); else - pline("%s %s %s.", noit_Monnam(mtmp), + pline_xy(mtmp->mx, mtmp->my, "%s %s %s.", noit_Monnam(mtmp), devour ? "devours" : "eats", obj_name); } else if (seeobj) { obj_name = distant_name(obj, doname); @@ -335,7 +335,7 @@ dog_starve(struct monst *mtmp) if (mtmp->mleashed && mtmp != u.usteed) Your("leash goes slack."); else if (cansee(mtmp->mx, mtmp->my)) - pline("%s starves.", Monnam(mtmp)); + pline_xy(mtmp->mx, mtmp->my, "%s starves.", Monnam(mtmp)); else You_feel("%s for a moment.", Hallucination ? "bummed" : "sad"); @@ -363,7 +363,8 @@ dog_hunger(struct monst *mtmp, struct edog *edog) return TRUE; } if (cansee(mtmp->mx, mtmp->my)) - pline("%s is confused from hunger.", Monnam(mtmp)); + pline_xy(mtmp->mx, mtmp->my, + "%s is confused from hunger.", Monnam(mtmp)); else if (couldsee(mtmp->mx, mtmp->my)) beg(mtmp); else @@ -1263,8 +1264,8 @@ dog_move( if (info[chi] & ALLOW_U) { if (mtmp->mleashed) { /* play it safe */ - pline("%s breaks loose of %s leash!", Monnam(mtmp), - mhis(mtmp)); + pline_xy(mtmp->mx, mtmp->my, "%s breaks loose of %s leash!", + Monnam(mtmp), mhis(mtmp)); m_unleash(mtmp, FALSE); } (void) mattacku(mtmp); @@ -1288,7 +1289,8 @@ dog_move( ? vobj_at(nix, niy) : 0; const char *what = o ? distant_name(o, doname) : something; - pline("%s %s reluctantly %s %s.", noit_Monnam(mtmp), + pline_xy(mtmp->mx, mtmp->my, "%s %s reluctantly %s %s.", + noit_Monnam(mtmp), vtense((char *) 0, locomotion(mtmp->data, "step")), (is_flyer(mtmp->data) || is_floater(mtmp->data)) ? "over" : "onto", From 7fa38eb7b3cd9874b4c5fe3c853775011ef88f3f Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sat, 14 Dec 2024 15:20:14 +0200 Subject: [PATCH 185/791] Use pline_mon instead of pline_xy Forgot about this function. Whoops. --- src/dog.c | 18 ++++++++---------- src/dogmove.c | 14 ++++++-------- src/mon.c | 2 +- src/mthrowu.c | 2 +- 4 files changed, 16 insertions(+), 20 deletions(-) diff --git a/src/dog.c b/src/dog.c index 6c7849f0b..53d3aea66 100644 --- a/src/dog.c +++ b/src/dog.c @@ -791,8 +791,7 @@ keepdogs( mdrop_special_objs(mtmp); /* drop Amulet */ } else if (mtmp->meating || mtmp->mtrapped) { if (canseemon(mtmp)) - pline_xy(mtmp->mx, mtmp->my, - "%s is still %s.", Monnam(mtmp), + pline_mon(mtmp, "%s is still %s.", Monnam(mtmp), mtmp->meating ? "eating" : "trapped"); stay_behind = TRUE; } else if (mon_has_amulet(mtmp)) { @@ -1128,7 +1127,7 @@ tamedog( /* worst case, at least it'll be peaceful. */ if (givemsg && !mtmp->mpeaceful && canspotmon(mtmp)) { - pline_xy(mtmp->mx, mtmp->my, "%s seems %s.", Monnam(mtmp), + pline_mon(mtmp, "%s seems %s.", Monnam(mtmp), Hallucination ? "really chill" : "more amiable"); givemsg = FALSE; /* don't give another message below */ } @@ -1163,8 +1162,8 @@ tamedog( boolean big_corpse = (obj->otyp == CORPSE && ismnum(obj->corpsenm) && mons[obj->corpsenm].msize > mtmp->data->msize); - pline_xy(mtmp->mx, mtmp->my, - "%s catches %s%s", Monnam(mtmp), the(xname(obj)), + pline_mon(mtmp, "%s catches %s%s", + Monnam(mtmp), the(xname(obj)), !big_corpse ? "." : ", or vice versa!"); } else if (cansee(mtmp->mx, mtmp->my)) pline("%s.", Tobjnam(obj, "stop")); @@ -1225,7 +1224,7 @@ tamedog( } if (givemsg && canspotmon(mtmp)) - pline_xy(mtmp->mx, mtmp->my, "%s seems quite %s.", Monnam(mtmp), + pline_mon(mtmp, "%s seems quite %s.", Monnam(mtmp), Hallucination ? "approachable" : "friendly"); newsym(mtmp->mx, mtmp->my); @@ -1272,13 +1271,12 @@ wary_dog(struct monst *mtmp, boolean was_dead) if (!quietly && cansee(mtmp->mx, mtmp->my)) { if (haseyes(gy.youmonst.data)) { if (haseyes(mtmp->data)) - pline_xy(mtmp->mx, mtmp->my, + pline_mon(mtmp, "%s %s to look you in the %s.", Monnam(mtmp), mtmp->mpeaceful ? "seems unable" : "refuses", body_part(EYE)); else - pline_xy(mtmp->mx, mtmp->my, - "%s avoids your gaze.", Monnam(mtmp)); + pline_mon(mtmp, "%s avoids your gaze.", Monnam(mtmp)); } } } else { @@ -1290,7 +1288,7 @@ wary_dog(struct monst *mtmp, boolean was_dead) if (!mtmp->mtame) { if (!quietly && canspotmon(mtmp)) - pline_xy(mtmp->mx, mtmp->my, "%s %s.", Monnam(mtmp), + pline_mon(mtmp, "%s %s.", Monnam(mtmp), mtmp->mpeaceful ? "is no longer tame" : "has become feral"); newsym(mtmp->mx, mtmp->my); /* a life-saved monster might be leashed; diff --git a/src/dogmove.c b/src/dogmove.c index a6ff8bce0..b0fe44864 100644 --- a/src/dogmove.c +++ b/src/dogmove.c @@ -283,9 +283,9 @@ dog_eat(struct monst *mtmp, result won't be printed */ obj_name = distant_name(obj, doname); if (tunnels(mtmp->data)) - pline_xy(mtmp->mx, mtmp->my, "%s digs in.", noit_Monnam(mtmp)); + pline_mon(mtmp, "%s digs in.", noit_Monnam(mtmp)); else - pline_xy(mtmp->mx, mtmp->my, "%s %s %s.", noit_Monnam(mtmp), + pline_mon(mtmp, "%s %s %s.", noit_Monnam(mtmp), devour ? "devours" : "eats", obj_name); } else if (seeobj) { obj_name = distant_name(obj, doname); @@ -335,7 +335,7 @@ dog_starve(struct monst *mtmp) if (mtmp->mleashed && mtmp != u.usteed) Your("leash goes slack."); else if (cansee(mtmp->mx, mtmp->my)) - pline_xy(mtmp->mx, mtmp->my, "%s starves.", Monnam(mtmp)); + pline_mon(mtmp, "%s starves.", Monnam(mtmp)); else You_feel("%s for a moment.", Hallucination ? "bummed" : "sad"); @@ -363,8 +363,7 @@ dog_hunger(struct monst *mtmp, struct edog *edog) return TRUE; } if (cansee(mtmp->mx, mtmp->my)) - pline_xy(mtmp->mx, mtmp->my, - "%s is confused from hunger.", Monnam(mtmp)); + pline_mon(mtmp, "%s is confused from hunger.", Monnam(mtmp)); else if (couldsee(mtmp->mx, mtmp->my)) beg(mtmp); else @@ -1264,7 +1263,7 @@ dog_move( if (info[chi] & ALLOW_U) { if (mtmp->mleashed) { /* play it safe */ - pline_xy(mtmp->mx, mtmp->my, "%s breaks loose of %s leash!", + pline_mon(mtmp, "%s breaks loose of %s leash!", Monnam(mtmp), mhis(mtmp)); m_unleash(mtmp, FALSE); } @@ -1289,8 +1288,7 @@ dog_move( ? vobj_at(nix, niy) : 0; const char *what = o ? distant_name(o, doname) : something; - pline_xy(mtmp->mx, mtmp->my, "%s %s reluctantly %s %s.", - noit_Monnam(mtmp), + pline_mon(mtmp, "%s %s reluctantly %s %s.", noit_Monnam(mtmp), vtense((char *) 0, locomotion(mtmp->data, "step")), (is_flyer(mtmp->data) || is_floater(mtmp->data)) ? "over" : "onto", diff --git a/src/mon.c b/src/mon.c index cf77dd8c6..7a381420b 100644 --- a/src/mon.c +++ b/src/mon.c @@ -5846,7 +5846,7 @@ shieldeff_mon(struct monst *mtmp) shieldeff(mtmp->mx, mtmp->my); /* does not depend on seeing the monster; the shield effect is visible */ if (cansee(mtmp->mx, mtmp->my)) - pline_xy(mtmp->mx, mtmp->my, "%s resists!", Monnam(mtmp)); + pline_mon(mtmp, "%s resists!", Monnam(mtmp)); } /*mon.c*/ diff --git a/src/mthrowu.c b/src/mthrowu.c index 5c41ea428..1d3e749ef 100644 --- a/src/mthrowu.c +++ b/src/mthrowu.c @@ -1026,7 +1026,7 @@ thrwmu(struct monst *mtmp) if (canseemon(mtmp)) { onm = xname(otmp); - pline_xy(mtmp->mx, mtmp->my, "%s %s %s.", Monnam(mtmp), + pline_mon(mtmp, "%s %s %s.", Monnam(mtmp), /* "thrusts" or "swings", or "bashes with" if adjacent */ mswings_verb(otmp, (rang <= 2) ? TRUE : FALSE), obj_is_pname(otmp) ? the(onm) : an(onm)); From 8e186fd5e6ede4bcfd2699e70d1f2e8b65885b9a Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sat, 14 Dec 2024 15:24:24 +0200 Subject: [PATCH 186/791] Accessibility: more message locations --- src/mcastu.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/mcastu.c b/src/mcastu.c index a968d7e0a..4ac28f956 100644 --- a/src/mcastu.c +++ b/src/mcastu.c @@ -361,7 +361,7 @@ m_cure_self(struct monst *mtmp, int dmg) { if (mtmp->mhp < mtmp->mhpmax) { if (canseemon(mtmp)) - pline("%s looks better.", Monnam(mtmp)); + pline_mon(mtmp, "%s looks better.", Monnam(mtmp)); /* note: player healing does 6d4; this used to do 1d8 */ if ((mtmp->mhp += d(3, 6)) > mtmp->mhpmax) mtmp->mhp = mtmp->mhpmax; @@ -565,7 +565,7 @@ cast_wizard_spell(struct monst *mtmp, int dmg, int spellnum) case MGC_DISAPPEAR: /* makes self invisible */ if (!mtmp->minvis && !mtmp->invis_blkd) { if (canseemon(mtmp)) - pline("%s suddenly %s!", Monnam(mtmp), + pline_mon(mtmp, "%s suddenly %s!", Monnam(mtmp), !See_invisible ? "disappears" : "becomes transparent"); mon_set_minvis(mtmp); if (cansee(mtmp->mx, mtmp->my) && !canspotmon(mtmp)) @@ -790,7 +790,7 @@ cast_cleric_spell(struct monst *mtmp, int dmg, int spellnum) fmt = "%s summons %s!"; } if (fmt) - pline(fmt, Monnam(mtmp), what); + pline_mon(mtmp, fmt, Monnam(mtmp), what); dmg = 0; break; @@ -993,7 +993,7 @@ buzzmu(struct monst *mtmp, struct attack *mattk) if (lined_up(mtmp) && rn2(3)) { nomul(0); if (canseemon(mtmp)) - pline("%s zaps you with a %s!", Monnam(mtmp), + pline_mon(mtmp, "%s zaps you with a %s!", Monnam(mtmp), flash_str(BZ_OFS_AD(mattk->adtyp), FALSE)); gb.buzzer = mtmp; buzz(BZ_M_SPELL(BZ_OFS_AD(mattk->adtyp)), (int) mattk->damn, From 055c0d5954a59020aa1c6041605fcc8706331ae8 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sat, 14 Dec 2024 15:30:12 +0200 Subject: [PATCH 187/791] Accessibility: more message locations pt 2 --- src/mhitm.c | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/src/mhitm.c b/src/mhitm.c index a65ed98d7..eb3bcccda 100644 --- a/src/mhitm.c +++ b/src/mhitm.c @@ -232,7 +232,7 @@ mdisplacem( pline("%s tries to move %s out of %s way.", Monnam(magr), mon_nam(mdef), is_rider(pa) ? "the" : mhis(magr)); } - pline("%s turns to stone!", Monnam(magr)); + pline_mon(magr, "%s turns to stone!", Monnam(magr)); } monstone(magr); if (!DEADMONSTER(magr)) @@ -338,7 +338,7 @@ mattackm( } else { if (iflags.last_msg == PLNMSG_HIDE_UNDER && mdef->m_id == gl.last_hider) - pline("%s emerges from hiding.", Monnam(mdef)); + pline_mon(mdef, "%s emerges from hiding.", Monnam(mdef)); else if (mdef->m_id == gl.last_hider) You("notice %s.", mon_nam(mdef)); else @@ -771,7 +771,7 @@ gazemm(struct monst *magr, struct monst *mdef, struct attack *mattk) return M_ATTK_MISS; } if (canseemon(magr)) - pline("%s is turned to stone!", Monnam(magr)); + pline_mon(magr, "%s is turned to stone!", Monnam(magr)); monstone(magr); if (!DEADMONSTER(magr)) return M_ATTK_MISS; @@ -962,7 +962,7 @@ explmm(struct monst *magr, struct monst *mdef, struct attack *mattk) return M_ATTK_MISS; if (cansee(magr->mx, magr->my)) - pline("%s explodes!", Monnam(magr)); + pline_mon(magr, "%s explodes!", Monnam(magr)); else noises(magr, mattk); @@ -1033,7 +1033,7 @@ mdamagem( return M_ATTK_HIT; /* no damage during the polymorph */ } if (gv.vis && canspotmon(magr)) - pline("%s turns to stone!", Monnam(magr)); + pline_mon(magr, "%s turns to stone!", Monnam(magr)); monstone(magr); if (!DEADMONSTER(magr)) return M_ATTK_HIT; /* lifesaved */ @@ -1238,7 +1238,7 @@ slept_monst(struct monst *mon) { if (helpless(mon) && mon == u.ustuck && !sticks(gy.youmonst.data) && !u.uswallow) { - pline("%s grip relaxes.", s_suffix(Monnam(mon))); + pline_mon(mon, "%s grip relaxes.", s_suffix(Monnam(mon))); unstuck(mon); } } @@ -1382,14 +1382,14 @@ passivemm( case AD_COLD: if (resists_cold(magr)) { if (canseemon(magr)) { - pline("%s is mildly chilly.", Monnam(magr)); + pline_mon(magr, "%s is mildly chilly.", Monnam(magr)); golemeffects(magr, AD_COLD, tmp); } tmp = 0; break; } if (canseemon(magr)) - pline("%s is suddenly very cold!", Monnam(magr)); + pline_mon(magr, "%s is suddenly very cold!", Monnam(magr)); mdef->mhp += tmp / 2; if (mdef->mhpmax < mdef->mhp) mdef->mhpmax = mdef->mhp; @@ -1400,7 +1400,7 @@ passivemm( if (!magr->mstun) { magr->mstun = 1; if (canseemon(magr)) - pline("%s %s...", Monnam(magr), + pline_mon(magr, "%s %s...", Monnam(magr), makeplural(stagger(magr->data, "stagger"))); } tmp = 0; @@ -1408,26 +1408,27 @@ passivemm( case AD_FIRE: if (resists_fire(magr)) { if (canseemon(magr)) { - pline("%s is mildly warmed.", Monnam(magr)); + pline_mon(magr, "%s is mildly warmed.", Monnam(magr)); golemeffects(magr, AD_FIRE, tmp); } tmp = 0; break; } if (canseemon(magr)) - pline("%s is suddenly very hot!", Monnam(magr)); + pline_mon(magr, "%s is suddenly very hot!", Monnam(magr)); break; case AD_ELEC: if (resists_elec(magr)) { if (canseemon(magr)) { - pline("%s is mildly tingled.", Monnam(magr)); + pline_mon(magr, "%s is mildly tingled.", Monnam(magr)); golemeffects(magr, AD_ELEC, tmp); } tmp = 0; break; } if (canseemon(magr)) - pline("%s is jolted with electricity!", Monnam(magr)); + pline_mon(magr, "%s is jolted with electricity!", + Monnam(magr)); break; default: tmp = 0; @@ -1453,7 +1454,7 @@ xdrainenergym(struct monst *mon, boolean givemsg) || attacktype(mon->data, AT_BREA))) { mon->mspec_used += d(2, 2); if (givemsg) - pline("%s seems lethargic.", Monnam(mon)); + pline_mon(mon, "%s seems lethargic.", Monnam(mon)); } } From 369f1ff95916489673e42471e97934ba5a6c966b Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sat, 14 Dec 2024 15:36:05 +0200 Subject: [PATCH 188/791] Accessibility: more message locations pt 3 --- src/mhitu.c | 73 +++++++++++++++++++++++++++++------------------------ 1 file changed, 40 insertions(+), 33 deletions(-) diff --git a/src/mhitu.c b/src/mhitu.c index fea0349eb..31289282b 100644 --- a/src/mhitu.c +++ b/src/mhitu.c @@ -269,7 +269,7 @@ expels( if (digests(mdat)) { You("get regurgitated!"); } else if (enfolds(mdat)) { - pline("%s unfolds and you are released!", Monnam(mtmp)); + pline_mon(mtmp, "%s unfolds and you are released!", Monnam(mtmp)); } else { char blast[40]; struct attack *attk = attacktype_fordmg(mdat, AT_ENGL, AD_ANY); @@ -549,7 +549,7 @@ mattacku(struct monst *mtmp) so mtmp's next move will be a regular attack */ place_monster(mtmp, mtmp->mx, mtmp->my); /* put back */ newsym(u.ux, u.uy); /* u.uundetected was toggled */ - pline("%s draws back as you drop!", Monnam(mtmp)); + pline_mon(mtmp, "%s draws back as you drop!", Monnam(mtmp)); return 0; } @@ -717,7 +717,7 @@ mattacku(struct monst *mtmp) if (u.uinvulnerable) { /* in the midst of successful prayer */ /* monsters won't attack you */ if (mtmp == u.ustuck) { - pline("%s loosens its grip slightly.", Monnam(mtmp)); + pline_mon(mtmp, "%s loosens its grip slightly.", Monnam(mtmp)); } else if (!range2) { if (youseeit || sensemon(mtmp)) pline("%s starts to attack you, but pulls back.", @@ -821,10 +821,11 @@ mattacku(struct monst *mtmp) missmu(mtmp, (tmp == j), mattk); } } else if (digests(mtmp->data)) { - pline("%s gulps some air!", Monnam(mtmp)); + pline_mon(mtmp, "%s gulps some air!", Monnam(mtmp)); } else { if (youseeit) { - pline("%s lunges forward and recoils!", Monnam(mtmp)); + pline_mon(mtmp, "%s lunges forward and recoils!", + Monnam(mtmp)); } else { if (is_whirly(mtmp->data)) { Soundeffect(se_rushing_wind_noise, 60); @@ -956,7 +957,7 @@ summonmu(struct monst *mtmp, boolean youseeit) Strcpy(genericwere, "creature"); if (youseeit) - pline("%s summons help!", Monnam(mtmp)); + pline_mon(mtmp, "%s summons help!", Monnam(mtmp)); numhelp = were_summon(mdat, FALSE, &numseen, genericwere); if (youseeit) { if (numhelp > 0) { @@ -1026,7 +1027,7 @@ u_slip_free(struct monst *mtmp, struct attack *mattk) protection might fail (33% chance) when the armor is cursed */ if (obj && (obj->greased || obj->otyp == OILSKIN_CLOAK) && (!obj->cursed || rn2(3))) { - pline("%s %s your %s %s!", Monnam(mtmp), + pline_mon(mtmp, "%s %s your %s %s!", Monnam(mtmp), (mattk->adtyp == AD_WRAP) ? "slips off of" : "grabs you, but cannot hold onto", obj->greased ? "greased" : "slippery", @@ -1662,7 +1663,7 @@ gazemu(struct monst *mtmp, struct attack *mattk) if (is_medusa && Hallucination && !rn2(3)) pline("Someone seems overdue for a serpent cut."); else - pline("%s %s.", Monnam(mtmp), + pline_mon(mtmp, "%s %s.", Monnam(mtmp), (is_medusa && mtmp->mcan && !react) ? "doesn't look all that ugly" : "gazes ineffectually"); @@ -1686,7 +1687,7 @@ gazemu(struct monst *mtmp, struct attack *mattk) break; } if (useeit) - pline("%s is turned to stone!", Monnam(mtmp)); + pline_mon(mtmp, "%s is turned to stone!", Monnam(mtmp)); gs.stoned = TRUE; killed(mtmp); @@ -1716,7 +1717,8 @@ gazemu(struct monst *mtmp, struct attack *mattk) mtmp->mspec_used = mtmp->mspec_used + (conf + rn2(6)); if (!Confusion) - pline("%s gaze confuses you!", s_suffix(Monnam(mtmp))); + pline_mon(mtmp, "%s gaze confuses you!", + s_suffix(Monnam(mtmp))); else You("are getting more and more confused."); make_confused(HConfusion + conf, FALSE); @@ -1733,7 +1735,7 @@ gazemu(struct monst *mtmp, struct attack *mattk) int stun = d(2, 6); mtmp->mspec_used = mtmp->mspec_used + (stun + rn2(6)); - pline("%s stares piercingly at you!", Monnam(mtmp)); + pline_mon(mtmp, "%s stares piercingly at you!", Monnam(mtmp)); make_stunned((HStun & TIMEOUT) + (long) stun, TRUE); stop_occupation(); } @@ -1777,7 +1779,8 @@ gazemu(struct monst *mtmp, struct attack *mattk) } else { int dmg = d(2, 6), orig_dmg = dmg, lev = (int) mtmp->m_lev; - pline("%s attacks you with a fiery gaze!", Monnam(mtmp)); + pline_mon(mtmp, "%s attacks you with a fiery gaze!", + Monnam(mtmp)); stop_occupation(); if (Fire_resistance) { shieldeff(u.ux, u.uy); @@ -1837,7 +1840,7 @@ gazemu(struct monst *mtmp, struct attack *mattk) react = rn2(SIZE(reactions)); /* cancelled/hallucinatory feedback; monster might look "confused", "stunned",&c but we don't actually set corresponding attribute */ - pline("%s looks %s%s.", Monnam(mtmp), + pline_mon(mtmp, "%s looks %s%s.", Monnam(mtmp), !rn2(3) ? "" : already ? "quite " : (!rn2(2) ? "a bit " : "somewhat "), reactions[react]); @@ -1941,12 +1944,13 @@ doseduce(struct monst *mon) char qbuf[QBUFSZ], Who[QBUFSZ]; if (mon->mcan || mon->mspec_used) { - pline("%s acts as though %s has got a %sheadache.", Monnam(mon), - mhe(mon), mon->mcan ? "severe " : ""); + pline_mon(mon, "%s acts as though %s has got a %sheadache.", + Monnam(mon), mhe(mon), mon->mcan ? "severe " : ""); return 0; } if (unresponsive()) { - pline("%s seems dismayed at your lack of response.", Monnam(mon)); + pline_mon(mon, "%s seems dismayed at your lack of response.", + Monnam(mon)); return 0; } seewho = canseemon(mon); @@ -2104,7 +2108,7 @@ doseduce(struct monst *mon) : ""); } } else if (seewho) - pline("%s appears to sigh.", Monnam(mon)); + pline_mon(mon, "%s appears to sigh.", Monnam(mon)); /* else no regret message if can't see or hear seducer */ if (!tele_restrict(mon)) @@ -2214,7 +2218,8 @@ doseduce(struct monst *mon) pline("%s demands that you pay %s, but you refuse...", noit_Monnam(mon), noit_mhim(mon)); } else if (u.umonnum == PM_LEPRECHAUN) { - pline("%s tries to take your gold, but fails...", noit_Monnam(mon)); + pline_mon(mon, "%s tries to take your gold, but fails...", + noit_Monnam(mon)); } else { long cost; long umoney = money_cnt(gi.invent); @@ -2234,8 +2239,8 @@ doseduce(struct monst *mon) SetVoice(mon, 0, 80, 0); verbalize("It's on the house!"); } else { - pline("%s takes %ld %s for services rendered!", noit_Monnam(mon), - cost, currency(cost)); + pline_mon(mon, "%s takes %ld %s for services rendered!", + noit_Monnam(mon), cost, currency(cost)); money2mon(mon, cost); disp.botl = TRUE; } @@ -2298,7 +2303,7 @@ staticfn int assess_dmg(struct monst *mtmp, int tmp) { if ((mtmp->mhp -= tmp) <= 0) { - pline("%s dies!", Monnam(mtmp)); + pline_mon(mtmp, "%s dies!", Monnam(mtmp)); xkilled(mtmp, XKILL_NOMSG); if (!DEADMONSTER(mtmp)) return M_ATTK_HIT; @@ -2402,13 +2407,13 @@ passiveum( switch (oldu_mattk->adtyp) { case AD_ACID: if (!rn2(2)) { - pline("%s is splashed by %s%s!", Monnam(mtmp), + pline_mon(mtmp, "%s is splashed by %s%s!", Monnam(mtmp), /* temporary? hack for sequencing issue: "your acid" looks strange coming immediately after player has been told that hero has reverted to normal form */ !Upolyd ? "" : "your ", hliquid("acid")); if (resists_acid(mtmp)) { - pline("%s is not affected.", Monnam(mtmp)); + pline_mon(mtmp, "%s is not affected.", Monnam(mtmp)); tmp = 0; } } else @@ -2435,7 +2440,7 @@ passiveum( mon_to_stone(mtmp); return 1; } - pline("%s turns to stone!", Monnam(mtmp)); + pline_mon(mtmp, "%s turns to stone!", Monnam(mtmp)); gs.stoned = 1; xkilled(mtmp, XKILL_NOMSG); if (!DEADMONSTER(mtmp)) @@ -2485,13 +2490,14 @@ passiveum( if (mon_reflects(mtmp, "Your gaze is reflected by %s %s.")) return 1; - pline("%s is frozen by your gaze!", Monnam(mtmp)); + pline_mon(mtmp, "%s is frozen by your gaze!", + Monnam(mtmp)); paralyze_monst(mtmp, tmp); return M_ATTK_AGR_DONE; } } } else { /* gelatinous cube */ - pline("%s is frozen by you.", Monnam(mtmp)); + pline_mon(mtmp, "%s is frozen by you.", Monnam(mtmp)); paralyze_monst(mtmp, tmp); return M_ATTK_AGR_DONE; } @@ -2499,12 +2505,12 @@ passiveum( case AD_COLD: /* Brown mold or blue jelly */ if (resists_cold(mtmp)) { shieldeff(mtmp->mx, mtmp->my); - pline("%s is mildly chilly.", Monnam(mtmp)); + pline_mon(mtmp, "%s is mildly chilly.", Monnam(mtmp)); golemeffects(mtmp, AD_COLD, tmp); tmp = 0; break; } - pline("%s is suddenly very cold!", Monnam(mtmp)); + pline_mon(mtmp, "%s is suddenly very cold!", Monnam(mtmp)); u.mh += (tmp + rn2(2)) / 2; if (u.mhmax < u.mh) u.mhmax = u.mh; @@ -2514,7 +2520,7 @@ passiveum( case AD_STUN: /* Yellow mold */ if (!mtmp->mstun) { mtmp->mstun = 1; - pline("%s %s.", Monnam(mtmp), + pline_mon(mtmp, "%s %s.", Monnam(mtmp), makeplural(stagger(mtmp->data, "stagger"))); } tmp = 0; @@ -2522,22 +2528,23 @@ passiveum( case AD_FIRE: /* Red mold */ if (resists_fire(mtmp)) { shieldeff(mtmp->mx, mtmp->my); - pline("%s is mildly warm.", Monnam(mtmp)); + pline_mon(mtmp, "%s is mildly warm.", Monnam(mtmp)); golemeffects(mtmp, AD_FIRE, tmp); tmp = 0; break; } - pline("%s is suddenly very hot!", Monnam(mtmp)); + pline_mon(mtmp, "%s is suddenly very hot!", Monnam(mtmp)); break; case AD_ELEC: if (resists_elec(mtmp)) { shieldeff(mtmp->mx, mtmp->my); - pline("%s is slightly tingled.", Monnam(mtmp)); + pline_mon(mtmp, "%s is slightly tingled.", Monnam(mtmp)); golemeffects(mtmp, AD_ELEC, tmp); tmp = 0; break; } - pline("%s is jolted with your electricity!", Monnam(mtmp)); + pline_mon(mtmp, "%s is jolted with your electricity!", + Monnam(mtmp)); break; default: tmp = 0; From 1849985214b327ff507653fcd140a41d89342aa5 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sat, 14 Dec 2024 15:51:55 +0200 Subject: [PATCH 189/791] Accessibility: more message locations pt 4 --- src/muse.c | 108 +++++++++++++++++++++++++++-------------------------- 1 file changed, 55 insertions(+), 53 deletions(-) diff --git a/src/muse.c b/src/muse.c index 0cece8f6a..533f6ec22 100644 --- a/src/muse.c +++ b/src/muse.c @@ -107,7 +107,7 @@ precheck(struct monst *mon, struct obj *obj) pline1(empty); } else { if (vis) - pline("In a cloud of smoke, %s emerges!", a_monnam(mtmp)); + pline_mon(mtmp, "In a cloud of smoke, %s emerges!", a_monnam(mtmp)); pline("%s speaks.", vis ? Monnam(mtmp) : Something); /* I suspect few players will be upset that monsters */ /* can't wish for wands of death here.... */ @@ -133,7 +133,7 @@ precheck(struct monst *mon, struct obj *obj) /* 3.6.1: no Deaf filter; 'if' message doesn't warrant it, 'else' message doesn't need it since You_hear() has one of its own */ if (vis) { - pline("%s zaps %s, which suddenly explodes!", Monnam(mon), + pline_mon(mon, "%s zaps %s, which suddenly explodes!", Monnam(mon), an(xname(obj))); } else { /* same near/far threshold as mzapwand() */ @@ -182,7 +182,7 @@ mzapwand( monverbself(mtmp, Monnam(mtmp), "zap", (char *) 0), doname(otmp)); } else { - pline("%s zaps %s!", Monnam(mtmp), an(xname(otmp))); + pline_mon(mtmp, "%s zaps %s!", Monnam(mtmp), an(xname(otmp))); stop_occupation(); } otmp->spe -= 1; @@ -246,7 +246,7 @@ mreadmsg(struct monst *mtmp, struct obj *otmp) if (vismon) { /* directly see the monster reading the scroll */ - pline("%s reads %s!", Monnam(mtmp), onambuf); + pline_mon(mtmp, "%s reads %s!", Monnam(mtmp), onambuf); } else { /* !Deaf, otherwise we wouldn't reach here */ char blindbuf[BUFSZ]; boolean similar = same_race(gy.youmonst.data, mtmp->data), @@ -285,7 +285,7 @@ mquaffmsg(struct monst *mtmp, struct obj *otmp) { if (canseemon(mtmp)) { otmp->dknown = 1; - pline("%s drinks %s!", Monnam(mtmp), singular(otmp, doname)); + pline_mon(mtmp, "%s drinks %s!", Monnam(mtmp), singular(otmp, doname)); } else if (!Deaf) { Soundeffect(se_mon_chugging_potion, 25); You_hear("a chugging sound."); @@ -386,7 +386,7 @@ m_tele( mon_learns_traps(mtmp, TELEP_TRAP); } else if ((mon_has_amulet(mtmp) || On_W_tower_level(&u.uz)) && !rn2(3)) { if (vismon) - pline("%s seems disoriented for a moment.", Monnam(mtmp)); + pline_mon(mtmp, "%s seems disoriented for a moment.", Monnam(mtmp)); } else { /* teleport monster 'mtmp' */ if (how) { @@ -775,7 +775,7 @@ mon_escape(struct monst *mtmp, boolean vismon) || (mtmp->iswiz && svc.context.no_of_wizards < 2)) return 0; if (vismon) - pline("%s escapes the dungeon!", Monnam(mtmp)); + pline_mon(mtmp, "%s escapes the dungeon!", Monnam(mtmp)); mongone(mtmp); return 2; } @@ -811,7 +811,7 @@ use_defensive(struct monst *mtmp) case MUSE_UNICORN_HORN: if (vismon) { if (otmp) - pline("%s uses a unicorn horn!", Monnam(mtmp)); + pline_mon(mtmp, "%s uses a unicorn horn!", Monnam(mtmp)); else pline_The("tip of %s's horn glows!", mon_nam(mtmp)); } @@ -820,13 +820,13 @@ use_defensive(struct monst *mtmp) } else if (mtmp->mconf || mtmp->mstun) { mtmp->mconf = mtmp->mstun = 0; if (vismon) - pline("%s seems steadier now.", Monnam(mtmp)); + pline_mon(mtmp, "%s seems steadier now.", Monnam(mtmp)); } else impossible("No need for unicorn horn?"); return 2; case MUSE_BUGLE: if (vismon) { - pline("%s plays %s!", Monnam(mtmp), doname(otmp)); + pline_mon(mtmp, "%s plays %s!", Monnam(mtmp), doname(otmp)); } else if (!Deaf) { Soundeffect(se_bugle_playing_reveille, 100); You_hear("a bugle playing reveille!"); @@ -873,11 +873,11 @@ use_defensive(struct monst *mtmp) nlev = random_teleport_level(); if (mon_has_amulet(mtmp) || In_endgame(&u.uz)) { if (vismon) - pline("%s seems very disoriented for a moment.", + pline_mon(mtmp, "%s seems very disoriented for a moment.", Monnam(mtmp)); } else if (nlev == depth(&u.uz)) { if (vismon) - pline("%s shudders for a moment.", Monnam(mtmp)); + pline_mon(mtmp, "%s shudders for a moment.", Monnam(mtmp)); } else { get_level(&flev, nlev); migrate_to_level(mtmp, ledger_no(&flev), MIGR_RANDOM, @@ -920,7 +920,7 @@ use_defensive(struct monst *mtmp) /* pit creation succeeded */ if (vis) { seetrap(t); - pline("%s has made a pit in the %s.", Monnam(mtmp), + pline_mon(mtmp, "%s has made a pit in the %s.", Monnam(mtmp), surface(mtmp->mx, mtmp->my)); } fill_pit(mtmp->mx, mtmp->my); @@ -931,9 +931,9 @@ use_defensive(struct monst *mtmp) return 2; seetrap(t); if (vis) { - pline("%s has made a hole in the %s.", Monnam(mtmp), + pline_mon(mtmp, "%s has made a hole in the %s.", Monnam(mtmp), surface(mtmp->mx, mtmp->my)); - pline("%s %s through...", Monnam(mtmp), + pline_mon(mtmp, "%s %s through...", Monnam(mtmp), is_flyer(mtmp->data) ? "dives" : "falls"); } else if (!Deaf) { Soundeffect(se_crash_through_floor, 100); @@ -1014,7 +1014,7 @@ use_defensive(struct monst *mtmp) m_flee(mtmp); t = t_at(gt.trapx, gt.trapy); if (vis) { - pline("%s %s into a %s!", Monnam(mtmp), + pline_mon(mtmp, "%s %s into a %s!", Monnam(mtmp), vtense(fakename[0], locomotion(mtmp->data, "jump")), trapname(t->ttyp, FALSE)); } @@ -1054,7 +1054,7 @@ use_defensive(struct monst *mtmp) (coord *) 0); } else { if (vismon) - pline("%s escapes upstairs!", Monnam(mtmp)); + pline_mon(mtmp, "%s escapes upstairs!", Monnam(mtmp)); migrate_to_level(mtmp, ledger_no(&(stway->tolev)), MIGR_STAIRS_DOWN, (coord *) 0); } @@ -1065,7 +1065,7 @@ use_defensive(struct monst *mtmp) if (!stway) return 0; if (vismon) - pline("%s escapes downstairs!", Monnam(mtmp)); + pline_mon(mtmp, "%s escapes downstairs!", Monnam(mtmp)); migrate_to_level(mtmp, ledger_no(&(stway->tolev)), MIGR_STAIRS_UP, (coord *) 0); return 2; @@ -1075,7 +1075,7 @@ use_defensive(struct monst *mtmp) if (!stway) return 0; if (vismon) - pline("%s escapes up the ladder!", Monnam(mtmp)); + pline_mon(mtmp, "%s escapes up the ladder!", Monnam(mtmp)); migrate_to_level(mtmp, ledger_no(&(stway->tolev)), MIGR_LADDER_DOWN, (coord *) 0); return 2; @@ -1085,7 +1085,7 @@ use_defensive(struct monst *mtmp) if (!stway) return 0; if (vismon) - pline("%s escapes down the ladder!", Monnam(mtmp)); + pline_mon(mtmp, "%s escapes down the ladder!", Monnam(mtmp)); migrate_to_level(mtmp, ledger_no(&(stway->tolev)), MIGR_LADDER_UP, (coord *) 0); return 2; @@ -1098,7 +1098,7 @@ use_defensive(struct monst *mtmp) return mon_escape(mtmp, vismon); } if (vismon) - pline("%s escapes %sstairs!", Monnam(mtmp), + pline_mon(mtmp, "%s escapes %sstairs!", Monnam(mtmp), stway->up ? "up" : "down"); /* going from the Valley to Castle (Stronghold) has no sstairs to target, but having gs.sstairs. == <0,0> will work the @@ -1111,7 +1111,7 @@ use_defensive(struct monst *mtmp) m_flee(mtmp); t = t_at(gt.trapx, gt.trapy); if (vis) { - pline("%s %s onto a %s!", Monnam(mtmp), + pline_mon(mtmp, "%s %s onto a %s!", Monnam(mtmp), vtense(fakename[0], locomotion(mtmp->data, "jump")), trapname(t->ttyp, FALSE)); } @@ -1136,7 +1136,7 @@ use_defensive(struct monst *mtmp) if (!otmp->cursed && !mtmp->mcansee) mcureblindness(mtmp, vismon); if (vismon) - pline("%s looks better.", Monnam(mtmp)); + pline_mon(mtmp, "%s looks better.", Monnam(mtmp)); if (oseen) makeknown(POT_HEALING); m_useup(mtmp, otmp); @@ -1150,7 +1150,7 @@ use_defensive(struct monst *mtmp) if (!mtmp->mcansee) mcureblindness(mtmp, vismon); if (vismon) - pline("%s looks much better.", Monnam(mtmp)); + pline_mon(mtmp, "%s looks much better.", Monnam(mtmp)); if (oseen) makeknown(POT_EXTRA_HEALING); m_useup(mtmp, otmp); @@ -1163,7 +1163,7 @@ use_defensive(struct monst *mtmp) if (!mtmp->mcansee && otmp->otyp != POT_SICKNESS) mcureblindness(mtmp, vismon); if (vismon) - pline("%s looks completely healed.", Monnam(mtmp)); + pline_mon(mtmp, "%s looks completely healed.", Monnam(mtmp)); if (oseen) makeknown(otmp->otyp); m_useup(mtmp, otmp); @@ -1596,7 +1596,7 @@ mbhitm(struct monst *mtmp, struct obj *otmp) /* for consistency with zap.c, don't identify */ if (mtmp->ispriest && *in_rooms(mtmp->mx, mtmp->my, TEMPLE)) { if (cansee(mtmp->mx, mtmp->my)) - pline("%s resists the magic!", Monnam(mtmp)); + pline_mon(mtmp, "%s resists the magic!", Monnam(mtmp)); } else if (!tele_restrict(mtmp)) (void) rloc(mtmp, RLOC_MSG); } @@ -1889,7 +1889,7 @@ use_offensive(struct monst *mtmp) if (vis) pline_The("scroll erupts in a tower of flame!"); shieldeff(mtmp->mx, mtmp->my); - pline("%s is uninjured.", Monnam(mtmp)); + pline_mon(mtmp, "%s is uninjured.", Monnam(mtmp)); (void) destroy_mitem(mtmp, SCROLL_CLASS, AD_FIRE); (void) destroy_mitem(mtmp, SPBOOK_CLASS, AD_FIRE); (void) destroy_mitem(mtmp, POTION_CLASS, AD_FIRE); @@ -2262,7 +2262,7 @@ mloot_container( if (howfar > 2) /* not adjacent */ Norep("%s rummages through %s.", Monnam(mon), contnr_nam); else if (takeout_indx == 0) /* adjacent, first item */ - pline("%s removes %s from %s.", Monnam(mon), + pline_mon(mon, "%s removes %s from %s.", Monnam(mon), doname(xobj), contnr_nam); else /* adjacent, additional items */ pline("%s removes %s.", upstart(mpronounbuf), @@ -2324,8 +2324,9 @@ use_misc(struct monst *mtmp) if (on_level(&tolevel, &u.uz)) goto skipmsg; if (vismon) { - pline("%s rises up, through the %s!", Monnam(mtmp), - ceiling(mtmp->mx, mtmp->my)); + pline_mon(mtmp, "%s rises up, through the %s!", + Monnam(mtmp), + ceiling(mtmp->mx, mtmp->my)); trycall(otmp); } m_useup(mtmp, otmp); @@ -2335,7 +2336,7 @@ use_misc(struct monst *mtmp) } else { skipmsg: if (vismon) { - pline("%s looks uneasy.", Monnam(mtmp)); + pline_mon(mtmp, "%s looks uneasy.", Monnam(mtmp)); trycall(otmp); } m_useup(mtmp, otmp); @@ -2343,7 +2344,7 @@ use_misc(struct monst *mtmp) } } if (vismon) - pline("%s seems more experienced.", Monnam(mtmp)); + pline_mon(mtmp, "%s seems more experienced.", Monnam(mtmp)); if (oseen) makeknown(POT_GAIN_LEVEL); m_useup(mtmp, otmp); @@ -2403,7 +2404,7 @@ use_misc(struct monst *mtmp) mquaffmsg(mtmp, otmp); m_useup(mtmp, otmp); if (vismon) - pline("%s suddenly mutates!", Monnam(mtmp)); + pline_mon(mtmp, "%s suddenly mutates!", Monnam(mtmp)); (void) newcham(mtmp, muse_newcham_mon(mtmp), NC_SHOW_MSG); if (oseen) makeknown(POT_POLYMORPH); @@ -2414,7 +2415,7 @@ use_misc(struct monst *mtmp) if (vis || vistrapspot) seetrap(t); if (vismon || vistrapspot) { - pline("%s deliberately %s onto a %s!", Some_Monnam(mtmp), + pline_mon(mtmp, "%s deliberately %s onto a %s!", Some_Monnam(mtmp), vtense(fakename[0], locomotion(mtmp->data, "jump")), t->tseen ? trapname(t->ttyp, FALSE) : "hidden trap"); /* note: if mtmp is unseen because it is invisible, its new @@ -2457,8 +2458,8 @@ use_misc(struct monst *mtmp) hand = makeplural(hand); if (vismon) - pline("%s flicks a bullwhip towards your %s!", Monnam(mtmp), - hand); + pline_mon(mtmp, "%s flicks a bullwhip towards your %s!", + Monnam(mtmp), hand); if (obj->otyp == HEAVY_IRON_BALL) { pline("%s fails to wrap around %s.", The_whip, the_weapon); return 1; @@ -2485,17 +2486,17 @@ use_misc(struct monst *mtmp) freeinv(obj); switch (where_to) { case 1: /* onto floor beneath mon */ - pline("%s yanks %s from your %s!", Monnam(mtmp), the_weapon, - hand); + pline_mon(mtmp, "%s yanks %s from your %s!", Monnam(mtmp), + the_weapon, hand); place_object(obj, mtmp->mx, mtmp->my); break; case 2: /* onto floor beneath you */ - pline("%s yanks %s to the %s!", Monnam(mtmp), the_weapon, - surface(u.ux, u.uy)); + pline_mon(mtmp, "%s yanks %s to the %s!", Monnam(mtmp), + the_weapon, surface(u.ux, u.uy)); dropy(obj); break; case 3: /* into mon's inventory */ - pline("%s snatches %s!", Monnam(mtmp), the_weapon); + pline_mon(mtmp, "%s snatches %s!", Monnam(mtmp), the_weapon); (void) mpickobj(mtmp, obj); break; } @@ -2763,7 +2764,7 @@ mcureblindness(struct monst *mon, boolean verbos) mon->mcansee = 1; mon->mblinded = 0; if (verbos && haseyes(mon->data)) - pline("%s can see again.", Monnam(mon)); + pline_mon(mon, "%s can see again.", Monnam(mon)); } } @@ -2813,7 +2814,7 @@ mon_consume_unstone( long save_quan = obj->quan; obj->quan = 1L; - pline("%s %s %s.", Monnam(mon), + pline_mon(mon, "%s %s %s.", Monnam(mon), ((obj->oclass == POTION_CLASS) ? "quaffs" : (obj->otyp == TIN) ? "opens and eats the contents of" : "eats"), @@ -2829,9 +2830,9 @@ mon_consume_unstone( if (acid && !tinned && !resists_acid(mon)) { mon->mhp -= rnd(15); if (vis) - pline("%s has a very bad case of stomach acid.", Monnam(mon)); + pline_mon(mon, "%s has a very bad case of stomach acid.", Monnam(mon)); if (DEADMONSTER(mon)) { - pline("%s dies!", Monnam(mon)); + pline_mon(mon, "%s dies!", Monnam(mon)); if (by_you) /* hero gets credit (experience) and blame (possible loss of alignment and/or luck and/or telepathy depending on @@ -2847,13 +2848,13 @@ mon_consume_unstone( pline("What a pity - %s just ruined a future piece of art!", mon_nam(mon)); else - pline("%s seems limber!", Monnam(mon)); + pline_mon(mon, "%s seems limber!", Monnam(mon)); } if (lizard && (mon->mconf || mon->mstun)) { mon->mconf = 0; mon->mstun = 0; if (vis && !is_bat(mon->data) && mon->data != &mons[PM_STALKER]) - pline("%s seems steadier now.", Monnam(mon)); + pline_mon(mon, "%s seems steadier now.", Monnam(mon)); } if (mon->mtame && !mon->isminion && nutrit > 0) { struct edog *edog = EDOG(mon); @@ -3000,7 +3001,7 @@ muse_unslime( boolean vis = canseemon(mon), res = TRUE; if (vis) - pline("%s starts turning %s.", Monnam(mon), + pline_mon(mon, "%s starts turning %s.", Monnam(mon), green_mon(mon) ? "into ooze" : hcolor(NH_GREEN)); /* -4 => sliming, causes quiet loss of enhanced speed */ mon_adjust_speed(mon, -4, (struct obj *) 0); @@ -3029,7 +3030,8 @@ muse_unslime( } else if (otyp == STRANGE_OBJECT) { /* monster is using fire breath on self */ if (vis) - pline("%s.", monverbself(mon, Monnam(mon), "breath", "fire on")); + pline_mon(mon, "%s.", + monverbself(mon, Monnam(mon), "breath", "fire on")); if (!rn2(3)) mon->mspec_used = rn1(10, 5); /* -21 => monster's fire breath; 1 => # of damage dice */ @@ -3070,7 +3072,7 @@ muse_unslime( if (obj->quan > 1L) obj = splitobj(obj, 1L); if (vis && !was_lit) { - pline("%s ignites %s.", Monnam(mon), ansimpleoname(obj)); + pline_mon(mon, "%s ignites %s.", Monnam(mon), ansimpleoname(obj)); saw_lit = TRUE; } begin_burn(obj, was_lit); @@ -3105,7 +3107,7 @@ muse_unslime( for pacifist conduct); xkilled()'s message would say "You killed/destroyed " so give our own message */ if (vis) - pline("%s is %s by the fire!", Monnam(mon), + pline_mon(mon, "%s is %s by the fire!", Monnam(mon), nonliving(mon->data) ? "destroyed" : "killed"); xkilled(mon, XKILL_NOMSG | XKILL_NOCONDUCT); } else @@ -3113,12 +3115,12 @@ muse_unslime( } else { /* non-fatal damage occurred */ if (vis) - pline("%s is burned%s", Monnam(mon), exclam(dmg)); + pline_mon(mon, "%s is burned%s", Monnam(mon), exclam(dmg)); } } if (vis) { if (res && !DEADMONSTER(mon)) - pline("%s slime is burned away!", s_suffix(Monnam(mon))); + pline_mon(mon, "%s slime is burned away!", s_suffix(Monnam(mon))); if (otyp != STRANGE_OBJECT) makeknown(otyp); } From 141d24bdeb70285b3a1ef18e60fb8a6888846622 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sat, 14 Dec 2024 16:19:14 +0200 Subject: [PATCH 190/791] Accessibility: more message locations pt 5 --- src/worn.c | 60 +++++++++++++++++++++++++++++++----------------------- 1 file changed, 34 insertions(+), 26 deletions(-) diff --git a/src/worn.c b/src/worn.c index aae1611a4..7e545370c 100644 --- a/src/worn.c +++ b/src/worn.c @@ -475,11 +475,13 @@ mon_adjust_speed( /* mimic the player's petrification countdown; "slowing down" even if fast movement rate retained via worn speed boots */ if (flags.verbose) - pline("%s is slowing down.", Monnam(mon)); + pline_mon(mon, "%s is slowing down.", Monnam(mon)); } else if (adjust > 0 || mon->mspeed == MFAST) - pline("%s is suddenly moving %sfaster.", Monnam(mon), howmuch); + pline_mon(mon, "%s is suddenly moving %sfaster.", + Monnam(mon), howmuch); else - pline("%s seems to be moving %sslower.", Monnam(mon), howmuch); + pline_mon(mon, "%s seems to be moving %sslower.", + Monnam(mon), howmuch); /* might discover an object if we see the speed change happen */ if (obj != 0) @@ -871,7 +873,7 @@ m_dowear_type( (void) strsubst(newarm, "an ", "another "); newarm[BUFSZ - 1] = '\0'; } - pline("%s%s puts on %s.", Monnam(mon), buf, newarm); + pline_mon(mon, "%s%s puts on %s.", Monnam(mon), buf, newarm); if (autocurse) pline("%s %s %s %s for a moment.", s_suffix(Monnam(mon)), simpleonames(best), otense(best, "glow"), @@ -1117,7 +1119,8 @@ mon_break_armor(struct monst *mon, boolean polyspot) } else { Soundeffect(se_cracking_sound, 100); if (vis) - pline("%s breaks out of %s armor!", Monnam(mon), ppronoun); + pline_mon(mon, "%s breaks out of %s armor!", + Monnam(mon), ppronoun); else You_hear("a cracking sound."); } @@ -1128,13 +1131,13 @@ mon_break_armor(struct monst *mon, boolean polyspot) && (otmp->otyp != MUMMY_WRAPPING || !WrappingAllowed(mdat))) { if (otmp->oartifact) { if (vis) - pline("%s %s falls off!", s_suffix(Monnam(mon)), + pline_mon(mon, "%s %s falls off!", s_suffix(Monnam(mon)), cloak_simple_name(otmp)); m_lose_armor(mon, otmp, polyspot); } else { Soundeffect(se_ripping_sound, 100); if (vis) - pline("%s %s tears apart!", s_suffix(Monnam(mon)), + pline_mon(mon, "%s %s tears apart!", s_suffix(Monnam(mon)), cloak_simple_name(otmp)); else You_hear("a ripping sound."); @@ -1143,7 +1146,8 @@ mon_break_armor(struct monst *mon, boolean polyspot) } if ((otmp = which_armor(mon, W_ARMU)) != 0) { if (vis) - pline("%s shirt rips to shreds!", s_suffix(Monnam(mon))); + pline_mon(mon, "%s shirt rips to shreds!", + s_suffix(Monnam(mon))); else You_hear("a ripping sound."); m_useup(mon, otmp); @@ -1155,8 +1159,8 @@ mon_break_armor(struct monst *mon, boolean polyspot) if ((otmp = which_armor(mon, W_ARM)) != 0) { Soundeffect(se_thud, 50); if (vis) - pline("%s armor falls around %s!", s_suffix(Monnam(mon)), - pronoun); + pline_mon(mon, "%s armor falls around %s!", + s_suffix(Monnam(mon)), pronoun); else You_hear("a thud."); m_lose_armor(mon, otmp, polyspot); @@ -1166,21 +1170,22 @@ mon_break_armor(struct monst *mon, boolean polyspot) && (otmp->otyp != MUMMY_WRAPPING || !WrappingAllowed(mdat))) { if (vis) { if (is_whirly(mon->data)) - pline("%s %s falls, unsupported!", s_suffix(Monnam(mon)), - cloak_simple_name(otmp)); + pline_mon(mon, "%s %s falls, unsupported!", + s_suffix(Monnam(mon)), cloak_simple_name(otmp)); else - pline("%s shrinks out of %s %s!", Monnam(mon), ppronoun, - cloak_simple_name(otmp)); + pline_mon(mon, "%s shrinks out of %s %s!", + Monnam(mon), ppronoun, + cloak_simple_name(otmp)); } m_lose_armor(mon, otmp, polyspot); } if ((otmp = which_armor(mon, W_ARMU)) != 0) { if (vis) { if (passes_thru_clothes) - pline("%s seeps right through %s shirt!", Monnam(mon), - ppronoun); + pline_mon(mon, "%s seeps right through %s shirt!", + Monnam(mon), ppronoun); else - pline("%s becomes much too small for %s shirt!", + pline_mon(mon, "%s becomes much too small for %s shirt!", Monnam(mon), ppronoun); } m_lose_armor(mon, otmp, polyspot); @@ -1190,15 +1195,16 @@ mon_break_armor(struct monst *mon, boolean polyspot) /* [caller needs to handle weapon checks] */ if ((otmp = which_armor(mon, W_ARMG)) != 0) { if (vis) - pline("%s drops %s gloves%s!", Monnam(mon), ppronoun, - MON_WEP(mon) ? " and weapon" : ""); + pline_mon(mon, "%s drops %s gloves%s!", + Monnam(mon), ppronoun, + MON_WEP(mon) ? " and weapon" : ""); m_lose_armor(mon, otmp, polyspot); } if ((otmp = which_armor(mon, W_ARMS)) != 0) { Soundeffect(se_clank, 50); if (vis) - pline("%s can no longer hold %s shield!", Monnam(mon), - ppronoun); + pline_mon(mon, "%s can no longer hold %s shield!", + Monnam(mon), ppronoun); else You_hear("a clank."); m_lose_armor(mon, otmp, polyspot); @@ -1209,8 +1215,8 @@ mon_break_armor(struct monst *mon, boolean polyspot) /* flimsy test for horns matches polyself handling */ && (handless_or_tiny || !is_flimsy(otmp))) { if (vis) - pline("%s helmet falls to the %s!", s_suffix(Monnam(mon)), - surface(mon->mx, mon->my)); + pline_mon(mon, "%s helmet falls to the %s!", + s_suffix(Monnam(mon)), surface(mon->mx, mon->my)); else You_hear("a clank."); m_lose_armor(mon, otmp, polyspot); @@ -1220,9 +1226,11 @@ mon_break_armor(struct monst *mon, boolean polyspot) if ((otmp = which_armor(mon, W_ARMF)) != 0) { if (vis) { if (is_whirly(mon->data)) - pline("%s boots fall away!", s_suffix(Monnam(mon))); + pline_mon(mon, "%s boots fall away!", + s_suffix(Monnam(mon))); else - pline("%s boots %s off %s feet!", s_suffix(Monnam(mon)), + pline_mon(mon, "%s boots %s off %s feet!", + s_suffix(Monnam(mon)), verysmall(mdat) ? "slide" : "are pushed", ppronoun); } m_lose_armor(mon, otmp, polyspot); @@ -1232,7 +1240,7 @@ mon_break_armor(struct monst *mon, boolean polyspot) if ((otmp = which_armor(mon, W_SADDLE)) != 0) { m_lose_armor(mon, otmp, polyspot); if (vis) - pline("%s saddle falls off.", s_suffix(Monnam(mon))); + pline_mon(mon, "%s saddle falls off.", s_suffix(Monnam(mon))); } if (mon == u.usteed) noride = TRUE; From 79affad3126ccf85a259d02f38f405435e3ccd86 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sat, 14 Dec 2024 16:28:20 +0200 Subject: [PATCH 191/791] Accessibility: more message locations pt 6 --- src/weapon.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/weapon.c b/src/weapon.c index 5234c2781..82c980ec4 100644 --- a/src/weapon.c +++ b/src/weapon.c @@ -716,7 +716,7 @@ possibly_unwield(struct monst *mon, boolean polyspot) mon->weapon_check = NO_WEAPON_WANTED; /* if we're going to call distant_name(), do so before extract_self */ if (cansee(mon->mx, mon->my)) { - pline("%s drops %s.", Monnam(mon), distant_name(obj, doname)); + pline_mon(mon, "%s drops %s.", Monnam(mon), distant_name(obj, doname)); newsym(mon->mx, mon->my); } obj_extract_self(obj); @@ -827,7 +827,7 @@ mon_wield_item(struct monst *mon) pline("%s cannot wield that %s.", mon_nam(mon), xname(obj)); } else { - pline("%s tries to wield %s.", Monnam(mon), doname(obj)); + pline_mon(mon, "%s tries to wield %s.", Monnam(mon), doname(obj)); pline("%s %s!", Yname2(mw_tmp), welded_buf); } mw_tmp->bknown = 1; From e778d95ace7cabc374827a620decef3102d82777 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sat, 14 Dec 2024 16:37:49 +0200 Subject: [PATCH 192/791] Accessibility: more message locations pt 7 --- src/uhitm.c | 78 ++++++++++++++++++++++++++++------------------------- 1 file changed, 42 insertions(+), 36 deletions(-) diff --git a/src/uhitm.c b/src/uhitm.c index 82b50deda..b77c018e3 100644 --- a/src/uhitm.c +++ b/src/uhitm.c @@ -88,7 +88,7 @@ mhitm_mgc_atk_negated( if (mdef == &gy.youmonst) You("avoid harm."); else if (gv.vis && canseemon(mdef)) - pline("%s avoids harm.", Monnam(mdef)); + pline_mon(mdef, "%s avoids harm.", Monnam(mdef)); } return TRUE; } @@ -2242,7 +2242,7 @@ mhitm_ad_rust( return; if (completelyrusts(pd)) { /* PM_IRON_GOLEM */ if (gv.vis && canseemon(mdef)) - pline("%s %s to pieces!", Monnam(mdef), + pline_mon(mdef, "%s %s to pieces!", Monnam(mdef), !mlifesaver(mdef) ? "falls" : "starts to fall"); monkilled(mdef, (char *) 0, AD_RUST); if (!DEADMONSTER(mdef)) { @@ -2322,7 +2322,7 @@ mhitm_ad_dcay( /* note: the life-saved case is hypothetical because life-saving doesn't work for golems */ if (gv.vis && canseemon(mdef)) - pline("%s %s to pieces!", Monnam(mdef), + pline_mon(mdef, "%s %s to pieces!", Monnam(mdef), !mlifesaver(mdef) ? "falls" : "starts to fall"); monkilled(mdef, (char *) 0, AD_DCAY); if (!DEADMONSTER(mdef)) { @@ -2424,7 +2424,7 @@ mhitm_ad_drli( if (!is_death) /* Stormbringer uses monhp_per_lvl (1d8) */ mhm->damage = d(2, 6); if (gv.vis && canspotmon(mdef)) - pline("%s becomes weaker!", Monnam(mdef)); + pline_mon(mdef, "%s becomes weaker!", Monnam(mdef)); if (mdef->mhpmax - mhm->damage > (int) mdef->m_lev) { mdef->mhpmax -= mhm->damage; } else { @@ -2518,12 +2518,12 @@ mhitm_ad_fire( return; } if (gv.vis && canseemon(mdef)) - pline("%s is %s!", Monnam(mdef), on_fire(pd, mattk)); + pline_mon(mdef, "%s is %s!", Monnam(mdef), on_fire(pd, mattk)); if (completelyburns(pd)) { /* paper golem or straw golem */ /* note: the life-saved case is hypothetical because life-saving doesn't work for golems */ if (gv.vis && canseemon(mdef)) - pline("%s %s!", Monnam(mdef), + pline_mon(mdef, "%s %s!", Monnam(mdef), !mlifesaver(mdef) ? "burns completely" : "is totally engulfed in flames"); monkilled(mdef, (char *) 0, AD_FIRE); @@ -2595,7 +2595,7 @@ mhitm_ad_cold( return; } if (gv.vis && canseemon(mdef)) - pline("%s is covered in frost!", Monnam(mdef)); + pline_mon(mdef, "%s is covered in frost!", Monnam(mdef)); if (resists_cold(mdef) || defended(mdef, AD_COLD)) { if (gv.vis && canseemon(mdef)) pline_The("frost doesn't seem to chill %s!", mon_nam(mdef)); @@ -2653,7 +2653,7 @@ mhitm_ad_elec( return; } if (gv.vis && canseemon(mdef)) - pline("%s gets zapped!", Monnam(mdef)); + pline_mon(mdef, "%s gets zapped!", Monnam(mdef)); if (resists_elec(mdef) || defended(mdef, AD_ELEC)) { if (gv.vis && canseemon(mdef)) pline_The("zap doesn't shock %s!", mon_nam(mdef)); @@ -2702,7 +2702,7 @@ mhitm_ad_acid( Monnam(mdef), hliquid("acid")); mhm->damage = 0; } else if (gv.vis && canseemon(mdef)) { - pline("%s is covered in %s!", Monnam(mdef), hliquid("acid")); + pline_mon(mdef, "%s is covered in %s!", Monnam(mdef), hliquid("acid")); pline("It burns %s!", mon_nam(mdef)); } if (!rn2(30)) @@ -2858,7 +2858,7 @@ mhitm_ad_tlpt( ; /* no negation message */ } else if (mhitm_mgc_atk_negated(magr, mdef, TRUE)) { if (gv.vis) - pline("%s is not affected.", Monnam(mdef)); + pline_mon(mdef, "%s is not affected.", Monnam(mdef)); } else { char mdef_Monnam[BUFSZ]; boolean wasseen = canspotmon(mdef); @@ -2972,7 +2972,7 @@ mhitm_ad_curs( if (Blind) { You_hear("laughter."); } else { - pline("%s chuckles.", Monnam(magr)); + pline_mon(magr, "%s chuckles.", Monnam(magr)); } } if (u.umonnum == PM_CLAY_GOLEM) { @@ -2996,7 +2996,7 @@ mhitm_ad_curs( if (gv.vis && canseemon(mdef)) { pline("Some writing vanishes from %s head!", s_suffix(mon_nam(mdef))); - pline("%s is destroyed!", Monnam(mdef)); + pline_mon(mdef, "%s is destroyed!", Monnam(mdef)); } mondied(mdef); if (!DEADMONSTER(mdef)) { @@ -3016,7 +3016,7 @@ mhitm_ad_curs( if (!gv.vis) You_hear("laughter."); else if (canseemon(magr)) - pline("%s chuckles.", Monnam(magr)); + pline_mon(magr, "%s chuckles.", Monnam(magr)); } } } @@ -3187,7 +3187,7 @@ mhitm_ad_drin( if (gn.notonhead || !has_head(pd)) { if (gv.vis && canspotmon(mdef)) - pline("%s doesn't seem harmed.", Monnam(mdef)); + pline_mon(mdef, "%s doesn't seem harmed.", Monnam(mdef)); /* Not clear what to do for green slimes */ mhm->damage = 0; /* don't bother with additional DRIN attacks since they wouldn't @@ -3318,10 +3318,11 @@ mhitm_ad_wrap( mhm->damage = 0; if (flags.verbose) { if (coil) - pline("%s brushes against you.", Monnam(magr)); + pline_mon(magr, "%s brushes against you.", + Monnam(magr)); else - pline("%s brushes against your %s.", Monnam(magr), - body_part(LEG)); + pline_mon(magr, "%s brushes against your %s.", + Monnam(magr), body_part(LEG)); } } } else @@ -3591,7 +3592,7 @@ mhitm_ad_slow( mon_adjust_speed(mdef, -1, (struct obj *) 0); mdef->mstrategy &= ~STRAT_WAITFORU; if (mdef->mspeed != oldspeed && gv.vis && canspotmon(mdef)) - pline("%s slows down.", Monnam(mdef)); + pline_mon(mdef, "%s slows down.", Monnam(mdef)); } } } @@ -3628,7 +3629,7 @@ mhitm_ad_conf( */ if (!magr->mcan && !mdef->mconf && !magr->mspec_used) { if (gv.vis && canseemon(mdef)) - pline("%s looks confused.", Monnam(mdef)); + pline_mon(mdef, "%s looks confused.", Monnam(mdef)); mdef->mconf = 1; mdef->mstrategy &= ~STRAT_WAITFORU; } @@ -3698,7 +3699,8 @@ mhitm_ad_famn( goto mhitm_famn; } else if (mdef == &gy.youmonst) { /* mhitu */ - pline("%s reaches out, and your body shrivels.", Monnam(magr)); + pline_mon(magr, "%s reaches out, and your body shrivels.", + Monnam(magr)); exercise(A_CON, FALSE); if (!is_fainted()) morehungry(rn1(40, 40)); @@ -3728,7 +3730,8 @@ mhitm_ad_pest( goto mhitm_pest; } else if (mdef == &gy.youmonst) { /* mhitu */ - pline("%s reaches out, and you feel fever and chills.", Monnam(magr)); + pline_mon(magr, "%s reaches out, and you feel fever and chills.", + Monnam(magr)); (void) diseasemu(pa); /* plus the normal damage */ } else { @@ -3756,7 +3759,7 @@ mhitm_ad_deth( goto mhitm_deth; } else if (mdef == &gy.youmonst) { /* mhitu */ - pline("%s reaches out with its deadly touch.", Monnam(magr)); + pline_mon(magr, "%s reaches out with its deadly touch.", Monnam(magr)); if (is_undead(pd)) { /* still does some damage */ mhm->damage = (mhm->damage + 1) / 2; @@ -3819,7 +3822,7 @@ mhitm_ad_halu( /* mhitm */ if (!magr->mcan && haseyes(pd) && mdef->mcansee) { if (gv.vis && canseemon(mdef)) - pline("%s looks %sconfused.", Monnam(mdef), + pline_mon(mdef, "%s looks %sconfused.", Monnam(mdef), mdef->mconf ? "more " : ""); mdef->mconf = 1; mdef->mstrategy &= ~STRAT_WAITFORU; @@ -3867,7 +3870,7 @@ do_stone_mon( } if (!resists_ston(mdef)) { if (gv.vis && canseemon(mdef)) - pline("%s turns to stone!", Monnam(mdef)); + pline_mon(mdef, "%s turns to stone!", Monnam(mdef)); monstone(mdef); post_stone: if (!DEADMONSTER(mdef)) { @@ -3935,7 +3938,7 @@ mhitm_ad_phys( mhm->hitflags |= M_ATTK_MISS; } else { set_ustuck(magr); - pline("%s grabs you!", Monnam(magr)); + pline_mon(magr, "%s grabs you!", Monnam(magr)); mhm->hitflags |= M_ATTK_HIT; } } else if (u.ustuck == magr) { @@ -3953,8 +3956,9 @@ mhitm_ad_phys( if (otmp->otyp == CORPSE && touch_petrifies(&mons[otmp->corpsenm])) { mhm->damage = 1; - pline("%s hits you with the %s corpse.", Monnam(magr), - mons[otmp->corpsenm].pmnames[NEUTRAL]); + pline_mon(magr, "%s hits you with the %s corpse.", + Monnam(magr), + mons[otmp->corpsenm].pmnames[NEUTRAL]); if (!Stoned) { if (do_stone_u(magr)) { mhm->hitflags = M_ATTK_HIT; @@ -4051,7 +4055,7 @@ mhitm_ad_phys( if (!artifact_hit(magr, mdef, mwep, &mhm->damage, mhm->dieroll)) { if (gv.vis) - pline("%s hits %s.", Monnam(magr), + pline_mon(magr, "%s hits %s.", Monnam(magr), mon_nam_too(mdef, magr)); mhm->hitflags |= M_ATTK_HIT; } @@ -4198,7 +4202,8 @@ mhitm_ad_heal( && !uarms && !uarmg && !uarmf && !uarmh) { boolean goaway = FALSE; - pline("%s hits! (I hope you don't mind.)", Monnam(magr)); + pline_mon(magr, "%s hits! (I hope you don't mind.)", + Monnam(magr)); if (Upolyd) { u.mh += rnd(7); if (!rn2(7)) { @@ -4291,7 +4296,7 @@ mhitm_ad_stun( if (magr->mcan) return; if (canseemon(mdef)) - pline("%s %s for a moment.", Monnam(mdef), + pline_mon(mdef, "%s %s for a moment.", Monnam(mdef), makeplural(stagger(pd, "stagger"))); mdef->mstun = 1; mhitm_ad_phys(magr, mattk, mdef, mhm); @@ -4330,7 +4335,7 @@ mhitm_ad_legs( pline("%s tries to reach your %s %s!", Monst_name, sidestr, leg); mhm->damage = 0; } else if (magr->mcan) { - pline("%s nuzzles against your %s %s!", Monnam(magr), + pline_mon(magr, "%s nuzzles against your %s %s!", Monnam(magr), sidestr, leg); mhm->damage = 0; } else { @@ -4389,7 +4394,7 @@ mhitm_ad_dgst( /* eating a Rider or its corpse is fatal */ if (is_rider(pd)) { if (gv.vis && canseemon(magr)) - pline("%s %s!", Monnam(magr), + pline_mon(magr, "%s %s!", Monnam(magr), (pd == &mons[PM_FAMINE]) ? "belches feebly, shrivels up and dies" : (pd == &mons[PM_PESTILENCE]) @@ -4523,7 +4528,7 @@ mhitm_ad_sedu( is disabled, it would be changed to another damage type, but when defending, it remains as-is */ || dmgtype(gy.youmonst.data, AD_SSEX)) { - pline("%s %s.", Monnam(magr), + pline_mon(magr, "%s %s.", Monnam(magr), Deaf ? "says something but you can't hear it" : magr->minvent ? "brags about the goods some dungeon explorer provided" @@ -4561,8 +4566,9 @@ mhitm_ad_sedu( (void) rloc(magr, RLOC_MSG); if (is_animal(magr->data) && *buf) { if (canseemon(magr)) - pline("%s tries to %s away with %s.", Monnam(magr), - locomotion(magr->data, "run"), buf); + pline_mon(magr, "%s tries to %s away with %s.", + Monnam(magr), + locomotion(magr->data, "run"), buf); } monflee(magr, 0, FALSE, FALSE); mhm->hitflags = M_ATTK_AGR_DONE; /* return 3??? */ @@ -6239,7 +6245,7 @@ flash_hits_mon( void light_hits_gremlin(struct monst *mon, int dmg) { - pline("%s %s!", Monnam(mon), + pline_mon(mon, "%s %s!", Monnam(mon), (dmg > mon->mhp / 2) ? "wails in agony" : "cries out in pain"); mon->mhp -= dmg; wake_nearto(mon->mx, mon->my, 30); From 2965ce4bc51c4cb78a08567aa206dbc48a1b7434 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 15 Dec 2024 09:53:50 -0500 Subject: [PATCH 193/791] msdos build correction ENHANCED_SYMBOLS is defined by default in config.h. The msdos build tried to #undef ENHANCED_SYMBOLS in tilemap.c, but doing it in there created a mismatch between the data struct definition for glyph_map in wintype.h and the initializers generated in tilemap.c Move the msdos build catch for ENHANCED_SYMBOLS to one single place in config1.h so that the code and data agree. --- include/config1.h | 4 ++++ include/wintty.h | 2 +- sys/msdos/video.c | 9 +++++++++ win/share/tilemap.c | 4 ---- win/tty/wintty.c | 6 ------ 5 files changed, 14 insertions(+), 11 deletions(-) diff --git a/include/config1.h b/include/config1.h index c4e14610c..3a8632564 100644 --- a/include/config1.h +++ b/include/config1.h @@ -31,6 +31,10 @@ #ifndef CROSSCOMPILE #define SHORT_FILENAMES #endif +/* this is not fully-implemented yet for msdos */ +#ifdef ENHANCED_SYMBOLS +#undef ENHANCED_SYMBOLS +#endif #endif /* diff --git a/include/wintty.h b/include/wintty.h index 87183708e..ec29c112b 100644 --- a/include/wintty.h +++ b/include/wintty.h @@ -210,7 +210,7 @@ extern void docorner(int, int, int); extern void end_glyphout(void); extern void g_putch(int); #ifdef ENHANCED_SYMBOLS -#if defined(WIN32) || defined(UNIX) +#if defined(WIN32) || defined(UNIX) || defined(MSDOS) extern void g_pututf8(uint8 *); #endif #endif /* ENHANCED_SYMBOLS */ diff --git a/sys/msdos/video.c b/sys/msdos/video.c index 6397fa8d8..ae03e2541 100644 --- a/sys/msdos/video.c +++ b/sys/msdos/video.c @@ -14,6 +14,7 @@ */ #include "hack.h" +#include "wintty.h" #ifndef STUBVIDEO #include "pcvideo.h" @@ -88,6 +89,14 @@ get_scr_size(void) txt_get_scr_size(); } +#ifdef ENHANCED_SYMBOLS +void g_pututf8(uint8 *utf8str) +{ + /* not implemented for msdos (yet) */ + nhUse(utf8str); +} +#endif + /* * -------------------------------------------------------------- * The rest of this file is only compiled if NO_TERMS is defined. diff --git a/win/share/tilemap.c b/win/share/tilemap.c index ec26f513b..4842fc7a8 100644 --- a/win/share/tilemap.c +++ b/win/share/tilemap.c @@ -54,10 +54,6 @@ extern void exit(int); #endif #endif -#if defined(CROSSCOMPILE) && defined(ENHANCED_SYMBOLS) -#undef ENHANCED_SYMBOLS -#endif - struct { int idx; const char *tilelabel; diff --git a/win/tty/wintty.c b/win/tty/wintty.c index 693592fbb..207f396ac 100644 --- a/win/tty/wintty.c +++ b/win/tty/wintty.c @@ -27,12 +27,6 @@ extern void msmsg(const char *, ...); #endif #endif -#ifdef MSDOS -#ifdef ENHANCED_SYMBOLS -#undef ENHANCED_SYMBOLS -#endif -#endif /* MSDOS */ - #ifndef NO_TERMS #include "tcap.h" #endif From fd7c314e9e57045c3c163b870794ef2c27529781 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 15 Dec 2024 10:15:23 -0500 Subject: [PATCH 194/791] adjust compiler switches in msdos cross-compile --- sys/unix/hints/include/cross-pre2.370 | 42 +++++++++++++++++---------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/sys/unix/hints/include/cross-pre2.370 b/sys/unix/hints/include/cross-pre2.370 index bc38efa62..8d4fff0b2 100644 --- a/sys/unix/hints/include/cross-pre2.370 +++ b/sys/unix/hints/include/cross-pre2.370 @@ -133,20 +133,34 @@ override TARGET_CC = $(TOOLTOP1)/i586-pc-msdosdjgpp-gcc override TARGET_CXX = $(TOOLTOP1)/i586-pc-msdosdjgpp-g++ override TARGET_AR = $(TOOLTOP1)/i586-pc-msdosdjgpp-gcc-ar override TARGET_STUBEDIT = ../lib/djgpp/i586-pc-msdosdjgpp/bin/stubedit -MSDOS_TARGET_CFLAGS = -c -O -I../include -I../sys/msdos -I../win/share \ - $(LUAINCL) -DDLB $(PDCURSESDEF) \ - -DTILES_IN_GLYPHMAP -DCROSSCOMPILE -DCROSSCOMPILE_TARGET \ - -DCROSS_TO_MSDOS \ - -Wall -Wextra -Wno-missing-field-initializers -Wreturn-type -Wunused \ - -Wformat -Wswitch -Wshadow -Wwrite-strings \ - -Wimplicit -Wimplicit-function-declaration -Wimplicit-int \ - -Wimplicit-fallthrough \ - -Wmissing-parameter-type -Wold-style-definition -Wstrict-prototypes -MSDOS_TARGET_CXXFLAGS = -c -O -I../include -I../sys/msdos -I../win/share \ +# +ifeq "$(WANT_DEBUG)" "1" +DBGFLAGS = -g +else +DBGFLAGS = +endif +MSDOS_GCC_CFLAGS = -Wall -Wextra -Wreturn-type -Wunused -Wformat \ + -Wswitch -Wshadow -Wwrite-strings -Wmissing-declarations \ + -Wunreachable-code \ + -Wimplicit -Wimplicit-function-declaration \ + -Wimplicit-int -Wmissing-prototypes -Wold-style-definition \ + -Wstrict-prototypes -Wnonnull -Wformat-overflow \ + -Wmissing-parameter-type -Wimplicit-fallthrough +#-Wno-missing-field-initializers -Wno-cast-function-type +#-Wno-format +MSDOS_PEDANTIC = -pedantic +MSDOS_GPP_CFLAGS = -Wall -Wextra -Wno-missing-field-initializers -Wreturn-type \ + -Wunused -Wformat -Wswitch -Wshadow -Wwrite-strings -pedantic \ + -Wmissing-declarations -Wformat-nonliteral -Wunreachable-code \ + -Wno-maybe-uninitialized +MSDOS_TARGET_CFLAGS = -c -O $(DBGFLAGS) -I../include -I../sys/msdos -I../win/share \ + $(LUAINCL) -DDLB $(PDCURSESDEF) -DTILES_IN_GLYPHMAP \ + -DCROSSCOMPILE -DCROSSCOMPILE_TARGET -DCROSS_TO_MSDOS \ + $(MSDOS_GCC_CFLAGS) +MSDOS_TARGET_CXXFLAGS = -c -O $(DBGFLAGS) -I../include -I../sys/msdos -I../win/share \ $(LUAINCL) -DDLB $(PDCURSESDEF) \ -DUSE_TILES -DCROSSCOMPILE -DCROSSCOMPILE_TARGET -DCROSS_TO_MSDOS \ - -Wall -Wextra -Wno-missing-field-initializers -Wreturn-type -Wunused \ - -Wformat -Wswitch -Wshadow -Wwrite-strings -Wno-maybe-uninitialized + $(MSDOS_GPP_CFLAGS) PDCINCL += -I$(PDCPORT) PDC_TARGET_CFLAGS = $(MSDOS_TARGET_CFLAGS) -Wno-unused-parameter \ -Wno-missing-prototypes @@ -159,9 +173,7 @@ FONTTARGETS = $(DOSFONT)/ter-u16b.psf $(DOSFONT)/ter-u16v.psf \ $(DOSFONT)/ter-u28b.psf $(DOSFONT)/ter-u32b.psf LUABIN = ../lib/lua-$(LUA_VERSION)/src/lua LUA_TARGET_CFLAGS = $(MSDOS_TARGET_CFLAGS) -override TARGET_CFLAGS = $(MSDOS_TARGET_CFLAGS) -Wmissing-declarations \ - -Wmissing-prototypes -pedantic -Wmissing-declarations \ - -Wformat-nonliteral +override TARGET_CFLAGS = $(MSDOS_TARGET_CFLAGS) $(MSDOS_PEDANTIC) override TARGET_CXXFLAGS = $(MSDOS_TARGET_CXXFLAGS) ifdef CPLUSPLUS_NEEDED override TARGET_LINK = $(TOOLTOP1)/i586-pc-msdosdjgpp-g++ From 69600c3f380ff50dc7ee72efba1da46e04e316c0 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 15 Dec 2024 10:26:49 -0500 Subject: [PATCH 195/791] add an optional deploy-to-dosbox target for msdos cross-compile The WANT_DEBUG=1 will cause the cross-compile to include line number information in the NetHack executable, useful for backtraces and gdb debugging sessions. How a developer can use the optional deploy-to-dosbox target: make CROSS_TO_MSDOS=1 WANT_DEBUG=1 dosbox=/mnt/c/dosbox deploy-to-dosbox where dosbox= points to the directory which will be mounted for your drive in dosbox THe deploy-to-dosbox recipe ensures that a target copy of gdb.exe ends up alongside nethack.exe at the target, including: - placing the source code that gdb requires on the target in the nhsrc subfolder. - an nhgdb.bat that supplies the right switches to gdb for locating the NetHack sources. --- sys/unix/hints/include/cross-post.370 | 59 +++++++++++++++++++++++++++ sys/unix/hints/include/cross-pre2.370 | 20 +++++++++ 2 files changed, 79 insertions(+) diff --git a/sys/unix/hints/include/cross-post.370 b/sys/unix/hints/include/cross-post.370 index a509aae6f..70968d145 100644 --- a/sys/unix/hints/include/cross-post.370 +++ b/sys/unix/hints/include/cross-post.370 @@ -79,6 +79,65 @@ $(LUABIN): dodata: ( cd .. && make dlb && cd src) +ifdef dosbox +# make CROSS_TO_MSDOS=1 dosbox=~/dosbox deploy-to-dosbox +ifdef MAKEFILE_TOP +deploy-to-dosbox: + ( cd src; make $(DEPLOY); cd .. ) +endif +.PHONY: deploytodosbox + +deploytodosbox: ../targets/msdos/NH370DOS.ZIP $(dosboxnhfolder) $(dosboxnhsrc) \ + $(dosboxnhsrc)/src $(dosboxnhsrc)/include \ + $(dosboxnhsrc)/sys/msdos $(dosboxnhsrc)/sys/share \ + $(dosboxnhsrc)/win/share $(dosboxnhsrc)/win/curses \ + $(dosboxnhsrc)/win/tty $(dosboxnhsrc)/util \ + $(dosboxnhfolder)/NETHACK.EXE \ + $(dosboxnhfolder)/GDB.EXE $(dosboxnhfolder)/nhgdb.bat + @echo DOS NetHack deployed to dosbox at $(dosboxnhfolder) + +$(dosboxnhfolder): + mkdir -p $@ +$(dosboxnhsrc): $(dosboxnhfolder) + mkdir -p $@ +$(dosboxnhsrc)/src: $(dosboxnhsrc) + mkdir -p $@ + cp --preserve=timestamps $(FLDR)src/*.c $(dosboxnhsrc)/src +$(dosboxnhsrc)/include: $(dosboxnhsrc) + mkdir -p $@ + cp --preserve=timestamps $(FLDR)include/*.h $(dosboxnhsrc)/include +$(dosboxnhsrc)/sys/msdos: $(dosboxnhsrc) + mkdir -p $@ + cp --preserve=timestamps $(FLDR)sys/msdos/*.c $(dosboxnhsrc)/sys/msdos + cp --preserve=timestamps $(FLDR)sys/msdos/*.h $(dosboxnhsrc)/sys/msdos +$(dosboxnhsrc)/sys/share: $(dosboxnhsrc) + mkdir -p $@ + cp --preserve=timestamps $(FLDR)sys/share/*.c $(dosboxnhsrc)/sys/share +$(dosboxnhsrc)/win/share: $(dosboxnhsrc) + mkdir -p $@ + cp --preserve=timestamps $(FLDR)win/share/*.c $(dosboxnhsrc)/win/share +$(dosboxnhsrc)/win/curses: $(dosboxnhsrc) + mkdir -p $@ + cp --preserve=timestamps $(FLDR)win/curses/*.c $(dosboxnhsrc)/win/curses + cp --preserve=timestamps $(FLDR)win/curses/*.h $(dosboxnhsrc)/win/curses +$(dosboxnhsrc)/win/tty: $(dosboxnhsrc) + mkdir -p $@ + cp --preserve=timestamps $(FLDR)win/tty/*.c $(dosboxnhsrc)/win/tty +$(dosboxnhsrc)/util: $(dosboxnhsrc) + mkdir -p $@ + cp --preserve=timestamps $(FLDR)util/*.c $(dosboxnhsrc)/util + cp --preserve=timestamps $(FLDR)util/*.h $(dosboxnhsrc)/util +$(dosboxnhfolder)/NETHACK.EXE: $(TARGETPFX)NH370DOS.ZIP + unzip -o $(TARGETPFX)NH370DOS.ZIP -d $(dosboxnhfolder) + find $(dosboxnhfolder) -type f -name "$(dosboxconfigfile)" \ + | xargs sed -i 's/#OPTIONS=video:autodetect/OPTIONS=video:autodetect/g' +$(dosboxnhfolder)/GDB.EXE: $(dosboxnhfolder) + curl --output gdb801b.zip $(dosgdburl) + unzip -p gdb801b.zip bin/gdb.exe >$@ + rm gdb801b.zip +$(dosboxnhfolder)/nhgdb.bat: $(FLDR)src/Makefile + echo "gdb -ex 'directory nhsrc/src nhsrc/include nhsrc/sys/msdos nhsrc/sys/share nhsrc/win/share nhsrc/win/curses nhsrc/win/tty nhsrc/util' NETHACK.EXE"> $@ +endif # dosbox endif # CROSS_TO_MSDOS ifdef CROSS_TO_WASM diff --git a/sys/unix/hints/include/cross-pre2.370 b/sys/unix/hints/include/cross-pre2.370 index 8d4fff0b2..5b80f887a 100644 --- a/sys/unix/hints/include/cross-pre2.370 +++ b/sys/unix/hints/include/cross-pre2.370 @@ -134,6 +134,26 @@ override TARGET_CXX = $(TOOLTOP1)/i586-pc-msdosdjgpp-g++ override TARGET_AR = $(TOOLTOP1)/i586-pc-msdosdjgpp-gcc-ar override TARGET_STUBEDIT = ../lib/djgpp/i586-pc-msdosdjgpp/bin/stubedit # +ifdef DOSBOX +dosbox=$(DOSBOX) +endif +ifdef dosbox +dosboxgameid=NH370 +dosboxtop=$(dosbox) +dosboxnhfolder=$(dosboxtop)/$(dosboxgameid) +dosboxnhsrc=$(dosboxnhfolder)/NHSRC +dosboxconfigfile=NETHACK.CNF +dosgdburl=http://www.mirrorservice.org/sites/ftp.delorie.com/pub/djgpp/current/v2gnu/gdb801b.zip +ifdef MAKEFILE_SRC +FLDR=../ +endif +ifdef MAKEFILE_TOP +FLDR= +endif +WANT_DEBUG=1 +DEPLOY=deploytodosbox +endif # dosbox +# ifeq "$(WANT_DEBUG)" "1" DBGFLAGS = -g else From 0a5948fffc3895aa070dad37d3926f78746f865e Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 15 Dec 2024 20:08:10 -0500 Subject: [PATCH 196/791] follow-up on msdos cross-compile Obtain gdb.exe during the execution of sys/msdosfetch-cross-compiler.sh ahead of the build, so that the Makefile just has to move it into place. --- sys/msdos/fetch-cross-compiler.sh | 62 ++++++++++++++++++++------- sys/unix/hints/include/cross-post.370 | 22 +++++----- sys/unix/hints/include/cross-pre2.370 | 1 + 3 files changed, 59 insertions(+), 26 deletions(-) diff --git a/sys/msdos/fetch-cross-compiler.sh b/sys/msdos/fetch-cross-compiler.sh index 3dedc8847..b849b2953 100755 --- a/sys/msdos/fetch-cross-compiler.sh +++ b/sys/msdos/fetch-cross-compiler.sh @@ -135,31 +135,61 @@ if [ ! -d djgpp/djgpp-patch ]; then cd ../../ fi -# get a copy of symify to insert in the final zip package -# to make bug reports more useful -# curl --output djdev205.zip http://www.mirrorservice.org/sites/ftp.delorie.com/pub/djgpp/current/v2/djdev205.zip -if [ ! -d djgpp/symify ]; then - echo "Getting djdev205.zip" ; +# create a directory hold native DOS executables that might get deployed +if [ ! -d djgpp/target ]; then cd djgpp - mkdir -p symify - cd symify - if [ "$(uname)" = "Darwin" ]; then - #Mac + mkdir -p target + cd ../ +fi +if [ -d djgpp/target ]; then + cd djgpp/target +# symify to make bug reports more useful + if [ ! -f symify.exe ]; then + if [ ! -f djdev205.zip ]; then + echo "Getting djdev205.zip" ; + if [ "$(uname)" = "Darwin" ]; then + #Mac curl --output djdev205.zip http://www.mirrorservice.org/sites/ftp.delorie.com/pub/djgpp/current/v2/djdev205.zip export cmdstatus=$? - else + else wget --quiet --no-hsts http://www.mirrorservice.org/sites/ftp.delorie.com/pub/djgpp/current/v2/djdev205.zip export cmdstatus=$? + fi + if [ $cmdstatus -eq 0 ]; then + echo "fetch of djdev205.zip was successful" + fi fi - ls -l - if [ $cmdstatus -eq 0 ]; then - echo "fetch of symify was successful" - unzip -p djdev205.zip bin/symify.exe >./simify.exe + if [ -f djdev205.zip ]; then + echo "unzipping djdev205.zip" + unzip -p djdev205.zip bin/symify.exe >./symify.exe fi - cd ../../ + fi +# gdb + if [ ! -f gdb.exe ]; then + if [ ! -f gdb801b.zip ]; then + echo "getting gdb801b.zip" ; + if [ "$(uname)" = "Darwin" ]; then + #Mac + curl --output gdb801b.zip http://www.mirrorservice.org/sites/ftp.delorie.com/pub/djgpp/current/v2gnu/gdb801b.zip + export cmdstatus=$? + else + wget --quiet --no-hsts http://www.mirrorservice.org/sites/ftp.delorie.com/pub/djgpp/current/v2gnu/gdb801b.zip + export cmdstatus=$? + fi + if [ $cmdstatus -eq 0 ]; then + echo "fetch of gdb801b.zip was successful" + fi + fi + if [ -f gdb801b.zip ]; then + echo "unzipping gdb801b.zip" + unzip -p gdb801b.zip bin/gdb.exe >./gdb.exe + fi + fi + echo "Native DOS executables:" + ls -l *.exe + cd ../../ fi - FONT_VERSION="4.49" FONT_FILE="terminus-font-$FONT_VERSION" FONT_LFILE="$FONT_FILE.1" diff --git a/sys/unix/hints/include/cross-post.370 b/sys/unix/hints/include/cross-post.370 index 70968d145..2f775e90f 100644 --- a/sys/unix/hints/include/cross-post.370 +++ b/sys/unix/hints/include/cross-post.370 @@ -65,10 +65,10 @@ dospkg: dodata dosfonts $(GAMEBIN) $(TARGETPFX)recover.exe ../dat/nhtiles.bmp cp $(DOSFONT)/ter-u28b.psf $(TARGETPFX)pkg/TER-U28B.PSF cp $(DOSFONT)/ter-u32b.psf $(TARGETPFX)pkg/TER-U32B.PSF cp ../lib/djgpp/cwsdpmi/bin/CWSDPMI.EXE $(TARGETPFX)pkg/CWSDPMI.EXE - ( if [ -f ../lib/djgpp/symify/simify.exe ]; then \ - cp ../lib/djgpp/symify/simify.exe $(TARGETPFX)pkg/SYMIFY.EXE; \ + ( if [ -f ../lib/djgpp/target/symify.exe ]; then \ + cp ../lib/djgpp/target/symify.exe $(TARGETPFX)pkg/SYMIFY.EXE; \ else \ - pwd; echo "../lib/djgpp/symify/symify.exe not found"; \ + pwd; echo "../lib/djgpp/target/symify.exe not found"; \ fi; ) -touch $(TARGETPFX)pkg/RECORD cd $(TARGETPFX)pkg ; zip -9 ../NH370DOS.ZIP * ; cd ../../.. @@ -82,12 +82,12 @@ dodata: ifdef dosbox # make CROSS_TO_MSDOS=1 dosbox=~/dosbox deploy-to-dosbox ifdef MAKEFILE_TOP -deploy-to-dosbox: +deploy-to-dosbox: ( cd src; make $(DEPLOY); cd .. ) endif .PHONY: deploytodosbox -deploytodosbox: ../targets/msdos/NH370DOS.ZIP $(dosboxnhfolder) $(dosboxnhsrc) \ +deploytodosbox: $(TARGETPFX)NH370DOS.ZIP $(dosboxnhfolder) $(dosboxnhsrc) \ $(dosboxnhsrc)/src $(dosboxnhsrc)/include \ $(dosboxnhsrc)/sys/msdos $(dosboxnhsrc)/sys/share \ $(dosboxnhsrc)/win/share $(dosboxnhsrc)/win/curses \ @@ -95,7 +95,8 @@ deploytodosbox: ../targets/msdos/NH370DOS.ZIP $(dosboxnhfolder) $(dosboxnhsrc) \ $(dosboxnhfolder)/NETHACK.EXE \ $(dosboxnhfolder)/GDB.EXE $(dosboxnhfolder)/nhgdb.bat @echo DOS NetHack deployed to dosbox at $(dosboxnhfolder) - +$(TARGETPFX)NH370DOS.ZIP: dospkg +# ( cd ..; make CROSS_TO_MSDOS=1 WANT_DEBUG=1 dospkg; cd src) $(dosboxnhfolder): mkdir -p $@ $(dosboxnhsrc): $(dosboxnhfolder) @@ -131,10 +132,11 @@ $(dosboxnhfolder)/NETHACK.EXE: $(TARGETPFX)NH370DOS.ZIP unzip -o $(TARGETPFX)NH370DOS.ZIP -d $(dosboxnhfolder) find $(dosboxnhfolder) -type f -name "$(dosboxconfigfile)" \ | xargs sed -i 's/#OPTIONS=video:autodetect/OPTIONS=video:autodetect/g' -$(dosboxnhfolder)/GDB.EXE: $(dosboxnhfolder) - curl --output gdb801b.zip $(dosgdburl) - unzip -p gdb801b.zip bin/gdb.exe >$@ - rm gdb801b.zip +$(dosboxnhfolder)/GDB.EXE: $(dosboxnhfolder) $(dostargetexes)/gdb801b.zip + cp --preserve=timestamps $(dostargetexes)/gdb.exe $@ +$(dostargetexes)/gdb801b.zip: + curl --output $(dostargetexes)/gdb801b.zip $(dosgdburl) + unzip -p $(dostargetexes)/gdb801b.zip bin/gdb.exe >$@ $(dosboxnhfolder)/nhgdb.bat: $(FLDR)src/Makefile echo "gdb -ex 'directory nhsrc/src nhsrc/include nhsrc/sys/msdos nhsrc/sys/share nhsrc/win/share nhsrc/win/curses nhsrc/win/tty nhsrc/util' NETHACK.EXE"> $@ endif # dosbox diff --git a/sys/unix/hints/include/cross-pre2.370 b/sys/unix/hints/include/cross-pre2.370 index 5b80f887a..defe671fa 100644 --- a/sys/unix/hints/include/cross-pre2.370 +++ b/sys/unix/hints/include/cross-pre2.370 @@ -150,6 +150,7 @@ endif ifdef MAKEFILE_TOP FLDR= endif +dostargetexes=$(FLDR)lib/djgpp/target WANT_DEBUG=1 DEPLOY=deploytodosbox endif # dosbox From 5a3795184f9910f71c3c217da033021879e19fa6 Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 16 Dec 2024 13:35:05 -0500 Subject: [PATCH 197/791] use bash for sys/msdos/fetch-cross-compiler.sh bash allows arrays thus preventing duplication during fetching --- Cross-compiling | 6 +- azure-pipelines.yml | 2 +- sys/msdos/Install.dos | 10 +-- sys/msdos/fetch-cross-compiler.sh | 115 +++++++++++++++++------------- 4 files changed, 73 insertions(+), 60 deletions(-) diff --git a/Cross-compiling b/Cross-compiling index 6a03fe8bf..38998a937 100644 --- a/Cross-compiling +++ b/Cross-compiling @@ -472,10 +472,10 @@ Cross-compiler pre-built binary downloads: or pdcursesmod from: https://github.com/Bill-Gray/PDCursesMod.git - - A shell script to download that djgpp cross-compiler and associated + - A bash script to download that djgpp cross-compiler and associated pieces for either linux or macOS is available: - sh sys/msdos/fetch-cross-compiler.sh + bash sys/msdos/fetch-cross-compiler.sh That script won't install anything, it just does file fetches and stores them in subfolders of lib. The linux.370 and macOS.370 hints files are @@ -483,7 +483,7 @@ Cross-compiler pre-built binary downloads: CROSS_TO_MSDOS=1 on your make command line. - Note: Both the fetch-cross-compiler.sh script and the msdos + Note: Both the fetch-cross-compiler.sh bash script and the msdos cross-compile and package procedures require unzip and zip to be available on your host build system. diff --git a/azure-pipelines.yml b/azure-pipelines.yml index fced2c60d..cdec5d7d5 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -225,7 +225,7 @@ steps: sh setup.sh hints/linux.370 cd ../.. make fetch-lua - sh sys/msdos/fetch-cross-compiler.sh + sys/msdos/fetch-cross-compiler.sh retVal=$? if [ $retVal -eq 0 ]; then make LUA_VERSION=5.4.6 WANT_WIN_TTY=1 WANT_WIN_CURSES=1 CROSS_TO_MSDOS=1 package diff --git a/sys/msdos/Install.dos b/sys/msdos/Install.dos index 780061099..10b94888d 100644 --- a/sys/msdos/Install.dos +++ b/sys/msdos/Install.dos @@ -56,9 +56,9 @@ II. There once was a time when people built NetHack right on their DOS machine. pdcurses from: https://github.com/wmcbrine/PDCurses.git - - A shell script to download the above-mentioned djgpp cross-compiler and + - A bash script to download the above-mentioned djgpp cross-compiler and associated support pieces for either linux or macOS is available: - sh sys/msdos/fetch-cross-compiler.sh + sys/msdos/fetch-cross-compiler.sh That script won't install anything, it just does file fetches and stores them in subfolders of lib. The linux.370 and macOS.370 hints files are @@ -66,7 +66,7 @@ II. There once was a time when people built NetHack right on their DOS machine. CROSS_TO_MSDOS=1 on your make command line. - Note: Both the fetch-cross-compiler.sh script and the msdos + Note: Both the fetch-cross-compiler.sh bash script and the msdos cross-compile and package procedures require unzip and zip to be available on your host build system. @@ -136,8 +136,8 @@ Appendix B - Common Difficulties Encountered make: *** [Makefile:1531: nethack] Error 2 That result usually indicates that you haven't successfully run - the script to fetch the cross-compiler. Try again: - sh sys/msdos/fetch-cross-compiler.sh + the bash script to fetch the cross-compiler. Try again: + sys/msdos/fetch-cross-compiler.sh ii) The cross-compile stops with an error "libfl.so.2: cannot open shared object file: No such file or directory. diff --git a/sys/msdos/fetch-cross-compiler.sh b/sys/msdos/fetch-cross-compiler.sh index b849b2953..d5f956b38 100755 --- a/sys/msdos/fetch-cross-compiler.sh +++ b/sys/msdos/fetch-cross-compiler.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash if [ ! -z "${TF_BUILD}" ]; then set -x @@ -60,6 +60,7 @@ fi cd lib if [ ! -f "$DJGPP_FILE" ]; then + echo "fetching djgpp cross-compiler int lib/djgpp" if [ "$(uname)" = "Darwin" ]; then #Mac curl -L $DJGPP_URL -o $DJGPP_FILE @@ -69,12 +70,14 @@ if [ ! -f "$DJGPP_FILE" ]; then fi if [ ! -d djgpp/i586-pc-msdosdjgpp ]; then + echo "extracting djgpp from $DJGPP_FILE" tar xjf "$DJGPP_FILE" #rm -f $DJGPP_FILE fi # DOS-extender for use with djgpp if [ ! -d djgpp/cwsdpmi ]; then + echo "fetching DOS extender for use with djgpp" if [ "$(uname)" = "Darwin" ]; then #Mac curl http://sandmann.dotster.com/cwsdpmi/csdpmi7b.zip -o csdpmi7b.zip @@ -94,18 +97,18 @@ fi # PDCurses (non-Unicode build uses this) if [ ! -d "pdcurses" ]; then - echo "Getting ../pdcurses from https://github.com/wmcbrine/PDCurses.git" ; \ + echo "fetching ../pdcurses from https://github.com/wmcbrine/PDCurses.git" ; \ git clone --depth 1 https://github.com/wmcbrine/PDCurses.git pdcurses fi # PDCursesMod (Unicode build uses this) if [ ! -d "pdcursesmod" ]; then - echo "Getting ../pdcursesmod from https://github.com/Bill-Gray/PDCursesMod.git" ; \ + echo "fetching ../pdcursesmod from https://github.com/Bill-Gray/PDCursesMod.git" ; \ git clone --depth 1 https://github.com/Bill-Gray/PDCursesMod.git pdcursesmod fi if [ ! -d djgpp/djgpp-patch ]; then - echo "Getting djlsr205.zip" ; + echo "fetching djlsr205.zip" ; cd djgpp mkdir -p djgpp-patch cd djgpp-patch @@ -132,62 +135,70 @@ if [ ! -d djgpp/djgpp-patch ]; then mkdir -p src/libc/go32 unzip -p djlsr205.zip src/libc/go32/exceptn.S >src/libc/go32/exceptn.S patch -p0 -l -i ../../../sys/msdos/exceptn.S.patch + echo "djgpp patch applied" cd ../../ fi -# create a directory hold native DOS executables that might get deployed +# create a directory to hold some native DOS executables that might get deployed if [ ! -d djgpp/target ]; then cd djgpp mkdir -p target cd ../ fi + +# These 4 arrays must have their elements kept in synch. +# +# full URL for the remote zip file to fetch +zipurl=( + "http://www.mirrorservice.org/sites/ftp.delorie.com/pub/djgpp/current/v2/djdev205.zip" + "http://www.mirrorservice.org/sites/ftp.delorie.com/pub/djgpp/current/v2gnu/gdb801b.zip" +) +# name of zip file upon landing here +ziplocal=( + "djdev205.zip" + "gdb801b.zip" +) +# name of file after extraction from zip file +exesought=( + "symify.exe" + "gdb.exe" +) +# stored full path inside zip file +exepathinzip=( + "bin/symify.exe" + "bin/gdb.exe" +) + if [ -d djgpp/target ]; then - cd djgpp/target -# symify to make bug reports more useful - if [ ! -f symify.exe ]; then - if [ ! -f djdev205.zip ]; then - echo "Getting djdev205.zip" ; - if [ "$(uname)" = "Darwin" ]; then - #Mac - curl --output djdev205.zip http://www.mirrorservice.org/sites/ftp.delorie.com/pub/djgpp/current/v2/djdev205.zip - export cmdstatus=$? - else - wget --quiet --no-hsts http://www.mirrorservice.org/sites/ftp.delorie.com/pub/djgpp/current/v2/djdev205.zip - export cmdstatus=$? - fi - if [ $cmdstatus -eq 0 ]; then - echo "fetch of djdev205.zip was successful" - fi - fi - if [ -f djdev205.zip ]; then - echo "unzipping djdev205.zip" - unzip -p djdev205.zip bin/symify.exe >./symify.exe - fi - fi -# gdb - if [ ! -f gdb.exe ]; then - if [ ! -f gdb801b.zip ]; then - echo "getting gdb801b.zip" ; - if [ "$(uname)" = "Darwin" ]; then - #Mac - curl --output gdb801b.zip http://www.mirrorservice.org/sites/ftp.delorie.com/pub/djgpp/current/v2gnu/gdb801b.zip - export cmdstatus=$? - else - wget --quiet --no-hsts http://www.mirrorservice.org/sites/ftp.delorie.com/pub/djgpp/current/v2gnu/gdb801b.zip - export cmdstatus=$? - fi - if [ $cmdstatus -eq 0 ]; then - echo "fetch of gdb801b.zip was successful" - fi - fi - if [ -f gdb801b.zip ]; then - echo "unzipping gdb801b.zip" - unzip -p gdb801b.zip bin/gdb.exe >./gdb.exe - fi - fi - echo "Native DOS executables:" - ls -l *.exe - cd ../../ + cd djgpp/target + count=0 + while [ "x${zipurl[count]}" != "x" ] + do + if [ ! -f ${exesought[count]} ]; then + if [ ! -f ${ziplocal[count]} ]; then + echo "Getting ${ziplocal[count]}" ; + if [ "$(uname)" = "Darwin" ]; then + #Mac + curl --output ${ziplocal[count]} ${zipurl[count]} + export cmdstatus=$? + else + wget --quiet --no-hsts ${zipurl[count]} + export cmdstatus=$? + fi + if [ $cmdstatus -eq 0 ]; then + echo "fetch of ${ziplocal[count]} was successful" + fi + fi + if [ -f ${ziplocal[count]} ]; then + echo "unzipping ${ziplocal[count]}" + unzip -p ${ziplocal[count]} ${exepathinzip[count]} >./${exesought[count]} + fi + fi + count=$(( $count + 1 )) + done + echo "Native DOS executables in lib/djgpp/target:" + ls -l *.exe + cd ../../ fi FONT_VERSION="4.49" @@ -207,6 +218,8 @@ if [ ! -d "$FONT_LFILE" ]; then fi tar -xvf $FONT_RFILE rm $FONT_RFILE +else + echo "terminus fonts are already available in lib/$FONT_LFILE" fi cd ../ From 0381e6162459fe01038fbcdf279a1418796a4113 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Tue, 17 Dec 2024 18:22:52 +0200 Subject: [PATCH 198/791] Fix out-of-bounds in test_move Hero was on the top-left of an open map at (1,0), and a monster was trying to knock them back to (0,-1). --- src/hack.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/hack.c b/src/hack.c index 538a9b699..ed5475136 100644 --- a/src/hack.c +++ b/src/hack.c @@ -972,10 +972,16 @@ test_move( { coordxy x = ux + dx; coordxy y = uy + dy; - struct rm *tmpr = &levl[x][y]; + struct rm *tmpr; struct rm *ust; svc.context.door_opened = FALSE; + + if (!isok(x, y)) + return FALSE; + + tmpr = &levl[x][y]; + /* * Check for physical obstacles. First, the place we are going. */ From 8da4f74dcfb7f005f242848b19eef7d215e2195b Mon Sep 17 00:00:00 2001 From: nhmall Date: Tue, 17 Dec 2024 13:02:05 -0500 Subject: [PATCH 199/791] revisit some coordxy casts inherited from time of xchar The ones below marked "left,revisit" might be worthy of code changes explode.c:removed: arg sx,sy passed to breaks() are coordxy and so are the parameters invent.c: removed: discover_artifact() parameter is xint16, so change cast to match mail.c: removed: gv.viz_rmin[] contains coordxy's, and enexto() 2nd param is too mkmaze.c: removed: x, y are coordxy and so are cc->x, cc->y mkroom.c: removed: tx, ty are coordxy and so are parameters to occupied() mplayer.c: left,revisit: x,y declared int, but mk_mplayer() params are coordxy sp_lev.c 2890: left alone: x,y declared int, but is_ok_location() params coordxy sp_lev.c 4114: left alone: cast from lua_Integer sp_lev.c 4123: left alone: cast from lua_Integer sp_lev.c 4650: left alone: cast from lua_Integer returned from lua_tointeger sp_lev.c 4765: left alone: cast from int_Integer returned from lua_tointeger sp_lev.c 4772: left alone: cast from int_Integer returned from get_table_int teleport.c 366: left alone: cast from int returned from rn2() timeout.c 2171: left alone: cast from long vault.c: left,revisit: guardx,guardy declared int, but bestcc fields are coordxy worm.c 791: left,revisit: wseg.wx, wseg.wy are coordxy, so are nx, ny, but not ox, oy; why are ox, oy needed at all? worm.c 955: left alone: wx, wy are coordxy, wseg_at() params are int x, int y zap.c 5061: left alone: cast from long --- src/apply.c | 4 ++-- src/explode.c | 2 +- src/invent.c | 2 +- src/mail.c | 4 ++-- src/mkmaze.c | 8 ++++---- src/mkroom.c | 2 +- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/apply.c b/src/apply.c index 7e4c85c1c..f927f7085 100644 --- a/src/apply.c +++ b/src/apply.c @@ -1965,8 +1965,8 @@ display_jump_positions(boolean on_off) tmp_at(DISP_BEAM, cmap_to_glyph(S_goodpos)); for (dx = -4; dx <= 4; dx++) for (dy = -4; dy <= 4; dy++) { - x = dx + (coordxy) u.ux; - y = dy + (coordxy) u.uy; + x = dx + u.ux; + y = dy + u.uy; if (get_valid_jump_position(x, y) && !u_at(x, y)) tmp_at(x, y); } diff --git a/src/explode.c b/src/explode.c index f87c6008d..2aff34776 100644 --- a/src/explode.c +++ b/src/explode.c @@ -807,7 +807,7 @@ scatter(coordxy sx, coordxy sy, /* location of objects to scatter */ } else if ((scflags & MAY_DESTROY) != 0 && (!rn2(10) || (objects[otmp->otyp].oc_material == GLASS || otmp->otyp == EGG))) { - if (breaks(otmp, (coordxy) sx, (coordxy) sy)) + if (breaks(otmp, sx, sy)) used_up = TRUE; } diff --git a/src/invent.c b/src/invent.c index be0dff2cc..11bff7d23 100644 --- a/src/invent.c +++ b/src/invent.c @@ -2537,7 +2537,7 @@ fully_identify_obj(struct obj *otmp) { makeknown(otmp->otyp); if (otmp->oartifact) - discover_artifact((coordxy) otmp->oartifact); + discover_artifact((xint16) otmp->oartifact); otmp->known = otmp->dknown = otmp->bknown = otmp->rknown = 1; set_cknown_lknown(otmp); /* set otmp->{cknown,lknown} if applicable */ if (otmp->otyp == EGG && otmp->corpsenm != NON_PM) diff --git a/src/mail.c b/src/mail.c index c1c62dc78..e6a5c2935 100644 --- a/src/mail.c +++ b/src/mail.c @@ -201,7 +201,7 @@ md_start(coord *startp) startp->y = row; startp->x = gv.viz_rmin[row]; - } else if (enexto(&testcc, (coordxy) gv.viz_rmin[row], row, + } else if (enexto(&testcc, gv.viz_rmin[row], row, (struct permonst *) 0) && !cansee(testcc.x, testcc.y) && couldsee(testcc.x, testcc.y)) { @@ -216,7 +216,7 @@ md_start(coord *startp) startp->y = row; startp->x = gv.viz_rmax[row]; - } else if (enexto(&testcc, (coordxy) gv.viz_rmax[row], row, + } else if (enexto(&testcc, gv.viz_rmax[row], row, (struct permonst *) 0) && !cansee(testcc.x, testcc.y) && couldsee(testcc.x, testcc.y)) { diff --git a/src/mkmaze.c b/src/mkmaze.c index 2aa526ce0..e43b34caf 100644 --- a/src/mkmaze.c +++ b/src/mkmaze.c @@ -1322,8 +1322,8 @@ mazexy(coord *cc) x = rnd(gx.x_maze_max); y = rnd(gy.y_maze_max); if (levl[x][y].typ == allowedtyp) { - cc->x = (coordxy) x; - cc->y = (coordxy) y; + cc->x = x; + cc->y = y; return; } } while (++cpt < 100); @@ -1331,8 +1331,8 @@ mazexy(coord *cc) for (x = 1; x <= gx.x_maze_max; x++) for (y = 1; y <= gy.y_maze_max; y++) if (levl[x][y].typ == allowedtyp) { - cc->x = (coordxy) x; - cc->y = (coordxy) y; + cc->x = x; + cc->y = y; return; } /* every spot on the area of map allowed for mazes has been rejected */ diff --git a/src/mkroom.c b/src/mkroom.c index 61a913e8f..c9aecb15a 100644 --- a/src/mkroom.c +++ b/src/mkroom.c @@ -293,7 +293,7 @@ fill_zoo(struct mkroom *sroom) (void) somexyspace(sroom, &mm); tx = mm.x; ty = mm.y; - } while (occupied((coordxy) tx, (coordxy) ty) && --i > 0); + } while (occupied(tx, ty) && --i > 0); throne_placed: mk_zoo_thronemon(tx, ty); break; From 20c456cbbba65ccdb1429f140bb0b41895826a48 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Tue, 17 Dec 2024 20:57:59 +0200 Subject: [PATCH 200/791] Avoid using doopen return value in test_move We can't rely on doopen_indir return value to check whether hero moved and opened a door. Instead, explicitly check whether the door is still closed, and whether hero moved. --- src/hack.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/hack.c b/src/hack.c index ed5475136..4a19c9cf0 100644 --- a/src/hack.c +++ b/src/hack.c @@ -1073,9 +1073,9 @@ test_move( " but can't squeeze your possessions through."); if (flags.autoopen && !svc.context.run && !Confusion && !Stunned && !Fumbling) { - svc.context.door_opened - = svc.context.move - = (doopen_indir(x, y) == ECMD_TIME ? 1 : 0); + (void) doopen_indir(x, y); + svc.context.door_opened = !closed_door(x, y); + svc.context.move = (x != u.ux || y != u.uy); } else if (x == ux || y == uy) { if (Blind || Stunned || ACURR(A_DEX) < 10 || Fumbling) { From 6ce2ae956e56d635dfa18a955b5096bfb6562d2e Mon Sep 17 00:00:00 2001 From: nhmall Date: Tue, 17 Dec 2024 15:33:39 -0500 Subject: [PATCH 201/791] simplify inclusion of debugging capability in msdos package This build command will include line number info, gdb.exe or nhgdb.bat in the package: make CROSS_TO_MSDOS=1 WANT_DEBUG=1 package This build command will not include line number info, gdb.exe or nhgdb.bat in the package: make CROSS_TO_MSDOS=1 package --- sys/unix/hints/include/cross-post.370 | 24 +++++++++++++----------- sys/unix/hints/include/cross-pre2.370 | 11 +++++++++++ 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/sys/unix/hints/include/cross-post.370 b/sys/unix/hints/include/cross-post.370 index 2f775e90f..6e153bbc9 100644 --- a/sys/unix/hints/include/cross-post.370 +++ b/sys/unix/hints/include/cross-post.370 @@ -70,6 +70,18 @@ dospkg: dodata dosfonts $(GAMEBIN) $(TARGETPFX)recover.exe ../dat/nhtiles.bmp else \ pwd; echo "../lib/djgpp/target/symify.exe not found"; \ fi; ) +ifeq "$(WANT_DEBUG)" "1" + ( if [ -f $(GDBEXE) ]; \ + then \ + cp $(GDBEXE) $(TARGETPFX)pkg/GDB.EXE; \ + echo "gdb -ex '$(GDBCMDLINE)' NETHACK.EXE"> $(TARGETPFX)pkg/$(GDBBAT); \ + else \ + pwd; echo "$(GDBEXE) not found and WANT_DEBUG=1 specified"; \ + fi; ) +else + -rm $(TARGETPFX)pkg/GDB.EXE + -rm $(TARGETPFX)pkg/NHGDB.BAT +endif -touch $(TARGETPFX)pkg/RECORD cd $(TARGETPFX)pkg ; zip -9 ../NH370DOS.ZIP * ; cd ../../.. @echo msdos package zip file $(TARGETPFX)NH370DOS.ZIP @@ -78,7 +90,6 @@ $(LUABIN): ( cd .. && make luabin && cd src) dodata: ( cd .. && make dlb && cd src) - ifdef dosbox # make CROSS_TO_MSDOS=1 dosbox=~/dosbox deploy-to-dosbox ifdef MAKEFILE_TOP @@ -92,11 +103,9 @@ deploytodosbox: $(TARGETPFX)NH370DOS.ZIP $(dosboxnhfolder) $(dosboxnhsrc) \ $(dosboxnhsrc)/sys/msdos $(dosboxnhsrc)/sys/share \ $(dosboxnhsrc)/win/share $(dosboxnhsrc)/win/curses \ $(dosboxnhsrc)/win/tty $(dosboxnhsrc)/util \ - $(dosboxnhfolder)/NETHACK.EXE \ - $(dosboxnhfolder)/GDB.EXE $(dosboxnhfolder)/nhgdb.bat + $(dosboxnhfolder)/NETHACK.EXE @echo DOS NetHack deployed to dosbox at $(dosboxnhfolder) $(TARGETPFX)NH370DOS.ZIP: dospkg -# ( cd ..; make CROSS_TO_MSDOS=1 WANT_DEBUG=1 dospkg; cd src) $(dosboxnhfolder): mkdir -p $@ $(dosboxnhsrc): $(dosboxnhfolder) @@ -132,13 +141,6 @@ $(dosboxnhfolder)/NETHACK.EXE: $(TARGETPFX)NH370DOS.ZIP unzip -o $(TARGETPFX)NH370DOS.ZIP -d $(dosboxnhfolder) find $(dosboxnhfolder) -type f -name "$(dosboxconfigfile)" \ | xargs sed -i 's/#OPTIONS=video:autodetect/OPTIONS=video:autodetect/g' -$(dosboxnhfolder)/GDB.EXE: $(dosboxnhfolder) $(dostargetexes)/gdb801b.zip - cp --preserve=timestamps $(dostargetexes)/gdb.exe $@ -$(dostargetexes)/gdb801b.zip: - curl --output $(dostargetexes)/gdb801b.zip $(dosgdburl) - unzip -p $(dostargetexes)/gdb801b.zip bin/gdb.exe >$@ -$(dosboxnhfolder)/nhgdb.bat: $(FLDR)src/Makefile - echo "gdb -ex 'directory nhsrc/src nhsrc/include nhsrc/sys/msdos nhsrc/sys/share nhsrc/win/share nhsrc/win/curses nhsrc/win/tty nhsrc/util' NETHACK.EXE"> $@ endif # dosbox endif # CROSS_TO_MSDOS diff --git a/sys/unix/hints/include/cross-pre2.370 b/sys/unix/hints/include/cross-pre2.370 index defe671fa..b0abd3644 100644 --- a/sys/unix/hints/include/cross-pre2.370 +++ b/sys/unix/hints/include/cross-pre2.370 @@ -228,6 +228,17 @@ override RECOVERBIN = $(TARGETPFX)recover.exe override PACKAGE = dospkg override PREGAME += mkdir -p $(TARGETDIR) ; make $(TARGETPFX)exceptn.o ; override CLEANMORE += rm -f -r $(TARGETDIR) ; rm -f -r $(FONTTARGETS) ; +ifeq "$(WANT_DEBUG)" "1" +GDBEXE=../lib/djgpp/target/gdb.exe +GDBBAT=NHGDB.BAT +GDBCMDLINE=directory nhsrc/src nhsrc/include nhsrc/sys/msdos \ + nhsrc/sys/share nhsrc/win/share nhsrc/win/curses \ + nhsrc/win/tty nhsrc/util +else +GDBEXE= +GDBBAT= +GDBCMDLINE= +endif VARDATND += nhtiles.bmp # ifdef WANT_WIN_CURSES From 80a0a309ea56d8040b786444f6d6628e845a07c1 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Tue, 17 Dec 2024 22:54:47 +0200 Subject: [PATCH 202/791] Don't advance spell skills when using wizcast --- src/spell.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/spell.c b/src/spell.c index 3acdb3e1c..e3d7f2e12 100644 --- a/src/spell.c +++ b/src/spell.c @@ -1575,7 +1575,8 @@ spelleffects(int spell_otyp, boolean atme, boolean force) } /* gain skill for successful cast */ - use_skill(skill, spellev(spell)); + if (!force) + use_skill(skill, spellev(spell)); obfree(pseudo, (struct obj *) 0); /* now, get rid of it */ return ECMD_TIME; From 6e587fb282c81de66c818ea2cd92be5233754cc5 Mon Sep 17 00:00:00 2001 From: PatR Date: Tue, 17 Dec 2024 13:46:25 -0800 Subject: [PATCH 203/791] fix out-of-bounds not in test_move() Commit 0381e6162459fe01038fbcdf279a1418796a4113 fixed a problem for mon vs hero in test_move(), but the situation can also happen with mon vs mon which doesn't use test_move(). --- src/uhitm.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/uhitm.c b/src/uhitm.c index b77c018e3..64eb46e3e 100644 --- a/src/uhitm.c +++ b/src/uhitm.c @@ -5160,6 +5160,8 @@ mhitm_knockback( return FALSE; } else { /* subset of test_move() */ + if (!isok(defx + dx, defy + dy)) + return FALSE; if (IS_DOOR(levl[defx][defy].typ) && (defx - magr->mx && defy - magr->my) && !doorless_door(defx, defy)) From f32e766728e2bbe8d5582ca687813b0933ae3d90 Mon Sep 17 00:00:00 2001 From: nhmall Date: Tue, 17 Dec 2024 19:16:00 -0500 Subject: [PATCH 204/791] MIPS cross-compile bit Use 3 additional Makefile variables --- sys/unix/hints/include/cross-post.370 | 4 ++-- sys/unix/hints/include/cross-pre2.370 | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/sys/unix/hints/include/cross-post.370 b/sys/unix/hints/include/cross-post.370 index 6e153bbc9..c6f40e52d 100644 --- a/sys/unix/hints/include/cross-post.370 +++ b/sys/unix/hints/include/cross-post.370 @@ -302,11 +302,11 @@ ifdef BUILD_TARGET_NCURSES .PHONY: build-ncurses ifdef MAKEFILE_SRC ../lib/ncurses.tar.gz: - @echo "You will need to successfully execute 'make CROSS_TO_MIPS=1 fetch-ncurses' first" + @echo "You will need to successfully execute 'make CROSS_TO_$(NCURSES_PLATFORM)=1 fetch-ncurses' first" @false $(TARGETPFX)ncurses/lib/libncurses.a: ../lib/ncurses.tar.gz (cd $(TARGETDIR) ; mkdir -p ncurses ; cd ncurses ; tar -xf ../../../lib/ncurses.tar.gz --strip-components=1 ; \ - ./configure --build i686-pc-linux-gnu --host mipsel-linux-gnu ; \ + ./configure --build $(NCURSES_CONFIGURE_BUILD) --host $(NCURSES_CONFIGURE_HOST) ; \ make ; \ cd ../../../src) endif #MAKEFILE_SRC diff --git a/sys/unix/hints/include/cross-pre2.370 b/sys/unix/hints/include/cross-pre2.370 index b0abd3644..15fbe719c 100644 --- a/sys/unix/hints/include/cross-pre2.370 +++ b/sys/unix/hints/include/cross-pre2.370 @@ -439,6 +439,9 @@ override RECOVERBIN = $(TARGETPFX)recover override PACKAGE = mipspkg override PREGAME += mkdir -p $(TARGETDIR) ; override CLEANMORE += rm -f -r $(TARGETDIR) ; +NCURSES_CONFIGURE_BUILD=i686-pc-linux-gnu +NCURSES_CONFIGURE_HOST=mipsel-linux-gnu +NCURSES_PLATFORM=MIPS # Rule for file in sys/unix #$(TARGETPFX)%.o : ../sys/unix/%.c # $(TARGET_CC) $(TARGET_CFLAGS) -c -o$@ $< From faf2267aba1d817c26248a5321f92a171748c19d Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Wed, 18 Dec 2024 10:35:54 +0200 Subject: [PATCH 205/791] Use correct variables, not where we are trying to go --- src/hack.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hack.c b/src/hack.c index 4a19c9cf0..cf6ad1a0f 100644 --- a/src/hack.c +++ b/src/hack.c @@ -1075,7 +1075,7 @@ test_move( && !Confusion && !Stunned && !Fumbling) { (void) doopen_indir(x, y); svc.context.door_opened = !closed_door(x, y); - svc.context.move = (x != u.ux || y != u.uy); + svc.context.move = (ux != u.ux || uy != u.uy); } else if (x == ux || y == uy) { if (Blind || Stunned || ACURR(A_DEX) < 10 || Fumbling) { From 65070b746261d27fd42aa8d7368d3a47cd10a52e Mon Sep 17 00:00:00 2001 From: PatR Date: Wed, 18 Dec 2024 02:15:09 -0800 Subject: [PATCH 206/791] fix /e and /E A fix in Janurary to avoid appending engraving text or headstone text when examining a map location where a monster or object covers the engraving or headstone inadvently broke the /e and /E variations of the '/' command, which is intended to list such text even when covered. --- doc/fixes3-7-0.txt | 5 +++++ src/pager.c | 28 +++++++++++++++++----------- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index 892fa0dd0..ba11b8b90 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -1491,6 +1491,7 @@ artifact gifts are rebalanced (easier to obtain; higher-value sacrifices are gifted enchanted; unaligned artifacts are possible but rare even on the first gift; artifacts you can't use well are less likely) luck gains from sacrificing are limited by the value of the sacrifice +failed #untrap could move hero diagonally into or out of an open doorway Fixes to 3.7.0-x General Problems Exposed Via git Repository @@ -2071,6 +2072,10 @@ if a pile of objects had plain arrow(s) on top, map location classification got confused and reported 'unexplored area' when the 'fireassist' option was on, 'f' would choose uquiver over wielded throw-and-return uwep +knockback could move hero diagonally into or out of an open doorway +farlook of /e or /E stopped reporting engraving and headstone text after a fix + for the situation where // or ; reported such text when there was an + object or monster in the way Fixes to 3.7.0-x Platform and/or Interface Problems Exposed Via git Repository diff --git a/src/pager.c b/src/pager.c index d067b3f87..af885d4a6 100644 --- a/src/pager.c +++ b/src/pager.c @@ -50,7 +50,8 @@ staticfn void domenucontrols(void); extern void port_help(void); #endif staticfn char *setopt_cmd(char *) NONNULL NONNULLARG1; -staticfn boolean add_quoted_engraving(coordxy, coordxy, char *) NONNULLARG3; +staticfn boolean add_quoted_engraving(coordxy, coordxy, char *, boolean) + NONNULLARG3; enum checkfileflags { chkfilNone = 0, @@ -1581,7 +1582,7 @@ do_screen_description( *firstmatch = look_buf; if (*(*firstmatch)) { Sprintf(temp_buf, " (%s", *firstmatch); - (void) add_quoted_engraving(cc.x, cc.y, temp_buf); + (void) add_quoted_engraving(cc.x, cc.y, temp_buf, FALSE); Strcat(temp_buf, ")"); (void) strncat(out_str, temp_buf, BUFSZ - strlen(out_str) - 1); @@ -1600,7 +1601,10 @@ do_screen_description( /* when farlook is reporting on an engraving, include its text */ staticfn boolean -add_quoted_engraving(coordxy x, coordxy y, char *buf) +add_quoted_engraving( + coordxy x, coordxy y, + char *buf, + boolean force) /* True: '/e' or '/E', False: '//' or ';' */ { char temp_buf[BUFSZ]; struct engr *ep = engr_at(x, y); @@ -1617,7 +1621,10 @@ add_quoted_engraving(coordxy x, coordxy y, char *buf) * or object) that happens to be on top of an engraving, so we won't * append the engraving text. */ - if (!ep || (!floorengr && !headstone)) + if (!ep) + return FALSE; + + if (!floorengr && !headstone && !force) return FALSE; if (ep->eread) @@ -2100,13 +2107,12 @@ look_engrs(boolean nearby) if (!e) continue; glyph = glyph_at(x, y); - sym = ((levl[x][y].typ == GRAVE || svl.lastseentyp[x][y] == GRAVE) - ? S_grave + is_headstone = IS_GRAVE(svl.lastseentyp[x][y]); + sym = (is_headstone ? S_grave : (levl[x][y].typ == CORR) ? S_engrcorr : S_engroom); - is_headstone = (sym == S_grave); - Sprintf(lookbuf, "(%s", is_headstone ? "grave" : "engraving"); - (void) add_quoted_engraving(x, y, lookbuf); + Sprintf(lookbuf, " (%s", is_headstone ? "grave" : "engraving"); + (void) add_quoted_engraving(x, y, lookbuf, TRUE); /* the paren is used by farlook and add_quoted_engraving() expected to see it; we don't want it here */ if (is_headstone) { @@ -2114,7 +2120,7 @@ look_engrs(boolean nearby) (void) strsubst(lookbuf, "(grave whose ", ""); } else { (void) strsubst(lookbuf, "(engraving with ", ""); - (void) strsubst(lookbuf, "(engraving that ", "one that "); + (void) strsubst(lookbuf, "(engraving ", "engraving "); } if (glyph_is_cmap(glyph) && !glyph_is_trap(glyph)) { @@ -2150,7 +2156,7 @@ look_engrs(boolean nearby) : (cmode == GPCOORDS_MAP) ? "%8s " : "%12s ", coord_desc(x, y, coordbuf, cmode)); - Sprintf(eos(outbuf), "%s ", encglyph(glyph)); + Sprintf(eos(outbuf), "%s ", encglyph(glyph)); /* guard against potential overflow */ lookbuf[sizeof lookbuf - 1 - strlen(outbuf)] = '\0'; Strcat(outbuf, lookbuf); From 01e781fff3159ea8ff3118c42862f20ba8bb2f41 Mon Sep 17 00:00:00 2001 From: PatR Date: Wed, 18 Dec 2024 18:14:30 -0800 Subject: [PATCH 207/791] /e /E lint In look_engrs(), 'sym' isn't used anymore. --- src/pager.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/pager.c b/src/pager.c index af885d4a6..4654e1f57 100644 --- a/src/pager.c +++ b/src/pager.c @@ -2089,7 +2089,6 @@ look_engrs(boolean nearby) winid win; struct engr *e; char lookbuf[BUFSZ], outbuf[BUFSZ]; - nhsym sym; coordxy x, y, lo_x, lo_y, hi_x, hi_y; boolean is_headstone; int glyph, count = 0; @@ -2108,9 +2107,6 @@ look_engrs(boolean nearby) continue; glyph = glyph_at(x, y); is_headstone = IS_GRAVE(svl.lastseentyp[x][y]); - sym = (is_headstone ? S_grave - : (levl[x][y].typ == CORR) ? S_engrcorr - : S_engroom); Sprintf(lookbuf, " (%s", is_headstone ? "grave" : "engraving"); (void) add_quoted_engraving(x, y, lookbuf, TRUE); /* the paren is used by farlook and add_quoted_engraving() From 27a03ef75b13a0e415e752befbfb620bb88fb747 Mon Sep 17 00:00:00 2001 From: PatR Date: Thu, 19 Dec 2024 01:11:14 -0800 Subject: [PATCH 208/791] more /e /E Discovered but covered engravings weren't being shown by /e and /E. --- src/pager.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/pager.c b/src/pager.c index 4654e1f57..465659bd2 100644 --- a/src/pager.c +++ b/src/pager.c @@ -2091,13 +2091,17 @@ look_engrs(boolean nearby) char lookbuf[BUFSZ], outbuf[BUFSZ]; coordxy x, y, lo_x, lo_y, hi_x, hi_y; boolean is_headstone; + nhsym sym; int glyph, count = 0; win = create_nhwindow(NHW_TEXT); look_region_nearby(&lo_x, &lo_y, &hi_x, &hi_y, nearby); + /*assert(lo_x >= 1 && lo_y >= 0 && hi_x < MAXCO && hi_y < MAXLI);*/ for (y = lo_y; y <= hi_y; y++) { for (x = lo_x; x <= hi_x; x++) { lookbuf[0] = '\0'; + if (!levl[x][y].seenv) + continue; /* this won't find remembered engravings which aren't there anymore (in case the hero is unaware that they're gone; scuffed away by monster movement or deleted during shop @@ -2105,7 +2109,6 @@ look_engrs(boolean nearby) e = engr_at(x, y); if (!e) continue; - glyph = glyph_at(x, y); is_headstone = IS_GRAVE(svl.lastseentyp[x][y]); Sprintf(lookbuf, " (%s", is_headstone ? "grave" : "engraving"); (void) add_quoted_engraving(x, y, lookbuf, TRUE); @@ -2119,18 +2122,18 @@ look_engrs(boolean nearby) (void) strsubst(lookbuf, "(engraving ", "engraving "); } - if (glyph_is_cmap(glyph) && !glyph_is_trap(glyph)) { + glyph = glyph_at(x, y); + sym = glyph_is_cmap(glyph) ? glyph_to_cmap(glyph) : SYM_NOTHING; + if (is_cmap_engraving(sym) || sym == S_grave) { /* engraving or grave+headstone shown on the map */ ++count; - } else if (e->eread || is_headstone) { + } else { /* engraving or grave covered by object(s) */ Snprintf(eos(lookbuf), sizeof lookbuf - strlen(lookbuf), ", obscured by %s", encglyph(glyph)); glyph = is_headstone ? cmap_to_glyph(S_grave) : engraving_to_glyph(e); ++count; - } else { - continue; } if (*lookbuf) { /* (redundant) */ char coordbuf[20], cmode; From 87694e1a959096210f4b0b6567b23fa12dbc922c Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Thu, 19 Dec 2024 12:37:13 +0200 Subject: [PATCH 209/791] Hero remembers trapped boxes After finding a trap on a chest or a large box, remember it as trapped: "You see here a trapped large box." Randomly generated chests and boxes can be obviously trapped. Allow defining obviously trapped containers via lua. Invalidates saves and bones. --- doc/fixes3-7-0.txt | 1 + doc/lua.adoc | 1 + include/obj.h | 2 +- include/patchlevel.h | 2 +- include/sp_lev.h | 2 +- src/detect.c | 2 ++ src/lock.c | 12 ++++--- src/mkobj.c | 2 ++ src/nhlobj.c | 1 + src/objnam.c | 3 ++ src/sp_lev.c | 6 +++- src/trap.c | 77 ++++++++++++++++++++++++++++---------------- 12 files changed, 75 insertions(+), 36 deletions(-) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index ba11b8b90..24d7ec690 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -1492,6 +1492,7 @@ artifact gifts are rebalanced (easier to obtain; higher-value sacrifices are the first gift; artifacts you can't use well are less likely) luck gains from sacrificing are limited by the value of the sacrifice failed #untrap could move hero diagonally into or out of an open doorway +remember box is trapped after finding the trap Fixes to 3.7.0-x General Problems Exposed Via git Repository diff --git a/doc/lua.adoc b/doc/lua.adoc index eea32e7d7..e9962a174 100644 --- a/doc/lua.adoc +++ b/doc/lua.adoc @@ -849,6 +849,7 @@ The table parameter accepts the following: | eroded | int | Object erosion | locked | boolean | Is the object locked? | trapped | boolean | Is the object trapped? +| trap_known | boolean | If container is trapped, is it obvious? | recharged | boolean | Is the object recharged? | greased | boolean | Is the object greased? | broken | boolean | Is the object broken? diff --git a/include/obj.h b/include/obj.h index f43d94f81..7d716c518 100644 --- a/include/obj.h +++ b/include/obj.h @@ -141,9 +141,9 @@ struct obj { * they have no locks */ Bitfield(pickup_prev, 1); /* was picked up previously */ Bitfield(ghostly, 1); /* it just got placed into a bones file */ + Bitfield(tknown, 1); /* trap status known for chests */ #if 0 /* not implemented */ - Bitfield(tknown, 1); /* trap status known for chests */ Bitfield(eknown, 1); /* effect known for wands zapped or rings worn when * not seen yet after being picked up while blind * [maybe for remaining stack of used potion too] */ diff --git a/include/patchlevel.h b/include/patchlevel.h index 661160f1c..2f32a4b86 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 112 +#define EDITLEVEL 113 /* * Development status possibilities. diff --git a/include/sp_lev.h b/include/sp_lev.h index d4d4d8c4b..3a9a18d34 100644 --- a/include/sp_lev.h +++ b/include/sp_lev.h @@ -156,7 +156,7 @@ typedef struct { int quan; short buried; short lit; - short eroded, locked, trapped, recharged, invis, greased, broken, + short eroded, locked, trapped, tknown, recharged, invis, greased, broken, achievement; } object; diff --git a/src/detect.c b/src/detect.c index 7ccce8911..172f4704c 100644 --- a/src/detect.c +++ b/src/detect.c @@ -930,6 +930,8 @@ detect_obj_traps( continue; } if (Is_box(otmp) && otmp->otrapped) { + otmp->tknown = 1; + otmp->dknown = 1; result |= u_at(x, y) ? OTRAP_HERE : OTRAP_THERE; if (ft) { flash_glyph_at(x, y, trapglyph, FOUND_FLASH_COUNT); diff --git a/src/lock.c b/src/lock.c index fa8fb22f8..640083041 100644 --- a/src/lock.c +++ b/src/lock.c @@ -105,11 +105,12 @@ picklock(void) : (gx.xlock.door->doormask & D_TRAPPED) != 0) && gx.xlock.magic_key) { gx.xlock.chance += 20; /* less effort needed next time */ - /* unfortunately we don't have a 'tknown' flag to record - "known to be trapped" so declining to disarm and then - retrying lock manipulation will find it all over again */ - if (y_n("You find a trap! Do you want to try to disarm it?") - == 'y') { + if (!gx.xlock.door) { + if (!gx.xlock.box->tknown) + You("find a trap!"); + gx.xlock.box->tknown = 1; + } + if (y_n("Do you want to try to disarm it?") == 'y') { const char *what; boolean alreadyunlocked; @@ -120,6 +121,7 @@ picklock(void) alreadyunlocked = !(gx.xlock.door->doormask & D_LOCKED); } else { gx.xlock.box->otrapped = 0; + gx.xlock.box->tknown = 0; what = (gx.xlock.box->otyp == CHEST) ? "chest" : "box"; alreadyunlocked = !gx.xlock.box->olocked; } diff --git a/src/mkobj.c b/src/mkobj.c index e332502bd..1ec69aa7d 100644 --- a/src/mkobj.c +++ b/src/mkobj.c @@ -852,6 +852,7 @@ unknow_object(struct obj *obj) obj->bknown = obj->rknown = 0; obj->cknown = obj->lknown = 0; + obj->tknown = 0; /* for an existing object, awareness of charges or enchantment has gone poof... [object types which don't use the known flag have it set True for some reason] */ @@ -1000,6 +1001,7 @@ mksobj_init(struct obj *otmp, boolean artif) case LARGE_BOX: otmp->olocked = !!(rn2(5)); otmp->otrapped = !(rn2(10)); + otmp->tknown = otmp->otrapped && !rn2(100); /* obvious trap */ FALLTHROUGH; /*FALLTHRU*/ case ICE_BOX: diff --git a/src/nhlobj.c b/src/nhlobj.c index ca2f74e17..6e97c3b87 100644 --- a/src/nhlobj.c +++ b/src/nhlobj.c @@ -295,6 +295,7 @@ l_obj_to_table(lua_State *L) nhl_add_table_entry_int(L, "dknown", obj->dknown); nhl_add_table_entry_int(L, "bknown", obj->bknown); nhl_add_table_entry_int(L, "rknown", obj->rknown); + nhl_add_table_entry_int(L, "tknown", obj->tknown); if (obj->oclass == POTION_CLASS) nhl_add_table_entry_int(L, "odiluted", obj->odiluted); else diff --git a/src/objnam.c b/src/objnam.c index 14227bc5c..a445564d5 100644 --- a/src/objnam.c +++ b/src/objnam.c @@ -1334,6 +1334,9 @@ doname_base( Strcat(prefix, "uncursed "); } + /* "a large trapped box" would perhaps be more correct */ + if (Is_box(obj) && obj->otrapped && obj->tknown && obj->dknown) + Strcat(prefix,"trapped "); if (lknown && Is_box(obj)) { if (obj->obroken) /* 3.6.0 used "unlockable" here but that could be misunderstood diff --git a/src/sp_lev.c b/src/sp_lev.c index a429ba10b..135a72dec 100644 --- a/src/sp_lev.c +++ b/src/sp_lev.c @@ -2277,6 +2277,8 @@ create_object(object *o, struct mkroom *croom) } if (o->trapped == 0 || o->trapped == 1) otmp->otrapped = o->trapped; + if (o->trapped && (o->tknown == 0 || o->tknown == 1)) + otmp->tknown = o->tknown; otmp->greased = o->greased ? 1 : 0; if (o->quan > 0 && objects[otmp->otyp].oc_merge) { @@ -3517,7 +3519,7 @@ lspo_object(lua_State *L) 0, /* quan */ 0, /* buried */ 0, /* lit */ - 0, 0, 0, 0, /* eroded, locked, trapped, recharged */ + 0, 0, 0, 0, 0, /* eroded, locked, trapped, tknown, recharged */ 0, 0, 0, 0, /* invis, greased, broken, achievement */ }; #if 0 @@ -3537,6 +3539,7 @@ lspo_object(lua_State *L) tmpobj.spe = -127; tmpobj.quan = -1; tmpobj.trapped = -1; + tmpobj.tknown = -1; tmpobj.locked = -1; tmpobj.corpsenm = NON_PM; @@ -3590,6 +3593,7 @@ lspo_object(lua_State *L) tmpobj.eroded = get_table_int_opt(L, "eroded", 0); tmpobj.locked = get_table_boolean_opt(L, "locked", -1); tmpobj.trapped = get_table_boolean_opt(L, "trapped", -1); + tmpobj.tknown = get_table_boolean_opt(L, "trap_known", -1); tmpobj.recharged = get_table_int_opt(L, "recharged", 0); tmpobj.greased = get_table_boolean_opt(L, "greased", 0); tmpobj.broken = get_table_boolean_opt(L, "broken", 0); diff --git a/src/trap.c b/src/trap.c index d1be7d9b5..0ee5db704 100644 --- a/src/trap.c +++ b/src/trap.c @@ -65,6 +65,7 @@ staticfn void clear_conjoined_pits(struct trap *); staticfn boolean adj_nonconjoined_pit(struct trap *); staticfn int try_lift(struct monst *, struct trap *, int, boolean); staticfn int help_monster_out(struct monst *, struct trap *); +staticfn void disarm_box(struct obj *, boolean, boolean); staticfn void untrap_box(struct obj *, boolean, boolean); #if 0 staticfn void join_adjacent_pits(struct trap *); @@ -5687,6 +5688,32 @@ help_monster_out( return 1; } +staticfn void +disarm_box(struct obj *box, boolean force, boolean confused) +{ + if (box->otrapped) { + int ch = ACURR(A_DEX) + u.ulevel; + + if (Role_if(PM_ROGUE)) + ch *= 2; + if (!force && (confused || Fumbling + || rnd(75 + level_difficulty() / 2) > ch)) { + (void) chest_trap(box, FINGER, TRUE); + /* 'box' might be gone now */ + } else { + You("disarm it!"); + box->otrapped = 0; + box->tknown = 0; + more_experienced(8, 0); + newexplevel(); + } + exercise(A_DEX, TRUE); + } else { + pline("That %s was not trapped.", xname(box)); + box->tknown = 0; + } +} + /* check a particular container for a trap and optionally disarm it */ staticfn void untrap_box( @@ -5696,32 +5723,19 @@ untrap_box( { if ((box->otrapped && (force || (!confused && rn2(MAXULEV + 1 - u.ulevel) < 10))) + || box->tknown || (!force && confused && !rn2(3))) { - You("find a trap on %s!", the(xname(box))); + if (!(box->tknown && box->dknown)) + You("find a trap on %s!", the(xname(box))); + else + pline("There's a trap on %s.", the(xname(box))); + box->tknown = 1; + box->dknown = 1; if (!confused) exercise(A_WIS, TRUE); - if (ynq("Disarm it?") == 'y') { - if (box->otrapped) { - int ch = ACURR(A_DEX) + u.ulevel; - - if (Role_if(PM_ROGUE)) - ch *= 2; - if (!force && (confused || Fumbling - || rnd(75 + level_difficulty() / 2) > ch)) { - (void) chest_trap(box, FINGER, TRUE); - /* 'box' might be gone now */ - } else { - You("disarm it!"); - box->otrapped = 0; - more_experienced(8, 0); - newexplevel(); - } - exercise(A_DEX, TRUE); - } else { - pline("That %s was not trapped.", xname(box)); - } - } + if (ynq("Disarm it?") == 'y') + disarm_box(box, force, confused); } else { You("find no traps on %s.", the(xname(box))); } @@ -5882,20 +5896,28 @@ untrap( whether any had been found but not attempted to untrap; now at most one per move may be checked and we only continue on to door handling if they are all declined */ - for (otmp = svl.level.objects[x][y]; otmp; otmp = otmp->nexthere) - if (Is_box(otmp)) { + for (otmp = svl.level.objects[x][y]; otmp; otmp = otmp->nexthere) { + if (!Is_box(otmp)) + continue; + if (otmp->tknown && otmp->dknown) + (void) safe_qbuf(qbuf, "Disarm this ", NULL, + otmp, xname, ansimpleoname, "a box"); + else (void) safe_qbuf(qbuf, "There is ", " here. Check it for traps?", otmp, doname, ansimpleoname, "a box"); - switch (ynq(qbuf)) { + switch (ynq(qbuf)) { case 'q': return 0; case 'y': - untrap_box(otmp, force, confused); + if (otmp->tknown && otmp->dknown) + disarm_box(otmp, force, confused); + else + untrap_box(otmp, force, confused); return 1; /* even for 'no' at "Disarm it?" prompt */ } /* 'n' => continue to next box */ - } + } There("are no other chests or boxes here."); } @@ -6170,6 +6192,7 @@ chest_trap( if (get_obj_location(obj, &cc.x, &cc.y, 0)) /* might be carried */ obj->ox = cc.x, obj->oy = cc.y; + otmp->tknown = 0; otmp->otrapped = 0; /* trap is one-shot; clear flag first in case chest kills you and ends up in bones file */ You(disarm ? "set it off!" : "trigger a trap!"); From 5de7f986a014e27cb9296844d7bbcbbb1b429e34 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Thu, 19 Dec 2024 15:29:29 +0200 Subject: [PATCH 210/791] Forget obj trap known in bones file --- src/bones.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bones.c b/src/bones.c index 963c6d8f9..98fb9fd97 100644 --- a/src/bones.c +++ b/src/bones.c @@ -105,6 +105,7 @@ resetobjs(struct obj *ochain, boolean restore) otmp->rknown = 0; otmp->lknown = 0; otmp->cknown = 0; + otmp->tknown = 0; otmp->invlet = 0; otmp->no_charge = 0; otmp->how_lost = LOST_NONE; From 1e431139b4a85791732344ba370e32539edb3d54 Mon Sep 17 00:00:00 2001 From: PatR Date: Thu, 19 Dec 2024 13:11:01 -0800 Subject: [PATCH 211/791] fix issue #1342 - garbled iron bars message Issue reported by elunna: the message given when zap_over_floor() hits iron bars with lightning or acid was substituting a couple of words or phrases in the wrong order, resulting in |The {melt|dissolve} iron bars somewhat but remain intact. when the iron bar location is flagged as non-diggable. It should be |The iron bars {melt|dissolve} somewhat but remain intact. Not mentioned: the corresponding message for locations that aren't flagged as non-diggable used "melt" unconditionally. Change it to keep "melt" for lightning but switch to "corrode away" for acid. Fixes #1342 --- doc/fixes3-7-0.txt | 1 + src/zap.c | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index 24d7ec690..47e3c7753 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -2077,6 +2077,7 @@ knockback could move hero diagonally into or out of an open doorway farlook of /e or /E stopped reporting engraving and headstone text after a fix for the situation where // or ; reported such text when there was an object or monster in the way +message was garbled when lightning or acid breath hit iron bars Fixes to 3.7.0-x Platform and/or Interface Problems Exposed Via git Repository diff --git a/src/zap.c b/src/zap.c index 23fdac1be..d0e8fa077 100644 --- a/src/zap.c +++ b/src/zap.c @@ -5285,13 +5285,14 @@ zap_over_floor( if ((lev->wall_info & W_NONDIGGABLE) != 0) { if (see_it) Norep("The %s %s somewhat but remain intact.", - (damgtype == ZT_ACID) ? "corrode" : "melt", - defsyms[S_bars].explanation); + defsyms[S_bars].explanation, + (damgtype == ZT_ACID) ? "corrode" : "melt"); /* but nothing actually happens... */ } else { rangemod -= 3; if (see_it) - Norep("The %s melt.", defsyms[S_bars].explanation); + Norep("The %s %s.", defsyms[S_bars].explanation, + (damgtype == ZT_ACID) ? "corrode away" : "melt"); dissolve_bars(x, y); if (*in_rooms(x, y, SHOPBASE)) { add_damage(x, y, (type >= 0) ? SHOP_BARS_COST : 0L); From f7853be3dc9732b595d46d2c3b514c06a8534eba Mon Sep 17 00:00:00 2001 From: nhmall Date: Thu, 19 Dec 2024 17:53:43 -0500 Subject: [PATCH 212/791] fix GitHub issue 1303 related to engravings GitHub issue reported by ars3niy: https://github.com/NetHack/NetHack/issues/1303 @ars3niy commented on Oct 27: Stepping on a square with a dust or "graffiti" engraving while blind produces no message because presumably you can't read them by swiping the floor with your hands, however the engraving glyph still shows up on the map afterwards. While this helps zen players, it looks like a bug. @ville-v commented 3 days ago: Searching while blind also reveals the engravings. Here is a save file demonstrating the issue. [...] This adds an erevealed bit to engravings, to accompany the the eread bit that is already there. eread: refers to the text of the engraving erevealed: refers to the engraving map symbol Hopefully, this resolves issue 1303 without creating additional bugs. This invalidates existing save files and bones. Fixes #1303 --- include/engrave.h | 5 ++-- include/extern.h | 1 + src/display.c | 59 +++++++++++++++++++++++++++++------------------ src/engrave.c | 36 +++++++++++++++++++++++++++-- 4 files changed, 74 insertions(+), 27 deletions(-) diff --git a/include/engrave.h b/include/engrave.h index c0a53a6df..00fd586e1 100644 --- a/include/engrave.h +++ b/include/engrave.h @@ -33,8 +33,9 @@ struct engr { * even when hero isn't (so behaves similarly * to how Elbereth did in 3.4.3) */ Bitfield(nowipeout, 1); /* this engraving will not degrade */ - Bitfield(eread, 1); /* the engraving text has been read or felt */ - /* 5 free bits */ + Bitfield(eread, 1); /* refers to the engaving text: read or felt */ + Bitfield(erevealed, 1); /* refers to engraving map symbol: revealed */ + /* 4 free bits */ }; #define newengr(lth) \ diff --git a/include/extern.h b/include/extern.h index 84d61a8e1..932e95514 100644 --- a/include/extern.h +++ b/include/extern.h @@ -969,6 +969,7 @@ extern void make_grave(coordxy, coordxy, const char *); extern void disturb_grave(coordxy, coordxy); extern void see_engraving(struct engr *) NONNULLARG1; extern void feel_engraving(struct engr *) NONNULLARG1; +extern boolean engr_can_be_felt(struct engr *) NONNULLARG1; /* ### exper.c ### */ diff --git a/src/display.c b/src/display.c index 0e9cca612..f47e63062 100644 --- a/src/display.c +++ b/src/display.c @@ -420,10 +420,12 @@ unmap_object(coordxy x, coordxy y) struct rm *lev = &levl[x][y]; if (spot_shows_engravings(x, y) - && (ep = engr_at(x, y)) != 0 && !covers_traps(x, y)) + && (ep = engr_at(x, y)) != 0 && !covers_traps(x, y)) { + ep->erevealed = 0; map_engraving(ep, 0); - else + } else { map_background(x, y, 0); + } /* turn remembered dark room squares dark */ if (!lev->waslit && lev->glyph == cmap_to_glyph(S_room) @@ -443,26 +445,29 @@ unmap_object(coordxy x, coordxy y) * Internal to display.c, this is a #define for speed. */ #define _map_location(x, y, show) \ - do { \ - struct obj *obj; \ - struct trap *trap; \ - struct engr *ep; \ - NhRegion *_ml_reg; \ - \ - if ((obj = vobj_at(x, y)) && !covers_objects(x, y)) \ - map_object(obj, show); \ - else if ((trap = t_at(x, y)) && trap->tseen && !covers_traps(x, y)) \ - map_trap(trap, show); \ - else if (spot_shows_engravings(x, y) \ - && (ep = engr_at(x, y)) != 0 \ - && !covers_traps(x, y)) \ - map_engraving(ep, show); \ - else \ - map_background(x, y, show); \ - \ - update_lastseentyp(x, y); \ - if (show && !Blind && (_ml_reg = visible_region_at(x, y)) != 0) \ - show_region(_ml_reg, x, y); \ + do { \ + struct obj *obj; \ + struct trap *trap; \ + struct engr *ml_ep; \ + NhRegion *_ml_reg; \ + \ + if ((obj = vobj_at(x, y)) && !covers_objects(x, y)) { \ + map_object(obj, show); \ + } else if ((trap = t_at(x, y)) \ + && trap->tseen && !covers_traps(x, y)) { \ + map_trap(trap, show); \ + } else if (spot_shows_engravings(x, y) \ + && (ml_ep = engr_at(x, y)) != 0 \ + && ml_ep->erevealed != 0 \ + && !covers_traps(x, y)) { \ + map_engraving(ml_ep, show); \ + } else { \ + map_background(x, y, show); \ + } \ + \ + update_lastseentyp(x, y); \ + if (show && !Blind && (_ml_reg = visible_region_at(x, y)) != 0) \ + show_region(_ml_reg, x, y); \ } while (0) void @@ -742,6 +747,7 @@ feel_location(coordxy x, coordxy y) struct rm *lev; struct obj *boulder; struct monst *mon; + struct engr *ep; /* replicate safeguards used by newsym(); might not be required here */ if (_suppress_map_output()) @@ -851,6 +857,9 @@ feel_location(coordxy x, coordxy y) show_glyph(x, y, lev->glyph = cmap_to_glyph(S_darkroom)); } } else { + if ((ep = engr_at(x, y)) && !ep->erevealed && engr_can_be_felt(ep)) + ep->erevealed = 1; + _map_location(x, y, 1); if (Punished) { @@ -911,6 +920,7 @@ newsym(coordxy x, coordxy y) int see_it; boolean worm_tail; struct rm *lev = &(levl[x][y]); + struct engr *ep; /* don't try to produce map output when level is in a state of flux */ if (_suppress_map_output()) @@ -1009,8 +1019,11 @@ newsym(coordxy x, coordxy y) display_warning(mon); } else if (glyph_is_invisible(lev->glyph)) { map_invisible(x, y); - } else + } else { + if ((ep = engr_at(x, y)) && !ep->erevealed) + ep->erevealed = 1; _map_location(x, y, 1); /* map the location */ + } } /* Can't see the location. */ diff --git a/src/engrave.c b/src/engrave.c index 88ac6b29e..07f30bea5 100644 --- a/src/engrave.c +++ b/src/engrave.c @@ -285,6 +285,31 @@ wipe_engr_at(coordxy x, coordxy y, xint16 cnt, boolean magical) } } +/* + * Returns: + * non-zero if it can be felt + */ +boolean +engr_can_be_felt(struct engr *ep) +{ + boolean canfeel = FALSE; + + switch (ep->engr_type) { + case ENGRAVE: + case HEADSTONE: + case BURN: + canfeel = TRUE; + break; + case DUST: + case MARK: + case ENGR_BLOOD: + default: + canfeel = FALSE; + break; + } + return canfeel; +} + void read_engr_at(coordxy x, coordxy y) { @@ -355,6 +380,7 @@ read_engr_at(coordxy x, coordxy y) You("%s: \"%s\".", (Blind) ? "feel the words" : "read", et); Strcpy(ep->engr_txt[remembered_text], ep->engr_txt[actual_text]); ep->eread = 1; + ep->erevealed = 1; if (svc.context.run > 0) nomul(0); } @@ -399,7 +425,8 @@ make_engr_at( ep->engr_type = (xint8) ((e_type > 0) ? e_type : rnd(N_ENGRAVE - 1)); ep->engr_szeach = smem; ep->engr_alloc = smem * 3; - /* we do not set ep->eread; the caller will need to if required */ + /* we do not set ep->eread or ep->erevealed; + * the caller will need to if required */ } /* delete any engraving at location */ @@ -996,6 +1023,7 @@ doengrave(void) if (de->teleengr) { rloc_engr(de->oep); de->oep->eread = 0; + de->oep->erevealed = 0; de->disprefresh = TRUE; de->oep = (struct engr *) 0; } @@ -1014,6 +1042,7 @@ doengrave(void) if (tmp_ep != 0) { pline_The("engraving now reads: \"%s\".", de->buf); tmp_ep->eread = 1; + tmp_ep->erevealed = 1; de->disprefresh = TRUE; } } @@ -1395,8 +1424,10 @@ engrave(void) make_engr_at(u.ux, u.uy, buf, svm.moves - gm.multi, svc.context.engraving.type); oep = engr_at(u.ux, u.uy); - if (oep) + if (oep) { oep->eread = 1; + oep->erevealed = 1; + } if (*endc) { svc.context.engraving.nextc = endc; @@ -1640,6 +1671,7 @@ void feel_engraving(struct engr *ep) { ep->eread = 1; + ep->erevealed = 1; map_engraving(ep, 1); /* in case it's beneath something, redisplay the something */ newsym(ep->engr_x, ep->engr_y); From 111ef1e1a51fbf63b7d57f7fbcfa20a2dd52add1 Mon Sep 17 00:00:00 2001 From: nhmall Date: Thu, 19 Dec 2024 17:54:14 -0500 Subject: [PATCH 213/791] consume a bit in obj.h for future resolution of a TODO in bones.c Since EDITLEVEL is being incremented for the previous patch anyway, add the "name_from" bit to the obj struct now, as groundwork for the code change mentioned in a TODO comment in bones.c: /* strip user-supplied names */ /* Statue and some corpse names are left intact, presumably in case they came from score file. [TODO: this ought to be done differently--names which came from such a source or came from any stoned or killed monster should be flagged in some manner; then we could just check the flag here and keep "real" names (dead pets, &c) while discarding player notes attached to statues.] */ if (has_oname(otmp) && !(otmp->oartifact || otmp->otyp == STATUE || otmp->otyp == SPE_NOVEL || (otmp->otyp == CORPSE && otmp->corpsenm >= SPECIAL_PM))) { free_oname(otmp); } Also, the bitfield per-byte groupings identified in the struct weren't accurately reflected, so rearrange the Bitfields, and correct the per-byte groupings. This invalidates existing save files and bones. --- include/obj.h | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/include/obj.h b/include/obj.h index 7d716c518..f841725ef 100644 --- a/include/obj.h +++ b/include/obj.h @@ -87,6 +87,7 @@ struct obj { #define NOBJ_STATES 10 xint16 timed; /* # of fuses (timers) attached to this obj */ + /* Bitfields currently require 5 bytes minimum */ Bitfield(cursed, 1); /* uncursed when neither cursed nor blessed */ Bitfield(blessed, 1); Bitfield(unpaid, 1); /* owned by shop; valid for objects in hero's @@ -98,6 +99,10 @@ struct obj { * items on shop floor or in containers there; * implicit for items at any other location * unless carried and explicitly flagged unpaid */ + Bitfield(recharged, 3); /* number of times it's been recharged */ +#define on_ice recharged /* corpse on ice */ + Bitfield(lamplit, 1); /* a light-source -- can be lit */ + Bitfield(known, 1); /* exact nature known (for instance, charge count * or enchantment); many items have this preset if * they lack anything interesting to discover */ @@ -105,6 +110,14 @@ struct obj { * some types of items always have dknown set */ Bitfield(bknown, 1); /* BUC (blessed/uncursed/cursed) known */ Bitfield(rknown, 1); /* rustproofing status known */ + Bitfield(cknown, 1); /* for containers (including statues): the contents + * are known; also applicable to tins; also applies + * to horn of plenty but only for empty/non-empty */ + Bitfield(lknown, 1); /* locked/unlocked status is known; assigned for bags + * and for horn of plenty (when tipping) even though + * they have no locks */ + Bitfield(tknown, 1); /* trap status known for chests */ + Bitfield(nomerge, 1); /* set temporarily to prevent merging */ Bitfield(oeroded, 2); /* rusted/burnt weapon/armor */ Bitfield(oeroded2, 2); /* corroded/rotted weapon/armor */ @@ -123,33 +136,23 @@ struct obj { /* or accidental tripped rolling boulder trap */ #define opoisoned otrapped /* object (weapon) is coated with poison */ - Bitfield(recharged, 3); /* number of times it's been recharged */ -#define on_ice recharged /* corpse on ice */ - Bitfield(lamplit, 1); /* a light-source -- can be lit */ Bitfield(globby, 1); /* combines with like types on adjacent squares */ Bitfield(greased, 1); /* covered with grease */ - Bitfield(nomerge, 1); /* set temporarily to prevent merging */ - Bitfield(how_lost, 2); /* stolen by mon or thrown, dropped by hero */ - Bitfield(in_use, 1); /* for magic items before useup items */ Bitfield(bypass, 1); /* mark this as an object to be skipped by bhito() */ - Bitfield(cknown, 1); /* for containers (including statues): the contents - * are known; also applicable to tins; also applies - * to horn of plenty but only for empty/non-empty */ - Bitfield(lknown, 1); /* locked/unlocked status is known; assigned for bags - * and for horn of plenty (when tipping) even though - * they have no locks */ Bitfield(pickup_prev, 1); /* was picked up previously */ Bitfield(ghostly, 1); /* it just got placed into a bones file */ - Bitfield(tknown, 1); /* trap status known for chests */ + Bitfield(how_lost, 2); /* stolen by mon or thrown, dropped by hero */ + + Bitfield(named_how, 1); /* source of name per TODO in resetobjs() */ #if 0 /* not implemented */ Bitfield(eknown, 1); /* effect known for wands zapped or rings worn when * not seen yet after being picked up while blind * [maybe for remaining stack of used potion too] */ - /* 7 free bits */ + /* 6 free bits */ #else - /* 1 free bit */ + /* 7 free bits */ #endif int corpsenm; /* type of corpse is mons[corpsenm] */ @@ -465,12 +468,16 @@ struct obj { #define POTHIT_MONST_THROW 2 /* thrown by a monster */ #define POTHIT_OTHER_THROW 3 /* propelled by some other means [scatter()] */ -/* tracking how an item left your inventory */ +/* tracking how an item left your inventory via how_lost field */ #define LOST_NONE 0 /* still in inventory, or method not covered below */ #define LOST_THROWN 1 /* thrown or fired by the hero */ #define LOST_DROPPED 2 /* dropped or tipped out of a container by the hero */ #define LOST_STOLEN 3 /* stolen from hero's inventory by a monster */ +/* tracking how a name got acquired by an object in named_how field */ +#define NAMED_PLAIN 0 /* nothing special, typical naming */ +#define NAMED_KEEP 1 /* historic statue, or stoned/killed monster */ + /* * Notes for adding new oextra structures: * From 21d35e768c2bbc9126c931331b30088f4a4d7192 Mon Sep 17 00:00:00 2001 From: nhmall Date: Thu, 19 Dec 2024 17:54:55 -0500 Subject: [PATCH 214/791] bump EDITLEVEL for previous two commits DEC19-2024 --- include/patchlevel.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/patchlevel.h b/include/patchlevel.h index 2f32a4b86..4bfe37f3d 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 113 +#define EDITLEVEL 114 /* * Development status possibilities. From 8a7f3b2b6bde8d73dc8da942778e45e60d06c5ea Mon Sep 17 00:00:00 2001 From: PatR Date: Thu, 19 Dec 2024 18:18:11 -0800 Subject: [PATCH 215/791] more issue #1303 Various bits I had in progress before Michael's commit. Mainly forget engravings when bones are saved instead of leaving them flagged as seen for the next hero who gets the level. --- include/engrave.h | 3 +-- include/extern.h | 1 + src/bones.c | 1 + src/detect.c | 2 +- src/display.c | 13 +++++++------ src/engrave.c | 34 ++++++++++++++++++++++++++-------- 6 files changed, 37 insertions(+), 17 deletions(-) diff --git a/include/engrave.h b/include/engrave.h index 00fd586e1..47fd84783 100644 --- a/include/engrave.h +++ b/include/engrave.h @@ -47,8 +47,7 @@ struct engr { #define spot_shows_engravings(x,y) \ (levl[(x)][(y)].typ == CORR \ - || levl[(x)][(y)].typ == SCORR \ || levl[(x)][(y)].typ == ICE \ - || levl[(x)][(y)].typ == ROOM ) + || levl[(x)][(y)].typ == ROOM) #endif /* ENGRAVE_H */ diff --git a/include/extern.h b/include/extern.h index 932e95514..2b8bba295 100644 --- a/include/extern.h +++ b/include/extern.h @@ -959,6 +959,7 @@ extern void del_engr_at(coordxy, coordxy); extern int freehand(void); extern int doengrave(void); extern void sanitize_engravings(void); +extern void forget_engravings(void); extern void engraving_sanity_check(void); extern void save_engravings(NHFILE *) NONNULLARG1; extern void rest_engravings(NHFILE *) NONNULLARG1; diff --git a/src/bones.c b/src/bones.c index 98fb9fd97..3ecd93125 100644 --- a/src/bones.c +++ b/src/bones.c @@ -445,6 +445,7 @@ savebones(int how, time_t when, struct obj *corpse) iter_mons(remove_mon_from_bones); /* send various unique monsters away, */ dmonsfree(); /* then discard dead or gone monsters */ + forget_engravings(); /* next hero won't have read any engravings yet */ /* mark all named fruits as nonexistent; if/when we come to instances of any of them we'll mark those as existing (using goodfruit()) */ for (f = gf.ffruit; f; f = f->nextf) diff --git a/src/detect.c b/src/detect.c index 172f4704c..ccede5c5d 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1404,7 +1404,7 @@ show_map_spot(coordxy x, coordxy y, boolean cnf) if (!IS_FURNITURE(lev->typ)) { if ((t = t_at(x, y)) != 0 && t->tseen) { map_trap(t, 1); - } else if ((ep = engr_at(x, y)) != 0) { + } else if ((ep = engr_at(x, y)) != 0 && !cnf) { map_engraving(ep, 1); } else if (glyph_is_trap(oldglyph) || glyph_is_object(oldglyph)) { show_glyph(x, y, oldglyph); diff --git a/src/display.c b/src/display.c index f47e63062..71c77bb87 100644 --- a/src/display.c +++ b/src/display.c @@ -420,8 +420,9 @@ unmap_object(coordxy x, coordxy y) struct rm *lev = &levl[x][y]; if (spot_shows_engravings(x, y) - && (ep = engr_at(x, y)) != 0 && !covers_traps(x, y)) { - ep->erevealed = 0; + && (ep = engr_at(x, y)) != 0 && !covers_traps(x, y)) { + if (cansee(x, y)) + ep->erevealed = 1; map_engraving(ep, 0); } else { map_background(x, y, 0); @@ -458,7 +459,7 @@ unmap_object(coordxy x, coordxy y) map_trap(trap, show); \ } else if (spot_shows_engravings(x, y) \ && (ml_ep = engr_at(x, y)) != 0 \ - && ml_ep->erevealed != 0 \ + && ml_ep->erevealed \ && !covers_traps(x, y)) { \ map_engraving(ml_ep, show); \ } else { \ @@ -857,7 +858,7 @@ feel_location(coordxy x, coordxy y) show_glyph(x, y, lev->glyph = cmap_to_glyph(S_darkroom)); } } else { - if ((ep = engr_at(x, y)) && !ep->erevealed && engr_can_be_felt(ep)) + if ((ep = engr_at(x, y)) != 0 && engr_can_be_felt(ep)) ep->erevealed = 1; _map_location(x, y, 1); @@ -959,6 +960,8 @@ newsym(coordxy x, coordxy y) mon = m_at(x, y); worm_tail = is_worm_tail(mon); + if ((ep = engr_at(x, y)) != 0) + ep->erevealed = 1; /* even when covered by objects or a monster */ /* * Normal region shown only on accessible positions, but * poison clouds and steam clouds also shown above lava, @@ -1020,8 +1023,6 @@ newsym(coordxy x, coordxy y) } else if (glyph_is_invisible(lev->glyph)) { map_invisible(x, y); } else { - if ((ep = engr_at(x, y)) && !ep->erevealed) - ep->erevealed = 1; _map_location(x, y, 1); /* map the location */ } } diff --git a/src/engrave.c b/src/engrave.c index 07f30bea5..a11d8bc4c 100644 --- a/src/engrave.c +++ b/src/engrave.c @@ -317,7 +317,7 @@ read_engr_at(coordxy x, coordxy y) const char *eloc = surface(x, y); int sensed = 0; - /* Sensing an engraving does not require sight, + /* Sensing an engraving does not require sight for some engraving types, * nor does it necessarily imply comprehension (literacy). */ if (ep && ep->engr_txt[actual_text][0]) { @@ -1467,6 +1467,22 @@ sanitize_engravings(void) } } +/* mark all engravings as not-discovered/not-read when saving bones */ +void +forget_engravings(void) +{ + struct engr *ep; + + for (ep = head_engr; ep; ep = ep->nxt_engr) { + ep->erevealed = ep->eread = 0; + + /* Note: engr_txt[actual_text], engr_txt[rememberd_text], and + * engr_txt[pristine_text] retain their original text rather + * than get updated to reflect each engraving's current text. + * Does it matter? */ + } +} + void engraving_sanity_check(void) { @@ -1665,16 +1681,18 @@ see_engraving(struct engr *ep) newsym(ep->engr_x, ep->engr_y); } -/* like see_engravings() but overrides vision, but - only for some types of engravings that can be felt */ +/* like see_engravings() but overrides vision, but only for some types + of engravings that can be felt [this isn't actually used anywhere?] */ void feel_engraving(struct engr *ep) { - ep->eread = 1; - ep->erevealed = 1; - map_engraving(ep, 1); - /* in case it's beneath something, redisplay the something */ - newsym(ep->engr_x, ep->engr_y); + if (engr_can_be_felt(ep)) { + ep->eread = 1; + ep->erevealed = 1; + map_engraving(ep, 1); + /* in case it's beneath something, redisplay the something */ + newsym(ep->engr_x, ep->engr_y); + } } static const char blind_writing[][21] = { From 837da48621b30ce80e195c253a1e35c2aa774e0d Mon Sep 17 00:00:00 2001 From: PatR Date: Thu, 19 Dec 2024 19:59:13 -0800 Subject: [PATCH 216/791] fix issue #1340 - winter wolf, hellhound alignment Issue reported by k21971: winter wolf cub and hellhound pup were defined with alignment -5 (chaotic) while winter wolf and hellhound were 0 (neutral). K2 suggested that winter wolf plus cub both be neutral and hellhound plus pup both be chaotic but I've gone another way: both cub and pup are now 0 and both adults are -5. Fixes #1340 --- include/monsters.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/include/monsters.h b/include/monsters.h index e1987f8db..14278e339 100644 --- a/include/monsters.h +++ b/include/monsters.h @@ -215,8 +215,8 @@ SIZ(300, 250, MS_BARK, MZ_SMALL), 0, 0, M1_ANIMAL | M1_NOHANDS | M1_CARNIVORE, M2_HOSTILE, M3_INFRAVISIBLE, 2, CLR_BROWN, COYOTE), - MON(NAM("werejackal"), - S_DOG, LVL(2, 12, 7, 10, -7), (G_NOGEN | G_NOCORPSE), + MON(NAM("werejackal"), S_DOG, + LVL(2, 12, 7, 10, -7), (G_NOGEN | G_NOCORPSE), A(ATTK(AT_BITE, AD_WERE, 1, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(300, 250, MS_BARK, MZ_SMALL), MR_POISON, 0, @@ -271,7 +271,7 @@ M2_NOPOLY | M2_WERE | M2_HOSTILE, M3_INFRAVISIBLE, 7, CLR_GRAY, WEREWOLF), MON(NAM("winter wolf cub"), S_DOG, - LVL(5, 12, 4, 0, -5), + LVL(5, 12, 4, 0, 0), (G_NOHELL | G_GENO | G_SGROUP | 2), A(ATTK(AT_BITE, AD_PHYS, 1, 8), ATTK(AT_BREA, AD_COLD, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), @@ -286,21 +286,21 @@ M1_ANIMAL | M1_NOHANDS | M1_CARNIVORE, M2_HOSTILE, M3_INFRAVISIBLE, 8, CLR_BLACK, WARG), MON(NAM("winter wolf"), S_DOG, - LVL(7, 12, 4, 20, 0), (G_NOHELL | G_GENO | 1), + LVL(7, 12, 4, 20, -5), (G_NOHELL | G_GENO | 1), A(ATTK(AT_BITE, AD_PHYS, 2, 6), ATTK(AT_BREA, AD_COLD, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(700, 300, MS_BARK, MZ_LARGE), MR_COLD, MR_COLD, M1_ANIMAL | M1_NOHANDS | M1_CARNIVORE, M2_HOSTILE | M2_STRONG, 0, 9, CLR_CYAN, WINTER_WOLF), MON(NAM("hell hound pup"), S_DOG, - LVL(7, 12, 4, 20, -5), (G_HELL | G_GENO | G_SGROUP | 1), + LVL(7, 12, 4, 20, 0), (G_HELL | G_GENO | G_SGROUP | 1), A(ATTK(AT_BITE, AD_PHYS, 2, 6), ATTK(AT_BREA, AD_FIRE, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(200, 200, MS_BARK, MZ_SMALL), MR_FIRE, MR_FIRE, M1_ANIMAL | M1_NOHANDS | M1_CARNIVORE, M2_HOSTILE, M3_INFRAVISIBLE, 9, CLR_RED, HELL_HOUND_PUP), MON(NAM("hell hound"), S_DOG, - LVL(12, 14, 2, 20, 0), (G_HELL | G_GENO | 1), + LVL(12, 14, 2, 20, -5), (G_HELL | G_GENO | 1), A(ATTK(AT_BITE, AD_PHYS, 3, 6), ATTK(AT_BREA, AD_FIRE, 3, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(600, 300, MS_BARK, MZ_MEDIUM), MR_FIRE, MR_FIRE, From 45b2a6c49ac240f06aab363c8169174b23e499cd Mon Sep 17 00:00:00 2001 From: nhmall Date: Fri, 20 Dec 2024 10:32:38 -0500 Subject: [PATCH 217/791] more C standard progress There was a transcription error in the comments in cstd.h for the standard list of header files, where only the description remained for , not the name of the file itself. Remove several extraneous inclusions of the standard C99 headers. Tested on the following afterwards: Linux (using hints/linux.370) including tty, curses, qt6, and X11 macOS (using hints/macOS.370) including tty, curses, qt5, and X11 Windows MSYS2 using sys/windows/GNUmakefile Windows Visual Studio using sys/windows/Makefile.nmake msdos cross-compile on Ubuntu using djgpp cross-compiler --- include/cstd.h | 12 ++++++++---- include/global.h | 2 -- include/pcconf.h | 16 ---------------- include/unixconf.h | 5 ----- include/vmsconf.h | 3 --- include/windconf.h | 6 ------ src/allmain.c | 1 - src/attrib.c | 1 - src/coloratt.c | 1 - src/end.c | 1 - src/files.c | 2 -- src/makemon.c | 2 -- src/mon.c | 1 - src/report.c | 1 - src/utf8map.c | 1 - sys/libnh/libnhmain.c | 1 - sys/msdos/Makefile.GCC | 11 ++--------- sys/msdos/msdos.c | 1 - sys/msdos/tile2bin.c | 4 ---- sys/msdos/video.c | 1 - sys/msdos/vidtxt.c | 1 - sys/msdos/vidvga.c | 1 - sys/share/pcmain.c | 2 -- sys/share/pcsys.c | 1 - sys/unix/hints/include/cross-post.370 | 10 ++++++++-- sys/unix/hints/include/cross-pre2.370 | 2 ++ sys/unix/unixmain.c | 1 - sys/vms/vmsfiles.c | 1 - sys/vms/vmsmail.c | 1 - sys/vms/vmsunix.c | 1 - sys/windows/GNUmakefile | 2 ++ sys/windows/win32api.h | 3 ++- sys/windows/windmain.c | 2 -- sys/windows/windsys.c | 1 - win/X11/winval.c | 2 +- win/chain/wc_trace.c | 1 - win/curses/cursdial.c | 1 - win/curses/cursinit.c | 2 -- win/curses/cursmesg.c | 1 - win/curses/cursmisc.c | 2 -- 40 files changed, 25 insertions(+), 86 deletions(-) diff --git a/include/cstd.h b/include/cstd.h index 64028749f..3e4764b52 100644 --- a/include/cstd.h +++ b/include/cstd.h @@ -27,9 +27,9 @@ * Common macro definitions * (C99) Fixed-width integer types * Input/output program utilities - * - * General utilities: memory management, program utilities, string - * conversions, random numbers, algorithms + * General utilities: memory management, + * program utilities, string conversions, + * random numbers, algorithms * String handling * (C99) Type-generic math (macros wrapping math.h and * complex.h) @@ -51,13 +51,17 @@ * */ #if !defined(__cplusplus) - #include +#include #include #include #include #include #include +#include +#else /* !__cplusplus */ +/* for FILE */ +#include #endif /* !__cplusplus */ #endif /* CSTD_H */ diff --git a/include/global.h b/include/global.h index 7a32d105f..197a92da1 100644 --- a/include/global.h +++ b/include/global.h @@ -6,8 +6,6 @@ #ifndef GLOBAL_H #define GLOBAL_H -#include - /* * Files expected to exist in the playground directory (possibly inside * a dlb container file). diff --git a/include/pcconf.h b/include/pcconf.h index 5f8de8fb5..6736d8d9d 100644 --- a/include/pcconf.h +++ b/include/pcconf.h @@ -111,33 +111,21 @@ #if defined(_MSC_VER) && (_MSC_VER >= 7) #include -#include #ifdef strcmpi #undef strcmpi #endif -#include /* Provides prototypes of strncmpi(), etc. */ #include #include #include #define SIG_RET_TYPE void(__cdecl *)(int) -#define M(c) ((char) (0x80 | (c))) #define vprintf printf #define vfprintf fprintf #define vsprintf sprintf #endif -#if defined(__BORLANDC__) && defined(STRNCMPI) -#include /* Provides prototypes of strncmpi(), etc. */ -#endif - -#if defined(__DJGPP__) -#define _NAIVE_DOS_REGS -#include -#include /* Provides prototypes of strncmpi(), etc. */ #ifndef M #define M(c) ((char) (0x80 | (c))) #endif -#endif /* * On the VMS and unix, this option controls whether a delay is done by @@ -226,10 +214,6 @@ #define HLOCK "NHPERM" #endif -#ifndef AMIGA -#include -#endif - /* the high quality random number routines */ #ifndef USE_ISAAC64 # ifdef RANDOM diff --git a/include/unixconf.h b/include/unixconf.h index e27f542d2..1e346d3d5 100644 --- a/include/unixconf.h +++ b/include/unixconf.h @@ -302,8 +302,6 @@ #if defined(BSD) || defined(ULTRIX) #include -#else -#include #endif /* these might be needed for include/system.h; @@ -324,10 +322,7 @@ #define SHELL /* do not delete the '!' command */ #endif -/* #include "system.h" */ - #if defined(POSIX_TYPES) || defined(__GNUC__) -#include #include #endif diff --git a/include/vmsconf.h b/include/vmsconf.h index 7eac14895..57b8a7b05 100644 --- a/include/vmsconf.h +++ b/include/vmsconf.h @@ -213,7 +213,6 @@ PANICTRACE_GDB=2 #at conclusion of panic, show a call traceback and then #include #include #include -#include #include #include #include @@ -246,8 +245,6 @@ typedef int32_t off_t; #endif #endif /* _DECC_V4_SOURCE */ -#include - #ifndef VMSVSI #if 0 /* is missing for old gcc versions; skip it to save time */ #include diff --git a/include/windconf.h b/include/windconf.h index 63c58cdbc..55b68dfa5 100644 --- a/include/windconf.h +++ b/include/windconf.h @@ -165,8 +165,6 @@ typedef SSIZE_T ssize_t; #include -#include -#include #ifdef __BORLANDC__ #undef randomize #undef random @@ -185,10 +183,6 @@ typedef SSIZE_T ssize_t; #endif #define NO_SIGNAL - -/* Time stuff */ -#include - #define USE_STDARG /* Use the high quality random number routines. */ diff --git a/src/allmain.c b/src/allmain.c index 852904683..18e163b5a 100644 --- a/src/allmain.c +++ b/src/allmain.c @@ -6,7 +6,6 @@ /* various code that was replicated in *main.c */ #include "hack.h" -#include #ifndef NO_SIGNAL #include diff --git a/src/attrib.c b/src/attrib.c index 36dd9ea91..079607c1b 100644 --- a/src/attrib.c +++ b/src/attrib.c @@ -5,7 +5,6 @@ /* attribute modification routines. */ #include "hack.h" -#include /* part of the output on gain or loss of attribute */ static const char diff --git a/src/coloratt.c b/src/coloratt.c index 8e68a469d..e2053e238 100644 --- a/src/coloratt.c +++ b/src/coloratt.c @@ -3,7 +3,6 @@ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" -#include struct color_names { const char *name; diff --git a/src/end.c b/src/end.c index ace45f699..1bacb7547 100644 --- a/src/end.c +++ b/src/end.c @@ -9,7 +9,6 @@ #ifndef NO_SIGNAL #include #endif -#include #ifndef LONG_MAX #include #endif diff --git a/src/files.c b/src/files.c index b214c7a55..d7ce06f60 100644 --- a/src/files.c +++ b/src/files.c @@ -7,7 +7,6 @@ #include "hack.h" #include "dlb.h" -#include #ifdef TTY_GRAPHICS #include "wintty.h" /* more() */ @@ -45,7 +44,6 @@ const #if defined(UNIX) && defined(SELECTSAVED) #include #include -#include #endif #if defined(UNIX) || defined(VMS) || !defined(NO_SIGNAL) diff --git a/src/makemon.c b/src/makemon.c index e8c6bf298..9ff2c2da5 100644 --- a/src/makemon.c +++ b/src/makemon.c @@ -5,8 +5,6 @@ #include "hack.h" -#include - /* this assumes that a human quest leader or nemesis is an archetype of the corresponding role; that isn't so for some roles (tourist for instance) but is for the priests and monks we use it for... */ diff --git a/src/mon.c b/src/mon.c index 7a381420b..cda5f4b65 100644 --- a/src/mon.c +++ b/src/mon.c @@ -5,7 +5,6 @@ #include "hack.h" #include "mfndpos.h" -#include staticfn void sanity_check_single_mon(struct monst *, boolean, const char *); staticfn struct obj *make_corpse(struct monst *, unsigned); diff --git a/src/report.c b/src/report.c index 5be3e93dd..6e82c66c3 100644 --- a/src/report.c +++ b/src/report.c @@ -9,7 +9,6 @@ # ifndef NO_SIGNAL #include # endif -#include # ifndef LONG_MAX #include # endif diff --git a/src/utf8map.c b/src/utf8map.c index f39ce26a1..87688b9ce 100644 --- a/src/utf8map.c +++ b/src/utf8map.c @@ -3,7 +3,6 @@ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" -#include #ifdef ENHANCED_SYMBOLS diff --git a/sys/libnh/libnhmain.c b/sys/libnh/libnhmain.c index 56ee3cb58..20835dda6 100644 --- a/sys/libnh/libnhmain.c +++ b/sys/libnh/libnhmain.c @@ -8,7 +8,6 @@ #include "hack.h" #include "dlb.h" -#include #include #include #include diff --git a/sys/msdos/Makefile.GCC b/sys/msdos/Makefile.GCC index 6b4a7cc6f..9ed3b27a2 100644 --- a/sys/msdos/Makefile.GCC +++ b/sys/msdos/Makefile.GCC @@ -458,18 +458,11 @@ endif INCLDIR=$(PDCINCL) -I../include -I../sys/msdos $(LUAINCL) # Debugging -#cflags = -pg -c $(INCLDIR) $(DLBFLG) $(CURSESDEF) -DSUPPRESS_GRAPHICS +#cflags = -pg -c -D_NAIVE_DOS_REGS $(INCLDIR) $(DLBFLG) $(CURSESDEF) -DSUPPRESS_GRAPHICS #LFLAGS = -pg -cflags = -c -O $(INCLDIR) $(DLBFLG) $(CURSESDEF) -DSUPPRESS_GRAPHICS -LFLAGS = - -# Debugging -#cflags = -g -c $(INCLDIR) $(DLBFLG) $(CURSESDEF) -DTILES_IN_GLYPHMAP -#LFLAGS = -g - # Normal -cflags = -c -O $(INCLDIR) $(DLBFLG) $(CURSESDEF) -DTILES_IN_GLYPHMAP +cflags = -c -O -D_NAIVE_DOS_REGS $(INCLDIR) $(DLBFLG) $(CURSESDEF) -DTILES_IN_GLYPHMAP LFLAGS = #========================================== diff --git a/sys/msdos/msdos.c b/sys/msdos/msdos.c index 735e84dd9..8a059008d 100644 --- a/sys/msdos/msdos.c +++ b/sys/msdos/msdos.c @@ -15,7 +15,6 @@ #include "pcvideo.h" #include -#include /* * MS-DOS functions diff --git a/sys/msdos/tile2bin.c b/sys/msdos/tile2bin.c index 1fa622d11..0e90935fc 100644 --- a/sys/msdos/tile2bin.c +++ b/sys/msdos/tile2bin.c @@ -18,10 +18,6 @@ #include "pctiles.h" /* #include */ -#ifndef MONITOR_HEAP -#include -#endif -#include #ifdef __GO32__ #include diff --git a/sys/msdos/video.c b/sys/msdos/video.c index ae03e2541..a849027eb 100644 --- a/sys/msdos/video.c +++ b/sys/msdos/video.c @@ -105,7 +105,6 @@ void g_pututf8(uint8 *utf8str) #ifdef NO_TERMS -#include #include "wintty.h" #ifdef __GO32__ diff --git a/sys/msdos/vidtxt.c b/sys/msdos/vidtxt.c index b89d3616c..35b314b26 100644 --- a/sys/msdos/vidtxt.c +++ b/sys/msdos/vidtxt.c @@ -18,7 +18,6 @@ #include "wintty.h" #include -#include #if defined(_MSC_VER) #if _MSC_VER >= 700 diff --git a/sys/msdos/vidvga.c b/sys/msdos/vidvga.c index f2473cfc5..506068ac9 100644 --- a/sys/msdos/vidvga.c +++ b/sys/msdos/vidvga.c @@ -14,7 +14,6 @@ #include "font.h" #include -#include #include "wintty.h" #ifdef __GO32__ diff --git a/sys/share/pcmain.c b/sys/share/pcmain.c index 3e0a4c355..0bb30b488 100644 --- a/sys/share/pcmain.c +++ b/sys/share/pcmain.c @@ -12,8 +12,6 @@ #include #endif -#include - #if !defined(AMIGA) && !defined(__DJGPP__) #include #else diff --git a/sys/share/pcsys.c b/sys/share/pcsys.c index 20b68c3e3..ed779a284 100644 --- a/sys/share/pcsys.c +++ b/sys/share/pcsys.c @@ -10,7 +10,6 @@ #include "hack.h" #include "wintty.h" -#include #include #if !defined(MSDOS) && !defined(WIN_CE) && !defined(CROSS_TO_AMIGA) #include diff --git a/sys/unix/hints/include/cross-post.370 b/sys/unix/hints/include/cross-post.370 index c6f40e52d..5c4c9ba08 100644 --- a/sys/unix/hints/include/cross-post.370 +++ b/sys/unix/hints/include/cross-post.370 @@ -79,8 +79,14 @@ ifeq "$(WANT_DEBUG)" "1" pwd; echo "$(GDBEXE) not found and WANT_DEBUG=1 specified"; \ fi; ) else - -rm $(TARGETPFX)pkg/GDB.EXE - -rm $(TARGETPFX)pkg/NHGDB.BAT + -( if [ -f $(TARGETPFX)pkg/GDB.EXE ]; \ + then \ + rm $(TARGETPFX)pkg/GDB.EXE; \ + fi; ) + -( if [ -f $(TARGETPFX)pkg/NHGDB.BAT ]; \ + then \ + rm $(TARGETPFX)pkg/NHGDB.BAT; \ + fi; ) endif -touch $(TARGETPFX)pkg/RECORD cd $(TARGETPFX)pkg ; zip -9 ../NH370DOS.ZIP * ; cd ../../.. diff --git a/sys/unix/hints/include/cross-pre2.370 b/sys/unix/hints/include/cross-pre2.370 index 15fbe719c..e1ade8fb3 100644 --- a/sys/unix/hints/include/cross-pre2.370 +++ b/sys/unix/hints/include/cross-pre2.370 @@ -177,10 +177,12 @@ MSDOS_GPP_CFLAGS = -Wall -Wextra -Wno-missing-field-initializers -Wreturn-type \ MSDOS_TARGET_CFLAGS = -c -O $(DBGFLAGS) -I../include -I../sys/msdos -I../win/share \ $(LUAINCL) -DDLB $(PDCURSESDEF) -DTILES_IN_GLYPHMAP \ -DCROSSCOMPILE -DCROSSCOMPILE_TARGET -DCROSS_TO_MSDOS \ + -D_NAIVE_DOS_REGS \ $(MSDOS_GCC_CFLAGS) MSDOS_TARGET_CXXFLAGS = -c -O $(DBGFLAGS) -I../include -I../sys/msdos -I../win/share \ $(LUAINCL) -DDLB $(PDCURSESDEF) \ -DUSE_TILES -DCROSSCOMPILE -DCROSSCOMPILE_TARGET -DCROSS_TO_MSDOS \ + -D_NAIVE_DOS_REGS \ $(MSDOS_GPP_CFLAGS) PDCINCL += -I$(PDCPORT) PDC_TARGET_CFLAGS = $(MSDOS_TARGET_CFLAGS) -Wno-unused-parameter \ diff --git a/sys/unix/unixmain.c b/sys/unix/unixmain.c index 2da734fd0..e6b09492c 100644 --- a/sys/unix/unixmain.c +++ b/sys/unix/unixmain.c @@ -8,7 +8,6 @@ #include "hack.h" #include "dlb.h" -#include #include #include #include diff --git a/sys/vms/vmsfiles.c b/sys/vms/vmsfiles.c index 885b4c5f1..38a80b9a8 100644 --- a/sys/vms/vmsfiles.c +++ b/sys/vms/vmsfiles.c @@ -8,7 +8,6 @@ * routines or substitute for ones where we want behavior modification. */ #include "config.h" -#include #ifdef VMSVSI #include diff --git a/sys/vms/vmsmail.c b/sys/vms/vmsmail.c index d29fdb888..24f9ad5fa 100644 --- a/sys/vms/vmsmail.c +++ b/sys/vms/vmsmail.c @@ -20,7 +20,6 @@ struct mail_info *parse_next_broadcast(void); #ifdef MAIL #include "wintype.h" #include "winprocs.h" -#include #include #include #ifndef __GNUC__ diff --git a/sys/vms/vmsunix.c b/sys/vms/vmsunix.c index 090ce9e64..89b18a174 100644 --- a/sys/vms/vmsunix.c +++ b/sys/vms/vmsunix.c @@ -29,7 +29,6 @@ #include #undef umask #endif -#include extern int debuggable; /* defined in vmsmisc.c */ diff --git a/sys/windows/GNUmakefile b/sys/windows/GNUmakefile index f38aaf4f6..4e6ee45e5 100644 --- a/sys/windows/GNUmakefile +++ b/sys/windows/GNUmakefile @@ -97,6 +97,8 @@ GCC_EXTRA_WARNINGS = N # #============================================================================== +$(info Using $(lastword $(MAKEFILE_LIST))) + SKIP_NETHACKW = N USE_LUADLL = Y WANT_LUAC = N diff --git a/sys/windows/win32api.h b/sys/windows/win32api.h index d37daf7f3..1089f8b45 100644 --- a/sys/windows/win32api.h +++ b/sys/windows/win32api.h @@ -30,6 +30,8 @@ #error win32api.h should be included first #endif +#include "config.h" + #if defined(_MSC_VER) #pragma warning(disable : 4142) /* Warning, Benign redefinition of type */ #pragma pack(8) @@ -37,7 +39,6 @@ #ifdef DEBUG #define _CRTDBG_MAP_ALLOC -#include #include #endif diff --git a/sys/windows/windmain.c b/sys/windows/windmain.c index cd1bdf9bd..df7144a20 100644 --- a/sys/windows/windmain.c +++ b/sys/windows/windmain.c @@ -10,8 +10,6 @@ #ifdef DLB #include "dlb.h" #endif -#include -#include #include #include #include diff --git a/sys/windows/windsys.c b/sys/windows/windsys.c index 93d7f5f58..05b073a45 100644 --- a/sys/windows/windsys.c +++ b/sys/windows/windsys.c @@ -20,7 +20,6 @@ #ifndef __BORLANDC__ #include #endif -#include #ifdef TTY_GRAPHICS #include "wintty.h" #endif diff --git a/win/X11/winval.c b/win/X11/winval.c index c333a5483..651ba2cbb 100644 --- a/win/X11/winval.c +++ b/win/X11/winval.c @@ -6,7 +6,7 @@ * Routines that define a name-value label widget pair that fit inside a * form widget. */ -#include +/* #include */ #ifndef SYSV #define PRESERVE_NO_SYSV /* X11 include files may define SYSV */ diff --git a/win/chain/wc_trace.c b/win/chain/wc_trace.c index 6738d0b0b..2048a05c4 100644 --- a/win/chain/wc_trace.c +++ b/win/chain/wc_trace.c @@ -6,7 +6,6 @@ #include "wintty.h" #include "func_tab.h" -#include #include #ifdef WIN32 diff --git a/win/curses/cursdial.c b/win/curses/cursdial.c index a0e93d093..dddfd400e 100644 --- a/win/curses/cursdial.c +++ b/win/curses/cursdial.c @@ -11,7 +11,6 @@ #include "cursmisc.h" #include "cursdial.h" #include "func_tab.h" -#include #if defined(FILENAME_CMP) && !defined(strcasecmp) #define strcasecmp FILENAME_CMP diff --git a/win/curses/cursinit.c b/win/curses/cursinit.c index fcf13ec19..529b46182 100644 --- a/win/curses/cursinit.c +++ b/win/curses/cursinit.c @@ -8,8 +8,6 @@ #include "wincurs.h" #include "cursinit.h" -#include - /* Initialization and startup functions for curses interface */ /* Private declarations */ diff --git a/win/curses/cursmesg.c b/win/curses/cursmesg.c index 2709d592a..6a30c159c 100644 --- a/win/curses/cursmesg.c +++ b/win/curses/cursmesg.c @@ -8,7 +8,6 @@ #include "wincurs.h" #include "cursmesg.h" #include "curswins.h" -#include /* defined in sys//tty.c or cursmain.c as last resort; set up by curses_init_nhwindows() */ diff --git a/win/curses/cursmisc.c b/win/curses/cursmisc.c index 71b9f31f6..42dd6250b 100644 --- a/win/curses/cursmisc.c +++ b/win/curses/cursmisc.c @@ -10,8 +10,6 @@ #include "func_tab.h" #include "dlb.h" -#include - /* Misc. curses interface functions */ /* Private declarations */ From cc31017265d49969519c238956f085332f7f42e8 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Fri, 20 Dec 2024 19:39:16 +0200 Subject: [PATCH 218/791] Use NO_MATERIAL instead of a magic number --- include/objclass.h | 1 + src/uhitm.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/include/objclass.h b/include/objclass.h index 7e1af7fab..23c3a86f2 100644 --- a/include/objclass.h +++ b/include/objclass.h @@ -10,6 +10,7 @@ (liquid potion inside glass bottle, metal arrowhead on wooden shaft) and object definitions only specify one type on a best-fit basis */ enum obj_material_types { + NO_MATERIAL = 0, LIQUID = 1, /* currently only for venom */ WAX = 2, VEGGY = 3, /* foodstuffs */ diff --git a/src/uhitm.c b/src/uhitm.c index 64eb46e3e..47a8aef23 100644 --- a/src/uhitm.c +++ b/src/uhitm.c @@ -1732,7 +1732,7 @@ hmon_hitmon( hmd.silverobj = FALSE; hmd.lightobj = FALSE; hmd.material = obj ? objects[obj->otyp].oc_material - : 0; /* 0 == NO_MATERIAL */ + : NO_MATERIAL; hmd.jousting = 0; hmd.hittxt = FALSE; hmd.get_dmg_bonus = TRUE; From a35e5779f686869c6611c70f20f0f2145846dec3 Mon Sep 17 00:00:00 2001 From: nhmall Date: Fri, 20 Dec 2024 13:04:08 -0500 Subject: [PATCH 219/791] heard incantation: don't trump telepathy with 'I' GitHub 1343 report by @ars3niy: "When you are blind and see with telepathy a monster whom you then hear read a scroll, said monster turns into an "I". While it reveals which one exactly read the scroll, it is strange that you can no longer see it with telepathy until it moves to another square." Fixes #1343 --- doc/fixes3-7-0.txt | 2 ++ src/muse.c | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index 47e3c7753..ab2e93f20 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -1493,6 +1493,8 @@ artifact gifts are rebalanced (easier to obtain; higher-value sacrifices are luck gains from sacrificing are limited by the value of the sacrifice failed #untrap could move hero diagonally into or out of an open doorway remember box is trapped after finding the trap +when you hear a monster incant a scroll, ensure that the 'I' invisible + monster indicator doesn't trump telepathy briefly Fixes to 3.7.0-x General Problems Exposed Via git Repository diff --git a/src/muse.c b/src/muse.c index 533f6ec22..f42a98f97 100644 --- a/src/muse.c +++ b/src/muse.c @@ -265,7 +265,8 @@ mreadmsg(struct monst *mtmp, struct obj *otmp) /* monster can't be seen; hero might be blind or monster might be at a spot that isn't in view or might be invisible; remember it if the spot is within line of sight and relatively close */ - if (couldsee(mtmp->mx, mtmp->my) && mdistu(mtmp) <= 10 * 10) + if (!sensemon(mtmp) + && couldsee(mtmp->mx, mtmp->my) && mdistu(mtmp) <= 10 * 10) map_invisible(mtmp->mx, mtmp->my); Snprintf(blindbuf, sizeof blindbuf, "reading %s", onambuf); From f6a5236beb91912aad169d23818c8aa13c848c16 Mon Sep 17 00:00:00 2001 From: nhmall Date: Fri, 20 Dec 2024 15:30:37 -0500 Subject: [PATCH 220/791] follow-up to #1343 fix for telepathic hero telepathic hero can discern which particular monster just read a scroll, even though he cannot see the monster --- doc/fixes3-7-0.txt | 1 + include/extern.h | 1 + src/mon.c | 14 ++++++++++++++ src/muse.c | 18 ++++++++++++------ src/read.c | 12 ++---------- 5 files changed, 30 insertions(+), 16 deletions(-) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index ab2e93f20..a9de275c9 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -2751,6 +2751,7 @@ tourists gain experience by seeing new types of creatures up close, and healers gain experience by healing pets blessed scroll of destroy armor asks which armor to destroy archeologists' fedora is lucky +telepathic hero can discern which particular monster just read a scroll Platform- and/or Interface-Specific New Features diff --git a/include/extern.h b/include/extern.h index 2b8bba295..35bb33138 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1785,6 +1785,7 @@ extern void adj_erinys(unsigned); extern void see_monster_closeup(struct monst *) NONNULLARG1; extern void see_nearby_monsters(void); extern void shieldeff_mon(struct monst *) NONNULLARG1; +extern void flash_mon(struct monst *) NONNULLARG1; /* ### mondata.c ### */ diff --git a/src/mon.c b/src/mon.c index cda5f4b65..93aad677a 100644 --- a/src/mon.c +++ b/src/mon.c @@ -5848,4 +5848,18 @@ shieldeff_mon(struct monst *mtmp) pline_mon(mtmp, "%s resists!", Monnam(mtmp)); } +void +flash_mon(struct monst *mtmp) +{ + coordxy mx = mtmp->mx, my = mtmp->my; + int count = couldsee(mx, my) ? 8 : 4; + char saveviz = gv.viz_array[my][mx]; + + if (!flags.sparkle) + count /= 2; + gv.viz_array[my][mx] |= (IN_SIGHT | COULD_SEE); + flash_glyph_at(mx, my, mon_to_glyph(mtmp, newsym_rn2), count); + gv.viz_array[my][mx] = saveviz; + newsym(mx, my); +} /*mon.c*/ diff --git a/src/muse.c b/src/muse.c index f42a98f97..865ae5d05 100644 --- a/src/muse.c +++ b/src/muse.c @@ -236,7 +236,8 @@ staticfn void mreadmsg(struct monst *mtmp, struct obj *otmp) { char onambuf[BUFSZ]; - boolean vismon = canseemon(mtmp); + boolean vismon = canseemon(mtmp), + tpindicator = (!vismon && sensemon(mtmp)); if (!vismon && Deaf) return; /* no feedback */ @@ -262,12 +263,15 @@ mreadmsg(struct monst *mtmp, struct obj *otmp) int mflags = (SUPPRESS_INVISIBLE | SUPPRESS_SADDLE | (recognize ? SUPPRESS_IT : AUGMENT_IT)); - /* monster can't be seen; hero might be blind or monster might - be at a spot that isn't in view or might be invisible; remember - it if the spot is within line of sight and relatively close */ - if (!sensemon(mtmp) - && couldsee(mtmp->mx, mtmp->my) && mdistu(mtmp) <= 10 * 10) + if (sensemon(mtmp)) { + tpindicator = TRUE; + } else if (couldsee(mtmp->mx, mtmp->my) && mdistu(mtmp) <= 10 * 10) { + /* monster can't be seen or sensed; hero might be blind or monster + might be at a spot that isn't in view or might be invisible; + remember it if the spot is within line of sight and relatively + close */ map_invisible(mtmp->mx, mtmp->my); + } Snprintf(blindbuf, sizeof blindbuf, "reading %s", onambuf); strsubst(blindbuf, "reading a scroll labeled", @@ -275,6 +279,8 @@ mreadmsg(struct monst *mtmp, struct obj *otmp) You_hear("%s %s.", x_monnam(mtmp, ARTICLE_A, (char *) 0, mflags, FALSE), blindbuf); + if (tpindicator) + flash_mon(mtmp); } if (mtmp->mconf) /* (note: won't get if not seen and hero can't hear) */ pline("Being confused, %s mispronounces the magic words...", diff --git a/src/read.c b/src/read.c index b3c265d38..47c4d2594 100644 --- a/src/read.c +++ b/src/read.c @@ -3248,17 +3248,9 @@ create_particular_creation( /* if asking for 'hidden', show location of every created monster that can't be seen--whether that's due to successfully hiding or vision issues (line-of-sight, invisibility, blindness) */ - if ((d->hidden || d->invisible) && !canspotmon(mtmp)) { - int count = couldsee(mx, my) ? 8 : 4; - char saveviz = gv.viz_array[my][mx]; + if ((d->hidden || d->invisible) && !canspotmon(mtmp)) + flash_mon(mtmp); - if (!flags.sparkle) - count /= 2; - gv.viz_array[my][mx] |= (IN_SIGHT | COULD_SEE); - flash_glyph_at(mx, my, mon_to_glyph(mtmp, newsym_rn2), count); - gv.viz_array[my][mx] = saveviz; - newsym(mx, my); - } madeany = TRUE; /* in case we got a doppelganger instead of what was asked for, make it start out looking like what was asked for */ From 20511564f75dc993cef7cb1c5fba80bebd8e993f Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 21 Dec 2024 00:47:18 -0500 Subject: [PATCH 221/791] utility to help maintain lua files on platform builds Use by: make -f dat/luahelper [target] Target examples: Visual Studio nmake : make -f dat/luahelper devhelp-nmake >file.txt msys2 GNUmakefile : make -f dat/luahelper devhelp-msys >file.txt Xcode project.pbxproj: make -f dat/luahelper devhelp-xcode >file.txt all: generate txt files for all the above --- dat/luahelper | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 dat/luahelper diff --git a/dat/luahelper b/dat/luahelper new file mode 100644 index 000000000..cc209a0ba --- /dev/null +++ b/dat/luahelper @@ -0,0 +1,80 @@ +# NetHack 3.7 luahelper $NHDT-Date: $ $NHDT-Branch: NetHack-3.7 $ +# +# Makefile to assist developers in adding lines to various build +# Makefiles, or project files, as lua files are added or removed. +# NetHack may be freely redistributed. See license for details. +# +# Must be run while your current directory is the top of the +# NetHack source tree. +# +# make -f dat/luahelper [target] +# +# Target examples: +# +# Visual Studio nmake : make -f dat/luahelper devhelp-nmake >file.txt +# +# MSYS2 GNUmakefile : make -f dat/luahelper devhelp-msys >file.txt +# +# Xcode project.pbxproj: make -f dat/luahelper devhelp-xcode >file.txt +# +# + +luanames = asmodeus baalz bigrm-* castle fakewiz? juiblex knox medusa-? \ + minend-? minefill minetn-? oracle orcus sanctum soko?-? tower? \ + valley wizard? nhcore nhlib themerms astral air earth fire water \ + hellfill tut-? ???-goal ???-fil? ???-loca ???-strt \ + dungeon quest + +alllua = $(wildcard $(addsuffix .lua,$(addprefix dat/, $(luanames)))) + +# +# generates lines to insert into +# sys/windows/Makefile.nmake +# +devhelp-nmake: + @echo "$(notdir $(alllua))" | \ + awk '{for (i=1; i<=NF; ++i)printf "%s%s%s%s", \ + i == 1? "ALL_LUA_FILES = " : "", \ + "$$(DAT)\\", \ + $$i, \ + i % 3? " ": ((i == NF)? "\n" : " \\\n\t")} \ + i % 3{print ""}' + @echo "" + +# +# generates lines to insert into +# sys/windows/GNUmakefile +# +devhelp-msys2: + @echo "$(basename $(notdir $(alllua)))" | \ + awk '{for (i=1; i<=NF; ++i)printf "%s%s%s", \ + i == 1? "LUALIST = " : "", \ + $$i, \ + i % 5? " ": ((i == NF)? "\n" : " \\\n\t")} \ + i % 5{print ""}' + @echo "" + +xcodeextra = bogusmon cmdhelp data engrave epitaph help hh \ + history keyhelp opthelp optmenu options oracles \ + rumors tribute wizhelp +# +# generates lines to insert into +# sys/unix/NetHack.xcodeproj/project.pbxproj +# +devhelp-xcode: + @echo "\t\t\tinputPaths = (" + @echo "$(xcodeextra) $(notdir $(alllua))" | \ + awk '{for (i=1; i<=NF; ++i)printf "%s%s%s%s%s", \ + i == 1? "\t" : "", \ + "\t\t\t\042$$(NH_DAT_DIR)/", \ + $$i, \ + "\042", \ + i % 1? " ": ((i == NF)? "\n" : ",\n\t")} \ + i % 1{print ""}' + @echo "\t\t\t);" + +all: + make -f dat/luahelper devhelp-nmake >./luahelp-nmake.txt + make -f dat/luahelper devhelp-msys2 >./luahelp-msys2.txt + make -f dat/luahelper devhelp-xcode >./luahelp-xcode.txt +# end From 7c54d9e651ef108885f11cfc64df92d4f5e3172f Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 21 Dec 2024 01:13:45 -0500 Subject: [PATCH 222/791] add support for vs files.props to dat/luahelper --- dat/luahelper | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/dat/luahelper b/dat/luahelper index cc209a0ba..087d1dae3 100644 --- a/dat/luahelper +++ b/dat/luahelper @@ -13,6 +13,8 @@ # # Visual Studio nmake : make -f dat/luahelper devhelp-nmake >file.txt # +# Visual Studio project: make -f dat/luahelper devhelp-vstudio >file.txt +# # MSYS2 GNUmakefile : make -f dat/luahelper devhelp-msys >file.txt # # Xcode project.pbxproj: make -f dat/luahelper devhelp-xcode >file.txt @@ -72,6 +74,21 @@ devhelp-xcode: i % 1? " ": ((i == NF)? "\n" : ",\n\t")} \ i % 1{print ""}' @echo "\t\t\t);" +# +# generates lines to insert into +# sys/windows/vs/files.props +# +devhelp-vstudio: + @echo " " + @echo "$(notdir $(alllua))" | \ + awk '{for (i=1; i<=NF; ++i)printf "%s%s%s%s%s", \ + i == 1? " " : "", \ + "", \ + i % 1? " ": ((i == NF)? "\n" : "\n ")} \ + i % 1{print ""}' + @echo " " all: make -f dat/luahelper devhelp-nmake >./luahelp-nmake.txt From f490e54d88dd75a4b745fd2f269dbcccc85efcf0 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 21 Dec 2024 01:15:54 -0500 Subject: [PATCH 223/791] update target all in dat/luahelper --- dat/luahelper | 1 + 1 file changed, 1 insertion(+) diff --git a/dat/luahelper b/dat/luahelper index 087d1dae3..a302755f3 100644 --- a/dat/luahelper +++ b/dat/luahelper @@ -94,4 +94,5 @@ all: make -f dat/luahelper devhelp-nmake >./luahelp-nmake.txt make -f dat/luahelper devhelp-msys2 >./luahelp-msys2.txt make -f dat/luahelper devhelp-xcode >./luahelp-xcode.txt + make -f dat/luahelper devhelp-vstudio >./luahelp-vstudio.txt # end From d42c4faea0af3866661cc5f53b456cb152ca5577 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 21 Dec 2024 01:19:34 -0500 Subject: [PATCH 224/791] suppress "Entering directory" messages from the output --- dat/luahelper | 1 + 1 file changed, 1 insertion(+) diff --git a/dat/luahelper b/dat/luahelper index a302755f3..28da91371 100644 --- a/dat/luahelper +++ b/dat/luahelper @@ -20,6 +20,7 @@ # Xcode project.pbxproj: make -f dat/luahelper devhelp-xcode >file.txt # # +MAKEFLAGS += --no-print-directory luanames = asmodeus baalz bigrm-* castle fakewiz? juiblex knox medusa-? \ minend-? minefill minetn-? oracle orcus sanctum soko?-? tower? \ From e7a714849e6f22efee66bf03f9900d1d3e32bf68 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sat, 21 Dec 2024 12:06:20 +0200 Subject: [PATCH 225/791] luahelper doc nit --- dat/luahelper | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dat/luahelper b/dat/luahelper index 28da91371..94774024a 100644 --- a/dat/luahelper +++ b/dat/luahelper @@ -15,7 +15,7 @@ # # Visual Studio project: make -f dat/luahelper devhelp-vstudio >file.txt # -# MSYS2 GNUmakefile : make -f dat/luahelper devhelp-msys >file.txt +# MSYS2 GNUmakefile : make -f dat/luahelper devhelp-msys2 >file.txt # # Xcode project.pbxproj: make -f dat/luahelper devhelp-xcode >file.txt # From f7e86aa150ccbe593043588bc9bdbf381bbebb7c Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sat, 21 Dec 2024 12:11:03 +0200 Subject: [PATCH 226/791] Add a new bigroom variant "two hexagons" --- dat/bigrm-12.lua | 85 ++++++++++++++++++++++ dat/dungeon.lua | 2 +- sys/unix/NetHack.xcodeproj/project.pbxproj | 2 + sys/windows/GNUmakefile | 1 + sys/windows/Makefile.nmake | 1 + sys/windows/vs/files.props | 1 + 6 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 dat/bigrm-12.lua diff --git a/dat/bigrm-12.lua b/dat/bigrm-12.lua new file mode 100644 index 000000000..0e41bd9e4 --- /dev/null +++ b/dat/bigrm-12.lua @@ -0,0 +1,85 @@ +-- NetHack bigroom bigrm-12.lua $NHDT-Date: $ $NHDT-Branch: NetHack-3.7 $ +-- Copyright (c) 2024 by Pasi Kallinen +-- NetHack may be freely redistributed. See license for details. +-- +-- Two hexagons + +des.level_flags("mazelevel", "noflipy"); +des.level_init({ style = "solidfill", fg = " " }); + +des.map([[ + + ....................... ....................... + ......................... ......................... + ........................... ........................... + ............................. ............................. + ........PPPPPPPPPPPPPPP........ ........LLLLLLLLLLLLLLL........ + ........PPPPPPPPPPPPPPPPP........ ........LLLLLLLLLLLLLLLLL........ + ........PPPWWWWWWWWWWWWWPPP...............LLLZZZZZZZZZZZZZLLL........ + ........PPPWWWWWWWWWWWWWWWPPP.............LLLZZZZZZZZZZZZZZZLLL........ + ........PPPWWWWWWWWWWWWWWWWWPPP...........LLLZZZZZZZZZZZZZZZZZLLL........ + ........PPPWWWWWWWWWWWWWWWPPP.............LLLZZZZZZZZZZZZZZZLLL........ + ........PPPWWWWWWWWWWWWWPPP...............LLLZZZZZZZZZZZZZLLL........ + ........PPPPPPPPPPPPPPPPP........ ........LLLLLLLLLLLLLLLLL........ + ........PPPPPPPPPPPPPPP........ ........LLLLLLLLLLLLLLL........ + ............................. ............................. + ........................... ........................... + ......................... ......................... + ....................... ....................... + +]]); + +-- maybe replace lavawalls/waterwalls with stone walls +if percent(20) then + if percent(50) then + des.replace_terrain({ fromterrain = "W", toterrain = "-" }); + end + if percent(50) then + des.replace_terrain({ fromterrain = "Z", toterrain = "-" }); + end +end + +-- maybe replace pools with floor and then possibly walls with pools +if percent(25) then + des.replace_terrain({ fromterrain = "P", toterrain = "." }); + if percent(75) then + des.replace_terrain({ fromterrain = "W", toterrain = "P" }); + end +end +if percent(25) then + des.replace_terrain({ fromterrain = "L", toterrain = "." }); + if percent(75) then + des.replace_terrain({ fromterrain = "Z", toterrain = "L" }); + end +end + +-- maybe make both sides have the same terrain +if percent(20) then + if percent(50) then + -- both are lava + des.replace_terrain({ fromterrain = "P", toterrain = "L" }); + des.replace_terrain({ fromterrain = "W", toterrain = "Z" }); + else + -- both are water + des.replace_terrain({ fromterrain = "L", toterrain = "P" }); + des.replace_terrain({ fromterrain = "Z", toterrain = "W" }); + end +end + +des.region(selection.area(00,00,75,19), "lit") +des.non_diggable(); + +des.wallify(); + +des.stair("up"); +des.stair("down"); + +for i = 1,15 do + des.object(); +end +for i = 1,6 do + des.trap(); +end +for i = 1,28 do + des.monster(); +end diff --git a/dat/dungeon.lua b/dat/dungeon.lua index ff9e9130a..eb6223d66 100644 --- a/dat/dungeon.lua +++ b/dat/dungeon.lua @@ -70,7 +70,7 @@ dungeon = { base = 10, range = 3, chance = 40, - nlevels = 11 + nlevels = 12 }, { name = "medusa", diff --git a/sys/unix/NetHack.xcodeproj/project.pbxproj b/sys/unix/NetHack.xcodeproj/project.pbxproj index 8e8caa1a5..55f36fd7f 100644 --- a/sys/unix/NetHack.xcodeproj/project.pbxproj +++ b/sys/unix/NetHack.xcodeproj/project.pbxproj @@ -1423,6 +1423,8 @@ "$(NH_DAT_DIR)/Bar-strt.lua", "$(NH_DAT_DIR)/bigrm-1.lua", "$(NH_DAT_DIR)/bigrm-10.lua", + "$(NH_DAT_DIR)/bigrm-11.lua", + "$(NH_DAT_DIR)/bigrm-12.lua", "$(NH_DAT_DIR)/bigrm-2.lua", "$(NH_DAT_DIR)/bigrm-3.lua", "$(NH_DAT_DIR)/bigrm-4.lua", diff --git a/sys/windows/GNUmakefile b/sys/windows/GNUmakefile index 4e6ee45e5..29085431c 100644 --- a/sys/windows/GNUmakefile +++ b/sys/windows/GNUmakefile @@ -449,6 +449,7 @@ CLEAN_FILE += $(NHLUAH) LUALIST = air Arc-fila Arc-filb Arc-goal Arc-loca Arc-strt \ asmodeus astral baalz Bar-fila Bar-filb Bar-goal \ Bar-loca Bar-strt bigrm-1 bigrm-10 bigrm-11 bigrm-2 \ + bigrm-12 \ bigrm-3 bigrm-4 bigrm-5 bigrm-6 bigrm-7 bigrm-8 \ bigrm-9 castle Cav-fila Cav-filb Cav-goal Cav-loca \ Cav-strt dungeon earth fakewiz1 fakewiz2 fire \ diff --git a/sys/windows/Makefile.nmake b/sys/windows/Makefile.nmake index 5da031bec..7d72c27eb 100644 --- a/sys/windows/Makefile.nmake +++ b/sys/windows/Makefile.nmake @@ -554,6 +554,7 @@ LUA_FILES = $(DAT)\air.lua $(DAT)\Arc-fila.lua $(DAT)\Arc-filb.lua \ $(DAT)\Bar-fila.lua $(DAT)\Bar-filb.lua $(DAT)\Bar-goal.lua \ $(DAT)\Bar-loca.lua $(DAT)\Bar-strt.lua $(DAT)\bigrm-1.lua \ $(DAT)\bigrm-10.lua $(DAT)\bigrm-11.lua $(DAT)\bigrm-2.lua \ + $(DAT)\bigrm-12.lua \ $(DAT)\bigrm-3.lua $(DAT)\bigrm-4.lua $(DAT)\bigrm-5.lua \ $(DAT)\bigrm-6.lua $(DAT)\bigrm-7.lua $(DAT)\bigrm-8.lua \ $(DAT)\bigrm-9.lua $(DAT)\castle.lua $(DAT)\Cav-fila.lua \ diff --git a/sys/windows/vs/files.props b/sys/windows/vs/files.props index 9dd50ca4c..16a62721e 100644 --- a/sys/windows/vs/files.props +++ b/sys/windows/vs/files.props @@ -32,6 +32,7 @@ + From 6b0e21dc1a450663406d48fbee937e1327932ca0 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sat, 21 Dec 2024 14:11:00 +0200 Subject: [PATCH 227/791] Wish alias "tripe" for tripe ration --- src/objnam.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/objnam.c b/src/objnam.c index a445564d5..b566778e7 100644 --- a/src/objnam.c +++ b/src/objnam.c @@ -3356,6 +3356,7 @@ static const struct alt_spellings { { "kelp", KELP_FROND }, { "eucalyptus", EUCALYPTUS_LEAF }, { "lembas", LEMBAS_WAFER }, + { "tripe", TRIPE_RATION }, { "cookie", FORTUNE_COOKIE }, { "pie", CREAM_PIE }, { "huge meatball", ENORMOUS_MEATBALL }, /* likely conflated name */ From 0079bf87bb287dee9fd0d75128df0b00cde0b443 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sat, 21 Dec 2024 18:19:42 +0200 Subject: [PATCH 228/791] fixes update --- doc/fixes3-7-0.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index a9de275c9..03b0488c7 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -2596,7 +2596,7 @@ menu for what-is command supports /^ and /" to view a list of nearby or whole level visible and remembered traps spiders will occasionally spin webs when moving around drinking a burning potion of oil will cure being turned into slime -new bigroom variant, a boulder maze +new bigroom variants, a boulder maze and hexagons vomiting on an altar provokes the deities wrath branch stairs have a different glyph, show up in yellow color in tty duration of confusion when drinking booze depends upon hunger state From f12d755ba2f1e4687279c4f4f165d48f37109ba3 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 22 Dec 2024 09:43:00 -0500 Subject: [PATCH 229/791] Makefile.nmake updates Be more consistent in the use of path separators. Add a second version of Makefile variables that contain paths, one with a trailing separator, and one without (prefixed with R_ for use in Makefile rules). Also, in dat/luahelper, Updates due to correspond to the Makefile.nmake changes. Add Makefile variable AWK to use $(AWK) instead of hardcoded awk. --- dat/luahelper | 15 +- sys/windows/Makefile.nmake | 2153 +++++++++++++++++++----------------- 2 files changed, 1177 insertions(+), 991 deletions(-) diff --git a/dat/luahelper b/dat/luahelper index 94774024a..7f8a653fa 100644 --- a/dat/luahelper +++ b/dat/luahelper @@ -20,7 +20,10 @@ # Xcode project.pbxproj: make -f dat/luahelper devhelp-xcode >file.txt # # + MAKEFLAGS += --no-print-directory +AWK=awk + luanames = asmodeus baalz bigrm-* castle fakewiz? juiblex knox medusa-? \ minend-? minefill minetn-? oracle orcus sanctum soko?-? tower? \ @@ -36,9 +39,9 @@ alllua = $(wildcard $(addsuffix .lua,$(addprefix dat/, $(luanames)))) # devhelp-nmake: @echo "$(notdir $(alllua))" | \ - awk '{for (i=1; i<=NF; ++i)printf "%s%s%s%s", \ - i == 1? "ALL_LUA_FILES = " : "", \ - "$$(DAT)\\", \ + $(AWK) '{for (i=1; i<=NF; ++i)printf "%s%s%s%s", \ + i == 1? "LUA_FILES = " : "", \ + "$$(DAT)", \ $$i, \ i % 3? " ": ((i == NF)? "\n" : " \\\n\t")} \ i % 3{print ""}' @@ -50,7 +53,7 @@ devhelp-nmake: # devhelp-msys2: @echo "$(basename $(notdir $(alllua)))" | \ - awk '{for (i=1; i<=NF; ++i)printf "%s%s%s", \ + $(AWK) '{for (i=1; i<=NF; ++i)printf "%s%s%s", \ i == 1? "LUALIST = " : "", \ $$i, \ i % 5? " ": ((i == NF)? "\n" : " \\\n\t")} \ @@ -67,7 +70,7 @@ xcodeextra = bogusmon cmdhelp data engrave epitaph help hh \ devhelp-xcode: @echo "\t\t\tinputPaths = (" @echo "$(xcodeextra) $(notdir $(alllua))" | \ - awk '{for (i=1; i<=NF; ++i)printf "%s%s%s%s%s", \ + $(AWK) '{for (i=1; i<=NF; ++i)printf "%s%s%s%s%s", \ i == 1? "\t" : "", \ "\t\t\t\042$$(NH_DAT_DIR)/", \ $$i, \ @@ -82,7 +85,7 @@ devhelp-xcode: devhelp-vstudio: @echo " " @echo "$(notdir $(alllua))" | \ - awk '{for (i=1; i<=NF; ++i)printf "%s%s%s%s%s", \ + $(AWK) '{for (i=1; i<=NF; ++i)printf "%s%s%s%s%s", \ i == 1? " " : "", \ " ..\src\allmain.c +# SRC ..\src\ $(SRC)allmain.c => ..\src\allmain.c +# +#============================================================================== # if next line is commented out, full compiler command lines will be output Q=@ @@ -150,29 +165,87 @@ NETHACK_VERSION="3.7.0" NHV=$(NETHACK_VERSION:.=) NHV=$(NHV:"=) +#============================================================================== # # Source directories. Makedefs hardcodes these, don't change them. # -INCL = ..\include # NetHack include files -DAT = ..\dat # NetHack data files -DOC = ..\doc # NetHack documentation files -UTIL = ..\util # Utility source -SRC = ..\src # Main source -SSYS = ..\sys\share # Shared system files -MSWSYS = ..\sys\windows # MS windows specific files -TTY = ..\win\tty # window port files (tty) -MSWIN = ..\win\win32 # window port files (win32) -WCURSES = ..\win\curses # window port files (curses) -WSHR = ..\win\share # Tile support files -QT = ..\win\Qt # QT support files -X11 = ..\win\X11 # X11 support files -LIBDIR = ..\lib # libraries and external bits -SUBM = ..\submodules # NetHack git submodules -SndWavDir = ..\sound\wav # sound files that get integrated -BinDir = ..\binary -PkgDir = ..\package +R_INCL = ..\include # NetHack include files +R_DAT = ..\dat # NetHack data files +R_DOC = ..\doc # NetHack documentation files +R_UTIL = ..\util # Utility source +R_SRC = ..\src # Main source +R_SSYS = ..\sys\share # Shared system files +R_MSWSYS = ..\sys\windows # MS windows specific files +R_TTY = ..\win\tty # window port files (tty) +R_MSWIN = ..\win\win32 # window port files (win32) +R_WCURSES = ..\win\curses # window port files (curses) +R_WSHR = ..\win\share # Tile support files +R_QT = ..\win\Qt # QT support files +R_X11 = ..\win\X11 # X11 support files +R_LIBDIR = ..\lib # libraries and external bits +R_SUBM = ..\submodules # NetHack git submodules +R_SndWavDir = ..\sound\wav # sound files that get integrated +R_BinDir = ..\binary +R_PkgDir = ..\package +R_SOUNDDIR = ..\sound +#R_GAMEDIR is user option up near the top +#!MESSAGE $(R_SRC) +#!MESSAGE $(R_GAMEDIR) +#============================================================================== +# Ordinary path variations with trailing backslash +# +BACKSLASH=^\ +INCL = $(R_INCL)$(BACKSLASH) +DAT = $(R_DAT)$(BACKSLASH) +UTIL = $(R_UTIL)$(BACKSLASH) +SRC = $(R_SRC)$(BACKSLASH) +SSYS = $(R_SSYS)$(BACKSLASH) +MSWSYS = $(R_MSWSYS)$(BACKSLASH) +TTY = $(R_TTY)$(BACKSLASH) +MSWIN = $(R_MSWIN)$(BACKSLASH) +WCURSES = $(R_WCURSES)$(BACKSLASH) +WSHR = $(R_WSHR)$(BACKSLASH) +QT = $(R_QT)$(BACKSLASH) +X11 = $(R_X11)$(BACKSLASH) +LIBDIR = $(R_LIBDIR)$(BACKSLASH) +SUBM = $(R_SUBM)$(BACKSLASH) +DOC = $(R_DOC)$(BACKSLASH) +SndWavDir = $(R_SndWavDir)$(BACKSLASH) +BinDir = $(R_BinDir)$(BACKSLASH) +PkgDir = $(R_PkgDir)$(BACKSLASH) +SOUNDDIR = $(R_SOUNDDIR)$(BACKSLASH) +GAMEDIR = $(R_GAMEDIR)$(BACKSLASH) + +#!MESSAGE $(SRC) +#!MESSAGE $(GAMEDIR) +#============================================================================== +# Unix path variations with trailing forward slash +# +#U_INCL = $(INCL:\=/) +#U_DAT = $(DAT:\=/) +#U_UTIL = $(UTIL:\=/) +#U_SRC = $(SRC:\=/) +#U_SSYS = $(SSYS:\=/) +#U_MSWSYS = $(MSWSYS:\=/) +#U_TTY = $(TTY:\=/) +#U_MSWIN = $(MSWIN:\=/) +#U_WCURSES = $(WCURSES:\=/) +#U_WSHR = $(WSHR:\=/) +#U_QT = $(QT:\=/) +#U_X11 = $(X11:\=/) +#U_LIBDIR = $(LIBDIR:\=/) +#U_SUBM = $(SUBM:\=/) +#U_DOC = $(DOC:\=/) +#U_SndWavDir = $(SndWavDir:\=/) +#U_BinDir = $(BinDir:\=/) +#U_PkgDir = $(PkgDir:\=/) +#U_SOUNDDIR = $(SOUNDDIR:\=/) +U_GAMEDIR = $(GAMEDIR:\=/) +# +#!MESSAGE $(U_SRC) +#!MESSAGE $(U_GAMEDIR) #============================================================================== # Sanity checks for prerequisite Lua and pdcursesmod # @@ -182,12 +255,18 @@ ADD_CURSES=N # First, Lua !IF "$(INTERNET_AVAILABLE)" == "Y" !IF "$(GIT_AVAILABLE)" == "Y" -LUATOP=$(SUBM)\lua -LUASRC=$(LUATOP) +R_LUATOP=$(SUBM)lua +LUATOP=$(SUBM)lua$(BACKSLASH) +R_LUASRC=$(R_LUATOP) +LUASRC=$(R_LUASRC)$(BACKSLASH) LUA_MAY_PROCEED=Y !ELSE # GIT_AVAILABLE -LUATOP = $(LIBDIR)\lua-$(LUAVER) -LUASRC = $(LUATOP)\src +R_LUATOP=$(LIBDIR)lua-$(LUAVER) +LUATOP=$(R_LUATOP)$(BACKSLASH) +#U_LUATOP=$(LUATOP:\=/) +R_LUASRC=$(LUATOP)src +LUASRC=$(R_LUASRC)$(BACKSLASH) +#U_LUASRC=$(LUASRC:\=/) LUA_MAY_PROCEED=Y !ENDIF # GIT_AVAILABLE !ELSE # INTERNET_AVAILABLE is not Y below @@ -195,13 +274,21 @@ LUA_MAY_PROCEED=Y # method (git or download). Check to see if it is available already, with # precedence given to ../submodules, then ../lib. # -!IF EXIST("$(SUBM)\lua\lua.h") -LUATOP=$(SUBM)\lua -LUASRC=$(LUATOP) +!IF EXIST("$(SUBM)lua\lua.h") +R_LUATOP=$(SUBM)lua +LUATOP=$(R_LUATOP)$(BACKSLASH) +#U_LUATOP=$(LUATOP:\=/) +R_LUASRC=$(LUATOP) +LUASRC=$(LUATOP)$(BACKSLASH) +#U_LUASRC=$(LUASRC:\=/) LUA_MAY_PROCEED=Y -!ELSEIF EXIST("$(LIBDIR)\lua-$(LUAVER)\src\lua.h") -LUATOP = $(LIBDIR)\lua-$(LUAVER) -LUASRC = $(LUATOP)\src +!ELSEIF EXIST("$(LIBDIR)lua-$(LUAVER)\src\lua.h") +R_LUATOP=$(LIBDIR)lua-$(LUAVER) +LUATOP=$(R_LUATOP)$(BACKSLASH) +#U_LUATOP=$(LUATOP:\=/) +R_LUASRC=$(LUATOP)src +LUASRC=$(R_LUASRC)$(BACKSLASH) +#U_LUASRC=$(LUASRC:\=/) LUA_MAY_PROCEED=Y !ENDIF # Lua sources !IF "$(LUA_MAY_PROCEED)" == "Y" @@ -210,11 +297,16 @@ LUA_MAY_PROCEED=Y !ENDIF # LUA_MAY_PROCEED !ENDIF # INTERNET_AVAILABLE +#!MESSAGE R_LUATOP=$(R_LUATOP) +#!MESSAGE LUATOP=$(R_LUATOP) +#!MESSAGE R_LUASRC=$(R_LUASRC) +#!MESSAGE LUASRC=$(LUASRC) + !IF "$(LUA_MAY_PROCEED)" != "Y" !IF "$(INTERNET_AVAILABLE)" != "Y" !MESSAGE Your Makefile settings do not allow use of the internet to obtain Lua !ENDIF # INTERNET_AVAILABLE -!MESSAGE and no copy of Lua was found in either $(SUBM)\lua or $(LIBDIR)\lua-$(LUAVER). +!MESSAGE and no copy of Lua was found in either $(SUBM)lua or $(LIBDIR)lua-$(LUAVER). !MESSAGE Change your nmake command line to include: !MESSAGE GIT=1 !MESSAGE or modify your Makefile to set the following: @@ -240,35 +332,57 @@ ADD_CURSES=N # Now, pdcursesmod !IF "$(WANT_CURSES)" == "Y" -PDCDIST=pdcursesmod -!IF "$(INTERNET_AVAILABLE)" == "Y" -!IF "$(GIT_AVAILABLE)" == "Y" -PDCURSES_TOP=$(SUBM)\$(PDCDIST) +R_PDCDIST=pdcursesmod +PDCDIST=$(R_PDCDIST)$(BACKSLASH) +#U_PDCDIST=$(PDCDIST:\=/) +! IF "$(INTERNET_AVAILABLE)" == "Y" +! IF "$(GIT_AVAILABLE)" == "Y" +#!MESSAGE debug spot1 +R_PDCURSES_TOP=$(SUBM)$(R_PDCDIST) +PDCURSES_TOP=$(R_PDCURSES_TOP)$(BACKSLASH) +#U_PDCURSES_TOP=$(PDCURSES_TOP:\=/) ADD_CURSES=Y -!ELSE # GIT_AVAILABLE -PDCURSES_TOP=$(LIBDIR)\$(PDCDIST) +! ELSE # GIT_AVAILABLE +#!MESSAGE debug spot2 +R_PDCURSES_TOP=$(LIBDIR)$(R_PDCDIST) +PDCURSES_TOP=$(R_PDCURSES_TOP)$(BACKSLASH) +#U_PDCURSES_TOP=$(PDCURSES_TOP:\=/) ADD_CURSES=Y -!ENDIF # GIT_AVAILABLE -!ELSE # INTERNET_AVAILABLE is not Y below +! ENDIF # GIT_AVAILABLE +! ELSE # NO internet available # Your Makefile settings do not allow $(PDCDIST) to be obtained by # git or by download. Check to see if it is available at one of # the expected locations already, with precedence given to ../submodules, # then ../lib. -# -!IF EXIST("$(SUBM)\$(PDCDIST)\curses.h") -PDCURSES_TOP=$(SUBM)\$(PDCDIST) +#! MESSAGE debug spot3 +! IF EXIST("$(LIBDIR)$(R_PDCDIST)curses.h") +R_PDCURSES_TOP=$(LIBDIR)$(PDCDIST) +PDCURSES_TOP=$(R_PDCURSES_TOP)$(BACKSLASH) ADD_CURSES=Y -!ELSEIF EXIST("$(LIBDIR)\$(PDCDIST)\curses.h") -PDCURSES_TOP=$(LIBDIR)\$(PDCDIST) +! ELSEIF EXIST("$(SUBM)$(R_PDCDIST)curses.h") +#!MESSAGE debug spot4 +R_PDCURSES_TOP=$(LIBDIR)$(PDCDIST) +PDCURSES_TOP=$(R_PDCURSES_TOP)$(BACKSLASH) ADD_CURSES=Y -!ENDIF # pdcursesmod sources available somewhere -!IF "$(ADD_CURSES)" == "Y" +! ENDIF # pdcursesmod sources available somewhere +! ENDIF # Internet dealt with +! IF "$(ADD_CURSES)" != "Y" +#!MESSAGE debug spot5 !MESSAGE Your Makefile settings do not allow $(PDCDIST) to be !MESSAGE obtained by git or by download, but a copy of pdcursesmod was !MESSAGE found in $(PDCURSES_TOP), !MESSAGE so that will be used. -!ENDIF # ADD_CURSES == Y -!ENDIF # INTERNET_AVAILABLE +! ELSE +#!MESSAGE debug spot6 +! IF EXIST("$(PDCURSES_TOP)curses.h") +INCLCURSES_H=-I$(R_PDCURSES_TOP) +! ELSE +# Cannot do it, sorry + PDCINCL= + INCLCURSES_H= + ADD_CURSES = N +! ENDIF # If we found a copy of curses.h +! ENDIF # ADD_CURSES == Y !ENDIF # WANT_CURSES !IF "$(ADD_CURSES)" != "Y" @@ -346,35 +460,51 @@ DLBDEF = # Object file directories. # -OBJTTY_B = objtty -OBJGUI_B = objgui -OBJUTIL_B = objutil -OBJLUA_B = objlua -OBJPDC_B = objpdc -OBJPDCC_B = objpdcc -OBJPDCG_B = objpdcg +R_OBJTTY_B = objtty +R_OBJGUI_B = objgui +R_OBJUTIL_B = objutil +R_OBJLUA_B = objlua +R_OBJPDC_B = objpdc +R_OBJPDCC_B = objpdcc +R_OBJPDCG_B = objpdcg -OBJTTY = $(OBJTTY_B)\$(TARGET_CPU) -OBJGUI = $(OBJGUI_B)\$(TARGET_CPU) -OBJUTIL = $(OBJUTIL_B)\$(TARGET_CPU) -OBJLUA = $(OBJLUA_B)\$(TARGET_CPU) -OBJPDC = $(OBJPDC_B)\$(TARGET_CPU) -OBJPDCC = $(OBJPDCC_B)\$(TARGET_CPU) -OBJPDCG = $(OBJPDCG_B)\$(TARGET_CPU) +OBJTTY_B = $(R_OBJTTY_B)$(BACKSLASH) +OBJGUI_B = $(R_OBJGUI_B)$(BACKSLASH) +OBJUTIL_B = $(R_OBJUTIL_B)$(BACKSLASH) +OBJLUA_B = $(R_OBJLUA_B)$(BACKSLASH) +OBJPDC_B = $(R_OBJPDC_B)$(BACKSLASH) +OBJPDCC_B = $(R_OBJPDCC_B)$(BACKSLASH) +OBJPDCG_B = $(R_OBJPDCG_B)$(BACKSLASH) + +R_OBJTTY = $(OBJTTY_B)$(TARGET_CPU) +R_OBJGUI = $(OBJGUI_B)$(TARGET_CPU) +R_OBJUTIL = $(OBJUTIL_B)$(TARGET_CPU) +R_OBJLUA = $(OBJLUA_B)$(TARGET_CPU) +R_OBJPDC = $(OBJPDC_B)$(TARGET_CPU) +R_OBJPDCC = $(OBJPDCC_B)$(TARGET_CPU) +R_OBJPDCG = $(OBJPDCG_B)$(TARGET_CPU) + +OBJTTY = $(R_OBJTTY)$(BACKSLASH) +OBJGUI = $(R_OBJGUI)$(BACKSLASH) +OBJUTIL = $(R_OBJUTIL)$(BACKSLASH) +OBJLUA = $(R_OBJLUA)$(BACKSLASH) +OBJPDC = $(R_OBJPDC)$(BACKSLASH) +OBJPDCC = $(R_OBJPDCC)$(BACKSLASH) +OBJPDCG = $(R_OBJPDCG)$(BACKSLASH) # # Shorten up the location for some files # -OTTY = $(OBJTTY)^\ -OGUI = $(OBJGUI)^\ -OUTL = $(OBJUTIL)^\ -OLUA = $(OBJLUA)^\ -OPDC = $(OBJPDC)^\ -OPDCC = $(OBJPDCC)^\ -OPDCG = $(OBJPDCG)^\ +OTTY = $(OBJTTY) +OGUI = $(OBJGUI) +OUTL = $(OBJUTIL) +OLUA = $(OBJLUA) +OPDC = $(OBJPDC) +OPDCC = $(OBJPDCC) +OPDCG = $(OBJPDCG) -U = $(UTIL)^\ +U = $(UTIL) !IFDEF TEST_CROSSCOMPILE HOST=_host @@ -422,9 +552,9 @@ GITPREFIX = -DNETHACK_GIT_PREFIX=\"$(GIT_PREFIX)\" LUAVER=5.4.6 !ENDIF -LUALIB = $(LIBDIR)\lua$(LUAVER)-$(TARGET_CPU)-static.lib -LUADLL = $(LIBDIR)\lua$(LUAVER)-$(TARGET_CPU).dll -LUAINCL = /I$(LUASRC) +LUALIB = $(LIBDIR)lua$(LUAVER)-$(TARGET_CPU)-static.lib +LUADLL = $(LIBDIR)lua$(LUAVER)-$(TARGET_CPU).dll +R_LUAINCL = /I$(R_LUASRC) LUATARGETS = lua.exe $(LUADLL) $(LUALIB) LUASRCFILES = lapi.c lauxlib.c lbaselib.c lcode.c \ @@ -462,17 +592,20 @@ LUAOBJFILES = $(LUAOBJFILES) $(OLUA)lbitlib.o #================================================================= !IF "$(ADD_CURSES)" == "Y" -PDCURSES_CURSES_H = $(PDCURSES_TOP)\curses.h -PDCURSES_CURSPRIV_H = $(PDCURSES_TOP)\curspriv.h +PDCURSES_CURSES_H = $(PDCURSES_TOP)curses.h +PDCURSES_CURSPRIV_H = $(PDCURSES_TOP)curspriv.h PDCURSES_HEADERS = $(PDCURSES_CURSES_H) $(PDCURSES_CURSPRIV_H) -PDCSRC = $(PDCURSES_TOP)\pdcurses +R_PDCSRC = $(PDCURSES_TOP)pdcurses +PDCSRC = $(R_PDCSRC)$(BACKSLASH) !IF "$(CURSES_CONSOLE)" == "Y" -PDCWINCON = $(PDCURSES_TOP)\wincon +R_PDCWINCON = $(PDCURSES_TOP)wincon +PDCWINCON = $(PDCURSES_TOP)wincon$(BACKSLASH) !ENDIF !IF "$(CURSES_GRAPHICAL)" == "Y" -PDCWINGUI = $(PDCURSES_TOP)\wingui +R_PDCWINGUI = $(PDCURSES_TOP)wingui +PDCWINGUI = $(PDCURSES_TOP)wingui$(BACKSLASH) !ENDIF -PDCDEP = $(PDCURSES_TOP)\curses.h +PDCDEP = $(PDCURSES_TOP)curses.h PDCCOMMONOBJS = $(OPDC)addch.o $(OPDC)addchstr.o $(OPDC)addstr.o $(OPDC)attr.o $(OPDC)beep.o \ $(OPDC)bkgd.o $(OPDC)border.o $(OPDC)clear.o $(OPDC)color.o $(OPDC)debug.o \ @@ -484,8 +617,7 @@ PDCCOMMONOBJS = $(OPDC)addch.o $(OPDC)addchstr.o $(OPDC)addstr.o $(OPDC)attr.o $ $(OPDC)printw.o $(OPDC)refresh.o $(OPDC)scanw.o $(OPDC)scr_dump.o \ $(OPDC)scroll.o $(OPDC)slk.o $(OPDC)termattr.o $(OPDC)touch.o \ $(OPDC)util.o $(OPDC)window.o - -PDCINCL = /I$(PDCURSES_TOP) /I$(PDCSRC) +PDCINCL = /I$(R_PDCURSES_TOP) /I$(R_PDCSRC) !IF "$(CURSES_CONSOLE)" == "Y" PDCINCLCON = /I$(PDCWINCON) PDCWINCONOBJS = $(OPDCC)pdcclip.o $(OPDCC)pdcdisp.o $(OPDCC)pdcgetsc.o \ @@ -508,92 +640,122 @@ PDCINCLCON= #================================================================= -HACKINCL = $(INCL)\align.h $(INCL)\artifact.h $(INCL)\artilist.h \ - $(INCL)\attrib.h $(INCL)\botl.h $(INCL)\color.h $(INCL)\config.h \ - $(INCL)\config1.h $(INCL)\context.h $(INCL)\coord.h $(INCL)\decl.h \ - $(INCL)\display.h $(INCL)\dlb.h $(INCL)\dungeon.h $(INCL)\engrave.h \ - $(INCL)\extern.h $(INCL)\flag.h $(INCL)\fnamesiz.h $(INCL)\func_tab.h \ - $(INCL)\global.h $(INCL)\warnings.h $(INCL)\hack.h $(INCL)\lint.h \ - $(INCL)\mextra.h $(INCL)\mfndpos.h $(INCL)\micro.h $(INCL)\mkroom.h \ - $(INCL)\monattk.h $(INCL)\mondata.h $(INCL)\monflag.h $(INCL)\monst.h \ - $(INCL)\monsters.h $(INCL)\obj.h $(INCL)\objects.h $(INCL)\objclass.h \ - $(INCL)\optlist.h $(INCL)\patchlevel.h $(INCL)\pcconf.h \ - $(INCL)\permonst.h $(INCL)\prop.h $(INCL)\rect.h $(INCL)\region.h \ - $(INCL)\sym.h $(INCL)\defsym.h $(INCL)\rm.h $(INCL)\selvar.h $(INCL)\sp_lev.h \ - $(INCL)\spell.h $(INCL)\stairs.h $(INCL)\sys.h $(INCL)\cstd.h $(INCL)\tcap.h \ - $(INCL)\timeout.h $(INCL)\tradstdc.h $(INCL)\trap.h \ - $(INCL)\unixconf.h $(INCL)\vision.h $(INCL)\vmsconf.h \ - $(INCL)\wintty.h $(INCL)\wincurs.h $(INCL)\winX.h \ - $(INCL)\winprocs.h $(INCL)\sndprocs.h $(INCL)\seffects.h \ - $(INCL)\wintype.h $(INCL)\you.h $(INCL)\youprop.h - # all .c that are part of the main NetHack program and are not operating- or # windowing-system specific -HACKCSRC = allmain.c alloc.c apply.c artifact.c attrib.c ball.c bones.c \ - botl.c calendar.c cmd.c coloratt.c dbridge.c decl.c detect.c dig.c display.c \ - dlb.c do.c do_name.c do_wear.c dog.c dogmove.c dokick.c dothrow.c \ - drawing.c dungeon.c eat.c end.c engrave.c exper.c explode.c \ - files.c fountain.c getpos.c glyphs.c hack.c \ - insight.c invent.c isaac64.c light.c \ - lock.c mail.c makemon.c mcastu.c mdlib.c mhitm.c \ - mhitu.c minion.c mklev.c mkmap.c mkmaze.c mkobj.c mkroom.c mon.c \ - mondata.c monmove.c monst.c mplayer.c mthrowu.c muse.c music.c \ - nhlua.c nhlsel.c nhlobj.c o_init.c objects.c objnam.c \ - options.c pager.c pickup.c pline.c polyself.c potion.c pray.c \ - priest.c quest.c questpgr.c read.c rect.c region.c restore.c \ - rip.c rnd.c role.c rumors.c save.c selvar.c sfstruct.c \ - shk.c shknam.c sit.c sounds.c sp_lev.c spell.c \ - stairs.c steal.c steed.c symbols.c sys.c teleport.c \ - timeout.c topten.c track.c trap.c u_init.c uhitm.c utf8map.c \ - vault.c version.c vision.c weapon.c were.c wield.c \ - windows.c wizard.c worm.c worn.c write.c zap.c -LUA_FILES = $(DAT)\air.lua $(DAT)\Arc-fila.lua $(DAT)\Arc-filb.lua \ - $(DAT)\Arc-goal.lua $(DAT)\Arc-loca.lua $(DAT)\Arc-strt.lua \ - $(DAT)\asmodeus.lua $(DAT)\astral.lua $(DAT)\baalz.lua \ - $(DAT)\Bar-fila.lua $(DAT)\Bar-filb.lua $(DAT)\Bar-goal.lua \ - $(DAT)\Bar-loca.lua $(DAT)\Bar-strt.lua $(DAT)\bigrm-1.lua \ - $(DAT)\bigrm-10.lua $(DAT)\bigrm-11.lua $(DAT)\bigrm-2.lua \ - $(DAT)\bigrm-12.lua \ - $(DAT)\bigrm-3.lua $(DAT)\bigrm-4.lua $(DAT)\bigrm-5.lua \ - $(DAT)\bigrm-6.lua $(DAT)\bigrm-7.lua $(DAT)\bigrm-8.lua \ - $(DAT)\bigrm-9.lua $(DAT)\castle.lua $(DAT)\Cav-fila.lua \ - $(DAT)\Cav-filb.lua $(DAT)\Cav-goal.lua $(DAT)\Cav-loca.lua \ - $(DAT)\Cav-strt.lua $(DAT)\dungeon.lua $(DAT)\earth.lua \ - $(DAT)\fakewiz1.lua $(DAT)\fakewiz2.lua $(DAT)\fire.lua \ - $(DAT)\Hea-fila.lua $(DAT)\Hea-filb.lua $(DAT)\Hea-goal.lua \ - $(DAT)\Hea-loca.lua $(DAT)\Hea-strt.lua $(DAT)\hellfill.lua \ - $(DAT)\juiblex.lua $(DAT)\Kni-fila.lua $(DAT)\Kni-filb.lua \ - $(DAT)\Kni-goal.lua $(DAT)\Kni-loca.lua $(DAT)\Kni-strt.lua \ - $(DAT)\knox.lua $(DAT)\medusa-1.lua $(DAT)\medusa-2.lua \ - $(DAT)\medusa-3.lua $(DAT)\medusa-4.lua $(DAT)\minefill.lua \ - $(DAT)\minend-1.lua $(DAT)\minend-2.lua $(DAT)\minend-3.lua \ - $(DAT)\minetn-1.lua $(DAT)\minetn-2.lua $(DAT)\minetn-3.lua \ - $(DAT)\minetn-4.lua $(DAT)\minetn-5.lua $(DAT)\minetn-6.lua \ - $(DAT)\minetn-7.lua $(DAT)\Mon-fila.lua $(DAT)\Mon-filb.lua \ - $(DAT)\Mon-goal.lua $(DAT)\Mon-loca.lua $(DAT)\Mon-strt.lua \ - $(DAT)\nhcore.lua $(DAT)\nhlib.lua $(DAT)\oracle.lua \ - $(DAT)\orcus.lua $(DAT)\Pri-fila.lua $(DAT)\Pri-filb.lua \ - $(DAT)\Pri-goal.lua $(DAT)\Pri-loca.lua $(DAT)\Pri-strt.lua \ - $(DAT)\quest.lua $(DAT)\Ran-fila.lua $(DAT)\Ran-filb.lua \ - $(DAT)\Ran-goal.lua $(DAT)\Ran-loca.lua $(DAT)\Ran-strt.lua \ - $(DAT)\Rog-fila.lua $(DAT)\Rog-filb.lua $(DAT)\Rog-goal.lua \ - $(DAT)\Rog-loca.lua $(DAT)\Rog-strt.lua $(DAT)\Sam-fila.lua \ - $(DAT)\Sam-filb.lua $(DAT)\Sam-goal.lua $(DAT)\Sam-loca.lua \ - $(DAT)\Sam-strt.lua $(DAT)\sanctum.lua $(DAT)\soko1-1.lua \ - $(DAT)\soko1-2.lua $(DAT)\soko2-1.lua $(DAT)\soko2-2.lua \ - $(DAT)\soko3-1.lua $(DAT)\soko3-2.lua $(DAT)\soko4-1.lua \ - $(DAT)\soko4-2.lua $(DAT)\themerms.lua $(DAT)\Tou-fila.lua \ - $(DAT)\Tou-filb.lua $(DAT)\Tou-goal.lua $(DAT)\Tou-loca.lua \ - $(DAT)\Tou-strt.lua $(DAT)\tower1.lua $(DAT)\tower2.lua \ - $(DAT)\tower3.lua $(DAT)\Val-fila.lua $(DAT)\Val-filb.lua \ - $(DAT)\Val-goal.lua $(DAT)\Val-loca.lua $(DAT)\Val-strt.lua \ - $(DAT)\valley.lua $(DAT)\water.lua $(DAT)\Wiz-fila.lua \ - $(DAT)\Wiz-filb.lua $(DAT)\Wiz-goal.lua $(DAT)\Wiz-loca.lua \ - $(DAT)\Wiz-strt.lua $(DAT)\wizard1.lua $(DAT)\wizard2.lua \ - $(DAT)\wizard3.lua $(DAT)\tut-1.lua $(DAT)\tut-2.lua +HACKCSRC = \ + $(SRC)allmain.c $(SRC)alloc.c $(SRC)apply.c $(SRC)artifact.c \ + $(SRC)attrib.c $(SRC)ball.c $(SRC)bones.c $(SRC)botl.c \ + $(SRC)calendar.c $(SRC)cmd.c $(SRC)coloratt.c $(SRC)dbridge.c \ + $(SRC)decl.c $(SRC)detect.c $(SRC)dig.c $(SRC)display.c \ + $(SRC)dlb.c $(SRC)do.c $(SRC)do_name.c $(SRC)do_wear.c \ + $(SRC)dog.c $(SRC)dogmove.c $(SRC)dokick.c $(SRC)dothrow.c \ + $(SRC)drawing.c $(SRC)dungeon.c $(SRC)eat.c $(SRC)end.c \ + $(SRC)engrave.c $(SRC)exper.c $(SRC)explode.c $(SRC)files.c \ + $(SRC)fountain.c $(SRC)getpos.c $(SRC)glyphs.c $(SRC)hack.c \ + $(SRC)insight.c $(SRC)invent.c $(SRC)isaac64.c $(SRC)light.c \ + $(SRC)lock.c $(SRC)mail.c $(SRC)makemon.c $(SRC)mcastu.c \ + $(SRC)mdlib.c $(SRC)mhitm.c $(SRC)mhitu.c $(SRC)minion.c \ + $(SRC)mklev.c $(SRC)mkmap.c $(SRC)mkmaze.c $(SRC)mkobj.c \ + $(SRC)mkroom.c $(SRC)mon.c $(SRC)mondata.c $(SRC)monmove.c \ + $(SRC)monst.c $(SRC)mplayer.c $(SRC)mthrowu.c $(SRC)muse.c \ + $(SRC)music.c $(SRC)nhlua.c $(SRC)nhlsel.c $(SRC)nhlobj.c \ + $(SRC)o_init.c $(SRC)objects.c $(SRC)objnam.c $(SRC)options.c \ + $(SRC)pager.c $(SRC)pickup.c $(SRC)pline.c $(SRC)polyself.c \ + $(SRC)potion.c $(SRC)pray.c $(SRC)priest.c $(SRC)quest.c \ + $(SRC)questpgr.c $(SRC)read.c $(SRC)rect.c $(SRC)region.c \ + $(SRC)restore.c $(SRC)rip.c $(SRC)rnd.c $(SRC)role.c \ + $(SRC)rumors.c $(SRC)save.c $(SRC)selvar.c $(SRC)sfstruct.c \ + $(SRC)shk.c $(SRC)shknam.c $(SRC)sit.c $(SRC)sounds.c \ + $(SRC)sp_lev.c $(SRC)spell.c $(SRC)stairs.c $(SRC)steal.c \ + $(SRC)steed.c $(SRC)symbols.c $(SRC)sys.c $(SRC)teleport.c \ + $(SRC)timeout.c $(SRC)topten.c $(SRC)track.c $(SRC)trap.c \ + $(SRC)u_init.c $(SRC)uhitm.c $(SRC)utf8map.c $(SRC)vault.c \ + $(SRC)version.c $(SRC)vision.c $(SRC)weapon.c $(SRC)were.c \ + $(SRC)wield.c $(SRC)windows.c $(SRC)wizard.c $(SRC)worm.c \ + $(SRC)worn.c $(SRC)write.c $(SRC)zap.c + +# all .h files except date.h +HACKINCL = \ + $(INCL)align.h $(INCL)artifact.h $(INCL)artilist.h \ + $(INCL)attrib.h $(INCL)botl.h $(INCL)color.h \ + $(INCL)config.h $(INCL)config1.h $(INCL)context.h \ + $(INCL)coord.h $(INCL)cstd.h $(INCL)decl.h \ + $(INCL)display.h $(INCL)dlb.h $(INCL)dungeon.h \ + $(INCL)engrave.h $(INCL)extern.h $(INCL)flag.h \ + $(INCL)fnamesiz.h $(INCL)func_tab.h $(INCL)global.h \ + $(INCL)warnings.h $(INCL)hack.h $(INCL)lint.h \ + $(INCL)mextra.h $(INCL)mfndpos.h $(INCL)micro.h \ + $(INCL)mkroom.h $(INCL)monattk.h $(INCL)mondata.h \ + $(INCL)monflag.h $(INCL)monst.h $(INCL)monsters.h \ + $(INCL)nhmd4.h $(INCL)obj.h $(INCL)objects.h \ + $(INCL)objclass.h $(INCL)optlist.h $(INCL)patchlevel.h \ + $(INCL)pcconf.h $(INCL)permonst.h $(INCL)prop.h \ + $(INCL)rect.h $(INCL)region.h $(INCL)selvar.h \ + $(INCL)sym.h $(INCL)defsym.h $(INCL)rm.h \ + $(INCL)sp_lev.h $(INCL)spell.h $(INCL)sndprocs.h \ + $(INCL)seffects.h $(INCL)stairs.h $(INCL)sys.h \ + $(INCL)tcap.h $(INCL)timeout.h $(INCL)tradstdc.h \ + $(INCL)trap.h $(INCL)unixconf.h $(INCL)vision.h \ + $(INCL)vmsconf.h $(INCL)wintty.h $(INCL)wincurs.h \ + $(INCL)winX.h $(INCL)winprocs.h $(INCL)wintype.h \ + $(INCL)you.h $(INCL)youprop.h + +LUA_FILES = $(DAT)asmodeus.lua $(DAT)baalz.lua $(DAT)bigrm-1.lua \ + $(DAT)bigrm-10.lua $(DAT)bigrm-11.lua $(DAT)bigrm-12.lua \ + $(DAT)bigrm-2.lua $(DAT)bigrm-3.lua $(DAT)bigrm-4.lua \ + $(DAT)bigrm-5.lua $(DAT)bigrm-6.lua $(DAT)bigrm-7.lua \ + $(DAT)bigrm-8.lua $(DAT)bigrm-9.lua $(DAT)castle.lua \ + $(DAT)fakewiz1.lua $(DAT)fakewiz2.lua $(DAT)juiblex.lua \ + $(DAT)knox.lua $(DAT)medusa-1.lua $(DAT)medusa-2.lua \ + $(DAT)medusa-3.lua $(DAT)medusa-4.lua $(DAT)minend-1.lua \ + $(DAT)minend-2.lua $(DAT)minend-3.lua $(DAT)minefill.lua \ + $(DAT)minetn-1.lua $(DAT)minetn-2.lua $(DAT)minetn-3.lua \ + $(DAT)minetn-4.lua $(DAT)minetn-5.lua $(DAT)minetn-6.lua \ + $(DAT)minetn-7.lua $(DAT)oracle.lua $(DAT)orcus.lua \ + $(DAT)sanctum.lua $(DAT)soko1-1.lua $(DAT)soko1-2.lua \ + $(DAT)soko2-1.lua $(DAT)soko2-2.lua $(DAT)soko3-1.lua \ + $(DAT)soko3-2.lua $(DAT)soko4-1.lua $(DAT)soko4-2.lua \ + $(DAT)tower1.lua $(DAT)tower2.lua $(DAT)tower3.lua \ + $(DAT)valley.lua $(DAT)wizard1.lua $(DAT)wizard2.lua \ + $(DAT)wizard3.lua $(DAT)nhcore.lua $(DAT)nhlib.lua \ + $(DAT)themerms.lua $(DAT)astral.lua $(DAT)air.lua \ + $(DAT)earth.lua $(DAT)fire.lua $(DAT)water.lua \ + $(DAT)hellfill.lua $(DAT)tut-1.lua $(DAT)tut-2.lua \ + $(DAT)Arc-goal.lua $(DAT)Bar-goal.lua $(DAT)Cav-goal.lua \ + $(DAT)Hea-goal.lua $(DAT)Kni-goal.lua $(DAT)Mon-goal.lua \ + $(DAT)Pri-goal.lua $(DAT)Ran-goal.lua $(DAT)Rog-goal.lua \ + $(DAT)Sam-goal.lua $(DAT)Tou-goal.lua $(DAT)Val-goal.lua \ + $(DAT)Wiz-goal.lua $(DAT)Arc-fila.lua $(DAT)Arc-filb.lua \ + $(DAT)Bar-fila.lua $(DAT)Bar-filb.lua $(DAT)Cav-fila.lua \ + $(DAT)Cav-filb.lua $(DAT)Hea-fila.lua $(DAT)Hea-filb.lua \ + $(DAT)Kni-fila.lua $(DAT)Kni-filb.lua $(DAT)Mon-fila.lua \ + $(DAT)Mon-filb.lua $(DAT)Pri-fila.lua $(DAT)Pri-filb.lua \ + $(DAT)Ran-fila.lua $(DAT)Ran-filb.lua $(DAT)Rog-fila.lua \ + $(DAT)Rog-filb.lua $(DAT)Sam-fila.lua $(DAT)Sam-filb.lua \ + $(DAT)Tou-fila.lua $(DAT)Tou-filb.lua $(DAT)Val-fila.lua \ + $(DAT)Val-filb.lua $(DAT)Wiz-fila.lua $(DAT)Wiz-filb.lua \ + $(DAT)Arc-loca.lua $(DAT)Bar-loca.lua $(DAT)Cav-loca.lua \ + $(DAT)Hea-loca.lua $(DAT)Kni-loca.lua $(DAT)Mon-loca.lua \ + $(DAT)Pri-loca.lua $(DAT)Ran-loca.lua $(DAT)Rog-loca.lua \ + $(DAT)Sam-loca.lua $(DAT)Tou-loca.lua $(DAT)Val-loca.lua \ + $(DAT)Wiz-loca.lua $(DAT)Arc-strt.lua $(DAT)Bar-strt.lua \ + $(DAT)Cav-strt.lua $(DAT)Hea-strt.lua $(DAT)Kni-strt.lua \ + $(DAT)Mon-strt.lua $(DAT)Pri-strt.lua $(DAT)Ran-strt.lua \ + $(DAT)Rog-strt.lua $(DAT)Sam-strt.lua $(DAT)Tou-strt.lua \ + $(DAT)Val-strt.lua $(DAT)Wiz-strt.lua $(DAT)dungeon.lua \ + $(DAT)quest.lua + +luawildcards = asmodeus.lua baalz.lua bigrm-*.lua castle.lua fakewiz?.lua \ + juiblex.lua knox.lua medusa-?.lua minend-?.lua minefill.lua \ + minetn-?.lua oracle.lua orcus.lua sanctum.lua soko?-?.lua tower?.lua \ + valley.lua wizard?.lua nhcore.lua nhlib.lua themerms.lua astral.lua \ + air.lua earth.lua fire.lua water.lua hellfill.lua tut-?.lua \ + ???-goal.lua ???-fil?.lua ???-loca.lua ???-strt.lua \ + dungeon.lua quest.lua + # -# Utility Objects. +# - Utility # MAKESRC = $(U)makedefs.c @@ -603,7 +765,7 @@ MAKEDEFSOBJS = $(OUTL)makedefs.o $(OUTL)monst$(HOST).o $(OUTL)objects$(HOST).o RECOVOBJS = $(OUTL)recover.o -TILEFILES = $(WSHR)\monsters.txt $(WSHR)\objects.txt $(WSHR)\other.txt +TILEFILES = $(WSHR)monsters.txt $(WSHR)objects.txt $(WSHR)other.txt # # These are not invoked during a normal game build in 3.7 @@ -620,7 +782,7 @@ GIFREADERS32_HOST = $(OUTL)gifrd32.o $(OUTL)alloc$(HOST).o $(OUTL)panic$(HOST) PPMWRITERS = $(OUTL)ppmwrite.o $(OUTL)alloc$(HOST).o $(OUTL)panic$(HOST).o -WINDHDR = $(MSWSYS)\win10.h $(MSWSYS)\winos.h $(MSWSYS)\win32api.h +WINDHDR = $(MSWSYS)win10.h $(MSWSYS)winos.h $(MSWSYS)win32api.h # # - Curses @@ -633,14 +795,14 @@ CURSESOBJ= $(OTTY)cursdial.o $(OTTY)cursinit.o $(OTTY)cursinvt.o \ $(OTTY)cursstat.o $(OTTY)curswins.o !IF "$(CURSES_CONSOLE)" == "Y" CURSESWINCONOBJS = $(CURSESOBJ) -PDCWINCONLIB = $(LIBDIR)\$(PDCDIST)-wincon-$(TARGET_CPU)-static.lib +PDCWINCONLIB = $(LIBDIR)$(PDCDIST)-wincon-$(TARGET_CPU)-static.lib CURSESCONDEF1=-D"CURSES_GRAPHICS" -DPDC_NCMOUSE #CURSESDEF2=-D"CURSES_BRIEF_INCLUDE" -DCHTYPE_32 CURSESDEF2=-DCURSES_UNICODE $(PDCURSESFLAGS) !ENDIF !IF "$(CURSES_GRAPHICAL)" == "Y" CURSESWINGUIOBJS = $(CURSESOBJ) $(OGUI)guitty.o -PDCWINGUILIB = $(LIBDIR)\$(PDCDIST)-wingui-$(TARGET_CPU)-static.lib +PDCWINGUILIB = $(LIBDIR)$(PDCDIST)-wingui-$(TARGET_CPU)-static.lib CURSESGUIDEF1=-D"CURSES_GRAPHICS" -DPDC_NCMOUSE #CURSESDEF2=-D"CURSES_BRIEF_INCLUDE" -DCHTYPE_32 CURSESDEF2=-DCURSES_UNICODE $(PDCURSESFLAGS) @@ -663,14 +825,13 @@ OUTLHACKLIB = $(OUTL)hacklib-$(TARGET_CPU)-static.lib OTTYHACKLIB = $(OTTY)hacklib-$(TARGET_CPU)-static.lib OGUIHACKLIB = $(OGUI)hacklib-$(TARGET_CPU)-static.lib - # # - TTY # TTYDEF= -D"_CONSOLE" -DWIN32CON $(CURSESCONDEF1) $(CURSESGUIDEF1) -RANDOMTTY = $(OTTY)random.o +#RANDOMTTY = $(OTTY)random.o MDLIBTTY = $(OTTY)mdlib.o DLBOBJTTY = $(OTTY)dlb.o REGEXTTY = $(OTTY)cppregex.o @@ -680,46 +841,41 @@ VVOBJTTY = $(OTTY)version.o SOBJTTY = $(OTTY)windmain.o $(OTTY)windsys.o $(OTTY)win10.o \ $(OTTY)safeproc.o -TTYOBJ = $(OTTY)topl.o $(OTTY)getline.o $(OTTY)wintty.o +TTYOBJTTY = $(OTTY)topl.o $(OTTY)getline.o $(OTTY)wintty.o -VTTYOBJ01 = $(OTTY)allmain.o $(OTTY)alloc.o $(OTTY)apply.o $(OTTY)artifact.o -VTTYOBJ02 = $(OTTY)attrib.o $(OTTY)ball.o $(OTTY)bones.o $(OTTY)botl.o -VTTYOBJ03 = $(OTTY)calendar.o $(OTTY)cmd.o $(OTTY)coloratt.o $(OTTY)dbridge.o -VTTYOBJ04 = $(OTTY)decl.o $(OTTY)detect.o $(OTTY)dig.o $(OTTY)display.o $(OTTY)do.o -VTTYOBJ05 = $(OTTY)do_name.o $(OTTY)do_wear.o $(OTTY)dog.o $(OTTY)dogmove.o $(OTTY)dokick.o -VTTYOBJ06 = $(OTTY)dothrow.o $(OTTY)drawing.o $(OTTY)dungeon.o $(OTTY)eat.o -VTTYOBJ07 = $(OTTY)end.o $(OTTY)engrave.o $(OTTY)exper.o $(OTTY)explode.o -VTTYOBJ08 = $(OTTY)extralev.o $(OTTY)files.o $(OTTY)fountain.o $(OTTY)getpos.o -VTTYOBJ09 = $(OTTY)glyphs.o $(OTTY)hack.o $(OTTY)insight.o $(OTTY)invent.o -VTTYOBJ10 = $(OTTY)isaac64.o $(OTTY)light.o $(OTTY)lock.o $(OTTY)mail.o -VTTYOBJ11 = $(OTTY)makemon.o $(OTTY)mcastu.o $(OTTY)mhitm.o $(OTTY)mhitu.o -VTTYOBJ12 = $(OTTY)minion.o $(OTTY)mklev.o $(OTTY)mkmap.o $(OTTY)mkmaze.o -VTTYOBJ13 = $(OTTY)mkobj.o $(OTTY)mkroom.o $(OTTY)mon.o $(OTTY)mondata.o -VTTYOBJ14 = $(OTTY)monmove.o $(OTTY)monst.o $(OTTY)mplayer.o $(OTTY)mthrowu.o -VTTYOBJ15 = $(OTTY)muse.o $(OTTY)music.o $(OTTY)o_init.o $(OTTY)objects.o -VTTYOBJ16 = $(OTTY)objnam.o $(OTTY)options.o $(OTTY)pager.o $(OTTY)pickup.o -VTTYOBJ17 = $(OTTY)pline.o $(OTTY)polyself.o $(OTTY)potion.o $(OTTY)pray.o -VTTYOBJ18 = $(OTTY)priest.o $(OTTY)quest.o $(OTTY)questpgr.o $(RANDOM) -VTTYOBJ19 = $(OTTY)read.o $(OTTY)rect.o $(OTTY)region.o $(OTTY)report.o $(OTTY)restore.o -VTTYOBJ20 = $(OTTY)rip.o $(OTTY)rnd.o $(OTTY)role.o $(OTTY)rumors.o -VTTYOBJ21 = $(OTTY)save.o $(OTTY)selvar.o $(OTTY)sfstruct.o $(OTTY)shk.o -VTTYOBJ22 = $(OTTY)shknam.o $(OTTY)sit.o $(OTTY)sounds.o $(OTTY)sp_lev.o -VTTYOBJ23 = $(OTTY)spell.o $(OTTY)stairs.o $(OTTY)steal.o $(OTTY)steed.o -VTTYOBJ24 = $(OTTY)strutil.o $(OTTY)symbols.o $(OTTY)sys.o $(OTTY)teleport.o $(OTTY)timeout.o -VTTYOBJ25 = $(OTTY)topten.o $(OTTY)track.o $(OTTY)trap.o $(OTTY)u_init.o -VTTYOBJ26 = $(OTTY)uhitm.o $(OTTY)utf8map.o $(OTTY)vault.o $(OTTY)vision.o -VTTYOBJ27 = $(OTTY)weapon.o $(OTTY)were.o $(OTTY)wield.o $(OTTY)windows.o -VTTYOBJ28 = $(OTTY)wizard.o $(OTTY)wizcmds.o $(OTTY)worm.o $(OTTY)worn.o -VTTYOBJ29 = $(OTTY)write.o $(OTTY)zap.o +COREOBJTTY = \ + $(OTTY)allmain.o $(OTTY)alloc.o $(OTTY)apply.o $(OTTY)artifact.o \ + $(OTTY)attrib.o $(OTTY)ball.o $(OTTY)bones.o $(OTTY)botl.o \ + $(OTTY)calendar.o $(OTTY)cmd.o $(OTTY)coloratt.o $(OTTY)dbridge.o \ + $(OTTY)decl.o $(OTTY)detect.o $(OTTY)dig.o $(OTTY)display.o \ + $(OTTY)do.o $(OTTY)do_name.o $(OTTY)do_wear.o $(OTTY)dog.o \ + $(OTTY)dogmove.o $(OTTY)dokick.o $(OTTY)dothrow.o $(OTTY)drawing.o \ + $(OTTY)dungeon.o $(OTTY)eat.o $(OTTY)end.o $(OTTY)engrave.o \ + $(OTTY)exper.o $(OTTY)explode.o $(OTTY)extralev.o $(OTTY)files.o \ + $(OTTY)fountain.o $(OTTY)getpos.o $(OTTY)glyphs.o $(OTTY)hack.o \ + $(OTTY)insight.o $(OTTY)invent.o $(OTTY)isaac64.o $(OTTY)light.o \ + $(OTTY)lock.o $(OTTY)mail.o $(OTTY)makemon.o $(OTTY)mcastu.o \ + $(OTTY)mhitm.o $(OTTY)mhitu.o $(OTTY)minion.o $(OTTY)mklev.o \ + $(OTTY)mkmap.o $(OTTY)mkmaze.o $(OTTY)mkobj.o $(OTTY)mkroom.o \ + $(OTTY)mon.o $(OTTY)mondata.o $(OTTY)monmove.o $(OTTY)monst.o \ + $(OTTY)mplayer.o $(OTTY)mthrowu.o $(OTTY)muse.o $(OTTY)music.o \ + $(OTTY)o_init.o $(OTTY)objects.o $(OTTY)objnam.o $(OTTY)options.o \ + $(OTTY)pager.o $(OTTY)pickup.o $(OTTY)pline.o $(OTTY)polyself.o \ + $(OTTY)potion.o $(OTTY)pray.o $(OTTY)priest.o $(OTTY)quest.o \ + $(OTTY)questpgr.o $(OTTY)read.o $(OTTY)rect.o $(OTTY)region.o \ + $(OTTY)report.o $(OTTY)restore.o $(OTTY)rip.o $(OTTY)rnd.o \ + $(OTTY)role.o $(OTTY)rumors.o $(OTTY)save.o $(OTTY)selvar.o \ + $(OTTY)sfstruct.o $(OTTY)shk.o $(OTTY)shknam.o $(OTTY)sit.o \ + $(OTTY)sounds.o $(OTTY)sp_lev.o $(OTTY)spell.o $(OTTY)stairs.o \ + $(OTTY)steal.o $(OTTY)steed.o $(OTTY)strutil.o $(OTTY)symbols.o \ + $(OTTY)sys.o $(OTTY)teleport.o $(OTTY)timeout.o $(OTTY)topten.o \ + $(OTTY)track.o $(OTTY)trap.o $(OTTY)u_init.o $(OTTY)uhitm.o \ + $(OTTY)utf8map.o $(OTTY)vault.o $(OTTY)vision.o $(OTTY)weapon.o \ + $(OTTY)were.o $(OTTY)wield.o $(OTTY)windows.o $(OTTY)wizard.o \ + $(OTTY)wizcmds.o $(OTTY)worm.o $(OTTY)worn.o $(OTTY)write.o \ + $(OTTY)zap.o -OBJSTTY = $(MDLIBTTY) \ - $(VTTYOBJ01) $(VTTYOBJ02) $(VTTYOBJ03) $(VTTYOBJ04) $(VTTYOBJ05) \ - $(VTTYOBJ06) $(VTTYOBJ07) $(VTTYOBJ08) $(VTTYOBJ09) $(VTTYOBJ10) \ - $(VTTYOBJ11) $(VTTYOBJ12) $(VTTYOBJ13) $(VTTYOBJ14) $(VTTYOBJ15) \ - $(VTTYOBJ16) $(VTTYOBJ17) $(VTTYOBJ18) $(VTTYOBJ19) $(VTTYOBJ20) \ - $(VTTYOBJ21) $(VTTYOBJ22) $(VTTYOBJ23) $(VTTYOBJ24) $(VTTYOBJ25) \ - $(VTTYOBJ26) $(VTTYOBJ27) $(VTTYOBJ28) $(VTTYOBJ29) $(VTTYOBJ30) \ - $(REGEXTTY) +OBJSTTY = $(MDLIBTTY) $(COREOBJTTY) $(REGEXTTY) $(RANDOMTTY) ALLOBJTTY = $(SOBJTTY) $(DLBOBJTTY) $(OBJSTTY) $(VVOBJTTY) $(LUAOBJTTY) @@ -729,13 +885,13 @@ ALLOBJTTY = $(SOBJTTY) $(DLBOBJTTY) $(OBJSTTY) $(VVOBJTTY) $(LUAOBJTTY) GUIDEF= -DTILES -DMSWIN_GRAPHICS -DNOTTYGRAPHICS $(CURSESGUIDEF1) -ALL_GUIHDR = $(MSWIN)\mhaskyn.h $(MSWIN)\mhdlg.h $(MSWIN)\mhfont.h \ - $(MSWIN)\mhinput.h $(MSWIN)\mhmain.h $(MSWIN)\mhmap.h $(MSWIN)\mhmenu.h \ - $(MSWIN)\mhmsg.h $(MSWIN)\mhmsgwnd.h $(MSWIN)\mhrip.h \ - $(MSWIN)\mhsplash.h $(MSWIN)\mhstatus.h \ - $(MSWIN)\mhtext.h $(MSWIN)\resource.h $(MSWIN)\winMS.h +ALL_GUIHDR = $(MSWIN)mhaskyn.h $(MSWIN)mhdlg.h $(MSWIN)mhfont.h \ + $(MSWIN)mhinput.h $(MSWIN)mhmain.h $(MSWIN)mhmap.h $(MSWIN)mhmenu.h \ + $(MSWIN)mhmsg.h $(MSWIN)mhmsgwnd.h $(MSWIN)mhrip.h \ + $(MSWIN)mhsplash.h $(MSWIN)mhstatus.h \ + $(MSWIN)mhtext.h $(MSWIN)resource.h $(MSWIN)winMS.h -RANDOMGUI = $(OGUI)random.o +#RANDOMGUI = $(OGUI)random.o MDLIBGUI = $(OGUI)mdlib.o DLBOBJGUI = $(OGUI)dlb.o REGEXGUI = $(OGUI)cppregex.o @@ -750,44 +906,39 @@ GUIOBJ = $(OGUI)mhaskyn.o $(OGUI)mhdlg.o \ $(OGUI)mhmenu.o $(OGUI)mhmsgwnd.o $(OGUI)mhrip.o $(OGUI)mhsplash.o \ $(OGUI)mhstatus.o $(OGUI)mhtext.o $(OGUI)mswproc.o $(OGUI)NetHackW.o -VGUIOBJ01 = $(OGUI)allmain.o $(OGUI)alloc.o $(OGUI)apply.o $(OGUI)artifact.o -VGUIOBJ02 = $(OGUI)attrib.o $(OGUI)ball.o $(OGUI)bones.o $(OGUI)botl.o -VGUIOBJ03 = $(OGUI)calendar.o $(OGUI)cmd.o $(OGUI)coloratt.o $(OGUI)dbridge.o $(OGUI)decl.o -VGUIOBJ04 = $(OGUI)detect.o $(OGUI)dig.o $(OGUI)display.o $(OGUI)do.o $(OGUI)do_name.o -VGUIOBJ05 = $(OGUI)do_wear.o $(OGUI)dog.o $(OGUI)dogmove.o $(OGUI)dokick.o -VGUIOBJ06 = $(OGUI)dothrow.o $(OGUI)drawing.o $(OGUI)dungeon.o $(OGUI)eat.o -VGUIOBJ07 = $(OGUI)end.o $(OGUI)engrave.o $(OGUI)exper.o $(OGUI)explode.o -VGUIOBJ08 = $(OGUI)extralev.o $(OGUI)files.o $(OGUI)fountain.o $(OGUI)getpos.o -VGUIOBJ09 = $(OGUI)glyphs.o $(OGUI)hack.o $(OGUI)insight.o $(OGUI)invent.o -VGUIOBJ10 = $(OGUI)isaac64.o $(OGUI)light.o $(OGUI)lock.o $(OGUI)mail.o -VGUIOBJ11 = $(OGUI)makemon.o $(OGUI)mcastu.o $(OGUI)mhitm.o $(OGUI)mhitu.o -VGUIOBJ12 = $(OGUI)minion.o $(OGUI)mklev.o $(OGUI)mkmap.o $(OGUI)mkmaze.o -VGUIOBJ13 = $(OGUI)mkobj.o $(OGUI)mkroom.o $(OGUI)mon.o $(OGUI)mondata.o -VGUIOBJ14 = $(OGUI)monmove.o $(OGUI)monst.o $(OGUI)mplayer.o $(OGUI)mthrowu.o -VGUIOBJ15 = $(OGUI)muse.o $(OGUI)music.o $(OGUI)o_init.o $(OGUI)objects.o -VGUIOBJ16 = $(OGUI)objnam.o $(OGUI)options.o $(OGUI)pager.o $(OGUI)pickup.o -VGUIOBJ17 = $(OGUI)pline.o $(OGUI)polyself.o $(OGUI)potion.o $(OGUI)pray.o -VGUIOBJ18 = $(OGUI)priest.o $(OGUI)quest.o $(OGUI)questpgr.o $(RANDOMGUI) -VGUIOBJ19 = $(OGUI)read.o $(OGUI)rect.o $(OGUI)region.o $(OGUI)report.o $(OGUI)restore.o -VGUIOBJ20 = $(OGUI)rip.o $(OGUI)rnd.o $(OGUI)role.o $(OGUI)rumors.o -VGUIOBJ21 = $(OGUI)save.o $(OGUI)selvar.o $(OGUI)sfstruct.o $(OGUI)shk.o -VGUIOBJ22 = $(OGUI)shknam.o $(OGUI)sit.o $(OGUI)sounds.o $(OGUI)sp_lev.o -VGUIOBJ23 = $(OGUI)spell.o $(OGUI)stairs.o $(OGUI)steal.o $(OGUI)steed.o -VGUIOBJ24 = $(OGUI)strutil.o $(OGUI)symbols.o $(OGUI)sys.o $(OGUI)teleport.o $(OGUI)timeout.o -VGUIOBJ25 = $(OGUI)topten.o $(OGUI)track.o $(OGUI)trap.o $(OGUI)u_init.o -VGUIOBJ26 = $(OGUI)uhitm.o $(OGUI)utf8map.o $(OGUI)vault.o $(OGUI)vision.o -VGUIOBJ27 = $(OGUI)weapon.o $(OGUI)were.o $(OGUI)wield.o $(OGUI)windows.o -VGUIOBJ28 = $(OGUI)wizard.o $(OGUI)wizcmds.o $(OGUI)worm.o $(OGUI)worn.o -VGUIOBJ29 = $(OGUI)write.o $(OGUI)zap.o +COREOBJGUI = \ + $(OGUI)allmain.o $(OGUI)alloc.o $(OGUI)apply.o $(OGUI)artifact.o \ + $(OGUI)attrib.o $(OGUI)ball.o $(OGUI)bones.o $(OGUI)botl.o \ + $(OGUI)calendar.o $(OGUI)cmd.o $(OGUI)coloratt.o $(OGUI)dbridge.o \ + $(OGUI)decl.o $(OGUI)detect.o $(OGUI)dig.o $(OGUI)display.o \ + $(OGUI)do.o $(OGUI)do_name.o $(OGUI)do_wear.o $(OGUI)dog.o \ + $(OGUI)dogmove.o $(OGUI)dokick.o $(OGUI)dothrow.o $(OGUI)drawing.o \ + $(OGUI)dungeon.o $(OGUI)eat.o $(OGUI)end.o $(OGUI)engrave.o \ + $(OGUI)exper.o $(OGUI)explode.o $(OGUI)extralev.o $(OGUI)files.o \ + $(OGUI)fountain.o $(OGUI)getpos.o $(OGUI)glyphs.o $(OGUI)hack.o \ + $(OGUI)insight.o $(OGUI)invent.o $(OGUI)isaac64.o $(OGUI)light.o \ + $(OGUI)lock.o $(OGUI)mail.o $(OGUI)makemon.o $(OGUI)mcastu.o \ + $(OGUI)mhitm.o $(OGUI)mhitu.o $(OGUI)minion.o $(OGUI)mklev.o \ + $(OGUI)mkmap.o $(OGUI)mkmaze.o $(OGUI)mkobj.o $(OGUI)mkroom.o \ + $(OGUI)mon.o $(OGUI)mondata.o $(OGUI)monmove.o $(OGUI)monst.o \ + $(OGUI)mplayer.o $(OGUI)mthrowu.o $(OGUI)muse.o $(OGUI)music.o \ + $(OGUI)o_init.o $(OGUI)objects.o $(OGUI)objnam.o $(OGUI)options.o \ + $(OGUI)pager.o $(OGUI)pickup.o $(OGUI)pline.o $(OGUI)polyself.o \ + $(OGUI)potion.o $(OGUI)pray.o $(OGUI)priest.o $(OGUI)quest.o \ + $(OGUI)questpgr.o $(OGUI)read.o $(OGUI)rect.o $(OGUI)region.o \ + $(OGUI)report.o $(OGUI)restore.o $(OGUI)rip.o $(OGUI)rnd.o \ + $(OGUI)role.o $(OGUI)rumors.o $(OGUI)save.o $(OGUI)selvar.o \ + $(OGUI)sfstruct.o $(OGUI)shk.o $(OGUI)shknam.o $(OGUI)sit.o \ + $(OGUI)sounds.o $(OGUI)sp_lev.o $(OGUI)spell.o $(OGUI)stairs.o \ + $(OGUI)steal.o $(OGUI)steed.o $(OGUI)strutil.o $(OGUI)symbols.o \ + $(OGUI)sys.o $(OGUI)teleport.o $(OGUI)timeout.o $(OGUI)topten.o \ + $(OGUI)track.o $(OGUI)trap.o $(OGUI)u_init.o $(OGUI)uhitm.o \ + $(OGUI)utf8map.o $(OGUI)vault.o $(OGUI)vision.o $(OGUI)weapon.o \ + $(OGUI)were.o $(OGUI)wield.o $(OGUI)windows.o $(OGUI)wizard.o \ + $(OGUI)wizcmds.o $(OGUI)worm.o $(OGUI)worn.o $(OGUI)write.o \ + $(OGUI)zap.o -OBJSGUI = $(MDLIBGUI) \ - $(VGUIOBJ01) $(VGUIOBJ02) $(VGUIOBJ03) $(VGUIOBJ04) $(VGUIOBJ05) \ - $(VGUIOBJ06) $(VGUIOBJ07) $(VGUIOBJ08) $(VGUIOBJ09) $(VGUIOBJ10) \ - $(VGUIOBJ11) $(VGUIOBJ12) $(VGUIOBJ13) $(VGUIOBJ14) $(VGUIOBJ15) \ - $(VGUIOBJ16) $(VGUIOBJ17) $(VGUIOBJ18) $(VGUIOBJ19) $(VGUIOBJ20) \ - $(VGUIOBJ21) $(VGUIOBJ22) $(VGUIOBJ23) $(VGUIOBJ24) $(VGUIOBJ25) \ - $(VGUIOBJ26) $(VGUIOBJ27) $(VGUIOBJ28) $(VGUIOBJ29) $(VGUIOBJ30) \ - $(REGEXGUI) +OBJSGUI = $(MDLIBGUI) $(COREOBJGUI) $(REGEXGUI) $(RANDOMGUI) ALLOBJGUI = $(SOBJGUI) $(DLBOBJGUI) $(OBJSGUI) $(VVOBJGUI) $(LUAOBJGUI) @@ -796,7 +947,7 @@ ALLOBJGUI = $(SOBJGUI) $(DLBOBJGUI) $(OBJSGUI) $(VVOBJGUI) $(LUAOBJGUI) # COMCTRL = comctl32.lib -OPTIONS_FILE = $(DAT)\options +OPTIONS_FILE = $(DAT)options !IFDEF TEST_CROSSCOMPILE DLBOBJ_HOST = $(OTTY)dlb$(HOST).o @@ -818,18 +969,21 @@ HAVE_SOUNDLIB=Y NEED_USERSOUNDS=Y NEED_SEAUTOMAP=Y NEED_WAV=Y -SOUNDLIBINCL = $(SOUNDLIBINCL) +R_SOUNDLIBINCL = $(R_SOUNDLIBINCL) +SOUNDLIBINCL = $(R_SOUNDLIBINCL)$(BACKSLASH) SOUNDLIBDEFS = $(SOUNDLIBDEFS) -DSND_LIB_WINDSOUND TTYSOUNDOBJS = $(TTYSOUNDOBJS) $(OTTY)windsound.o GUISOUNDOBJS = $(GUISOUNDOBJS) $(OGUI)windsound.o -#WINDSOUNDLIBDIR = +#WINDSOUNDLIBDIR = #TTYSOUNDLIBS = $(TTYSOUNDLIBS) #GUISOUNDLIBS = $(GUISOUNDLIBS) #WINDSOUNDLIBDIR = #WINDSOUNDLIBDLL = -WINDSOUNDDIR = ..\sound\windsound -SOUNDSRCS = $(SOUNDSRCS) $(WINDSOUNDDIR)\windsound.c -#GAMEDIRDLLS = $(GAMEDIRDLLS) $(GAMEDIR\$(WINDSOUNDLIBDLL) +R_WINDSOUNDDIR = $(SOUNDDIR)windsound +WINDSOUNDDIR=$(R_WINDSOUNDDIR)$(BACKSLASH) +#U_WINDSOUNDDIR = $(WINDSOUNDDIR:\=/) +SOUNDSRCS = $(SOUNDSRCS) $(WINDSOUNDDIR)windsound.c +#GAMEDIRDLLS = $(GAMEDIRDLLS) $(GAMEDIR)$(WINDSOUNDLIBDLL) !ENDIF SNDTEMP= @@ -846,40 +1000,47 @@ HAVE_SOUNDLIB=Y NEED_USERSOUNDS=Y NEED_SEAUTOMAP=Y NEED_WAV=Y -FMODROOT=..\lib\fmod\api\core +R_FMODROOT=..\lib\fmod\api\core +FMODROOT=$(R_FMODROOT)$(BACKSLASH) +U_FMODROOT=$(FMODROOT:\=/) FMODDLLBASENAME = fmod.dll -SOUNDLIBINCL = $(SOUNDLIBINCL) -I$(FMODROOT)/inc +R_SOUNDLIBINCL = $(R_SOUNDLIBINCL) -I$(FMODROOT)inc +SOUNDLIBINCL = $(R_SOUNDLIBINCL)$BACKSLASH) SOUNDLIBDEFS = $(SOUNDLIBDEFS) -DSND_LIB_FMOD TTYSOUNDOBJS = $(TTYSOUNDOBJS) $(OTTY)fmod.o GUISOUNDOBJS = $(GUISOUNDOBJS) $(OGUI)fmod.o -FMODLIBDIR = $(FMODROOT)\lib\$(TARGET_CPU) -FMODLIBDLL = $(FMODLIBDIR)\$(FMODDLLBASENAME) +R_FMODLIBDIR = $(FMODROOT)lib\$(TARGET_CPU) +FMODLIBDIR=$(R_FMODLIBDIR)$(BACKSLASH) +#U_FMODLIBDIR=$(FMODLIBDIR:\=/) +FMODLIBDLL = $(FMODLIBDIR)$(FMODDLLBASENAME) FMODFLAGS = -wd4201 -TTYSOUNDLIBS = $(TTYSOUNDLIBS) $(FMODLIBDIR)\fmod_vc.lib -GUISOUNDLIBS = $(GUISOUNDLIBS) $(FMODLIBDIR)\fmod_vc.lib +TTYSOUNDLIBS = $(TTYSOUNDLIBS) $(FMODLIBDIR)fmod_vc.lib +GUISOUNDLIBS = $(GUISOUNDLIBS) $(FMODLIBDIR)fmod_vc.lib GAMEDIRDLLS = $(GAMEDIRDLLS) $(GAMEDIR)\$(FMODDLLBASENAME) -FMODDIR = ..\sound\fmod -SOUNDSRCS = $(SOUNDSRCS) $(FMODDIR)\fmod.c +R_FMODDIR = $(SOUNDDIR)fmod +FMODDIR=$(R_FMODDIR)$(BACKSLASH) +#U_FMODDIR=$(FMODDIR:\=/) +SOUNDSRCS = $(SOUNDSRCS) $(FMODDIR)fmod.c !MESSAGE --------------------------------------------------------------------- !MESSAGE ** NOTES for fmod sound library integration ** !MESSAGE For fmod integration, this Makefile expects: -!MESSAGE fmod include directory : $(FMODROOT)\inc +!MESSAGE fmod include directory : $(FMODROOT)inc !MESSAGE fmod library directory : $(FMODLIBDIR) -!MESSAGE fmod library to link with : $(FMODLIBDIR)\fmod_vc.lib +!MESSAGE fmod library to link with : $(FMODLIBDIR)fmod_vc.lib !MESSAGE fmod library dll : $(FMODLIBDLL) !MESSAGE --------------------------------------------------------------------- FMOD_MISSING= -!IF !EXIST("$(FMODROOT)\inc") -FMOD_MISSING= $(FMOD_MISSING) $(FMODROOT)\inc -!MESSAGE Error: missing $(FMODROOT)\inc +!IF !EXIST("$(FMODROOT)inc") +FMOD_MISSING= $(FMOD_MISSING) $(FMODROOT)inc +!MESSAGE Error: missing $(FMODROOT)inc !ENDIF !IF !EXIST("$(FMODLIBDIR)") FMOD_MISSING= $(FMOD_MISSING) $(FMODLIBDIR) !MESSAGE Error: missing $(FMODLIBDIR) !ENDIF -!IF !EXIST("$(FMODLIBDIR)\fmod_vc.lib") -FMOD_MISSING= $(FMOD_MISSING) $(FMODLIBDIR)\fmod_vc.lib -!MESSAGE Error: missing $(FMODLIBDIR)\fmod_vc.lib +!IF !EXIST("$(FMODLIBDIR)fmod_vc.lib") +FMOD_MISSING= $(FMOD_MISSING) $(FMODLIBDIR)fmod_vc.lib +!MESSAGE Error: missing $(FMODLIBDIR)fmod_vc.lib !ENDIF !IF !EXIST("$(FMODLIBDLL)") FMOD_MISSING= $(FMOD_MISSING) $(FMODLIBDLL) @@ -895,38 +1056,38 @@ SNDTEMP= # SOUND Support #================================================================= -WAVS = $(SndWavDir)\se_squeak_A.wav $(SndWavDir)\se_squeak_B.wav \ - $(SndWavDir)\se_squeak_B_flat.wav $(SndWavDir)\se_squeak_C.wav \ - $(SndWavDir)\se_squeak_D.wav $(SndWavDir)\se_squeak_D_flat.wav \ - $(SndWavDir)\se_squeak_E.wav $(SndWavDir)\se_squeak_E_flat.wav \ - $(SndWavDir)\se_squeak_F.wav $(SndWavDir)\se_squeak_F_sharp.wav \ - $(SndWavDir)\se_squeak_G.wav $(SndWavDir)\se_squeak_G_sharp.wav \ - $(SndWavDir)\sound_Bell.wav $(SndWavDir)\sound_Bugle_A.wav \ - $(SndWavDir)\sound_Bugle_B.wav $(SndWavDir)\sound_Bugle_C.wav \ - $(SndWavDir)\sound_Bugle_D.wav $(SndWavDir)\sound_Bugle_E.wav \ - $(SndWavDir)\sound_Bugle_F.wav $(SndWavDir)\sound_Bugle_G.wav \ - $(SndWavDir)\sound_Drum_Of_Earthquake.wav \ - $(SndWavDir)\sound_Fire_Horn.wav $(SndWavDir)\sound_Frost_Horn.wav \ - $(SndWavDir)\sound_Leather_Drum.wav $(SndWavDir)\sound_Magic_Harp_A.wav \ - $(SndWavDir)\sound_Magic_Harp_B.wav $(SndWavDir)\sound_Magic_Harp_C.wav \ - $(SndWavDir)\sound_Magic_Harp_D.wav $(SndWavDir)\sound_Magic_Harp_E.wav \ - $(SndWavDir)\sound_Magic_Harp_F.wav $(SndWavDir)\sound_Magic_Harp_G.wav \ - $(SndWavDir)\sound_Magic_Flute_A.wav \ - $(SndWavDir)\sound_Magic_Flute_B.wav $(SndWavDir)\sound_Magic_Flute_C.wav \ - $(SndWavDir)\sound_Magic_Flute_D.wav $(SndWavDir)\sound_Magic_Flute_E.wav \ - $(SndWavDir)\sound_Magic_Flute_F.wav $(SndWavDir)\sound_Magic_Flute_G.wav \ - $(SndWavDir)\sound_Tooled_Horn_A.wav $(SndWavDir)\sound_Tooled_Horn_B.wav \ - $(SndWavDir)\sound_Tooled_Horn_C.wav $(SndWavDir)\sound_Tooled_Horn_D.wav \ - $(SndWavDir)\sound_Tooled_Horn_E.wav $(SndWavDir)\sound_Tooled_Horn_F.wav \ - $(SndWavDir)\sound_Tooled_Horn_G.wav $(SndWavDir)\sound_Wooden_Flute_A.wav \ - $(SndWavDir)\sound_Wooden_Flute_B.wav $(SndWavDir)\sound_Wooden_Flute_C.wav \ - $(SndWavDir)\sound_Wooden_Flute_D.wav $(SndWavDir)\sound_Wooden_Flute_E.wav \ - $(SndWavDir)\sound_Wooden_Flute_F.wav $(SndWavDir)\sound_Wooden_Flute_G.wav \ - $(SndWavDir)\sound_Wooden_Harp_A.wav $(SndWavDir)\sound_Wooden_Harp_B.wav \ - $(SndWavDir)\sound_Wooden_Harp_C.wav $(SndWavDir)\sound_Wooden_Harp_D.wav \ - $(SndWavDir)\sound_Wooden_Harp_E.wav $(SndWavDir)\sound_Wooden_Harp_F.wav \ - $(SndWavDir)\sound_Wooden_Harp_G.wav $(SndWavDir)\sa2_xpleveldown.wav \ - $(SndWavDir)\sa2_xplevelup.wav +WAVS = $(SndWavDir)se_squeak_A.wav $(SndWavDir)se_squeak_B.wav \ + $(SndWavDir)se_squeak_B_flat.wav $(SndWavDir)se_squeak_C.wav \ + $(SndWavDir)se_squeak_D.wav $(SndWavDir)se_squeak_D_flat.wav \ + $(SndWavDir)se_squeak_E.wav $(SndWavDir)se_squeak_E_flat.wav \ + $(SndWavDir)se_squeak_F.wav $(SndWavDir)se_squeak_F_sharp.wav \ + $(SndWavDir)se_squeak_G.wav $(SndWavDir)se_squeak_G_sharp.wav \ + $(SndWavDir)sound_Bell.wav $(SndWavDir)sound_Bugle_A.wav \ + $(SndWavDir)sound_Bugle_B.wav $(SndWavDir)sound_Bugle_C.wav \ + $(SndWavDir)sound_Bugle_D.wav $(SndWavDir)sound_Bugle_E.wav \ + $(SndWavDir)sound_Bugle_F.wav $(SndWavDir)sound_Bugle_G.wav \ + $(SndWavDir)sound_Drum_Of_Earthquake.wav \ + $(SndWavDir)sound_Fire_Horn.wav $(SndWavDir)sound_Frost_Horn.wav \ + $(SndWavDir)sound_Leather_Drum.wav $(SndWavDir)sound_Magic_Harp_A.wav \ + $(SndWavDir)sound_Magic_Harp_B.wav $(SndWavDir)sound_Magic_Harp_C.wav \ + $(SndWavDir)sound_Magic_Harp_D.wav $(SndWavDir)sound_Magic_Harp_E.wav \ + $(SndWavDir)sound_Magic_Harp_F.wav $(SndWavDir)sound_Magic_Harp_G.wav \ + $(SndWavDir)sound_Magic_Flute_A.wav \ + $(SndWavDir)sound_Magic_Flute_B.wav $(SndWavDir)sound_Magic_Flute_C.wav \ + $(SndWavDir)sound_Magic_Flute_D.wav $(SndWavDir)sound_Magic_Flute_E.wav \ + $(SndWavDir)sound_Magic_Flute_F.wav $(SndWavDir)sound_Magic_Flute_G.wav \ + $(SndWavDir)sound_Tooled_Horn_A.wav $(SndWavDir)sound_Tooled_Horn_B.wav \ + $(SndWavDir)sound_Tooled_Horn_C.wav $(SndWavDir)sound_Tooled_Horn_D.wav \ + $(SndWavDir)sound_Tooled_Horn_E.wav $(SndWavDir)sound_Tooled_Horn_F.wav \ + $(SndWavDir)sound_Tooled_Horn_G.wav $(SndWavDir)sound_Wooden_Flute_A.wav \ + $(SndWavDir)sound_Wooden_Flute_B.wav $(SndWavDir)sound_Wooden_Flute_C.wav \ + $(SndWavDir)sound_Wooden_Flute_D.wav $(SndWavDir)sound_Wooden_Flute_E.wav \ + $(SndWavDir)sound_Wooden_Flute_F.wav $(SndWavDir)sound_Wooden_Flute_G.wav \ + $(SndWavDir)sound_Wooden_Harp_A.wav $(SndWavDir)sound_Wooden_Harp_B.wav \ + $(SndWavDir)sound_Wooden_Harp_C.wav $(SndWavDir)sound_Wooden_Harp_D.wav \ + $(SndWavDir)sound_Wooden_Harp_E.wav $(SndWavDir)sound_Wooden_Harp_F.wav \ + $(SndWavDir)sound_Wooden_Harp_G.wav $(SndWavDir)sa2_xpleveldown.wav \ + $(SndWavDir)sa2_xplevelup.wav !IF "$(HAVE_SOUNDLIB)" == "Y" !IF "$(NEED_USERSOUNDS)" == "Y" @@ -943,37 +1104,40 @@ RCFLAGS = $(RCFLAGS) -dRCWAV # Header file macros #========================================== -CONFIG_H = $(INCL)\config.h $(INCL)\config1.h $(INCL)\patchlevel.h \ - $(INCL)\tradstdc.h $(INCL)\global.h $(INCL)\coord.h \ - $(INCL)\vmsconf.h $(INCL)\cstd.h $(INCL)\nhlua.h \ - $(INCL)\unixconf.h $(INCL)\pcconf.h $(INCL)\micro.h \ - $(INCL)\windconf.h $(INCL)\warnings.h \ - $(INCL)\fnamesiz.h +# config.h +CONFIG_H = $(INCL)color.h $(INCL)config.h $(INCL)config1.h \ + $(INCL)coord.h $(INCL)cstd.h $(INCL)fnamesiz.h \ + $(INCL)global.h $(INCL)integer.h $(INCL)micro.h \ + $(INCL)patchlevel.h $(INCL)pcconf.h \ + $(INCL)tradstdc.h $(INCL)unixconf.h \ + $(INCL)vmsconf.h $(INCL)warnings.h \ + $(INCL)windconf.h -HACK_H = $(INCL)\hack.h $(CONFIG_H) $(INCL)\lint.h $(INCL)\align.h \ - $(INCL)\dungeon.h $(INCL)\sym.h $(INCL)\defsym.h \ - $(INCL)\mkroom.h $(INCL)\artilist.h \ - $(INCL)\objclass.h $(INCL)\objects.h \ - $(INCL)\youprop.h $(INCL)\prop.h $(INCL)\permonst.h \ - $(INCL)\monattk.h $(INCL)\monflag.h \ - $(INCL)\monsters.h $(INCL)\mondata.h \ - $(INCL)\wintype.h $(INCL)\context.h $(INCL)\rm.h \ - $(INCL)\botl.h $(INCL)\rect.h $(INCL)\region.h \ - $(INCL)\display.h $(INCL)\vision.h $(INCL)\color.h \ - $(INCL)\decl.h $(INCL)\quest.h $(INCL)\spell.h \ - $(INCL)\obj.h $(INCL)\engrave.h $(INCL)\you.h \ - $(INCL)\attrib.h $(INCL)\monst.h $(INCL)\mextra.h \ - $(INCL)\skills.h $(INCL)\timeout.h $(INCL)\trap.h \ - $(INCL)\flag.h $(INCL)\winprocs.h $(INCL)\sndprocs.h \ - $(INCL)\seffects.h $(INCL)\sys.h +# hack.h +HACK_H = $(CONFIG_H) $(INCL)align.h $(INCL)artilist.h \ + $(INCL)attrib.h $(INCL)botl.h $(INCL)context.h \ + $(INCL)decl.h $(INCL)defsym.h $(INCL)display.h \ + $(INCL)dungeon.h $(INCL)engrave.h $(INCL)flag.h \ + $(INCL)hack.h $(INCL)lint.h $(INCL)mextra.h \ + $(INCL)mkroom.h $(INCL)monattk.h $(INCL)mondata.h \ + $(INCL)monflag.h $(INCL)monst.h $(INCL)monsters.h \ + $(INCL)nhlua.h $(INCL)obj.h $(INCL)objclass.h \ + $(INCL)objects.h $(INCL)permonst.h $(INCL)prop.h \ + $(INCL)quest.h $(INCL)rect.h $(INCL)region.h \ + $(INCL)rm.h $(INCL)seffects.h $(INCL)selvar.h \ + $(INCL)skills.h $(INCL)sndprocs.h $(INCL)spell.h \ + $(INCL)stairs.h $(INCL)sym.h $(INCL)sys.h \ + $(INCL)timeout.h $(INCL)trap.h $(INCL)vision.h \ + $(INCL)winprocs.h $(INCL)wintype.h $(INCL)you.h \ + $(INCL)youprop.h -TILE_H = ..\win\share\tile.h +TILE_H = $(WSHR)tile.h #========================================== # Miscellaneous #========================================== -DATABASE = $(DAT)\data.base +DATABASE = $(DAT)data.base #========================================== #========================================== @@ -986,17 +1150,20 @@ DATABASE = $(DAT)\data.base # #CTAGSCMD=ctags-orig.exe !IF "$(CI_BUILD_DIR)" != "" -CTAGSCMD=$(LIBDIR)\ctags\ctags.exe +R_CTAGSDIR=$(LIBDIR)ctags +CTAGSDIR=$(R_CTAGSDIR)$(BACKSLASH) +#U_CTAGSDIR=$(CTAGSDIR:\=/) !ELSE -CTAGSCMD=..\..\..\ctags\ctags.exe +R_CTAGSDIR=..\..\..\ctags +CTAGSDIR=$(R_CTAGSDIR)$(BACKSLASH) +#U_CTAGSDIR=$(CTAGSDIR:\=/) !ENDIF +CTAGSCMD=$(CTAGSDIR)ctags.exe CTAGSOPT =--language-force=c --sort=no -D"Bitfield(x,n)=unsigned x : n" --excmd=pattern # # ctags wants unix-style pathnames # -TINC = $(INCL:\=/) -TSRC = $(SRC:\=/) cc=cl.exe cpp=cpp.exe @@ -1180,14 +1347,14 @@ conlibs = $(baselibs) guilibs = $(winlibs) # -INCLDIR= /I..\include /I..\sys\windows $(LUAINCL) $(SOUNDLIBINCL) +INCLUSIONS= /I$(R_INCL) /I$(R_MSWSYS) $(R_LUAINCL) $(R_SOUNDLIBINCL) #========================================== # Util and console builds #========================================== -CFLAGS = $(ctmpflags) $(INCLDIR) $(DLBDEF) -DSAFEPROCS $(SOUNDLIBDEFS) -CPPFLAGS = $(cpptmpflags) $(INCLDIR) $(DLBDEF) -DSAFEPROCS $(SOUNDLIBDEFS) +CFLAGS = $(ctmpflags) $(INCLUSIONS) $(DLBDEF) -DSAFEPROCS $(SOUNDLIBDEFS) +CPPFLAGS = $(cpptmpflags) $(INCLUSIONS) $(DLBDEF) -DSAFEPROCS $(SOUNDLIBDEFS) LFLAGS = $(lflags) $(conlibs) $(MACHINE) #========================================== @@ -1212,181 +1379,192 @@ DLB = # Rules for files in src #========================================== -.c{$(OBJTTY)}.o: +.c{$(R_OBJTTY)}.o: $(Q)$(CC) $(CFLAGS) $(TTYDEF) $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) -Fo$@ $< -.c{$(OBJGUI)}.o: +.c{$(R_OBJGUI)}.o: $(Q)$(CC) $(CFLAGS) $(GUIDEF) $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) -Fo$@ $< -.c{$(OBJUTIL)}.o: +.c{$(R_OBJUTIL)}.o: $(Q)$(CC) $(CFLAGS) $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) -Fo$@ $< -{$(SRC)}.c{$(OBJTTY)}.o: +{$(R_SRC)}.c{$(R_OBJTTY)}.o: $(Q)$(CC) $(CFLAGS) $(TTYDEF) $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) -Fo$@ $< -{$(SRC)}.c{$(OBJGUI)}.o: +{$(R_SRC)}.c{$(R_OBJGUI)}.o: $(Q)$(CC) $(CFLAGS) $(GUIDEF) $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) -Fo$@ $< -{$(SRC)}.c{$(OBJUTIL)}.o: +{$(R_SRC)}.c{$(R_OBJUTIL)}.o: $(Q)$(CC) $(CFLAGS) $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) -Fo$@ $< #========================================== # Rules for files in sound\windsound #========================================== -{..\sound\windsound}.c{$(OBJTTY)}.o: - $(Q)$(CC) $(CFLAGS) -I$(WSHR) $(TTYDEF) $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) -Fo$@ $< +{$(R_WINDSOUNDDIR)}.c{$(R_OBJTTY)}.o: + $(Q)$(CC) $(CFLAGS) -I$(R_WSHR) $(TTYDEF) $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) -Fo$@ $< -{..\sound\windsound}.c{$(OBJGUI)}.o: - $(Q)$(CC) $(CFLAGS) -I$(WSHR) $(GUIDEF) $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) -Fo$@ $< +{$(R_WINDSOUNDDIR)}.c{$(R_OBJGUI)}.o: + $(Q)$(CC) $(CFLAGS) -I$(R_WSHR) $(GUIDEF) $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) -Fo$@ $< #========================================== # Rules for files in sound\sample #========================================== -{..\sound\sample}.c{$(OBJTTY)}.o: - $(Q)$(CC) $(CFLAGS) -I$(WSHR) $(TTYDEF) $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) -Fo$@ $< +{$(SOUNDDIR)sample}.c{$(R_OBJTTY)}.o: + $(Q)$(CC) $(CFLAGS) -I$(R_WSHR) $(TTYDEF) $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) -Fo$@ $< -{..\sound\sample}.c{$(OBJGUI)}.o: - $(Q)$(CC) $(CFLAGS) -I$(WSHR) $(GUIDEF) $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) -Fo$@ $< +{$(SOUNDDIR)sample}.c{$(R_OBJGUI)}.o: + $(Q)$(CC) $(CFLAGS) -I$(R_WSHR) $(GUIDEF) $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) -Fo$@ $< #========================================== # Rules for files in sys\share #========================================== -{$(SSYS)}.c{$(OBJTTY)}.o: +{$(R_SSYS)}.c{$(R_OBJTTY)}.o: $(Q)$(CC) $(CFLAGS) $(TTYDEF) $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) -Fo$@ $< -{$(SSYS)}.c{$(OBJGUI)}.o: +{$(R_SSYS)}.c{$(R_OBJGUI)}.o: $(Q)$(CC) $(CFLAGS) $(GUIDEF) $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) -Fo$@ $< -{$(SSYS)}.c{$(OBJUTIL)}.o: +{$(R_SSYS)}.c{$(R_OBJUTIL)}.o: $(Q)$(CC) $(CFLAGS) $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) -Fo$@ $< -{$(SSYS)}.cpp{$(OBJTTY)}.o: +{$(R_SSYS)}.cpp{$(R_OBJTTY)}.o: $(Q)$(CC) $(CPPFLAGS) $(TTYDEF) $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) /EHsc -Fo$@ $< -{$(SSYS)}.cpp{$(OBJGUI)}.o: +{$(R_SSYS)}.cpp{$(R_OBJGUI)}.o: $(Q)$(CC) $(CPPFLAGS) $(GUIDEF) $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) /EHsc -Fo$@ $< -{$(SSYS)}.cpp{$(OBJUTIL)}.o: +{$(R_SSYS)}.cpp{$(R_OBJUTIL)}.o: $(Q)$(CC) $(CPPFLAGS) $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) /EHsc -Fo$@ $< #========================================== # Rules for files in sys\windows #========================================== -{$(MSWSYS)}.c{$(OBJTTY)}.o: +{$(R_MSWSYS)}.c{$(R_OBJTTY)}.o: $(Q)$(CC) $(CFLAGS) $(TTYDEF) -Fo$@ $< -{$(MSWSYS)}.c{$(OBJGUI)}.o: +{$(R_MSWSYS)}.c{$(R_OBJGUI)}.o: $(Q)$(CC) $(CFLAGS) -I$(MSWSYS) $(GUIDEF) -Fo$@ $< -{$(MSWSYS)}.uu{$(MSWSYS)}.bmp: +{$(R_MSWSYS)}.uu{$(R_MSWSYS)}.bmp: $(U)uudecode.exe $< - move $(SRC)\$(@B).bmp $@ + move $(SRC)$(@B).bmp $@ #========================================== # Rules for files in util #========================================== -{$(UTIL)}.c{$(OBJUTIL)}.o: +{$(R_UTIL)}.c{$(R_OBJUTIL)}.o: $(Q)$(CC) $(CFLAGS) -Fo$@ $< #========================================== # Rules for files in win\share #========================================== -{$(WSHR)}.c{$(OBJTTY)}.o: - $(Q)$(CC) $(CFLAGS) -I$(WSHR) $(TTYDEF) $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) -Fo$@ $< +{$(R_WSHR)}.c{$(R_OBJTTY)}.o: + $(Q)$(CC) $(CFLAGS) -I$(R_WSHR) $(TTYDEF) $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) -Fo$@ $< -{$(WSHR)}.c{$(OBJGUI)}.o: - $(Q)$(CC) $(CFLAGS) -I$(WSHR) $(GUIDEF) $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) -Fo$@ $< +{$(R_WSHR)}.c{$(R_OBJGUI)}.o: + $(Q)$(CC) $(CFLAGS) -I$(R_WSHR) $(GUIDEF) $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) -Fo$@ $< -{$(WSHR)}.c{$(OBJUTIL)}.o: - $(Q)$(CC) $(CFLAGS) -I$(WSHR) $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) -Fo$@ $< +{$(R_WSHR)}.c{$(R_OBJUTIL)}.o: + $(Q)$(CC) $(CFLAGS) -I$(R_WSHR) $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) -Fo$@ $< #========================================== # Rules for files in win\tty #========================================== -{$(TTY)}.c{$(OBJTTY)}.o: - $(Q)$(CC) $(CFLAGS) $(TTYDEF) -I$(MSWSYS) $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) -Fo$@ $< +{$(R_TTY)}.c{$(R_OBJTTY)}.o: + $(Q)$(CC) $(CFLAGS) $(TTYDEF) -I$(R_MSWSYS) $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) -Fo$@ $< #========================================== # Rules for files in win\win32 #========================================== -{$(MSWIN)}.c{$(OBJGUI)}.o: - $(Q)$(CC) $(CFLAGS) $(GUIDEF) -I$(MSWSYS) -I$(MSWIN) $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) -Fo$@ $< +{$(R_MSWIN)}.c{$(R_OBJGUI)}.o: + $(Q)$(CC) $(CFLAGS) $(GUIDEF) -I$(R_MSWSYS) -I$(R_MSWIN) $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) -Fo$@ $< -{$(MSWIN)}.uu{$(MSWIN)}.bmp: +{$(R_MSWIN)}.uu{$(R_MSWIN)}.bmp: $(U)uudecode.exe $< - move $(SRC)\$(@B).bmp $@ + move $(SRC)$(@B).bmp $@ #========================================== # Rules for files in win\curses #========================================== -{$(WCURSES)}.c{$(OBJTTY)}.o: - $(Q)$(CC) $(PDCINCL) $(CFLAGS) $(CURSESCONDEF1) $(CURSESGUIDEF1) $(CURSESDEF2) $(TTYDEF) $(GUIDEF) $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) -Fo$@ $< +#!MESSAGE INCLCURSES_H=$(INCLCURSES_H) + +{$(R_WCURSES)}.c{$(R_OBJTTY)}.o: + $(Q)$(CC) $(INCLCURSES_H) $(CFLAGS) $(CURSESCONDEF1) $(CURSESGUIDEF1) $(CURSESDEF2) $(TTYDEF) $(GUIDEF) $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) -Fo$@ $< #========================================== # Rules for files in PDCurses #========================================== +#!MESSAGE {$(R_PDCURSES_TOP)}.c{$(R_OBJPDC)}.o: +#!MESSAGE {$(R_PDCSRC)}.c{$(R_OBJPDC)}.o: +#!MESSAGE PDCINCL = $(PDCINCL) +#!MESSAGE PDCINCLGUI = $(PDCINCLGUI) +#!MESSAGE PDCINCLCON = $(PDCINCLCON) +#!MESSAGE $(Q)$(CC) /wd4244 /wd4267 /wd4774 $(R_PDCINCL) $(CFLAGS:-w44774= ) $(CURSESDEF2) /wd5262 $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) -FoX2 X1 # !IF "$(ADD_CURSES)" == "Y" -{$(PDCURSES_TOP)}.c{$(OBJPDC)}.o: +{$(R_PDCURSES_TOP)}.c{$(R_OBJPDC)}.o: $(Q)$(CC) /wd4244 $(PDCINCL) $(CFLAGS) $(CURSESDEF2) /wd5262 $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) -Fo$@ $< -{$(PDCSRC)}.c{$(OBJPDC)}.o: +{$(R_PDCSRC)}.c{$(R_OBJPDC)}.o: $(Q)$(CC) /wd4244 /wd4267 /wd4774 $(PDCINCL) $(CFLAGS:-w44774= ) $(CURSESDEF2) /wd5262 $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) -Fo$@ $< !IF "$(CURSES_CONSOLE)" == "Y" -{$(PDCWINCON)}.c{$(OBJPDCC)}.o: +{$(R_PDCWINCON)}.c{$(R_OBJPDCC)}.o: $(Q)$(CC) /wd4244 /wd4267 /wd4774 $(PDCINCL) $(PDCINCLCON) $(CFLAGS) $(CURSESDEF2) /wd5262 $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) -Fo$@ $< +#!MESSAGE {$(R_PDCWINCON)}.c{$(R_OBJPDCC)}.o: !ENDIF !IF "$(CURSES_GRAPHICAL)" == "Y" -{$(PDCWINGUI)}.c{$(OBJPDCG)}.o: +{$(R_PDCWINGUI)}.c{$(R_OBJPDCG)}.o: $(Q)$(CC) /wd4244 /wd4267 /wd4774 $(PDCINCL) $(PDCINCLGUI) $(CFLAGS) $(CURSESDEF2) /wd5262 $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) -Fo$@ $< +#!MESSAGE {$(R_PDCWINGUI)}.c{$(R_OBJPDCG)}.o: !ENDIF !ENDIF + #========================================== # Rules for LUA files #========================================== -{$(LUASRC)}.c{$(OBJLUA)}.o: +{$(R_LUASRC)}.c{$(R_OBJLUA)}.o: $(Q)$(CC) $(CFLAGS) -wd4701 -wd4702 -wd4774 -wd4324 -wd5262 $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) -Fo$@ $< #=============================================================================== # Rules for integrated sound files in sound/wav #=============================================================================== -{$(SndWavDir)}.uu{$(SndWavDir)}.wav: - $(U)uudecode.exe $(SndWavDir)\$(@B).uu - move $(SRC)\$(@B).wav $(SndWavDir)\$(@B).wav +{$(R_SndWavDir)}.uu{$(R_SndWavDir)}.wav: + $(U)uudecode.exe $(SndWavDir)$(@B).uu + move $(SRC)$(@B).wav $(SndWavDir)$(@B).wav #========================================== # Rules for files in sound\windsound #========================================== -{$(WINDSOUNDDIR)}.c{$(OBJTTY)}.o: - $(Q)$(CC) $(CFLAGS) -I$(WSHR) $(TTYDEF) $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) -Fo$@ $< +{$(R_WINDSOUNDDIR)}.c{$(R_OBJTTY)}.o: + $(Q)$(CC) $(CFLAGS) -I$(R_WSHR) $(TTYDEF) $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) -Fo$@ $< -{$(WINDSOUNDDIR)}.c{$(OBJGUI)}.o: - $(Q)$(CC) $(CFLAGS) -I$(WSHR) $(GUIDEF) $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) -Fo$@ $< +{$(R_WINDSOUNDDIR)}.c{$(R_OBJGUI)}.o: + $(Q)$(CC) $(CFLAGS) -I$(R_WSHR) $(GUIDEF) $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) -Fo$@ $< #========================================== # Rules for files in sound\fmod #========================================== -{$(FMODDIR)}.c{$(OBJTTY)}.o: - $(Q)$(CC) $(CFLAGS) $(FMODFLAGS) -I$(WSHR) $(TTYDEF) $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) -Fo$@ $< +{$(R_FMODDIR)}.c{$(R_OBJTTY)}.o: + $(Q)$(CC) $(CFLAGS) $(FMODFLAGS) -I$(R_WSHR) $(TTYDEF) $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) -Fo$@ $< -{$(FMODDIR)}.c{$(OBJGUI)}.o: - $(Q)$(CC) $(CFLAGS) $(FMODFLAGS) -I$(WSHR) $(GUIDEF) $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) -Fo$@ $< +{$(R_FMODDIR)}.c{$(R_OBJGUI)}.o: + $(Q)$(CC) $(CFLAGS) $(FMODFLAGS) -I$(R_WSHR) $(GUIDEF) $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) -Fo$@ $< #========================================== #=============== TARGETS ================== @@ -1403,17 +1581,17 @@ all : package !IF "$(INTERNET_AVAILABLE)" == "Y" !IF "$(GIT_AVAILABLE)" == "Y" -$(LUASRC)\lua.h: - git submodule init ../submodules/lua - git submodule update ../submodules/lua -# git submodule update --remote ../submodules/lua +$(LUASRC)lua.h: + git submodule init $(SUBM)lua + git submodule update $(SUBM)lua +# git submodule update --remote $(SUBM)lua # #aka PDCDEP !IF "$(ADD_CURSES)" == "Y" -$(PDCURSES_TOP)\curses.h: - git submodule init ../submodules/$(PDCDIST) - git submodule update ../submodules/$(PDCDIST) -# git submodule update --remote ../submodules/$(PDCDIST) +$(PDCURSES_TOP)curses.h: + git submodule init $(SUBM)$(R_PDCDIST) + git submodule update $(SUBM)$(R_PDCDIST) +# git submodule update --remote $(SUBM)$(R_PDCDIST) !ENDIF !ELSE # GIT_AVAILABLE no CURLLUASRC=http://www.lua.org/ftp/lua-5.4.6.tar.gz @@ -1423,26 +1601,26 @@ CURLLUADST=lua-5.4.6.tar.gz CURLPDCSRC=https://github.com/Bill-Gray/PDCursesMod/archive/refs/tags/v4.4.0.zip CURLPDCDST=$(PDCDIST).zip -$(LUASRC)\lua.h: - @if not exist $(LIBDIR)\*.* mkdir $(LIBDIR) - cd $(LIBDIR) +$(LUASRC)lua.h: + @if not exist $(LIBDIR)*.* mkdir $(R_LIBDIR) + cd $(R_LIBDIR) curl -L $(CURLLUASRC) -o $(CURLLUADST) tar -xvf $(CURLLUADST) - cd ..\src + cd $(R_SRC) !IF "$(ADD_CURSES)" == "Y" -$(PDCURSES_TOP)\curses.h: - @if not exist $(LIBDIR)\*.* mkdir $(LIBDIR) +$(PDCURSES_TOP)curses.h: + @if not exist $(LIBDIR)*.* mkdir $(R_LIBDIR) cd $(LIBDIR) curl -L $(CURLPDCSRC) -o $(CURLPDCDST) - if not exist $(PDCDIST)\*.* mkdir $(PDCDIST) - tar -C $(PDCDIST) --strip-components=1 -xvf $(CURLPDCDST) - cd ..\src + if not exist $(PDCDIST)*.* mkdir $(R_PDCDIST) + tar -C $(R_PDCDIST) --strip-components=1 -xvf $(CURLPDCDST) + cd $(R_SRC) !ENDIF # ADD_CURSES !ENDIF # GIT_AVAILABLE !ELSE # INTERNET_AVAILABLE -$(LUASRC)\lua.h: +$(LUASRC)lua.h: !IF "$(ADD_CURSES)" == "Y" -$(PDCURSES_TOP)\curses.h: +$(PDCURSES_TOP)curses.h: !ENDIF !ENDIF # INTERNET_AVAILABLE @@ -1486,18 +1664,18 @@ GAMEOBJ=$(GAMEOBJ:^ =^ #-------- # -$(GAMEDIR)\NetHack.exe : gamedir.tag $(OTTY)consoletty.o \ +$(GAMEDIR)NetHack.exe : gamedir.tag $(OTTY)consoletty.o \ $(ALLOBJTTY) $(CURSESWINCONOBJS) \ $(TTYSOUNDOBJS) $(OTTY)date.o $(OTTY)console.res \ - $(LUALIB) $(TTYOBJ) $(PDCWINCONLIB) $(PDCWINCONOBJS) $(OTTYHACKLIB) - @if not exist $(GAMEDIR)\*.* mkdir $(GAMEDIR) + $(LUALIB) $(TTYOBJTTY) $(PDCWINCONLIB) $(PDCWINCONOBJS) $(OTTYHACKLIB) + @if not exist $(GAMEDIR)*.* mkdir $(R_GAMEDIR) @echo Linking $(@:\=/) - $(link) $(LFLAGS) $(conlflags) /STACK:2048 /PDB:$(GAMEDIR)\$(@B).PDB /MAP:$(OTTY)$(@B).MAP \ + $(link) $(LFLAGS) $(conlflags) /STACK:2048 /PDB:$(GAMEDIR)$(@B).PDB /MAP:$(OTTY)$(@B).MAP \ $(LIBS) $(PDCWINCONLIB) $(LUALIB) $(TTYSOUNDLIBS) $(OTTYHACKLIB) \ $(conlibs) $(BCRYPT) -out:$@ @<<$(@B).lnk $(GAMEOBJTTY) $(ALLOBJTTY) - $(TTYOBJ) + $(TTYOBJTTY) $(TTYSOUNDOBJS) $(CURSESWINCONOBJS) $(PDCWINCONOBJS) $(OTTY)consoletty.o $(OTTY)date.o @@ -1509,14 +1687,14 @@ $(GAMEDIR)\NetHack.exe : gamedir.tag $(OTTY)consoletty.o \ # NetHackW #--------- # -$(GAMEDIR)\NetHackW.exe : gamedir.tag $(OGUI)tile.o \ +$(GAMEDIR)NetHackW.exe : gamedir.tag $(OGUI)tile.o \ $(ALLOBJGUI) $(GAMEOBJGUI) $(GUIOBJ) $(GUISOUNDOBJS) \ $(CURSESWINGUIOBJS) $(OGUI)date.o \ $(OGUI)NetHackW.res \ $(LUALIB) $(PDCWINGUILIB) $(PDCWINGUIOBJS) $(OGUIHACKLIB) - @if not exist $(GAMEDIR)\*.* mkdir $(GAMEDIR) + @if not exist $(GAMEDIR)*.* mkdir $(R_GAMEDIR) @echo Linking $(@:\=/) - $(link) $(LFLAGS) $(guilflags) /STACK:2048 /PDB:$(GAMEDIR)\$(@B).PDB \ + $(link) $(LFLAGS) $(guilflags) /STACK:2048 /PDB:$(GAMEDIR)$(@B).PDB \ /MAP:$(OGUI)$(@B).MAP \ $(LIBS) $(PDCWINGUILIB) $(LUALIB) \ $(GUISOUNDLIBS) $(OGUIHACKLIB) \ @@ -1534,58 +1712,58 @@ $(GAMEDIR)\NetHackW.exe : gamedir.tag $(OGUI)tile.o \ # install #-------- # -binary.tag: $(DAT)\data $(DAT)\rumors $(DAT)\oracles $(DLB) \ +binary.tag: $(DAT)data $(DAT)rumors $(DAT)oracles $(DLB) \ $(HACKCSRC) $(SOUNDSRCS) -! IF ("$(USE_DLB)"=="Y") copy nhdat$(NHV) $(GAMEDIR) - copy $(DAT)\license $(GAMEDIR) - copy $(DAT)\opthelp $(GAMEDIR) + copy $(DAT)license $(GAMEDIR) + if exist $(DAT)opthelp copy $(DAT)opthelp $(GAMEDIR) + if exist $(MSWSYS)sysconf.template copy $(MSWSYS)sysconf.template $(GAMEDIR) + if exist $(DAT)symbols copy $(DAT)symbols $(GAMEDIR)symbols + if exist $(DOC)guidebook.txt copy $(DOC)guidebook.txt $(GAMEDIR)Guidebook.txt + if exist $(DOC)nethack.txt copy $(DOC)nethack.txt $(GAMEDIR)NetHack.txt + @if exist $(GAMEDIR)NetHack.PDB echo NOTE: You may want to remove $(U_GAMEDIR)/NetHack.PDB to conserve space + @if exist $(GAMEDIR)NetHackW.PDB echo NOTE: You may want to remove $(U_GAMEDIR)/NetHackW.PDB to conserve space + -if exist $(MSWSYS)nethackrc.template copy $(MSWSYS)nethackrc.template $(R_GAMEDIR) + -if not exist $(GAMEDIR)record. goto>$(GAMEDIR)record. +! IF ("$(USE_DLB)" == "Y") + copy /Y nhdat$(NHV) $(GAMEDIR) ! ELSE - copy $(DAT)\bogusmon $(GAMEDIR) - copy $(DAT)\cmdhelp $(GAMEDIR) - copy $(DAT)\data $(GAMEDIR) - copy $(DAT)\dungeon $(GAMEDIR) - copy $(DAT)\engrave $(GAMEDIR) - copy $(DAT)\epitaph $(GAMEDIR) - copy $(DAT)\help $(GAMEDIR) - copy $(DAT)\hh $(GAMDEDIR) - copy $(DAT)\history $(GAMEDIR) - copy $(DAT)\license $(GAMEDIR) - copy $(DAT)\optmenu $(GAMEDIR) - copy $(DAT)\oracles $(GAMEDIR) - copy $(DAT)\rumors $(GAMEDIR) - copy $(DAT)\symbols $(GAMEDIR) - copy $(DAT)\tribute $(GAMEDIR) - copy $(DAT)\wizhelp $(GAMEDIR) - copy $(DAT)\*.lua $(GAMEDIR) - if exist $(DAT)\guioptions copy $(DAT)\guioptions $(GAMEDIR) - if exist $(DAT)\keyhelp copy $(DAT)\keyhelp $(GAMEDIR) - if exist $(DAT)\opthelp copy $(DAT)\opthelp $(GAMEDIR) - if exist $(DAT)\options copy $(DAT)\options $(GAMEDIR) - if exist $(DAT)\porthelp copy $(DAT)\porthelp $(GAMEDIR) - if exist $(DAT)\ttyoptions copy $(DAT)\ttyoptions $(GAMEDIR) + copy $(DAT)bogusmon $(GAMEDIR) + copy $(DAT)cmdhelp $(GAMEDIR) + copy $(DAT)data $(GAMEDIR) + copy $(DAT)dungeon $(GAMEDIR) + copy $(DAT)engrave $(GAMEDIR) + copy $(DAT)epitaph $(GAMEDIR) + copy $(DAT)help $(GAMEDIR) + copy $(DAT)hh $(GAMDEDIR) + copy $(DAT)history $(GAMEDIR) + copy $(DAT)license $(GAMEDIR) + copy $(DAT)optmenu $(GAMEDIR) + copy $(DAT)oracles $(GAMEDIR) + copy $(DAT)rumors $(GAMEDIR) + copy $(DAT)symbols $(GAMEDIR) + copy $(DAT)tribute $(GAMEDIR) + copy $(DAT)wizhelp $(GAMEDIR) + copy /Y $(DAT)*.lua $(GAMEDIR) + if exist $(DAT)guioptions copy $(DAT)guioptions $(GAMEDIR) + if exist $(DAT)keyhelp copy $(DAT)keyhelp $(GAMEDIR) + if exist $(DAT)options copy $(DAT)options $(GAMEDIR) + if exist $(DAT)porthelp copy $(DAT)porthelp $(GAMEDIR) + if exist $(DAT)ttyoptions copy $(DAT)ttyoptions $(GAMEDIR) ! ENDIF - if exist $(MSWSYS)\sysconf.template copy $(MSWSYS)\sysconf.template $(GAMEDIR) - if exist $(DAT)\symbols copy $(DAT)\symbols $(GAMEDIR)\symbols - if exist $(DOC)\guidebook.txt copy $(DOC)\guidebook.txt $(GAMEDIR)\Guidebook.txt - if exist $(DOC)\nethack.txt copy $(DOC)\nethack.txt $(GAMEDIR)\NetHack.txt - @if exist $(GAMEDIR)\NetHack.PDB echo NOTE: You may want to remove $(GAMEDIR:\=/)/NetHack.PDB to conserve space - @if exist $(GAMEDIR)\NetHackW.PDB echo NOTE: You may want to remove $(GAMEDIR:\=/)/NetHackW.PDB to conserve space - -if exist $(MSWSYS)\nethackrc.template copy $(MSWSYS)\nethackrc.template $(GAMEDIR) - -if not exist $(GAMEDIR)\record. goto>$(GAMEDIR)\record. echo binary built > $@ -# copy $(MSWSYS)\windsyshlp $(GAMEDIR) +# copy $(MSWSYS)windsyshlp $(GAMEDIR) recover: $(OUTLHACKLIB) $(U)recover.exe if exist $(U)recover.exe copy $(U)recover.exe $(GAMEDIR) - if exist $(DOC)\recover.txt copy $(DOC)\recover.txt $(GAMEDIR)\recover.txt + if exist $(DOC)recover.txt copy $(DOC)recover.txt $(GAMEDIR)recover.txt -$(OUTL)utility.tag: $(INCL)\nhlua.h outldir$(TARGET_CPU).tag $(OUTLHACKLIB) $(U)tile2bmp.exe $(U)makedefs.exe +$(OUTL)utility.tag: $(INCL)nhlua.h outldir$(TARGET_CPU).tag $(OUTLHACKLIB) $(U)tile2bmp.exe $(U)makedefs.exe @echo utilities made >$@ @echo utilities made. -$(INCL)\nhlua.h: +$(INCL)nhlua.h: @echo /* nhlua.h - generated by Makefile from Makefile.nmake */ > $@ @echo #include "lua.h" >> $@ @echo LUA_API int (lua_error) (lua_State *L) NORETURN; >> $@ @@ -1596,16 +1774,16 @@ $(INCL)\nhlua.h: tileutil: $(U)gif2txt.exe $(U)gif2tx32.exe $(U)txt2ppm.exe @echo Optional tile development utilities are up to date. -$(OGUI)NetHackW.res: $(SRC)\tiles.bmp $(MSWIN)\NetHackW.rc $(MSWIN)\NetHack.ico \ - $(MSWIN)\mnsel.bmp $(MSWIN)\mnselcnt.bmp $(MSWIN)\mnunsel.bmp \ - $(MSWIN)\petmark.bmp $(MSWIN)\pilemark.bmp $(MSWIN)\NetHack.ico \ - $(MSWIN)\rip.bmp $(MSWIN)\splash.bmp $(MSWIN)\NetHackW.exe.manifest $(WAV) +$(OGUI)NetHackW.res: $(SRC)tiles.bmp $(MSWIN)NetHackW.rc $(MSWIN)NetHack.ico \ + $(MSWIN)mnsel.bmp $(MSWIN)mnselcnt.bmp $(MSWIN)mnunsel.bmp \ + $(MSWIN)petmark.bmp $(MSWIN)pilemark.bmp $(MSWIN)NetHack.ico \ + $(MSWIN)rip.bmp $(MSWIN)splash.bmp $(MSWIN)NetHackW.exe.manifest $(WAV) @echo Building resource file $@ from $** - $(rc) -nologo -r -fo$@ -i$(MSWIN) -i$(SndWavDir) -dNDEBUG -dVIA_MAKE $(RCFLAGS) $(MSWIN)\NetHackW.rc + $(rc) -nologo -r -fo$@ -i$(MSWIN) -i$(SndWavDir) -dNDEBUG -dVIA_MAKE $(RCFLAGS) $(MSWIN)NetHackW.rc -$(OTTY)console.res: $(MSWSYS)\console.rc $(MSWSYS)\NetHack.ico $(WAV) +$(OTTY)console.res: $(MSWSYS)console.rc $(MSWSYS)NetHack.ico $(WAV) @echo Building resource file $@ from $** - $(rc) -nologo -r -fo$@ -i$(MSWSYS) -i$(SndWavDir) -dNDEBUG $(RCFLAGS) $(MSWSYS)\console.rc + $(rc) -nologo -r -fo$@ -i$(MSWSYS) -i$(SndWavDir) -dNDEBUG $(RCFLAGS) $(MSWSYS)console.rc # # Secondary Targets. @@ -1625,13 +1803,13 @@ $(U)makedefs.exe: $(OUTLHACKLIB) $(MAKEDEFSOBJS) @echo Linking $(@:\=/) @$(link) $(LFLAGS) /PDB:"$(OUTL)$(@B).PDB" /MAP:"$(OUTL)$(@B).MAP" -out:$@ $(MAKEDEFSOBJS) $(OUTLHACKLIB) -$(OUTL)makedefs.o: $(U)makedefs.c $(SRC)\mdlib.c $(CONFIG_H) $(INCL)\permonst.h \ - $(INCL)\objclass.h $(INCL)\sym.h $(INCL)\defsym.h \ - $(INCL)\artilist.h $(INCL)\dungeon.h $(INCL)\obj.h \ - $(INCL)\monst.h $(INCL)\you.h $(INCL)\flag.h \ - $(INCL)\dlb.h - @if not exist $(OBJTTY)\*.* echo creating directory $(OBJTTY:\=/) - @if not exist $(OBJTTY)\*.* mkdir $(OBJTTY) +$(OUTL)makedefs.o: $(U)makedefs.c $(SRC)mdlib.c $(CONFIG_H) $(INCL)permonst.h \ + $(INCL)objclass.h $(INCL)sym.h $(INCL)defsym.h \ + $(INCL)artilist.h $(INCL)dungeon.h $(INCL)obj.h \ + $(INCL)monst.h $(INCL)you.h $(INCL)flag.h \ + $(INCL)dlb.h + @if not exist $(OBJTTY)*.* echo creating directory $(OBJTTY:\=/) + @if not exist $(OBJTTY)*.* mkdir $(R_OBJTTY) $(Q)$(CC) -DENUM_PM $(CFLAGS) $(TTYDEF) $(CROSSCOMPILE) -Fo$@ $(U)makedefs.c # $(Q)$(CC) -DENUM_PM $(CFLAGS) $(TTYDEF) $(CROSSCOMPILE) /EP -Fo$@ $(U)makedefs.c >$(OUTL)makedefs.c.preproc @@ -1692,13 +1870,13 @@ $(OGUI)date.o: $(HACKINCL) $(HACKSRC) $(HACKOBJ) $(ALLOBJGUI) # onames.h is not used with NetHack 3.7 # pm.h is not used with NetHack 3.7 -$(INCL)\date.h $(OPTIONS_FILE) : $(U)makedefs.exe +$(INCL)date.h $(OPTIONS_FILE) : $(U)makedefs.exe $(U)makedefs -v -$(INCL)\onames.h : $(U)makedefs.exe +$(INCL)onames.h : $(U)makedefs.exe $(U)makedefs -o -$(INCL)\pm.h : $(U)makedefs.exe +$(INCL)pm.h : $(U)makedefs.exe $(U)makedefs -p @@ -1724,25 +1902,27 @@ $(OGUIHACKLIB): $(OGUIHACKLIBOBJS) $(U)uudecode.exe: $(OUTL)uudecode.o @echo Linking $(@:\=/) - @$(link) $(LFLAGS) /PDB:"$(OUTL)$(@B).PDB" /MAP:"$(OUTL)$(@B).MAP" -out:$@ $(OUTL)uudecode.o + @$(link) $(LFLAGS) /PDB:"$(OUTL)$(@B).PDB" /MAP:"$(OUTL)$(@B).MAP" \ + -out:$@ $(OUTL)uudecode.o -$(OUTL)uudecode.o: $(SSYS)\uudecode.c - $(Q)$(CC) $(CFLAGS) -wd4702 $(TTYDEF) $(CROSSCOMPILE) /D_CRT_SECURE_NO_DEPRECATE -Fo$@ $(SSYS)\uudecode.c +$(OUTL)uudecode.o: $(SSYS)uudecode.c + $(Q)$(CC) $(CFLAGS) -wd4702 $(TTYDEF) $(CROSSCOMPILE) \ + /D_CRT_SECURE_NO_DEPRECATE -Fo$@ $(SSYS)uudecode.c -$(MSWIN)\mnsel.bmp: $(U)uudecode.exe $(MSWIN)\mnsel.uu -$(MSWIN)\mnselcnt.bmp: $(U)uudecode.exe $(MSWIN)\mnselcnt.uu -$(MSWIN)\mnunsel.bmp: $(U)uudecode.exe $(MSWIN)\mnunsel.uu -$(MSWIN)\petmark.bmp: $(U)uudecode.exe $(MSWIN)\petmark.uu -$(MSWIN)\pilemark.bmp: $(U)uudecode.exe $(MSWIN)\pilemark.uu -$(MSWIN)\rip.bmp: $(U)uudecode.exe $(MSWIN)\rip.uu -$(MSWIN)\splash.bmp: $(U)uudecode.exe $(MSWIN)\splash.uu +$(MSWIN)mnsel.bmp: $(U)uudecode.exe $(MSWIN)mnsel.uu +$(MSWIN)mnselcnt.bmp: $(U)uudecode.exe $(MSWIN)mnselcnt.uu +$(MSWIN)mnunsel.bmp: $(U)uudecode.exe $(MSWIN)mnunsel.uu +$(MSWIN)petmark.bmp: $(U)uudecode.exe $(MSWIN)petmark.uu +$(MSWIN)pilemark.bmp: $(U)uudecode.exe $(MSWIN)pilemark.uu +$(MSWIN)rip.bmp: $(U)uudecode.exe $(MSWIN)rip.uu +$(MSWIN)splash.bmp: $(U)uudecode.exe $(MSWIN)splash.uu -$(MSWIN)\NetHack.ico: $(U)uudecode.exe $(MSWSYS)\nhico.uu - $(U)uudecode.exe $(MSWSYS)\nhico.uu +$(MSWIN)NetHack.ico: $(U)uudecode.exe $(MSWSYS)nhico.uu + $(U)uudecode.exe $(MSWSYS)nhico.uu move nethack.ico $@ -$(MSWSYS)\NetHack.ico: $(U)uudecode.exe $(MSWSYS)\nhico.uu - $(U)uudecode.exe $(MSWSYS)\nhico.uu +$(MSWSYS)NetHack.ico: $(U)uudecode.exe $(MSWSYS)nhico.uu + $(U)uudecode.exe $(MSWSYS)nhico.uu move nethack.ico $@ #================================================= @@ -1750,53 +1930,53 @@ $(MSWSYS)\NetHack.ico: $(U)uudecode.exe $(MSWSYS)\nhico.uu #================================================= gamedir.tag: - @if not exist $(GAMEDIR)\*.* echo creating directory $(GAMEDIR:\=/) - @if not exist $(GAMEDIR)\*.* mkdir $(GAMEDIR) + @if not exist $(GAMEDIR)*.* echo creating directory $(GAMEDIR:\=/) + @if not exist $(GAMEDIR)*.* mkdir $(R_GAMEDIR) @echo directory created > $@ ottydir$(TARGET_CPU).tag: - @if not exist $(OBJTTY)\*.* echo creating directory $(OBJTTY:\=/) - @if not exist $(OBJTTY)\*.* mkdir $(OBJTTY) + @if not exist $(OBJTTY)*.* echo creating directory $(OBJTTY:\=/) + @if not exist $(OBJTTY)*.* mkdir $(R_OBJTTY) @echo directory created >$@ oguidir$(TARGET_CPU).tag: - @if not exist $(OBJGUI)\*.* echo creating directory $(OBJGUI:\=/) - @if not exist $(OBJGUI)\*.* mkdir $(OBJGUI) + @if not exist $(OBJGUI)*.* echo creating directory $(OBJGUI:\=/) + @if not exist $(OBJGUI)*.* mkdir $(R_OBJGUI) @echo directory created >$@ outldir$(TARGET_CPU).tag: - @if not exist $(OBJUTIL)\*.* echo creating directory $(OBJUTIL:\=/) - @if not exist $(OBJUTIL)\*.* mkdir $(OBJUTIL) + @if not exist $(OBJUTIL)*.* echo creating directory $(OBJUTIL:\=/) + @if not exist $(OBJUTIL)*.* mkdir $(R_OBJUTIL) @echo directory created >$@ oluadir$(TARGET_CPU).tag: - @if not exist $(OBJLUA)\*.* echo creating directory $(OBJLUA:\=/) - @if not exist $(OBJLUA)\*.* mkdir $(OBJLUA) + @if not exist $(OBJLUA)*.* echo creating directory $(OBJLUA:\=/) + @if not exist $(OBJLUA)*.* mkdir $(R_OBJLUA) @echo directory created >$@ opdcdir$(TARGET_CPU).tag: - @if not exist $(OBJPDC)\*.* echo creating directory $(OBJPDC:\=/) - @if not exist $(OBJPDC)\*.* mkdir $(OBJPDC) + @if not exist $(OBJPDC)*.* echo creating directory $(OBJPDC:\=/) + @if not exist $(OBJPDC)*.* mkdir $(R_OBJPDC) @echo directory created >$@ opdccdir$(TARGET_CPU).tag: - @if not exist $(OBJPDCC)\*.* echo creating directory $(OBJPDCC:\=/) - @if not exist $(OBJPDCC)\*.* mkdir $(OBJPDCC) + @if not exist $(OBJPDCC)*.* echo creating directory $(OBJPDCC:\=/) + @if not exist $(OBJPDCC)*.* mkdir $(R_OBJPDCC) @echo directory created >$@ opdcgdir$(TARGET_CPU).tag: - @if not exist $(OBJPDCG)\*.* echo creating directory $(OBJPDCG:\=/) - @if not exist $(OBJPDCG)\*.* mkdir $(OBJPDCG) + @if not exist $(OBJPDCG)*.* echo creating directory $(OBJPDCG:\=/) + @if not exist $(OBJPDCG)*.* mkdir $(R_OBJPDCG) @echo directory created >$@ libdir.tag: - @if not exist $(LIBDIR)\*.* echo creating directory $(LIB:\=/) - @if not exist $(LIBDIR)\*.* mkdir $(LIBDIR) + @if not exist $(LIBDIR)*.* echo creating directory $(LIB:\=/) + @if not exist $(LIBDIR)*.* mkdir $(R_LIBDIR) @echo directory created >$@ pkgdir.tag: - if NOT exist $(PkgDir)\*.* echo creating directory $(PkgDir:\=/) - if NOT exist $(PkgDir)\*.* mkdir $(PkgDir) + if NOT exist $(PkgDir)*.* echo creating directory $(PkgDir:\=/) + if NOT exist $(PkgDir)*.* mkdir $(R_PkgDir) @echo directory created >$@ #========================================== @@ -1806,7 +1986,7 @@ pkgdir.tag: #========================================== envchk.tag: cpu.tag -!IFDEF TTYOBJ +!IFDEF TTYOBJTTY @echo tty window support included ! IF "$(CURSES_CONSOLE)" == "Y" @echo curses console window support also included @@ -1838,18 +2018,18 @@ fetch-lua: fetch-actual-Lua fetch-Lua: fetch-actual-Lua fetch-actual-Lua: - @if not exist $(LIBDIR)\*.* mkdir $(LIBDIR) + @if not exist $(LIBDIR)*.* mkdir $(R_LIBDIR) cd $(LIBDIR) curl -R -O http://www.lua.org/ftp/lua-$(LUAVER).tar.gz tar zxf lua-$(LUAVER).tar.gz if exist lua-$(LUAVER).tar.gz del lua-$(LUAVER).tar.gz if exist lua-$(LUAVER).tar del lua-$(LUAVER).tar - cd ..\src - @echo Lua has been fetched into $(LIBDIR)\lua-$(LUAVER) + cd $(R_SRC) + @echo Lua has been fetched into $(LIBDIR)lua-$(LUAVER) !IF "$(ADD_CURSES)" == "Y" fetch-pdcurses: - @if not exist $(LIBDIR)\*.* mkdir $(LIBDIR) + @if not exist $(LIBDIR)*.* mkdir $(R_LIBDIR) cd $(LIBDIR) # curl -L -R https://codeload.github.com/wmcbrine/PDCurses/zip/master -o pdcurses.zip curl -L -R https://github.com/Bill-Gray/PDCursesMod/archive/refs/tags/v4.3.5.zip -o $(PDCDIST).zip @@ -1859,8 +2039,8 @@ fetch-pdcurses: ren PDCurses-master $(PDCDIST) if exist .\$(PDCDIST)-temp\* rd .\$(PDCDIST)-temp /s /Q if exist .\$(PDCDIST).zip del .\$(PDCDIST).zip - cd ..\src - @echo $(PDCDIST) has been fetched into $(LIBDIR)\$(PDCDIST) + cd $(R_SRC) + @echo $(PDCDIST) has been fetched into $(LIBDIR)$(PDCDIST) !ENDIF #========================================== @@ -1877,35 +2057,36 @@ $(U)dlb.exe: $(DLBOBJ_HOST) $(OUTL)dlb$(HOST).o $(OUTLHACKLIB) << !IFDEF TEST_CROSSCOMPILE -$(OUTL)dlb$(HOST).o: $(OUTL)dlb_main$(HOST).o $(OUTL)alloc$(HOST).o $(OUTL)panic$(HOST).o $(INCL)\dlb.h - $(Q)$(CC) $(CFLAGS) $(TTYDEF) $(CROSSCOMPILE) /Fo$@ $(SRC)\dlb.c +$(OUTL)dlb$(HOST).o: $(OUTL)dlb_main$(HOST).o $(OUTL)alloc$(HOST).o $(OUTL)panic$(HOST).o $(INCL)dlb.h + $(Q)$(CC) $(CFLAGS) $(TTYDEF) $(CROSSCOMPILE) /Fo$@ $(SRC)dlb.c !ENDIF -$(OUTL)dlb.o: $(OUTL)dlb_main.o $(OUTL)alloc.o $(OUTL)panic.o $(INCL)\dlb.h - $(Q)$(CC) $(CFLAGS) $(TTYDEF) /Fo$@ $(SRC)\dlb.c +$(OUTL)dlb.o: $(OUTL)dlb_main.o $(OUTL)alloc.o $(OUTL)panic.o $(INCL)dlb.h + $(Q)$(CC) $(CFLAGS) $(TTYDEF) /Fo$@ $(SRC)dlb.c -$(OTTY)dlb.o: $(OTTY)dlb_main.o $(OTTY)alloc.o $(OTTY)panic.o $(INCL)\dlb.h - $(Q)$(CC) $(CFLAGS) $(TTYDEF) /Fo$@ $(SRC)\dlb.c +$(OTTY)dlb.o: $(OTTY)dlb_main.o $(OTTY)alloc.o $(OTTY)panic.o $(INCL)dlb.h + $(Q)$(CC) $(CFLAGS) $(TTYDEF) /Fo$@ $(SRC)dlb.c -$(OGUI)dlb.o: $(OGUI)dlb_main.o $(OGUI)alloc.o $(OGUI)panic.o $(INCL)\dlb.h - $(Q)$(CC) $(CFLAGS) $(TTYDEF) /Fo$@ $(SRC)\dlb.c +$(OGUI)dlb.o: $(OGUI)dlb_main.o $(OGUI)alloc.o $(OGUI)panic.o $(INCL)dlb.h + $(Q)$(CC) $(CFLAGS) $(TTYDEF) /Fo$@ $(SRC)dlb.c -$(OUTL)dlb_main.o: $(UTIL)\dlb_main.c $(INCL)\config.h $(INCL)\dlb.h - $(Q)$(CC) $(CFLAGS) $(TTYDEF) $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) /Fo$@ $(UTIL)\dlb_main.c +$(OUTL)dlb_main.o: $(UTIL)dlb_main.c $(INCL)config.h $(INCL)dlb.h + $(Q)$(CC) $(CFLAGS) $(TTYDEF) $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) /Fo$@ $(UTIL)dlb_main.c -$(OTTY)dlb_main.o: $(UTIL)\dlb_main.c $(INCL)\config.h $(INCL)\dlb.h - $(Q)$(CC) $(CFLAGS) $(TTYDEF) $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) /Fo$@ $(UTIL)\dlb_main.c +$(OTTY)dlb_main.o: $(UTIL)dlb_main.c $(INCL)config.h $(INCL)dlb.h + $(Q)$(CC) $(CFLAGS) $(TTYDEF) $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) /Fo$@ $(UTIL)dlb_main.c -$(OGUI)dlb_main.o: $(UTIL)\dlb_main.c $(INCL)\config.h $(INCL)\dlb.h - $(Q)$(CC) $(CFLAGS) $(TTYDEF) $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) /Fo$@ $(UTIL)\dlb_main.c +$(OGUI)dlb_main.o: $(UTIL)dlb_main.c $(INCL)config.h $(INCL)dlb.h + $(Q)$(CC) $(CFLAGS) $(TTYDEF) $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) /Fo$@ $(UTIL)dlb_main.c -$(DAT)\porthelp: $(MSWSYS)\porthelp - @copy $(MSWSYS)\porthelp $@ >nul +$(DAT)porthelp: $(MSWSYS)porthelp + @copy $(MSWSYS)porthelp $@ >nul -nhdat$(NHV): $(U)dlb.exe $(DAT)\data $(DAT)\oracles $(OPTIONS_FILE) $(LUA_FILES) \ - $(DAT)\rumors $(DAT)\help $(DAT)\hh $(DAT)\cmdhelp $(DAT)\keyhelp \ - $(DAT)\history $(DAT)\opthelp $(DAT)\optmenu $(DAT)\wizhelp $(DAT)\porthelp \ - $(DAT)\license $(DAT)\engrave $(DAT)\epitaph $(DAT)\bogusmon $(DAT)\tribute +!IF ("$(USE_DLB)"=="Y") +nhdat$(NHV): $(U)dlb.exe $(DAT)data $(DAT)oracles $(OPTIONS_FILE) $(LUA_FILES) \ + $(DAT)rumors $(DAT)help $(DAT)hh $(DAT)cmdhelp $(DAT)keyhelp \ + $(DAT)history $(DAT)opthelp $(DAT)optmenu $(DAT)wizhelp $(DAT)porthelp \ + $(DAT)license $(DAT)engrave $(DAT)epitaph $(DAT)bogusmon $(DAT)tribute @echo Building $@ @cd $(DAT) @echo data >dlb.lst @@ -1928,9 +2109,11 @@ nhdat$(NHV): $(U)dlb.exe $(DAT)\data $(DAT)\oracles $(OPTIONS_FILE) $(LUA_FILES) @echo epitaph >>dlb.lst @echo bogusmon >>dlb.lst @echo tribute >>dlb.lst +# @for %%N in ($(luawildcards)) do dir /b %%N >>dlb.lst @for %%N in (*.lua) do @echo %%N >>dlb.lst - @$(U)dlb cIf dlb.lst $(SRC)\nhdat + @$(U)dlb cIf dlb.lst $(SRC)nhdat @cd $(SRC) +!ENDIF #========================================== # Recover Utility @@ -1941,7 +2124,7 @@ $(U)recover.exe: $(RECOVOBJS) $(OUTLHACKLIB) @$(link) $(LFLAGS) /PDB:"$(OUTL)$(@B).PDB" /MAP:"$(OUTL)$(@B).MAP" \ -out:$@ $(RECOVOBJS) $(OUTLHACKLIB) -$(OUTL)recover.o: $(CONFIG_H) $(U)recover.c $(MSWSYS)\win32api.h +$(OUTL)recover.o: $(CONFIG_H) $(U)recover.c $(MSWSYS)win32api.h $(Q)$(CC) $(CFLAGS) $(TTYDEF) -Fo$@ $(U)recover.c #========================================== @@ -1957,29 +2140,29 @@ $(U)tilemap.exe: $(OUTL)tilemap.o $(OUTL)monst.o $(OUTL)objects.o $(OUTL)drawing @$(link) $(LFLAGS) /PDB:"$(OUTL)$(@B).PDB" /MAP:"$(OUTL)$(@B).MAP" $(HACKLIB) -out:$@ \ $(OUTL)tilemap.o $(OUTL)monst.o $(OUTL)objects.o $(OUTL)drawing.o $(OUTLHACKLIB) -$(OUTL)tilemap.o: $(WSHR)\tilemap.c $(HACK_H) - $(Q)$(CC) $(CFLAGS) $(CROSSCOMPILE) -Fo$@ $(WSHR)\tilemap.c +$(OUTL)tilemap.o: $(WSHR)tilemap.c $(HACK_H) + $(Q)$(CC) $(CFLAGS) $(CROSSCOMPILE) -Fo$@ $(WSHR)tilemap.c -$(OUTL)tiletx32.o: $(WSHR)\tilemap.c $(HACK_H) - $(Q)$(CC) $(CFLAGS) $(CROSSCOMPILE) /DTILETEXT /DTILE_X=32 /DTILE_Y=32 -Fo$@ $(WSHR)\tilemap.c +$(OUTL)tiletx32.o: $(WSHR)tilemap.c $(HACK_H) + $(Q)$(CC) $(CFLAGS) $(CROSSCOMPILE) /DTILETEXT /DTILE_X=32 /DTILE_Y=32 -Fo$@ $(WSHR)tilemap.c -$(OUTL)tiletxt.o: $(WSHR)\tilemap.c $(HACK_H) - $(Q)$(CC) $(CFLAGS) $(CROSSCOMPILE) /DTILETEXT -Fo$@ $(WSHR)\tilemap.c +$(OUTL)tiletxt.o: $(WSHR)tilemap.c $(HACK_H) + $(Q)$(CC) $(CFLAGS) $(CROSSCOMPILE) /DTILETEXT -Fo$@ $(WSHR)tilemap.c -$(OUTL)gifread.o: $(WSHR)\gifread.c $(CONFIG_H) $(TILE_H) - $(Q)$(CC) $(CFLAGS) $(CROSSCOMPILE) -I$(WSHR) -Fo$@ $(WSHR)\gifread.c +$(OUTL)gifread.o: $(WSHR)gifread.c $(CONFIG_H) $(TILE_H) + $(Q)$(CC) $(CFLAGS) $(CROSSCOMPILE) -I$(WSHR) -Fo$@ $(WSHR)gifread.c -$(OUTL)gifrd32.o: $(WSHR)\gifread.c $(CONFIG_H) $(TILE_H) - $(Q)$(CC) $(CFLAGS) $(CROSSCOMPILE) -I$(WSHR) /DTILE_X=32 /DTILE_Y=32 -Fo$@ $(WSHR)\gifread.c +$(OUTL)gifrd32.o: $(WSHR)gifread.c $(CONFIG_H) $(TILE_H) + $(Q)$(CC) $(CFLAGS) $(CROSSCOMPILE) -I$(WSHR) /DTILE_X=32 /DTILE_Y=32 -Fo$@ $(WSHR)gifread.c -$(OUTL)ppmwrite.o: $(WSHR)\ppmwrite.c $(CONFIG_H) $(TILE_H) - $(Q)$(CC) $(CFLAGS) $(CROSSCOMPILE) -I$(WSHR) -Fo$@ $(WSHR)\ppmwrite.c +$(OUTL)ppmwrite.o: $(WSHR)ppmwrite.c $(CONFIG_H) $(TILE_H) + $(Q)$(CC) $(CFLAGS) $(CROSSCOMPILE) -I$(WSHR) -Fo$@ $(WSHR)ppmwrite.c -$(OUTL)tiletext.o: $(WSHR)\tiletext.c $(CONFIG_H) $(TILE_H) - $(Q)$(CC) $(CFLAGS) $(CROSSCOMPILE) -I$(WSHR) -Fo$@ $(WSHR)\tiletext.c +$(OUTL)tiletext.o: $(WSHR)tiletext.c $(CONFIG_H) $(TILE_H) + $(Q)$(CC) $(CFLAGS) $(CROSSCOMPILE) -I$(WSHR) -Fo$@ $(WSHR)tiletext.c -$(OUTL)tilete32.o: $(WSHR)\tiletext.c $(CONFIG_H) $(TILE_H) - $(Q)$(CC) $(CFLAGS) $(CROSSCOMPILE) -I$(WSHR) /DTILE_X=32 /DTILE_Y=32 -Fo$@ $(WSHR)\tiletext.c +$(OUTL)tilete32.o: $(WSHR)tiletext.c $(CONFIG_H) $(TILE_H) + $(Q)$(CC) $(CFLAGS) $(CROSSCOMPILE) -I$(WSHR) /DTILE_X=32 /DTILE_Y=32 -Fo$@ $(WSHR)tiletext.c #========================================== # Optional Tile Utilities @@ -2012,7 +2195,7 @@ $(U)txt2ppm.exe: $(PPMWRITERS) $(TEXT_IO) ) << -$(SRC)\tiles.bmp: $(U)tile2bmp.exe $(TILEFILES) +$(SRC)tiles.bmp: $(U)tile2bmp.exe $(TILEFILES) @echo Creating 16x16 binary tile files (this may take some time) @$(U)tile2bmp $@ @@ -2034,11 +2217,11 @@ $(U)til2bm32.exe: $(OUTL)til2bm32.o $(TEXT_IO32) ) << -$(OUTL)tile2bmp.o: $(WSHR)\tile2bmp.c $(HACK_H) $(TILE_H) $(MSWSYS)\win32api.h - $(Q)$(CC) $(CFLAGS) $(TTYDEF) $(CROSSCOMPILE) -I$(WSHR) /DPACKED_FILE /Fo$@ $(WSHR)\tile2bmp.c +$(OUTL)tile2bmp.o: $(WSHR)tile2bmp.c $(HACK_H) $(TILE_H) $(MSWSYS)win32api.h + $(Q)$(CC) $(CFLAGS) $(TTYDEF) $(CROSSCOMPILE) -I$(WSHR) /DPACKED_FILE /Fo$@ $(WSHR)tile2bmp.c -#$(OUTL)til2bm32.o: $(WSHR)\tile2bmp.c $(HACK_H) $(TILE_H) $(MSWSYS)\win32api.h -# $(Q)$(CC) $(CFLAGS) $(TTYDEF) $(CROSSCOMPILE) -I$(WSHR) /DPACKED_FILE /DTILE_X=32 /DTILE_Y=32 /Fo$@ $(WSHR)\tile2bmp.c +#$(OUTL)til2bm32.o: $(WSHR)tile2bmp.c $(HACK_H) $(TILE_H) $(MSWSYS)win32api.h +# $(Q)$(CC) $(CFLAGS) $(TTYDEF) $(CROSSCOMPILE) -I$(WSHR) /DPACKED_FILE /DTILE_X=32 /DTILE_Y=32 /Fo$@ $(WSHR)tile2bmp.c $(U)tile2x11.exe: $(OUTL)tile2x11.o $(OUTL)tiletext.o $(OUTL)tiletxt.o $(OUTL)alloc.o \ $(OUTL)panic.o $(OUTL)monst.o $(OUTL)objects.o @@ -2054,15 +2237,15 @@ $(U)tile2x11.exe: $(OUTL)tile2x11.o $(OUTL)tiletext.o $(OUTL)tiletxt.o $(OUTL)al $(OUTL)panic.o << -$(OUTL)tile2x11.o: $(X11)\tile2x11.c $(HACK_H) $(TILE_H) $(INCL)\tile2x11.h - $(Q)$(CC) $(CFLAGS) $(CROSSCOMPILE) -I$(WSHR) /DPACKED_FILE /Fo$@ $(X11)\tile2x11.c +$(OUTL)tile2x11.o: $(X11)tile2x11.c $(HACK_H) $(TILE_H) $(INCL)tile2x11.h + $(Q)$(CC) $(CFLAGS) $(CROSSCOMPILE) -I$(WSHR) /DPACKED_FILE /Fo$@ $(X11)tile2x11.c -$(SRC)\x11tiles: $(U)tile2x11.exe $(WSHR)\monsters.txt $(WSHR)\objects.txt \ - $(WSHR)\other.txt \ - $(WSHR)\monsters.txt - $(U)tile2x11 $(WSHR)\monsters.txt $(WSHR)\objects.txt \ - $(WSHR)\other.txt \ - -grayscale $(WSHR)\monsters.txt +$(SRC)x11tiles: $(U)tile2x11.exe $(WSHR)monsters.txt $(WSHR)objects.txt \ + $(WSHR)other.txt \ + $(WSHR)monsters.txt + $(U)tile2x11 $(WSHR)monsters.txt $(WSHR)objects.txt \ + $(WSHR)other.txt \ + -grayscale $(WSHR)monsters.txt #=============================================================================== # PDCurses @@ -2079,7 +2262,7 @@ $(PDCWINGUILIB) : $(PDCCOMMONOBJS) $(PDCWINGUIOBJS) @$(librarian) -nologo /out:$@ $(PDCCOMMONOBJS) $(PDCWINGUIOBJS) !ENDIF !ENDIF -$(OGUI)guitty.o: $(MSWSYS)\guitty.c $(WINDHDR) $(HACK_H) $(TILE_H) +$(OGUI)guitty.o: $(MSWSYS)guitty.c $(WINDHDR) $(HACK_H) $(TILE_H) #=============================================================================== # LUA @@ -2093,91 +2276,91 @@ lua.exe: $(OLUA)lua.o $(LUALIB) # @echo Linking $(@:\=/) # @$(link) /OUT:$@ $(OLUA)luac.o $(LUALIB) -$(LIBDIR)\lua$(LUAVER)-$(TARGET_CPU).dll: $(LUAOBJFILES) +$(LIBDIR)lua$(LUAVER)-$(TARGET_CPU).dll: $(LUAOBJFILES) @echo Linking $(@:\=/) - @$(link) /DLL /IMPLIB:$(LIBDIR)\lua$(LUAVER).lib /OUT:$@ $(LUAOBJFILES) + @$(link) /DLL /IMPLIB:$(LIBDIR)lua$(LUAVER).lib /OUT:$@ $(LUAOBJFILES) -$(LIBDIR)\lua$(LUAVER)-$(TARGET_CPU)-static.lib: $(LUAOBJFILES) +$(LIBDIR)lua$(LUAVER)-$(TARGET_CPU)-static.lib: $(LUAOBJFILES) @echo Building library $@ from $** @$(librarian) /OUT:$@ $(LUAOBJFILES) -$(OLUA)lua.o: $(LUASRC)\lua.c -#$(OLUA)luac.o: $(LUASRC)\luac.c -$(OLUA)lapi.o: $(LUASRC)\lapi.c - $(Q)$(CC) $(CFLAGS) $(TTYDEF) $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) -wd4244 -wd4701 -wd4702 -Fo$@ $(LUASRC)\lapi.c +$(OLUA)lua.o: $(LUASRC)lua.c +#$(OLUA)luac.o: $(LUASRC)luac.c +$(OLUA)lapi.o: $(LUASRC)lapi.c + $(Q)$(CC) $(CFLAGS) $(TTYDEF) $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) -wd4244 -wd4701 -wd4702 -Fo$@ $(LUASRC)lapi.c #=================================================================== # windsound dependencies #=================================================================== !IF "$(SOUND_WINDSOUND)" == "Y" -$(OTTY)windsound.o: ..\sound\windsound\windsound.c $(HACK_H) -$(OGUI)windsound.o: ..\sound\windsound\windsound.c $(HACK_H) +$(OTTY)windsound.o: $(WINDSOUNDDIR)windsound.c $(HACK_H) +$(OGUI)windsound.o: $(WINDSOUNDDIR)windsound.c $(HACK_H) !ENDIF #=================================================================== # fmod dependencies #=================================================================== !IF "$(SOUND_FMOD)" == "Y" -$(OTTY)fmod.o: $(FMODDIR)\fmod.c $(HACK_H) -$(OGUI)fmod.o: $(FMODDIR)\fmod.c $(HACK_H) +$(OTTY)fmod.o: $(FMODDIR)fmod.c $(HACK_H) +$(OGUI)fmod.o: $(FMODDIR)fmod.c $(HACK_H) # Copy the DLL to GAMEDIR -$(GAMEDIR)\$(FMODDLLBASENAME): +$(GAMEDIR)$(FMODDLLBASENAME): copy $(FMODLIBDLL) $@ !ENDIF #=================================================================== # sys/windows dependencies #=================================================================== -$(OTTY)consoletty.o: $(MSWSYS)\consoletty.c $(WINDHDR) $(HACK_H) $(TILE_H) -$(OTTY)win10.o: $(MSWSYS)\win10.c $(WINDHDR) $(HACK_H) -$(OTTY)windsys.o: $(MSWSYS)\windsys.c $(WINDHDR) $(HACK_H) -$(OTTY)windsound.o: ..\sound\windsound\windsound.c $(HACK_H) -#$(OTTY)sample.o: ..\sound\sample\sample.c $(HACK_H) -$(OTTY)windmain.o: $(MSWSYS)\windmain.c $(WINDHDR) $(HACK_H) -$(OTTY)safeproc.o: $(WSHR)\safeproc.c $(WINDHDR) $(HACK_H) +$(OTTY)consoletty.o: $(MSWSYS)consoletty.c $(WINDHDR) $(HACK_H) $(TILE_H) +$(OTTY)win10.o: $(MSWSYS)win10.c $(WINDHDR) $(HACK_H) +$(OTTY)windsys.o: $(MSWSYS)windsys.c $(WINDHDR) $(HACK_H) +$(OTTY)windsound.o: $(WINDSOUNDDIR)windsound.c $(HACK_H) +#$(OTTY)sample.o: $(SOUNDDIR)sample.c $(HACK_H) +$(OTTY)windmain.o: $(MSWSYS)windmain.c $(WINDHDR) $(HACK_H) +$(OTTY)safeproc.o: $(WSHR)safeproc.c $(WINDHDR) $(HACK_H) -$(OGUI)consoletty.o: $(MSWSYS)\consoletty.c $(WINDHDR) $(HACK_H) $(TILE_H) -$(OGUI)win10.o: $(MSWSYS)\win10.c $(WINDHDR) $(HACK_H) -$(OGUI)windsys.o: $(MSWSYS)\windsys.c $(WINDHDR) $(HACK_H) -$(OGUI)windsound.o: ..\sound\windsound\windsound.c $(HACK_H) -$(OGUI)windmain.o: $(MSWSYS)\windmain.c $(WINDHDR) $(HACK_H) -$(OGUI)safeproc.o: $(WSHR)\safeproc.c $(WINDHDR) $(HACK_H) +$(OGUI)consoletty.o: $(MSWSYS)consoletty.c $(WINDHDR) $(HACK_H) $(TILE_H) +$(OGUI)win10.o: $(MSWSYS)win10.c $(WINDHDR) $(HACK_H) +$(OGUI)windsys.o: $(MSWSYS)windsys.c $(WINDHDR) $(HACK_H) +$(OGUI)windsound.o: $(WINDSOUNDDIR)windsound.c $(HACK_H) +$(OGUI)windmain.o: $(MSWSYS)windmain.c $(WINDHDR) $(HACK_H) +$(OGUI)safeproc.o: $(WSHR)safeproc.c $(WINDHDR) $(HACK_H) #=================================================================== # win/win32 dependencies #=================================================================== -$(OGUI)mhaskyn.o: $(MSWIN)\mhaskyn.c $(MSWIN)\$(@B).h $(WINDHDR) $(HACK_H) -$(OGUI)mhdlg.o: $(MSWIN)\mhdlg.c $(MSWIN)\$(@B).h $(MSWIN)\resource.h $(WINDHDR) $(HACK_H) -$(OGUI)mhfont.o: $(MSWIN)\mhfont.c $(MSWIN)\$(@B).h $(WINDHDR) $(HACK_H) -$(OGUI)mhinput.o: $(MSWIN)\mhinput.c $(MSWIN)\$(@B).h $(MSWIN)\winMS.h $(WINDHDR) $(HACK_H) -$(OGUI)mhmain.o: $(MSWIN)\mhmain.c $(ALL_GUIHDR) $(WINDHDR) $(HACK_H) -$(OGUI)mhmap.o: $(MSWIN)\mhmap.c $(MSWIN)\$(@B).h $(MSWIN)\mhfont.h $(MSWIN)\mhinput.h \ - $(MSWIN)\mhmsg.h $(MSWIN)\resource.h $(WINDHDR) $(HACK_H) -$(OGUI)mhmenu.o: $(MSWIN)\mhmenu.c $(MSWIN)\$(@B).h $(MSWIN)\mhmain.h $(MSWIN)\mhmsg.h \ - $(MSWIN)\mhfont.h $(MSWIN)\mhdlg.h $(MSWIN)\resource.h $(WINDHDR) $(HACK_H) -$(OGUI)mhmsgwnd.o: $(MSWIN)\mhmsgwnd.c $(MSWIN)\$(@B).h $(MSWIN)\mhmsg.h $(MSWIN)\mhfont.h \ - $(MSWIN)\winMS.h $(WINDHDR) $(HACK_H) -$(OGUI)mhrip.o: $(MSWIN)\mhrip.c $(MSWIN)\$(@B).h $(MSWIN)\mhmsg.h $(MSWIN)\mhfont.h \ - $(MSWIN)\resource.h $(WINDHDR) $(HACK_H) -$(OGUI)mhsplash.o: $(MSWIN)\mhsplash.c $(MSWIN)\$(@B).h $(MSWIN)\mhmsg.h $(MSWIN)\mhfont.h \ - $(MSWIN)\resource.h $(WINDHDR) $(HACK_H) -$(OGUI)mhstatus.o: $(MSWIN)\mhstatus.c $(MSWIN)\$(@B).h $(MSWIN)\mhmsg.h $(MSWIN)\mhfont.h \ +$(OGUI)mhaskyn.o: $(MSWIN)mhaskyn.c $(MSWIN)$(@B).h $(WINDHDR) $(HACK_H) +$(OGUI)mhdlg.o: $(MSWIN)mhdlg.c $(MSWIN)$(@B).h $(MSWIN)resource.h $(WINDHDR) $(HACK_H) +$(OGUI)mhfont.o: $(MSWIN)mhfont.c $(MSWIN)$(@B).h $(WINDHDR) $(HACK_H) +$(OGUI)mhinput.o: $(MSWIN)mhinput.c $(MSWIN)$(@B).h $(MSWIN)winMS.h $(WINDHDR) $(HACK_H) +$(OGUI)mhmain.o: $(MSWIN)mhmain.c $(ALL_GUIHDR) $(WINDHDR) $(HACK_H) +$(OGUI)mhmap.o: $(MSWIN)mhmap.c $(MSWIN)$(@B).h $(MSWIN)mhfont.h $(MSWIN)mhinput.h \ + $(MSWIN)mhmsg.h $(MSWIN)resource.h $(WINDHDR) $(HACK_H) +$(OGUI)mhmenu.o: $(MSWIN)mhmenu.c $(MSWIN)$(@B).h $(MSWIN)mhmain.h $(MSWIN)mhmsg.h \ + $(MSWIN)mhfont.h $(MSWIN)mhdlg.h $(MSWIN)resource.h $(WINDHDR) $(HACK_H) +$(OGUI)mhmsgwnd.o: $(MSWIN)mhmsgwnd.c $(MSWIN)$(@B).h $(MSWIN)mhmsg.h $(MSWIN)mhfont.h \ + $(MSWIN)winMS.h $(WINDHDR) $(HACK_H) +$(OGUI)mhrip.o: $(MSWIN)mhrip.c $(MSWIN)$(@B).h $(MSWIN)mhmsg.h $(MSWIN)mhfont.h \ + $(MSWIN)resource.h $(WINDHDR) $(HACK_H) +$(OGUI)mhsplash.o: $(MSWIN)mhsplash.c $(MSWIN)$(@B).h $(MSWIN)mhmsg.h $(MSWIN)mhfont.h \ + $(MSWIN)resource.h $(WINDHDR) $(HACK_H) +$(OGUI)mhstatus.o: $(MSWIN)mhstatus.c $(MSWIN)$(@B).h $(MSWIN)mhmsg.h $(MSWIN)mhfont.h \ $(WINDHDR) $(HACK_H) -$(OGUI)mhtext.o: $(MSWIN)\mhtext.c $(MSWIN)\$(@B).h $(MSWIN)\mhmsg.h $(MSWIN)\mhfont.h \ +$(OGUI)mhtext.o: $(MSWIN)mhtext.c $(MSWIN)$(@B).h $(MSWIN)mhmsg.h $(MSWIN)mhfont.h \ $(WINDHDR) $(HACK_H) -$(OGUI)mswproc.o: $(MSWIN)\mswproc.c $(ALL_GUIHDR) $(MSWIN)\resource.h $(WINDHDR) $(HACK_H) -$(OGUI)NetHackW.o: $(MSWIN)\NetHackW.c $(ALL_GUIHDR) $(MSWIN)\resource.h $(WINDHDR) $(HACK_H) +$(OGUI)mswproc.o: $(MSWIN)mswproc.c $(ALL_GUIHDR) $(MSWIN)resource.h $(WINDHDR) $(HACK_H) +$(OGUI)NetHackW.o: $(MSWIN)NetHackW.c $(ALL_GUIHDR) $(MSWIN)resource.h $(WINDHDR) $(HACK_H) #=================================================================== # sys/share dependencies #=================================================================== -#$(OTTY)cppregex.o: $(SSYS)\cppregex.cpp $(HACK_H) -# $(Q)$(CC) $(CPPFLAGS) $(TTYDEF) $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) -Fo$@ $(SSYS)\cppregex.cpp +#$(OTTY)cppregex.o: $(SSYS)cppregex.cpp $(HACK_H) +# $(Q)$(CC) $(CPPFLAGS) $(TTYDEF) $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) -Fo$@ $(SSYS)cppregex.cpp -#$(OGUI)cppregex.o: $(SSYS)\cppregex.cpp $(HACK_H) -# $(Q)$(CC) $(CPPFLAGS) $(GUIDEF) $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) -Fo$@ $(SSYS)\cppregex.cpp +#$(OGUI)cppregex.o: $(SSYS)cppregex.cpp $(HACK_H) +# $(Q)$(CC) $(CPPFLAGS) $(GUIDEF) $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) -Fo$@ $(SSYS)cppregex.cpp #=============================================================================== # CROSSCOMPILE @@ -2194,13 +2377,13 @@ $(OGUI)NetHackW.o: $(MSWIN)\NetHackW.c $(ALL_GUIHDR) $(MSWIN)\resource.h $(WINDH # !IFDEF TEST_CROSSCOMPILE -$(OUTL)mdlib$(HOST).o: $(SRC)\mdlib.c - $(Q)$(CC) $(CFLAGS) $(TTYDEF) $(CROSSCOMPILE) -Fo$@ $(SRC)\mdlib.c +$(OUTL)mdlib$(HOST).o: $(SRC)mdlib.c + $(Q)$(CC) $(CFLAGS) $(TTYDEF) $(CROSSCOMPILE) -Fo$@ $(SRC)mdlib.c !ENDIF -$(OUTL)mdlib.o: $(SRC)\mdlib.c - $(Q)$(CC) $(CFLAGS) $(TTYDEF) -Fo$@ $(SRC)\mdlib.c -# $(Q)$(CC) $(CFLAGS) $(TTYDEF) /EP -Fo$@ $(SRC)\mdlib.c >$(OUTL)mdlib.c.preproc +$(OUTL)mdlib.o: $(SRC)mdlib.c + $(Q)$(CC) $(CFLAGS) $(TTYDEF) -Fo$@ $(SRC)mdlib.c +# $(Q)$(CC) $(CFLAGS) $(TTYDEF) /EP -Fo$@ $(SRC)mdlib.c >$(OUTL)mdlib.c.preproc #============================================ # util dual-role CROSSCOMPILE dependencies @@ -2221,28 +2404,28 @@ $(OGUI)panic.o: $(U)panic.c $(CONFIG_H) #$(OUTL)drawing_host.o: drawing.c $(CONFIG_H) # $(Q)$(CC) $(CFLAGS) $(CROSSCOMPILE) -Fo$@ drawing.c -$(OUTL)drawing.o: drawing.c $(CONFIG_H) $(INCL)\color.h \ - $(INCL)\sym.h $(INCL)\defsym.h $(INCL)\rm.h \ - $(INCL)\objclass.h +$(OUTL)drawing.o: drawing.c $(CONFIG_H) $(INCL)color.h \ + $(INCL)sym.h $(INCL)defsym.h $(INCL)rm.h \ + $(INCL)objclass.h $(Q)$(CC) $(CFLAGS) -Fo$@ drawing.c -#$(OUTL)monst_host.o: monst.c $(CONFIG_H) $(INCL)\permonst.h $(INCL)\align.h \ -# $(INCL)\monattk.h $(INCL)\monflag.h $(INCL)\sym.h \ -# $(INCL)\defsym.h $(INCL)\color.h +#$(OUTL)monst_host.o: monst.c $(CONFIG_H) $(INCL)permonst.h $(INCL)align.h \ +# $(INCL)monattk.h $(INCL)monflag.h $(INCL)sym.h \ +# $(INCL)defsym.h $(INCL)color.h # $(Q)$(CC) $(CFLAGS) $(TTYDEF) -Fo$@ monst.c -$(OUTL)monst.o: monst.c $(CONFIG_H) $(INCL)\permonst.h $(INCL)\align.h \ - $(INCL)\monattk.h $(INCL)\monflag.h $(INCL)\sym.h \ - $(INCL)\defsym.h $(INCL)\color.h +$(OUTL)monst.o: monst.c $(CONFIG_H) $(INCL)permonst.h $(INCL)align.h \ + $(INCL)monattk.h $(INCL)monflag.h $(INCL)sym.h \ + $(INCL)defsym.h $(INCL)color.h $(Q)$(CC) $(CFLAGS) -Fo$@ monst.c -#$(OUTL)objects_host.o: objects.c $(CONFIG_H) $(INCL)\obj.h $(INCL)\objclass.h \ -# $(INCL)\prop.h $(INCL)\skills.h $(INCL)\color.h +#$(OUTL)objects_host.o: objects.c $(CONFIG_H) $(INCL)obj.h $(INCL)objclass.h \ +# $(INCL)prop.h $(INCL)skills.h $(INCL)color.h # $(Q)$(CC) $(CFLAGS) $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) /EP $(@B).c > $(OUTL)$(@B).c.preproc # $(Q)$(CC) $(CFLAGS) $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) -Fo$@ $(@B).c -$(OUTL)objects.o: objects.c $(CONFIG_H) $(INCL)\obj.h $(INCL)\objclass.h \ - $(INCL)\prop.h $(INCL)\skills.h $(INCL)\color.h +$(OUTL)objects.o: objects.c $(CONFIG_H) $(INCL)obj.h $(INCL)objclass.h \ + $(INCL)prop.h $(INCL)skills.h $(INCL)color.h $(Q)$(CC) $(CFLAGS) /EP $(@B).c > $(OUTL)$(@B).c.preproc $(Q)$(CC) $(CFLAGS) -Fo$@ $(@B).c @@ -2260,88 +2443,88 @@ $(OUTL)alloc.o: alloc.c $(CONFIG_H) # dat dependencies # -$(DAT)\data: $(U)makedefs.exe $(DATABASE) +$(DAT)data: $(U)makedefs.exe $(DATABASE) $(U)makedefs -d -$(DAT)\rumors: $(U)makedefs.exe $(DAT)\rumors.tru $(DAT)\rumors.fal +$(DAT)rumors: $(U)makedefs.exe $(DAT)rumors.tru $(DAT)rumors.fal $(U)makedefs -r -$(DAT)\oracles: $(U)makedefs.exe $(DAT)\oracles.txt +$(DAT)oracles: $(U)makedefs.exe $(DAT)oracles.txt $(U)makedefs -h -$(DAT)\engrave: $(U)makedefs.exe $(DAT)\engrave.txt - $(U)makedefs -s +$(DAT)engrave: $(U)makedefs.exe $(DAT)engrave.txt + $(U)makedefs -2 -$(DAT)\epitaph: $(U)makedefs.exe $(DAT)\epitaph.txt - $(U)makedefs -s +$(DAT)epitaph: $(U)makedefs.exe $(DAT)epitaph.txt + $(U)makedefs -1 -$(DAT)\bogusmon: $(U)makedefs.exe $(DAT)\bogusmon.txt - $(U)makedefs -s +$(DAT)bogusmon: $(U)makedefs.exe $(DAT)bogusmon.txt + $(U)makedefs -3 #=============================================================================== # Integrated sound files #=============================================================================== -$(SndWavDir)\se_squeak_A.wav: $(SndWavDir)\se_squeak_A.uu $(U)uudecode.exe -$(SndWavDir)\se_squeak_B.wav: $(SndWavDir)\se_squeak_B.uu $(U)uudecode.exe -$(SndWavDir)\se_squeak_B_flat.wav: $(SndWavDir)\se_squeak_B_flat.uu $(U)uudecode.exe -$(SndWavDir)\se_squeak_C.wav: $(SndWavDir)\se_squeak_C.uu $(U)uudecode.exe -$(SndWavDir)\se_squeak_D.wav: $(SndWavDir)\se_squeak_D.uu $(U)uudecode.exe -$(SndWavDir)\se_squeak_D_flat.wav: $(SndWavDir)\se_squeak_D_flat.uu $(U)uudecode.exe -$(SndWavDir)\se_squeak_E.wav: $(SndWavDir)\se_squeak_E.uu $(U)uudecode.exe -$(SndWavDir)\se_squeak_E_flat.wav: $(SndWavDir)\se_squeak_E_flat.uu $(U)uudecode.exe -$(SndWavDir)\se_squeak_F.wav: $(SndWavDir)\se_squeak_F.uu $(U)uudecode.exe -$(SndWavDir)\se_squeak_F_sharp.wav: $(SndWavDir)\se_squeak_F_sharp.uu $(U)uudecode.exe -$(SndWavDir)\se_squeak_G.wav: $(SndWavDir)\se_squeak_G.uu $(U)uudecode.exe -$(SndWavDir)\se_squeak_G_sharp.wav: $(SndWavDir)\se_squeak_G_sharp.uu $(U)uudecode.exe -$(SndWavDir)\sound_Bell.wav: $(SndWavDir)\sound_Bell.uu $(U)uudecode.exe -$(SndWavDir)\sound_Bugle_A.wav: $(SndWavDir)\sound_Bugle_A.uu $(U)uudecode.exe -$(SndWavDir)\sound_Bugle_B.wav: $(SndWavDir)\sound_Bugle_B.uu $(U)uudecode.exe -$(SndWavDir)\sound_Bugle_C.wav: $(SndWavDir)\sound_Bugle_C.uu $(U)uudecode.exe -$(SndWavDir)\sound_Bugle_D.wav: $(SndWavDir)\sound_Bugle_D.uu $(U)uudecode.exe -$(SndWavDir)\sound_Bugle_E.wav: $(SndWavDir)\sound_Bugle_E.uu $(U)uudecode.exe -$(SndWavDir)\sound_Bugle_F.wav: $(SndWavDir)\sound_Bugle_F.uu $(U)uudecode.exe -$(SndWavDir)\sound_Bugle_G.wav: $(SndWavDir)\sound_Bugle_G.uu $(U)uudecode.exe -$(SndWavDir)\sound_Drum_Of_Earthquake.wav: $(SndWavDir)\sound_Drum_Of_Earthquake.uu $(U)uudecode.exe -$(SndWavDir)\sound_Fire_Horn.wav: $(SndWavDir)\sound_Fire_Horn.uu $(U)uudecode.exe -$(SndWavDir)\sound_Frost_Horn.wav: $(SndWavDir)\sound_Frost_Horn.uu $(U)uudecode.exe -$(SndWavDir)\sound_Leather_Drum.wav: $(SndWavDir)\sound_Leather_Drum.uu $(U)uudecode.exe -$(SndWavDir)\sound_Magic_Harp_A.wav: $(SndWavDir)\sound_Magic_Harp_A.uu $(U)uudecode.exe -$(SndWavDir)\sound_Magic_Harp_B.wav: $(SndWavDir)\sound_Magic_Harp_B.uu $(U)uudecode.exe -$(SndWavDir)\sound_Magic_Harp_C.wav: $(SndWavDir)\sound_Magic_Harp_C.uu $(U)uudecode.exe -$(SndWavDir)\sound_Magic_Harp_D.wav: $(SndWavDir)\sound_Magic_Harp_D.uu $(U)uudecode.exe -$(SndWavDir)\sound_Magic_Harp_E.wav: $(SndWavDir)\sound_Magic_Harp_E.uu $(U)uudecode.exe -$(SndWavDir)\sound_Magic_Harp_F.wav: $(SndWavDir)\sound_Magic_Harp_F.uu $(U)uudecode.exe -$(SndWavDir)\sound_Magic_Harp_G.wav: $(SndWavDir)\sound_Magic_Harp_G.uu $(U)uudecode.exe -$(SndWavDir)\sound_Magic_Flute_A.wav: $(SndWavDir)\sound_Magic_Flute_A.uu $(U)uudecode.exe -$(SndWavDir)\sound_Magic_Flute_B.wav: $(SndWavDir)\sound_Magic_Flute_B.uu $(U)uudecode.exe -$(SndWavDir)\sound_Magic_Flute_C.wav: $(SndWavDir)\sound_Magic_Flute_C.uu $(U)uudecode.exe -$(SndWavDir)\sound_Magic_Flute_D.wav: $(SndWavDir)\sound_Magic_Flute_D.uu $(U)uudecode.exe -$(SndWavDir)\sound_Magic_Flute_E.wav: $(SndWavDir)\sound_Magic_Flute_E.uu $(U)uudecode.exe -$(SndWavDir)\sound_Magic_Flute_F.wav: $(SndWavDir)\sound_Magic_Flute_F.uu $(U)uudecode.exe -$(SndWavDir)\sound_Magic_Flute_G.wav: $(SndWavDir)\sound_Magic_Flute_G.uu $(U)uudecode.exe -$(SndWavDir)\sound_Tooled_Horn_A.wav: $(SndWavDir)\sound_Tooled_Horn_A.uu $(U)uudecode.exe -$(SndWavDir)\sound_Tooled_Horn_B.wav: $(SndWavDir)\sound_Tooled_Horn_B.uu $(U)uudecode.exe -$(SndWavDir)\sound_Tooled_Horn_C.wav: $(SndWavDir)\sound_Tooled_Horn_C.uu $(U)uudecode.exe -$(SndWavDir)\sound_Tooled_Horn_D.wav: $(SndWavDir)\sound_Tooled_Horn_D.uu $(U)uudecode.exe -$(SndWavDir)\sound_Tooled_Horn_E.wav: $(SndWavDir)\sound_Tooled_Horn_E.uu $(U)uudecode.exe -$(SndWavDir)\sound_Tooled_Horn_F.wav: $(SndWavDir)\sound_Tooled_Horn_F.uu $(U)uudecode.exe -$(SndWavDir)\sound_Tooled_Horn_G.wav: $(SndWavDir)\sound_Tooled_Horn_G.uu $(U)uudecode.exe -$(SndWavDir)\sound_Wooden_Flute_A.wav: $(SndWavDir)\sound_Wooden_Flute_A.uu $(U)uudecode.exe -$(SndWavDir)\sound_Wooden_Flute_B.wav: $(SndWavDir)\sound_Wooden_Flute_B.uu $(U)uudecode.exe -$(SndWavDir)\sound_Wooden_Flute_C.wav: $(SndWavDir)\sound_Wooden_Flute_C.uu $(U)uudecode.exe -$(SndWavDir)\sound_Wooden_Flute_D.wav: $(SndWavDir)\sound_Wooden_Flute_D.uu $(U)uudecode.exe -$(SndWavDir)\sound_Wooden_Flute_E.wav: $(SndWavDir)\sound_Wooden_Flute_E.uu $(U)uudecode.exe -$(SndWavDir)\sound_Wooden_Flute_F.wav: $(SndWavDir)\sound_Wooden_Flute_F.uu $(U)uudecode.exe -$(SndWavDir)\sound_Wooden_Flute_G.wav: $(SndWavDir)\sound_Wooden_Flute_G.uu $(U)uudecode.exe -$(SndWavDir)\sound_Wooden_Harp_A.wav: $(SndWavDir)\sound_Wooden_Harp_A.uu $(U)uudecode.exe -$(SndWavDir)\sound_Wooden_Harp_B.wav: $(SndWavDir)\sound_Wooden_Harp_B.uu $(U)uudecode.exe -$(SndWavDir)\sound_Wooden_Harp_C.wav: $(SndWavDir)\sound_Wooden_Harp_C.uu $(U)uudecode.exe -$(SndWavDir)\sound_Wooden_Harp_D.wav: $(SndWavDir)\sound_Wooden_Harp_D.uu $(U)uudecode.exe -$(SndWavDir)\sound_Wooden_Harp_E.wav: $(SndWavDir)\sound_Wooden_Harp_E.uu $(U)uudecode.exe -$(SndWavDir)\sound_Wooden_Harp_F.wav: $(SndWavDir)\sound_Wooden_Harp_F.uu $(U)uudecode.exe -$(SndWavDir)\sound_Wooden_Harp_G.wav: $(SndWavDir)\sound_Wooden_Harp_G.uu $(U)uudecode.exe -$(SndWavDir)\sa2_xpleveldown.wav: $(SndWavDir)\sa2_xpleveldown.uu $(U)uudecode.exe -$(SndWavDir)\sa2_xplevelup.wav: $(SndWavDir)\sa2_xplevelup.uu $(U)uudecode.exe +$(SndWavDir)se_squeak_A.wav: $(SndWavDir)se_squeak_A.uu $(U)uudecode.exe +$(SndWavDir)se_squeak_B.wav: $(SndWavDir)se_squeak_B.uu $(U)uudecode.exe +$(SndWavDir)se_squeak_B_flat.wav: $(SndWavDir)se_squeak_B_flat.uu $(U)uudecode.exe +$(SndWavDir)se_squeak_C.wav: $(SndWavDir)se_squeak_C.uu $(U)uudecode.exe +$(SndWavDir)se_squeak_D.wav: $(SndWavDir)se_squeak_D.uu $(U)uudecode.exe +$(SndWavDir)se_squeak_D_flat.wav: $(SndWavDir)se_squeak_D_flat.uu $(U)uudecode.exe +$(SndWavDir)se_squeak_E.wav: $(SndWavDir)se_squeak_E.uu $(U)uudecode.exe +$(SndWavDir)se_squeak_E_flat.wav: $(SndWavDir)se_squeak_E_flat.uu $(U)uudecode.exe +$(SndWavDir)se_squeak_F.wav: $(SndWavDir)se_squeak_F.uu $(U)uudecode.exe +$(SndWavDir)se_squeak_F_sharp.wav: $(SndWavDir)se_squeak_F_sharp.uu $(U)uudecode.exe +$(SndWavDir)se_squeak_G.wav: $(SndWavDir)se_squeak_G.uu $(U)uudecode.exe +$(SndWavDir)se_squeak_G_sharp.wav: $(SndWavDir)se_squeak_G_sharp.uu $(U)uudecode.exe +$(SndWavDir)sound_Bell.wav: $(SndWavDir)sound_Bell.uu $(U)uudecode.exe +$(SndWavDir)sound_Bugle_A.wav: $(SndWavDir)sound_Bugle_A.uu $(U)uudecode.exe +$(SndWavDir)sound_Bugle_B.wav: $(SndWavDir)sound_Bugle_B.uu $(U)uudecode.exe +$(SndWavDir)sound_Bugle_C.wav: $(SndWavDir)sound_Bugle_C.uu $(U)uudecode.exe +$(SndWavDir)sound_Bugle_D.wav: $(SndWavDir)sound_Bugle_D.uu $(U)uudecode.exe +$(SndWavDir)sound_Bugle_E.wav: $(SndWavDir)sound_Bugle_E.uu $(U)uudecode.exe +$(SndWavDir)sound_Bugle_F.wav: $(SndWavDir)sound_Bugle_F.uu $(U)uudecode.exe +$(SndWavDir)sound_Bugle_G.wav: $(SndWavDir)sound_Bugle_G.uu $(U)uudecode.exe +$(SndWavDir)sound_Drum_Of_Earthquake.wav: $(SndWavDir)sound_Drum_Of_Earthquake.uu $(U)uudecode.exe +$(SndWavDir)sound_Fire_Horn.wav: $(SndWavDir)sound_Fire_Horn.uu $(U)uudecode.exe +$(SndWavDir)sound_Frost_Horn.wav: $(SndWavDir)sound_Frost_Horn.uu $(U)uudecode.exe +$(SndWavDir)sound_Leather_Drum.wav: $(SndWavDir)sound_Leather_Drum.uu $(U)uudecode.exe +$(SndWavDir)sound_Magic_Harp_A.wav: $(SndWavDir)sound_Magic_Harp_A.uu $(U)uudecode.exe +$(SndWavDir)sound_Magic_Harp_B.wav: $(SndWavDir)sound_Magic_Harp_B.uu $(U)uudecode.exe +$(SndWavDir)sound_Magic_Harp_C.wav: $(SndWavDir)sound_Magic_Harp_C.uu $(U)uudecode.exe +$(SndWavDir)sound_Magic_Harp_D.wav: $(SndWavDir)sound_Magic_Harp_D.uu $(U)uudecode.exe +$(SndWavDir)sound_Magic_Harp_E.wav: $(SndWavDir)sound_Magic_Harp_E.uu $(U)uudecode.exe +$(SndWavDir)sound_Magic_Harp_F.wav: $(SndWavDir)sound_Magic_Harp_F.uu $(U)uudecode.exe +$(SndWavDir)sound_Magic_Harp_G.wav: $(SndWavDir)sound_Magic_Harp_G.uu $(U)uudecode.exe +$(SndWavDir)sound_Magic_Flute_A.wav: $(SndWavDir)sound_Magic_Flute_A.uu $(U)uudecode.exe +$(SndWavDir)sound_Magic_Flute_B.wav: $(SndWavDir)sound_Magic_Flute_B.uu $(U)uudecode.exe +$(SndWavDir)sound_Magic_Flute_C.wav: $(SndWavDir)sound_Magic_Flute_C.uu $(U)uudecode.exe +$(SndWavDir)sound_Magic_Flute_D.wav: $(SndWavDir)sound_Magic_Flute_D.uu $(U)uudecode.exe +$(SndWavDir)sound_Magic_Flute_E.wav: $(SndWavDir)sound_Magic_Flute_E.uu $(U)uudecode.exe +$(SndWavDir)sound_Magic_Flute_F.wav: $(SndWavDir)sound_Magic_Flute_F.uu $(U)uudecode.exe +$(SndWavDir)sound_Magic_Flute_G.wav: $(SndWavDir)sound_Magic_Flute_G.uu $(U)uudecode.exe +$(SndWavDir)sound_Tooled_Horn_A.wav: $(SndWavDir)sound_Tooled_Horn_A.uu $(U)uudecode.exe +$(SndWavDir)sound_Tooled_Horn_B.wav: $(SndWavDir)sound_Tooled_Horn_B.uu $(U)uudecode.exe +$(SndWavDir)sound_Tooled_Horn_C.wav: $(SndWavDir)sound_Tooled_Horn_C.uu $(U)uudecode.exe +$(SndWavDir)sound_Tooled_Horn_D.wav: $(SndWavDir)sound_Tooled_Horn_D.uu $(U)uudecode.exe +$(SndWavDir)sound_Tooled_Horn_E.wav: $(SndWavDir)sound_Tooled_Horn_E.uu $(U)uudecode.exe +$(SndWavDir)sound_Tooled_Horn_F.wav: $(SndWavDir)sound_Tooled_Horn_F.uu $(U)uudecode.exe +$(SndWavDir)sound_Tooled_Horn_G.wav: $(SndWavDir)sound_Tooled_Horn_G.uu $(U)uudecode.exe +$(SndWavDir)sound_Wooden_Flute_A.wav: $(SndWavDir)sound_Wooden_Flute_A.uu $(U)uudecode.exe +$(SndWavDir)sound_Wooden_Flute_B.wav: $(SndWavDir)sound_Wooden_Flute_B.uu $(U)uudecode.exe +$(SndWavDir)sound_Wooden_Flute_C.wav: $(SndWavDir)sound_Wooden_Flute_C.uu $(U)uudecode.exe +$(SndWavDir)sound_Wooden_Flute_D.wav: $(SndWavDir)sound_Wooden_Flute_D.uu $(U)uudecode.exe +$(SndWavDir)sound_Wooden_Flute_E.wav: $(SndWavDir)sound_Wooden_Flute_E.uu $(U)uudecode.exe +$(SndWavDir)sound_Wooden_Flute_F.wav: $(SndWavDir)sound_Wooden_Flute_F.uu $(U)uudecode.exe +$(SndWavDir)sound_Wooden_Flute_G.wav: $(SndWavDir)sound_Wooden_Flute_G.uu $(U)uudecode.exe +$(SndWavDir)sound_Wooden_Harp_A.wav: $(SndWavDir)sound_Wooden_Harp_A.uu $(U)uudecode.exe +$(SndWavDir)sound_Wooden_Harp_B.wav: $(SndWavDir)sound_Wooden_Harp_B.uu $(U)uudecode.exe +$(SndWavDir)sound_Wooden_Harp_C.wav: $(SndWavDir)sound_Wooden_Harp_C.uu $(U)uudecode.exe +$(SndWavDir)sound_Wooden_Harp_D.wav: $(SndWavDir)sound_Wooden_Harp_D.uu $(U)uudecode.exe +$(SndWavDir)sound_Wooden_Harp_E.wav: $(SndWavDir)sound_Wooden_Harp_E.uu $(U)uudecode.exe +$(SndWavDir)sound_Wooden_Harp_F.wav: $(SndWavDir)sound_Wooden_Harp_F.uu $(U)uudecode.exe +$(SndWavDir)sound_Wooden_Harp_G.wav: $(SndWavDir)sound_Wooden_Harp_G.uu $(U)uudecode.exe +$(SndWavDir)sa2_xpleveldown.wav: $(SndWavDir)sa2_xpleveldown.uu $(U)uudecode.exe +$(SndWavDir)sa2_xplevelup.wav: $(SndWavDir)sa2_xplevelup.uu $(U)uudecode.exe #=============================================================================== # packaging @@ -2349,33 +2532,33 @@ $(SndWavDir)\sa2_xplevelup.wav: $(SndWavDir)\sa2_xplevelup.uu $(U)uudecode.exe PKGFILES = nethackrc.template Guidebook.txt license NetHack.exe NetHack.txt \ NetHackW.exe opthelp nhdat370 record symbols sysconf.template -FILESTOZIP = $(BinDir)\nethackrc.template $(BinDir)\Guidebook.txt $(BinDir)\license \ - $(BinDir)\NetHack.exe $(BinDir)\NetHack.txt $(BinDir)\NetHackW.exe \ - $(BinDir)\opthelp $(BinDir)\nhdat370 $(BinDir)\record \ - $(BinDir)\symbols $(BinDir)\sysconf.template +FILESTOZIP = $(BinDir)nethackrc.template $(BinDir)Guidebook.txt $(BinDir)license \ + $(BinDir)NetHack.exe $(BinDir)NetHack.txt $(BinDir)NetHackW.exe \ + $(BinDir)opthelp $(BinDir)nhdat370 $(BinDir)record \ + $(BinDir)symbols $(BinDir)sysconf.template DBGSYMS = NetHack.PDB NetHackW.PDB -PDBTOZIP = $(BinDir)\NetHack.PDB $(BinDir)\NetHackW.PDB -MAINZIP = $(PkgDir)\nethack-$(NHV)-win-$(TARGET_CPU).zip -DBGSYMZIP = $(PkgDir)\nethack-$(NHV)-win-$(TARGET_CPU)-debugsymbols.zip +PDBTOZIP = $(BinDir)NetHack.PDB $(BinDir)NetHackW.PDB +MAINZIP = $(PkgDir)nethack-$(NHV)-win-$(TARGET_CPU).zip +DBGSYMZIP = $(PkgDir)nethack-$(NHV)-win-$(TARGET_CPU)-debugsymbols.zip package: binary $(FILESTOZIP) $(MAINZIP) $(DBGSYMZIP) @echo NetHack Windows package created: $(MAINZIP) $(MAINZIP): $(FILESTOZIP) - if not exist $(PkgDir)\*.* mkdir $(PkgDir) - tar -a -cf $(MAINZIP) -C $(BinDir) $(PKGFILES) + if not exist $(PkgDir)*.* mkdir $(R_PkgDir) + tar -a -cf $(MAINZIP) -C $(R_BinDir) $(PKGFILES) $(DBGSYMZIP): $(PDBTOZIP) - tar -a -cf $(DBGSYMZIP) -C $(BinDir) $(DBGSYMS) + tar -a -cf $(DBGSYMZIP) -C $(R_BinDir) $(DBGSYMS) binary: envchk.tag libdir.tag ottydir$(TARGET_CPU).tag \ outldir$(TARGET_CPU).tag oguidir$(TARGET_CPU).tag \ oluadir$(TARGET_CPU).tag opdcdir$(TARGET_CPU).tag \ opdccdir$(TARGET_CPU).tag opdcgdir$(TARGET_CPU).tag \ - $(LUASRC)\lua.h $(PDCDEP) \ - $(INCL)\nhlua.h $(OUTL)utility.tag \ - $(DAT)\data $(DAT)\rumors $(DAT)\oracles $(DAT)\engrave \ - $(DAT)\epitaph $(DAT)\bogusmon $(GAMEDIR)\NetHack.exe \ - $(GAMEDIR)\NetHackW.exe $(GAMEDIRDLLS) binary.tag + $(LUASRC)lua.h $(PDCDEP) \ + $(INCL)nhlua.h $(OUTL)utility.tag \ + $(DAT)data $(DAT)rumors $(DAT)oracles $(DAT)engrave \ + $(DAT)epitaph $(DAT)bogusmon $(GAMEDIR)NetHack.exe \ + $(GAMEDIR)NetHackW.exe $(GAMEDIRDLLS) binary.tag @echo NetHack is up to date. #=============================================================================== @@ -2383,21 +2566,21 @@ binary: envchk.tag libdir.tag ottydir$(TARGET_CPU).tag \ #=============================================================================== spotless: clean - if exist $(GAMEDIR)\NetHack.exe del $(GAMEDIR)\NetHack.exe - if exist $(GAMEDIR)\NetHackW.exe del $(GAMEDIR)NetHackW.exe - if exist $(GAMEDIR)\NetHack.pdb del $(GAMEDIR)\NetHack.pdb - if exist $(GAMEDIR)\nhdat$(NHV) del $(GAMEDIR)\nhdat$(NHV) - if exist $(INCL)\date.h del $(INCL)\date.h - if exist $(INCL)\onames.h del $(INCL)\onames.h - if exist $(INCL)\pm.h del $(INCL)\pm.h + if exist $(GAMEDIR)NetHack.exe del $(GAMEDIR)NetHack.exe + if exist $(GAMEDIR)NetHackW.exe del $(GAMEDIR)NetHackW.exe + if exist $(GAMEDIR)NetHack.pdb del $(GAMEDIR)NetHack.pdb + if exist $(GAMEDIR)nhdat$(NHV) del $(GAMEDIR)nhdat$(NHV) + if exist $(INCL)date.h del $(INCL)date.h + if exist $(INCL)onames.h del $(INCL)onames.h + if exist $(INCL)pm.h del $(INCL)pm.h if exist $(U)*.lnk del $(U)*.lnk if exist $(U)*.map del $(U)*.map - if exist $(DAT)\data del $(DAT)\data - if exist $(DAT)\rumors del $(DAT)\rumors - if exist $(DAT)\engrave del $(DAT)\engrave - if exist $(DAT)\epitaph del $(DAT)\epitaph - if exist $(DAT)\bogusmon del $(DAT)\bogusmon - if exist $(DAT)\porthelp del $(DAT)\porthelp + if exist $(DAT)data del $(DAT)data + if exist $(DAT)rumors del $(DAT)rumors + if exist $(DAT)engrave del $(DAT)engrave + if exist $(DAT)epitaph del $(DAT)epitaph + if exist $(DAT)bogusmon del $(DAT)bogusmon + if exist $(DAT)porthelp del $(DAT)porthelp if exist nhdat$(NHV). del nhdat$(NHV). if exist outldirx86.tag del outldirx86.tag if exist ottydirx86.tag del ottydirx86.tag @@ -2415,49 +2598,49 @@ spotless: clean if exist opdcgdirx64.tag del opdcgdirx64.tag if exist libdir.tag del libdir.tag if exist gamedir.tag del gamedir.tag - if exist $(MSWIN)\mnsel.bmp del $(MSWIN)\mnsel.bmp - if exist $(MSWIN)\mnselcnt.bmp del $(MSWIN)\mnselcnt.bmp - if exist $(MSWIN)\mnunsel.bmp del $(MSWIN)\mnunsel.bmp - if exist $(MSWIN)\petmark.bmp del $(MSWIN)\petmark.bmp - if exist $(MSWIN)\pilemark.bmp del $(MSWIN)\pilemark.bmp - if exist $(MSWIN)\rip.bmp del $(MSWIN)\rip.bmp - if exist $(MSWIN)\splash.bmp del $(MSWIN)\splash.bmp - if exist $(MSWIN)\nethack.ico del $(MSWIN)\nethack.ico - if exist $(MSWSYS)\nethack.ico del $(MSWSYS)\nethack.ico + if exist $(MSWIN)mnsel.bmp del $(MSWIN)mnsel.bmp + if exist $(MSWIN)mnselcnt.bmp del $(MSWIN)mnselcnt.bmp + if exist $(MSWIN)mnunsel.bmp del $(MSWIN)mnunsel.bmp + if exist $(MSWIN)petmark.bmp del $(MSWIN)petmark.bmp + if exist $(MSWIN)pilemark.bmp del $(MSWIN)pilemark.bmp + if exist $(MSWIN)rip.bmp del $(MSWIN)rip.bmp + if exist $(MSWIN)splash.bmp del $(MSWIN)splash.bmp + if exist $(MSWIN)nethack.ico del $(MSWIN)nethack.ico + if exist $(MSWSYS)nethack.ico del $(MSWSYS)nethack.ico if exist $(U)recover.exe del $(U)recover.exe if exist $(U)tile2bmp.exe del $(U)tile2bmp.exe if exist $(U)tilemap.exe del $(U)tilemap.exe if exist $(U)uudecode.exe del $(U)uudecode.exe if exist $(U)dlb.exe del $(U)dlb.exe !IF "$(ADD_CURSES)" == "Y" - if exist $(LIBDIR)\$(PDCDIST)-wincon-$(TARGET_CPU)-static.lib del $(LIBDIR)\$(PDCDIST)-wincon-$(TARGET_CPU)-static.lib - if exist $(LIBDIR)\$(PDCDIST)-wingui-$(TARGET_CPU)-static.lib del $(LIBDIR)\$(PDCDIST)-wingui-$(TARGET_CPU)-static.lib + if exist $(LIBDIR)$(PDCDIST)-wincon-$(TARGET_CPU)-static.lib del $(LIBDIR)$(PDCDIST)-wincon-$(TARGET_CPU)-static.lib + if exist $(LIBDIR)$(PDCDIST)-wingui-$(TARGET_CPU)-static.lib del $(LIBDIR)$(PDCDIST)-wingui-$(TARGET_CPU)-static.lib !ENDIF if exist $(LUALIB) del $(LUALIB) - if exist $(DAT)\oracles del $(DAT)\oracles - if exist $(DAT)\rumors del $(DAT)\rumors - if exist $(DAT)\options del $(DAT)\options - if exist $(DAT)\ttyoptions del $(DAT)\ttyoptions - if exist $(DAT)\guioptions del $(DAT)\guioptions - if exist $(DAT)\data del $(DAT)\data + if exist $(DAT)oracles del $(DAT)oracles + if exist $(DAT)rumors del $(DAT)rumors + if exist $(DAT)options del $(DAT)options + if exist $(DAT)ttyoptions del $(DAT)ttyoptions + if exist $(DAT)guioptions del $(DAT)guioptions + if exist $(DAT)data del $(DAT)data if exist tilemappings.lst del tilemappings.lst - if exist $(SndWavDir)\*.wav del $(SndWavDir)\*.wav + if exist $(SndWavDir)*.wav del $(SndWavDir)*.wav if exist $(MAINZIP) del $(MAINZIP) if exist $(DBGSYMZIP) del $(DBGSYMZIP) - if exist $(OBJTTY)\* rmdir $(OBJTTY) /s /Q - if exist $(OBJGUI)\* rmdir $(OBJGUI) /s /Q - if exist $(OBJUTIL)\* rmdir $(OBJUTIL) /s /Q - if exist $(OBJLUA)\* rmdir $(OBJLUA) /s /Q - if exist $(OBJPDC)\* rmdir $(OBJPDC) /s /Q - if exist $(OBJPDCC)\* rmdir $(OBJPDCC) /s /Q - if exist $(OBJPDCG)\* rmdir $(OBJPDCG) /s /Q - if exist $(OBJTTY_B)\* rmdir $(OBJTTY_B) /s /Q - if exist $(OBJGUI_B)\* rmdir $(OBJGUI_B) /s /Q - if exist $(OBJUTIL_B)\* rmdir $(OBJUTIL_B) /s /Q - if exist $(OBJLUA_B)\* rmdir $(OBJLUA_B) /s /Q - if exist $(OBJPDC_B)\* rmdir $(OBJPDC_B) /s /Q - if exist $(OBJPDCC_B)\* rmdir $(OBJPDCC_B) /s /Q - if exist $(OBJPDCG_B)\* rmdir $(OBJPDCG_B) /s /Q + if exist $(OBJTTY)* rmdir $(OBJTTY) /s /Q + if exist $(OBJGUI)* rmdir $(OBJGUI) /s /Q + if exist $(OBJUTIL)* rmdir $(OBJUTIL) /s /Q + if exist $(OBJLUA)* rmdir $(OBJLUA) /s /Q + if exist $(OBJPDC)* rmdir $(OBJPDC) /s /Q + if exist $(OBJPDCC)* rmdir $(OBJPDCC) /s /Q + if exist $(OBJPDCG)* rmdir $(OBJPDCG) /s /Q + if exist $(OBJTTY_B)* rmdir $(OBJTTY_B) /s /Q + if exist $(OBJGUI_B)* rmdir $(OBJGUI_B) /s /Q + if exist $(OBJUTIL_B)* rmdir $(OBJUTIL_B) /s /Q + if exist $(OBJLUA_B)* rmdir $(OBJLUA_B) /s /Q + if exist $(OBJPDC_B)* rmdir $(OBJPDC_B) /s /Q + if exist $(OBJPDCC_B)* rmdir $(OBJPDCC_B) /s /Q + if exist $(OBJPDCG_B)* rmdir $(OBJPDCG_B) /s /Q clean: if exist binary.tag del binary.tag @@ -2469,14 +2652,14 @@ clean: if exist $(OUTL)utility.tag del $(OUTL)utility.tag if exist $(OTTY)sp_lev.tag del $(OTTY)sp_lev.tag if exist $(OGUI)sp_lev.tag del $(OGUI)sp_lev.tag - if exist $(SRC)\tile.c del $(SRC)\tile.c - if exist $(INCL)\nhlua.h del $(INCL)\nhlua.h + if exist $(SRC)tile.c del $(SRC)tile.c + if exist $(INCL)nhlua.h del $(INCL)nhlua.h if exist $(U)makedefs.exe del $(U)makedefs.exe if exist $(U)dlb_main.exe del $(U)dlb_main.exe if exist $(U)tile2bmp.exe del $(U)tile2bmp.exe if exist $(U)tilemap.exe del $(U)tilemap.exe - if exist $(SRC)\*.lnk del $(SRC)\*.lnk - if exist $(DAT)\dlb.lst del $(DAT)\dlb.lst + if exist $(SRC)*.lnk del $(SRC)*.lnk + if exist $(DAT)dlb.lst del $(DAT)dlb.lst if exist $(OUTL)*.o del $(OUTL)*.o if exist $(OTTY)*.o del $(OTTY)*.o if exist $(OGUI)*.o del $(OGUI)*.o @@ -2510,7 +2693,7 @@ clean: if exist $(OPDC)*.EXP del $(OPDC)*.EXP if exist $(OPDCC)*.EXP del $(OPDCC)*.EXP if exist $(OPDCG)*.EXP del $(OPDCG)*.EXP - if exist $(SRC)\tiles.bmp del $(SRC)\tiles.bmp + if exist $(SRC)tiles.bmp del $(SRC)tiles.bmp if exist $(OTTY)console.res del $(OTTY)console.res if exist $(OTTY)NetHack.res del $(OTTY)NetHack.res if exist $(OGUI)NetHackW.res del $(OGUI)NetHackW.res @@ -2521,7 +2704,7 @@ clean: # The rest are stolen from sys/unix/Makefile.src, # twice, with the following changes: # * the CONFIG_H and HACK_H sections comment out or removed completely -# * ../include/ changed to $(INCL)\ +# * ../include/ changed to $(INCL) # * slashes changed to back-slashes # * -c (which is included in cflagsBuild) substituted with -Fo$@ # * "-o $@ " is removed @@ -2549,15 +2732,15 @@ MOCPATH = moc.exe #$(OTTY)cppregex.o: ..\sys\share\cppregex.cpp $(CONFIG_H) # $(TARGET_CXX) $(TARGET_CXXFLAGS) -Fo$@ ..\sys\share\cppregex.cpp -$(OTTY)ioctl.o: ..\sys\share\ioctl.c $(HACK_H) $(INCL)\tcap.h +$(OTTY)ioctl.o: ..\sys\share\ioctl.c $(HACK_H) $(INCL)tcap.h # $(TARGET_CC) $(TARGET_CFLAGS) -Fo$@ ..\sys\share\ioctl.c -$(OTTY)pcmain.o: ..\sys\share\pcmain.c $(HACK_H) $(INCL)\dlb.h +$(OTTY)pcmain.o: ..\sys\share\pcmain.c $(HACK_H) $(INCL)dlb.h # $(TARGET_CC) $(TARGET_CFLAGS) -Fo$@ ..\sys\share\pcmain.c -$(OTTY)pcsys.o: ..\sys\share\pcsys.c $(HACK_H) $(INCL)\wintty.h +$(OTTY)pcsys.o: ..\sys\share\pcsys.c $(HACK_H) $(INCL)wintty.h # $(TARGET_CC) $(TARGET_CFLAGS) -Fo$@ ..\sys\share\pcsys.c -$(OTTY)pctty.o: ..\sys\share\pctty.c $(HACK_H) $(INCL)\wintty.h +$(OTTY)pctty.o: ..\sys\share\pctty.c $(HACK_H) $(INCL)wintty.h # $(TARGET_CC) $(TARGET_CFLAGS) -Fo$@ ..\sys\share\pctty.c -$(OTTY)pcunix.o: ..\sys\share\pcunix.c $(HACK_H) $(INCL)\wintty.h +$(OTTY)pcunix.o: ..\sys\share\pcunix.c $(HACK_H) $(INCL)wintty.h # $(TARGET_CC) $(TARGET_CFLAGS) -Fo$@ ..\sys\share\pcunix.c $(OTTY)pmatchregex.o: ..\sys\share\pmatchregex.c $(HACK_H) # $(TARGET_CC) $(TARGET_CFLAGS) -Fo$@ ..\sys\share\pmatchregex.c @@ -2567,14 +2750,14 @@ $(OTTY)random.o: ..\sys\share\random.c $(HACK_H) # $(TARGET_CC) $(TARGET_CFLAGS) -Fo$@ ..\sys\share\random.c $(OTTY)unixtty.o: ..\sys\share\unixtty.c $(HACK_H) # $(TARGET_CC) $(TARGET_CFLAGS) -Fo$@ ..\sys\share\unixtty.c -$(OTTY)unixmain.o: ..\sys\unix\unixmain.c $(HACK_H) $(INCL)\dlb.h +$(OTTY)unixmain.o: ..\sys\unix\unixmain.c $(HACK_H) $(INCL)dlb.h # $(TARGET_CC) $(TARGET_CFLAGS) -Fo$@ ..\sys\unix\unixmain.c $(OTTY)unixres.o: ..\sys\unix\unixres.c $(CONFIG_H) # $(TARGET_CC) $(TARGET_CFLAGS) -Fo$@ ..\sys\unix\unixres.c $(OTTY)unixunix.o: ..\sys\unix\unixunix.c $(HACK_H) # $(TARGET_CC) $(TARGET_CFLAGS) -Fo$@ ..\sys\unix\unixunix.c $(OTTY)qt_bind.o: ..\win\Qt\qt_bind.cpp $(HACK_H) $(QTn_H) \ - $(INCL)\dlb.h ..\win\Qt\qt_bind.h ..\win\Qt\qt_click.h \ + $(INCL)dlb.h ..\win\Qt\qt_bind.h ..\win\Qt\qt_click.h \ ..\win\Qt\qt_clust.h ..\win\Qt\qt_delay.h ..\win\Qt\qt_icon.h \ ..\win\Qt\qt_kde0.h ..\win\Qt\qt_key.h ..\win\Qt\qt_line.h \ ..\win\Qt\qt_main.h ..\win\Qt\qt_map.h ..\win\Qt\qt_menu.h \ @@ -2593,7 +2776,7 @@ $(OTTY)qt_delay.o: ..\win\Qt\qt_delay.cpp $(HACK_H) $(QTn_H) \ ..\win\Qt\qt_delay.h ..\win\Qt\qt_post.h ..\win\Qt\qt_pre.h $(TARGET_CXX) $(TARGET_CXXFLAGS) -Fo$@ ..\win\Qt\qt_delay.cpp $(OTTY)qt_glyph.o: ..\win\Qt\qt_glyph.cpp $(HACK_H) $(QTn_H) \ - $(INCL)\tile2x11.h ..\win\Qt\qt_bind.h \ + $(INCL)tile2x11.h ..\win\Qt\qt_bind.h \ ..\win\Qt\qt_clust.h ..\win\Qt\qt_glyph.h ..\win\Qt\qt_inv.h \ ..\win\Qt\qt_kde0.h ..\win\Qt\qt_main.h ..\win\Qt\qt_map.h \ ..\win\Qt\qt_post.h ..\win\Qt\qt_pre.h ..\win\Qt\qt_set.h \ @@ -2686,7 +2869,7 @@ $(OTTY)qt_win.o: ..\win\Qt\qt_win.cpp $(HACK_H) $(QTn_H) \ ..\win\Qt\qt_set.h ..\win\Qt\qt_win.h $(TARGET_CXX) $(TARGET_CXXFLAGS) -Fo$@ ..\win\Qt\qt_win.cpp $(OTTY)qt_xcmd.o: ..\win\Qt\qt_xcmd.cpp $(HACK_H) $(QTn_H) \ - $(INCL)\func_tab.h ..\win\Qt\qt_bind.h ..\win\Qt\qt_kde0.h \ + $(INCL)func_tab.h ..\win\Qt\qt_bind.h ..\win\Qt\qt_kde0.h \ ..\win\Qt\qt_key.h ..\win\Qt\qt_main.h ..\win\Qt\qt_post.h \ ..\win\Qt\qt_pre.h ..\win\Qt\qt_set.h ..\win\Qt\qt_str.h \ ..\win\Qt\qt_xcmd.h qt_xcmd.moc @@ -2695,119 +2878,119 @@ $(OTTY)qt_yndlg.o: ..\win\Qt\qt_yndlg.cpp $(HACK_H) $(QTn_H) \ ..\win\Qt\qt_key.h ..\win\Qt\qt_post.h ..\win\Qt\qt_pre.h \ ..\win\Qt\qt_str.h ..\win\Qt\qt_yndlg.h qt_yndlg.moc $(TARGET_CXX) $(TARGET_CXXFLAGS) -Fo$@ ..\win\Qt\qt_yndlg.cpp -#$(OTTY)Window.o: ..\win\X11\Window.c $(CONFIG_H) $(INCL)\lint.h \ -# $(INCL)\winX.h $(INCL)\wintype.h $(INCL)\xwindow.h \ -# $(INCL)\xwindowp.h +#$(OTTY)Window.o: ..\win\X11\Window.c $(CONFIG_H) $(INCL)lint.h \ +# $(INCL)winX.h $(INCL)wintype.h $(INCL)xwindow.h \ +# $(INCL)xwindowp.h # $(TARGET_CC) $(TARGET_CFLAGS) $(X11CFLAGS) -Fo$@ ..\win\X11\Window.c -$(OTTY)dialogs.o: ..\win\X11\dialogs.c $(CONFIG_H) $(INCL)\lint.h \ - $(INCL)\winX.h $(INCL)\wintype.h +$(OTTY)dialogs.o: ..\win\X11\dialogs.c $(CONFIG_H) $(INCL)lint.h \ + $(INCL)winX.h $(INCL)wintype.h # $(TARGET_CC) $(TARGET_CFLAGS) $(X11CFLAGS) -Fo$@ ..\win\X11\dialogs.c -$(OTTY)winX.o: ..\win\X11\winX.c $(HACK_H) $(INCL)\dlb.h \ - $(INCL)\winX.h $(INCL)\xwindow.h ..\win\X11\nh32icon \ +$(OTTY)winX.o: ..\win\X11\winX.c $(HACK_H) $(INCL)dlb.h \ + $(INCL)winX.h $(INCL)xwindow.h ..\win\X11\nh32icon \ ..\win\X11\nh56icon ..\win\X11\nh72icon # $(TARGET_CC) $(TARGET_CFLAGS) $(X11CFLAGS) -Fo$@ ..\win\X11\winX.c -$(OTTY)winmap.o: ..\win\X11\winmap.c $(HACK_H) $(INCL)\dlb.h \ - $(INCL)\tile2x11.h $(INCL)\winX.h $(INCL)\xwindow.h +$(OTTY)winmap.o: ..\win\X11\winmap.c $(HACK_H) $(INCL)dlb.h \ + $(INCL)tile2x11.h $(INCL)winX.h $(INCL)xwindow.h # $(TARGET_CC) $(TARGET_CFLAGS) $(X11CFLAGS) -Fo$@ ..\win\X11\winmap.c -$(OTTY)winmenu.o: ..\win\X11\winmenu.c $(HACK_H) $(INCL)\winX.h +$(OTTY)winmenu.o: ..\win\X11\winmenu.c $(HACK_H) $(INCL)winX.h # $(TARGET_CC) $(TARGET_CFLAGS) $(X11CFLAGS) -Fo$@ ..\win\X11\winmenu.c -$(OTTY)winmesg.o: ..\win\X11\winmesg.c $(HACK_H) $(INCL)\winX.h \ - $(INCL)\xwindow.h +$(OTTY)winmesg.o: ..\win\X11\winmesg.c $(HACK_H) $(INCL)winX.h \ + $(INCL)xwindow.h # $(TARGET_CC) $(TARGET_CFLAGS) $(X11CFLAGS) -Fo$@ ..\win\X11\winmesg.c -$(OTTY)winmisc.o: ..\win\X11\winmisc.c $(HACK_H) $(INCL)\func_tab.h \ - $(INCL)\winX.h +$(OTTY)winmisc.o: ..\win\X11\winmisc.c $(HACK_H) $(INCL)func_tab.h \ + $(INCL)winX.h # $(TARGET_CC) $(TARGET_CFLAGS) $(X11CFLAGS) -Fo$@ ..\win\X11\winmisc.c -$(OTTY)winstat.o: ..\win\X11\winstat.c $(HACK_H) $(INCL)\winX.h \ - $(INCL)\xwindow.h +$(OTTY)winstat.o: ..\win\X11\winstat.c $(HACK_H) $(INCL)winX.h \ + $(INCL)xwindow.h # $(TARGET_CC) $(TARGET_CFLAGS) $(X11CFLAGS) -Fo$@ ..\win\X11\winstat.c -$(OTTY)wintext.o: ..\win\X11\wintext.c $(HACK_H) $(INCL)\winX.h \ - $(INCL)\xwindow.h +$(OTTY)wintext.o: ..\win\X11\wintext.c $(HACK_H) $(INCL)winX.h \ + $(INCL)xwindow.h # $(TARGET_CC) $(TARGET_CFLAGS) $(X11CFLAGS) -Fo$@ ..\win\X11\wintext.c -$(OTTY)winval.o: ..\win\X11\winval.c $(HACK_H) $(INCL)\winX.h +$(OTTY)winval.o: ..\win\X11\winval.c $(HACK_H) $(INCL)winX.h # $(TARGET_CC) $(TARGET_CFLAGS) $(X11CFLAGS) -Fo$@ ..\win\X11\winval.c $(OTTY)wc_chainin.o: ..\win\chain\wc_chainin.c $(HACK_H) # $(TARGET_CC) $(TARGET_CFLAGS) -Fo$@ ..\win\chain\wc_chainin.c $(OTTY)wc_chainout.o: ..\win\chain\wc_chainout.c $(HACK_H) # $(TARGET_CC) $(TARGET_CFLAGS) -Fo$@ ..\win\chain\wc_chainout.c $(OTTY)wc_trace.o: ..\win\chain\wc_trace.c $(HACK_H) \ - $(INCL)\func_tab.h $(INCL)\wintty.h + $(INCL)func_tab.h $(INCL)wintty.h # $(TARGET_CC) $(TARGET_CFLAGS) -Fo$@ ..\win\chain\wc_trace.c $(OTTY)cursdial.o: ..\win\curses\cursdial.c $(HACK_H) \ - $(INCL)\func_tab.h $(INCL)\wincurs.h \ + $(INCL)func_tab.h $(INCL)wincurs.h \ ..\win\curses\cursdial.h # $(TARGET_CC) $(TARGET_CFLAGS) -Fo$@ ..\win\curses\cursdial.c $(OTTY)cursinit.o: ..\win\curses\cursinit.c $(HACK_H) \ - $(INCL)\wincurs.h ..\win\curses\cursinit.h + $(INCL)wincurs.h ..\win\curses\cursinit.h # $(TARGET_CC) $(TARGET_CFLAGS) -Fo$@ ..\win\curses\cursinit.c $(OTTY)cursinvt.o: ..\win\curses\cursinvt.c $(HACK_H) \ - $(INCL)\wincurs.h ..\win\curses\cursinvt.h + $(INCL)wincurs.h ..\win\curses\cursinvt.h # $(TARGET_CC) $(TARGET_CFLAGS) -Fo$@ ..\win\curses\cursinvt.c -$(OTTY)cursmain.o: ..\win\curses\cursmain.c $(HACK_H) $(INCL)\wincurs.h +$(OTTY)cursmain.o: ..\win\curses\cursmain.c $(HACK_H) $(INCL)wincurs.h # $(TARGET_CC) $(TARGET_CFLAGS) -Fo$@ ..\win\curses\cursmain.c $(OTTY)cursmesg.o: ..\win\curses\cursmesg.c $(HACK_H) \ - $(INCL)\wincurs.h ..\win\curses\cursmesg.h + $(INCL)wincurs.h ..\win\curses\cursmesg.h # $(TARGET_CC) $(TARGET_CFLAGS) -Fo$@ ..\win\curses\cursmesg.c -$(OTTY)cursmisc.o: ..\win\curses\cursmisc.c $(HACK_H) $(INCL)\dlb.h \ - $(INCL)\func_tab.h $(INCL)\wincurs.h \ +$(OTTY)cursmisc.o: ..\win\curses\cursmisc.c $(HACK_H) $(INCL)dlb.h \ + $(INCL)func_tab.h $(INCL)wincurs.h \ ..\win\curses\cursmisc.h # $(TARGET_CC) $(TARGET_CFLAGS) -Fo$@ ..\win\curses\cursmisc.c $(OTTY)cursstat.o: ..\win\curses\cursstat.c $(HACK_H) \ - $(INCL)\wincurs.h ..\win\curses\cursstat.h + $(INCL)wincurs.h ..\win\curses\cursstat.h # $(TARGET_CC) $(TARGET_CFLAGS) -Fo$@ ..\win\curses\cursstat.c $(OTTY)curswins.o: ..\win\curses\curswins.c $(HACK_H) \ - $(INCL)\wincurs.h ..\win\curses\curswins.h + $(INCL)wincurs.h ..\win\curses\curswins.h # $(TARGET_CC) $(TARGET_CFLAGS) -Fo$@ ..\win\curses\curswins.c $(OTTY)winshim.o: ..\win\shim\winshim.c $(HACK_H) # $(TARGET_CC) $(TARGET_CFLAGS) -Fo$@ ..\win\shim\winshim.c -$(OTTY)getline.o: ..\win\tty\getline.c $(HACK_H) $(INCL)\func_tab.h \ - $(INCL)\wintty.h +$(OTTY)getline.o: ..\win\tty\getline.c $(HACK_H) $(INCL)func_tab.h \ + $(INCL)wintty.h # $(TARGET_CC) $(TARGET_CFLAGS) -Fo$@ ..\win\tty\getline.c -$(OTTY)termcap.o: ..\win\tty\termcap.c $(HACK_H) $(INCL)\tcap.h \ - $(INCL)\wintty.h +$(OTTY)termcap.o: ..\win\tty\termcap.c $(HACK_H) $(INCL)tcap.h \ + $(INCL)wintty.h # $(TARGET_CC) $(TARGET_CFLAGS) -Fo$@ ..\win\tty\termcap.c -$(OTTY)topl.o: ..\win\tty\topl.c $(HACK_H) $(INCL)\tcap.h \ - $(INCL)\wintty.h +$(OTTY)topl.o: ..\win\tty\topl.c $(HACK_H) $(INCL)tcap.h \ + $(INCL)wintty.h # $(TARGET_CC) $(TARGET_CFLAGS) -Fo$@ ..\win\tty\topl.c -$(OTTY)wintty.o: ..\win\tty\wintty.c $(HACK_H) $(INCL)\dlb.h \ - $(INCL)\tcap.h $(INCL)\wintty.h +$(OTTY)wintty.o: ..\win\tty\wintty.c $(HACK_H) $(INCL)dlb.h \ + $(INCL)tcap.h $(INCL)wintty.h # $(TARGET_CC) $(TARGET_CFLAGS) -Fo$@ ..\win\tty\wintty.c $(OTTY)allmain.o: allmain.c $(HACK_H) -$(OTTY)alloc.o: alloc.c $(CONFIG_H) $(INCL)\nhlua.h +$(OTTY)alloc.o: alloc.c $(CONFIG_H) $(INCL)nhlua.h $(OTTY)apply.o: apply.c $(HACK_H) -$(OTTY)artifact.o: artifact.c $(HACK_H) $(INCL)\artifact.h +$(OTTY)artifact.o: artifact.c $(HACK_H) $(INCL)artifact.h $(OTTY)attrib.o: attrib.c $(HACK_H) $(OTTY)ball.o: ball.c $(HACK_H) $(OTTY)bones.o: bones.c $(HACK_H) $(OTTY)botl.o: botl.c $(HACK_H) $(OTTY)calendar.o: calendar.c $(HACK_H) -$(OTTY)cmd.o: cmd.c $(HACK_H) $(INCL)\func_tab.h +$(OTTY)cmd.o: cmd.c $(HACK_H) $(INCL)func_tab.h $(OTTY)coloratt.o: coloratt.c $(HACK_H) $(OTTY)dbridge.o: dbridge.c $(HACK_H) $(OTTY)decl.o: decl.c $(HACK_H) -$(OTTY)detect.o: detect.c $(HACK_H) $(INCL)\artifact.h +$(OTTY)detect.o: detect.c $(HACK_H) $(INCL)artifact.h $(OTTY)dig.o: dig.c $(HACK_H) $(OTTY)display.o: display.c $(HACK_H) -$(OTTY)dlb.o: dlb.c $(CONFIG_H) $(INCL)\dlb.h +$(OTTY)dlb.o: dlb.c $(CONFIG_H) $(INCL)dlb.h $(OTTY)do.o: do.c $(HACK_H) $(OTTY)do_name.o: do_name.c $(HACK_H) $(OTTY)do_wear.o: do_wear.c $(HACK_H) $(OTTY)dog.o: dog.c $(HACK_H) -$(OTTY)dogmove.o: dogmove.c $(HACK_H) $(INCL)\mfndpos.h +$(OTTY)dogmove.o: dogmove.c $(HACK_H) $(INCL)mfndpos.h $(OTTY)dokick.o: dokick.c $(HACK_H) $(OTTY)dothrow.o: dothrow.c $(HACK_H) -$(OTTY)drawing.o: drawing.c $(CONFIG_H) $(INCL)\defsym.h \ - $(INCL)\objclass.h $(INCL)\objects.h $(INCL)\rm.h \ - $(INCL)\sym.h $(INCL)\wintype.h -$(OTTY)dungeon.o: dungeon.c $(HACK_H) $(INCL)\dgn_file.h \ - $(INCL)\dlb.h +$(OTTY)drawing.o: drawing.c $(CONFIG_H) $(INCL)defsym.h \ + $(INCL)objclass.h $(INCL)objects.h $(INCL)rm.h \ + $(INCL)sym.h $(INCL)wintype.h +$(OTTY)dungeon.o: dungeon.c $(HACK_H) $(INCL)dgn_file.h \ + $(INCL)dlb.h $(OTTY)eat.o: eat.c $(HACK_H) -$(OTTY)end.o: end.c $(HACK_H) $(INCL)\dlb.h +$(OTTY)end.o: end.c $(HACK_H) $(INCL)dlb.h $(OTTY)engrave.o: engrave.c $(HACK_H) $(OTTY)exper.o: exper.c $(HACK_H) $(OTTY)explode.o: explode.c $(HACK_H) $(OTTY)extralev.o: extralev.c $(HACK_H) -$(OTTY)files.o: files.c $(HACK_H) $(INCL)\dlb.h \ - $(INCL)\wintty.h +$(OTTY)files.o: files.c $(HACK_H) $(INCL)dlb.h \ + $(INCL)wintty.h $(OTTY)fountain.o: fountain.c $(HACK_H) $(OTTY)getpos.o: getpos.c $(HACK_H) $(OTTY)glyphs.o: glyphs.c $(HACK_H) @@ -2815,109 +2998,109 @@ $(OTTY)hack.o: hack.c $(HACK_H) $(OTTY)hacklib.o: hacklib.c $(HACK_H) $(OTTY)insight.o: insight.c $(HACK_H) $(OTTY)invent.o: invent.c $(HACK_H) -$(OTTY)isaac64.o: isaac64.c $(CONFIG_H) $(INCL)\isaac64.h +$(OTTY)isaac64.o: isaac64.c $(CONFIG_H) $(INCL)isaac64.h $(OTTY)light.o: light.c $(HACK_H) $(OTTY)lock.o: lock.c $(HACK_H) -$(OTTY)mail.o: mail.c $(HACK_H) $(INCL)\mail.h +$(OTTY)mail.o: mail.c $(HACK_H) $(INCL)mail.h $(OTTY)makemon.o: makemon.c $(HACK_H) $(OTTY)mcastu.o: mcastu.c $(HACK_H) -$(OTTY)mdlib.o: mdlib.c $(CONFIG_H) $(INCL)\align.h \ - $(INCL)\artilist.h $(INCL)\attrib.h \ - $(INCL)\context.h $(INCL)\defsym.h $(INCL)\dlb.h \ - $(INCL)\dungeon.h $(INCL)\flag.h $(INCL)\hacklib.h \ - $(INCL)\mextra.h $(INCL)\monattk.h $(INCL)\monflag.h \ - $(INCL)\monst.h $(INCL)\monsters.h $(INCL)\obj.h \ - $(INCL)\objclass.h $(INCL)\objects.h \ - $(INCL)\permonst.h $(INCL)\prop.h $(INCL)\seffects.h \ - $(INCL)\skills.h $(INCL)\sndprocs.h $(INCL)\sym.h \ - $(INCL)\wintype.h $(INCL)\you.h -$(OTTY)mhitm.o: mhitm.c $(HACK_H) $(INCL)\artifact.h -$(OTTY)mhitu.o: mhitu.c $(HACK_H) $(INCL)\artifact.h +$(OTTY)mdlib.o: mdlib.c $(CONFIG_H) $(INCL)align.h \ + $(INCL)artilist.h $(INCL)attrib.h \ + $(INCL)context.h $(INCL)defsym.h $(INCL)dlb.h \ + $(INCL)dungeon.h $(INCL)flag.h $(INCL)hacklib.h \ + $(INCL)mextra.h $(INCL)monattk.h $(INCL)monflag.h \ + $(INCL)monst.h $(INCL)monsters.h $(INCL)obj.h \ + $(INCL)objclass.h $(INCL)objects.h \ + $(INCL)permonst.h $(INCL)prop.h $(INCL)seffects.h \ + $(INCL)skills.h $(INCL)sndprocs.h $(INCL)sym.h \ + $(INCL)wintype.h $(INCL)you.h +$(OTTY)mhitm.o: mhitm.c $(HACK_H) $(INCL)artifact.h +$(OTTY)mhitu.o: mhitu.c $(HACK_H) $(INCL)artifact.h $(OTTY)minion.o: minion.c $(HACK_H) $(OTTY)mklev.o: mklev.c $(HACK_H) -$(OTTY)mkmap.o: mkmap.c $(HACK_H) $(INCL)\sp_lev.h -$(OTTY)mkmaze.o: mkmaze.c $(HACK_H) $(INCL)\sp_lev.h +$(OTTY)mkmap.o: mkmap.c $(HACK_H) $(INCL)sp_lev.h +$(OTTY)mkmaze.o: mkmaze.c $(HACK_H) $(INCL)sp_lev.h $(OTTY)mkobj.o: mkobj.c $(HACK_H) $(OTTY)mkroom.o: mkroom.c $(HACK_H) -$(OTTY)mon.o: mon.c $(HACK_H) $(INCL)\mfndpos.h +$(OTTY)mon.o: mon.c $(HACK_H) $(INCL)mfndpos.h $(OTTY)mondata.o: mondata.c $(HACK_H) -$(OTTY)monmove.o: monmove.c $(HACK_H) $(INCL)\artifact.h \ - $(INCL)\mfndpos.h -$(OTTY)monst.o: monst.c $(CONFIG_H) $(INCL)\align.h \ - $(INCL)\defsym.h $(INCL)\monattk.h $(INCL)\monflag.h \ - $(INCL)\monsters.h $(INCL)\permonst.h $(INCL)\sym.h \ - $(INCL)\wintype.h +$(OTTY)monmove.o: monmove.c $(HACK_H) $(INCL)artifact.h \ + $(INCL)mfndpos.h +$(OTTY)monst.o: monst.c $(CONFIG_H) $(INCL)align.h \ + $(INCL)defsym.h $(INCL)monattk.h $(INCL)monflag.h \ + $(INCL)monsters.h $(INCL)permonst.h $(INCL)sym.h \ + $(INCL)wintype.h $(OTTY)mplayer.o: mplayer.c $(HACK_H) $(OTTY)mthrowu.o: mthrowu.c $(HACK_H) $(OTTY)muse.o: muse.c $(HACK_H) $(OTTY)music.o: music.c $(HACK_H) -$(OTTY)nhlobj.o: nhlobj.c $(HACK_H) $(INCL)\sp_lev.h -$(OTTY)nhlsel.o: nhlsel.c $(HACK_H) $(INCL)\sp_lev.h -$(OTTY)nhlua.o: nhlua.c $(HACK_H) $(INCL)\dlb.h +$(OTTY)nhlobj.o: nhlobj.c $(HACK_H) $(INCL)sp_lev.h +$(OTTY)nhlsel.o: nhlsel.c $(HACK_H) $(INCL)sp_lev.h +$(OTTY)nhlua.o: nhlua.c $(HACK_H) $(INCL)dlb.h $(Q)$(CC) $(CFLAGS) $(TTYDEF) -wd4324 $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) -Fo$@ $(@B).c -$(OTTY)nhmd4.o: nhmd4.c $(HACK_H) $(INCL)\nhmd4.h +$(OTTY)nhmd4.o: nhmd4.c $(HACK_H) $(INCL)nhmd4.h $(OTTY)o_init.o: o_init.c $(HACK_H) -$(OTTY)objects.o: objects.c $(CONFIG_H) $(INCL)\defsym.h \ - $(INCL)\obj.h $(INCL)\objclass.h $(INCL)\objects.h \ - $(INCL)\prop.h $(INCL)\skills.h +$(OTTY)objects.o: objects.c $(CONFIG_H) $(INCL)defsym.h \ + $(INCL)obj.h $(INCL)objclass.h $(INCL)objects.h \ + $(INCL)prop.h $(INCL)skills.h $(OTTY)objnam.o: objnam.c $(HACK_H) -$(OTTY)options.o: options.c $(CONFIG_H) $(HACK_H) $(INCL)\defsym.h \ - $(INCL)\flag.h $(INCL)\objclass.h $(INCL)\objects.h \ - $(INCL)\optlist.h $(INCL)\tcap.h -$(OTTY)pager.o: pager.c $(HACK_H) $(INCL)\dlb.h +$(OTTY)options.o: options.c $(CONFIG_H) $(HACK_H) $(INCL)defsym.h \ + $(INCL)flag.h $(INCL)objclass.h $(INCL)objects.h \ + $(INCL)optlist.h $(INCL)tcap.h +$(OTTY)pager.o: pager.c $(HACK_H) $(INCL)dlb.h $(OTTY)pickup.o: pickup.c $(HACK_H) $(OTTY)pline.o: pline.c $(HACK_H) $(OTTY)polyself.o: polyself.c $(HACK_H) $(OTTY)potion.o: potion.c $(HACK_H) $(OTTY)pray.o: pray.c $(HACK_H) -$(OTTY)priest.o: priest.c $(HACK_H) $(INCL)\mfndpos.h +$(OTTY)priest.o: priest.c $(HACK_H) $(INCL)mfndpos.h $(OTTY)quest.o: quest.c $(HACK_H) -$(OTTY)questpgr.o: questpgr.c $(HACK_H) $(INCL)\dlb.h \ - $(INCL)\wintty.h +$(OTTY)questpgr.o: questpgr.c $(HACK_H) $(INCL)dlb.h \ + $(INCL)wintty.h $(OTTY)read.o: read.c $(HACK_H) $(OTTY)rect.o: rect.c $(HACK_H) $(OTTY)region.o: region.c $(HACK_H) -$(OTTY)report.o: report.c $(HACK_H) $(INCL)\dlb.h $(INCL)\nhmd4.h -$(OTTY)restore.o: restore.c $(HACK_H) $(INCL)\tcap.h +$(OTTY)report.o: report.c $(HACK_H) $(INCL)dlb.h $(INCL)nhmd4.h +$(OTTY)restore.o: restore.c $(HACK_H) $(INCL)tcap.h $(OTTY)rip.o: rip.c $(HACK_H) -$(OTTY)rnd.o: rnd.c $(HACK_H) $(INCL)\isaac64.h +$(OTTY)rnd.o: rnd.c $(HACK_H) $(INCL)isaac64.h $(OTTY)role.o: role.c $(HACK_H) -$(OTTY)rumors.o: rumors.c $(HACK_H) $(INCL)\dlb.h +$(OTTY)rumors.o: rumors.c $(HACK_H) $(INCL)dlb.h $(OTTY)save.o: save.c $(HACK_H) -$(OTTY)selvar.o: selvar.c $(HACK_H) $(INCL)\sp_lev.h +$(OTTY)selvar.o: selvar.c $(HACK_H) $(INCL)sp_lev.h $(OTTY)sfstruct.o: sfstruct.c $(HACK_H) $(OTTY)shk.o: shk.c $(HACK_H) $(OTTY)shknam.o: shknam.c $(HACK_H) -$(OTTY)sit.o: sit.c $(HACK_H) $(INCL)\artifact.h +$(OTTY)sit.o: sit.c $(HACK_H) $(INCL)artifact.h $(Q)$(CC) $(CFLAGS) /EP $(@B).c > $(OTTY)$(@B).c.preproc $(Q)$(CC) $(CFLAGS) -Fo$@ $(@B).c $(OTTY)sounds.o: sounds.c $(HACK_H) -$(OTTY)sp_lev.o: sp_lev.c $(HACK_H) $(INCL)\sp_lev.h +$(OTTY)sp_lev.o: sp_lev.c $(HACK_H) $(INCL)sp_lev.h $(OTTY)spell.o: spell.c $(HACK_H) $(OTTY)stairs.o: stairs.c $(HACK_H) $(OTTY)steal.o: steal.c $(HACK_H) $(OTTY)steed.o: steed.c $(HACK_H) $(OTTY)strutil.o: strutil.c $(HACK_H) -$(OTTY)symbols.o: symbols.c $(HACK_H) $(INCL)\tcap.h +$(OTTY)symbols.o: symbols.c $(HACK_H) $(INCL)tcap.h $(OTTY)sys.o: sys.c $(HACK_H) $(OTTY)teleport.o: teleport.c $(HACK_H) #$(OTTY)tile.o: tile.c $(HACK_H) $(OTTY)timeout.o: timeout.c $(HACK_H) -$(OTTY)topten.o: topten.c $(HACK_H) $(INCL)\dlb.h +$(OTTY)topten.o: topten.c $(HACK_H) $(INCL)dlb.h $(OTTY)track.o: track.c $(HACK_H) $(OTTY)trap.o: trap.c $(HACK_H) $(OTTY)u_init.o: u_init.c $(HACK_H) $(OTTY)uhitm.o: uhitm.c $(HACK_H) $(OTTY)utf8map.o: utf8map.c $(HACK_H) $(OTTY)vault.o: vault.c $(HACK_H) -$(OTTY)version.o: version.c $(HACK_H) $(INCL)\dlb.h +$(OTTY)version.o: version.c $(HACK_H) $(INCL)dlb.h $(OTTY)vision.o: vision.c $(HACK_H) $(OTTY)weapon.o: weapon.c $(HACK_H) $(OTTY)were.o: were.c $(HACK_H) $(OTTY)wield.o: wield.c $(HACK_H) -$(OTTY)windows.o: windows.c $(HACK_H) $(INCL)\dlb.h $(INCL)\wintty.h +$(OTTY)windows.o: windows.c $(HACK_H) $(INCL)dlb.h $(INCL)wintty.h $(OTTY)wizard.o: wizard.c $(HACK_H) -$(OTTY)wizcmds.o: wizcmds.c $(HACK_H) $(INCL)\func_tab.h +$(OTTY)wizcmds.o: wizcmds.c $(HACK_H) $(INCL)func_tab.h $(OTTY)worm.o: worm.c $(HACK_H) $(OTTY)worn.o: worn.c $(HACK_H) $(OTTY)write.o: write.c $(HACK_H) @@ -2925,15 +3108,15 @@ $(OTTY)zap.o: zap.c $(HACK_H) # #$(OGUI)cppregex.o: ..\sys\share\cppregex.cpp $(CONFIG_H) # $(TARGET_CXX) $(TARGET_CXXFLAGS) -Fo$@ ..\sys\share\cppregex.cpp -$(OGUI)ioctl.o: ..\sys\share\ioctl.c $(HACK_H) $(INCL)\tcap.h +$(OGUI)ioctl.o: ..\sys\share\ioctl.c $(HACK_H) $(INCL)tcap.h # $(TARGET_CC) $(TARGET_CFLAGS) -Fo$@ ..\sys\share\ioctl.c -$(OGUI)pcmain.o: ..\sys\share\pcmain.c $(HACK_H) $(INCL)\dlb.h +$(OGUI)pcmain.o: ..\sys\share\pcmain.c $(HACK_H) $(INCL)dlb.h # $(TARGET_CC) $(TARGET_CFLAGS) -Fo$@ ..\sys\share\pcmain.c -$(OGUI)pcsys.o: ..\sys\share\pcsys.c $(HACK_H) $(INCL)\wintty.h +$(OGUI)pcsys.o: ..\sys\share\pcsys.c $(HACK_H) $(INCL)wintty.h # $(TARGET_CC) $(TARGET_CFLAGS) -Fo$@ ..\sys\share\pcsys.c -$(OGUI)pctty.o: ..\sys\share\pctty.c $(HACK_H) $(INCL)\wintty.h +$(OGUI)pctty.o: ..\sys\share\pctty.c $(HACK_H) $(INCL)wintty.h # $(TARGET_CC) $(TARGET_CFLAGS) -Fo$@ ..\sys\share\pctty.c -$(OGUI)pcunix.o: ..\sys\share\pcunix.c $(HACK_H) $(INCL)\wintty.h +$(OGUI)pcunix.o: ..\sys\share\pcunix.c $(HACK_H) $(INCL)wintty.h # $(TARGET_CC) $(TARGET_CFLAGS) -Fo$@ ..\sys\share\pcunix.c $(OGUI)pmatchregex.o: ..\sys\share\pmatchregex.c $(HACK_H) # $(TARGET_CC) $(TARGET_CFLAGS) -Fo$@ ..\sys\share\pmatchregex.c @@ -2943,14 +3126,14 @@ $(OGUI)random.o: ..\sys\share\random.c $(HACK_H) # $(TARGET_CC) $(TARGET_CFLAGS) -Fo$@ ..\sys\share\random.c $(OGUI)unixtty.o: ..\sys\share\unixtty.c $(HACK_H) # $(TARGET_CC) $(TARGET_CFLAGS) -Fo$@ ..\sys\share\unixtty.c -$(OGUI)unixmain.o: ..\sys\unix\unixmain.c $(HACK_H) $(INCL)\dlb.h +$(OGUI)unixmain.o: ..\sys\unix\unixmain.c $(HACK_H) $(INCL)dlb.h # $(TARGET_CC) $(TARGET_CFLAGS) -Fo$@ ..\sys\unix\unixmain.c $(OGUI)unixres.o: ..\sys\unix\unixres.c $(CONFIG_H) # $(TARGET_CC) $(TARGET_CFLAGS) -Fo$@ ..\sys\unix\unixres.c $(OGUI)unixunix.o: ..\sys\unix\unixunix.c $(HACK_H) # $(TARGET_CC) $(TARGET_CFLAGS) -Fo$@ ..\sys\unix\unixunix.c $(OGUI)qt_bind.o: ..\win\Qt\qt_bind.cpp $(HACK_H) $(QTn_H) \ - $(INCL)\dlb.h ..\win\Qt\qt_bind.h ..\win\Qt\qt_click.h \ + $(INCL)dlb.h ..\win\Qt\qt_bind.h ..\win\Qt\qt_click.h \ ..\win\Qt\qt_clust.h ..\win\Qt\qt_delay.h ..\win\Qt\qt_icon.h \ ..\win\Qt\qt_kde0.h ..\win\Qt\qt_key.h ..\win\Qt\qt_line.h \ ..\win\Qt\qt_main.h ..\win\Qt\qt_map.h ..\win\Qt\qt_menu.h \ @@ -2969,7 +3152,7 @@ $(OGUI)qt_delay.o: ..\win\Qt\qt_delay.cpp $(HACK_H) $(QTn_H) \ ..\win\Qt\qt_delay.h ..\win\Qt\qt_post.h ..\win\Qt\qt_pre.h $(TARGET_CXX) $(TARGET_CXXFLAGS) -Fo$@ ..\win\Qt\qt_delay.cpp $(OGUI)qt_glyph.o: ..\win\Qt\qt_glyph.cpp $(HACK_H) $(QTn_H) \ - $(INCL)\tile2x11.h ..\win\Qt\qt_bind.h \ + $(INCL)tile2x11.h ..\win\Qt\qt_bind.h \ ..\win\Qt\qt_clust.h ..\win\Qt\qt_glyph.h ..\win\Qt\qt_inv.h \ ..\win\Qt\qt_kde0.h ..\win\Qt\qt_main.h ..\win\Qt\qt_map.h \ ..\win\Qt\qt_post.h ..\win\Qt\qt_pre.h ..\win\Qt\qt_set.h \ @@ -3062,7 +3245,7 @@ $(OGUI)qt_win.o: ..\win\Qt\qt_win.cpp $(HACK_H) $(QTn_H) \ ..\win\Qt\qt_set.h ..\win\Qt\qt_win.h $(TARGET_CXX) $(TARGET_CXXFLAGS) -Fo$@ ..\win\Qt\qt_win.cpp $(OGUI)qt_xcmd.o: ..\win\Qt\qt_xcmd.cpp $(HACK_H) $(QTn_H) \ - $(INCL)\func_tab.h ..\win\Qt\qt_bind.h ..\win\Qt\qt_kde0.h \ + $(INCL)func_tab.h ..\win\Qt\qt_bind.h ..\win\Qt\qt_kde0.h \ ..\win\Qt\qt_key.h ..\win\Qt\qt_main.h ..\win\Qt\qt_post.h \ ..\win\Qt\qt_pre.h ..\win\Qt\qt_set.h ..\win\Qt\qt_str.h \ ..\win\Qt\qt_xcmd.h qt_xcmd.moc @@ -3071,119 +3254,119 @@ $(OGUI)qt_yndlg.o: ..\win\Qt\qt_yndlg.cpp $(HACK_H) $(QTn_H) \ ..\win\Qt\qt_key.h ..\win\Qt\qt_post.h ..\win\Qt\qt_pre.h \ ..\win\Qt\qt_str.h ..\win\Qt\qt_yndlg.h qt_yndlg.moc $(TARGET_CXX) $(TARGET_CXXFLAGS) -Fo$@ ..\win\Qt\qt_yndlg.cpp -#$(OGUI)Window.o: ..\win\X11\Window.c $(CONFIG_H) $(INCL)\lint.h \ -# $(INCL)\winX.h $(INCL)\wintype.h $(INCL)\xwindow.h \ -# $(INCL)\xwindowp.h +#$(OGUI)Window.o: ..\win\X11\Window.c $(CONFIG_H) $(INCL)lint.h \ +# $(INCL)winX.h $(INCL)wintype.h $(INCL)xwindow.h \ +# $(INCL)xwindowp.h # $(TARGET_CC) $(TARGET_CFLAGS) $(X11CFLAGS) -Fo$@ ..\win\X11\Window.c -$(OGUI)dialogs.o: ..\win\X11\dialogs.c $(CONFIG_H) $(INCL)\lint.h \ - $(INCL)\winX.h $(INCL)\wintype.h +$(OGUI)dialogs.o: ..\win\X11\dialogs.c $(CONFIG_H) $(INCL)lint.h \ + $(INCL)winX.h $(INCL)wintype.h # $(TARGET_CC) $(TARGET_CFLAGS) $(X11CFLAGS) -Fo$@ ..\win\X11\dialogs.c -$(OGUI)winX.o: ..\win\X11\winX.c $(HACK_H) $(INCL)\dlb.h \ - $(INCL)\winX.h $(INCL)\xwindow.h ..\win\X11\nh32icon \ +$(OGUI)winX.o: ..\win\X11\winX.c $(HACK_H) $(INCL)dlb.h \ + $(INCL)winX.h $(INCL)xwindow.h ..\win\X11\nh32icon \ ..\win\X11\nh56icon ..\win\X11\nh72icon # $(TARGET_CC) $(TARGET_CFLAGS) $(X11CFLAGS) -Fo$@ ..\win\X11\winX.c -$(OGUI)winmap.o: ..\win\X11\winmap.c $(HACK_H) $(INCL)\dlb.h \ - $(INCL)\tile2x11.h $(INCL)\winX.h $(INCL)\xwindow.h +$(OGUI)winmap.o: ..\win\X11\winmap.c $(HACK_H) $(INCL)dlb.h \ + $(INCL)tile2x11.h $(INCL)winX.h $(INCL)xwindow.h # $(TARGET_CC) $(TARGET_CFLAGS) $(X11CFLAGS) -Fo$@ ..\win\X11\winmap.c -$(OGUI)winmenu.o: ..\win\X11\winmenu.c $(HACK_H) $(INCL)\winX.h +$(OGUI)winmenu.o: ..\win\X11\winmenu.c $(HACK_H) $(INCL)winX.h # $(TARGET_CC) $(TARGET_CFLAGS) $(X11CFLAGS) -Fo$@ ..\win\X11\winmenu.c -$(OGUI)winmesg.o: ..\win\X11\winmesg.c $(HACK_H) $(INCL)\winX.h \ - $(INCL)\xwindow.h +$(OGUI)winmesg.o: ..\win\X11\winmesg.c $(HACK_H) $(INCL)winX.h \ + $(INCL)xwindow.h # $(TARGET_CC) $(TARGET_CFLAGS) $(X11CFLAGS) -Fo$@ ..\win\X11\winmesg.c -$(OGUI)winmisc.o: ..\win\X11\winmisc.c $(HACK_H) $(INCL)\func_tab.h \ - $(INCL)\winX.h +$(OGUI)winmisc.o: ..\win\X11\winmisc.c $(HACK_H) $(INCL)func_tab.h \ + $(INCL)winX.h # $(TARGET_CC) $(TARGET_CFLAGS) $(X11CFLAGS) -Fo$@ ..\win\X11\winmisc.c -$(OGUI)winstat.o: ..\win\X11\winstat.c $(HACK_H) $(INCL)\winX.h \ - $(INCL)\xwindow.h +$(OGUI)winstat.o: ..\win\X11\winstat.c $(HACK_H) $(INCL)winX.h \ + $(INCL)xwindow.h # $(TARGET_CC) $(TARGET_CFLAGS) $(X11CFLAGS) -Fo$@ ..\win\X11\winstat.c -$(OGUI)wintext.o: ..\win\X11\wintext.c $(HACK_H) $(INCL)\winX.h \ - $(INCL)\xwindow.h +$(OGUI)wintext.o: ..\win\X11\wintext.c $(HACK_H) $(INCL)winX.h \ + $(INCL)xwindow.h # $(TARGET_CC) $(TARGET_CFLAGS) $(X11CFLAGS) -Fo$@ ..\win\X11\wintext.c -$(OGUI)winval.o: ..\win\X11\winval.c $(HACK_H) $(INCL)\winX.h +$(OGUI)winval.o: ..\win\X11\winval.c $(HACK_H) $(INCL)winX.h # $(TARGET_CC) $(TARGET_CFLAGS) $(X11CFLAGS) -Fo$@ ..\win\X11\winval.c $(OGUI)wc_chainin.o: ..\win\chain\wc_chainin.c $(HACK_H) # $(TARGET_CC) $(TARGET_CFLAGS) -Fo$@ ..\win\chain\wc_chainin.c $(OGUI)wc_chainout.o: ..\win\chain\wc_chainout.c $(HACK_H) # $(TARGET_CC) $(TARGET_CFLAGS) -Fo$@ ..\win\chain\wc_chainout.c $(OGUI)wc_trace.o: ..\win\chain\wc_trace.c $(HACK_H) \ - $(INCL)\func_tab.h $(INCL)\wintty.h + $(INCL)func_tab.h $(INCL)wintty.h # $(TARGET_CC) $(TARGET_CFLAGS) -Fo$@ ..\win\chain\wc_trace.c $(OGUI)cursdial.o: ..\win\curses\cursdial.c $(HACK_H) \ - $(INCL)\func_tab.h $(INCL)\wincurs.h \ + $(INCL)func_tab.h $(INCL)wincurs.h \ ..\win\curses\cursdial.h # $(TARGET_CC) $(TARGET_CFLAGS) -Fo$@ ..\win\curses\cursdial.c $(OGUI)cursinit.o: ..\win\curses\cursinit.c $(HACK_H) \ - $(INCL)\wincurs.h ..\win\curses\cursinit.h + $(INCL)wincurs.h ..\win\curses\cursinit.h # $(TARGET_CC) $(TARGET_CFLAGS) -Fo$@ ..\win\curses\cursinit.c $(OGUI)cursinvt.o: ..\win\curses\cursinvt.c $(HACK_H) \ - $(INCL)\wincurs.h ..\win\curses\cursinvt.h + $(INCL)wincurs.h ..\win\curses\cursinvt.h # $(TARGET_CC) $(TARGET_CFLAGS) -Fo$@ ..\win\curses\cursinvt.c -$(OGUI)cursmain.o: ..\win\curses\cursmain.c $(HACK_H) $(INCL)\wincurs.h +$(OGUI)cursmain.o: ..\win\curses\cursmain.c $(HACK_H) $(INCL)wincurs.h # $(TARGET_CC) $(TARGET_CFLAGS) -Fo$@ ..\win\curses\cursmain.c $(OGUI)cursmesg.o: ..\win\curses\cursmesg.c $(HACK_H) \ - $(INCL)\wincurs.h ..\win\curses\cursmesg.h + $(INCL)wincurs.h ..\win\curses\cursmesg.h # $(TARGET_CC) $(TARGET_CFLAGS) -Fo$@ ..\win\curses\cursmesg.c -$(OGUI)cursmisc.o: ..\win\curses\cursmisc.c $(HACK_H) $(INCL)\dlb.h \ - $(INCL)\func_tab.h $(INCL)\wincurs.h \ +$(OGUI)cursmisc.o: ..\win\curses\cursmisc.c $(HACK_H) $(INCL)dlb.h \ + $(INCL)func_tab.h $(INCL)wincurs.h \ ..\win\curses\cursmisc.h # $(TARGET_CC) $(TARGET_CFLAGS) -Fo$@ ..\win\curses\cursmisc.c $(OGUI)cursstat.o: ..\win\curses\cursstat.c $(HACK_H) \ - $(INCL)\wincurs.h ..\win\curses\cursstat.h + $(INCL)wincurs.h ..\win\curses\cursstat.h # $(TARGET_CC) $(TARGET_CFLAGS) -Fo$@ ..\win\curses\cursstat.c $(OGUI)curswins.o: ..\win\curses\curswins.c $(HACK_H) \ - $(INCL)\wincurs.h ..\win\curses\curswins.h + $(INCL)wincurs.h ..\win\curses\curswins.h # $(TARGET_CC) $(TARGET_CFLAGS) -Fo$@ ..\win\curses\curswins.c $(OGUI)winshim.o: ..\win\shim\winshim.c $(HACK_H) # $(TARGET_CC) $(TARGET_CFLAGS) -Fo$@ ..\win\shim\winshim.c -$(OGUI)getline.o: ..\win\tty\getline.c $(HACK_H) $(INCL)\func_tab.h \ - $(INCL)\wintty.h +$(OGUI)getline.o: ..\win\tty\getline.c $(HACK_H) $(INCL)func_tab.h \ + $(INCL)wintty.h # $(TARGET_CC) $(TARGET_CFLAGS) -Fo$@ ..\win\tty\getline.c -$(OGUI)termcap.o: ..\win\tty\termcap.c $(HACK_H) $(INCL)\tcap.h \ - $(INCL)\wintty.h +$(OGUI)termcap.o: ..\win\tty\termcap.c $(HACK_H) $(INCL)tcap.h \ + $(INCL)wintty.h # $(TARGET_CC) $(TARGET_CFLAGS) -Fo$@ ..\win\tty\termcap.c -$(OGUI)topl.o: ..\win\tty\topl.c $(HACK_H) $(INCL)\tcap.h \ - $(INCL)\wintty.h +$(OGUI)topl.o: ..\win\tty\topl.c $(HACK_H) $(INCL)tcap.h \ + $(INCL)wintty.h # $(TARGET_CC) $(TARGET_CFLAGS) -Fo$@ ..\win\tty\topl.c -$(OGUI)wintty.o: ..\win\tty\wintty.c $(HACK_H) $(INCL)\dlb.h \ - $(INCL)\tcap.h $(INCL)\wintty.h +$(OGUI)wintty.o: ..\win\tty\wintty.c $(HACK_H) $(INCL)dlb.h \ + $(INCL)tcap.h $(INCL)wintty.h # $(TARGET_CC) $(TARGET_CFLAGS) -Fo$@ ..\win\tty\wintty.c $(OGUI)allmain.o: allmain.c $(HACK_H) -$(OGUI)alloc.o: alloc.c $(CONFIG_H) $(INCL)\nhlua.h +$(OGUI)alloc.o: alloc.c $(CONFIG_H) $(INCL)nhlua.h $(OGUI)apply.o: apply.c $(HACK_H) -$(OGUI)artifact.o: artifact.c $(HACK_H) $(INCL)\artifact.h +$(OGUI)artifact.o: artifact.c $(HACK_H) $(INCL)artifact.h $(OGUI)attrib.o: attrib.c $(HACK_H) $(OGUI)ball.o: ball.c $(HACK_H) $(OGUI)bones.o: bones.c $(HACK_H) $(OGUI)botl.o: botl.c $(HACK_H) $(OGUI)calendar.o: calendar.c $(HACK_H) -$(OGUI)cmd.o: cmd.c $(HACK_H) $(INCL)\func_tab.h +$(OGUI)cmd.o: cmd.c $(HACK_H) $(INCL)func_tab.h $(OGUI)coloratt.o: coloratt.c $(HACK_H) $(OGUI)dbridge.o: dbridge.c $(HACK_H) $(OGUI)decl.o: decl.c $(HACK_H) -$(OGUI)detect.o: detect.c $(HACK_H) $(INCL)\artifact.h +$(OGUI)detect.o: detect.c $(HACK_H) $(INCL)artifact.h $(OGUI)dig.o: dig.c $(HACK_H) $(OGUI)display.o: display.c $(HACK_H) -$(OGUI)dlb.o: dlb.c $(CONFIG_H) $(INCL)\dlb.h +$(OGUI)dlb.o: dlb.c $(CONFIG_H) $(INCL)dlb.h $(OGUI)do.o: do.c $(HACK_H) $(OGUI)do_name.o: do_name.c $(HACK_H) $(OGUI)do_wear.o: do_wear.c $(HACK_H) $(OGUI)dog.o: dog.c $(HACK_H) -$(OGUI)dogmove.o: dogmove.c $(HACK_H) $(INCL)\mfndpos.h +$(OGUI)dogmove.o: dogmove.c $(HACK_H) $(INCL)mfndpos.h $(OGUI)dokick.o: dokick.c $(HACK_H) $(OGUI)dothrow.o: dothrow.c $(HACK_H) -$(OGUI)drawing.o: drawing.c $(CONFIG_H) $(INCL)\defsym.h \ - $(INCL)\objclass.h $(INCL)\objects.h $(INCL)\rm.h \ - $(INCL)\sym.h $(INCL)\wintype.h -$(OGUI)dungeon.o: dungeon.c $(HACK_H) $(INCL)\dgn_file.h \ - $(INCL)\dlb.h +$(OGUI)drawing.o: drawing.c $(CONFIG_H) $(INCL)defsym.h \ + $(INCL)objclass.h $(INCL)objects.h $(INCL)rm.h \ + $(INCL)sym.h $(INCL)wintype.h +$(OGUI)dungeon.o: dungeon.c $(HACK_H) $(INCL)dgn_file.h \ + $(INCL)dlb.h $(OGUI)eat.o: eat.c $(HACK_H) -$(OGUI)end.o: end.c $(HACK_H) $(INCL)\dlb.h +$(OGUI)end.o: end.c $(HACK_H) $(INCL)dlb.h $(OGUI)engrave.o: engrave.c $(HACK_H) $(OGUI)exper.o: exper.c $(HACK_H) $(OGUI)explode.o: explode.c $(HACK_H) $(OGUI)extralev.o: extralev.c $(HACK_H) -$(OGUI)files.o: files.c $(HACK_H) $(INCL)\dlb.h \ - $(INCL)\wintty.h +$(OGUI)files.o: files.c $(HACK_H) $(INCL)dlb.h \ + $(INCL)wintty.h $(OGUI)fountain.o: fountain.c $(HACK_H) $(OGUI)getpos.o: getpos.c $(HACK_H) $(OGUI)glyphs.o: glyphs.c $(HACK_H) @@ -3191,106 +3374,106 @@ $(OGUI)hack.o: hack.c $(HACK_H) $(OGUI)hacklib.o: hacklib.c $(HACK_H) $(OGUI)insight.o: insight.c $(HACK_H) $(OGUI)invent.o: invent.c $(HACK_H) -$(OGUI)isaac64.o: isaac64.c $(CONFIG_H) $(INCL)\isaac64.h +$(OGUI)isaac64.o: isaac64.c $(CONFIG_H) $(INCL)isaac64.h $(OGUI)light.o: light.c $(HACK_H) $(OGUI)lock.o: lock.c $(HACK_H) -$(OGUI)mail.o: mail.c $(HACK_H) $(INCL)\mail.h +$(OGUI)mail.o: mail.c $(HACK_H) $(INCL)mail.h $(OGUI)makemon.o: makemon.c $(HACK_H) $(OGUI)mcastu.o: mcastu.c $(HACK_H) -$(OGUI)mdlib.o: mdlib.c $(CONFIG_H) $(INCL)\align.h \ - $(INCL)\artilist.h $(INCL)\attrib.h \ - $(INCL)\context.h $(INCL)\defsym.h $(INCL)\dlb.h \ - $(INCL)\dungeon.h $(INCL)\flag.h $(INCL)\hacklib.h \ - $(INCL)\mextra.h $(INCL)\monattk.h $(INCL)\monflag.h \ - $(INCL)\monst.h $(INCL)\monsters.h $(INCL)\obj.h \ - $(INCL)\objclass.h $(INCL)\objects.h \ - $(INCL)\permonst.h $(INCL)\prop.h $(INCL)\seffects.h \ - $(INCL)\skills.h $(INCL)\sndprocs.h $(INCL)\sym.h \ - $(INCL)\wintype.h $(INCL)\you.h -$(OGUI)mhitm.o: mhitm.c $(HACK_H) $(INCL)\artifact.h -$(OGUI)mhitu.o: mhitu.c $(HACK_H) $(INCL)\artifact.h +$(OGUI)mdlib.o: mdlib.c $(CONFIG_H) $(INCL)align.h \ + $(INCL)artilist.h $(INCL)attrib.h \ + $(INCL)context.h $(INCL)defsym.h $(INCL)dlb.h \ + $(INCL)dungeon.h $(INCL)flag.h $(INCL)hacklib.h \ + $(INCL)mextra.h $(INCL)monattk.h $(INCL)monflag.h \ + $(INCL)monst.h $(INCL)monsters.h $(INCL)obj.h \ + $(INCL)objclass.h $(INCL)objects.h \ + $(INCL)permonst.h $(INCL)prop.h $(INCL)seffects.h \ + $(INCL)skills.h $(INCL)sndprocs.h $(INCL)sym.h \ + $(INCL)wintype.h $(INCL)you.h +$(OGUI)mhitm.o: mhitm.c $(HACK_H) $(INCL)artifact.h +$(OGUI)mhitu.o: mhitu.c $(HACK_H) $(INCL)artifact.h $(OGUI)minion.o: minion.c $(HACK_H) $(OGUI)mklev.o: mklev.c $(HACK_H) -$(OGUI)mkmap.o: mkmap.c $(HACK_H) $(INCL)\sp_lev.h -$(OGUI)mkmaze.o: mkmaze.c $(HACK_H) $(INCL)\sp_lev.h +$(OGUI)mkmap.o: mkmap.c $(HACK_H) $(INCL)sp_lev.h +$(OGUI)mkmaze.o: mkmaze.c $(HACK_H) $(INCL)sp_lev.h $(OGUI)mkobj.o: mkobj.c $(HACK_H) $(OGUI)mkroom.o: mkroom.c $(HACK_H) -$(OGUI)mon.o: mon.c $(HACK_H) $(INCL)\mfndpos.h +$(OGUI)mon.o: mon.c $(HACK_H) $(INCL)mfndpos.h $(OGUI)mondata.o: mondata.c $(HACK_H) -$(OGUI)monmove.o: monmove.c $(HACK_H) $(INCL)\artifact.h \ - $(INCL)\mfndpos.h -$(OGUI)monst.o: monst.c $(CONFIG_H) $(INCL)\align.h \ - $(INCL)\defsym.h $(INCL)\monattk.h $(INCL)\monflag.h \ - $(INCL)\monsters.h $(INCL)\permonst.h $(INCL)\sym.h \ - $(INCL)\wintype.h +$(OGUI)monmove.o: monmove.c $(HACK_H) $(INCL)artifact.h \ + $(INCL)mfndpos.h +$(OGUI)monst.o: monst.c $(CONFIG_H) $(INCL)align.h \ + $(INCL)defsym.h $(INCL)monattk.h $(INCL)monflag.h \ + $(INCL)monsters.h $(INCL)permonst.h $(INCL)sym.h \ + $(INCL)wintype.h $(OGUI)mplayer.o: mplayer.c $(HACK_H) $(OGUI)mthrowu.o: mthrowu.c $(HACK_H) $(OGUI)muse.o: muse.c $(HACK_H) $(OGUI)music.o: music.c $(HACK_H) -$(OGUI)nhlobj.o: nhlobj.c $(HACK_H) $(INCL)\sp_lev.h -$(OGUI)nhlsel.o: nhlsel.c $(HACK_H) $(INCL)\sp_lev.h -$(OGUI)nhlua.o: nhlua.c $(HACK_H) $(INCL)\dlb.h -$(OGUI)nhmd4.o: nhmd4.c $(HACK_H) $(INCL)\nhmd4.h +$(OGUI)nhlobj.o: nhlobj.c $(HACK_H) $(INCL)sp_lev.h +$(OGUI)nhlsel.o: nhlsel.c $(HACK_H) $(INCL)sp_lev.h +$(OGUI)nhlua.o: nhlua.c $(HACK_H) $(INCL)dlb.h +$(OGUI)nhmd4.o: nhmd4.c $(HACK_H) $(INCL)nhmd4.h $(OGUI)o_init.o: o_init.c $(HACK_H) -$(OGUI)objects.o: objects.c $(CONFIG_H) $(INCL)\defsym.h \ - $(INCL)\obj.h $(INCL)\objclass.h $(INCL)\objects.h \ - $(INCL)\prop.h $(INCL)\skills.h +$(OGUI)objects.o: objects.c $(CONFIG_H) $(INCL)defsym.h \ + $(INCL)obj.h $(INCL)objclass.h $(INCL)objects.h \ + $(INCL)prop.h $(INCL)skills.h $(OGUI)objnam.o: objnam.c $(HACK_H) -$(OGUI)options.o: options.c $(CONFIG_H) $(HACK_H) $(INCL)\defsym.h \ - $(INCL)\flag.h $(INCL)\objclass.h $(INCL)\objects.h \ - $(INCL)\optlist.h $(INCL)\tcap.h -$(OGUI)pager.o: pager.c $(HACK_H) $(INCL)\dlb.h +$(OGUI)options.o: options.c $(CONFIG_H) $(HACK_H) $(INCL)defsym.h \ + $(INCL)flag.h $(INCL)objclass.h $(INCL)objects.h \ + $(INCL)optlist.h $(INCL)tcap.h +$(OGUI)pager.o: pager.c $(HACK_H) $(INCL)dlb.h $(OGUI)pickup.o: pickup.c $(HACK_H) $(OGUI)pline.o: pline.c $(HACK_H) $(OGUI)polyself.o: polyself.c $(HACK_H) $(OGUI)potion.o: potion.c $(HACK_H) $(OGUI)pray.o: pray.c $(HACK_H) -$(OGUI)priest.o: priest.c $(HACK_H) $(INCL)\mfndpos.h +$(OGUI)priest.o: priest.c $(HACK_H) $(INCL)mfndpos.h $(OGUI)quest.o: quest.c $(HACK_H) -$(OGUI)questpgr.o: questpgr.c $(HACK_H) $(INCL)\dlb.h \ - $(INCL)\wintty.h +$(OGUI)questpgr.o: questpgr.c $(HACK_H) $(INCL)dlb.h \ + $(INCL)wintty.h $(OGUI)read.o: read.c $(HACK_H) $(OGUI)rect.o: rect.c $(HACK_H) $(OGUI)region.o: region.c $(HACK_H) -$(OGUI)report.o: report.c $(HACK_H) $(INCL)\dlb.h $(INCL)\nhmd4.h -$(OGUI)restore.o: restore.c $(HACK_H) $(INCL)\tcap.h +$(OGUI)report.o: report.c $(HACK_H) $(INCL)dlb.h $(INCL)nhmd4.h +$(OGUI)restore.o: restore.c $(HACK_H) $(INCL)tcap.h $(OGUI)rip.o: rip.c $(HACK_H) -$(OGUI)rnd.o: rnd.c $(HACK_H) $(INCL)\isaac64.h +$(OGUI)rnd.o: rnd.c $(HACK_H) $(INCL)isaac64.h $(OGUI)role.o: role.c $(HACK_H) -$(OGUI)rumors.o: rumors.c $(HACK_H) $(INCL)\dlb.h +$(OGUI)rumors.o: rumors.c $(HACK_H) $(INCL)dlb.h $(OGUI)save.o: save.c $(HACK_H) -$(OGUI)selvar.o: selvar.c $(HACK_H) $(INCL)\sp_lev.h +$(OGUI)selvar.o: selvar.c $(HACK_H) $(INCL)sp_lev.h $(OGUI)sfstruct.o: sfstruct.c $(HACK_H) $(OGUI)shk.o: shk.c $(HACK_H) $(OGUI)shknam.o: shknam.c $(HACK_H) -$(OGUI)sit.o: sit.c $(HACK_H) $(INCL)\artifact.h +$(OGUI)sit.o: sit.c $(HACK_H) $(INCL)artifact.h $(OGUI)sounds.o: sounds.c $(HACK_H) -$(OGUI)sp_lev.o: sp_lev.c $(HACK_H) $(INCL)\sp_lev.h +$(OGUI)sp_lev.o: sp_lev.c $(HACK_H) $(INCL)sp_lev.h $(OGUI)spell.o: spell.c $(HACK_H) $(OGUI)stairs.o: stairs.c $(HACK_H) $(OGUI)steal.o: steal.c $(HACK_H) $(OGUI)steed.o: steed.c $(HACK_H) $(OGUI)strutil.o: strutil.c $(HACK_H) -$(OGUI)symbols.o: symbols.c $(HACK_H) $(INCL)\tcap.h +$(OGUI)symbols.o: symbols.c $(HACK_H) $(INCL)tcap.h $(OGUI)sys.o: sys.c $(HACK_H) $(OGUI)teleport.o: teleport.c $(HACK_H) #$(OGUI)tile.o: tile.c $(HACK_H) $(OGUI)timeout.o: timeout.c $(HACK_H) -$(OGUI)topten.o: topten.c $(HACK_H) $(INCL)\dlb.h +$(OGUI)topten.o: topten.c $(HACK_H) $(INCL)dlb.h $(OGUI)track.o: track.c $(HACK_H) $(OGUI)trap.o: trap.c $(HACK_H) $(OGUI)u_init.o: u_init.c $(HACK_H) $(OGUI)uhitm.o: uhitm.c $(HACK_H) $(OGUI)utf8map.o: utf8map.c $(HACK_H) $(OGUI)vault.o: vault.c $(HACK_H) -$(OGUI)version.o: version.c $(HACK_H) $(INCL)\dlb.h +$(OGUI)version.o: version.c $(HACK_H) $(INCL)dlb.h $(OGUI)vision.o: vision.c $(HACK_H) $(OGUI)weapon.o: weapon.c $(HACK_H) $(OGUI)were.o: were.c $(HACK_H) $(OGUI)wield.o: wield.c $(HACK_H) -$(OGUI)windows.o: windows.c $(HACK_H) $(INCL)\dlb.h $(INCL)\wintty.h +$(OGUI)windows.o: windows.c $(HACK_H) $(INCL)dlb.h $(INCL)wintty.h $(OGUI)wizard.o: wizard.c $(HACK_H) -$(OGUI)wizcmds.o: wizcmds.c $(HACK_H) $(INCL)\func_tab.h +$(OGUI)wizcmds.o: wizcmds.c $(HACK_H) $(INCL)func_tab.h $(OGUI)worm.o: worm.c $(HACK_H) $(OGUI)worn.o: worn.c $(HACK_H) $(OGUI)write.o: write.c $(HACK_H) From 8b11bda6cb5c36ca8831b5890e99812eff50167a Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sun, 22 Dec 2024 18:13:55 +0200 Subject: [PATCH 230/791] Open cavern -style Gehennom filler level --- dat/hellfill.lua | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/dat/hellfill.lua b/dat/hellfill.lua index d7675e19b..00175ffd3 100644 --- a/dat/hellfill.lua +++ b/dat/hellfill.lua @@ -410,6 +410,20 @@ hells = { end des.terrain(outside_walls, " "); -- return the outside back to solid wall end, + + -- 7: open cavern, "mines" with more space + function () + des.level_init({ style = "solidfill", fg = " ", lit = 0 }); + des.level_flags("mazelevel", "noflip"); + des.level_init({ style="mines", fg=".", smoothed=true ,joined=true, lit=0 }); + local sel = selection.match("."):grow(); + des.terrain({ selection = sel, typ = "." }); + + local border = selection.rect(0,0, 78, 20); + des.terrain({ selection = border, typ = " " }); + des.wallify(); + end, + }; local hellno = math.random(1, #hells); From 57f86662fd9d2157e288d544e078d78648dc8818 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 22 Dec 2024 19:58:52 -0500 Subject: [PATCH 231/791] try harder to have --showpaths succeed This helps avoid a potential chicken-and-egg scenario with the system configuration file (sysconf). If sysconf wasn't accessible at the expected location, it caused an immediate exit, without relaying any helpful information. That happened even when using: 'nethack --showpaths' That's particularly unhelpful, because the --showpaths output might have been useful towards understanding where NetHack was looking for such things. That left you without an easy recourse to identify where the game is looking for the sysconf file. That might be especially troublesome if you didn't build the game yourself. --- include/decl.h | 4 ++++ include/extern.h | 4 +++- src/decl.c | 2 ++ src/files.c | 35 ++++++++++++++++++++++++++++++++--- src/options.c | 5 +++++ sys/libnh/libnhmain.c | 10 ++-------- sys/unix/unixmain.c | 18 ++++++++---------- sys/vms/vmsmain.c | 12 +++--------- sys/windows/windmain.c | 26 +++++++++++--------------- 9 files changed, 70 insertions(+), 46 deletions(-) diff --git a/include/decl.h b/include/decl.h index 415d710b1..9859c3e24 100644 --- a/include/decl.h +++ b/include/decl.h @@ -340,6 +340,10 @@ struct instance_globals_d { boolean decor_fumble_override; boolean decor_levitate_override; + /* new */ + boolean deferred_showpaths; + const char *deferred_showpaths_dir; + boolean havestate; unsigned long magic; /* validate that structure layout is preserved */ }; diff --git a/include/extern.h b/include/extern.h index 35bb33138..760ad30e2 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1072,11 +1072,12 @@ extern int nhclose(int); #ifdef DEBUG extern boolean debugcore(const char *, boolean); #endif -extern void reveal_paths(void); +extern void reveal_paths(int); extern boolean read_tribute(const char *, const char *, int, char *, int, unsigned); extern boolean Death_quote(char *, int) NONNULLARG1; extern void livelog_add(long ll_type, const char *) NONNULLARG2; +ATTRNORETURN extern void do_deferred_showpaths(int) NORETURN; /* ### fountain.c ### */ @@ -3379,6 +3380,7 @@ extern void append_slash(char *) NONNULLARG1; extern boolean check_user_string(const char *) NONNULLARG1; extern char *get_login_name(void); extern unsigned long sys_random_seed(void); +ATTRNORETURN extern void after_opt_showpaths(const char *) NORETURN; #endif /* UNIX */ /* ### unixtty.c ### */ diff --git a/src/decl.c b/src/decl.c index 08b54e4f7..e21cfc8db 100644 --- a/src/decl.c +++ b/src/decl.c @@ -339,6 +339,8 @@ static const struct instance_globals_d g_init_d = { /* pickup.c */ FALSE, /* decor_fumble_override */ FALSE, /* decor_levitate_override */ + FALSE, /* deferred_showpaths */ + NULL, /* deferred_showpaths_dir */ TRUE, /* havestate*/ IVMAGIC /* d_magic to validate that structure layout has been preserved */ }; diff --git a/src/files.c b/src/files.c index d7ce06f60..8a23a0175 100644 --- a/src/files.c +++ b/src/files.c @@ -4467,6 +4467,8 @@ assure_syscf_file(void) close(fd); return; } + if (gd.deferred_showpaths) + do_deferred_showpaths(1); /* does not return */ raw_printf("Unable to open SYSCF_FILE.\n"); exit(EXIT_FAILURE); } @@ -4474,6 +4476,26 @@ assure_syscf_file(void) #endif /* SYSCF_FILE */ #endif /* SYSCF */ +ATTRNORETURN void +do_deferred_showpaths(int code) +{ + gd.deferred_showpaths = FALSE; + reveal_paths(code); + +#ifdef UNIX + after_opt_showpaths(gd.deferred_showpaths_dir); +#else +#ifdef CHDIR + chdirx(gd.deferred_showpaths_dir, 0); +#endif +#if defined(WIN32) || defined(MICRO) || defined(OS2) + nethack_exit(EXIT_SUCCESS); +#else + exit(EXIT_SUCCESS); +#endif +#endif +} + #ifdef DEBUG /* used by debugpline() to decide whether to issue a message * from a particular source file; caller passes __FILE__ and we check @@ -4534,9 +4556,11 @@ debugcore(const char *filename, boolean wildcards) #endif void -reveal_paths(void) +reveal_paths(int code) { - const char *fqn, *nodumpreason; + const char *fqn, *nodumpreason, + *sysconffile = "system configuration file"; + char buf[BUFSZ]; #if defined(SYSCF) || !defined(UNIX) || defined(DLB) const char *filep; @@ -4570,7 +4594,8 @@ reveal_paths(void) #else buf[0] = '\0'; #endif - raw_printf("%s system configuration file%s:", s_suffix(gamename), buf); + raw_printf("%s %s%s:", + s_suffix(gamename), sysconffile, buf); #ifdef SYSCF_FILE filep = SYSCF_FILE; #else @@ -4582,6 +4607,10 @@ reveal_paths(void) filep = configfile; } raw_printf(" \"%s\"", filep); + if (code == 1) { + raw_printf("NOTE: The %s above is missing or inaccessible!", + sysconffile); + } #else /* !SYSCF */ raw_printf("No system configuration file."); #endif /* ?SYSCF */ diff --git a/src/options.c b/src/options.c index 0a9a7dc85..30d7709f4 100644 --- a/src/options.c +++ b/src/options.c @@ -6942,6 +6942,11 @@ initoptions(void) */ #endif #endif /* SYSCF */ + + /* Carry out options that got deferred from early_options */ + if (gd.deferred_showpaths) + do_deferred_showpaths(0); /* does not return */ + initoptions_finish(); } diff --git a/sys/libnh/libnhmain.c b/sys/libnh/libnhmain.c index 20835dda6..289ee2c5f 100644 --- a/sys/libnh/libnhmain.c +++ b/sys/libnh/libnhmain.c @@ -108,14 +108,8 @@ nhmain(int argc, char *argv[]) #endif if (argcheck(argc, argv, ARG_SHOWPATHS) == 2) { -#ifdef CHDIR - chdirx((char *) 0, 0); -#endif - iflags.initoptions_noterminate = TRUE; - initoptions(); - iflags.initoptions_noterminate = FALSE; - reveal_paths(); - exit(EXIT_SUCCESS); + gd.deferred_showpaths = TRUE; + return; } if (argcheck(argc, argv, ARG_DEBUG) == 1) { argc--; diff --git a/sys/unix/unixmain.c b/sys/unix/unixmain.c index e6b09492c..617a1ef06 100644 --- a/sys/unix/unixmain.c +++ b/sys/unix/unixmain.c @@ -36,7 +36,6 @@ static void consume_two_args(int, int *, char ***); static void early_options(int *, char ***, char **); ATTRNORETURN static void opt_terminate(void) NORETURN; ATTRNORETURN static void opt_usage(const char *) NORETURN; -static void opt_showpaths(const char *); ATTRNORETURN static void scores_only(int, char **, const char *) NORETURN; #ifdef SND_LIB_INTEGRATED uint32_t soundlibchoice = soundlib_nosound; @@ -702,9 +701,10 @@ early_options(int *argc_p, char ***argv_p, char **hackdir_p) break; case 's': if (argcheck(argc, argv, ARG_SHOWPATHS) == 2) { - opt_showpaths(*hackdir_p); - opt_terminate(); - /*NOTREACHED*/ + gd.deferred_showpaths = TRUE; + gd.deferred_showpaths_dir = *hackdir_p; + config_error_done(); + return; } /* check for "-s" request to show scores */ if (lopt(arg, ((ArgValDisallowed | ArgErrComplain) @@ -785,18 +785,16 @@ opt_usage(const char *hackdir) /* show the sysconf file name, playground directory, run-time configuration file name, dumplog file name if applicable, and some other things */ -static void -opt_showpaths(const char *dir) +ATTRNORETURN void +after_opt_showpaths(const char *dir) { #ifdef CHDIR chdirx(dir, FALSE); #else nhUse(dir); #endif - iflags.initoptions_noterminate = TRUE; - initoptions(); - iflags.initoptions_noterminate = FALSE; - reveal_paths(); + opt_terminate(); + /*NOTREACHED*/ } /* handle "-s [character-names]" to show all the entries diff --git a/sys/vms/vmsmain.c b/sys/vms/vmsmain.c index dcb681caa..25c40b842 100644 --- a/sys/vms/vmsmain.c +++ b/sys/vms/vmsmain.c @@ -80,15 +80,9 @@ main(int argc, char *argv[]) exit(EXIT_SUCCESS); if (argcheck(argc, argv, ARG_SHOWPATHS) == 2) { -#ifdef CHDIR - chdirx((char *) 0, 0); -#endif - iflags.initoptions_noterminate = TRUE; - initoptions(); - iflags.initoptions_noterminate = FALSE; - reveal_paths(); - exit(EXIT_SUCCESS); - } + gd.deferred_showpaths = TRUE; + return; + } if (argcheck(argc, argv, ARG_DEBUG) == 1) { argc--; argv++; diff --git a/sys/windows/windmain.c b/sys/windows/windmain.c index df7144a20..15cb8442f 100644 --- a/sys/windows/windmain.c +++ b/sys/windows/windmain.c @@ -18,9 +18,9 @@ #error You must #define SAFEPROCS to build windmain.c #endif -static void process_options(int argc, char **argv); static void nhusage(void); static char *get_executable_path(void); +static void early_options(int argc, char **argv); char *translate_path_variables(const char *, char *); char *exename(void); boolean fakeconsole(void); @@ -242,6 +242,7 @@ _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);*/ iflags.windowtype_deferred = TRUE; copy_sysconf_content(); copy_symbols_content(); + early_options(argc, argv); initoptions(); /* Now that sysconf has had a chance to set the TROUBLEPREFIX, don't @@ -249,7 +250,6 @@ _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);*/ fqn_prefix_locked[TROUBLEPREFIX] = TRUE; copy_config_content(); - process_options(argc, argv); /* did something earlier flag a need to exit without starting a game? */ if (windows_startup_state > 0) { @@ -462,23 +462,18 @@ attempt_restore: RESTORE_WARNING_UNREACHABLE_CODE static void -process_options(int argc, char * argv[]) +early_options(int argc, char *argv[]) { int i; - /* - * Process options. - */ if (argc > 1) { if (argcheck(argc, argv, ARG_VERSION) == 2) nethack_exit(EXIT_SUCCESS); if (argcheck(argc, argv, ARG_SHOWPATHS) == 2) { - iflags.initoptions_noterminate = TRUE; - initoptions(); - iflags.initoptions_noterminate = FALSE; - reveal_paths(); - nethack_exit(EXIT_SUCCESS); + gd.deferred_showpaths = TRUE; + /* gd.deferred_showpaths is not used by windows */ + return; } #ifndef NODUMPENUMS if (argcheck(argc, argv, ARG_DUMPENUMS) == 2) { @@ -509,7 +504,7 @@ process_options(int argc, char * argv[]) */ argc--; argv++; - const char * dir = argv[0] + 2; + const char *dir = argv[0] + 2; if (*dir == '=' || *dir == ':') dir++; if (!*dir && argc > 1) { @@ -578,7 +573,8 @@ process_options(int argc, char * argv[]) #endif case 'u': if (argv[0][2]) - (void) strncpy(svp.plname, argv[0] + 2, sizeof(svp.plname) - 1); + (void) strncpy(svp.plname, argv[0] + 2, + sizeof(svp.plname) - 1); else if (argc > 1) { argc--; argv++; @@ -634,8 +630,8 @@ process_options(int argc, char * argv[]) break; } else raw_printf("\nUnknown switch: %s", argv[0]); - FALLTHROUGH; - /* FALLTHRU */ + FALLTHROUGH; + /* FALLTHRU */ case '?': nhusage(); nethack_exit(EXIT_SUCCESS); From a62c62fd968dfd6499a9cbef896ac0bd344e02ff Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 22 Dec 2024 20:45:55 -0500 Subject: [PATCH 232/791] follow-up for --showpaths Ensure that memory allocations are freed up. Windows: Fix a Windows compiler warning. Fix an undefined link symbol. --- include/decl.h | 2 +- src/files.c | 7 +++++++ src/save.c | 3 +++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/include/decl.h b/include/decl.h index 9859c3e24..fb444cbf6 100644 --- a/include/decl.h +++ b/include/decl.h @@ -342,7 +342,7 @@ struct instance_globals_d { /* new */ boolean deferred_showpaths; - const char *deferred_showpaths_dir; + char *deferred_showpaths_dir; boolean havestate; unsigned long magic; /* validate that structure layout is preserved */ diff --git a/src/files.c b/src/files.c index 8a23a0175..0d36deaa3 100644 --- a/src/files.c +++ b/src/files.c @@ -4482,12 +4482,19 @@ do_deferred_showpaths(int code) gd.deferred_showpaths = FALSE; reveal_paths(code); + /* cleanup before heading to an exit */ + freedynamicdata(); + dlb_cleanup(); + l_nhcore_done(); + #ifdef UNIX after_opt_showpaths(gd.deferred_showpaths_dir); #else +#ifndef WIN32 #ifdef CHDIR chdirx(gd.deferred_showpaths_dir, 0); #endif +#endif #if defined(WIN32) || defined(MICRO) || defined(OS2) nethack_exit(EXIT_SUCCESS); #else diff --git a/src/save.c b/src/save.c index 1497c4d5b..933a0b0f8 100644 --- a/src/save.c +++ b/src/save.c @@ -1278,6 +1278,9 @@ freedynamicdata(void) if (options_set_window_colors_flag) options_free_window_colors(); + if (glyphid_cache_status()) + free_glyphid_cache(); + /* last, because it frees data that might be used by panic() to provide feedback to the user; conceivably other freeing might trigger panic */ sysopt_release(); /* SYSCF strings */ From 1746f57f379a1eae3960e98812c5da0c43e59ae8 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 22 Dec 2024 23:20:04 -0500 Subject: [PATCH 233/791] avoid double free If freedynamicdata() gets called twice, for whatever reason, a "double free" can occur. warning: 44 ./nptl/pthread_kill.c: No such file or directory (gdb) bt #0 __pthread_kill_implementation (no_tid=0, signo=6, threadid=) at ./nptl/pthread_kill.c:44 #1 __pthread_kill_internal (signo=6, threadid=) at ./nptl/pthread_kill.c:78 #2 __GI___pthread_kill (threadid=, signo=signo@entry=6) at ./nptl/pthread_kill.c:89 #3 0x00007ffff7c8b26e in __GI_raise (sig=sig@entry=6) at ../sysdeps/posix/raise.c:26 #4 0x00007ffff7c6e8ff in __GI_abort () at ./stdlib/abort.c:79 #5 0x00007ffff7c6f7b6 in __libc_message_impl (fmt=fmt@entry=0x7ffff7e148d7 "%s\n") at ../sysdeps/posix/libc_fatal.c:132 #6 0x00007ffff7ceefe5 in malloc_printerr (str=str@entry=0x7ffff7e17bf0 "free(): double free detected in tcache 2") at ./malloc/malloc.c:5772 #7 0x00007ffff7cf154f in _int_free (av=0x7ffff7e49ac0 , p=, have_lock=0) at ./malloc/malloc.c:4541 #8 0x00007ffff7cf3d9e in __GI___libc_free (mem=0x555555ad82a0) at ./malloc/malloc.c:3398 #9 0x00005555557c12e9 in free_rect () at rect.c:48 #10 0x00005555557d77a2 in freedynamicdata () at save.c:1240 #11 0x0000555555682754 in nh_terminate (status=0) at end.c:1671 #12 0x000055555589af15 in opt_terminate () at ../sys/unix/unixmain.c:768 #13 0x000055555589af7a in after_opt_showpaths (dir=0x0) at ../sys/unix/unixmain.c:796 #14 0x0000555555693dd9 in do_deferred_showpaths (code=0) at files.c:4491 #15 0x0000555555778405 in initoptions () at options.c:6948 #16 0x0000555555899cd9 in main (argc=2, argv=0x7fffffffdad8) at ../sys/unix/unixmain.c:151 --- src/rect.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/rect.c b/src/rect.c index 801af1343..1fb0f2b82 100644 --- a/src/rect.c +++ b/src/rect.c @@ -46,6 +46,7 @@ free_rect(void) { if (rect) free(rect); + rect = 0; n_rects = rect_cnt = 0; } From 1a6847ca1576c64543ead492c8befe89d2f86cbc Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 23 Dec 2024 00:16:52 -0500 Subject: [PATCH 234/791] follow-up tweaking for missing sysconf --showpaths --- src/files.c | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/src/files.c b/src/files.c index 0d36deaa3..8acf9f527 100644 --- a/src/files.c +++ b/src/files.c @@ -4565,6 +4565,7 @@ debugcore(const char *filename, boolean wildcards) void reveal_paths(int code) { + boolean skip_sysopt = FALSE; const char *fqn, *nodumpreason, *sysconffile = "system configuration file"; @@ -4617,6 +4618,7 @@ reveal_paths(int code) if (code == 1) { raw_printf("NOTE: The %s above is missing or inaccessible!", sysconffile); + skip_sysopt = TRUE; } #else /* !SYSCF */ raw_printf("No system configuration file."); @@ -4690,17 +4692,20 @@ reveal_paths(int code) /* dumplog */ + fqn = (char *) 0; #ifndef DUMPLOG nodumpreason = "not supported"; #else nodumpreason = "disabled"; #ifdef SYSCF - fqn = sysopt.dumplogfile; + if (!skip_sysopt) { + fqn = sysopt.dumplogfile; + } else { + nodumpreason = "dumplogfile setting unavailable from missing sysconf"; + } #else /* !SYSCF */ #ifdef DUMPLOG_FILE fqn = DUMPLOG_FILE; -#else - fqn = (char *) 0; #endif #endif /* ?SYSCF */ if (fqn && *fqn) { @@ -4708,20 +4713,23 @@ reveal_paths(int code) (void) dump_fmtstr(fqn, buf, FALSE); buf[sizeof buf - sizeof " \"\""] = '\0'; raw_printf(" \"%s\"", buf); - } else + } else { + raw_printf("No end-of-game disclosure file (%s)", nodumpreason); + } #endif /* ?DUMPLOG */ - raw_printf("No end-of-game disclosure file (%s).", nodumpreason); #ifdef WIN32 - if (sysopt.portable_device_paths) { - const char *pd = get_portable_device(); + if (!skip_sysopt) { + if (sysopt.portable_device_paths) { + const char *pd = get_portable_device(); - /* an empty value for pd indicates that portable_device_paths - got set TRUE in a sysconf file other than the one containing - the executable; disregard it */ - if (strlen(pd) > 0) { - raw_printf("portable_device_paths (set in sysconf):"); - raw_printf(" \"%s\"", pd); + /* an empty value for pd indicates that portable_device_paths + got set TRUE in a sysconf file other than the one containing + the executable; disregard it */ + if (strlen(pd) > 0) { + raw_printf("portable_device_paths (set in sysconf):"); + raw_printf(" \"%s\"", pd); + } } } #endif From 9ba20d0e2275c4ec28e2297d042e6328c9465f7f Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 23 Dec 2024 00:33:12 -0500 Subject: [PATCH 235/791] more follow-up tweaking for missing sysconf --showpaths --- src/files.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/files.c b/src/files.c index 8acf9f527..76f7197ee 100644 --- a/src/files.c +++ b/src/files.c @@ -4562,12 +4562,13 @@ debugcore(const char *filename, boolean wildcards) #endif #endif +#define SYSCONFFILE "system configuration file" + void reveal_paths(int code) { boolean skip_sysopt = FALSE; - const char *fqn, *nodumpreason, - *sysconffile = "system configuration file"; + const char *fqn, *nodumpreason; char buf[BUFSZ]; #if defined(SYSCF) || !defined(UNIX) || defined(DLB) @@ -4602,8 +4603,8 @@ reveal_paths(int code) #else buf[0] = '\0'; #endif - raw_printf("%s %s%s:", - s_suffix(gamename), sysconffile, buf); + raw_printf("%s %s%s:", s_suffix(gamename), + SYSCONFFILE, buf); #ifdef SYSCF_FILE filep = SYSCF_FILE; #else @@ -4617,7 +4618,7 @@ reveal_paths(int code) raw_printf(" \"%s\"", filep); if (code == 1) { raw_printf("NOTE: The %s above is missing or inaccessible!", - sysconffile); + SYSCONFFILE); skip_sysopt = TRUE; } #else /* !SYSCF */ @@ -4700,8 +4701,10 @@ reveal_paths(int code) #ifdef SYSCF if (!skip_sysopt) { fqn = sysopt.dumplogfile; + if (!fqn) + nodumpreason = "DUMPLOGFILE is not set in " SYSCONFFILE; } else { - nodumpreason = "dumplogfile setting unavailable from missing sysconf"; + nodumpreason = SYSCONFFILE " is missing; no DUMPLOGFILE setting"; } #else /* !SYSCF */ #ifdef DUMPLOG_FILE @@ -4714,7 +4717,7 @@ reveal_paths(int code) buf[sizeof buf - sizeof " \"\""] = '\0'; raw_printf(" \"%s\"", buf); } else { - raw_printf("No end-of-game disclosure file (%s)", nodumpreason); + raw_printf("No end-of-game disclosure file (%s).", nodumpreason); } #endif /* ?DUMPLOG */ From e32ac5a7c77074b13136ab2582add1bf01d71913 Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 23 Dec 2024 00:50:38 -0500 Subject: [PATCH 236/791] fixes3-7-0.txt update for showpaths option tweaks --- doc/fixes3-7-0.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index 03b0488c7..773720728 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -1495,6 +1495,7 @@ failed #untrap could move hero diagonally into or out of an open doorway remember box is trapped after finding the trap when you hear a monster incant a scroll, ensure that the 'I' invisible monster indicator doesn't trump telepathy briefly +proceed with showpaths option even if the sysconf file is missing Fixes to 3.7.0-x General Problems Exposed Via git Repository From 95cf46c1020a3278865485add77fe5881d1dd910 Mon Sep 17 00:00:00 2001 From: nhmall Date: Tue, 24 Dec 2024 10:27:12 -0500 Subject: [PATCH 237/791] update Guidebook and some generated files --- Files | 29 ++++++++++----------- doc/Guidebook.mn | 2 +- doc/Guidebook.tex | 2 +- doc/dlb.txt | 18 ++++++------- doc/makedefs.txt | 64 +++++++++++++++++++++++------------------------ doc/nethack.txt | 4 +-- doc/recover.txt | 28 ++++++++++----------- 7 files changed, 74 insertions(+), 73 deletions(-) diff --git a/Files b/Files index 995b17ff3..d9706ea8e 100644 --- a/Files +++ b/Files @@ -47,20 +47,21 @@ Val-strt.lua Wiz-fila.lua Wiz-filb.lua Wiz-goal.lua Wiz-loca.lua Wiz-strt.lua air.lua asmodeus.lua astral.lua baalz.lua bigrm-1.lua bigrm-2.lua bigrm-3.lua bigrm-4.lua bigrm-5.lua bigrm-6.lua bigrm-7.lua bigrm-8.lua bigrm-9.lua bigrm-10.lua -bigrm-11.lua bogusmon.txt castle.lua cmdhelp data.base -dungeon.lua earth.lua engrave.txt epitaph.txt fakewiz1.lua -fakewiz2.lua fire.lua hellfill.lua help hh -history juiblex.lua keyhelp knox.lua license -medusa-1.lua medusa-2.lua medusa-3.lua medusa-4.lua minefill.lua -minend-1.lua minend-2.lua minend-3.lua minetn-1.lua minetn-2.lua -minetn-3.lua minetn-4.lua minetn-5.lua minetn-6.lua minetn-7.lua -nhcore.lua nhlib.lua opthelp optmenu oracle.lua -oracles.txt orcus.lua quest.lua rumors.fal rumors.tru -sanctum.lua soko1-1.lua soko1-2.lua soko2-1.lua soko2-2.lua -soko3-1.lua soko3-2.lua soko4-1.lua soko4-2.lua symbols -themerms.lua tower1.lua tower2.lua tower3.lua tribute -tut-1.lua tut-2.lua usagehlp valley.lua water.lua -wizard1.lua wizard2.lua wizard3.lua wizhelp +bigrm-11.lua bigrm-12.lua bogusmon.txt castle.lua cmdhelp +data.base dungeon.lua earth.lua engrave.txt epitaph.txt +fakewiz1.lua fakewiz2.lua fire.lua hellfill.lua help +hh history juiblex.lua keyhelp knox.lua +license luahelper medusa-1.lua medusa-2.lua medusa-3.lua +medusa-4.lua minefill.lua minend-1.lua minend-2.lua minend-3.lua +minetn-1.lua minetn-2.lua minetn-3.lua minetn-4.lua minetn-5.lua +minetn-6.lua minetn-7.lua nhcore.lua nhlib.lua opthelp +optmenu oracle.lua oracles.txt orcus.lua quest.lua +rumors.fal rumors.tru sanctum.lua soko1-1.lua soko1-2.lua +soko2-1.lua soko2-2.lua soko3-1.lua soko3-2.lua soko4-1.lua +soko4-2.lua symbols themerms.lua tower1.lua tower2.lua +tower3.lua tribute tut-1.lua tut-2.lua usagehlp +valley.lua water.lua wizard1.lua wizard2.lua wizard3.lua +wizhelp doc: (files for all versions) diff --git a/doc/Guidebook.mn b/doc/Guidebook.mn index ebf6fd82d..7d5eabde2 100644 --- a/doc/Guidebook.mn +++ b/doc/Guidebook.mn @@ -47,7 +47,7 @@ .ds f0 \*(vr .ds f1 \" empty .\"DO NOT REMOVE NH_DATESUB .ds f2 Date(%B %-d, %Y) -.ds f2 November 4, 2024 +.ds f2 November 16, 2024 . .\" A note on some special characters: .\" \(lq = left double quote diff --git a/doc/Guidebook.tex b/doc/Guidebook.tex index 491477711..b6769704c 100644 --- a/doc/Guidebook.tex +++ b/doc/Guidebook.tex @@ -48,7 +48,7 @@ \author{Original version - Eric S. Raymond\\ (Edited and expanded for 3.7.0 by Mike Stephenson and others)} %DO NOT REMOVE NH_DATESUB \date{Date(%B %-d, %Y)} -\date{September 13, 2024} +\date{November 16, 2024} \maketitle diff --git a/doc/dlb.txt b/doc/dlb.txt index f185c3b2a..cd037be37 100644 --- a/doc/dlb.txt +++ b/doc/dlb.txt @@ -1,4 +1,4 @@ -DLB(6) DLB(6) +DLB(6) Games Manual DLB(6) @@ -13,8 +13,8 @@ DESCRIPTION NetHack version 3.1 and higher. It is used to maintain the archive files from which NetHack reads special level files and other read-only information. Note that like tar the command and option specifiers are - specified as a continuous string and are followed by any arguments - required in the same order as the option specifiers. + specified as a continuous string and are followed by any arguments re- + quired in the same order as the option specifiers. This facility is optional and may be excluded during NetHack configura- tion. @@ -55,16 +55,16 @@ SEE ALSO nethack(6), tar(1) BUGS - Not a good tar emulation; - does not mean stdin or stdout. Should - include an optional compression facility. Not all read-only files for + Not a good tar emulation; - does not mean stdin or stdout. Should in- + clude an optional compression facility. Not all read-only files for NetHack can be read out of an archive; examining the source is the only way to know which files can be. COPYRIGHT - This file is Copyright (C) Kenneth Lorber, 2022 for version - NetHack-3.7:1.12. NetHack may be freely redistributed. See license - for details. + This file is Copyright (C) Kenneth Lorber, DATE(%Y) for version keni- + gitset:1.13. NetHack may be freely redistributed. See license for de- + tails. -NETHACK 8 February 2022 DLB(6) +NETHACK DATE(1-d 1B 1Y) DLB(6) diff --git a/doc/makedefs.txt b/doc/makedefs.txt index ad7ab4175..975a9cde5 100644 --- a/doc/makedefs.txt +++ b/doc/makedefs.txt @@ -1,4 +1,4 @@ -MAKEDEFS(6) MAKEDEFS(6) +MAKEDEFS(6) Games Manual MAKEDEFS(6) @@ -32,13 +32,13 @@ SHORT COMMANDS -m Generate date.h and options file. It will read dat/gitinfo.txt, only if it is present, to obtain githash= and gitbranch= - info and include related preprocessor #defines in date.h file. + info and include related preprocessor #defines in date.h file. -p Generate pm.h -q Generate the rumors file. - -s Generate the bogusmon , engrave and epitaph files. + -s Generate the bogusmon, engrave, and epitaph files. -1 Generate the epitaph file. @@ -53,7 +53,7 @@ LONG COMMANDS Show debugging output. --make [command] - Execute a short command. Command is given without preceding + Execute a short command. Command is given without preceding dash. --input file @@ -61,67 +61,67 @@ LONG COMMANDS is - standard input is read. --output file - Specify the output file for the command (if needed). If the + Specify the output file for the command (if needed). If the file is - standard output is written. --svs [delimiter] - Generate a version string to standard output without a trailing - newline. If specified, the delimiter is used between each part + Generate a version string to standard output without a trailing + newline. If specified, the delimiter is used between each part of the version string. - --grep Filter the input file to the output file. See the MDGREP FUNC- + --grep Filter the input file to the output file. See the MDGREP FUNC- TIONS section below for information on controlling the filtering operation. --grep-showvars - Show the name and value for each variable known to the grep - option. + Show the name and value for each variable known to the grep op- + tion. --grep-trace - Turn on debug tracing for the grep function ( --grep must be + Turn on debug tracing for the grep function ( --grep must be specified as well). --grep-defined symbol - Exit shell true (0) if symbol is known and defined, otherwise + Exit shell true (0) if symbol is known and defined, otherwise exit shell false (1). --grep-define symbol - Force the value of symbol to be "defined." Symbol must already + Force the value of symbol to be "defined." Symbol must already be known to makedefs. --grep-undef symbol - Force the definition of symbol to be "undefined." Symbol must + Force the definition of symbol to be "undefined." Symbol must already be known to makedefs. MDGREP FUNCTIONS - The --grep command (and certain other commands) filter their input, on - a line-by-line basis, according to control lines embedded in the input - and on information gleaned from the NetHack(6) configuration. This - allows certain changes such as embedding platform-specific documenta- - tion into the master documentation files. + The --grep command (and certain other commands) filter their input, on + a line-by-line basis, according to control lines embedded in the input + and on information gleaned from the NetHack(6) configuration. This al- + lows certain changes such as embedding platform-specific documentation + into the master documentation files. Rules: - The default conditional state is printing enabled. - - Any line NOT starting with a caret (^) is either suppressed - or passed through unchanged depending on the current condi- + - Any line NOT starting with a caret (^) is either suppressed + or passed through unchanged depending on the current condi- tional state. - - Any line starting with a caret is a control line; as in C, - zero or more spaces may be embedded in the line almost any- - where (except immediately after the caret); however the + - Any line starting with a caret is a control line; as in C, + zero or more spaces may be embedded in the line almost any- + where (except immediately after the caret); however the caret must be in column 1. - Conditionals may be nested. - - Makedefs will exit with an error code if any errors are - detected; processing will continue (if it can) to allow as + - Makedefs will exit with an error code if any errors are de- + tected; processing will continue (if it can) to allow as many errors as possible to be detected. - - Unknown identifiers are treated as both TRUE and as an - error. Note that --undef or #undef in the NetHack(6) con- - figuration are different from unknown. + - Unknown identifiers are treated as both TRUE and as an er- + ror. Note that --undef or #undef in the NetHack(6) configu- + ration are different from unknown. Control lines: @@ -143,9 +143,9 @@ AUTHOR The NetHack Development Team COPYRIGHT - This file is Copyright (C) Kenneth Lorber, 2022 for version keni-crash- - web2:1.21. NetHack may be freely redistributed. See license for - details. + This file is Copyright (C) Kenneth Lorber, 2022 for version + NetHack-3.7:1.22. NetHack may be freely redistributed. See license + for details. diff --git a/doc/nethack.txt b/doc/nethack.txt index 9afe9924d..39f8d3bd9 100644 --- a/doc/nethack.txt +++ b/doc/nethack.txt @@ -278,7 +278,7 @@ BUGS Probably infinite. COPYRIGHT - This file is Copyright (C) Robert Patrick Rankin, 2024 for version + This file is Copyright (C) Robert Patrick Rankin, 2022 for version NetHack-3.7:1.31. NetHack may be freely redistributed. See license for details. @@ -286,4 +286,4 @@ COPYRIGHT -NETHACK 28 February 2024 NETHACK(6) +NETHACK 21 February 2022 NETHACK(6) diff --git a/doc/recover.txt b/doc/recover.txt index 1eacac0d7..b19d9cb43 100644 --- a/doc/recover.txt +++ b/doc/recover.txt @@ -1,4 +1,4 @@ -RECOVER(6) RECOVER(6) +RECOVER(6) Games Manual RECOVER(6) @@ -35,14 +35,14 @@ DESCRIPTION The level file names are of the form base.nn, where nn is an internal bookkeeping number for the level. The file base.0 is used for game identity, locking, and, when checkpointing, for the game state. Vari- - ous OSes use different strategies for constructing the base name. - Microcomputers use the character name, possibly truncated and modified - to be a legal filename on that system. Multi-user systems use the - (modified) character name prefixed by a user number to avoid conflicts, - or "xlock" if the number of concurrent players is being limited. It - may be necessary to look in the playground to find the correct base - name of the interrupted game. recover will transform these level files - into a save file of the same name as nethack would have used. + ous OSes use different strategies for constructing the base name. Mi- + crocomputers use the character name, possibly truncated and modified to + be a legal filename on that system. Multi-user systems use the (modi- + fied) character name prefixed by a user number to avoid conflicts, or + "xlock" if the number of concurrent players is being limited. It may + be necessary to look in the playground to find the correct base name of + the interrupted game. recover will transform these level files into a + save file of the same name as nethack would have used. Since recover must be able to read and delete files from the playground and create files in the save directory, it has interesting interactions @@ -53,9 +53,9 @@ DESCRIPTION some of the microcomputer ports install recover by default. For a multi-user system, the game administrator may want to arrange for - all .0 files in the playground to be fed to recover when the host - machine boots, and handle game crashes individually. If the user popu- - lation is sufficiently trustworthy, recover can be installed with the + all .0 files in the playground to be fed to recover when the host ma- + chine boots, and handle game crashes individually. If the user popula- + tion is sufficiently trustworthy, recover can be installed with the same permissions the nethack executable has. In either case, recover is easily compiled from the distribution utility directory. @@ -70,8 +70,8 @@ SEE ALSO BUGS recover makes no attempt to find out if a base name specifies a game in - progress. If multiple machines share a playground, this would be - impossible to determine. + progress. If multiple machines share a playground, this would be im- + possible to determine. recover should be taught to use the nethack playground locking mecha- nism to avoid conflicts. From bdff809099106abd0389325c4b817add24d0c436 Mon Sep 17 00:00:00 2001 From: nhkeni Date: Tue, 24 Dec 2024 12:37:20 -0500 Subject: [PATCH 238/791] Update hyphenation for *.mn and *.6 files. --- doc/dlb.6 | 5 +++++ doc/makedefs.6 | 5 +++++ doc/nethack.6 | 5 +++++ doc/recover.6 | 5 +++++ doc/tmac.nh | 9 +++++---- 5 files changed, 25 insertions(+), 4 deletions(-) diff --git a/doc/dlb.6 b/doc/dlb.6 index 058c6b42f..f70a3da41 100644 --- a/doc/dlb.6 +++ b/doc/dlb.6 @@ -11,6 +11,11 @@ .. .NB $NHDT-Branch: keni-gitset $ .NR $NHDT-Revision: 1.13 $ +.\" groff and AT&T-descended troffs use different hyphenation patterns. +.\" Don't hyphenate the last word on a page or column, or +.\" before/after last/first 2 characters of a word. +.ie \n(.g .hy 12 +.el .hy 14 .ds Na Kenneth Lorber .SH NAME dlb \- NetHack data librarian diff --git a/doc/makedefs.6 b/doc/makedefs.6 index 4c4a65dd6..4da8c4b43 100644 --- a/doc/makedefs.6 +++ b/doc/makedefs.6 @@ -10,6 +10,11 @@ .. .NB $NHDT-Branch: NetHack-3.7 $ .NR $NHDT-Revision: 1.22 $ +.\" groff and AT&T-descended troffs use different hyphenation patterns. +.\" Don't hyphenate the last word on a page or column, or +.\" before/after last/first 2 characters of a word. +.ie \n(.g .hy 12 +.el .hy 14 .ds Na Kenneth Lorber .SH NAME makedefs \- NetHack miscellaneous build-time functions diff --git a/doc/nethack.6 b/doc/nethack.6 index 735ffa46e..3c1c7f6c9 100644 --- a/doc/nethack.6 +++ b/doc/nethack.6 @@ -10,6 +10,11 @@ .. .NB $NHDT-Branch: NetHack-3.7 $ .NR $NHDT-Revision: 1.31 $ +.\" groff and AT&T-descended troffs use different hyphenation patterns. +.\" Don't hyphenate the last word on a page or column, or +.\" before/after last/first 2 characters of a word. +.ie \n(.g .hy 12 +.el .hy 14 .ds Na Robert Patrick Rankin .SH NAME nethack \- Exploring The Mazes of Menace diff --git a/doc/recover.6 b/doc/recover.6 index 9972ff6d6..488e9e33b 100644 --- a/doc/recover.6 +++ b/doc/recover.6 @@ -10,6 +10,11 @@ .. .NB $NHDT-Branch: NetHack-3.7 $ .NR $NHDT-Revision: 1.12 $ +.\" groff and AT&T-descended troffs use different hyphenation patterns. +.\" Don't hyphenate the last word on a page or column, or +.\" before/after last/first 2 characters of a word. +.ie \n(.g .hy 12 +.el .hy 14 .ds Na Kenneth Lorber .SH NAME recover \- recover a NetHack game interrupted by disaster diff --git a/doc/tmac.nh b/doc/tmac.nh index fce6f786d..86bc643b4 100644 --- a/doc/tmac.nh +++ b/doc/tmac.nh @@ -134,8 +134,9 @@ \\$1\\$2 .. . -.\" Don't hyphenate the last word on a page or column. groff and AT&T- -.\" descended troffs use different hyphenation patterns. -.ie \n(.g .hy 6 -.el .hy 2 +.\" groff and AT&T-descended troffs use different hyphenation patterns. +.\" Don't hyphenate the last word on a page or column, or +.\" before/after last/first 2 characters of a word. +.ie \n(.g .hy 12 +.el .hy 14 .\"tmac.nh/" From c27cb28ec5d63078395f089524b1263d6484be1b Mon Sep 17 00:00:00 2001 From: nhkeni Date: Tue, 24 Dec 2024 12:46:53 -0500 Subject: [PATCH 239/791] Use old-style --int flag to git to work with older gits. --- DEVEL/hooksdir/NHgithook.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEVEL/hooksdir/NHgithook.pm b/DEVEL/hooksdir/NHgithook.pm index 3f52008c0..065fcd60a 100644 --- a/DEVEL/hooksdir/NHgithook.pm +++ b/DEVEL/hooksdir/NHgithook.pm @@ -151,7 +151,7 @@ sub nhversioning { # Check for pre-v4 source repo. my $is_sourcerepo; { - chomp($is_sourcerepo = `git config --type=int --get nethack.is-sourcerepo`); + chomp($is_sourcerepo = `git config --int --get nethack.is-sourcerepo`); if(0 == length $is_sourcerepo){ # not set - assume old repo $is_sourcerepo = 1; }elsif($is_sourcerepo==1){ From 4507323a42aa5beae459703274299e196cb4196a Mon Sep 17 00:00:00 2001 From: nhmall Date: Tue, 24 Dec 2024 13:41:17 -0500 Subject: [PATCH 240/791] more doc updates --- doc/Guidebook.txt | 3814 ++++++++++++++++++++++----------------------- doc/dlb.txt | 33 +- doc/makedefs.txt | 75 +- doc/mn.txt | 18 +- doc/nethack.txt | 201 +-- doc/recover.txt | 81 +- 6 files changed, 2117 insertions(+), 2105 deletions(-) diff --git a/doc/Guidebook.txt b/doc/Guidebook.txt index 22a706fac..480c55893 100644 --- a/doc/Guidebook.txt +++ b/doc/Guidebook.txt @@ -15,7 +15,7 @@ Original version - Eric S. Raymond (Edited and expanded for NetHack 3.7.0 by Mike Stephenson and others) - September 13, 2024 + November 16, 2024 @@ -81,8 +81,8 @@ much treasure as you can, retrieve the Amulet of Yendor, and escape the Mazes of Menace alive. - Your abilities and strengths for dealing with the hazards of ad- - venture will vary with your background and training: + Your abilities and strengths for dealing with the hazards of + adventure will vary with your background and training: Archeologists understand dungeons pretty well; this enables them to move quickly and sneak up on the local nasties. They start @@ -97,12 +97,13 @@ Healers are wise in medicine and apothecary. They know the herbs and simples that can restore vitality, ease pain, anesthetize, and - neutralize poisons; and with their instruments, they can divine a be- - ing's state of health or sickness. Their medical practice earns them - quite reasonable amounts of money, with which they enter the dungeon. + neutralize poisons; and with their instruments, they can divine a + being's state of health or sickness. Their medical practice earns + them quite reasonable amounts of money, with which they enter the dun- + geon. - Knights are distinguished from the common skirmisher by their de- - votion to the ideals of chivalry and by the surpassing excellence of + Knights are distinguished from the common skirmisher by their + devotion to the ideals of chivalry and by the surpassing excellence of their armor. Monks are ascetics, who by rigorous practice of physical and men- @@ -111,22 +112,21 @@ mobility. Priests and Priestesses are clerics militant, crusaders advancing - the cause of righteousness with arms, armor, and arts thaumaturgic. - Their ability to commune with deities via prayer occasionally extri- + the cause of righteousness with arms, armor, and arts thaumaturgic. + Their ability to commune with deities via prayer occasionally extri- cates them from peril, but can also put them in it. - Rangers are most at home in the woods, and some say slightly out - of place in a dungeon. They are, however, experts in archery as well + Rangers are most at home in the woods, and some say slightly out + of place in a dungeon. They are, however, experts in archery as well as tracking and stealthy movement. - Rogues are agile and stealthy thieves, with knowledge of locks, - traps, and poisons. Their advantage lies in surprise, which they em- - ploy to great advantage. + Rogues are agile and stealthy thieves, with knowledge of locks, + traps, and poisons. Their advantage lies in surprise, which they + employ to great advantage. - - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -136,63 +136,63 @@ - Samurai are the elite warriors of feudal Nippon. They are - lightly armored and quick, and wear the dai-sho, two swords of the + Samurai are the elite warriors of feudal Nippon. They are + lightly armored and quick, and wear the dai-sho, two swords of the deadliest keenness. - Tourists start out with lots of gold (suitable for shopping - with), a credit card, lots of food, some maps, and an expensive cam- + Tourists start out with lots of gold (suitable for shopping + with), a credit card, lots of food, some maps, and an expensive cam- era. Most monsters don't like being photographed. Valkyries are hardy warrior women. Their upbringing in the harsh - Northlands makes them strong, inures them to extremes of cold, and in- - stills in them stealth and cunning. + Northlands makes them strong, inures them to extremes of cold, and + instills in them stealth and cunning. Wizards start out with a knowledge of magic, a selection of magi- cal items, and a particular affinity for dweomercraft. Although seem- - ingly weak and easy to overcome at first sight, an experienced Wizard + ingly weak and easy to overcome at first sight, an experienced Wizard is a deadly foe. - You may also choose the race of your character (within limits; + You may also choose the race of your character (within limits; most roles have restrictions on which races are eligible for them): - Dwarves are smaller than humans or elves, but are stocky and - solid individuals. Dwarves' most notable trait is their great exper- - tise in mining and metalwork. Dwarvish armor is said to be second in + Dwarves are smaller than humans or elves, but are stocky and + solid individuals. Dwarves' most notable trait is their great exper- + tise in mining and metalwork. Dwarvish armor is said to be second in quality not even to the mithril armor of the Elves. - Elves are agile, quick, and perceptive; very little of what goes + Elves are agile, quick, and perceptive; very little of what goes on will escape an Elf. The quality of Elven craftsmanship often gives them an advantage in arms and armor. Gnomes are smaller than but generally similar to dwarves. Gnomes - are known to be expert miners, and it is known that a secret under- + are known to be expert miners, and it is known that a secret under- ground mine complex built by this race exists within the Mazes of Men- ace, filled with both riches and danger. - Humans are by far the most common race of the surface world, and - are thus the norm to which other races are often compared. Although + Humans are by far the most common race of the surface world, and + are thus the norm to which other races are often compared. Although they have no special abilities, they can succeed in any role. - Orcs are a cruel and barbaric race that hate every living thing + Orcs are a cruel and barbaric race that hate every living thing (including other orcs). Above all others, Orcs hate Elves with a pas- - sion unequalled, and will go out of their way to kill one at any op- - portunity. The armor and weapons fashioned by the Orcs are typically - of inferior quality. + sion unequalled, and will go out of their way to kill one at any + opportunity. The armor and weapons fashioned by the Orcs are typi- + cally of inferior quality. 3. What do all those things on the screen mean? - On the screen is kept a map of where you have been and what you - have seen on the current dungeon level; as you explore more of the + On the screen is kept a map of where you have been and what you + have seen on the current dungeon level; as you explore more of the level, it appears on the screen in front of you. When NetHack's ancestor rogue first appeared, its screen orienta- - tion was almost unique among computer fantasy games. Since then, - screen orientation has become the norm rather than the exception; - NetHack continues this fine tradition. Unlike text adventure games + tion was almost unique among computer fantasy games. Since then, + screen orientation has become the norm rather than the exception; + NetHack continues this fine tradition. Unlike text adventure games - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -202,38 +202,38 @@ - that accept commands in pseudo-English sentences and explain the re- - sults in words, NetHack commands are all one or two keystrokes and the - results are displayed graphically on the screen. A minimum screen - size of 24 lines by 80 columns is recommended; if the screen is + that accept commands in pseudo-English sentences and explain the + results in words, NetHack commands are all one or two keystrokes and + the results are displayed graphically on the screen. A minimum screen + size of 24 lines by 80 columns is recommended; if the screen is larger, only a 21x80 section will be used for the map. - NetHack can even be played by blind players, with the assistance + NetHack can even be played by blind players, with the assistance of Braille readers or speech synthesisers. Instructions for configur- ing NetHack for the blind are included later in this document. - NetHack generates a new dungeon every time you play it; even the + NetHack generates a new dungeon every time you play it; even the authors still find it an entertaining and exciting game despite having won several times. - NetHack offers a variety of display options. The options avail- + NetHack offers a variety of display options. The options avail- able to you will vary from port to port, depending on the capabilities - of your hardware and software, and whether various compile-time op- - tions were enabled when your executable was created. The three possi- - ble display options are: a monochrome character interface, a color - character interface, and a graphical interface using small pictures - called tiles. The two character interfaces allow fonts with other + of your hardware and software, and whether various compile-time + options were enabled when your executable was created. The three pos- + sible display options are: a monochrome character interface, a color + character interface, and a graphical interface using small pictures + called tiles. The two character interfaces allow fonts with other characters to be substituted, but the default assignments use standard - ASCII characters to represent everything. There is no difference be- - tween the various display options with respect to game play. Because - we cannot reproduce the tiles or colors in the Guidebook, and because - it is common to all ports, we will use the default ASCII characters - from the monochrome character display when referring to things you - might see on the screen during your game. + ASCII characters to represent everything. There is no difference + between the various display options with respect to game play. + Because we cannot reproduce the tiles or colors in the Guidebook, and + because it is common to all ports, we will use the default ASCII char- + acters from the monochrome character display when referring to things + you might see on the screen during your game. - In order to understand what is going on in NetHack, first you - must understand what NetHack is doing with the screen. The NetHack - screen replaces the "You see ..." descriptions of text adventure + In order to understand what is going on in NetHack, first you + must understand what NetHack is doing with the screen. The NetHack + screen replaces the "You see ..." descriptions of text adventure games. Figure 1 is a sample of what a NetHack screen might look like. The way the screen looks for you depends on your platform. @@ -258,7 +258,7 @@ - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -324,7 +324,7 @@ - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -342,15 +342,15 @@ 3.1. The status lines (bottom) - The bottom two (or three) lines of the screen contain several - cryptic pieces of information describing your current status. Figure - 1 shows the traditional two-line status area below the map. Figure 2 + The bottom two (or three) lines of the screen contain several + cryptic pieces of information describing your current status. Figure + 1 shows the traditional two-line status area below the map. Figure 2 shows just the status area, when the statuslines:3 option has been set - (not all interfaces support this option). If any status line becomes - wider than the screen, you might not see all of it due to truncation. - When the numbers grow bigger and multiple conditions are present, the - two-line format will run out of room on the second line, but sta- - tuslines:2 is the default because a basic 24-line terminal isn't tall + (not all interfaces support this option). If any status line becomes + wider than the screen, you might not see all of it due to truncation. + When the numbers grow bigger and multiple conditions are present, the + two-line format will run out of room on the second line, but sta- + tuslines:2 is the default because a basic 24-line terminal isn't tall enough for the third line. Here are explanations of what the various status items mean: @@ -360,37 +360,37 @@ experience level, see below). Strength - A measure of your character's strength; one of your six basic at- - tributes. A human character's attributes can range from 3 to 18 - inclusive; non-humans may exceed these limits (occasionally you - may get super-strengths of the form 18/xx, and magic can also - cause attributes to exceed the normal limits). The higher your - strength, the stronger you are. Strength affects how success- - fully you perform physical tasks, how much damage you do in com- + A measure of your character's strength; one of your six basic + attributes. A human character's attributes can range from 3 to + 18 inclusive; non-humans may exceed these limits (occasionally + you may get super-strengths of the form 18/xx, and magic can also + cause attributes to exceed the normal limits). The higher your + strength, the stronger you are. Strength affects how success- + fully you perform physical tasks, how much damage you do in com- bat, and how much loot you can carry. Dexterity - Dexterity affects your chances to hit in combat, to avoid traps, + Dexterity affects your chances to hit in combat, to avoid traps, and do other tasks requiring agility or manipulation of objects. Constitution - Constitution affects your ability to recover from injuries and - other strains on your stamina. When strength is low or modest, - constitution also affects how much you can carry. With suffi- + Constitution affects your ability to recover from injuries and + other strains on your stamina. When strength is low or modest, + constitution also affects how much you can carry. With suffi- ciently high strength, the contribution to carrying capacity from your constitution no longer matters. Intelligence - Intelligence affects your ability to cast spells and read spell- + Intelligence affects your ability to cast spells and read spell- books. Wisdom - Wisdom comes from your practical experience (especially when + Wisdom comes from your practical experience (especially when dealing with magic). It affects your magical energy. - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -405,58 +405,58 @@ ticular, it can affect the prices shopkeepers offer you. Alignment - Lawful, Neutral, or Chaotic. Often, Lawful is taken as good and - Chaotic as evil, but legal and ethical do not always coincide. - Your alignment influences how other monsters react toward you. - Monsters of a like alignment are more likely to be non-aggres- - sive, while those of an opposing alignment are more likely to be + Lawful, Neutral, or Chaotic. Often, Lawful is taken as good and + Chaotic as evil, but legal and ethical do not always coincide. + Your alignment influences how other monsters react toward you. + Monsters of a like alignment are more likely to be non-aggres- + sive, while those of an opposing alignment are more likely to be seriously offended at your presence. Dungeon Level - How deep you are in the dungeon. You start at level one and the - number increases as you go deeper into the dungeon. Some levels - are special, and are identified by a name and not a number. The + How deep you are in the dungeon. You start at level one and the + number increases as you go deeper into the dungeon. Some levels + are special, and are identified by a name and not a number. The Amulet of Yendor is reputed to be somewhere beneath the twentieth level. Gold - The number of gold pieces you are openly carrying. Gold which + The number of gold pieces you are openly carrying. Gold which you have concealed in containers is not counted. Hit Points - Your current and maximum hit points. Hit points indicate how + Your current and maximum hit points. Hit points indicate how much damage you can take before you die. The more you get hit in - a fight, the lower they get. You can regain hit points by rest- - ing, or by using certain magical items or spells. The number in + a fight, the lower they get. You can regain hit points by rest- + ing, or by using certain magical items or spells. The number in parentheses is the maximum number your hit points can reach. Power - Spell points. This tells you how much mystic energy (mana) you + Spell points. This tells you how much mystic energy (mana) you have available for spell casting. Again, resting will regenerate the amount available. Armor Class - A measure of how effectively your armor stops blows from un- - friendly creatures. The lower this number is, the more effective - the armor; it is quite possible to have negative armor class. - See the Armor subsection of Objects for more information. + A measure of how effectively your armor stops blows from + unfriendly creatures. The lower this number is, the more effec- + tive the armor; it is quite possible to have negative armor + class. See the Armor subsection of Objects for more information. Experience - Your current experience level. If the showexp option is set, it + Your current experience level. If the showexp option is set, it will be followed by a slash and experience points. As you adven- - ture, you gain experience points. At certain experience point - totals, you gain an experience level. The more experienced you + ture, you gain experience points. At certain experience point + totals, you gain an experience level. The more experienced you are, the better you fight and withstand magical attacks. (By the - time your level reaches double digits, the usefulness of showing - the points with it has dropped significantly. You can use the - `O' command to turn showexp off to avoid using up the limited + time your level reaches double digits, the usefulness of showing + the points with it has dropped significantly. You can use the + `O' command to turn showexp off to avoid using up the limited status line space.) Time - The number of turns elapsed so far, displayed if you have the + The number of turns elapsed so far, displayed if you have the - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -469,60 +469,60 @@ time option set. Status - Hunger: your current hunger status. Values are Satiated, Not - Hungry (or Normal), Hungry, Weak, and Fainting. Not shown when + Hunger: your current hunger status. Values are Satiated, Not + Hungry (or Normal), Hungry, Weak, and Fainting. Not shown when Normal. - Encumbrance: an indication of how what you are carrying affects - your ability to move. Values are Unencumbered, Burdened, - Stressed, Strained, Overtaxed, and Overloaded. Not shown when + Encumbrance: an indication of how what you are carrying affects + your ability to move. Values are Unencumbered, Burdened, + Stressed, Strained, Overtaxed, and Overloaded. Not shown when Unencumbered. Fatal conditions: Stone (aka Petrifying, turning to stone), Slime - (turning into green slime), Strngl (being strangled), FoodPois - (suffering from acute food poisoning), TermIll (suffering from a + (turning into green slime), Strngl (being strangled), FoodPois + (suffering from acute food poisoning), TermIll (suffering from a terminal illness). - Non-fatal conditions: Blind (can't see), Deaf (can't hear), Stun + Non-fatal conditions: Blind (can't see), Deaf (can't hear), Stun (stunned), Conf (confused), Hallu (hallucinating). - Movement modifiers: Lev (levitating), Fly (flying), Ride (rid- + Movement modifiers: Lev (levitating), Fly (flying), Ride (rid- ing). Other conditions and modifiers exist, but there isn't enough room to display them with the other status fields. - The #attributes command (default key ^X) will show all current status - information in unabbreviated format. It also shows other information + The #attributes command (default key ^X) will show all current status + information in unabbreviated format. It also shows other information which might be included on the status lines if those had more room. 3.2. The message line (top) The top line of the screen is reserved for messages that describe - things that are impossible to represent visually. If you see a - "--More--" on the top line, this means that NetHack has another mes- - sage to display on the screen, but it wants to make certain that - you've read the one that is there first. To read the next message, + things that are impossible to represent visually. If you see a + "--More--" on the top line, this means that NetHack has another mes- + sage to display on the screen, but it wants to make certain that + you've read the one that is there first. To read the next message, just press the space bar. - To change how and what messages are shown on the message line, + To change how and what messages are shown on the message line, see "Configuring Message Types" and the verbose option. 3.3. The map (rest of the screen) - The rest of the screen is the map of the level as you have ex- - plored it so far. Each symbol on the screen represents something. + The rest of the screen is the map of the level as you have + explored it so far. Each symbol on the screen represents something. You can set various graphics options to change some of the symbols the - game uses; otherwise, the game will use default symbols. Here is a + game uses; otherwise, the game will use default symbols. Here is a list of what the default symbols mean: - - The horizontal or corner walls of a room, or an open east/west + - The horizontal or corner walls of a room, or an open east/west door. - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -532,13 +532,13 @@ - | The vertical walls of a room, or an open north/south door, or a + | The vertical walls of a room, or an open north/south door, or a grave. - . The floor of a room, or ice, or a doorless doorway, or the span + . The floor of a room, or ice, or a doorless doorway, or the span of an open drawbridge. - # A corridor, or iron bars, or a tree, or the portcullis of a + # A corridor, or iron bars, or a tree, or the portcullis of a closed drawbridge. Note: engravings in corridors also appear as # but are shown in a @@ -548,7 +548,7 @@ < Stairs up: a way to the previous level. - + A closed door, or a spellbook containing a spell you may be able + + A closed door, or a spellbook containing a spell you may be able to learn. @ Your character or a human or an elf. @@ -579,8 +579,8 @@ ` A boulder or statue or an engraving on the floor of a room. - Note: statues are displayed as if they were the monsters they de- - pict so won't appear as a grave accent (aka back-tick). + Note: statues are displayed as if they were the monsters they + depict so won't appear as a grave accent (aka back-tick). 0 An iron ball. @@ -588,7 +588,7 @@ - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -610,51 +610,51 @@ A-HJ-Z and @&':; - Letters and certain other symbols represent the various inhabi- - tants of the Mazes of Menace. Watch out, they can be nasty and + Letters and certain other symbols represent the various inhabi- + tants of the Mazes of Menace. Watch out, they can be nasty and vicious. Sometimes, however, they can be helpful. I Rather than a specific type of monster, this marks the last known - location of an invisible or otherwise unseen monster. Note that + location of an invisible or otherwise unseen monster. Note that the monster could have moved. The `s', `F', and `m' commands may be useful here. - 1-5 The digits 1 through 5 may be displayed, marking unseen monsters - sensed via the Warning attribute. Less dangerous monsters are + 1-5 The digits 1 through 5 may be displayed, marking unseen monsters + sensed via the Warning attribute. Less dangerous monsters are indicated by lower values, more dangerous by higher values. - You need not memorize all these symbols; you can ask the game - what any symbol represents with the `/' command (see the next section + You need not memorize all these symbols; you can ask the game + what any symbol represents with the `/' command (see the next section for more info). 4. Commands - Commands can be initiated by typing one or two characters to - which the command is bound to, or typing the command name in the ex- - tended commands entry. Some commands, like "search", do not require - that any more information be collected by NetHack. Other commands - might require additional information, for example a direction, or an - object to be used. For those commands that require additional infor- + Commands can be initiated by typing one or two characters to + which the command is bound to, or typing the command name in the + extended commands entry. Some commands, like "search", do not require + that any more information be collected by NetHack. Other commands + might require additional information, for example a direction, or an + object to be used. For those commands that require additional infor- mation, NetHack will present you with either a menu of choices or with a command line prompt requesting information. Which you are presented with will depend chiefly on how you have set the menustyle option. - For example, a common question, in the form "What do you want to - use? [a-zA-Z ?*]", asks you to choose an object you are carrying. - Here, "a-zA-Z" are the inventory letters of your possible choices. - Typing `?' gives you an inventory list of these items, so you can see - what each letter refers to. In this example, there is also a `*' in- - dicating that you may choose an object not on the list, if you wanted - to use something unexpected. Typing a `*' lists your entire inven- - tory, so you can see the inventory letters of every object you're car- - rying. Finally, if you change your mind and decide you don't want to - do this command after all, you can press the ESC key to abort the com- - mand. + For example, a common question, in the form "What do you want to + use? [a-zA-Z ?*]", asks you to choose an object you are carrying. + Here, "a-zA-Z" are the inventory letters of your possible choices. + Typing `?' gives you an inventory list of these items, so you can see + what each letter refers to. In this example, there is also a `*' + indicating that you may choose an object not on the list, if you + wanted to use something unexpected. Typing a `*' lists your entire + inventory, so you can see the inventory letters of every object you're + carrying. Finally, if you change your mind and decide you don't want + to do this command after all, you can press the ESC key to abort the + command. - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -664,63 +664,63 @@ - You can put a number before some commands to repeat them that + You can put a number before some commands to repeat them that many times; for example, "10s" will search ten times. If you have the - number_pad option set, you must type `n' to prefix a count, so the ex- - ample above would be typed "n10s" instead. Commands for which counts - make no sense ignore them. In addition, movement commands can be pre- - fixed for greater control (see below). To cancel a count or a prefix, - press the ESC key. + number_pad option set, you must type `n' to prefix a count, so the + example above would be typed "n10s" instead. Commands for which + counts make no sense ignore them. In addition, movement commands can + be prefixed for greater control (see below). To cancel a count or a + prefix, press the ESC key. - The list of commands is rather long, but it can be read at any + The list of commands is rather long, but it can be read at any time during the game through the `?' command, which accesses a menu of helpful texts. Here are the default key bindings for your reference: ? Help menu: display one of several help texts available. - / The "whatis" command, to tell what a symbol represents. You may - choose to specify a location or type a symbol (or even a whole - word) to explain. Specifying a location is done by moving the - cursor to a particular spot on the map and then pressing one of + / The "whatis" command, to tell what a symbol represents. You may + choose to specify a location or type a symbol (or even a whole + word) to explain. Specifying a location is done by moving the + cursor to a particular spot on the map and then pressing one of `.', `,', `;', or `:'. `.' will explain the symbol at the chosen - location, conditionally check for "More info?" depending upon + location, conditionally check for "More info?" depending upon whether the help option is on, and then you will be asked to pick - another location; `,' will explain the symbol but skip any addi- - tional information, then let you pick another location; `;' will - skip additional info and also not bother asking you to choose an- - other location to examine; `:' will show additional info, if any, - without asking for confirmation. When picking a location, press- - ing the ESC key will terminate this command, or pressing `?' will - give a brief reminder about how it works. + another location; `,' will explain the symbol but skip any addi- + tional information, then let you pick another location; `;' will + skip additional info and also not bother asking you to choose + another location to examine; `:' will show additional info, if + any, without asking for confirmation. When picking a location, + pressing the ESC key will terminate this command, or pressing `?' + will give a brief reminder about how it works. If the autodescribe option is on, a short description of what you see at each location is shown as you move the cursor. Typing `#' - while picking a location will toggle that option on or off. The - whatis_coord option controls whether the short description in- - cludes map coordinates. + while picking a location will toggle that option on or off. The + whatis_coord option controls whether the short description + includes map coordinates. - Specifying a name rather than a location always gives any addi- + Specifying a name rather than a location always gives any addi- tional information available about that name. - You may also request a description of nearby monsters, all mon- - sters currently displayed, nearby objects, or all objects. The - whatis_coord option controls which format of map coordinate is + You may also request a description of nearby monsters, all mon- + sters currently displayed, nearby objects, or all objects. The + whatis_coord option controls which format of map coordinate is included with their descriptions. & Tell what a command does. - < Go up to the previous level (if you are on a staircase or lad- + < Go up to the previous level (if you are on a staircase or lad- der). > Go down to the next level (if you are on a staircase or ladder). [yuhjklbn] - Go one step in the direction indicated (see Figure 3). If you - sense or remember a monster there, you will fight the monster in- - stead. Only these one-step movement commands cause you to fight + Go one step in the direction indicated (see Figure 3). If you + sense or remember a monster there, you will fight the monster + instead. Only these one-step movement commands cause you to - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -730,7 +730,7 @@ - monsters; the others (below) are "safe." + fight monsters; the others (below) are "safe." +----------------------------------------------------------------+ | y k u 7 8 9 | | \ | / \ | / | @@ -748,27 +748,27 @@ remember a monster there). A few non-movement commands use the `m' prefix to request operat- - ing via menu (to temporarily override the menustyle:traditional - option). Primarily useful for `,' (pickup) when there is only - one class of objects present (where there won't be any "what - kinds of objects?" prompt, so no opportunity to answer `m' at + ing via menu (to temporarily override the menustyle:traditional + option). Primarily useful for `,' (pickup) when there is only + one class of objects present (where there won't be any "what + kinds of objects?" prompt, so no opportunity to answer `m' at that prompt). The prefix will make "#travel" command show a menu of interesting - targets in sight. It can also be used with the `\' (known, show + targets in sight. It can also be used with the `\' (known, show a list of all discovered objects) and the ``' (knownclass, show a - list of discovered objects in a particular class) commands to of- - fer a menu of several sorting alternatives (which sets a new + list of discovered objects in a particular class) commands to + offer a menu of several sorting alternatives (which sets a new value for the sortdiscoveries option); also for "#vanquished" and "#genocided" commands to offer a sorting menu. - A few other commands (eat food, offer sacrifice, apply tinning- - kit, drink/quaff, dip, tip container) use the `m' prefix to skip - checking for applicable objects on the floor and go straight to - checking inventory, or (for "#loot" to remove a saddle), skip + A few other commands (eat food, offer sacrifice, apply tinning- + kit, drink/quaff, dip, tip container) use the `m' prefix to skip + checking for applicable objects on the floor and go straight to + checking inventory, or (for "#loot" to remove a saddle), skip containers and go straight to adjacent monsters. - In debug mode (aka "wizard mode"), the `m' prefix may also be + In debug mode (aka "wizard mode"), the `m' prefix may also be used with the "#teleport" and "#wizlevelport" commands. F[yuhjklbn] @@ -778,15 +778,15 @@ Prefix: move until something interesting is found. G[yuhjklbn] or +[yuhjklbn] - Prefix: similar to `g', but forking of corridors is not consid- + Prefix: similar to `g', but forking of corridors is not consid- ered interesting. - Note: + means holding the or key - down like while typing and releasing , then releas- - ing . ^ is used as shorthand elsewhere in the + Note: + means holding the or key + down like while typing and releasing , then releas- + ing . ^ is used as shorthand elsewhere in the - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -796,39 +796,39 @@ - Guidebook to mean the same thing. Control characters are case- + Guidebook to mean the same thing. Control characters are case- insensitive so ^x and ^X are the same. M[yuhjklbn] - Old versions supported `M' as a movement prefix which combined - the effect of `m' with +. That is no longer + Old versions supported `M' as a movement prefix which combined + the effect of `m' with +. That is no longer supported as a prefix but similar effect can be achieved by using - `m' and G in combination. m can also be used in com- + `m' and G in combination. m can also be used in com- bination with g, +, or +. _ Travel to a map location via a shortest-path algorithm. - The shortest path is computed over map locations the hero knows - about (e.g. seen or previously traversed). If there is no known - path, a guess is made instead. Stops on most of the same condi- - tions as the `G' prefix, but without picking up objects, so im- - plicitly forces the `m' prefix. For ports with mouse support, - the command is also invoked when a mouse-click takes place on a + The shortest path is computed over map locations the hero knows + about (e.g. seen or previously traversed). If there is no known + path, a guess is made instead. Stops on most of the same condi- + tions as the `G' prefix, but without picking up objects, so + implicitly forces the `m' prefix. For ports with mouse support, + the command is also invoked when a mouse-click takes place on a location other than the current position. . Wait or rest, do nothing for one turn. Precede with the `m' pre- - fix to wait for a turn even next to a hostile monster, if + fix to wait for a turn even next to a hostile monster, if safe_wait is on. a Apply (use) a tool (pick-axe, key, lamp...). - If used on a wand, that wand will be broken, releasing its magic + If used on a wand, that wand will be broken, releasing its magic in the process. Confirmation is required. A Remove one or more worn items, such as armor. - Use `T' (take off) to take off only one piece of armor or `R' + Use `T' (take off) to take off only one piece of armor or `R' (remove) to take off only one accessory. ^A Repeat the previous command. @@ -852,7 +852,7 @@ - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -864,8 +864,8 @@ "What kinds of things do you want to drop? [!%= BUCXPaium]" - you should type zero or more object symbols possibly followed by - `a' and/or `i' and/or `u' and/or `m'. In addition, one or more + you should type zero or more object symbols possibly followed by + `a' and/or `i' and/or `u' and/or `m'. In addition, one or more of the blessed/uncursed/cursed groups may be typed. DB - drop all objects known to be blessed. @@ -879,22 +879,22 @@ Dm - use a menu to pick which object(s) to drop. D%u - drop only unpaid food. - The last example shows a combination. There are four categories + The last example shows a combination. There are four categories of object filtering: class (`!' for potions, `?' for scrolls, and so on), shop status (`u' for unpaid, in other words, owned by the shop), bless/curse state (`B', `U', `C', and `X' as shown above), and novelty (`P', recently picked up items; controlled by picking up or dropping things rather than by any time factor). - If you specify more than one value in a category (such as "!?" - for potions and scrolls or "BU" for blessed and uncursed), an in- - ventory object will meet the criteria if it matches any of the + If you specify more than one value in a category (such as "!?" + for potions and scrolls or "BU" for blessed and uncursed), an + inventory object will meet the criteria if it matches any of the specified values (so "!?" means `!' or `?'). If you specify more than one category, an inventory object must meet each of the cat- egory criteria (so "%u" means class `%' and unpaid `u'). Lastly, - you may specify multiple values within multiple categories: - "!?BU" will select all potions and scrolls which are known to be - blessed or uncursed. (In versions prior to 3.6, filter combina- + you may specify multiple values within multiple categories: + "!?BU" will select all potions and scrolls which are known to be + blessed or uncursed. (In versions prior to 3.6, filter combina- tions behaved differently.) ^D Kick something (usually a door). @@ -903,14 +903,14 @@ Normally checks for edible item(s) on the floor, then if none are found or none are chosen, checks for edible item(s) in inventory. - Precede `e' with the `m' prefix to bypass attempting to eat any- + Precede `e' with the `m' prefix to bypass attempting to eat any- thing off the floor. - If you attempt to eat while already satiated, you might choke to - death. If you risk it, you will be asked whether to "continue - eating?" if you survive the first bite. You can set the para- - noid_confirmation:eating option to require a response of yes in- - stead of just y. + If you attempt to eat while already satiated, you might choke to + death. If you risk it, you will be asked whether to "continue + eating?" if you survive the first bite. You can set the para- + noid_confirmation:eating option to require a response of yes + instead of just y. E Engrave a message on the floor. @@ -918,7 +918,7 @@ - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -928,29 +928,29 @@ - Engraving the word "Elbereth" will cause most monsters to not at- - tack you hand-to-hand (but if you attack, you will rub it out); + Engraving the word "Elbereth" will cause most monsters to not + attack you hand-to-hand (but if you attack, you will rub it out); this is often useful to give yourself a breather. - f Fire (shoot or throw) one of the objects placed in your quiver - (or quiver sack, or that you have at the ready). You may select - ammunition with a previous `Q' command, or let the computer pick - something appropriate if autoquiver is true. If your wielded - weapon has the throw-and-return property, your quiver is empty, - and autoquiver is false, you will throw that wielded weapon in- - stead of filling the quiver. This will also automatically use a - polearm if wielded. If fireassist is true, firing will automati- - cally try to wield a launcher (for example, a bow or a sling) - matching the ammo in the quiver; this might take multiple turns, - and get interrupted by a monster. Remember to swap back to your + f Fire (shoot or throw) one of the objects placed in your quiver + (or quiver sack, or that you have at the ready). You may select + ammunition with a previous `Q' command, or let the computer pick + something appropriate if autoquiver is true. If your wielded + weapon has the throw-and-return property, your quiver is empty, + and autoquiver is false, you will throw that wielded weapon + instead of filling the quiver. This will also automatically use + a polearm if wielded. If fireassist is true, firing will auto- + matically try to wield a launcher (for example, a bow or a sling) + matching the ammo in the quiver; this might take multiple turns, + and get interrupted by a monster. Remember to swap back to your main melee weapon afterwards. See also `t' (throw) for more general throwing and shooting. i List your inventory (everything you're carrying). - I List selected parts of your inventory, usually be specifying the - character for a particular set of objects, like `[' for armor or + I List selected parts of your inventory, usually be specifying the + character for a particular set of objects, like `[' for armor or `!' for potions. I* - list all gems in inventory; @@ -967,24 +967,24 @@ O Set options. - A menu showing the current option values will be displayed. You + A menu showing the current option values will be displayed. You can change most values simply by selecting the menu entry for the - given option (ie, by typing its letter or clicking upon it, de- - pending on your user interface). For the non-boolean choices, a - further menu or prompt will appear once you've closed this menu. - The available options are listed later in this Guidebook. Op- - tions are usually set before the game rather than with the `O' - command; see the section on options below. Precede `O' with the + given option (ie, by typing its letter or clicking upon it, + depending on your user interface). For the non-boolean choices, + a further menu or prompt will appear once you've closed this + menu. The available options are listed later in this Guidebook. + Options are usually set before the game rather than with the `O' + command; see the section on options below. Precede `O' with the `m' prefix to show advanced options. ^O Show overview. - Shortcut for "#overview": list interesting dungeon levels vis- + Shortcut for "#overview": list interesting dungeon levels vis- ited. - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -994,33 +994,33 @@ - (Prior to 3.6.0, `^O' was a debug mode command which listed the - placement of all special levels. Use "#wizwhere" to run that + (Prior to 3.6.0, `^O' was a debug mode command which listed the + placement of all special levels. Use "#wizwhere" to run that command.) p Pay your shopping bill. P Put on an accessory (ring, amulet, or blindfold). - This command may also be used to wear armor. The prompt for - which inventory item to use will only list accessories, but + This command may also be used to wear armor. The prompt for + which inventory item to use will only list accessories, but choosing an unlisted item of armor will attempt to wear it. (See - the `W' command below. It lists armor as the inventory choices + the `W' command below. It lists armor as the inventory choices but will accept an accessory and attempt to put that on.) ^P Repeat previous message. - Subsequent `^P's repeat earlier messages. For some interfaces, + Subsequent `^P's repeat earlier messages. For some interfaces, the behavior can be varied via the msg_window option. q Quaff (drink) something (potion, water, etc). - When there is a fountain or sink present, it asks whether to + When there is a fountain or sink present, it asks whether to drink from that. If that is declined, then it offers a chance to - choose a potion from inventory. Precede `q' with the `m' prefix + choose a potion from inventory. Precede `q' with the `m' prefix to skip asking about drinking from a fountain or sink. - Q Select an object for your quiver, quiver sack, or just generally + Q Select an object for your quiver, quiver sack, or just generally at the ready (only one of these is available at a time). You can then throw this (or one of these) using the `f' command. @@ -1033,24 +1033,24 @@ be removed without asking, but you can set the paranoid_confirma- tion:Remove option to require a prompt. - This command may also be used to take off armor. The prompt for - which inventory item to remove only lists worn accessories, but + This command may also be used to take off armor. The prompt for + which inventory item to remove only lists worn accessories, but an item of worn armor can be chosen. (See the `T' command below. It lists armor as the inventory choices but will accept an acces- sory and attempt to remove it.) ^R Redraw the screen. - s Search for secret doors and traps around you. It usually takes - several tries to find something. Precede with the `m' prefix to + s Search for secret doors and traps around you. It usually takes + several tries to find something. Precede with the `m' prefix to search for a turn even next to a hostile monster, if safe_wait is on. - Can also be used to figure out whether there is still a monster + Can also be used to figure out whether there is still a monster at an adjacent "remembered, unseen monster" marker. - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -1060,26 +1060,26 @@ - S Save the game (which suspends play and exits the program). The - saved game will be restored automatically the next time you play + S Save the game (which suspends play and exits the program). The + saved game will be restored automatically the next time you play using the same character name. - In normal play, once a saved game is restored the file used to - hold the saved data is deleted. In explore mode, once restora- - tion is accomplished you are asked whether to keep or delete the - file. Keeping the file makes it feasible to play for a while + In normal play, once a saved game is restored the file used to + hold the saved data is deleted. In explore mode, once restora- + tion is accomplished you are asked whether to keep or delete the + file. Keeping the file makes it feasible to play for a while then quit without saving and later restore again. - There is no "save current game state and keep playing" command, - not even in explore mode where saved game files can be kept and + There is no "save current game state and keep playing" command, + not even in explore mode where saved game files can be kept and re-used. t Throw an object or shoot a projectile. There's no separate "shoot" command. If you throw an arrow while - wielding a bow, you are shooting that arrow and any weapon skill - bonus or penalty for bow applies. If you throw an arrow while - not wielding a bow, you are throwing it by hand and it will gen- + wielding a bow, you are shooting that arrow and any weapon skill + bonus or penalty for bow applies. If you throw an arrow while + not wielding a bow, you are throwing it by hand and it will gen- erally be less effective than when shot. See also `f' (fire) for throwing or shooting an item pre-selected @@ -1087,17 +1087,17 @@ T Take off armor. - If you're wearing more than one piece, you'll be prompted for + If you're wearing more than one piece, you'll be prompted for which one to take off. (Note that this treats a cloak covering a suit and/or a shirt, or a suit covering a shirt, as if the under- - lying items weren't there.) When you're only wearing one, then - by default it will be taken off without asking, but you can set + lying items weren't there.) When you're only wearing one, then + by default it will be taken off without asking, but you can set the paranoid_confirmation:Remove option to require a prompt. - This command may also be used to remove accessories. The prompt + This command may also be used to remove accessories. The prompt for which inventory item to take off only lists worn armor, but a - worn accessory can be chosen. (See the `R' command above. It - lists accessories as the inventory choices but will accept an + worn accessory can be chosen. (See the `R' command above. It + lists accessories as the inventory choices but will accept an item of armor and attempt to take it off.) ^T Teleport, if you have the ability. @@ -1110,13 +1110,13 @@ w- - wield nothing, use your bare (or gloved) hands. - Some characters can wield two weapons at once; use the `X' com- + Some characters can wield two weapons at once; use the `X' com- mand (or the "#twoweapon" extended command) to do so. - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -1128,38 +1128,38 @@ W Wear armor. - This command may also be used to put on an accessory (ring, - amulet, or blindfold). The prompt for which inventory item to + This command may also be used to put on an accessory (ring, + amulet, or blindfold). The prompt for which inventory item to use will only list armor, but choosing an unlisted accessory will - attempt to put it on. (See the `P' command above. It lists ac- - cessories as the inventory choices but will accept an item of ar- - mor and attempt to wear it.) + attempt to put it on. (See the `P' command above. It lists + accessories as the inventory choices but will accept an item of + armor and attempt to wear it.) - x Exchange your wielded weapon with the item in your alternate + x Exchange your wielded weapon with the item in your alternate weapon slot. The latter is used as your secondary weapon when engaging in two- - weapon combat. Note that if one of these slots is empty, the ex- - change still takes place. + weapon combat. Note that if one of these slots is empty, the + exchange still takes place. - X Toggle two-weapon combat, if your character can do it. Also + X Toggle two-weapon combat, if your character can do it. Also available via the "#twoweapon" extended command. - (In versions prior to 3.6 this keystroke ran the command to + (In versions prior to 3.6 this keystroke ran the command to switch from normal play to "explore mode", also known as "discov- ery mode", which has now been moved to "#exploremode" and M-X.) ^X Display basic information about your character. - Displays name, role, race, gender (unless role name makes that - redundant, such as Caveman or Priestess), and alignment, along - with your patron deity and his or her opposition. It also shows - most of the various items of information from the status line(s) - in a less terse form, including several additional things which + Displays name, role, race, gender (unless role name makes that + redundant, such as Caveman or Priestess), and alignment, along + with your patron deity and his or her opposition. It also shows + most of the various items of information from the status line(s) + in a less terse form, including several additional things which don't appear in the normal status display due to space considera- tions. - In normal play, that's all that `^X' displays. In explore mode, + In normal play, that's all that `^X' displays. In explore mode, the role and status feedback is augmented by the information pro- vided by enlightenment magic. @@ -1171,7 +1171,7 @@ Z. - to cast at yourself, use `.' for the direction. - ^Z Suspend the game (UNIX(R) versions with job control only). See + ^Z Suspend the game (UNIX(R) versions with job control only). See "#suspend" below for more details. : Look at what is here. @@ -1182,7 +1182,7 @@ (R)UNIX is a registered trademark of The Open Group. - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -1221,15 +1221,15 @@ + List the spells you know. - Using this command, you can also rearrange the order in which - your spells are listed, either by sorting the entire list or by - picking one spell from the menu then picking another to swap - places with it. Swapping pairs of spells changes their casting - letters, so the change lasts after the current `+' command fin- - ishes. Sorting the whole list is temporary. To make the most - recent sort order persist beyond the current `+' command, choose - the sort option again and then pick "reassign casting letters". - (Any spells learned after that will be added to the end of the + Using this command, you can also rearrange the order in which + your spells are listed, either by sorting the entire list or by + picking one spell from the menu then picking another to swap + places with it. Swapping pairs of spells changes their casting + letters, so the change lasts after the current `+' command fin- + ishes. Sorting the whole list is temporary. To make the most + recent sort order persist beyond the current `+' command, choose + the sort option again and then pick "reassign casting letters". + (Any spells learned after that will be added to the end of the list rather than be inserted into the sorted ordering.) \ Show what types of objects have been discovered. @@ -1240,15 +1240,15 @@ May be preceded by `m' to select preferred display order. - | If persistent inventory display is supported and enabled (with - the perm_invent option), interact with it instead of with the + | If persistent inventory display is supported and enabled (with + the perm_invent option), interact with it instead of with the map. - Allows scrolling with the menu_first_page, menu_previous_page, - menu_next_page, and menu_last_page keys (`^', `<', `>', `|' by + Allows scrolling with the menu_first_page, menu_previous_page, + menu_next_page, and menu_last_page keys (`^', `<', `>', `|' by - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -1259,7 +1259,7 @@ default). Some interfaces also support menu_shift_left and - menu_shift_right keys (`{' and `}' by default). Use the Return + menu_shift_right keys (`{' and `}' by default). Use the Return (aka Enter) or Escape key to resume play. ! Escape to a shell. See "#shell" below for more details. @@ -1268,53 +1268,53 @@ of the current level's map without monsters; without monsters and objects; or without monsters, objects, and traps. - The key is also shown as on some keyboards or - on others. It is sometimes displayed as ^? even though + The key is also shown as on some keyboards or + on others. It is sometimes displayed as ^? even though that is not an actual control character. - Many terminals have an option to swap the and - keys, so typing the key might not execute this - command. If that happens, you can use the extended command + Many terminals have an option to swap the and + keys, so typing the key might not execute this + command. If that happens, you can use the extended command "#terrain" instead. # Perform an extended command. - As you can see, the authors of NetHack used up all the letters, + As you can see, the authors of NetHack used up all the letters, so this is a way to introduce the less frequently used commands. What - extended commands are available depends on what features the game was + extended commands are available depends on what features the game was compiled with. #adjust - Adjust inventory letters (most useful when the fixinv option is + Adjust inventory letters (most useful when the fixinv option is "on"). Autocompletes. Default key is `M-a'. - This command allows you to move an item from one particular in- - ventory slot to another so that it has a letter which is more - meaningful for you or that it will appear in a particular loca- - tion when inventory listings are displayed. You can move to a - currently empty slot, or if the destination is occupied--and - won't merge--the item there will swap slots with the one being - moved. "#adjust" can also be used to split a stack of objects; + This command allows you to move an item from one particular + inventory slot to another so that it has a letter which is more + meaningful for you or that it will appear in a particular loca- + tion when inventory listings are displayed. You can move to a + currently empty slot, or if the destination is occupied--and + won't merge--the item there will swap slots with the one being + moved. "#adjust" can also be used to split a stack of objects; when choosing the item to adjust, enter a count prior to its let- ter. - Adjusting without a count used to collect all compatible stacks - when moving to the destination. That behavior has been changed; - to gather compatible stacks, "#adjust" a stack into its own in- - ventory slot. If it has a name assigned, other stacks with the - same name or with no name will merge provided that all their - other attributes match. If it does not have a name, only other + Adjusting without a count used to collect all compatible stacks + when moving to the destination. That behavior has been changed; + to gather compatible stacks, "#adjust" a stack into its own + inventory slot. If it has a name assigned, other stacks with the + same name or with no name will merge provided that all their + other attributes match. If it does not have a name, only other stacks with no name are eligible. In either case, otherwise com- - patible stacks with a different name will not be merged. This + patible stacks with a different name will not be merged. This contrasts with using "#adjust" to move from one slot to a differ- - ent slot. In that situation, moving (no count given) a compati- - ble stack will merge if either stack has a name when the other - doesn't and give that name to the result, while splitting (count + ent slot. In that situation, moving (no count given) a compati- + ble stack will merge if either stack has a name when the other + doesn't and give that name to the result, while splitting (count - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -1324,13 +1324,13 @@ - given) will ignore the source stack's name when deciding whether + given) will ignore the source stack's name when deciding whether to merge with the destination stack. #annotate Allows you to specify one line of text to associate with the cur- rent dungeon level. All levels with annotations are displayed by - the "#overview" command. Autocompletes. Default key is `M-A', + the "#overview" command. Autocompletes. Default key is `M-A', and also `^N' if number_pad is on. #apply @@ -1340,7 +1340,7 @@ If the tool used acts on items on the floor, using the `m' prefix skips those items. - If used on a wand, that wand will be broken, releasing its magic + If used on a wand, that wand will be broken, releasing its magic in the process. Confirmation is required. #attributes @@ -1350,14 +1350,14 @@ Toggle the autopickup option on/off. Default key is `@'. #bugreport - Bring up a browser window to submit a report to the NetHack De- - velopment Team. Can be disabled at the time the program is - built; when enabled, CRASHREPORTURL must be set in the system + Bring up a browser window to submit a report to the NetHack + Development Team. Can be disabled at the time the program is + built; when enabled, CRASHREPORTURL must be set in the system configuration file. #call - Call (name) a monster, or an object in inventory, on the floor, - or in the discoveries list, or add an annotation for the current + Call (name) a monster, or an object in inventory, on the floor, + or in the discoveries list, or add an annotation for the current level (same as "#annotate"). Default key is `C'. #cast @@ -1373,14 +1373,14 @@ Close a door. Default key is `c'. #conduct - List voluntary challenges you have maintained. Autocompletes. + List voluntary challenges you have maintained. Autocompletes. Default key is `M-C'. See the section below entitled "Conduct" for details. - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -1397,7 +1397,7 @@ Dip an object into something. Autocompletes. Default key is `M- d'. - The `m' prefix skips dipping into a fountain or pool if there is + The `m' prefix skips dipping into a fountain or pool if there is one at your location. #down @@ -1410,24 +1410,24 @@ Drop specific item types. Default key is `D'. #eat - Eat something. Default key is `e'. The `m' prefix skips eating + Eat something. Default key is `e'. The `m' prefix skips eating items on the floor. #engrave Engrave writing on the floor. Default key is `E'. #enhance - Advance or check weapon and spell skills. Autocompletes. De- - fault key is `M-e'. + Advance or check weapon and spell skills. Autocompletes. + Default key is `M-e'. #exploremode Switch from normal play to non-scoring explore mode. Default key is `M-X'. - Requires confirmation; default response is n (no). To really - switch to explore mode, respond with y. You can set the para- - noid_confirmation:quit option to require a response of yes in- - stead. + Requires confirmation; default response is n (no). To really + switch to explore mode, respond with y. You can set the para- + noid_confirmation:quit option to require a response of yes + instead. #fight Prefix key to force fight a direction, even if you see nothing to @@ -1441,12 +1441,12 @@ Force a lock. Autocompletes. Default key is `M-f'. #genocided - List any monster types which have been genocided. In explore - mode and debug mode it also shows types which have become ex- - tinct. + List any monster types which have been genocided. In explore + mode and debug mode it also shows types which have become + extinct. - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -1457,14 +1457,14 @@ The display order is the same as is used by #vanquished. The `m' - prefix brings up a menu of available sorting orders, and doing - that for either #genocided or #vanquished changes the order for + prefix brings up a menu of available sorting orders, and doing + that for either #genocided or #vanquished changes the order for both. - If the sorting order is "count high to low" or "count low to - high" (which are applicable for #vanquished), that will be ig- - nored for #genocided and alphabetical will be used instead. The - menu omits those two choices when used for #genocide. + If the sorting order is "count high to low" or "count low to + high" (which are applicable for #vanquished), that will be + ignored for #genocided and alphabetical will be used instead. + The menu omits those two choices when used for #genocide. Autocompletes. Default key is `M-g'. @@ -1473,16 +1473,16 @@ is `;'. #help - Show the help menu. Default key is `?', and also `h' if num- + Show the help menu. Default key is `?', and also `h' if num- ber_pad is on. #herecmdmenu - Show a menu of possible actions directed at your current loca- - tion. The menu is limited to a subset of the likeliest actions, + Show a menu of possible actions directed at your current loca- + tion. The menu is limited to a subset of the likeliest actions, not an exhaustive set of all possibilities. Autocompletes. - If mouse support is enabled and the herecmd_menu option is On, - clicking on the hero (or steed when mounted) will execute this + If mouse support is enabled and the herecmd_menu option is On, + clicking on the hero (or steed when mounted) will execute this command. #history @@ -1495,15 +1495,15 @@ Inventory specific item types. Default key is `I'. #invoke - Invoke an object's special powers. Autocompletes. Default key + Invoke an object's special powers. Autocompletes. Default key is `M-i'. #jump - Jump to another location. Autocompletes. Default key is `M-j', + Jump to another location. Autocompletes. Default key is `M-j', and also `j' if number_pad is on. #kick - Kick something. Default key is `^D', and `k' if number_pad is + Kick something. Default key is `^D', and `k' if number_pad is on. #known @@ -1512,7 +1512,7 @@ - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -1522,12 +1522,12 @@ - The `m' prefix allows assigning a new value to the sortdiscover- + The `m' prefix allows assigning a new value to the sortdiscover- ies option to control the order in which the discoveries are dis- played. #knownclass - Show discovered types for one class of objects. Default key is + Show discovered types for one class of objects. Default key is ``'. The `m' prefix operates the same as for "#known". @@ -1545,26 +1545,26 @@ Describe what you can see, or remember, of your surroundings. #loot - Loot a box or bag on the floor beneath you, or the saddle from a + Loot a box or bag on the floor beneath you, or the saddle from a steed standing next to you. Autocompletes. Precede with the `m' - prefix to skip containers at your location and go directly to re- - moving a saddle. Default key is `M-l', and also `l' if num- + prefix to skip containers at your location and go directly to + removing a saddle. Default key is `M-l', and also `l' if num- ber_pad is on. #monster - Use a monster's special ability (when polymorphed into monster + Use a monster's special ability (when polymorphed into monster form). Autocompletes. Default key is `M-m'. #name - Name a monster, an individual object, or a type of object. Same + Name a monster, an individual object, or a type of object. Same as "#call". Autocompletes. Default keys are `N', `M-n', and `M- N'. #offer - Offer a sacrifice to the gods. Autocompletes. Default key is + Offer a sacrifice to the gods. Autocompletes. Default key is `M-o'. - You'll need to find an altar to have any chance at success. + You'll need to find an altar to have any chance at success. Corpses of recently killed monsters are the fodder of choice. The `m' prefix skips offering any items which are on the altar. @@ -1573,12 +1573,12 @@ Open a door. Default key is `o'. #options - Show and change option settings. Default key is `O'. Precede + Show and change option settings. Default key is `O'. Precede with the `m' prefix to show advanced options. - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -1589,32 +1589,32 @@ #optionsfull - Show advanced game option settings. No default key. Precede - with the `m' prefix to execute the simpler options command. - (Mainly useful if you use BINDING=O:optionsfull to switch `O' + Show advanced game option settings. No default key. Precede + with the `m' prefix to execute the simpler options command. + (Mainly useful if you use BINDING=O:optionsfull to switch `O' from simple options back to traditional advanced options.) #overview - Display information you've discovered about the dungeon. Any - visited level with an annotation is included, and many things - (altars, thrones, fountains, and so on; extra stairs leading to + Display information you've discovered about the dungeon. Any + visited level with an annotation is included, and many things + (altars, thrones, fountains, and so on; extra stairs leading to another dungeon branch) trigger an automatic annotation. If dun- geon overview is chosen during end-of-game disclosure, every vis- ited level will be included regardless of annotations. - Precede #overview with the `m' prefix to display the dungeon - overview as a menu where you can select any visited level to add - or remove an annotation without needing to return to that level. - This will also force all visited levels to be displayed rather + Precede #overview with the `m' prefix to display the dungeon + overview as a menu where you can select any visited level to add + or remove an annotation without needing to return to that level. + This will also force all visited levels to be displayed rather than just the "interesting" subset. Autocompletes. Default keys are `^O', and `M-O'. #panic - Test the panic routine. Terminates the current game. Autocom- + Test the panic routine. Terminates the current game. Autocom- pletes. Debug mode only. - Asks for confirmation; default is n (no); continue playing. To + Asks for confirmation; default is n (no); continue playing. To really panic, respond with y. You can set the paranoid_confirma- tion:quit option to require a response of yes instead. @@ -1622,11 +1622,11 @@ Pay your shopping bill. Default key is `p'. #perminv - If persistent inventory display is supported and enabled (with - the perm_invent option), interact with it instead of with the - map. You'll be prompted for menu scrolling keystrokes such as - `>' and `<'. Press Return or Escape to resume normal play. De- - fault key is `|'. + If persistent inventory display is supported and enabled (with + the perm_invent option), interact with it instead of with the + map. You'll be prompted for menu scrolling keystrokes such as + `>' and `<'. Press Return or Escape to resume normal play. + Default key is `|'. #pickup Pick up things at the current location. Default key is `,'. The @@ -1638,13 +1638,13 @@ #pray Pray to the gods for help. Autocompletes. Default key is `M-p'. - Praying too soon after receiving prior help is a bad idea. - (Hint: entering the dungeon alive is treated as having received - help. You probably shouldn't start off a new game by praying - right away.) Since using this command by accident can cause + Praying too soon after receiving prior help is a bad idea. + (Hint: entering the dungeon alive is treated as having received + help. You probably shouldn't start off a new game by praying + right away.) Since using this command by accident can cause - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -1654,8 +1654,8 @@ - trouble, there is an option to make you confirm your intent be- - fore praying. It is enabled by default, and you can reset the + trouble, there is an option to make you confirm your intent + before praying. It is enabled by default, and you can reset the paranoid_confirmation option to disable it. #prevmsg @@ -1674,20 +1674,20 @@ Quit the program without saving your game. Autocompletes. Since using this command by accident would throw away the current - game, you are asked to confirm your intent before quitting. De- - fault response is n (no); continue playing. To really quit, re- - spond with y. You can set the paranoid_confirmation:quit option - to require a response of yes instead. + game, you are asked to confirm your intent before quitting. + Default response is n (no); continue playing. To really quit, + respond with y. You can set the paranoid_confirmation:quit + option to require a response of yes instead. #quiver Select ammunition for quiver. Default key is `Q'. #read - Read a scroll, a spellbook, or something else. Default key is + Read a scroll, a spellbook, or something else. Default key is `r'. #redraw - Redraw the screen. Default key is `^R', and also `^L' if num- + Redraw the screen. Default key is `^R', and also `^L' if num- ber_pad is on. #remove @@ -1697,20 +1697,20 @@ Repeat the previous command. Default key is `^A'. #reqmenu - Prefix key to modify the behavior or request menu from some com- - mands. Prevents autopickup when used with movement commands. + Prefix key to modify the behavior or request menu from some com- + mands. Prevents autopickup when used with movement commands. Default key is `m'. #retravel - Travel to a previously selected travel destination. Default key + Travel to a previously selected travel destination. Default key is `C-_'. See also #travel. #ride - Ride (or stop riding) a saddled creature. Autocompletes. De- - fault key is `M-R'. + Ride (or stop riding) a saddled creature. Autocompletes. + Default key is `M-R'. - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -1724,8 +1724,8 @@ Rub a lamp or a stone. Autocompletes. Default key is `M-r'. #run - Prefix key to run towards a direction. Default key is `G' when - number_pad is off, `5' when number_pad is set to 1 or 3, other- + Prefix key to run towards a direction. Default key is `G' when + number_pad is off, `5' when number_pad is set to 1 or 3, other- wise `M-5' when it is set to 2 or 4. #rush @@ -1737,12 +1737,12 @@ Save the game and exit the program. Default key is `S'. #saveoptions - Save configuration options to the config file. This will over- - write the file, removing all comments, so if you have manually + Save configuration options to the config file. This will over- + write the file, removing all comments, so if you have manually edited the config file, don't use this. #search - Search for traps and secret doors around you. Default key is + Search for traps and secret doors around you. Default key is `s'. #seeall @@ -1759,24 +1759,24 @@ #seearmor Show the armor currently worn. Default key is `['. - Will display worn armor in a menu even when there is only thing + Will display worn armor in a menu even when there is only thing worn. #seerings Show the ring(s) currently worn. Default key is `='. - Will display worn rings in a menu if there are two (or there is - just one and is a meat ring rather than a "real" ring). Use the + Will display worn rings in a menu if there are two (or there is + just one and is a meat ring rather than a "real" ring). Use the `m' prefix to force a menu for one ring. #seetools Show the tools currently in use. Default key is `('. - Will display the result in a message if there is one tool in use + Will display the result in a message if there is one tool in use (worn blindfold or towel or lenses, lit lamp(s) and/or candle(s), - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -1792,32 +1792,32 @@ #seeweapon Show the weapon currently wielded. Default key is `)'. - If dual-wielding, a separate message about the secondary weapon - will be given. Using the `m' prefix will force a menu and it + If dual-wielding, a separate message about the secondary weapon + will be given. Using the `m' prefix will force a menu and it will include primary weapon, alternate weapon even when not dual- - wielding, and also whatever is currently assigned to the quiver + wielding, and also whatever is currently assigned to the quiver slot. #shell - Do a shell escape, switching from NetHack to a subprocess. Can - be disabled at the time the program is built. When enabled, ac- - cess for specific users can be controlled by the system configu- - ration file. Use the shell command `exit' to return to the game. - Default key is `!'. + Do a shell escape, switching from NetHack to a subprocess. Can + be disabled at the time the program is built. When enabled, + access for specific users can be controlled by the system config- + uration file. Use the shell command `exit' to return to the + game. Default key is `!'. #showgold - Report the gold in your inventory, including gold you know about - in containers you're carrying. If you are inside a shop, report + Report the gold in your inventory, including gold you know about + in containers you're carrying. If you are inside a shop, report any credit or debt you have in that shop. Default key is `$'. #showspells List and reorder known spells. Default key is `+'. #showtrap - Describe an adjacent trap, possibly covered by objects or a mon- + Describe an adjacent trap, possibly covered by objects or a mon- ster. To be eligible, the trap must already be discovered. (The "#terrain" command can display your map with all objects and mon- - sters temporarily removed, making it possible to see all discov- + sters temporarily removed, making it possible to see all discov- ered traps.) Default key is `^'. #sit @@ -1827,10 +1827,10 @@ Show memory usage statistics. Autocompletes. Debug mode only. #suspend - Suspend the game, switching from NetHack to the terminal it was - started from without performing save-and-exit. Can be disabled - at the time the program is built. When enabled, mainly useful - for tty and curses interfaces on UNIX. Use the shell command + Suspend the game, switching from NetHack to the terminal it was + started from without performing save-and-exit. Can be disabled + at the time the program is built. When enabled, mainly useful + for tty and curses interfaces on UNIX. Use the shell command `fg' to return to the game. Default key is `^Z'. #swap @@ -1842,7 +1842,7 @@ - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -1859,25 +1859,25 @@ Teleport around the level. Default key is `^T'. #terrain - Show map without obstructions. In normal play you can view the - explored portion of the current level's map without monsters; - without monsters and objects; or without monsters, objects, and + Show map without obstructions. In normal play you can view the + explored portion of the current level's map without monsters; + without monsters and objects; or without monsters, objects, and traps. If there are visible clouds of gas in view, they are treated like - traps when deciding whether to show them or the floor underneath + traps when deciding whether to show them or the floor underneath them. - In explore mode, you can choose to view the full map rather than - just its explored portion. In debug mode there are additional + In explore mode, you can choose to view the full map rather than + just its explored portion. In debug mode there are additional choices. - Autocompletes. Default key is `' or `' (see Del + Autocompletes. Default key is `' or `' (see Del above). #therecmdmenu - Show a menu of possible actions directed at a location next to - you. The menu is limited to a subset of the likeliest actions, + Show a menu of possible actions directed at a location next to + you. The menu is limited to a subset of the likeliest actions, not an exhaustive set of all possibilities. Autocompletes. #throw @@ -1888,27 +1888,27 @@ #tip Tip over a container (bag or box) to pour out its contents. When - there are containers on the floor, the game will prompt to pick - one of them or "tip something being carried". If the latter is - chosen, there will be another prompt for which item from inven- + there are containers on the floor, the game will prompt to pick + one of them or "tip something being carried". If the latter is + chosen, there will be another prompt for which item from inven- tory to tip. The `m' prefix makes the command skip containers on the floor and - pick one from inventory, except for the special case of - menustyle:traditional with two or more containers present; that + pick one from inventory, except for the special case of + menustyle:traditional with two or more containers present; that situation will start with the floor container menu. Autocompletes. Default key is `M-T'. #travel - Travel to a specific location on the map. Default key is `_'. - Using the "request menu" prefix shows a menu of interesting tar- - gets in sight without asking to move the cursor. When picking a - target with cursor and the autodescribe option is on, the top + Travel to a specific location on the map. Default key is `_'. + Using the "request menu" prefix shows a menu of interesting tar- + gets in sight without asking to move the cursor. When picking a + target with cursor and the autodescribe option is on, the top line will show "(no travel path)" if your character does not know - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -1924,17 +1924,17 @@ Turn undead away. Autocompletes. Default key is `M-t'. #twoweapon - Toggle two-weapon combat on or off. Autocompletes. Default key + Toggle two-weapon combat on or off. Autocompletes. Default key is `X', and also `M-2' if number_pad is off. - Note that you must use suitable weapons for this type of combat, + Note that you must use suitable weapons for this type of combat, or it will be automatically turned off. #untrap - Untrap something (trap, door, or chest). Default key is `M-u', + Untrap something (trap, door, or chest). Default key is `M-u', and `u' if number_pad is on. - In some circumstances it can also be used to rescue trapped mon- + In some circumstances it can also be used to rescue trapped mon- sters. #up @@ -1943,21 +1943,21 @@ #vanquished List vanquished monsters by type and count. - Note that the vanquished monsters list includes all monsters - killed by traps and each other as well as by you, and omits any - which got removed from the game without being killed (perhaps by - genocide, or by a mollified shopkeeper dismissing summoned Kops) + Note that the vanquished monsters list includes all monsters + killed by traps and each other as well as by you, and omits any + which got removed from the game without being killed (perhaps by + genocide, or by a mollified shopkeeper dismissing summoned Kops) or were already corpses when placed on the map. - Using the "request menu" prefix prior to #vanquished brings up a - menu of sorting orders available (provided that the vanquished - monsters list contains at least two types of monsters). Which- - ever ordering is picked gets assigned to the sortvanquished op- - tion so is remembered for subsequent #vanquished requests. The + Using the "request menu" prefix prior to #vanquished brings up a + menu of sorting orders available (provided that the vanquished + monsters list contains at least two types of monsters). Which- + ever ordering is picked gets assigned to the sortvanquished + option so is remembered for subsequent #vanquished requests. The "#genocided" command shares this sorting order. - During end-of-game disclosure, when asked whether to show van- - quished monsters answering `a' will let you choose from the sort + During end-of-game disclosure, when asked whether to show van- + quished monsters answering `a' will let you choose from the sort menu. Autocompletes. Default key is `M-V'. @@ -1965,16 +1965,16 @@ #version Print compile time options for this version of NetHack. - The second paragraph lists the user interface(s) that are in- - cluded. If there are more than one, you can use the windowtype - option in your run-time configuration file to select the one you + The second paragraph lists the user interface(s) that are + included. If there are more than one, you can use the windowtype + option in your run-time configuration file to select the one you want. Autocompletes. Default key is `M-v'. - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -1985,15 +1985,15 @@ #versionshort - Show the program's version number, plus the date and time that - the running copy was built from sources (not the version's re- - lease date). Default key is `v'. + Show the program's version number, plus the date and time that + the running copy was built from sources (not the version's + release date). Default key is `v'. #vision Show vision array. Autocompletes. Debug mode only. #wait - Rest one move while doing nothing. Default key is `.', and also + Rest one move while doing nothing. Default key is `.', and also ` ' if rest_on_space is on. #wear @@ -2003,7 +2003,7 @@ Tell what a key does. Default key is `&'. #whatis - Show what type of thing a symbol corresponds to. Default key is + Show what type of thing a symbol corresponds to. Default key is `/'. #wield @@ -2013,19 +2013,19 @@ Wipe off your face. Autocompletes. Default key is `M-w'. #wizborn - Show monster birth, death, genocide, and extinct statistics. De- - bug mode only. + Show monster birth, death, genocide, and extinct statistics. + Debug mode only. #wizbury - Bury objects under and around you. Autocompletes. Debug mode + Bury objects under and around you. Autocompletes. Debug mode only. #wizcast Cast any spell. Debug mode only. #wizdetect - Reveal hidden things (secret doors or traps or unseen monsters) - within a modest radius. No time elapses. Autocompletes. Debug + Reveal hidden things (secret doors or traps or unseen monsters) + within a modest radius. No time elapses. Autocompletes. Debug mode only. Default key is `^E'. #wizgenesis @@ -2033,14 +2033,14 @@ one. Autocompletes. Debug mode only. Default key is `^G'. #wizidentify - Identify all items in inventory. Autocompletes. Debug mode + Identify all items in inventory. Autocompletes. Debug mode only. Default key is `^I'. #wizintrinsic Set one or more intrinsic attributes. Autocompletes. Debug mode - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -2053,41 +2053,41 @@ only. #wizkill - Remove monsters from play by just pointing at them. By default - the hero gets credit or blame for killing the targets. Precede - this command with the `m' prefix to override that. Autocom- + Remove monsters from play by just pointing at them. By default + the hero gets credit or blame for killing the targets. Precede + this command with the `m' prefix to override that. Autocom- pletes. Debug mode only. #wizlevelport - Teleport to another level. Autocompletes. Debug mode only. De- - fault key is `^V'. + Teleport to another level. Autocompletes. Debug mode only. + Default key is `^V'. #wizmap - Map the level. Autocompletes. Debug mode only. Default key is + Map the level. Autocompletes. Debug mode only. Default key is `^F'. #wizrumorcheck - Verify rumor boundaries by displaying first and last true rumors + Verify rumor boundaries by displaying first and last true rumors and first and last false rumors. - Also displays first, second, and last random engravings, epi- + Also displays first, second, and last random engravings, epi- taphs, and hallucinatory monsters. Autocompletes. Debug mode only. #wizseenv - Show map locations' seen vectors. Autocompletes. Debug mode + Show map locations' seen vectors. Autocompletes. Debug mode only. #wizsmell Smell monster. Autocompletes. Debug mode only. #wizwhere - Show locations of special levels. Autocompletes. Debug mode + Show locations of special levels. Autocompletes. Debug mode only. #wizwish - Wish for something. Autocompletes. Debug mode only. Default + Wish for something. Autocompletes. Debug mode only. Default key is `^W'. #wmode @@ -2101,12 +2101,12 @@ - If your keyboard has a meta key (which, when pressed in combina- - tion with another key, modifies it by setting the "meta" [8th, or - "high"] bit), you can invoke many extended commands by meta-ing the + If your keyboard has a meta key (which, when pressed in combina- + tion with another key, modifies it by setting the "meta" [8th, or + "high"] bit), you can invoke many extended commands by meta-ing the - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -2119,17 +2119,17 @@ first letter of the command. On Windows and MS-DOS, the "Alt" key can be used in this fashion. - On other systems, if typing "Alt" plus another key transmits a two - character sequence consisting of an Escape followed by the other key, - you may set the altmeta option to have NetHack combine them into - meta+. (This combining action only takes place when NetHack is + On other systems, if typing "Alt" plus another key transmits a two + character sequence consisting of an Escape followed by the other key, + you may set the altmeta option to have NetHack combine them into + meta+. (This combining action only takes place when NetHack is expecting a command to execute, not when accepting input to name some- thing or to make a wish.) Unlike control characters, where ^x and ^X denote the same thing, - meta characters are case-sensitive: M-x and M-X represent different - things. Some commands which can be run via a meta character require - that the letter be capitalized because the lower-case equivalent is + meta characters are case-sensitive: M-x and M-X represent different + things. Some commands which can be run via a meta character require + that the letter be capitalized because the lower-case equivalent is used for another command, so the three key combination meta+Shift+ is needed. @@ -2172,7 +2172,7 @@ - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -2238,7 +2238,7 @@ - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -2252,7 +2252,7 @@ - If the number_pad option is on, some additional letter commands + If the number_pad option is on, some additional letter commands are available: h #help @@ -2304,7 +2304,7 @@ - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -2316,61 +2316,61 @@ 5. Rooms and corridors - Rooms and corridors in the dungeon are either lit or dark. Any - lit areas within your line of sight will be displayed; dark areas are - only displayed if they are within one space of you. Walls and corri- + Rooms and corridors in the dungeon are either lit or dark. Any + lit areas within your line of sight will be displayed; dark areas are + only displayed if they are within one space of you. Walls and corri- dors remain on the map as you explore them. Secret corridors are hidden and appear to be solid rock. You can find them with the `s' (search) command when adjacent to them. Multi- - ple search attempts may be needed. When searching is successful, se- - cret corridors become ordinary open corridor locations. Mapping magic - reveals secret corridors, so converts them into ordinary corridors and - shows them as such. + ple search attempts may be needed. When searching is successful, + secret corridors become ordinary open corridor locations. Mapping + magic reveals secret corridors, so converts them into ordinary corri- + dors and shows them as such. 5.1. Doorways - Doorways connect rooms and corridors. Some doorways have no - doors; you can walk right through. Others have doors in them, which - may be open, closed, or locked. To open a closed door, use the `o' - (open) command; to close it again, use the `c' (close) command. By - default the autoopen option is enabled, so simply attempting to walk - onto a closed door's location will attempt to open it without needing - `o'. Opening via autoopen will not work if you are confused or + Doorways connect rooms and corridors. Some doorways have no + doors; you can walk right through. Others have doors in them, which + may be open, closed, or locked. To open a closed door, use the `o' + (open) command; to close it again, use the `c' (close) command. By + default the autoopen option is enabled, so simply attempting to walk + onto a closed door's location will attempt to open it without needing + `o'. Opening via autoopen will not work if you are confused or stunned or suffer from the fumbling attribute. - Open doors cannot be entered diagonally; you must approach them - straight on, horizontally or vertically. Doorways without doors are - not restricted in this fashion except on one particular level (de- - scribed by "#overview" as "a primitive area"). + Open doors cannot be entered diagonally; you must approach them + straight on, horizontally or vertically. Doorways without doors are + not restricted in this fashion except on one particular level + (described by "#overview" as "a primitive area"). - Unlocking magic exists but usually won't be available early on. - You can get through a locked door without magic by first using an un- - locking tool with the `a' (apply) command, and then opening it. By - default the autounlock option is also enabled, so if you attempt to - open (via `o' or autoopen) a locked door while carrying an unlocking - tool, you'll be asked whether to use it on the door's lock. Alterna- - tively, you can break a closed door (whether locked or not) down by - kicking it via the `^D' (kick) command. Kicking down a door destroys + Unlocking magic exists but usually won't be available early on. + You can get through a locked door without magic by first using an + unlocking tool with the `a' (apply) command, and then opening it. By + default the autounlock option is also enabled, so if you attempt to + open (via `o' or autoopen) a locked door while carrying an unlocking + tool, you'll be asked whether to use it on the door's lock. Alterna- + tively, you can break a closed door (whether locked or not) down by + kicking it via the `^D' (kick) command. Kicking down a door destroys it and makes a lot of noise which might wake sleeping monsters. - Some closed doors are booby-trapped and will explode if an at- - tempt is made to open (when unlocked) or unlock (when locked) or kick - down. Like kicking, an explosion destroys the door and makes a lot of - noise. The "#untrap" command can be used to search a door for traps - but might take multiple attempts to find one. When one is found, - you'll be asked whether to try to disarm it. If you accede, success - will eliminate the trap but failure will set off the trap's explosion. - (If you decline, you effectively forget that a trap was found there.) + Some closed doors are booby-trapped and will explode if an + attempt is made to open (when unlocked) or unlock (when locked) or + kick down. Like kicking, an explosion destroys the door and makes a + lot of noise. The "#untrap" command can be used to search a door for + traps but might take multiple attempts to find one. When one is + found, you'll be asked whether to try to disarm it. If you accede, + success will eliminate the trap but failure will set off the trap's + explosion. (If you decline, you effectively forget that a trap was + found there.) Closed doors can be useful for shutting out monsters. Most mon- - sters cannot open closed doors, although a few don't need to (for ex- - ample, ghosts can walk through doors and fog clouds can flow under + sters cannot open closed doors, although a few don't need to (for + example, ghosts can walk through doors and fog clouds can flow under them). Some monsters who can open doors can also use unlocking tools. - And some (giants) can smash doors. - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -2380,63 +2380,63 @@ - Secret doors are hidden and appear to be ordinary wall (from in- - side a room) or solid rock (from outside). You can find them with the - `s' (search) command but it might take multiple tries (possibly many - tries if your luck is poor). Once found they are in all ways equiva- - lent to normal doors. Mapping magic does not reveal secret doors. + And some (giants) can smash doors. + + Secret doors are hidden and appear to be ordinary wall (from + inside a room) or solid rock (from outside). You can find them with + the `s' (search) command but it might take multiple tries (possibly + many tries if your luck is poor). Once found they are in all ways + equivalent to normal doors. Mapping magic does not reveal secret + doors. 5.2. Traps (`^') - There are traps throughout the dungeon to snare the unwary in- - truder. For example, you may suddenly fall into a pit and be stuck + There are traps throughout the dungeon to snare the unwary + intruder. For example, you may suddenly fall into a pit and be stuck for a few turns trying to climb out (see below). A trap usually won't - appear on your map until you trigger it by moving onto it, you see + appear on your map until you trigger it by moving onto it, you see someone else trigger it, or you discover it with the `s' (search) com- - mand (multiple attempts are often needed; if your luck is poor, many - attempts might be needed). Wands of secret door detection and spell - of detect unseen also reveal traps within a modest radius but only if + mand (multiple attempts are often needed; if your luck is poor, many + attempts might be needed). Wands of secret door detection and spell + of detect unseen also reveal traps within a modest radius but only if the trap is also within line-of-sight (whether you can see at the time or not). There is also other magic which can reveal traps. - Monsters can fall prey to traps, too, which can potentially be - used as a defensive strategy. Unfortunately traps can be harmful to - your pet(s) as well. Monsters, including pets, usually will avoid + Monsters can fall prey to traps, too, which can potentially be + used as a defensive strategy. Unfortunately traps can be harmful to + your pet(s) as well. Monsters, including pets, usually will avoid moving onto a trap which is shown on your map if they have encountered that type of trap before. - Some traps such as pits, bear traps, and webs hold you in one - place. You can escape by simply trying to move to an adjacent spot + Some traps such as pits, bear traps, and webs hold you in one + place. You can escape by simply trying to move to an adjacent spot and repeat as needed; eventually you will get free. - Other traps can send you to different locations. Teleporters - send you elsewhere on the same dungeon level. Level teleporters send - you to a random dungeon level, the destination chosen from a few lev- - els lower all the way to the top. These traps choose a new destina- - tion each time they're activated. Trap doors and holes also send you - to another level, but one which is always below the current level. - Usually that will be the next level down but it can be farther. Un- - like (level) teleporters, the destination level of a particular trap - door or hole is persistent, so falling into one will bring you to the - same level each time--though not necessarily the same spot on the + Other traps can send you to different locations. Teleporters + send you elsewhere on the same dungeon level. Level teleporters send + you to a random dungeon level, the destination chosen from a few lev- + els lower all the way to the top. These traps choose a new destina- + tion each time they're activated. Trap doors and holes also send you + to another level, but one which is always below the current level. + Usually that will be the next level down but it can be farther. + Unlike (level) teleporters, the destination level of a particular trap + door or hole is persistent, so falling into one will bring you to the + same level each time--though not necessarily the same spot on the level. Magic portals behave similarly, but with some additional vari- - ation. Some portals are two-way and their remote destination is al- - ways the same: another portal which can take you back. Others are + ation. Some portals are two-way and their remote destination is + always the same: another portal which can take you back. Others are one-way and send you to a specific destination level but not necessar- ily to a specific location there. - There is a special multi-level branch of the dungeon with pre- - mapped levels based on the classic computer game "Sokoban." In that - game, you operate as a warehouse worker who pushes crates around ob- - stacles to position them at designated locations. In NetHack, the + There is a special multi-level branch of the dungeon with pre- + mapped levels based on the classic computer game "Sokoban." In that + game, you operate as a warehouse worker who pushes crates around + obstacles to position them at designated locations. In NetHack, the goal is to push boulders into pits or holes until those traps have all - been nullified, giving access to whatever is beyond them. In the - Sokoban game, you can only move in the four cardinal compass direc- - tions, and a crate in its final destination blocks further access to - that spot. In the Sokoban levels of NetHack, you can move diagonally + been nullified, giving access to whatever is beyond them. In the - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -2446,63 +2446,63 @@ - (unless that would let you pass between two neighboring boulders) but - you can only push boulders in the four cardinal directions, and a - boulder which fills a pit or hole removes both the boulder and the - trap so opens up normal access to that spot. With careful foresight, - it is possible to complete all of the levels according to the tradi- - tional rules of Sokoban. (Hint: to solve Sokoban puzzles, you often - need to move things away from their eventual destinations in order to - open up more room to maneuver.) Since NetHack does not support an - undo capability, some allowances are permitted in case you get stuck. - For example, each level has at least one extra boulder. Also, it is - possible to drop everything in order to be able to squeeze into the - same location as a boulder (and then presumably move past it), or to - destroy a boulder with magic or tools, or to create new boulders with - a scroll of earth. However, doing such things will lower your luck - without any specific message given about that. See the Conduct sec- - tion for information about getting feedback for your actions in + Sokoban game, you can only move in the four cardinal compass direc- + tions, and a crate in its final destination blocks further access to + that spot. In the Sokoban levels of NetHack, you can move diagonally + (unless that would let you pass between two neighboring boulders) but + you can only push boulders in the four cardinal directions, and a + boulder which fills a pit or hole removes both the boulder and the + trap so opens up normal access to that spot. With careful foresight, + it is possible to complete all of the levels according to the tradi- + tional rules of Sokoban. (Hint: to solve Sokoban puzzles, you often + need to move things away from their eventual destinations in order to + open up more room to maneuver.) Since NetHack does not support an + undo capability, some allowances are permitted in case you get stuck. + For example, each level has at least one extra boulder. Also, it is + possible to drop everything in order to be able to squeeze into the + same location as a boulder (and then presumably move past it), or to + destroy a boulder with magic or tools, or to create new boulders with + a scroll of earth. However, doing such things will lower your luck + without any specific message given about that. See the Conduct sec- + tion for information about getting feedback for your actions in Sokoban. 5.3. Stairs and ladders (`<', `>') In general, each level in the dungeon will have a staircase going - up (`<') to the previous level and another going down (`>') to the - next level. There are some exceptions though. For instance, fairly - early in the dungeon you will find a level with two down staircases, - one continuing into the dungeon and the other branching into an area + up (`<') to the previous level and another going down (`>') to the + next level. There are some exceptions though. For instance, fairly + early in the dungeon you will find a level with two down staircases, + one continuing into the dungeon and the other branching into an area known as the Gnomish Mines. Those mines eventually hit a dead end, so - after exploring them (if you choose to do so), you'll need to climb + after exploring them (if you choose to do so), you'll need to climb back up to the main dungeon. - When you traverse a set of stairs, or trigger a trap which sends + When you traverse a set of stairs, or trigger a trap which sends you to another level, the level you're leaving will be deactivated and - stored in a file on disk. If you're moving to a previously visited - level, it will be loaded from its file on disk and reactivated. If - you're moving to a level which has not yet been visited, it will be + stored in a file on disk. If you're moving to a previously visited + level, it will be loaded from its file on disk and reactivated. If + you're moving to a level which has not yet been visited, it will be created (from scratch for most random levels, from a template for some - "special" levels, or loaded from the remains of an earlier game for a - "bones" level as briefly described below). Monsters are only active - on the current level; those on other levels are essentially placed + "special" levels, or loaded from the remains of an earlier game for a + "bones" level as briefly described below). Monsters are only active + on the current level; those on other levels are essentially placed into stasis. Ordinarily when you climb a set of stairs, you will arrive on the - corresponding staircase at your destination. However, pets (see be- - low) and some other monsters will follow along if they're close enough - when you travel up or down stairs, and occasionally one of these crea- - tures will displace you during the climb. When that occurs, the pet - or other monster will arrive on the staircase and you will end up - nearby. + corresponding staircase at your destination. However, pets (see + below) and some other monsters will follow along if they're close + enough when you travel up or down stairs, and occasionally one of + these creatures will displace you during the climb. When that occurs, + the pet or other monster will arrive on the staircase and you will end + up nearby. - Ladders serve the same purpose as staircases, and the two types - of inter-level connections are nearly indistinguishable during game + Ladders serve the same purpose as staircases, and the two types + of inter-level connections are nearly indistinguishable during game play. - - - - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -2514,36 +2514,36 @@ 5.4. Shops and shopping - Occasionally you will run across a room with a shopkeeper near - the door and many items lying on the floor. You can buy items by + Occasionally you will run across a room with a shopkeeper near + the door and many items lying on the floor. You can buy items by picking them up and then using the `p' command. You can inquire about - the price of an item prior to picking it up by using the "#chat" com- - mand while standing on it. Using an item prior to paying for it will - incur a charge, and the shopkeeper won't allow you to leave the shop + the price of an item prior to picking it up by using the "#chat" com- + mand while standing on it. Using an item prior to paying for it will + incur a charge, and the shopkeeper won't allow you to leave the shop until you have paid any debt you owe. - You can sell items to a shopkeeper by dropping them to the floor + You can sell items to a shopkeeper by dropping them to the floor while inside a shop. You will either be offered an amount of gold and asked whether you're willing to sell, or you'll be told that the shop- - keeper isn't interested (generally, your item needs to be compatible + keeper isn't interested (generally, your item needs to be compatible with the type of merchandise carried by the shop). - If you drop something in a shop by accident, the shopkeeper will - usually claim ownership without offering any compensation. You'll + If you drop something in a shop by accident, the shopkeeper will + usually claim ownership without offering any compensation. You'll have to buy it back if you want to reclaim it. Shopkeepers sometime run out of money. When that happens, you'll - be offered credit instead of gold when you try to sell something. - Credit can be used to pay for purchases, but it is only good in the + be offered credit instead of gold when you try to sell something. + Credit can be used to pay for purchases, but it is only good in the shop where it was obtained; other shopkeepers won't honor it. (If you - happen to find a "credit card" in the dungeon, don't bother trying to + happen to find a "credit card" in the dungeon, don't bother trying to use it in shops; shopkeepers will not accept it.) - The `$' command, which reports the amount of gold you are carry- - ing, will also show current shop debt or credit, if any. The "Iu" - command lists unpaid items (those which still belong to the shop) if - you are carrying any. The "Ix" command shows an inventory-like dis- - play of any unpaid items which have been used up, along with other + The `$' command, which reports the amount of gold you are carry- + ing, will also show current shop debt or credit, if any. The "Iu" + command lists unpaid items (those which still belong to the shop) if + you are carrying any. The "Ix" command shows an inventory-like dis- + play of any unpaid items which have been used up, along with other shop fees, if any. 5.4.1. Shop idiosyncrasies @@ -2552,23 +2552,23 @@ * The price of a given item can vary due to a variety of factors. - * A shopkeeper treats the spot immediately inside the door as if it + * A shopkeeper treats the spot immediately inside the door as if it were outside the shop. - * While the shopkeeper watches you like a hawk, he or she will gener- + * While the shopkeeper watches you like a hawk, he or she will gener- ally ignore any other customers. - * If a shop is "closed for inventory," it will not open of its own ac- - cord. + * If a shop is "closed for inventory," it will not open of its own + accord. - * Shops do not get restocked with new items, regardless of inventory + * Shops do not get restocked with new items, regardless of inventory depletion. - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -2580,61 +2580,61 @@ 5.5. Movement feedback - Moving around the map usually provides no feedback--other than - drawing the hero at the new location--unless you step on an object or - pile of objects, or on a trap, or attempt to move onto a spot where a - monster is located. There are several options which can be used to + Moving around the map usually provides no feedback--other than + drawing the hero at the new location--unless you step on an object or + pile of objects, or on a trap, or attempt to move onto a spot where a + monster is located. There are several options which can be used to augment the normal feedback. - The pile_limit option controls how many objects can be in a - pile--sharing the same map location--for the game to state "there are - objects here" instead of listing them. The default is 5. Setting it - to 1 would always give that message instead of listing any objects. - Setting it to 0 is a special case which will always list all objects + The pile_limit option controls how many objects can be in a + pile--sharing the same map location--for the game to state "there are + objects here" instead of listing them. The default is 5. Setting it + to 1 would always give that message instead of listing any objects. + Setting it to 0 is a special case which will always list all objects no matter how big a pile is. Note that the number refers to the count of separate stacks of objects present rather than the sum of the quan- - tities of those stacks (so 7 arrows or 25 gold pieces will each count - as 1 rather than as 7 and 25, respectively, and total to 2 when both + tities of those stacks (so 7 arrows or 25 gold pieces will each count + as 1 rather than as 7 and 25, respectively, and total to 2 when both are at the same location). - The "nopickup" command prefix (default `m') can be used before a - movement direction to step on objects without attempting auto-pickup + The "nopickup" command prefix (default `m') can be used before a + movement direction to step on objects without attempting auto-pickup and without giving feedback about them. The mention_walls option controls whether you get feedback if you - try to walk into a wall or solid stone or off the edge of the map. - Normally nothing happens (unless the hero is blind and no wall is - shown, then the wall that is being bumped into will be drawn on the - map). This option also gives feedback when rushing or running stops + try to walk into a wall or solid stone or off the edge of the map. + Normally nothing happens (unless the hero is blind and no wall is + shown, then the wall that is being bumped into will be drawn on the + map). This option also gives feedback when rushing or running stops for some non-obvious reason. - The mention_decor option controls whether you get feedback when - walking on "furniture." Normally stepping onto stairs or a fountain - or an altar or various other things doesn't elicit anything unless it - is covered by one or more objects so is obscured on the map. Setting - this option to true will describe such things even when they aren't - obscured. Doorless doorways and open doors aren't considered worthy + The mention_decor option controls whether you get feedback when + walking on "furniture." Normally stepping onto stairs or a fountain + or an altar or various other things doesn't elicit anything unless it + is covered by one or more objects so is obscured on the map. Setting + this option to true will describe such things even when they aren't + obscured. Doorless doorways and open doors aren't considered worthy of mention; closed doors (if you can move onto their spots) and broken - doors are. Assuming that you're able to do so, moving onto water or - lava or ice will give feedback if not yet on that type of terrain but - not repeat it (unless there has been some intervening message) when - moving from water to another water spot, or lava to lava, or ice to - ice. Moving off of any of those back onto "normal" terrain will give - one message too, unless there is feedback about one or more objects, + doors are. Assuming that you're able to do so, moving onto water or + lava or ice will give feedback if not yet on that type of terrain but + not repeat it (unless there has been some intervening message) when + moving from water to another water spot, or lava to lava, or ice to + ice. Moving off of any of those back onto "normal" terrain will give + one message too, unless there is feedback about one or more objects, in which case the back on land circumstance is implied. - The confirm and safe_pet options control what happens when you + The confirm and safe_pet options control what happens when you try to move onto a peaceful monster's spot or a tame one's spot. - The "nopickup" command prefix (default `m') is also the move- + The "nopickup" command prefix (default `m') is also the move- without-attacking prefix and can be used to try to step onto a visible - monster's spot without the move being considered an attack (see the - Fighting subsection of Monsters below). The "fight" command prefix - (default `F'; also `-' if number_pad is on) can be used to force an - attack, when guessing where an unseen monster is or when deliberately + monster's spot without the move being considered an attack (see the + Fighting subsection of Monsters below). The "fight" command prefix + (default `F'; also `-' if number_pad is on) can be used to force an + attack, when guessing where an unseen monster is or when deliberately - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -2646,61 +2646,61 @@ attacking a peaceful or tame creature. - The run_mode option controls how frequently the map gets redrawn - when moving more than one step in a single command (so when rushing, + The run_mode option controls how frequently the map gets redrawn + when moving more than one step in a single command (so when rushing, running, or traveling). 5.6. Rogue level - One dungeon level (occurring in mid to late teens of the main + One dungeon level (occurring in mid to late teens of the main dungeon) is a tribute to the ancestor game hack's inspiration rogue. - It is usually displayed differently from other levels: possibly - in characters instead of tiles, or without line-drawing symbols if al- - ready in characters; also, gold is shown as * rather than $ and stairs - are shown as % rather than < and >. There are some minor differences - in actual game play: doorways lack doors; a scroll, wand, or spell of - light used in a room lights up the whole room rather than within a ra- - dius around your character. And monsters represented by lower-case - letters aren't randomly generated on the rogue level. + It is usually displayed differently from other levels: possibly + in characters instead of tiles, or without line-drawing symbols if + already in characters; also, gold is shown as * rather than $ and + stairs are shown as % rather than < and >. There are some minor dif- + ferences in actual game play: doorways lack doors; a scroll, wand, or + spell of light used in a room lights up the whole room rather than + within a radius around your character. And monsters represented by + lower-case letters aren't randomly generated on the rogue level. The slight strangeness of this level is a feature, not a bug.... 6. Monsters Monsters you cannot see are not displayed on the screen. Beware! - You may suddenly come upon one in a dark place. Some magic items can - help you locate them before they locate you (which some monsters can + You may suddenly come upon one in a dark place. Some magic items can + help you locate them before they locate you (which some monsters can do very well). - The commands `/' and `;' may be used to obtain information about - those monsters who are displayed on the screen. The command "#name" - (by default bound to `C'), allows you to assign a name to a monster, + The commands `/' and `;' may be used to obtain information about + those monsters who are displayed on the screen. The command "#name" + (by default bound to `C'), allows you to assign a name to a monster, which may be useful to help distinguish one from another when multiple - monsters are present. Assigning a name which is just a space will re- - move any prior name. + monsters are present. Assigning a name which is just a space will + remove any prior name. - The extended command "#chat" can be used to interact with an ad- - jacent monster. There is no actual dialog (in other words, you don't - get to choose what you'll say), but chatting with some monsters such - as a shopkeeper or the Oracle of Delphi can produce useful results. + The extended command "#chat" can be used to interact with an + adjacent monster. There is no actual dialog (in other words, you + don't get to choose what you'll say), but chatting with some monsters + such as a shopkeeper or the Oracle of Delphi can produce useful + results. 6.1. Fighting If you see a monster and you wish to fight it, just attempt to - walk into it. Many monsters you find will mind their own business un- - less you attack them. Some of them are very dangerous when angered. + walk into it. Many monsters you find will mind their own business + unless you attack them. Some of them are very dangerous when angered. Remember: discretion is the better part of valor. In most circumstances, if you attempt to attack a peaceful mon- - ster by moving into its location, you'll be asked to confirm your in- - tent. By default an answer of `y' acknowledges that intent, which can - be error prone if you're using `y' to move. You can set the para- - noid_confirmation:attack option to require a response of "yes" in- - stead. + ster by moving into its location, you'll be asked to confirm your + intent. By default an answer of `y' acknowledges that intent, which + can be error prone if you're using `y' to move. You can set the para- + noid_confirmation:attack option to require a response of "yes" - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -2710,6 +2710,8 @@ + instead. + If you can't see a monster (if it is invisible, or if you are blinded), the symbol `I' will be shown when you learn of its presence. If you attempt to walk into it, you will try to fight it just like a @@ -2747,8 +2749,8 @@ Some types of creatures in the dungeon can actually be ridden if you have the right equipment and skill. Convincing a wild beast to let you saddle it up is difficult to say the least. Many a dungeoneer - has had to resort to magic and wizardry in order to forge the al- - liance. Once you do have the beast under your control however, you + has had to resort to magic and wizardry in order to forge the + alliance. Once you do have the beast under your control however, you can easily climb in and out of the saddle with the "#ride" command. Lead the beast around the dungeon when riding, in the same manner as you would move yourself. It is the beast that you will see displayed @@ -2761,12 +2763,10 @@ to attempt to put that saddle on an adjacent creature. If successful, it will be transferred to that creature's inventory. - Use the "#loot" command while adjacent to a saddled creature to - try to remove the saddle from that creature. If successful, it will - be transferred to your inventory. - NetHack 3.7.0 September 13, 2024 + + NetHack 3.7.0 November 16, 2024 @@ -2776,6 +2776,10 @@ + Use the "#loot" command while adjacent to a saddled creature to + try to remove the saddle from that creature. If successful, it will + be transferred to your inventory. + 6.4. Bones levels You may encounter the shades and corpses of other adventurers (or @@ -2799,8 +2803,8 @@ a special "remembered, unseen monster" marker will be displayed at the location where you think it is. That will persist until you have proven that there is no monster there, even if the unseen monster - moves to another location or you move to a spot where the marker's lo- - cation ordinarily wouldn't be seen any more. + moves to another location or you move to a spot where the marker's + location ordinarily wouldn't be seen any more. 7. Objects @@ -2826,13 +2830,9 @@ NetHack will tell you how badly you have loaded yourself. If you are encumbered, one of the conditions Burdened, Stressed, Strained, - Overtaxed, or Overloaded will be shown on the bottom line status dis- - play. - - - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -2842,63 +2842,63 @@ + Overtaxed, or Overloaded will be shown on the bottom line status dis- + play. + When you pick up an object, it is assigned an inventory letter. Many commands that operate on objects must ask you to find out which object you want to use. When NetHack asks you to choose a particular - object you are carrying, you are usually presented with a list of in- - ventory letters to choose from (see Commands, above). + object you are carrying, you are usually presented with a list of + inventory letters to choose from (see Commands, above). Some objects, such as weapons, are easily differentiated. Oth- - ers, like scrolls and potions, are given descriptions which vary ac- - cording to type. During a game, any two objects with the same de- - scription are the same type. However, the descriptions will vary from - game to game. + ers, like scrolls and potions, are given descriptions which vary + according to type. During a game, any two objects with the same + description are the same type. However, the descriptions will vary + from game to game. When you use one of these objects, if its effect is obvious, - NetHack will remember what it is for you. If its effect isn't ex- - tremely obvious, you will be asked what you want to call this type of - object so you will recognize it later. You can also use the "#name" - command, for the same purpose at any time, to name all objects of a - particular type or just an individual object. When you use "#name" on - an object which has already been named, specifying a space as the - value will remove the prior name instead of assigning a new one. + NetHack will remember what it is for you. If its effect isn't + extremely obvious, you will be asked what you want to call this type + of object so you will recognize it later. You can also use the + "#name" command, for the same purpose at any time, to name all objects + of a particular type or just an individual object. When you use + "#name" on an object which has already been named, specifying a space + as the value will remove the prior name instead of assigning a new + one. 7.1. Curses and Blessings - Any object that you find may be cursed, even if the object is - otherwise helpful. The most common effect of a curse is being stuck - with (and to) the item. Cursed weapons weld themselves to your hand + Any object that you find may be cursed, even if the object is + otherwise helpful. The most common effect of a curse is being stuck + with (and to) the item. Cursed weapons weld themselves to your hand when wielded, so you cannot unwield them. Any cursed item you wear is - not removable by ordinary means. In addition, cursed arms and armor - usually, but not always, bear negative enchantments that make them - less effective in combat. Other cursed objects may act poorly or + not removable by ordinary means. In addition, cursed arms and armor + usually, but not always, bear negative enchantments that make them + less effective in combat. Other cursed objects may act poorly or detrimentally in other ways. - Objects can also be blessed instead. Blessed items usually work - better or more beneficially than normal uncursed items. For example, + Objects can also be blessed instead. Blessed items usually work + better or more beneficially than normal uncursed items. For example, a blessed weapon will do slightly more damage against demons. - Objects which are neither cursed nor blessed are referred to as + Objects which are neither cursed nor blessed are referred to as uncursed. They could just as easily have been described as unblessed, - but the uncursed designation is what you will see within the game. A + but the uncursed designation is what you will see within the game. A "glass half full versus glass half empty" situation; make of that what you will. - There are magical means of bestowing or removing curses upon ob- - jects, so even if you are stuck with one, you can still have the curse - lifted and the item removed. Priests and Priestesses have an innate - sensitivity to this property in any object, so they can more easily - avoid cursed objects than other character roles. Dropping objects - onto an altar will reveal their bless or curse state provided that you - can see them land. - - An item with unknown status will be reported in your inventory - with no prefix. An item which you know the state of will be distin- - guished in your inventory by the presence of the word cursed, un- - cursed, or blessed in the description of the item. In some cases + There are magical means of bestowing or removing curses upon + objects, so even if you are stuck with one, you can still have the + curse lifted and the item removed. Priests and Priestesses have an + innate sensitivity to this property in any object, so they can more + easily avoid cursed objects than other character roles. Dropping + objects onto an altar will reveal their bless or curse state provided + that you can see them land. - NetHack 3.7.0 September 13, 2024 + + NetHack 3.7.0 November 16, 2024 @@ -2908,63 +2908,63 @@ + An item with unknown status will be reported in your inventory + with no prefix. An item which you know the state of will be distin- + guished in your inventory by the presence of the word cursed, + uncursed, or blessed in the description of the item. In some cases uncursed will be omitted as being redundant when enough other informa- - tion is displayed. The implicit_uncursed option can be used to con- - trol this; toggle it off to have uncursed be displayed even when that + tion is displayed. The implicit_uncursed option can be used to con- + trol this; toggle it off to have uncursed be displayed even when that can be deduced from other attributes. - Sometimes the bless or curse state of objects is referred to as - their "BUC" attribute, for Blessed, Uncursed, or Cursed state, or + Sometimes the bless or curse state of objects is referred to as + their "BUC" attribute, for Blessed, Uncursed, or Cursed state, or "BUCX" for Blessed, Uncursed, Cursed, or unknown. (The term beatitude is occasionally used as well.) 7.2. Weapons (`)') - Given a chance, most monsters in the Mazes of Menace will gratu- - itously try to kill you. You need weapons for self-defense (killing - them first). Without a weapon, you do only 1-2 hit points of damage - (plus bonuses, if any). Monk characters are an exception; they nor- - mally do more damage with bare (or gloved) hands than they do with + Given a chance, most monsters in the Mazes of Menace will gratu- + itously try to kill you. You need weapons for self-defense (killing + them first). Without a weapon, you do only 1-2 hit points of damage + (plus bonuses, if any). Monk characters are an exception; they nor- + mally do more damage with bare (or gloved) hands than they do with weapons. - There are wielded weapons, like maces and swords, and thrown - weapons, like arrows and spears. To hit monsters with a weapon, you - must wield it and attack them, or throw it at them. You can simply - elect to throw a spear. To shoot an arrow, you should first wield a - bow, then throw the arrow. Crossbows shoot crossbow bolts. Slings + There are wielded weapons, like maces and swords, and thrown + weapons, like arrows and spears. To hit monsters with a weapon, you + must wield it and attack them, or throw it at them. You can simply + elect to throw a spear. To shoot an arrow, you should first wield a + bow, then throw the arrow. Crossbows shoot crossbow bolts. Slings hurl rocks and (other) stones (like gems). - Enchanted weapons have a "plus" (or "to hit enhancement" which - can be either positive or negative) that adds to your chance to hit - and the damage you do to a monster. The only way to determine a + Enchanted weapons have a "plus" (or "to hit enhancement" which + can be either positive or negative) that adds to your chance to hit + and the damage you do to a monster. The only way to determine a weapon's enchantment is to have it magically identified somehow. Most - weapons are subject to some type of damage like rust. Such "erosion" + weapons are subject to some type of damage like rust. Such "erosion" damage can be repaired. - The chance that an attack will successfully hit a monster, and - the amount of damage such a hit will do, depends upon many factors. - Among them are: type of weapon, quality of weapon (enchantment and/or + The chance that an attack will successfully hit a monster, and + the amount of damage such a hit will do, depends upon many factors. + Among them are: type of weapon, quality of weapon (enchantment and/or erosion), experience level, strength, dexterity, encumbrance, and pro- - ficiency (see below). The monster's armor class--a general defense - rating, not necessarily due to wearing of armor--is a factor too; - also, some monsters are particularly vulnerable to certain types of + ficiency (see below). The monster's armor class--a general defense + rating, not necessarily due to wearing of armor--is a factor too; + also, some monsters are particularly vulnerable to certain types of weapons. Many weapons can be wielded in one hand; some require both hands. When wielding a two-handed weapon, you can not wear a shield, and vice versa. When wielding a one-handed weapon, you can have another weapon - ready to use by setting things up with the `x' command, which ex- - changes your primary (the one being wielded) and alternate weapons. - And if you have proficiency in the "two weapon combat" skill, you may - wield both weapons simultaneously as primary and secondary; use the - `X' command to engage or disengage that. Only some types of charac- - ters (barbarians, for instance) have the necessary skill available. - Even with that skill, using two weapons at once incurs a penalty in - the chance to hit your target compared to using just one weapon at a - time. + ready to use by setting things up with the `x' command, which + exchanges your primary (the one being wielded) and alternate weapons. + And if you have proficiency in the "two weapon combat" skill, you may + wield both weapons simultaneously as primary and secondary; use the + `X' command to engage or disengage that. Only some types of charac- - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -2974,63 +2974,63 @@ - There might be times when you'd rather not wield any weapon at + ters (barbarians, for instance) have the necessary skill available. + Even with that skill, using two weapons at once incurs a penalty in + the chance to hit your target compared to using just one weapon at a + time. + + There might be times when you'd rather not wield any weapon at all. To accomplish that, wield `-', or else use the `A' command which - allows you to unwield the current weapon in addition to taking off + allows you to unwield the current weapon in addition to taking off other worn items. - Those of you in the audience who are AD&D players, be aware that + Those of you in the audience who are AD&D players, be aware that each weapon which existed in AD&D does roughly the same damage to mon- - sters in NetHack. Some of the more obscure weapons (such as the + sters in NetHack. Some of the more obscure weapons (such as the aklys, lucern hammer, and bec-de-corbin) are defined in an appendix to Unearthed Arcana, an AD&D supplement. - The commands to use weapons are `w' (wield), `t' (throw), `f' - (fire), `Q' (quiver), `x' (exchange), `X' (twoweapon), and "#enhance" + The commands to use weapons are `w' (wield), `t' (throw), `f' + (fire), `Q' (quiver), `x' (exchange), `X' (twoweapon), and "#enhance" (see below). 7.2.1. Throwing and shooting - You can throw just about anything via the `t' command. It will - prompt for the item to throw; picking `?' will list things in your in- - ventory which are considered likely to be thrown, or picking `*' will - list your entire inventory. After you've chosen what to throw, you - will be prompted for a direction rather than for a specific target. - The distance something can be thrown depends mainly on the type of ob- - ject and your strength. Arrows can be thrown by hand, but can be - thrown much farther and will be more likely to hit when thrown while + You can throw just about anything via the `t' command. It will + prompt for the item to throw; picking `?' will list things in your + inventory which are considered likely to be thrown, or picking `*' + will list your entire inventory. After you've chosen what to throw, + you will be prompted for a direction rather than for a specific tar- + get. The distance something can be thrown depends mainly on the type + of object and your strength. Arrows can be thrown by hand, but can be + thrown much farther and will be more likely to hit when thrown while you are wielding a bow. - Some weapons will return when thrown. A boomerang--provided it - fails to hit anything--is an obvious example. If an aklys (thonged - club) is thrown while it is wielded, it will return even when it hits - something. A sufficiently strong hero can throw the warhammer Mjoll- - nir; when thrown by a Valkyrie it will return too. However, aklyses - and Mjollnir occasionally fail to return. Returning thrown objects - occasionally fail to be caught, sometimes even hitting the thrower, + Some weapons will return when thrown. A boomerang--provided it + fails to hit anything--is an obvious example. If an aklys (thonged + club) is thrown while it is wielded, it will return even when it hits + something. A sufficiently strong hero can throw the warhammer Mjoll- + nir; when thrown by a Valkyrie it will return too. However, aklyses + and Mjollnir occasionally fail to return. Returning thrown objects + occasionally fail to be caught, sometimes even hitting the thrower, but when caught they become re-wielded. - You can simplify the throwing operation by using the `Q' command - to select your preferred "missile", then using the `f' command to - throw it. You'll be prompted for a direction as above, but you don't - have to specify which item to throw each time you use `f'. There is - also an option, autoquiver, which has NetHack choose another item to - automatically fill your quiver (or quiver sack, or have at the ready) - when the inventory slot used for `Q' runs out. If your quiver is - empty, autoquiver is false, and you are wielding a weapon which re- - turns when thrown, you will throw that weapon instead of filling the - quiver. The fire command also has extra assistance, if fireassist is + You can simplify the throwing operation by using the `Q' command + to select your preferred "missile", then using the `f' command to + throw it. You'll be prompted for a direction as above, but you don't + have to specify which item to throw each time you use `f'. There is + also an option, autoquiver, which has NetHack choose another item to + automatically fill your quiver (or quiver sack, or have at the ready) + when the inventory slot used for `Q' runs out. If your quiver is + empty, autoquiver is false, and you are wielding a weapon which + returns when thrown, you will throw that weapon instead of filling the + quiver. The fire command also has extra assistance, if fireassist is on it will try to wield a launcher matching the ammo in the quiver. - Some characters have the ability to throw or shoot a volley of - multiple items (from the same stack) in a single action. Knowing how - to load several rounds of ammunition at once--or hold several missiles - in your hand--and still hit a target is not an easy task. Rangers are - among those who are adept at this task, as are those with a high level - of proficiency in the relevant weapon skill (in bow skill if you're - NetHack 3.7.0 September 13, 2024 + + NetHack 3.7.0 November 16, 2024 @@ -3040,63 +3040,63 @@ + Some characters have the ability to throw or shoot a volley of + multiple items (from the same stack) in a single action. Knowing how + to load several rounds of ammunition at once--or hold several missiles + in your hand--and still hit a target is not an easy task. Rangers are + among those who are adept at this task, as are those with a high level + of proficiency in the relevant weapon skill (in bow skill if you're wielding one to shoot arrows, in crossbow skill if you're wielding one - to shoot bolts, or in sling skill if you're wielding one to shoot - stones). The number of items that the character has a chance to fire - varies from turn to turn. You can explicitly limit the number of - shots by using a numeric prefix before the `t' or `f' command. For + to shoot bolts, or in sling skill if you're wielding one to shoot + stones). The number of items that the character has a chance to fire + varies from turn to turn. You can explicitly limit the number of + shots by using a numeric prefix before the `t' or `f' command. For example, "2f" (or "n2f" if using number_pad mode) would ensure that at most 2 arrows are shot even if you could have fired 3. If you specify - a larger number than would have been shot ("4f" in this example), - you'll just end up shooting the same number (3, here) as if no limit - had been specified. Once the volley is in motion, all of the items - will travel in the same direction; if the first ones kill a monster, + a larger number than would have been shot ("4f" in this example), + you'll just end up shooting the same number (3, here) as if no limit + had been specified. Once the volley is in motion, all of the items + will travel in the same direction; if the first ones kill a monster, the others can still continue beyond that spot. 7.2.2. Weapon proficiency - You will have varying degrees of skill in the weapons available. + You will have varying degrees of skill in the weapons available. Weapon proficiency, or weapon skills, affect how well you can use par- ticular types of weapons, and you'll be able to improve your skills as - you progress through a game, depending on your role, your experience + you progress through a game, depending on your role, your experience level, and use of the weapons. - For the purposes of proficiency, weapons have been divided up - into various groups such as daggers, broadswords, and polearms. Each - role has a limit on what level of proficiency a character can achieve - for each group. For instance, wizards can become highly skilled in + For the purposes of proficiency, weapons have been divided up + into various groups such as daggers, broadswords, and polearms. Each + role has a limit on what level of proficiency a character can achieve + for each group. For instance, wizards can become highly skilled in daggers or staves but not in swords or bows. The "#enhance" extended command is used to review current weapons - proficiency (also spell proficiency) and to choose which skill(s) to - improve when you've used one or more skills enough to become eligible - to do so. The skill rankings are "none" (sometimes also referred to - as "restricted", because you won't be able to advance), "unskilled", - "basic", "skilled", and "expert". Restricted skills simply will not - appear in the list shown by "#enhance". (Divine intervention might - unrestrict a particular skill, in which case it will start at un- - skilled and be limited to basic.) Some characters can enhance their - barehanded combat or martial arts skill beyond expert to "master" or + proficiency (also spell proficiency) and to choose which skill(s) to + improve when you've used one or more skills enough to become eligible + to do so. The skill rankings are "none" (sometimes also referred to + as "restricted", because you won't be able to advance), "unskilled", + "basic", "skilled", and "expert". Restricted skills simply will not + appear in the list shown by "#enhance". (Divine intervention might + unrestrict a particular skill, in which case it will start at + unskilled and be limited to basic.) Some characters can enhance their + barehanded combat or martial arts skill beyond expert to "master" or "grand master". - Use of a weapon in which you're restricted or unskilled will in- - cur a modest penalty in the chance to hit a monster and also in the - amount of damage done when you do hit; at basic level, there is no - penalty or bonus; at skilled level, you receive a modest bonus in the + Use of a weapon in which you're restricted or unskilled will + incur a modest penalty in the chance to hit a monster and also in the + amount of damage done when you do hit; at basic level, there is no + penalty or bonus; at skilled level, you receive a modest bonus in the chance to hit and amount of damage done; at expert level, the bonus is - higher. A successful hit has a chance to boost your training towards + higher. A successful hit has a chance to boost your training towards the next skill level (unless you've already reached the limit for this skill). Once such training reaches the threshold for that next level, - you'll be told that you feel more confident in your skills. At that - point you can use "#enhance" to increase one or more skills. Such - skills are not increased automatically because there is a limit to - your total overall skills, so you need to actively choose which skills - to enhance and which to ignore. + you'll be told that you feel more confident in your skills. At that - - - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -3106,63 +3106,63 @@ + point you can use "#enhance" to increase one or more skills. Such + skills are not increased automatically because there is a limit to + your total overall skills, so you need to actively choose which skills + to enhance and which to ignore. + 7.2.3. Two-Weapon combat - Some characters can use two weapons at once. Setting things up - to do so can seem cumbersome but becomes second nature with use. To - wield two weapons, you need to use the "#twoweapon" command. But - first you need to have a weapon in each hand. (Note that your two - weapons are not fully equal; the one in the hand you normally wield - with is considered primary and the other one is considered secondary. + Some characters can use two weapons at once. Setting things up + to do so can seem cumbersome but becomes second nature with use. To + wield two weapons, you need to use the "#twoweapon" command. But + first you need to have a weapon in each hand. (Note that your two + weapons are not fully equal; the one in the hand you normally wield + with is considered primary and the other one is considered secondary. The most noticeable difference is after you stop--or before you begin, - for that matter--wielding two weapons at once. The primary is your - wielded weapon and the secondary is just an item in your inventory + for that matter--wielding two weapons at once. The primary is your + wielded weapon and the secondary is just an item in your inventory that's been designated as alternate weapon.) - If your primary weapon is wielded but your off hand is empty or - has the wrong weapon, use the sequence `x', `w', `x' to first swap - your primary into your off hand, wield whatever you want as secondary - weapon, then swap them both back into the intended hands. If your - secondary or alternate weapon is correct but your primary one is not, - simply use `w' to wield the primary. Lastly, if neither hand holds + If your primary weapon is wielded but your off hand is empty or + has the wrong weapon, use the sequence `x', `w', `x' to first swap + your primary into your off hand, wield whatever you want as secondary + weapon, then swap them both back into the intended hands. If your + secondary or alternate weapon is correct but your primary one is not, + simply use `w' to wield the primary. Lastly, if neither hand holds the correct weapon, use `w', `x', `w' to first wield the intended sec- ondary, swap it to off hand, and then wield the primary. - The whole process can be simplified via use of the pushweapon op- - tion. When it is enabled, then using `w' to wield something causes - the currently wielded weapon to become your alternate weapon. So the - sequence `w', `w' can be used to first wield the weapon you intend to - be secondary, and then wield the one you want as primary which will + The whole process can be simplified via use of the pushweapon + option. When it is enabled, then using `w' to wield something causes + the currently wielded weapon to become your alternate weapon. So the + sequence `w', `w' can be used to first wield the weapon you intend to + be secondary, and then wield the one you want as primary which will push the first into secondary position. - When in two-weapon combat mode, using the `X' command toggles - back to single-weapon mode. Throwing or dropping either of the weap- - ons or having one of them be stolen or destroyed will also make you + When in two-weapon combat mode, using the `X' command toggles + back to single-weapon mode. Throwing or dropping either of the weap- + ons or having one of them be stolen or destroyed will also make you revert to single-weapon combat. 7.3. Armor (`[') - Lots of unfriendly things lurk about; you need armor to protect - yourself from their blows. Some types of armor offer better protec- - tion than others. Your armor class is a measure of this protection. - Armor class (AC) is measured as in AD&D, with 10 being the equivalent - of no armor, and lower numbers meaning better armor. Each suit of ar- - mor which exists in AD&D gives the same protection in NetHack. + Lots of unfriendly things lurk about; you need armor to protect + yourself from their blows. Some types of armor offer better protec- + tion than others. Your armor class is a measure of this protection. + Armor class (AC) is measured as in AD&D, with 10 being the equivalent + of no armor, and lower numbers meaning better armor. Each suit of + armor which exists in AD&D gives the same protection in NetHack. - Here is a list of the armor class values provided by suits of ar- - mor: + Here is a list of the armor class values provided by suits of + armor: Dragon scale mail 1 Plate mail, Crystal plate mail 3 Bronze plate mail, Splint mail, - Banded mail, Dwarvish mithril-coat 4 - Chain mail, Elven mithril-coat 5 - Scale mail, Orcish chain mail 6 - Ring mail, Studded leather armor, - Dragon scales 7 - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -3172,63 +3172,63 @@ + Banded mail, Dwarvish mithril-coat 4 + Chain mail, Elven mithril-coat 5 + Scale mail, Orcish chain mail 6 + Ring mail, Studded leather armor, + Dragon scales 7 Leather armor, Orcish ring mail 8 Leather jacket 9 none 10 - You can also wear other pieces of armor (cloak over suit, shirt - under suit, helmet, gloves, boots, shield) to lower your armor class + You can also wear other pieces of armor (cloak over suit, shirt + under suit, helmet, gloves, boots, shield) to lower your armor class even further. Most of these provide a one or two point improvement to - AC (making the overall value smaller and eventually negative) but can - also be enchanted. Shirts are an exception; they don't provide any - protection unless enchanted. Some cloaks also don't improve AC when - unenchanted but all cloaks offer some protection against rust or cor- - rosion to suits worn under them and against some monster touch at- - tacks. + AC (making the overall value smaller and eventually negative) but can + also be enchanted. Shirts are an exception; they don't provide any + protection unless enchanted. Some cloaks also don't improve AC when + unenchanted but all cloaks offer some protection against rust or cor- + rosion to suits worn under them and against some monster touch + attacks. - If a piece of armor is enchanted, its armor protection will be + If a piece of armor is enchanted, its armor protection will be better (or worse) than normal, and its "plus" (or minus) will subtract - from your armor class. For example, a +1 chain mail would give you - better protection than normal chain mail, lowering your armor class - one unit further to 4. When you put on a piece of armor, you immedi- - ately find out the armor class and any "plusses" it provides. Cursed - pieces of armor usually have negative enchantments (minuses) in addi- + from your armor class. For example, a +1 chain mail would give you + better protection than normal chain mail, lowering your armor class + one unit further to 4. When you put on a piece of armor, you immedi- + ately find out the armor class and any "plusses" it provides. Cursed + pieces of armor usually have negative enchantments (minuses) in addi- tion to being unremovable. Many types of armor are subject to some kind of damage like rust. - Such damage can be repaired. Some types of armor may inhibit spell + Such damage can be repaired. Some types of armor may inhibit spell casting. - The nudist option can be set (prior to game start) to attempt to - play the entire game without wearing any armor (a self-imposed chal- + The nudist option can be set (prior to game start) to attempt to + play the entire game without wearing any armor (a self-imposed chal- lenge which is extremely difficult to accomplish). The commands to use armor are `W' (wear) and `T' (take off). The `A' command can be used to take off armor as well as other worn items. Also, `P' (put on) and `R' (remove) which are normally for accessories - can be used for armor, but pieces of armor won't be shown as likely + can be used for armor, but pieces of armor won't be shown as likely candidates in a prompt for choosing what to put on or remove. 7.4. Food (`%') - Food is necessary to survive. If you go too long without eating - you will faint, and eventually die of starvation. Some types of food - will spoil, and become unhealthy to eat, if not protected. Food - stored in ice boxes or tins ("cans") will usually stay fresh, but ice + Food is necessary to survive. If you go too long without eating + you will faint, and eventually die of starvation. Some types of food + will spoil, and become unhealthy to eat, if not protected. Food + stored in ice boxes or tins ("cans") will usually stay fresh, but ice boxes are heavy, and tins take a while to open. When you kill monsters, they usually leave corpses which are also - "food." Many, but not all, of these are edible; some also give you - special powers when you eat them. A good rule of thumb is "you are + "food." Many, but not all, of these are edible; some also give you + special powers when you eat them. A good rule of thumb is "you are what you eat." - Some character roles and some monsters are vegetarian. Vegetar- - ian monsters will typically never eat animal corpses, while vegetarian - players can, but with some rather unpleasant side-effects. - - - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -3238,32 +3238,36 @@ - You can name one food item after something you like to eat with + Some character roles and some monsters are vegetarian. Vegetar- + ian monsters will typically never eat animal corpses, while vegetarian + players can, but with some rather unpleasant side-effects. + + You can name one food item after something you like to eat with the fruit option. The command to eat food is `e'. 7.5. Scrolls (`?') - Scrolls are labeled with various titles, probably chosen by an- - cient wizards for their amusement value (for example "READ ME," or - "THANX MAUD" backwards). Scrolls disappear after you read them (ex- - cept for blank ones, without magic spells on them). + Scrolls are labeled with various titles, probably chosen by + ancient wizards for their amusement value (for example "READ ME," or + "THANX MAUD" backwards). Scrolls disappear after you read them + (except for blank ones, without magic spells on them). - One of the most useful of these is the scroll of identify, which - can be used to determine what another object is, whether it is cursed - or blessed, and how many uses it has left. Some objects of subtle en- - chantment are difficult to identify without these. + One of the most useful of these is the scroll of identify, which + can be used to determine what another object is, whether it is cursed + or blessed, and how many uses it has left. Some objects of subtle + enchantment are difficult to identify without these. - A mail daemon may run up and deliver mail to you as a scroll of + A mail daemon may run up and deliver mail to you as a scroll of mail (on versions compiled with this feature). To use this feature on - versions where NetHack mail delivery is triggered by electronic mail - appearing in your system mailbox, you must let NetHack know where to - look for new mail by setting the "MAIL" environment variable to the - file name of your mailbox. You may also want to set the "MAILREADER" - environment variable to the file name of your favorite reader, so - NetHack can shell to it when you read the scroll. On versions of - NetHack where mail is randomly generated internal to the game, these + versions where NetHack mail delivery is triggered by electronic mail + appearing in your system mailbox, you must let NetHack know where to + look for new mail by setting the "MAIL" environment variable to the + file name of your mailbox. You may also want to set the "MAILREADER" + environment variable to the file name of your favorite reader, so + NetHack can shell to it when you read the scroll. On versions of + NetHack where mail is randomly generated internal to the game, these environment variables are ignored. You can disable the mail daemon by turning off the mail option. @@ -3271,13 +3275,13 @@ 7.6. Potions (`!') - Potions are distinguished by the color of the liquid inside the + Potions are distinguished by the color of the liquid inside the flask. They disappear after you quaff them. - Clear potions are potions of water. Sometimes these are blessed - or cursed, resulting in holy or unholy water. Holy water is the bane + Clear potions are potions of water. Sometimes these are blessed + or cursed, resulting in holy or unholy water. Holy water is the bane of the undead, so potions of holy water are good things to throw (`t') - at them. It is also sometimes very useful to dip ("#dip") an object + at them. It is also sometimes very useful to dip ("#dip") an object into a potion. The command to drink a potion is `q' (quaff). @@ -3285,16 +3289,12 @@ 7.7. Wands (`/') Wands usually have multiple magical charges. Some types of wands - require a direction in which to zap them. You can also zap them at - yourself (just give a `.' or `s' for the direction). Be warned, how- - ever, for this is often unwise. Other types of wands don't require a - direction. The number of charges in a wand is random and decreases by - one whenever you use it. + require a direction in which to zap them. You can also zap them at + yourself (just give a `.' or `s' for the direction). Be warned, how- + ever, for this is often unwise. Other types of wands don't require a - - - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -3304,63 +3304,63 @@ - When the number of charges left in a wand becomes zero, attempts - to use the wand will usually result in nothing happening. Occasion- - ally, however, it may be possible to squeeze the last few mana points - from an otherwise spent wand, destroying it in the process. A wand - may be recharged by using suitable magic, but doing so runs the risk + direction. The number of charges in a wand is random and decreases by + one whenever you use it. + + When the number of charges left in a wand becomes zero, attempts + to use the wand will usually result in nothing happening. Occasion- + ally, however, it may be possible to squeeze the last few mana points + from an otherwise spent wand, destroying it in the process. A wand + may be recharged by using suitable magic, but doing so runs the risk of causing it to explode. The chance for such an explosion starts out very small and increases each time the wand is recharged. - In a truly desperate situation, when your back is up against the - wall, you might decide to go for broke and break your wand. This is - not for the faint of heart. Doing so will almost certainly cause a + In a truly desperate situation, when your back is up against the + wall, you might decide to go for broke and break your wand. This is + not for the faint of heart. Doing so will almost certainly cause a catastrophic release of magical energies. - When you have fully identified a particular wand, inventory dis- + When you have fully identified a particular wand, inventory dis- play will include additional information in parentheses: the number of - times it has been recharged followed by a colon and then by its cur- - rent number of charges. A current charge count of -1 is a special + times it has been recharged followed by a colon and then by its cur- + rent number of charges. A current charge count of -1 is a special case indicating that the wand has been cancelled. - The command to use a wand is `z' (zap). To break one, use the + The command to use a wand is `z' (zap). To break one, use the `a' (apply) command. 7.8. Rings (`=') - Rings are very useful items, since they are relatively permanent - magic, unlike the usually fleeting effects of potions, scrolls, and + Rings are very useful items, since they are relatively permanent + magic, unlike the usually fleeting effects of potions, scrolls, and wands. - Putting on a ring activates its magic. You can wear at most two + Putting on a ring activates its magic. You can wear at most two rings at any time, one on the ring finger of each hand. - Most worn rings also cause you to grow hungry more rapidly, the + Most worn rings also cause you to grow hungry more rapidly, the rate varying with the type of ring. - When wearing gloves, rings are worn underneath. If the gloves - are cursed, rings cannot be put on and any already being worn cannot - be removed. When worn gloves aren't cursed, you don't have to manu- - ally take them off before putting on or removing a ring and then re- + When wearing gloves, rings are worn underneath. If the gloves + are cursed, rings cannot be put on and any already being worn cannot + be removed. When worn gloves aren't cursed, you don't have to manu- + ally take them off before putting on or removing a ring and then re- wear them after. That's done implicitly to avoid unnecessary tedium. - The commands to use rings are `P' (put on) and `R' (remove). + The commands to use rings are `P' (put on) and `R' (remove). `A', `W', and `T' can also be used; see Amulets. 7.9. Spellbooks (`+') - Spellbooks are tomes of mighty magic. When studied with the `r' - (read) command, they transfer to the reader the knowledge of a spell + Spellbooks are tomes of mighty magic. When studied with the `r' + (read) command, they transfer to the reader the knowledge of a spell (and therefore eventually become unreadable)--unless the attempt back- - fires. Reading a cursed spellbook or one with mystic runes beyond + fires. Reading a cursed spellbook or one with mystic runes beyond your ken can be harmful to your health! - A spell (even when learned) can also backfire when you cast it. - If you attempt to cast a spell well above your experience level, or if - you have little skill with the appropriate spell type, or cast it at a - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -3370,63 +3370,63 @@ - time when your luck is particularly bad, you can end up wasting both + A spell (even when learned) can also backfire when you cast it. + If you attempt to cast a spell well above your experience level, or if + you have little skill with the appropriate spell type, or cast it at a + time when your luck is particularly bad, you can end up wasting both the energy and the time required in casting. - Casting a spell calls forth magical energies and focuses them - with your naked mind. Some of the magical energy released comes from + Casting a spell calls forth magical energies and focuses them + with your naked mind. Some of the magical energy released comes from within you. Casting temporarily drains your magical power, which will - slowly be recovered, and causes you to need additional food. Casting - of spells also requires practice. With practice, your skill in each + slowly be recovered, and causes you to need additional food. Casting + of spells also requires practice. With practice, your skill in each category of spell casting will improve. Over time, however, your mem- ory of each spell will dim, and you will need to relearn it. Some spells require a direction in which to cast them, similar to wands. To cast one at yourself, just give a `.' or `s' for the direc- - tion. A few spells require you to pick a target location rather than - just specify a particular direction. Other spells don't require any + tion. A few spells require you to pick a target location rather than + just specify a particular direction. Other spells don't require any direction or target. - Just as weapons are divided into groups in which a character can - become proficient (to varying degrees), spells are similarly grouped. - Successfully casting a spell exercises its skill group; using the - "#enhance" command to advance a sufficiently exercised skill will af- - fect all spells within the group. Advanced skill may increase the po- - tency of spells, reduce their risk of failure during casting attempts, - and improve the accuracy of the estimate for how much longer they will - be retained in your memory. Skill slots are shared with weapons - skills. (See also the section on "Weapon proficiency".) + Just as weapons are divided into groups in which a character can + become proficient (to varying degrees), spells are similarly grouped. + Successfully casting a spell exercises its skill group; using the + "#enhance" command to advance a sufficiently exercised skill will + affect all spells within the group. Advanced skill may increase the + potency of spells, reduce their risk of failure during casting + attempts, and improve the accuracy of the estimate for how much longer + they will be retained in your memory. Skill slots are shared with + weapons skills. (See also the section on "Weapon proficiency".) Casting a spell also requires flexible movement, and wearing var- ious types of armor may interfere with that. - The command to read a spellbook is the same as for scrolls, `r' - (read). The `+' command lists each spell you know along with its + The command to read a spellbook is the same as for scrolls, `r' + (read). The `+' command lists each spell you know along with its level, skill category, chance of failure when casting, and an estimate - of how strongly it is remembered. The `Z' (cast) command casts a + of how strongly it is remembered. The `Z' (cast) command casts a spell. 7.10. Tools (`(') - Tools are miscellaneous objects with various purposes. Some - tools have a limited number of uses, akin to wand charges. For exam- - ple, lamps burn out after a while. Other tools are containers, which + Tools are miscellaneous objects with various purposes. Some + tools have a limited number of uses, akin to wand charges. For exam- + ple, lamps burn out after a while. Other tools are containers, which objects can be placed into or taken out of. - Some tools (such as a blindfold) can be worn and can be put on - and removed like other accessories (rings, amulets); see Amulets. - Other tools (such as pick-axe) can be wielded as weapons in addition - to being applied for their usual purpose, and in some cases (again, + Some tools (such as a blindfold) can be worn and can be put on + and removed like other accessories (rings, amulets); see Amulets. + Other tools (such as pick-axe) can be wielded as weapons in addition + to being applied for their usual purpose, and in some cases (again, pick-axe) become wielded as a weapon even when applied. - The blind option can be set (prior to game start) to attempt to - play the entire game without being able to see (a self-imposed chal- - lenge which is very difficult to accomplish). + The blind option can be set (prior to game start) to attempt to + play the entire game without being able to see (a self-imposed chal- - - - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -3436,63 +3436,63 @@ + lenge which is very difficult to accomplish). + The command to use a tool is `a' (apply). 7.10.1. Containers - You may encounter bags, boxes, and chests in your travels. A + You may encounter bags, boxes, and chests in your travels. A tool of this sort can be opened with the "#loot" extended command when - you are standing on top of it (that is, on the same floor spot), or - with the `a' (apply) command when you are carrying it. However, - chests are often locked, and are in any case unwieldy objects. You - must set one down before unlocking it by using a key or lock-picking - tool with the `a' (apply) command, by kicking it with the `^D' com- - mand, or by using a weapon to force the lock with the "#force" ex- - tended command. + you are standing on top of it (that is, on the same floor spot), or + with the `a' (apply) command when you are carrying it. However, + chests are often locked, and are in any case unwieldy objects. You + must set one down before unlocking it by using a key or lock-picking + tool with the `a' (apply) command, by kicking it with the `^D' com- + mand, or by using a weapon to force the lock with the "#force" + extended command. - Some chests are trapped, causing nasty things to happen when you - unlock or open them. You can check for and try to deactivate traps + Some chests are trapped, causing nasty things to happen when you + unlock or open them. You can check for and try to deactivate traps with the "#untrap" extended command. - When the contents of a container are known, that container will - be described as something like "a sack containing 3 items". In this - example, the 3 refers to number of stacks of compatible items, not to - the total number of individual items. So a sack holding 2 sky blue - potions, 7 arrows, and 350 gold pieces would be described as having 3 - items rather than 10 or 359. And you would need to have 3 unused in- - ventory slots available in order to take everything out (for the case - where the items you remove don't combine into bigger stacks with + When the contents of a container are known, that container will + be described as something like "a sack containing 3 items". In this + example, the 3 refers to number of stacks of compatible items, not to + the total number of individual items. So a sack holding 2 sky blue + potions, 7 arrows, and 350 gold pieces would be described as having 3 + items rather than 10 or 359. And you would need to have 3 unused + inventory slots available in order to take everything out (for the + case where the items you remove don't combine into bigger stacks with things you're already carrying). If a chest or large box is described as "broken", that means that - it can't be locked rather than that it no longer functions as a con- + it can't be locked rather than that it no longer functions as a con- tainer. - The apply and loot commands allow you to take out and/or put in - an arbitrary number of items in a single operation. If you want to - take everything out of a container, you can use the "#tip" command to - pour the contents onto the floor. This may be your only way to get - things out if your hands are stuck to a cursed two-handed weapon. - When your hands aren't stuck, you have the potential to pour the con- - tents into another container. (As of this writing, the other con- + The apply and loot commands allow you to take out and/or put in + an arbitrary number of items in a single operation. If you want to + take everything out of a container, you can use the "#tip" command to + pour the contents onto the floor. This may be your only way to get + things out if your hands are stuck to a cursed two-handed weapon. + When your hands aren't stuck, you have the potential to pour the con- + tents into another container. (As of this writing, the other con- tainer must be carried rather than on the floor.) 7.11. Amulets (`"') Amulets are very similar to rings, and often more powerful. Like - rings, amulets have various magical properties, some beneficial, some + rings, amulets have various magical properties, some beneficial, some harmful, which are activated by putting them on. - Only one amulet may be worn at a time, around your neck. Like - wearing rings, wearing an amulet affects your metabolism, causing you + Only one amulet may be worn at a time, around your neck. Like + wearing rings, wearing an amulet affects your metabolism, causing you to grow hungry more rapidly. - The commands to use amulets are the same as for rings, `P' (put - on) and `R' (remove). `A' can be used to remove various worn items - including amulets. Also, `W' (wear) and `T' (take off) which are - NetHack 3.7.0 September 13, 2024 + + NetHack 3.7.0 November 16, 2024 @@ -3502,63 +3502,63 @@ - normally for armor can be used for amulets and other accessories - (rings and eyewear), but accessories won't be shown as likely candi- - dates in a prompt for choosing what to wear or take off. + The commands to use amulets are the same as for rings, `P' (put + on) and `R' (remove). `A' can be used to remove various worn items + including amulets. Also, `W' (wear) and `T' (take off) which are nor- + mally for armor can be used for amulets and other accessories (rings + and eyewear), but accessories won't be shown as likely candidates in a + prompt for choosing what to wear or take off. 7.12. Gems (`*') - Some gems are valuable, and can be sold for a lot of gold. They - are also a far more efficient way of carrying your riches. Valuable + Some gems are valuable, and can be sold for a lot of gold. They + are also a far more efficient way of carrying your riches. Valuable gems increase your score if you bring them with you when you exit. Other small rocks are also categorized as gems, but they are much - less valuable. All rocks, however, can be used as projectile weapons - (if you have a sling). In the most desperate of cases, you can still + less valuable. All rocks, however, can be used as projectile weapons + (if you have a sling). In the most desperate of cases, you can still throw them by hand. 7.13. Large rocks (``') - Statues and boulders are not particularly useful, and are gener- + Statues and boulders are not particularly useful, and are gener- ally heavy. It is rumored that some statues are not what they seem. - Boulders occasionally block your path. You can push one forward + Boulders occasionally block your path. You can push one forward (by attempting to walk onto its spot) when nothing blocks its path, or - you can smash it into a pile of small rocks with breaking magic or a + you can smash it into a pile of small rocks with breaking magic or a pick-axe. It is possible to move onto a boulder's location if certain conditions are met; ordinarily one of those conditions is that pushing - it any further be blocked. Using the move-without-picking-up prefix - (default key `m') prior to the direction of movement will attempt to - move to a boulder's location without pushing it in addition to the + it any further be blocked. Using the move-without-picking-up prefix + (default key `m') prior to the direction of movement will attempt to + move to a boulder's location without pushing it in addition to the prefix's usual action of suppressing auto-pickup at the destination. - Very large humanoids (giants and their ilk) have been known to + Very large humanoids (giants and their ilk) have been known to pick up boulders and use them as missile weapons. - Unlike boulders, statues can't be pushed, but don't need to be - because they don't block movement. They can be smashed into rocks + Unlike boulders, statues can't be pushed, but don't need to be + because they don't block movement. They can be smashed into rocks though. - For some configurations of the program, statues are no longer - shown as ``' but by the letter representing the monster they depict + For some configurations of the program, statues are no longer + shown as ``' but by the letter representing the monster they depict instead. 7.14. Gold (`$') Gold adds to your score, and you can buy things in shops with it. - There are a number of monsters in the dungeon that may be influenced + There are a number of monsters in the dungeon that may be influenced by the amount of gold you are carrying (shopkeepers aside). - Gold pieces are the only type of object where bless/curse state - does not apply. They're always uncursed but never described as un- - cursed even if you turn off the implicit_uncursed option. You can set - the goldX option if you prefer to have gold pieces be treated as - bless/curse state unknown rather than as known to be uncursed. Only - matters when you're using an object selection prompt that can filter - by "BUCX" state. + Gold pieces are the only type of object where bless/curse state + does not apply. They're always uncursed but never described as + uncursed even if you turn off the implicit_uncursed option. You can + set the goldX option if you prefer to have gold pieces be treated as - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -3568,63 +3568,63 @@ + bless/curse state unknown rather than as known to be uncursed. Only + matters when you're using an object selection prompt that can filter + by "BUCX" state. + 7.15. Persistence of Objects Normally, if you have seen an object at a particular map location - and move to another location where you can't directly see that object - any more, it will continue to be displayed on your map. That remains - the case even if it is not actually there any more--perhaps a monster + and move to another location where you can't directly see that object + any more, it will continue to be displayed on your map. That remains + the case even if it is not actually there any more--perhaps a monster has picked it up or it has rotted away--until you can see or feel that location again. One notable exception is that if the object gets cov- - ered by the "remembered, unseen monster" marker. When that marker is + ered by the "remembered, unseen monster" marker. When that marker is later removed after you've verified that no monster is there, you will - have forgotten that there was any object there regardless of whether - the unseen monster actually took the object. If the object is still - there, then once you see or feel that location again you will re-dis- + have forgotten that there was any object there regardless of whether + the unseen monster actually took the object. If the object is still + there, then once you see or feel that location again you will re-dis- cover the object and resume remembering it. The situation is the same for a pile of objects, except that only - the top item of the pile is displayed. The hilite_pile option can be + the top item of the pile is displayed. The hilite_pile option can be enabled in order to show an item differently when it is the top one of a pile. 8. Conduct - As if winning NetHack were not difficult enough, certain players - seek to challenge themselves by imposing restrictions on the way they - play the game. The game automatically tracks some of these chal- - lenges, which can be checked at any time with the #conduct command or - at the end of the game. When you perform an action which breaks a - challenge, it will no longer be listed. This gives players extra - "bragging rights" for winning the game with these challenges. Note - that it is perfectly acceptable to win the game without resorting to - these restrictions and that it is unusual for players to adhere to + As if winning NetHack were not difficult enough, certain players + seek to challenge themselves by imposing restrictions on the way they + play the game. The game automatically tracks some of these chal- + lenges, which can be checked at any time with the #conduct command or + at the end of the game. When you perform an action which breaks a + challenge, it will no longer be listed. This gives players extra + "bragging rights" for winning the game with these challenges. Note + that it is perfectly acceptable to win the game without resorting to + these restrictions and that it is unusual for players to adhere to challenges the first time they win the game. - Several of the challenges are related to eating behavior. The + Several of the challenges are related to eating behavior. The most difficult of these is the foodless challenge. Although creatures - can survive long periods of time without food, there is a physiologi- - cal need for water; thus there is no restriction on drinking bever- - ages, even if they provide some minor food benefits. Calling upon + can survive long periods of time without food, there is a physiologi- + cal need for water; thus there is no restriction on drinking bever- + ages, even if they provide some minor food benefits. Calling upon your god for help with starvation does not violate any food challenges either. - A strict vegan diet is one which avoids any food derived from an- - imals. The primary source of nutrition is fruits and vegetables. The - corpses and tins of blobs (`b'), jellies (`j'), and fungi (`F') are - also considered to be vegetable matter. Certain human food is pre- - pared without animal products; namely, lembas wafers, cram rations, - food rations (gunyoki), K-rations, and C-rations. Metal or another + A strict vegan diet is one which avoids any food derived from + animals. The primary source of nutrition is fruits and vegetables. + The corpses and tins of blobs (`b'), jellies (`j'), and fungi (`F') + are also considered to be vegetable matter. Certain human food is + prepared without animal products; namely, lembas wafers, cram rations, + food rations (gunyoki), K-rations, and C-rations. Metal or another normally indigestible material eaten while polymorphed into a creature - that can digest it is also considered vegan food. Note however that + that can digest it is also considered vegan food. Note however that eating such items still counts against foodless conduct. - Vegetarians do not eat animals; however, they are less selective - about eating animal byproducts than vegans. In addition to the vegan - items listed above, they may eat any kind of pudding (`P') other than - - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -3634,63 +3634,63 @@ - the black puddings, eggs and food made from eggs (fortune cookies and - pancakes), food made with milk (cream pies and candy bars), and lumps + Vegetarians do not eat animals; however, they are less selective + about eating animal byproducts than vegans. In addition to the vegan + items listed above, they may eat any kind of pudding (`P') other than + the black puddings, eggs and food made from eggs (fortune cookies and + pancakes), food made with milk (cream pies and candy bars), and lumps of royal jelly. Monks are expected to observe a vegetarian diet. Eating any kind of meat violates the vegetarian, vegan, and food- - less conducts. This includes tripe rations, the corpses or tins of + less conducts. This includes tripe rations, the corpses or tins of any monsters not mentioned above, and the various other chunks of meat - found in the dungeon. Swallowing and digesting a monster while poly- - morphed is treated as if you ate the creature's corpse. Eating - leather, dragon hide, or bone items while polymorphed into a creature - that can digest it, or eating monster brains while polymorphed into a - mind flayer, is considered eating an animal, although wax is only an + found in the dungeon. Swallowing and digesting a monster while poly- + morphed is treated as if you ate the creature's corpse. Eating + leather, dragon hide, or bone items while polymorphed into a creature + that can digest it, or eating monster brains while polymorphed into a + mind flayer, is considered eating an animal, although wax is only an animal byproduct. - Regardless of conduct, there will be some items which are indi- + Regardless of conduct, there will be some items which are indi- gestible, and others which are hazardous to eat. Using a swallow-and- - digest attack against a monster is equivalent to eating the monster's - corpse. Please note that the term "vegan" is used here only in the - context of diet. You are still free to choose not to use or wear - items derived from animals (e.g. leather, dragon hide, bone, horns, - coral), but the game will not keep track of this for you. Also note - that "milky" potions may be a translucent white, but they do not con- - tain milk, so they are compatible with a vegan diet. Slime molds or - player-defined "fruits", although they could be anything from "cher- + digest attack against a monster is equivalent to eating the monster's + corpse. Please note that the term "vegan" is used here only in the + context of diet. You are still free to choose not to use or wear + items derived from animals (e.g. leather, dragon hide, bone, horns, + coral), but the game will not keep track of this for you. Also note + that "milky" potions may be a translucent white, but they do not con- + tain milk, so they are compatible with a vegan diet. Slime molds or + player-defined "fruits", although they could be anything from "cher- ries" to "pork chops", are also assumed to be vegan. An atheist is one who rejects religion. This means that you can- not #pray, #offer sacrifices to any god, #turn undead, or #chat with a priest. Particularly selective readers may argue that playing Monk or - Priest characters should violate this conduct; that is a choice left + Priest characters should violate this conduct; that is a choice left to the player. Offering the Amulet of Yendor to your god is necessary to win the game and is not counted against this conduct. You are also - not penalized for being spoken to by an angry god, priest(ess), or + not penalized for being spoken to by an angry god, priest(ess), or other religious figure; a true atheist would hear the words but attach no special meaning to them. - Most players fight with a wielded weapon (or tool intended to be - wielded as a weapon). Another challenge is to win the game without - using such a wielded weapon. You are still permitted to throw, fire, - and kick weapons; use a wand, spell, or other type of item; or fight + Most players fight with a wielded weapon (or tool intended to be + wielded as a weapon). Another challenge is to win the game without + using such a wielded weapon. You are still permitted to throw, fire, + and kick weapons; use a wand, spell, or other type of item; or fight with your hands and feet. - In NetHack, a pacifist refuses to cause the death of any other - monster (i.e. if you would get experience for the death). This is a - particularly difficult challenge, although it is still possible to + In NetHack, a pacifist refuses to cause the death of any other + monster (i.e. if you would get experience for the death). This is a + particularly difficult challenge, although it is still possible to gain experience by other means. - An illiterate character does not read or write. This includes + An illiterate character does not read or write. This includes reading a scroll, spellbook, fortune cookie message, or t-shirt; writ- - ing a scroll; or making an engraving of anything other than a single - "X" (the traditional signature of an illiterate person). Reading an - engraving, or any item that is absolutely necessary to win the game, - is not counted against this conduct. The identity of scrolls and - spellbooks (and knowledge of spells) in your starting inventory is + ing a scroll; or making an engraving of anything other than a single + "X" (the traditional signature of an illiterate person). Reading an - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -3700,63 +3700,63 @@ - assumed to be learned from your teachers prior to the start of the + engraving, or any item that is absolutely necessary to win the game, + is not counted against this conduct. The identity of scrolls and + spellbooks (and knowledge of spells) in your starting inventory is + assumed to be learned from your teachers prior to the start of the game and isn't counted. - There is a side-branch to the main dungeon called "Sokoban," - briefly described in the earlier section about Traps. As mentioned - there, the goal is to push boulders into pits and/or holes to plug - those in order to both get the boulders out of the way and be able to - go past the traps. There are some special "rules" that are active - when in that branch of the dungeon. Some rules can't be bypassed, - such as being unable to push a boulder diagonally. Other rules can, + There is a side-branch to the main dungeon called "Sokoban," + briefly described in the earlier section about Traps. As mentioned + there, the goal is to push boulders into pits and/or holes to plug + those in order to both get the boulders out of the way and be able to + go past the traps. There are some special "rules" that are active + when in that branch of the dungeon. Some rules can't be bypassed, + such as being unable to push a boulder diagonally. Other rules can, such as not smashing boulders with magic or tools, but doing so causes - you to receive a luck penalty. No message about that is given at the + you to receive a luck penalty. No message about that is given at the time, but it is tracked as a conduct. The #conduct command and end of - game disclosure will report whether you have abided by the special - rules of Sokoban, and if not, how many times you violated them, pro- + game disclosure will report whether you have abided by the special + rules of Sokoban, and if not, how many times you violated them, pro- viding you with a way to discover which actions incur bad luck so that - you can be better informed about whether or not to avoid repeating + you can be better informed about whether or not to avoid repeating those actions in the future. (Note: the Sokoban conduct will only be displayed if you have entered the Sokoban branch of the dungeon during - the current game. Once that has happened, it becomes part of dis- - closed conduct even if you haven't done anything interesting there. - Ending the game with "never broke the Sokoban rules" conduct is most - meaningful if you also manage to perform the "obtained the Sokoban + the current game. Once that has happened, it becomes part of dis- + closed conduct even if you haven't done anything interesting there. + Ending the game with "never broke the Sokoban rules" conduct is most + meaningful if you also manage to perform the "obtained the Sokoban prize" achievement (see Achievements below).) - There are several other challenges tracked by the game. It is - possible to eliminate one or more species of monsters by genocide; + There are several other challenges tracked by the game. It is + possible to eliminate one or more species of monsters by genocide; playing without this feature is considered a challenge. When the game - offers you an opportunity to genocide monsters, you may respond with - the monster type "none" if you want to decline. You can change the - form of an item into another item of the same type ("polypiling") or - the form of your own body into another creature ("polyself") by wand, + offers you an opportunity to genocide monsters, you may respond with + the monster type "none" if you want to decline. You can change the + form of an item into another item of the same type ("polypiling") or + the form of your own body into another creature ("polyself") by wand, spell, or potion of polymorph; avoiding these effects are each consid- - ered challenges. Polymorphing monsters, including pets, does not - break either of these challenges. Finally, you may sometimes receive - wishes; a game without an attempt to wish for any items is a chal- + ered challenges. Polymorphing monsters, including pets, does not + break either of these challenges. Finally, you may sometimes receive + wishes; a game without an attempt to wish for any items is a chal- lenge, as is a game without wishing for an artifact (even if the arti- fact immediately disappears). When the game offers you an opportunity - to make a wish for an item, you may choose "nothing" if you want to + to make a wish for an item, you may choose "nothing" if you want to decline. 8.1. Achievements - End of game disclosure will also display various achievements - representing progress toward ultimate ascension, if any have been at- - tained. They aren't directly related to conduct but are grouped with - it because they fall into the same category of "bragging rights" and - to limit the number of questions during disclosure. Listed here - roughly in order of difficulty and not necessarily in the order in + End of game disclosure will also display various achievements + representing progress toward ultimate ascension, if any have been + attained. They aren't directly related to conduct but are grouped + with it because they fall into the same category of "bragging rights" + and to limit the number of questions during disclosure. Listed here + roughly in order of difficulty and not necessarily in the order in which you might accomplish them. - Rank - Attained rank title Rank. - Shop - Entered a shop. - - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -3766,6 +3766,8 @@ + Rank - Attained rank title Rank. + Shop - Entered a shop. Temple - Entered a temple. Mines - Entered the Gnomish Mines. Town - Entered Mine Town. @@ -3773,12 +3775,12 @@ Novel - Read a passage from a Discworld Novel. Sokoban - Entered Sokoban. Big Room - Entered the Big Room. - Soko-Prize - Explored to the top of Sokoban and found a + Soko-Prize - Explored to the top of Sokoban and found a special item there. - Mines' End - Explored to the bottom of the Gnomish Mines + Mines' End - Explored to the bottom of the Gnomish Mines and found a special item there. Medusa - Defeated Medusa. - Tune - Discovered the tune that can be used to open + Tune - Discovered the tune that can be used to open and close the drawbridge on the Castle level. Bell - Acquired the Bell of Opening. Gehennom - Entered Gehennom. @@ -3798,31 +3800,29 @@ Notes: - Achievements are recorded and subsequently reported in the order - in which they happen during your current game rather than the order + Achievements are recorded and subsequently reported in the order + in which they happen during your current game rather than the order listed here. - There are nine titles for each role, bestowed at experi- - ence levels 1, 3, 6, 10, 14, 18, 22, 26, and 30. The one for experi- - ence level 1 is not recorded as an achievement. Losing enough levels + There are nine titles for each role, bestowed at experi- + ence levels 1, 3, 6, 10, 14, 18, 22, 26, and 30. The one for experi- + ence level 1 is not recorded as an achievement. Losing enough levels to revert to lower rank(s) does not discard the corresponding achieve- ment(s). - There's no guaranteed Novel so the achievement to read one might - not always be attainable (except perhaps by wishing). Similarly, the - Big Room level is not always present. Unlike with the Novel, there's + There's no guaranteed Novel so the achievement to read one might + not always be attainable (except perhaps by wishing). Similarly, the + Big Room level is not always present. Unlike with the Novel, there's no way to wish for this opportunity. - The "special items" hidden in Mines' End and Sokoban are not - unique but are considered to be prizes or rewards for exploring those - levels since doing so is not necessary to complete the game. Finding - other instances of the same objects doesn't record the corresponding + The "special items" hidden in Mines' End and Sokoban are not + unique but are considered to be prizes or rewards for exploring those + levels since doing so is not necessary to complete the game. Finding + other instances of the same objects doesn't record the corresponding achievement. - - - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -3832,63 +3832,63 @@ - The Medusa achievement is recorded if she dies for any reason, + The Medusa achievement is recorded if she dies for any reason, even if you are not directly responsible, and only if she dies. The 5-note tune can be learned via trial and error with a musical - instrument played closely enough--but not too close!--to the Castle + instrument played closely enough--but not too close!--to the Castle level's drawbridge or can be given to you via prayer boon. - Blind, Deaf, Nudist, and Pauper are also conducts, and they can - only be enabled by setting the correspondingly named option in + Blind, Deaf, Nudist, and Pauper are also conducts, and they can + only be enabled by setting the correspondingly named option in NETHACKOPTIONS or run-time configuration file prior to game start. In - the case of Blind and Deaf, the option also enforces the conduct. - They aren't really significant accomplishments unless/until you make + the case of Blind and Deaf, the option also enforces the conduct. + They aren't really significant accomplishments unless/until you make substantial progress into the dungeon. 9. Options - Due to variations in personal tastes and conceptions of how - NetHack should do things, there are options you can set to change how + Due to variations in personal tastes and conceptions of how + NetHack should do things, there are options you can set to change how NetHack behaves. 9.1. Setting the options Options may be set in a number of ways. Within the game, the `O' - command allows you to view all options and change most of them. You - can also set options automatically by placing them in a configuration + command allows you to view all options and change most of them. You + can also set options automatically by placing them in a configuration file, or in the NETHACKOPTIONS environment variable. Some versions of - NetHack also have front-end programs that allow you to set options be- - fore starting the game or a global configuration for system adminis- + NetHack also have front-end programs that allow you to set options + before starting the game or a global configuration for system adminis- trators. 9.2. Using a configuration file - The default name of the configuration file varies on different + The default name of the configuration file varies on different operating systems. - On UNIX, Linux, and macOS it is ".nethackrc" in the user's home + On UNIX, Linux, and macOS it is ".nethackrc" in the user's home directory. The file may not exist, but it is a normal ASCII text file and can be created with any text editor. - On Windows, the name is ".nethackrc" located in the folder - "%USERPROFILE%\NetHack\". The file may not exist, but it is a normal - ASCII text file can can be created with any text editor. After run- - ning NetHack for the first time, you should find a default template - for the configuration file named ".nethackrc.template" in - "%USERPROFILE%\NetHack\". If you have not created the configuration + On Windows, the name is ".nethackrc" located in the folder + "%USERPROFILE%\NetHack\". The file may not exist, but it is a normal + ASCII text file can can be created with any text editor. After run- + ning NetHack for the first time, you should find a default template + for the configuration file named ".nethackrc.template" in + "%USERPROFILE%\NetHack\". If you have not created the configuration file, NetHack will create one for you using the default template file. On MS-DOS, it is "defaults.nh" in the same folder as nethack.exe. - Any line in the configuration file starting with `#' is treated + Any line in the configuration file starting with `#' is treated as a comment and ignored. Empty lines are ignored. Any line beginning with `[' and ending in `]' is a section marker - (the closing `]' can be followed by whitespace and then an arbitrary + (the closing `]' can be followed by whitespace and then an arbitrary - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -3898,29 +3898,29 @@ - comment beginning with `#'). The text between the square brackets is - the section name. Section markers are only valid after a CHOOSE di- - rective and their names are case insensitive. Lines after a section - marker belong to that section up until another section starts or a - marker without a name is encountered or the file ends. Lines within - sections are ignored unless a CHOOSE directive has selected that sec- + comment beginning with `#'). The text between the square brackets is + the section name. Section markers are only valid after a CHOOSE + directive and their names are case insensitive. Lines after a section + marker belong to that section up until another section starts or a + marker without a name is encountered or the file ends. Lines within + sections are ignored unless a CHOOSE directive has selected that sec- tion. - You can use different configuration directives in the file, some - of which can be used multiple times. In general, the directives are - written in capital letters, followed by an equals sign, followed by + You can use different configuration directives in the file, some + of which can be used multiple times. In general, the directives are + written in capital letters, followed by an equals sign, followed by settings particular to that directive. Here is a list of allowed directives: OPTIONS There are two types of options, boolean and compound options. Bool- - ean options toggle a setting on or off, while compound options take - more diverse values. Prefix a boolean option with "no" or `!' to - turn it off. For compound options, the option name and value are - separated by a colon. Some options are persistent, and apply only + ean options toggle a setting on or off, while compound options take + more diverse values. Prefix a boolean option with "no" or `!' to + turn it off. For compound options, the option name and value are + separated by a colon. Some options are persistent, and apply only to new games. You can specify multiple OPTIONS directives, and mul- - tiple options separated by commas in a single OPTIONS directive. + tiple options separated by commas in a single OPTIONS directive. (Comma separated options are processed from right to left.) Example: @@ -3930,15 +3930,15 @@ HACKDIR Default location of files NetHack needs. On Windows HACKDIR defaults - to the location of the NetHack.exe or NetHackw.exe file so setting + to the location of the NetHack.exe or NetHackw.exe file so setting HACKDIR to override that is not usually necessary or recommended. LEVELDIR - The location that in-progress level files are stored. Defaults to + The location that in-progress level files are stored. Defaults to HACKDIR, must be writable. SAVEDIR - The location where saved games are kept. Defaults to HACKDIR, must + The location where saved games are kept. Defaults to HACKDIR, must be writable. BONESDIR @@ -3950,11 +3950,11 @@ HACKDIR, must be writable. TROUBLEDIR - The location that a record of game aborts and self-diagnosed game + The location that a record of game aborts and self-diagnosed game problems is kept. Defaults to HACKDIR, must be writable. - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -3965,9 +3965,9 @@ AUTOCOMPLETE - Enable or disable an extended command autocompletion. Autocomple- + Enable or disable an extended command autocompletion. Autocomple- tion has no effect for the X11 windowport. You can specify multiple - autocompletions. To enable autocompletion, list the extended com- + autocompletions. To enable autocompletion, list the extended com- mand. Prefix the command with "!" to disable the autocompletion for that command. @@ -3976,13 +3976,13 @@ AUTOCOMPLETE=zap,!annotate AUTOPICKUP_EXCEPTION - Set exceptions to the pickup_types option. See the "Configuring Au- - topickup Exceptions" section. + Set exceptions to the pickup_types option. See the "Configuring + Autopickup Exceptions" section. BINDINGS - Change the key bindings of some special keys, menu accelerators, ex- - tended commands, or mouse buttons. You can specify multiple bind- - ings. Format is key followed by the command, separated by a colon. + Change the key bindings of some special keys, menu accelerators, + extended commands, or mouse buttons. You can specify multiple bind- + ings. Format is key followed by the command, separated by a colon. See the "Changing Key Bindings" section for more information. Example: @@ -4005,22 +4005,22 @@ OPTIONS=!rest_on_space If [] is present, the preceding section is closed and no new section - begins; whatever follows will be common to all sections. Otherwise + begins; whatever follows will be common to all sections. Otherwise the last section extends to the end of the options file. MENUCOLOR - Highlight menu lines with different colors. See the "Configuring + Highlight menu lines with different colors. See the "Configuring Menu Colors" section. MSGTYPE - Change the way messages are shown in the top status line. See the + Change the way messages are shown in the top status line. See the "Configuring Message Types" section. ROGUESYMBOLS Custom symbols for the rogue level's symbol set. See SYMBOLS below. - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -4034,12 +4034,12 @@ Define a sound mapping. See the "Configuring User Sounds" section. SOUNDDIR - Define the directory that contains the sound files. See the "Con- + Define the directory that contains the sound files. See the "Con- figuring User Sounds" section. SYMBOLS - Override one or more symbols in the symbol set used for all dungeon - levels except for the special rogue level. See the "Modifying + Override one or more symbols in the symbol set used for all dungeon + levels except for the special rogue level. See the "Modifying NetHack Symbols" section. Example: @@ -4049,8 +4049,8 @@ WIZKIT Debug mode only: extra items to add to initial inventory. Value is - the name of a text file containing a list of item names, one per - line, up to a maximum of 128 lines. Each line is processed by the + the name of a text file containing a list of item names, one per + line, up to a maximum of 128 lines. Each line is processed by the function that handles wishing. Example: @@ -4081,12 +4081,12 @@ 9.3. Using the NETHACKOPTIONS environment variable - The NETHACKOPTIONS variable is a comma-separated list of initial - values for the various options. Some can only be turned on or off. + The NETHACKOPTIONS variable is a comma-separated list of initial + values for the various options. Some can only be turned on or off. You turn one of these on by adding the name of the option to the list, - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -4096,19 +4096,19 @@ - and turn it off by typing a `!' or "no" before the name. Others take - a character string as a value. You can set string options by typing - the option name, a colon or equals sign, and then the value of the - string. The value is terminated by the next comma or the end of + and turn it off by typing a `!' or "no" before the name. Others take + a character string as a value. You can set string options by typing + the option name, a colon or equals sign, and then the value of the + string. The value is terminated by the next comma or the end of string. - For example, to set up an environment variable so that color is - on, legacy is off, character name is set to "Blue Meanie", and named + For example, to set up an environment variable so that color is + on, legacy is off, character name is set to "Blue Meanie", and named fruit is set to "lime", you would enter the command % setenv NETHACKOPTIONS "color,\!leg,name:Blue Meanie,fruit:lime" - in csh (note the need to escape the `!' since it's special to that + in csh (note the need to escape the `!' since it's special to that shell), or the pair of commands $ NETHACKOPTIONS="color,!leg,name:Blue Meanie,fruit:lime" @@ -4116,25 +4116,25 @@ in sh, ksh, or bash. - The NETHACKOPTIONS value is effectively the same as a single OP- - TIONS directive in a configuration file. The "OPTIONS=" prefix is im- - plied and comma separated options are processed from right to left. - Other types of configuration directives such as BIND or MSGTYPE are + The NETHACKOPTIONS value is effectively the same as a single + OPTIONS directive in a configuration file. The "OPTIONS=" prefix is + implied and comma separated options are processed from right to left. + Other types of configuration directives such as BIND or MSGTYPE are not allowed. - Instead of a comma-separated list of options, NETHACKOPTIONS can - be set to the full name of a configuration file you want to use. If - that full name doesn't start with a slash, precede it with `@' (at- - sign) to let NetHack know that the rest is intended as a file name. + Instead of a comma-separated list of options, NETHACKOPTIONS can + be set to the full name of a configuration file you want to use. If + that full name doesn't start with a slash, precede it with `@' (at- + sign) to let NetHack know that the rest is intended as a file name. If it does start with `/', the at-sign is optional. 9.4. Customization options - Here are explanations of what the various options do. Character - strings that are too long may be truncated. Some of the options + Here are explanations of what the various options do. Character + strings that are too long may be truncated. Some of the options listed may be inactive in your dungeon. - Some options are persistent, and are saved and reloaded along + Some options are persistent, and are saved and reloaded along with the game. Changing a persistent option in the configuration file applies only to new games. @@ -4142,17 +4142,17 @@ Add location or direction information to messages (default is off). acoustics - Enable messages about what your character hears (default on). Note + Enable messages about what your character hears (default on). Note that this has nothing to do with your computer's audio capabilities. Persistent. alignment - Your starting alignment (align:lawful, align:neutral, or - align:chaotic). You may specify just the first letter. Many roles - and the non-human races restrict which alignments are allowed. See + Your starting alignment (align:lawful, align:neutral, or + align:chaotic). You may specify just the first letter. Many roles + and the non-human races restrict which alignments are allowed. See - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -4167,8 +4167,8 @@ Default is random. Cannot be set with the `O' command. Persistent. autodescribe - Automatically describe the terrain under cursor when asked to get a - location on the map (default true). The whatis_coord option con- + Automatically describe the terrain under cursor when asked to get a + location on the map (default true). The whatis_coord option con- trols whether the description includes map coordinates. autodig @@ -4180,45 +4180,45 @@ sistent. autopickup - Automatically pick up things onto which you move (default off). + Automatically pick up things onto which you move (default off). Persistent. - See pickup_types and also autopickup_exception for ways to refine + See pickup_types and also autopickup_exception for ways to refine the behavior. Note: prior to version 3.7.0, the default for autopickup was on. autoquiver - This option controls what happens when you attempt the `f' (fire) - command when nothing is quivered or readied (default false). When - true, the computer will fill your quiver or quiver sack or make + This option controls what happens when you attempt the `f' (fire) + command when nothing is quivered or readied (default false). When + true, the computer will fill your quiver or quiver sack or make ready some suitable weapon. Note that it will not take into account - the blessed/cursed status, enchantment, damage, or quality of the - weapon; you are free to manually fill your quiver or quiver sack or - make ready with the `Q' command instead. If no weapon is found or - the option is false, the `t' (throw) command is executed instead. + the blessed/cursed status, enchantment, damage, or quality of the + weapon; you are free to manually fill your quiver or quiver sack or + make ready with the `Q' command instead. If no weapon is found or + the option is false, the `t' (throw) command is executed instead. Persistent. autounlock - Controls what action to take when attempting to walk into a locked - door or to loot a locked container. Takes a plus-sign separated + Controls what action to take when attempting to walk into a locked + door or to loot a locked container. Takes a plus-sign separated list of values: Untrap - prompt about whether to attempt to find a trap; it might fail to find one even when present; if it does find one, - it will ask whether you want to try to disarm the trap; + it will ask whether you want to try to disarm the trap; if you decline, your character will forget that the door or box is trapped; - Apply-Key - if carrying a key or other unlocking tool, prompt about + Apply-Key - if carrying a key or other unlocking tool, prompt about using it; - Kick - kick the door (if you omit untrap or decline to attempt - untrap and you omit apply-key or you lack a key or you + Kick - kick the door (if you omit untrap or decline to attempt + untrap and you omit apply-key or you lack a key or you decline to use the key; has no effect on containers); - Force - try to force a container's lid with your currently + Force - try to force a container's lid with your currently wielded weapon (if you omit untrap or decline to attempt - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -4228,18 +4228,18 @@ - untrap and you omit apply-key or you lack a key or you + untrap and you omit apply-key or you lack a key or you decline to use the key; has no effect on doors); - None - none of the above; can't be combined with the other + None - none of the above; can't be combined with the other choices. Omitting the value is treated as if autounlock:apply-key. Preceding autounlock with `!' or "no" is treated as autounlock:none. - Applying a key might set off a trap if the door or container is - trapped. Successfully kicking a door will break it and wake up - nearby monsters. Successfully forcing a container open will break - its lock and might also destroy some of its contents or damage your + Applying a key might set off a trap if the door or container is + trapped. Successfully kicking a door will break it and wake up + nearby monsters. Successfully forcing a container open will break + its lock and might also destroy some of its contents or damage your weapon or both. The default is Apply-Key. Persistent. @@ -4251,15 +4251,15 @@ Allow saving and loading bones files (default true). Persistent. boulder - Set the character used to display boulders (default is the "large + Set the character used to display boulders (default is the "large rock" class symbol, ``'). catname - Name your starting cat (for example "catname:Morris"). Cannot be + Name your starting cat (for example "catname:Morris"). Cannot be set with the `O' command. character - Synonym for "role" to pick the type of your character (for example + Synonym for "role" to pick the type of your character (for example "character:Monk"). See role for more details. checkpoint @@ -4267,11 +4267,11 @@ program crash (default on). Persistent. cmdassist - Have the game provide some additional command assistance for new + Have the game provide some additional command assistance for new players if it detects some anticipated mistakes (default on). confirm - Have user confirm attacks on pets, shopkeepers, and other peaceable + Have user confirm attacks on pets, shopkeepers, and other peaceable creatures (default on). Persistent. dark_room @@ -4281,10 +4281,10 @@ Start the character permanently deaf (default false). Persistent. dropped_nopick - If this option is on, items you dropped will not be automatically + If this option is on, items you dropped will not be automatically - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -4294,12 +4294,12 @@ - picked up, even if autopickup is also on and they are in - pickup_types or match a positive autopickup exception (default on). + picked up, even if autopickup is also on and they are in + pickup_types or match a positive autopickup exception (default on). Persistent. disclose - Controls what information the program reveals when the game ends. + Controls what information the program reveals when the game ends. Value is a space separated list of prompting/category pairs (default is "ni na nv ng nc no", prompt with default response of `n' for each candidate). Persistent. The possibilities are: @@ -4311,7 +4311,7 @@ c - display your conduct; also achievements, if any; o - display dungeon overview. - Each disclosure possibility can optionally be preceded by a prefix + Each disclosure possibility can optionally be preceded by a prefix which lets you refine how it behaves. Here are the valid prefixes: y - prompt you and default to yes on the prompt; @@ -4319,38 +4319,38 @@ + - disclose it without prompting; - - do not disclose it and do not prompt. - The listings of vanquished monsters and of genocided types can be + The listings of vanquished monsters and of genocided types can be sorted, so there are two additional choices for `v' and `g': ? - prompt you and default to ask on the prompt; # - disclose it without prompting, ask for sort order. - Asking refers to picking one of the orderings from a menu. The `+' - disclose without prompting choice, or being prompted and answering - `y' rather than `a', will default to showing monsters in the order + Asking refers to picking one of the orderings from a menu. The `+' + disclose without prompting choice, or being prompted and answering + `y' rather than `a', will default to showing monsters in the order specified by the sortvanquished option. - Omitted categories are implicitly added with `n' prefix. Specified - categories with omitted prefix implicitly use `+' prefix. Order of - the disclosure categories does not matter, program display for end- + Omitted categories are implicitly added with `n' prefix. Specified + categories with omitted prefix implicitly use `+' prefix. Order of + the disclosure categories does not matter, program display for end- of-game disclosure follows a set sequence. (for example "disclose:yi na +v -g o") The example sets inventory to - prompt and default to yes, attributes to prompt and default to no, - vanquished to disclose without prompting, genocided to not disclose - and not prompt, conduct to implicitly prompt and default to no, and + prompt and default to yes, attributes to prompt and default to no, + vanquished to disclose without prompting, genocided to not disclose + and not prompt, conduct to implicitly prompt and default to no, and overview to disclose without prompting. - Note that the vanquished monsters list includes all monsters killed + Note that the vanquished monsters list includes all monsters killed by traps and each other as well as by you. And the dungeon overview - shows all levels you had visited but does not reveal things about + shows all levels you had visited but does not reveal things about them that you hadn't discovered. dogname - Name your starting dog (for example "dogname:Fang"). Cannot be set + Name your starting dog (for example "dogname:Fang"). Cannot be set - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -4363,14 +4363,14 @@ with the `O' command. extmenu - Changes the extended commands interface to pop-up a menu of avail- - able commands. It is keystroke compatible with the traditional in- - terface except that it does not require that you hit Enter. It is + Changes the extended commands interface to pop-up a menu of avail- + able commands. It is keystroke compatible with the traditional + interface except that it does not require that you hit Enter. It is implemented for the tty interface (default off). - For the X11 interface, which always uses a menu for choosing an ex- - tended command, it controls whether the menu shows all available - commands (on) or just the subset of commands which have tradition- + For the X11 interface, which always uses a menu for choosing an + extended command, it controls whether the menu shows all available + commands (on) or just the subset of commands which have tradition- ally been considered extended ones (off). female @@ -4378,32 +4378,32 @@ command. fireassist - This option controls what happens when you attempt the `f' (fire) - and don't have an appropriate launcher, such as a bow or a sling, - wielded. If on, you will automatically wield the launcher. Default + This option controls what happens when you attempt the `f' (fire) + and don't have an appropriate launcher, such as a bow or a sling, + wielded. If on, you will automatically wield the launcher. Default is on. fixinv An object's inventory letter sticks to it when it's dropped (default - on). If this is off, dropping an object shifts all the remaining + on). If this is off, dropping an object shifts all the remaining inventory letters. Persistent. force_invmenu - Commands asking for an inventory item show a menu instead of a text + Commands asking for an inventory item show a menu instead of a text query with possible menu letters. Default is off. fruit - Name a fruit after something you enjoy eating (for example + Name a fruit after something you enjoy eating (for example "fruit:mango") (default "slime mold"). Basically a nostalgic whimsy - that NetHack uses from time to time. You should set this to some- - thing you find more appetizing than slime mold. Apples, oranges, - pears, bananas, and melons already exist in NetHack, so don't use + that NetHack uses from time to time. You should set this to some- + thing you find more appetizing than slime mold. Apples, oranges, + pears, bananas, and melons already exist in NetHack, so don't use those. gender - Your starting gender (gender:male or gender:female). You may spec- - ify just the first letter. Although you can still denote your gen- - der using either of the deprecated male and female options, if the + Your starting gender (gender:male or gender:female). You may spec- + ify just the first letter. Although you can still denote your gen- + der using either of the deprecated male and female options, if the gender option is also present it will take precedence. See role for a description of how to use negation to exclude choices. @@ -4411,12 +4411,12 @@ goldX When filtering objects based on bless/curse state (BUCX), whether to - treat gold pieces as X (unknown bless/curse state, when "on") or U - (known to be uncursed, when "off", the default). Gold is never - blessed or cursed, but it is not described as "uncursed" even when + treat gold pieces as X (unknown bless/curse state, when "on") or U + (known to be uncursed, when "off", the default). Gold is never + blessed or cursed, but it is not described as "uncursed" even when - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -4429,60 +4429,60 @@ the implicit_uncursed option is "off". help - If more information is available for an object looked at with the - `/' command, ask if you want to see it (default on). Turning help - off makes just looking at things faster, since you aren't inter- - rupted with the "More info?" prompt, but it also means that you - might miss some interesting and/or important information. Persis- + If more information is available for an object looked at with the + `/' command, ask if you want to see it (default on). Turning help + off makes just looking at things faster, since you aren't inter- + rupted with the "More info?" prompt, but it also means that you + might miss some interesting and/or important information. Persis- tent. herecmd_menu When using a windowport that supports mouse and clicking on yourself - or next to you, show a menu of possible actions for the location. + or next to you, show a menu of possible actions for the location. Same as "#herecmdmenu" and "#therecmdmenu" commands. hilite_pet - Visually distinguish pets from similar animals (default off). The - behavior of this option depends on the type of windowing you use. + Visually distinguish pets from similar animals (default off). The + behavior of this option depends on the type of windowing you use. In text windowing, text highlighting or inverse video is often used; with tiles, generally displays a heart symbol near pets. With the tty or curses interface, the petattr option controls how to - highlight pets and setting it will turn the hilite_pet option on or + highlight pets and setting it will turn the hilite_pet option on or off as warranted. hilite_pile - Visually distinguish piles of objects from individual objects (de- - fault off). The behavior of this option depends on the type of win- - dowing you use. In text windowing, text highlighting or inverse - video is often used; with tiles, generally displays a small plus- + Visually distinguish piles of objects from individual objects + (default off). The behavior of this option depends on the type of + windowing you use. In text windowing, text highlighting or inverse + video is often used; with tiles, generally displays a small plus- symbol beside the object on the top of the pile. hitpointbar - Show a hit point bar graph behind your name and title in the status + Show a hit point bar graph behind your name and title in the status display (default off). - The "curses" interface supports it even if the status highlighting - feature has been disabled when building the program. The "tty" and - "mswin" (aka "Windows GUI") interfaces support it only if status - highlighting is left enabled when building. You don't need to set - up any highlighting rules in order to display the bar. If there is - one for hitpoints in effect and it specifies color, that color will + The "curses" interface supports it even if the status highlighting + feature has been disabled when building the program. The "tty" and + "mswin" (aka "Windows GUI") interfaces support it only if status + highlighting is left enabled when building. You don't need to set + up any highlighting rules in order to display the bar. If there is + one for hitpoints in effect and it specifies color, that color will be used for the bar. However if it specifies video attributes, they will be ignored in favor of inverse. For tty and curses, blink will also be used if the current hitpoint value is at or below the criti- cal HP threshold. The "Qt" interface also supports hitpointbar, by drawing a solid bar - above the name and title with a hard-coded color scheme. (As of + above the name and title with a hard-coded color scheme. (As of this writing, having the bar enabled unintentionally inhibits resiz- - ing the status panel. To resize that, use the #optionsfull command - to toggle the hitpointbar option off, perform the resize while it's + ing the status panel. To resize that, use the #optionsfull command + to toggle the hitpointbar option off, perform the resize while it's off, then use the same command to toggle it back on.) - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -4493,11 +4493,11 @@ horsename - Name your starting horse (for example "horsename:Trigger"). Cannot + Name your starting horse (for example "horsename:Trigger"). Cannot be set with the `O' command. ignintr - Ignore interrupt signals, including breaks (default off). Persis- + Ignore interrupt signals, including breaks (default off). Persis- tent. implicit_uncursed @@ -4515,40 +4515,40 @@ your character as lit (default off). Persistent. lootabc - When using a menu to interact with a container, use the old `a', - `b', and `c' keyboard shortcuts rather than the mnemonics `o', `i', + When using a menu to interact with a container, use the old `a', + `b', and `c' keyboard shortcuts rather than the mnemonics `o', `i', and `b' (default off). Persistent. mail Enable mail delivery during the game (default on). Persistent. male - An obsolete synonym for "gender:male". Cannot be set with the `O' + An obsolete synonym for "gender:male". Cannot be set with the `O' command. mention_decor - Give feedback when walking onto various dungeon features such as - stairs, fountains, or altars which are ordinarily only described - when covered by one or more objects (default off). Cannot be set + Give feedback when walking onto various dungeon features such as + stairs, fountains, or altars which are ordinarily only described + when covered by one or more objects (default off). Cannot be set with the `O' command. Persistent. mention_map Give feedback when interesting map locations change (default off). mention_walls - Give feedback when walking against a wall (default off). Persis- + Give feedback when walking against a wall (default off). Persis- tent. menucolors - Enable coloring menu lines (default off). See "Configuring Menu + Enable coloring menu lines (default off). See "Configuring Menu Colors" on how to configure the colors. menustyle Controls the method used when you need to choose various objects (in - response to the Drop (aka droptype) command, for instance). The + response to the Drop (aka droptype) command, for instance). The - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -4558,21 +4558,21 @@ - value specified should be the first letter of one of the following: - traditional, combination, full, or partial. Default is full. Per- + value specified should be the first letter of one of the following: + traditional, combination, full, or partial. Default is full. Per- sistent. - Traditional was the only method available for very early versions; - it consists of a prompt for object class characters, followed by an - object-by-object prompt for all items matching the selected object + Traditional was the only method available for very early versions; + it consists of a prompt for object class characters, followed by an + object-by-object prompt for all items matching the selected object class(es). Combination starts with a prompt for object class(es) of - interest, but then displays a menu of matching objects rather than + interest, but then displays a menu of matching objects rather than prompting one-by-one. Full displays a menu of object classes rather - than a character prompt, and then a menu of matching objects for se- - lection. (Choosing its `A' (Autoselect-All) choice skips the second - menu. To avoid choosing that by accident, set paranoid_confirm:Au- - toAll to require confirmation.) Partial skips the object class fil- - tering and immediately displays a menu of all objects. + than a character prompt, and then a menu of matching objects for + selection. (Choosing its `A' (Autoselect-All) choice skips the sec- + ond menu. To avoid choosing that by accident, set paranoid_con- + firm:AutoAll to require confirmation.) Partial skips the object + class filtering and immediately displays a menu of all objects. menu_deselect_all Key to deselect all items in a menu. Default `-'. @@ -4584,9 +4584,9 @@ Key to jump to the first page in a menu. Default `^'. menu_headings - Controls how the headings in a menu are highlighted. Takes a text - attribute, or text color and attribute separated by ampersand. For - allowed attributes and colors, see "Configuring Menu Colors". Not + Controls how the headings in a menu are highlighted. Takes a text + attribute, or text color and attribute separated by ampersand. For + allowed attributes and colors, see "Configuring Menu Colors". Not all ports can actually display all types. menu_invert_all @@ -4602,7 +4602,7 @@ Key to go to the next menu page. Default `>'. menu_objsyms - Show object symbols in menu headings in menus where the object sym- + Show object symbols in menu headings in menus where the object sym- bols act as menu accelerators (default off). menu_overlay @@ -4614,7 +4614,7 @@ - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -4625,7 +4625,7 @@ menu_search - Key to search for some text and toggle selection state of matching + Key to search for some text and toggle selection state of matching menu items. Default `:'. menu_select_all @@ -4636,20 +4636,20 @@ menu_shift_left Key to scroll a menu--one which has been scrolled right--back to the - left. Implemented for perm_invent only by curses and X11. Default + left. Implemented for perm_invent only by curses and X11. Default `{'. menu_shift_right - Key to scroll a menu which has text beyond the right edge to the + Key to scroll a menu which has text beyond the right edge to the right. Implemented for perm_invent only by curses and X11. Default `}'. mon_movement - Show a message when hero notices a monster movement (default is + Show a message when hero notices a monster movement (default is off). monpolycontrol - Prompt for new form whenever any monster changes shape (default + Prompt for new form whenever any monster changes shape (default off). Debug mode only. montelecontrol @@ -4667,12 +4667,12 @@ port is the same as specifying 0. msghistory - The number of top line messages to keep (and be able to recall with + The number of top line messages to keep (and be able to recall with `^P') (default 20). Cannot be set with the `O' command. msg_window - Allows you to change the way recalled messages are displayed. Cur- - rently it is only supported for tty (all four choices) and for + Allows you to change the way recalled messages are displayed. Cur- + rently it is only supported for tty (all four choices) and for curses (`f' and `r' choices, default `r'). The possible values are: @@ -4680,7 +4680,7 @@ - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -4695,21 +4695,21 @@ f - full window, oldest message first; r - full window reversed, newest message first. - For backward compatibility, no value needs to be specified (which - defaults to "full"), or it can be negated (which defaults to "sin- + For backward compatibility, no value needs to be specified (which + defaults to "full"), or it can be negated (which defaults to "sin- gle"). name - Set your character's name (defaults to your user name). You can - also set your character's role by appending a dash and one or more - letters of the role (that is, by suffixing one of -A -B -C -H -K -M - -P -Ra -Ro -S -T -V -W). If -@ is used for the role, then a random - one will be automatically chosen. Cannot be set with the `O' com- + Set your character's name (defaults to your user name). You can + also set your character's role by appending a dash and one or more + letters of the role (that is, by suffixing one of -A -B -C -H -K -M + -P -Ra -Ro -S -T -V -W). If -@ is used for the role, then a random + one will be automatically chosen. Cannot be set with the `O' com- mand. news Read the NetHack news file, if present (default on). Since the news - is shown at the beginning of the game, there's no point in setting + is shown at the beginning of the game, there's no point in setting this with the `O' command. nudist @@ -4730,23 +4730,23 @@ -1 - by letters but use `z' to go northwest, `y' to zap wands For backward compatibility, omitting a value is the same as specify- - ing 1 and negating number_pad is the same as specifying 0. (Set- - tings 2 and 4 are for compatibility with MS-DOS or old PC Hack; in - addition to the different behavior for `5', `Alt-5' acts as `G' and - `Alt-0' acts as `I'. Setting -1 is to accommodate some QWERTZ key- - boards which have the location of the `y' and `z' keys swapped.) - When moving by numbers, to enter a count prefix for those commands - which accept one (such as "12s" to search twelve times), precede it + ing 1 and negating number_pad is the same as specifying 0. (Set- + tings 2 and 4 are for compatibility with MS-DOS or old PC Hack; in + addition to the different behavior for `5', `Alt-5' acts as `G' and + `Alt-0' acts as `I'. Setting -1 is to accommodate some QWERTZ key- + boards which have the location of the `y' and `z' keys swapped.) + When moving by numbers, to enter a count prefix for those commands + which accept one (such as "12s" to search twelve times), precede it with the letter `n' ("n12s"). packorder - Specify the order to list object types in (default + Specify the order to list object types in (default "")[%?+!=/(*`0_"). The value of this option should be a string con- taining the symbols for the various object types. Any omitted types are filled in at the end from the previous order. - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -4757,62 +4757,62 @@ paranoid_confirmation - A space separated list of specific situations where alternate - prompting is desired. The default is "paranoid_confirmation:pray + A space separated list of specific situations where alternate + prompting is desired. The default is "paranoid_confirmation:pray swim trap". - Confirm - for any prompts which are set to require "yes" rather - than `y', also require "no" to reject instead of ac- - cepting any non-yes response as no; changes pray and + Confirm - for any prompts which are set to require "yes" rather + than `y', also require "no" to reject instead of + accepting any non-yes response as no; changes pray and AutoAll to require "yes" or `no' too; - quit - require "yes" rather than `y' to confirm quitting the + quit - require "yes" rather than `y' to confirm quitting the game or switching into non-scoring explore mode; - die - require "yes" rather than `y' to confirm dying (not + die - require "yes" rather than `y' to confirm dying (not useful in normal play; applies to explore mode); - bones - require "yes" rather than `y' to confirm saving bones + bones - require "yes" rather than `y' to confirm saving bones data when dying in debug mode; - attack - require "yes" rather than `y' to confirm attacking a + attack - require "yes" rather than `y' to confirm attacking a peaceful monster; - wand-break - require "yes" rather than `y' to confirm breaking a + wand-break - require "yes" rather than `y' to confirm breaking a wand with the apply command; - eating - require "yes" rather than `y' to confirm whether to + eating - require "yes" rather than `y' to confirm whether to continue eating; Were-change - require "yes" rather than `y' to confirm changing form due to lycanthropy when hero has polymorph control; - pray - require `y' to confirm an attempt to pray rather than - immediately praying; on by default; (to require "yes" + pray - require `y' to confirm an attempt to pray rather than + immediately praying; on by default; (to require "yes" rather than just `y', set Confirm too); trap - require `y' to confirm an attempt to move into or onto - a known trap, unless doing so is considered to be + a known trap, unless doing so is considered to be harmless; when enabled, this confirmation is also used for moving into visible gas cloud regions; (to require - "yes" rather than just `y', set Confirm too); confir- - mation can be skipped by using the `m' movement pre- + "yes" rather than just `y', set Confirm too); confir- + mation can be skipped by using the `m' movement pre- fix; swim - prevent walking into water or lava; on by default; (to - deliberately step onto/into such terrain when this is + deliberately step onto/into such terrain when this is set, use the `m' movement prefix when adjacent); - AutoAll - require confirmation when the `A' (Autoselect-All) + AutoAll - require confirmation when the `A' (Autoselect-All) choice is selected in object class filtering menus for - menustyle:Full; (to require "yes" rather than just + menustyle:Full; (to require "yes" rather than just `y', set Confirm too); - Remove - require selection from inventory for `R' and `T' com- + Remove - require selection from inventory for `R' and `T' com- mands even when wearing just one applicable item; all - turn on all of the above. By default, the pray, swim, and trap choices are enabled, the others disabled. To disable them without setting any of the other choices, - use paranoid_confirmation:none. To keep them enabled while setting - any of the others, you can include them in the new list, such as + use paranoid_confirmation:none. To keep them enabled while setting + any of the others, you can include them in the new list, such as paranoid_confirmation:attack pray swim Remove or you can precede the - first entry in the list with a plus sign, paranoid_confirmation:+at- - tack Remove. To remove an entry that has been previously set with- - out removing others, precede the first entry in the list with a mi- - nus sign, paranoid_confirmation:-swim. To both add some new entries - and remove some old ones, you can use multiple paranoid_confirmation + first entry in the list with a plus sign, paranoid_confirma- + tion:+attack Remove. To remove an entry that has been previously + set without removing others, precede the first entry in the list + with a minus sign, paranoid_confirmation:-swim. To both add some + new entries and remove some old ones, you can use multiple para- - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -4822,9 +4822,10 @@ - option settings, or you can use the `+' form and list entries to be - added by their name and entries to be removed by `!' and name. The - positive (no `!') and negative (with `!') entries can be intermixed. + noid_confirmation option settings, or you can use the `+' form and + list entries to be added by their name and entries to be removed by + `!' and name. The positive (no `!') and negative (with `!') entries + can be intermixed. pauper Start the character with no possessions (default false). Persis- @@ -4877,8 +4878,7 @@ Persistent. - - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -4900,8 +4900,8 @@ an autopickup exception. Default is on. Persistent. pickup_types - Specify the object types to be picked up when autopickup is on. De- - fault is all types. Persistent. + Specify the object types to be picked up when autopickup is on. + Default is all types. Persistent. The value is a list of object symbols, such as pickup_types:$?! to pick up gold, scrolls, and potions. You can use autopickup_excep- @@ -4924,10 +4924,10 @@ least that big; default value is 5. Persistent. playmode - Values are "normal", "explore", or "debug". Allows selection of ex- - plore mode (also known as discovery mode) or debug mode (also known - as wizard mode) instead of normal play. Debug mode might only be - allowed for someone logged in under a particular user name (on + Values are "normal", "explore", or "debug". Allows selection of + explore mode (also known as discovery mode) or debug mode (also + known as wizard mode) instead of normal play. Debug mode might only + be allowed for someone logged in under a particular user name (on multi-user systems) or specifying a particular character name (on single-user systems) or it might be disabled entirely. Requesting it when not allowed or not possible results in explore mode instead. @@ -4944,7 +4944,7 @@ - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -5005,12 +5005,12 @@ on reading an existing save file. runmode - Controls the amount of screen updating for the map window when en- - gaged in multi-turn movement (running via shift+direction or con- + Controls the amount of screen updating for the map window when + engaged in multi-turn movement (running via shift+direction or con- trol+direction and so forth, or via the travel command or mouse - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -5076,7 +5076,7 @@ ants, or you are making screenshots or streaming video. Using the - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -5104,8 +5104,8 @@ class; default; s - list object types by sortloot classification: by class, by sub- class within class for classes which have substantial groupings - (like helmets, boots, gloves, and so forth for armor), with ob- - ject types partly-discovered via assigned name coming before + (like helmets, boots, gloves, and so forth for armor), with + object types partly-discovered via assigned name coming before fully identified types; c - list by class, alphabetically within each class; a - list alphabetically across all classes. @@ -5136,13 +5136,13 @@ t - traditional--order by monster level; ties are broken by internal monster index; default; - d - order by monster difficulty rating; ties broken by internal in- - dex; + d - order by monster difficulty rating; ties broken by internal + index; a - order alphabetically, first any unique monsters then all the others; - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -5181,8 +5181,8 @@ ing Status Hilites" for further information. status_updates - Allow updates to the status lines at the bottom of the screen (de- - fault true). + Allow updates to the status lines at the bottom of the screen + (default true). suppress_alert This option may be set to a NetHack version level to suppress alert @@ -5208,7 +5208,7 @@ - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -5225,17 +5225,17 @@ Draw a tombstone graphic upon your death (default on). Persistent. toptenwin - Put the ending display in a NetHack window instead of on stdout (de- - fault off). Setting this option makes the score list visible when a - windowing version of NetHack is started without a parent window, but - it no longer leaves the score list around after game end on a termi- - nal or emulating window. + Put the ending display in a NetHack window instead of on stdout + (default off). Setting this option makes the score list visible + when a windowing version of NetHack is started without a parent win- + dow, but it no longer leaves the score list around after game end on + a terminal or emulating window. travel Allow the travel command via mouse click (default on). Turning this option off will prevent the game from attempting unintended moves if - you make inadvertent mouse clicks on the map window. Does not af- - fect traveling via the `_' ("#travel") command. Persistent. + you make inadvertent mouse clicks on the map window. Does not + affect traveling via the `_' ("#travel") command. Persistent. tutorial Play a tutorial level at the start of the game. Setting this option @@ -5274,7 +5274,7 @@ on a doorway, it will consider the area on the side of the door you - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -5300,8 +5300,8 @@ time, move by skipping the same glyphs. (default off) windowtype - When the program has been built to support multiple interfaces, se- - lect which one to use, such as "tty" or "X11" (default depends on + When the program has been built to support multiple interfaces, + select which one to use, such as "tty" or "X11" (default depends on build-time settings; use "#version" to check). Cannot be set with the `O' command. @@ -5318,8 +5318,8 @@ zerocomp When writing out a save file, perform zero-comp compression of the - contents. Not all ports support zero-comp compression. It has no ef- - fect on reading an existing save file. + contents. Not all ports support zero-comp compression. It has no + effect on reading an existing save file. 9.5. Window Port Customization options @@ -5340,7 +5340,7 @@ right) - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -5406,7 +5406,7 @@ - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -5472,7 +5472,7 @@ - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -5483,8 +5483,8 @@ statuslines - Number of lines for traditional below-the-map status display. Ac- - ceptable values are 2 and 3 (default is 2). + Number of lines for traditional below-the-map status display. + Acceptable values are 2 and 3 (default is 2). When set to 3, the tty interface moves some fields around and mainly shows status conditions on their own line. A display capable of @@ -5513,12 +5513,12 @@ current window size. tile_file - Specify the name of an alternative tile file to override the de- - fault. + Specify the name of an alternative tile file to override the + default. - Note: the X11 interface uses X resources rather than NetHack's op- - tions to select an alternate tile file. See NetHack.ad, the sample - X "application defaults" file. + Note: the X11 interface uses X resources rather than NetHack's + options to select an alternate tile file. See NetHack.ad, the sam- + ple X "application defaults" file. tile_height Specify the preferred height of each tile in a tile capable port. @@ -5538,7 +5538,7 @@ - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -5558,8 +5558,8 @@ windowborders Whether to draw boxes around the map, status area, message area, and - persistent inventory window if enabled. Curses interface only. Ac- - ceptable values are + persistent inventory window if enabled. Curses interface only. + Acceptable values are 0 - off, never show borders 1 - on, always show borders @@ -5604,7 +5604,7 @@ - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -5667,10 +5667,10 @@ subkeyvalue (Win32 tty NetHack only). May be used to alter the value of key- - strokes that the operating system returns to NetHack to help + strokes that the operating system returns to NetHack to help compen- - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -5680,10 +5680,10 @@ - compensate for international keyboard issues. OPTIONS=subkey- - value:171/92 will return 92 to NetHack, if 171 was originally going - to be returned. You can use multiple subkeyvalue assignments in the - configuration file if needed. Cannot be set with the `O' command. + sate for international keyboard issues. OPTIONS=subkeyvalue:171/92 + will return 92 to NetHack, if 171 was originally going to be + returned. You can use multiple subkeyvalue assignments in the con- + figuration file if needed. Cannot be set with the `O' command. video Set the video mode used (PC NetHack only). Values are "autodetect", @@ -5691,9 +5691,9 @@ display tiles, using the full capability of the VGA hardware. Set- ting "vga" will cause the game to display tiles, fixed at 640x480 in 16 colors, a mode that is compatible with all VGA hardware. Third - party tilesets will probably not work. Setting "autodetect" at- - tempts "vesa", then "vga", and finally sets "default" if neither of - those modes works. Cannot be set with the `O' command. + party tilesets will probably not work. Setting "autodetect" + attempts "vesa", then "vga", and finally sets "default" if neither + of those modes works. Cannot be set with the `O' command. video_height Set the VGA mode resolution height (MS-DOS only, with video:vesa) @@ -5721,22 +5721,22 @@ support on a platform where there is no regular expression library. While this is not true of any modern platform, if your NetHack was built this way, patterns are instead glob patterns; regardless, this - document refers to both as `regular expressions.' This applies to Au- - topickup exceptions, Message types, Menu colors, and User sounds. + document refers to both as `regular expressions.' This applies to + Autopickup exceptions, Message types, Menu colors, and User sounds. 9.9. Configuring Autopickup Exceptions - You can further refine the behavior of the autopickup option be- - yond what is available through the pickup_types option. + You can further refine the behavior of the autopickup option + beyond what is available through the pickup_types option. By placing autopickup_exception lines in your configuration file, - you can define patterns to be checked when the game is about to au- - topickup something. + you can define patterns to be checked when the game is about to + autopickup something. - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -5802,7 +5802,7 @@ The menu control or accelerator keys can also be rebound via OPTIONS - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -5868,7 +5868,7 @@ - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -5903,8 +5903,8 @@ getpos.menu When asked for a location, and using one of the next or previous - keys to cycle through targets, toggle showing a menu instead. De- - fault is `!'. + keys to cycle through targets, toggle showing a menu instead. + Default is `!'. getpos.moveskip When asked for a location, and using the shifted movement keys or @@ -5913,9 +5913,9 @@ getpos.filter When asked for a location, change the filtering mode when using one - of the next or previous keys to cycle through targets. Toggles be- - tween no filtering, in view only, and in the same area only. De- - fault is `"'. + of the next or previous keys to cycle through targets. Toggles + between no filtering, in view only, and in the same area only. + Default is `"'. getpos.pick When asked for a location, the key to choose the location, and pos- @@ -5934,7 +5934,7 @@ ing for more info, and exit the location asking loop. Default is - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -6000,7 +6000,7 @@ - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -6066,7 +6066,7 @@ - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -6077,9 +6077,9 @@ Note that if you intend to have one or more color specifications - match " uncursed ", you will probably want to turn the implicit_un- - cursed option off so that all items known to be uncursed are actually - displayed with the "uncursed" description. + match " uncursed ", you will probably want to turn the + implicit_uncursed option off so that all items known to be uncursed + are actually displayed with the "uncursed" description. 9.13. Configuring User Sounds @@ -6129,10 +6129,10 @@ OPTION=hilite_status:field-name/behavior/color&attributes For example, the following line in your configuration file will - cause the hitpoints field to display in the color red if your + cause the hitpoints field to display in the color red if your hit- - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -6142,7 +6142,7 @@ - hitpoints drop to or below a threshold of 30%: + points drop to or below a threshold of 30%: OPTION=hilite_status:hitpoints/<=30%/red/normal @@ -6169,15 +6169,15 @@ them. To specify multiple attributes, use `+' to combine those. For example: "magenta&inverse+dim". - Note that the display may substitute or ignore particular at- - tributes depending upon its capabilities, and in general may interpret - the attributes any way it wants. For example, on some display systems - a request for bold might yield blink or vice versa. On others, issu- - ing an attribute request while another is already set up will replace - the earlier attribute rather than combine with it. Since NetHack is- - sues attribute requests sequentially (at least with the tty interface) - rather than all at once, the only way a situation like that can be - controlled is to specify just one attribute. + Note that the display may substitute or ignore particular + attributes depending upon its capabilities, and in general may inter- + pret the attributes any way it wants. For example, on some display + systems a request for bold might yield blink or vice versa. On oth- + ers, issuing an attribute request while another is already set up will + replace the earlier attribute rather than combine with it. Since + NetHack issues attribute requests sequentially (at least with the tty + interface) rather than all at once, the only way a situation like that + can be controlled is to specify just one attribute. You can adjust the appearance of the following status fields: title dungeon-level experience-level @@ -6191,14 +6191,14 @@ The pseudo-field "characteristics" can be used to set all six of Str, Dex, Con, Int, Wis, and Cha at once. "HD" is "hit dice", an - approximation of experience level displayed when polymorphed. "ex- - perience", "time", and "score" are conditionally displayed depending - upon your other option settings. + approximation of experience level displayed when polymorphed. + "experience", "time", and "score" are conditionally displayed + depending upon your other option settings. - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -6251,20 +6251,20 @@ starts at 20 points and level 3 starts at 40 points, having 30 points is 50% and 35 points is 75%. 100% is unattainable for experience because you'll gain a level and the calculations - will be reset for that new level, but a rule for =100% is al- - lowed and matches the special case of being exactly 1 experi- + will be reset for that new level, but a rule for =100% is + allowed and matches the special case of being exactly 1 experi- ence point short of the next level. * absolute value sets the attribute when the field value matches - that number. The number must be 0 or higher, except for "ar- - mor-class' which allows negative values, and may optionally be - preceded by `='. If the number is preceded by `<=' or `>=' in- - stead, it also matches when value is below or above. If the + that number. The number must be 0 or higher, except for + "armor-class' which allows negative values, and may optionally + be preceded by `='. If the number is preceded by `<=' or `>=' + instead, it also matches when value is below or above. If the prefix is `<' or `>', only match when strictly above or below. - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -6282,9 +6282,9 @@ * text match sets the attribute when the field value matches the text. Text matches can only be used for "alignment", "carry- - ing-capacity", "hunger", "dungeon-level", and "title". For ti- - tle, only the role's rank title is tested; the character's name - is ignored. + ing-capacity", "hunger", "dungeon-level", and "title". For + title, only the role's rank title is tested; the character's + name is ignored. The in-game options menu can help you determine the correct syn- tax for a configuration file. @@ -6330,7 +6330,7 @@ value, and the ^ prefix causes the following character to be treated - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -6396,7 +6396,7 @@ - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -6462,7 +6462,7 @@ - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -6528,7 +6528,7 @@ - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -6594,7 +6594,7 @@ - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -6660,7 +6660,7 @@ - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -6726,7 +6726,7 @@ seen via the "#attributes" command. - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -6744,10 +6744,10 @@ If NetHack is compiled with the SYSCF option, a system adminis- trator should set up a global configuration; this is a file in the same format as the traditional per-user configuration file (see - above). This file should be named sysconf and placed in the same di- - rectory as the other NetHack support files. The options recognized in - this file are listed below. Any option not set uses a compiled-in de- - fault (which may not be appropriate for your system). + above). This file should be named sysconf and placed in the same + directory as the other NetHack support files. The options recognized + in this file are listed below. Any option not set uses a compiled-in + default (which may not be appropriate for your system). WIZARDS = A space-separated list of user names who are allowed to play in debug mode (commonly referred to as wizard mode). A value @@ -6760,6 +6760,10 @@ EXPLORERS = A list of users who are allowed to use the explore mode. The syntax is the same as WIZARDS. + MSGHANDLER = A path and filename of executable. Whenever a message- + window message is shown, NetHack runs this program. The program + will get the message as the only parameter. + MAXPLAYERS = Limit the maximum number of games that can be running at the same time. @@ -6785,14 +6789,10 @@ RECOVER = A string explaining how to recover a game on this system (no default value). - SEDUCE = 0 or 1 to disable or enable, respectively, the SEDUCE op- - tion. When disabled, incubi and succubi behave like nymphs. - - CHECK_PLNAME = Setting this to 1 will make the EXPLORERS, WIZARDS, - and SHELLERS check for the player name instead of the user's login - NetHack 3.7.0 September 13, 2024 + + NetHack 3.7.0 November 16, 2024 @@ -6802,6 +6802,11 @@ + SEDUCE = 0 or 1 to disable or enable, respectively, the SEDUCE + option. When disabled, incubi and succubi behave like nymphs. + + CHECK_PLNAME = Setting this to 1 will make the EXPLORERS, WIZARDS, + and SHELLERS check for the player name instead of the user's login name. CHECK_SAVE_UID = 0 or 1 to disable or enable, respectively, the UID @@ -6851,14 +6856,9 @@ LIVELOG = A bit-mask of types of events that should be written to the livelog file if one is present. The sample sysconf file accom- - panying the program contains a comment which lists the meaning of - the various bits used. Intended for server systems supporting si- - multaneous play by multiple players (to be clear, each one running a - separate single player game), for displaying their game progress to - observers. Only relevant if the program was built with LIVELOG - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -6868,33 +6868,38 @@ + panying the program contains a comment which lists the meaning of + the various bits used. Intended for server systems supporting + simultaneous play by multiple players (to be clear, each one running + a separate single player game), for displaying their game progress + to observers. Only relevant if the program was built with LIVELOG enabled. When available, it should be left commented out on single - player installations because over time the file could grow to be ex- - tremely large unless it is actively maintained. + player installations because over time the file could grow to be + extremely large unless it is actively maintained. CRASHREPORTURL = If set to https://www.nethack.org/links/cr-37BETA.html and support is compiled in, brings up a browser window pre-populated with the information - needed to report a problem if the game panics or ends up in an in- - ternally inconsistent state, or if the #bugreport command is in- - voked. + needed to report a problem if the game panics or ends up in an + internally inconsistent state, or if the #bugreport command is + invoked. 10. Scoring - NetHack maintains a list of the top scores or scorers on your ma- - chine, depending on how it is set up. In the latter case, each ac- - count on the machine can post only one non-winning score on this list. - If you score higher than someone else on this list, or better your - previous score, you will be inserted in the proper place under your - current name. How many scores are kept can also be set up when + NetHack maintains a list of the top scores or scorers on your + machine, depending on how it is set up. In the latter case, each + account on the machine can post only one non-winning score on this + list. If you score higher than someone else on this list, or better + your previous score, you will be inserted in the proper place under + your current name. How many scores are kept can also be set up when NetHack is compiled. Your score is chiefly based upon how much experience you gained, how much loot you accumulated, how deep you explored, and how the game ended. If you quit the game, you escape with all of your gold intact. If, however, you get killed in the Mazes of Menace, the guild will - only hear about 90% of your gold when your corpse is discovered (ad- - venturers have been known to collect finder's fees). So, consider + only hear about 90% of your gold when your corpse is discovered + (adventurers have been known to collect finder's fees). So, consider whether you want to take one last hit at that monster and possibly live, or quit and stop with whatever you have. If you quit, you keep all your gold, but if you swing and live, you might find more. @@ -6911,20 +6916,15 @@ paltry cost of not getting on the high score list. There are two ways of enabling explore mode. One is to start the - game with the -X command-line switch or with the playmode:explore op- - tion. The other is to issue the "#exploremode" extended command while - already playing the game. Starting a new game in explore mode pro- - vides your character with a wand of wishing in initial inventory; + game with the -X command-line switch or with the playmode:explore + option. The other is to issue the "#exploremode" extended command + while already playing the game. Starting a new game in explore mode + provides your character with a wand of wishing in initial inventory; switching during play does not. The other benefits of explore mode are left for the trepid reader to discover. - 11.1. Debug mode - Debug mode, also known as wizard mode, is undocumented aside from - this brief description and the various "debug mode only" commands - - - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -6934,6 +6934,10 @@ + 11.1. Debug mode + + Debug mode, also known as wizard mode, is undocumented aside from + this brief description and the various "debug mode only" commands listed among the command descriptions. It is intended for tracking down problems within the program rather than to provide god-like pow- ers to your character, and players who attempt debugging are expected @@ -6945,8 +6949,8 @@ user name to be allowed to use debug mode; for others, the hero must be given a particular character name (but may be any role; there's no connection between "wizard mode" and the Wizard role). Attempting to - start a game in debug mode when not allowed or not available will re- - sult in falling back to explore mode instead. + start a game in debug mode when not allowed or not available will + result in falling back to explore mode instead. 12. Credits @@ -6968,29 +6972,25 @@ on UNIX systems by posting that to Usenet newsgroup net.sources (later renamed comp.sources) releasing version 1.0 in December of 1984, then versions 1.0.1, 1.0.2, and finally 1.0.3 in July of 1985. Usenet - newsgroup net.games.hack (later renamed rec.games.hack, eventually re- - placed by rec.games.roguelike.nethack) was created for discussing it. + newsgroup net.games.hack (later renamed rec.games.hack, eventually + replaced by rec.games.roguelike.nethack) was created for discussing + it. - Don G. Kneller ported Hack 1.0.3 to Microsoft C and MS-DOS, pro- - ducing PC HACK 1.01e, added support for DEC Rainbow graphics in ver- - sion 1.03g, and went on to produce at least four more versions (3.0, - 3.2, 3.51, and 3.6; note that these are old Hack version numbers, not + Don G. Kneller ported Hack 1.0.3 to Microsoft C and MS-DOS, pro- + ducing PC HACK 1.01e, added support for DEC Rainbow graphics in ver- + sion 1.03g, and went on to produce at least four more versions (3.0, + 3.2, 3.51, and 3.6; note that these are old Hack version numbers, not contemporary NetHack ones). - R. Black ported PC HACK 3.51 to Lattice C and the Atari + R. Black ported PC HACK 3.51 to Lattice C and the Atari 520/1040ST, producing ST Hack 1.03. - Mike Stephenson merged these various versions back together, in- - corporating many of the added features, and produced NetHack version + Mike Stephenson merged these various versions back together, + incorporating many of the added features, and produced NetHack version 1.4 in 1987. He then coordinated a cast of thousands in enhancing and - debugging NetHack 1.4 and released NetHack versions 2.2 and 2.3. Like - Hack, they were released by posting their source code to Usenet where - they remained available in various archives accessible via ftp and - uucp after expiring from the newsgroup. - - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -7000,63 +7000,63 @@ - Later, Mike coordinated a major re-write of the game, heading a + debugging NetHack 1.4 and released NetHack versions 2.2 and 2.3. Like + Hack, they were released by posting their source code to Usenet where + they remained available in various archives accessible via ftp and + uucp after expiring from the newsgroup. + + Later, Mike coordinated a major re-write of the game, heading a team which included Ken Arromdee, Jean-Christophe Collet, Steve Creps, - Eric Hendrickson, Izchak Miller, Eric S. Raymond, John Rupley, Mike + Eric Hendrickson, Izchak Miller, Eric S. Raymond, John Rupley, Mike Threepoint, and Janet Walz, to produce NetHack 3.0c. - NetHack 3.0 was ported to the Atari by Eric R. Smith, to OS/2 by - Timo Hakulinen, and to VMS by David Gentzel. The three of them and - Kevin Darcy later joined the main NetHack Development Team to produce + NetHack 3.0 was ported to the Atari by Eric R. Smith, to OS/2 by + Timo Hakulinen, and to VMS by David Gentzel. The three of them and + Kevin Darcy later joined the main NetHack Development Team to produce subsequent revisions of 3.0. - Olaf Seibert ported NetHack 2.3 and 3.0 to the Amiga. Norm - Meluch, Stephen Spackman and Pierre Martineau designed overlay code - for PC NetHack 3.0. Johnny Lee ported NetHack 3.0 to the Macintosh. - Along with various other Dungeoneers, they continued to enhance the + Olaf Seibert ported NetHack 2.3 and 3.0 to the Amiga. Norm + Meluch, Stephen Spackman and Pierre Martineau designed overlay code + for PC NetHack 3.0. Johnny Lee ported NetHack 3.0 to the Macintosh. + Along with various other Dungeoneers, they continued to enhance the PC, Macintosh, and Amiga ports through the later revisions of 3.0. - Version 3.0 went through ten relatively rapidly released "patch- + Version 3.0 went through ten relatively rapidly released "patch- level" revisions. Versions at the time were known as 3.0 for the base - release and variously as "3.0a" through "3.0j", "3.0 patchlevel 1" + release and variously as "3.0a" through "3.0j", "3.0 patchlevel 1" through "3.0 patchlevel 10", or "3.0pl1" through "3.0pl10" rather than - 3.0.0 and 3.0.1 through 3.0.10; the three component numbering scheme + 3.0.0 and 3.0.1 through 3.0.10; the three component numbering scheme began to be used with 3.1.0. - Headed by Mike Stephenson and coordinated by Izchak Miller and - Janet Walz, the NetHack Development Team which now included Ken Ar- - romdee, David Cohrs, Jean-Christophe Collet, Kevin Darcy, Matt Day, - Timo Hakulinen, Steve Linhart, Dean Luick, Pat Rankin, Eric Raymond, - and Eric Smith undertook a radical revision of 3.0. They re-struc- - tured the game's design, and re-wrote major parts of the code. They - added multiple dungeons, a new display, special individual character - quests, a new endgame and many other new features, and produced + Headed by Mike Stephenson and coordinated by Izchak Miller and + Janet Walz, the NetHack Development Team which now included Ken + Arromdee, David Cohrs, Jean-Christophe Collet, Kevin Darcy, Matt Day, + Timo Hakulinen, Steve Linhart, Dean Luick, Pat Rankin, Eric Raymond, + and Eric Smith undertook a radical revision of 3.0. They re-struc- + tured the game's design, and re-wrote major parts of the code. They + added multiple dungeons, a new display, special individual character + quests, a new endgame and many other new features, and produced NetHack 3.1. Version 3.1.0 was released in January of 1993. Ken Lorber, Gregg Wonderly and Greg Olson, with help from Richard - Addison, Mike Passaretti, and Olaf Seibert, developed NetHack 3.1 for + Addison, Mike Passaretti, and Olaf Seibert, developed NetHack 3.1 for the Amiga. - Norm Meluch and Kevin Smolkowski, with help from Carl Schelin, - Stephen Spackman, Steve VanDevender, and Paul Winner, ported NetHack + Norm Meluch and Kevin Smolkowski, with help from Carl Schelin, + Stephen Spackman, Steve VanDevender, and Paul Winner, ported NetHack 3.1 to the PC. Jon W{tte and Hao-yang Wang, with help from Ross Brown, Mike Eng- - ber, David Hairston, Michael Hamel, Jonathan Handler, Johnny Lee, Tim - Lennan, Rob Menke, and Andy Swanson, developed NetHack 3.1 for the - Macintosh, porting it for MPW. Building on their development, Bart + ber, David Hairston, Michael Hamel, Jonathan Handler, Johnny Lee, Tim + Lennan, Rob Menke, and Andy Swanson, developed NetHack 3.1 for the + Macintosh, porting it for MPW. Building on their development, Bart House added a Think C port. - Timo Hakulinen ported NetHack 3.1 to OS/2. Eric Smith ported - NetHack 3.1 to the Atari. Pat Rankin, with help from Joshua De- - lahunty, was responsible for the VMS version of NetHack 3.1. Michael - Allison ported NetHack 3.1 to Windows NT. - - Dean Luick, with help from David Cohrs, developed NetHack 3.1 for - X11. It drew the map as text rather than graphically but included + Timo Hakulinen ported NetHack 3.1 to OS/2. Eric Smith ported + NetHack 3.1 to the Atari. Pat Rankin, with help from Joshua - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -7066,63 +7066,63 @@ - nh10.bdf, an optionally used custom X11 font which has tiny images in - place of letters and punctuation, a precursor of tiles. Those images - don't extend to individual monster and object types, just replacements - for monster and object classes (so one custom image for all "a" in- - sects and another for all "[" armor and so forth, not separate images - for beetles and ants or for cloaks and boots). + Delahunty, was responsible for the VMS version of NetHack 3.1. + Michael Allison ported NetHack 3.1 to Windows NT. - Warwick Allison wrote a graphically displayed version of NetHack - for the Atari where the tiny pictures were described as "icons" and - were distinct for specific types of monsters and objects rather than - just their classes. He contributed them to the NetHack Development - Team which rechristened them "tiles", original usage which has subse- - quently been picked up by various other games. NetHack's tiles sup- - port was then implemented on other platforms (initially MS-DOS but + Dean Luick, with help from David Cohrs, developed NetHack 3.1 for + X11. It drew the map as text rather than graphically but included + nh10.bdf, an optionally used custom X11 font which has tiny images in + place of letters and punctuation, a precursor of tiles. Those images + don't extend to individual monster and object types, just replacements + for monster and object classes (so one custom image for all "a" + insects and another for all "[" armor and so forth, not separate + images for beetles and ants or for cloaks and boots). + + Warwick Allison wrote a graphically displayed version of NetHack + for the Atari where the tiny pictures were described as "icons" and + were distinct for specific types of monsters and objects rather than + just their classes. He contributed them to the NetHack Development + Team which rechristened them "tiles", original usage which has subse- + quently been picked up by various other games. NetHack's tiles sup- + port was then implemented on other platforms (initially MS-DOS but eventually Windows, Qt, and X11 too). - The 3.2 NetHack Development Team, comprised of Michael Allison, - Ken Arromdee, David Cohrs, Jessie Collet, Steve Creps, Kevin Darcy, - Timo Hakulinen, Steve Linhart, Dean Luick, Pat Rankin, Eric Smith, - Mike Stephenson, Janet Walz, and Paul Winner, released version 3.2.0 + The 3.2 NetHack Development Team, comprised of Michael Allison, + Ken Arromdee, David Cohrs, Jessie Collet, Steve Creps, Kevin Darcy, + Timo Hakulinen, Steve Linhart, Dean Luick, Pat Rankin, Eric Smith, + Mike Stephenson, Janet Walz, and Paul Winner, released version 3.2.0 in April of 1996. - Version 3.2 marked the tenth anniversary of the formation of the + Version 3.2 marked the tenth anniversary of the formation of the development team. In a testament to their dedication to the game, all - thirteen members of the original NetHack Development Team remained on - the team at the start of work on that release. During the interval + thirteen members of the original NetHack Development Team remained on + the team at the start of work on that release. During the interval between the release of 3.1.3 and 3.2.0, one of the founding members of - the NetHack Development Team, Dr. Izchak Miller, was diagnosed with + the NetHack Development Team, Dr. Izchak Miller, was diagnosed with cancer and passed away. That release of the game was dedicated to him by the development and porting teams. - Version 3.2 proved to be more stable than previous versions. - Many bugs were fixed, abuses eliminated, and game features tuned for + Version 3.2 proved to be more stable than previous versions. + Many bugs were fixed, abuses eliminated, and game features tuned for better game play. - During the lifespan of NetHack 3.1 and 3.2, several enthusiasts - of the game added their own modifications to the game and made these + During the lifespan of NetHack 3.1 and 3.2, several enthusiasts + of the game added their own modifications to the game and made these "variants" publicly available: Tom Proudfoot and Yuval Oren created NetHack++, which was quickly - renamed NetHack-- when some people incorrectly assumed that it was a - conversion of the C source code to C++. Working independently, - Stephen White wrote NetHack Plus. Tom Proudfoot later merged NetHack - Plus and his own NetHack-- to produce SLASH. Larry Stewart-Zerba and - Warwick Allison improved the spell casting system with the Wizard + renamed NetHack-- when some people incorrectly assumed that it was a + conversion of the C source code to C++. Working independently, + Stephen White wrote NetHack Plus. Tom Proudfoot later merged NetHack + Plus and his own NetHack-- to produce SLASH. Larry Stewart-Zerba and + Warwick Allison improved the spell casting system with the Wizard Patch. Warwick Allison also ported NetHack to use the Qt interface. - Warren Cheung combined SLASH with the Wizard Patch to produce + Warren Cheung combined SLASH with the Wizard Patch to produce Slash'EM, and with the help of Kevin Hugo, added more features. Kevin - later joined the NetHack Development Team and incorporated the best of - these ideas into NetHack 3.3. - - The final update to 3.2 was the bug fix release 3.2.3, which was - released simultaneously with 3.3.0 in December 1999 just in time for - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -7132,63 +7132,63 @@ - the Year 2000. Because of the newer version, 3.2.3 was released as a - source code patch only, without any ready-to-play distribution for + later joined the NetHack Development Team and incorporated the best of + these ideas into NetHack 3.3. + + The final update to 3.2 was the bug fix release 3.2.3, which was + released simultaneously with 3.3.0 in December 1999 just in time for + the Year 2000. Because of the newer version, 3.2.3 was released as a + source code patch only, without any ready-to-play distribution for systems that usually had such. (To anyone considering resurrecting an old version: all versions - before 3.2.3 had a Y2K bug. The high scores file and the log file - contained dates which were formatted using a two-digit year, and - 1999's year 99 was followed by 2000's year 100. That got written out - successfully but it unintentionally introduced an extra column in the + before 3.2.3 had a Y2K bug. The high scores file and the log file + contained dates which were formatted using a two-digit year, and + 1999's year 99 was followed by 2000's year 100. That got written out + successfully but it unintentionally introduced an extra column in the file layout which prevented score entries from being read back in cor- - rectly, interfering with insertion of new high scores and with re- - trieval of old character names to use for random ghost and statue + rectly, interfering with insertion of new high scores and with + retrieval of old character names to use for random ghost and statue names in the current game.) - The 3.3 NetHack Development Team, consisting of Michael Allison, - Ken Arromdee, David Cohrs, Jessie Collet, Steve Creps, Kevin Darcy, + The 3.3 NetHack Development Team, consisting of Michael Allison, + Ken Arromdee, David Cohrs, Jessie Collet, Steve Creps, Kevin Darcy, Timo Hakulinen, Kevin Hugo, Steve Linhart, Ken Lorber, Dean Luick, Pat - Rankin, Eric Smith, Mike Stephenson, Janet Walz, and Paul Winner, re- - leased 3.3.0 in December 1999 and 3.3.1 in August of 2000. + Rankin, Eric Smith, Mike Stephenson, Janet Walz, and Paul Winner, + released 3.3.0 in December 1999 and 3.3.1 in August of 2000. Version 3.3 offered many firsts. It was the first version to sep- - arate race and profession. The Elf class was removed in preference to - an elf race, and the races of dwarves, gnomes, and orcs made their - first appearance in the game alongside the familiar human race. Monk - and Ranger roles joined Archeologists, Barbarians, Cavemen, Healers, - Knights, Priests, Rogues, Samurai, Tourists, Valkyries and of course, - Wizards. It was also the first version to allow you to ride a steed, - and was the first version to have a publicly available web-site list- - ing all the bugs that had been discovered. Despite that constantly - growing bug list, 3.3 proved stable enough to last for more than a + arate race and profession. The Elf class was removed in preference to + an elf race, and the races of dwarves, gnomes, and orcs made their + first appearance in the game alongside the familiar human race. Monk + and Ranger roles joined Archeologists, Barbarians, Cavemen, Healers, + Knights, Priests, Rogues, Samurai, Tourists, Valkyries and of course, + Wizards. It was also the first version to allow you to ride a steed, + and was the first version to have a publicly available web-site list- + ing all the bugs that had been discovered. Despite that constantly + growing bug list, 3.3 proved stable enough to last for more than a year and a half. - The 3.4 NetHack Development Team initially consisted of Michael - Allison, Ken Arromdee, David Cohrs, Jessie Collet, Kevin Hugo, Ken - Lorber, Dean Luick, Pat Rankin, Mike Stephenson, Janet Walz, and Paul - Winner, with Warwick Allison joining just before the release of + The 3.4 NetHack Development Team initially consisted of Michael + Allison, Ken Arromdee, David Cohrs, Jessie Collet, Kevin Hugo, Ken + Lorber, Dean Luick, Pat Rankin, Mike Stephenson, Janet Walz, and Paul + Winner, with Warwick Allison joining just before the release of NetHack 3.4.0 in March 2002. - As with version 3.3, various people contributed to the game as a - whole as well as supporting ports on the different platforms that + As with version 3.3, various people contributed to the game as a + whole as well as supporting ports on the different platforms that NetHack runs on: Pat Rankin maintained 3.4 for VMS. - Michael Allison maintained NetHack 3.4 for the MS-DOS platform. + Michael Allison maintained NetHack 3.4 for the MS-DOS platform. Paul Winner and Yitzhak Sapir provided encouragement. - Dean Luick, Mark Modrall, and Kevin Hugo maintained and enhanced + Dean Luick, Mark Modrall, and Kevin Hugo maintained and enhanced the Macintosh port of 3.4. - Michael Allison, David Cohrs, Alex Kompel, Dion Nicolaas, and - Yitzhak Sapir maintained and enhanced 3.4 for the Microsoft Windows - platform. Alex Kompel contributed a new graphical interface for the - Windows port. Alex Kompel also contributed a Windows CE port for - - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -7198,63 +7198,63 @@ + Michael Allison, David Cohrs, Alex Kompel, Dion Nicolaas, and + Yitzhak Sapir maintained and enhanced 3.4 for the Microsoft Windows + platform. Alex Kompel contributed a new graphical interface for the + Windows port. Alex Kompel also contributed a Windows CE port for 3.4.1. - Ron Van Iwaarden was the sole maintainer of NetHack for OS/2 the - past several releases. Unfortunately Ron's last OS/2 machine stopped - working in early 2006. A great many thanks to Ron for keeping NetHack + Ron Van Iwaarden was the sole maintainer of NetHack for OS/2 the + past several releases. Unfortunately Ron's last OS/2 machine stopped + working in early 2006. A great many thanks to Ron for keeping NetHack alive on OS/2 all these years. - Janne Salmijarvi and Teemu Suikki maintained and enhanced the + Janne Salmijarvi and Teemu Suikki maintained and enhanced the Amiga port of 3.4 after Janne Salmijarvi resurrected it for 3.3.1. Christian "Marvin" Bressler maintained 3.4 for the Atari after he resurrected it for 3.3.1. - The release of NetHack 3.4.3 in December 2003 marked the begin- - ning of a long release hiatus. 3.4.3 proved to be a remarkably stable - version that provided continued enjoyment by the community for more + The release of NetHack 3.4.3 in December 2003 marked the begin- + ning of a long release hiatus. 3.4.3 proved to be a remarkably stable + version that provided continued enjoyment by the community for more than a decade. The NetHack Development Team slowly and quietly contin- - ued to work on the game behind the scenes during the tenure of 3.4.3. - It was during that same period that several new variants emerged - within the NetHack community. Notably sporkhack by Derek S. Ray, un- - nethack by Patric Mueller, nitrohack and its successors originally by - Daniel Thaler and then by Alex Smith, and Dynahack by Tung Nguyen. - Some of those variants continue to be developed, maintained, and en- - joyed by the community to this day. + ued to work on the game behind the scenes during the tenure of 3.4.3. + It was during that same period that several new variants emerged + within the NetHack community. Notably sporkhack by Derek S. Ray, + unnethack by Patric Mueller, nitrohack and its successors originally + by Daniel Thaler and then by Alex Smith, and Dynahack by Tung Nguyen. + Some of those variants continue to be developed, maintained, and + enjoyed by the community to this day. In September 2014, an interim snapshot of the code under develop- - ment was released publicly by other parties. Since that code was a - work-in-progress and had not gone through the process of debugging it + ment was released publicly by other parties. Since that code was a + work-in-progress and had not gone through the process of debugging it as a suitable release, it was decided that the version numbers present - on that code snapshot would be retired and never used in an official - NetHack release. An announcement was posted on the NetHack Develop- - ment Team's official nethack.org website to that effect, stating that + on that code snapshot would be retired and never used in an official + NetHack release. An announcement was posted on the NetHack Develop- + ment Team's official nethack.org website to that effect, stating that there would never be a 3.4.4, 3.5, or 3.5.0 official release version. - In January 2015, preparation began for the release of NetHack + In January 2015, preparation began for the release of NetHack 3.6. - At the beginning of development for what would eventually get re- - leased as 3.6.0, the NetHack Development Team consisted of Warwick Al- - lison, Michael Allison, Ken Arromdee, David Cohrs, Jessie Collet, Ken - Lorber, Dean Luick, Pat Rankin, Mike Stephenson, Janet Walz, and Paul - Winner. In early 2015, ahead of the release of 3.6.0, new members - Sean Hunt, Pasi Kallinen, and Derek S. Ray joined the NetHack Develop- - ment Team. + At the beginning of development for what would eventually get + released as 3.6.0, the NetHack Development Team consisted of Warwick + Allison, Michael Allison, Ken Arromdee, David Cohrs, Jessie Collet, + Ken Lorber, Dean Luick, Pat Rankin, Mike Stephenson, Janet Walz, and + Paul Winner. In early 2015, ahead of the release of 3.6.0, new mem- + bers Sean Hunt, Pasi Kallinen, and Derek S. Ray joined the NetHack + Development Team. - Near the end of the development of 3.6.0, one of the significant - inspirations for many of the humorous and fun features found in the + Near the end of the development of 3.6.0, one of the significant + inspirations for many of the humorous and fun features found in the game, author Terry Pratchett, passed away. NetHack 3.6.0 introduced a tribute to him. - 3.6.0 was released in December 2015, and merged work done by the - development team since the release of 3.4.3 with some of the beloved - community patches. Many bugs were fixed and some code was restruc- - tured. - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -7264,129 +7264,129 @@ - The NetHack Development Team, as well as Steve VanDevender and - Kevin Smolkowski, ensured that NetHack 3.6 continued to operate on + 3.6.0 was released in December 2015, and merged work done by the + development team since the release of 3.4.3 with some of the beloved + community patches. Many bugs were fixed and some code was restruc- + tured. + + The NetHack Development Team, as well as Steve VanDevender and + Kevin Smolkowski, ensured that NetHack 3.6 continued to operate on various UNIX flavors and maintained the X11 interface. - Ken Lorber, Haoyang Wang, Pat Rankin, and Dean Luick maintained + Ken Lorber, Haoyang Wang, Pat Rankin, and Dean Luick maintained the port of NetHack 3.6 for MacOS. - Michael Allison, David Cohrs, Bart House, Pasi Kallinen, Alex - Kompel, Dion Nicolaas, Derek S. Ray and Yitzhak Sapir maintained the + Michael Allison, David Cohrs, Bart House, Pasi Kallinen, Alex + Kompel, Dion Nicolaas, Derek S. Ray and Yitzhak Sapir maintained the port of NetHack 3.6 for Microsoft Windows. - Pat Rankin attempted to keep the VMS port running for NetHack - 3.6, hindered by limited access. Kevin Smolkowski has updated and - tested it for the most recent version of OpenVMS (V8.4 as of this + Pat Rankin attempted to keep the VMS port running for NetHack + 3.6, hindered by limited access. Kevin Smolkowski has updated and + tested it for the most recent version of OpenVMS (V8.4 as of this writing) on Alpha and Integrity (aka Itanium aka IA64) but not VAX. - Ray Chason resurrected the MS-DOS port for 3.6 and contributed + Ray Chason resurrected the MS-DOS port for 3.6 and contributed the necessary updates to the community at large. - In late April 2018, several hundred bug fixes for 3.6.0 and some - new features were assembled and released as NetHack 3.6.1. The - NetHack Development Team at the time of release of 3.6.1 consisted of - Warwick Allison, Michael Allison, Ken Arromdee, David Cohrs, Jessie - Collet, Pasi Kallinen, Ken Lorber, Dean Luick, Patric Mueller, Pat - Rankin, Derek S. Ray, Alex Smith, Mike Stephenson, Janet Walz, and + In late April 2018, several hundred bug fixes for 3.6.0 and some + new features were assembled and released as NetHack 3.6.1. The + NetHack Development Team at the time of release of 3.6.1 consisted of + Warwick Allison, Michael Allison, Ken Arromdee, David Cohrs, Jessie + Collet, Pasi Kallinen, Ken Lorber, Dean Luick, Patric Mueller, Pat + Rankin, Derek S. Ray, Alex Smith, Mike Stephenson, Janet Walz, and Paul Winner. In early May 2019, another 320 bug fixes along with some enhance- ments and the adopted curses window port, were released as 3.6.2. - Bart House, who had contributed to the game as a porting team - participant for decades, joined the NetHack Development Team in late + Bart House, who had contributed to the game as a porting team + participant for decades, joined the NetHack Development Team in late May 2019. - NetHack 3.6.3 was released on December 5, 2019 containing over + NetHack 3.6.3 was released on December 5, 2019 containing over 190 bug fixes to NetHack 3.6.2. - NetHack 3.6.4 was released on December 18, 2019 containing a se- - curity fix and a few bug fixes. + NetHack 3.6.4 was released on December 18, 2019 containing a + security fix and a few bug fixes. - NetHack 3.6.5 was released on January 27, 2020 containing some + NetHack 3.6.5 was released on January 27, 2020 containing some security fixes and a small number of bug fixes. NetHack 3.6.6 was released on March 8, 2020 containing a security fix and some bug fixes. - NetHack 3.6.7 was released on February 16, 2023 containing a se- - curity fix and some bug fixes. - - The official NetHack web site is maintained by Ken Lorber at - https://www.nethack.org/. + NetHack 3.6.7 was released on February 16, 2023 containing a + security fix and some bug fixes. - - - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 NetHack Guidebook 112 + + + + The official NetHack web site is maintained by Ken Lorber at + https://www.nethack.org/. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 12.1. Special Thanks - On behalf of the NetHack community, thank you very much once - again to M. Drew Streib and Pasi Kallinen for providing a public - NetHack server at nethack.alt.org. Thanks to Keith Simpson and Andy - Thomson for hardfought.org. Thanks to all those unnamed dungeoneers - who invest their time and effort into annual NetHack tournaments such - as Junethack, The November NetHack Tournament, and in days past, de- - vnull.net (gone for now, but not forgotten). + On behalf of the NetHack community, thank you very much once + again to M. Drew Streib and Pasi Kallinen for providing a public + NetHack server at nethack.alt.org. Thanks to Keith Simpson and Andy + Thomson for hardfought.org. Thanks to all those unnamed dungeoneers + who invest their time and effort into annual NetHack tournaments such + as Junethack, The November NetHack Tournament, and in days past, + devnull.net (gone for now, but not forgotten). - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 12.2. Dungeoneers - - From time to time, some depraved individual out there in netland - sends a particularly intriguing modification to help out with the - - - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -7396,7 +7396,11 @@ - game. The NetHack Development Team sometimes makes note of the names + 12.2. Dungeoneers + + From time to time, some depraved individual out there in netland + sends a particularly intriguing modification to help out with the + game. The NetHack Development Team sometimes makes note of the names of the worst of these miscreants in this, the list of Dungeoneers: @@ -7445,14 +7449,10 @@ Andy Church Jeff Bailey Pasi Kallinen Andy Swanson Jochen Erwied Pat Rankin Andy Thomson John Kallen Patric Mueller - Ari Huttunen John Rupley Paul Winner - Bart House John S. Bien Pierre Martineau - Benson I. Margulies Johnny Lee Ralf Brown - Bill Dyer Jon W{tte Ray Chason - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -7462,6 +7462,10 @@ + Ari Huttunen John Rupley Paul Winner + Bart House John S. Bien Pierre Martineau + Benson I. Margulies Johnny Lee Ralf Brown + Bill Dyer Jon W{tte Ray Chason Boudewijn Waijers Jonathan Handler Richard Addison Bruce Cox Joshua Delahunty Richard Beigel Bruce Holloway Karl Garrison Richard P. Hughey @@ -7514,11 +7518,7 @@ - - - - - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 @@ -7528,7 +7528,7 @@ - Brand and product names are trademarks or registered trademarks + Brand and product names are trademarks or registered trademarks of their respective holders. @@ -7584,7 +7584,7 @@ - NetHack 3.7.0 September 13, 2024 + NetHack 3.7.0 November 16, 2024 diff --git a/doc/dlb.txt b/doc/dlb.txt index cd037be37..9e59bfd21 100644 --- a/doc/dlb.txt +++ b/doc/dlb.txt @@ -1,7 +1,10 @@ +WARNING OLD LINE DOES NOT MATCH .TH DLB 6 OLDLINE: '.TH DLB 6 DLB(6) Games Manual DLB(6) +"DATE(%-d %B %Y)" NETHACK' + NAME dlb - NetHack data librarian @@ -9,18 +12,18 @@ SYNOPSIS dlb { xct } [ vfIC ] arguments... [ files... ] DESCRIPTION - Dlb is a file archiving tool in the spirit (and tradition) of tar for - NetHack version 3.1 and higher. It is used to maintain the archive - files from which NetHack reads special level files and other read-only - information. Note that like tar the command and option specifiers are - specified as a continuous string and are followed by any arguments re- - quired in the same order as the option specifiers. + Dlb is a file archiving tool in the spirit (and tradition) of tar for + NetHack version 3.1 and higher. It is used to maintain the archive + files from which NetHack reads special level files and other read-only + information. Note that like tar the command and option specifiers are + specified as a continuous string and are followed by any arguments + required in the same order as the option specifiers. This facility is optional and may be excluded during NetHack configura- tion. COMMANDS - The x command causes dlb to extract the contents of the archive into + The x command causes dlb to extract the contents of the archive into the current directory. The c command causes dlb to create a new archive from files in the cur- @@ -34,11 +37,11 @@ OPTIONS AND ARGUMENTS f archive specify the archive. Default if f not specified is LIBFILE (usually the nhdat file in the playground). - I lfile specify the file containing the list of files to put in to + I lfile specify the file containing the list of files to put in to or extract from the archive if no files are listed on the command line. Default for archive creation if no files are listed is LIBLISTFILE. - C dir change directory. Changes directory before trying to read + C dir change directory. Changes directory before trying to read any files (including the archive and the lfile). EXAMPLES @@ -55,16 +58,16 @@ SEE ALSO nethack(6), tar(1) BUGS - Not a good tar emulation; - does not mean stdin or stdout. Should in- - clude an optional compression facility. Not all read-only files for + Not a good tar emulation; - does not mean stdin or stdout. Should + include an optional compression facility. Not all read-only files for NetHack can be read out of an archive; examining the source is the only way to know which files can be. COPYRIGHT - This file is Copyright (C) Kenneth Lorber, DATE(%Y) for version keni- - gitset:1.13. NetHack may be freely redistributed. See license for de- - tails. + This file is Copyright (C) Kenneth Lorber, 2024 for version keni-git- + set:1.13. NetHack may be freely redistributed. See license for + details. -NETHACK DATE(1-d 1B 1Y) DLB(6) +Project(uc) 24 December 2024 DLB(6) diff --git a/doc/makedefs.txt b/doc/makedefs.txt index 975a9cde5..e8c3a6c81 100644 --- a/doc/makedefs.txt +++ b/doc/makedefs.txt @@ -1,7 +1,10 @@ +WARNING OLD LINE DOES NOT MATCH .TH MAKEDEFS 6 OLDLINE: '.TH MAKEDEFS(6) Games Manual MAKEDEFS(6) +MAKEDEFS 6 "8 February 2022" NETHACK' + NAME makedefs - NetHack miscellaneous build-time functions @@ -11,11 +14,11 @@ SYNOPSIS makedefs --input file --output file --command DESCRIPTION - Makedefs is a build-time tool used for a variety of NetHack(6) source + Makedefs is a build-time tool used for a variety of NetHack(6) source file creation and modification tasks. For historical reasons, makedefs - takes two types of command lines. When invoked with a short option, - the files operated on are determined when makedefs is compiled. When - invoked with a long option, the --input and --output options are used + takes two types of command lines. When invoked with a short option, + the files operated on are determined when makedefs is compiled. When + invoked with a long option, the --input and --output options are used to specify the files for the --command. Each command is only available in one of the two formats. @@ -26,11 +29,11 @@ SHORT COMMANDS -d Generate data.base. - -e Generate dungeon.pdf. The input file dungeon.def is passed - through the same logic as that used by the --grep command; see + -e Generate dungeon.pdf. The input file dungeon.def is passed + through the same logic as that used by the --grep command; see the MDGREP FUNCTIONS section below for details. - -m Generate date.h and options file. It will read dat/gitinfo.txt, + -m Generate date.h and options file. It will read dat/gitinfo.txt, only if it is present, to obtain githash= and gitbranch= info and include related preprocessor #defines in date.h file. @@ -53,7 +56,7 @@ LONG COMMANDS Show debugging output. --make [command] - Execute a short command. Command is given without preceding + Execute a short command. Command is given without preceding dash. --input file @@ -61,67 +64,67 @@ LONG COMMANDS is - standard input is read. --output file - Specify the output file for the command (if needed). If the + Specify the output file for the command (if needed). If the file is - standard output is written. --svs [delimiter] - Generate a version string to standard output without a trailing - newline. If specified, the delimiter is used between each part + Generate a version string to standard output without a trailing + newline. If specified, the delimiter is used between each part of the version string. - --grep Filter the input file to the output file. See the MDGREP FUNC- + --grep Filter the input file to the output file. See the MDGREP FUNC- TIONS section below for information on controlling the filtering operation. --grep-showvars - Show the name and value for each variable known to the grep op- - tion. + Show the name and value for each variable known to the grep + option. --grep-trace - Turn on debug tracing for the grep function ( --grep must be + Turn on debug tracing for the grep function ( --grep must be specified as well). --grep-defined symbol - Exit shell true (0) if symbol is known and defined, otherwise + Exit shell true (0) if symbol is known and defined, otherwise exit shell false (1). --grep-define symbol - Force the value of symbol to be "defined." Symbol must already + Force the value of symbol to be "defined." Symbol must already be known to makedefs. --grep-undef symbol - Force the definition of symbol to be "undefined." Symbol must + Force the definition of symbol to be "undefined." Symbol must already be known to makedefs. MDGREP FUNCTIONS - The --grep command (and certain other commands) filter their input, on - a line-by-line basis, according to control lines embedded in the input - and on information gleaned from the NetHack(6) configuration. This al- - lows certain changes such as embedding platform-specific documentation - into the master documentation files. + The --grep command (and certain other commands) filter their input, on + a line-by-line basis, according to control lines embedded in the input + and on information gleaned from the NetHack(6) configuration. This + allows certain changes such as embedding platform-specific documenta- + tion into the master documentation files. Rules: - The default conditional state is printing enabled. - - Any line NOT starting with a caret (^) is either suppressed - or passed through unchanged depending on the current condi- + - Any line NOT starting with a caret (^) is either suppressed + or passed through unchanged depending on the current condi- tional state. - - Any line starting with a caret is a control line; as in C, - zero or more spaces may be embedded in the line almost any- - where (except immediately after the caret); however the + - Any line starting with a caret is a control line; as in C, + zero or more spaces may be embedded in the line almost any- + where (except immediately after the caret); however the caret must be in column 1. - Conditionals may be nested. - - Makedefs will exit with an error code if any errors are de- - tected; processing will continue (if it can) to allow as + - Makedefs will exit with an error code if any errors are + detected; processing will continue (if it can) to allow as many errors as possible to be detected. - - Unknown identifiers are treated as both TRUE and as an er- - ror. Note that --undef or #undef in the NetHack(6) configu- - ration are different from unknown. + - Unknown identifiers are treated as both TRUE and as an + error. Note that --undef or #undef in the NetHack(6) con- + figuration are different from unknown. Control lines: @@ -143,10 +146,10 @@ AUTHOR The NetHack Development Team COPYRIGHT - This file is Copyright (C) Kenneth Lorber, 2022 for version - NetHack-3.7:1.22. NetHack may be freely redistributed. See license + This file is Copyright (C) Kenneth Lorber, 2024 for version + NetHack-3.7:1.22. NetHack may be freely redistributed. See license for details. -NETHACK 8 February 2022 MAKEDEFS(6) +Project(uc) 24 December 2024 MAKEDEFS(6) diff --git a/doc/mn.txt b/doc/mn.txt index 502a0f3bb..1c42c2a04 100644 --- a/doc/mn.txt +++ b/doc/mn.txt @@ -17,8 +17,8 @@ DESCRIPTION All -mn macros, diversions, string registers, and number registers are defined below. Many nroff and troff requests are unsafe in conjunction - with this package. However, the requests below may be used with - impunity: + with this package. However, the requests below may be used with im- + punity: .bp begin new page .br break output line @@ -29,8 +29,8 @@ DESCRIPTION Font and point size changes with \f and \s are also allowed; for exam- ple, ``\f2word\fR'' will italicize word. Output of the tbl(1), eqn(1), - and refer(1) preprocessors for equations, tables, and references is - acceptable as input. + and refer(1) preprocessors for equations, tables, and references is ac- + ceptable as input. FILES /usr/lib/tmac/tmac.n @@ -47,12 +47,12 @@ WARNINGS This package is not now intended for uses other than with the news doc- umentation. - Bug reports are always welcome; please send them to the author. - (Include a sample of the input; this helps track down the bug.) + Bug reports are always welcome; please send them to the author. (In- + clude a sample of the input; this helps track down the bug.) AUTHOR - Matt Bishop (mab@riacs.arpa, ihnp4!ames!riacs!mab, dec- - vax!decwrl!riacs!mab) + Matt Bishop (mab@riacs.arpa, ihnp4!ames!riacs!mab, decvax!decwrl!ri- + acs!mab) Updated for versions 1.4-1.6 by The NetHack Development Team REQUESTS @@ -82,7 +82,7 @@ bt num .5i+1v - bottom of footer to bottom of page cm num 0 - 0 if no cut marks, nonzero if cut marks .cn x y z mac - - print computer/site name; same as .i .dd div - i text of display -dg str *,- - footnote mark +dg str *,<*> - footnote mark dw str current - name of current day of week dy str current - full date .ed mac - b end display diff --git a/doc/nethack.txt b/doc/nethack.txt index 39f8d3bd9..80c7870f2 100644 --- a/doc/nethack.txt +++ b/doc/nethack.txt @@ -1,7 +1,10 @@ +WARNING OLD LINE DOES NOT MATCH .TH NETHACK 6 OLDLINE: '.TH NETHACK(6) Games Manual NETHACK(6) +NETHACK 6 "21 February 2022" NETHACK' + NAME nethack - Exploring The Mazes of Menace @@ -20,84 +23,84 @@ SYNOPSIS [ --version[:copy|:dump|:show] ] DESCRIPTION - NetHack is a display oriented Dungeons & Dragons(tm) - like game. The + NetHack is a display oriented Dungeons & Dragons(tm) - like game. The standard tty display and command structure resemble rogue. Other, more graphical display options exist for most platforms. - To get started you really only need to know two commands. The command - ? will give you a list of the available commands (as well as other - information) and the command / will identify the things you see on the + To get started you really only need to know two commands. The command + ? will give you a list of the available commands (as well as other + information) and the command / will identify the things you see on the screen. - To win the game (as opposed to merely playing to beat other people's - high scores) you must locate the Amulet of Yendor which is somewhere + To win the game (as opposed to merely playing to beat other people's + high scores) you must locate the Amulet of Yendor which is somewhere below the 20th level of the dungeon and get it out. Few people achieve - this; most never do. Those who have done so go down in history as - heroes among heroes -- and then they find ways of making the game even - harder. See the Guidebook section on Conduct if this game has gotten + this; most never do. Those who have done so go down in history as + heroes among heroes -- and then they find ways of making the game even + harder. See the Guidebook section on Conduct if this game has gotten too easy for you. - When the game ends, whether by your dying, quitting, or escaping from - the caves, NetHack will give you (a fragment of) the list of top scor- - ers. The scoring is based on many aspects of your behavior, but a + When the game ends, whether by your dying, quitting, or escaping from + the caves, NetHack will give you (a fragment of) the list of top scor- + ers. The scoring is based on many aspects of your behavior, but a rough estimate is obtained by taking the amount of gold you've found in - the cave plus four times your (real) experience. Precious stones may - be worth a lot of gold when brought to the exit. There is a 10% pen- + the cave plus four times your (real) experience. Precious stones may + be worth a lot of gold when brought to the exit. There is a 10% pen- alty for getting yourself killed. - The environment variable NETHACKOPTIONS can be used to initialize many - run-time options. The ? command provides a description of these - options and syntax. (The -dec and -ibm command line options are mutu- - ally exclusive and are equivalent to the decgraphics and ibmgraphics - run-time options described there, and are provided purely for conve- + The environment variable NETHACKOPTIONS can be used to initialize many + run-time options. The ? command provides a description of these + options and syntax. (The -dec and -ibm command line options are mutu- + ally exclusive and are equivalent to the decgraphics and ibmgraphics + run-time options described there, and are provided purely for conve- nience on systems supporting multiple types of terminals.) - Because the option list can be very long, options may also be included + Because the option list can be very long, options may also be included in a configuration file. The default is located in your home directory - and named .nethackrc on UNIX systems (including descendants such as + and named .nethackrc on UNIX systems (including descendants such as linux, NetBSD, and macOS). On Windows, the name is also .nethackrc but - the location can vary (see --showpaths below). On other systems, the + the location can vary (see --showpaths below). On other systems, the default may be different, possibly NetHack.cnf. On MS-DOS, the name is defaults.nh in NetHack's directory (folder), while on VMS|OpenVMS it is nethack.ini in your home directory. The default configuration file may - be overridden via the --nethackrc:rc-file command line option or by + be overridden via the --nethackrc:rc-file command line option or by setting NETHACKOPTIONS in your environment to a string consisting of an @ character followed by the path and filename. - The -u playername option supplies the answer to the question "Who are - you?". It overrides any name from the options or configuration file, - USER, LOGNAME, or getlogin(), which will otherwise be tried in order. - If none of these provides a useful name, the player will be asked for + The -u playername option supplies the answer to the question "Who are + you?". It overrides any name from the options or configuration file, + USER, LOGNAME, or getlogin(), which will otherwise be tried in order. + If none of these provides a useful name, the player will be asked for one. Player names (in conjunction with uids) are used to identify save files, so you can have several saved games under different names. Con- - versely, you must use the appropriate player name to restore a saved + versely, you must use the appropriate player name to restore a saved game. A playername suffix can be used to specify the profession, race, align- ment and/or gender of the character. The full syntax of the playername - that includes a suffix is "name-ppp-rrr-aaa-ggg". "ppp" are at least - the first three letters of the profession (this can also be specified - using a separate -p profession option). "rrr" are at least the first + that includes a suffix is "name-ppp-rrr-aaa-ggg". "ppp" are at least + the first three letters of the profession (this can also be specified + using a separate -p profession option). "rrr" are at least the first three letters of the character's race (this can also be specified using a separate -r race option). "aaa" are at least the first three letters - of the character's alignment, and "ggg" are at least the first three - letters of the character's gender. Any of the parts of the suffix may + of the character's alignment, and "ggg" are at least the first three + letters of the character's gender. Any of the parts of the suffix may be left out. - -p profession can be used to determine the character profession, also - known as the role. You can specify either the male or female name for - the character role, or the first three characters of the role as an + -p profession can be used to determine the character profession, also + known as the role. You can specify either the male or female name for + the character role, or the first three characters of the role as an abbreviation. Likewise, -r race can be used to explicitly request that a race be cho- sen. The -A|-Arc | -B|-Bar | -C|-Cav | -H|-Hea | -K|-Kni | -M|-Mon | -P|-Pri - | -R|-Rog | -Ran | -S|-Sam | -T|-Tou | -V|-Val | -W|-Wiz options for - role selection are maintained for compatibility with older versions of - the program. They are mutually exclusive and the single-letter form - must be uppercase. Ranger has no single-letter choice because -R is + | -R|-Rog | -Ran | -S|-Sam | -T|-Tou | -V|-Val | -W|-Wiz options for + role selection are maintained for compatibility with older versions of + the program. They are mutually exclusive and the single-letter form + must be uppercase. Ranger has no single-letter choice because -R is already used for the Rogue role. -@ tells nethack to choose any omitted characteristics (profes- @@ -108,97 +111,97 @@ DESCRIPTION The -n option suppresses printing of any news from the game administra- tor. - The -X option will start the game in a special non-scoring discovery - mode (also known as explore mode). -D will start the game in debug - mode (also known as wizard mode) after changing the character name to - "wizard", if the player is allowed. Otherwise it will switch to -X. - Control of who is allowed to use debug mode is done via the "WIZARDS=" + The -X option will start the game in a special non-scoring discovery + mode (also known as explore mode). -D will start the game in debug + mode (also known as wizard mode) after changing the character name to + "wizard", if the player is allowed. Otherwise it will switch to -X. + Control of who is allowed to use debug mode is done via the "WIZARDS=" line in nethack's sysconf file. - The -d or --directory option, which must be the first argument if it - appears, supplies a directory which is to serve as the playground. It - overrides the value from NETHACKDIR, HACKDIR, or the directory speci- - fied by the game administrator during compilation (usually - /usr/games/lib/nethackdir). This option is usually only useful to the - game administrator. The playground must contain several auxiliary - files such as help files, the list of top scorers, and a subdirectory + The -d or --directory option, which must be the first argument if it + appears, supplies a directory which is to serve as the playground. It + overrides the value from NETHACKDIR, HACKDIR, or the directory speci- + fied by the game administrator during compilation (usually + /usr/games/lib/nethackdir). This option is usually only useful to the + game administrator. The playground must contain several auxiliary + files such as help files, the list of top scorers, and a subdirectory save where games are saved. - The -w or --windowtype interface option can be used to specify which - interface to use if the program has been built with support for more - than one. Specifying a value on the command line overrides any value - specified in the run-time configuration file. NetHack's #version com- + The -w or --windowtype interface option can be used to specify which + interface to use if the program has been built with support for more + than one. Specifying a value on the command line overrides any value + specified in the run-time configuration file. NetHack's #version com- mand shows available interfaces. - The --nethackrc:RC-file option will use RC-file instead of the default - run-time configuration file (typically ~/.nethackrc) and the - --no-nethackrc option can be used to skip any run-time configuration + The --nethackrc:RC-file option will use RC-file instead of the default + run-time configuration file (typically ~/.nethackrc) and the + --no-nethackrc option can be used to skip any run-time configuration file. Some options provide feedback and then exit rather than play the game: - The -s or --scores option alone will print out the list of your scores - on the current version. An immediately following -v reports on all + The -s or --scores option alone will print out the list of your scores + on the current version. An immediately following -v reports on all versions present in the score file. '-s|-s -v' may also be followed by - arguments -p profession and -r race to print the scores of particular - roles and races only. Either can be specified multiple times to + arguments -p profession and -r race to print the scores of particular + roles and races only. Either can be specified multiple times to include more than one role or more than one race. When both are speci- - fied, score entries which match either the role or the race (or both) - are printed rather than just entries which match both. '-s|-s -v' may - be followed by one or more player names to print the scores of the - players mentioned, by 'all' to print out all scores, or by a number to - print that many top scores. Combining names with role or race or both - will report entries which match any of those rather than just the ones + fied, score entries which match either the role or the race (or both) + are printed rather than just entries which match both. '-s|-s -v' may + be followed by one or more player names to print the scores of the + players mentioned, by 'all' to print out all scores, or by a number to + print that many top scores. Combining names with role or race or both + will report entries which match any of those rather than just the ones which match all. - --version or --version:show can be used to cause NetHack to show the - version number, the date and time that the program was built from its - source code, and possibly some auxiliary information about that source + --version or --version:show can be used to cause NetHack to show the + version number, the date and time that the program was built from its + source code, and possibly some auxiliary information about that source code, then exit. The optional auxiliary information is git commit hash - (reflecting the source code's most recent modification when extracted - from the git version control system, if that is in use) if available - when the program was built. On some platforms such as Windows and - macOS, a variation, --version:copy, can be used to cause NetHack to - show the version information, then exit, while also leaving a copy of - that information in the paste buffer or clipboard for potential inser- + (reflecting the source code's most recent modification when extracted + from the git version control system, if that is in use) if available + when the program was built. On some platforms such as Windows and + macOS, a variation, --version:copy, can be used to cause NetHack to + show the version information, then exit, while also leaving a copy of + that information in the paste buffer or clipboard for potential inser- tion into things like bug reports. On any platform, --version:dump can be used to show most of the data used when checking whether a save file or bones file is compatible with the program. The program will display a line containing five numbers expressed in hexadecimal, then exit. - --showpaths can be used to cause NetHack to show where it is expecting - to find various files. Among other things it shows the path to and - name for the player's run-time configuration file, a text file which + --showpaths can be used to cause NetHack to show where it is expecting + to find various files. Among other things it shows the path to and + name for the player's run-time configuration file, a text file which can be edited to customize aspects of how the game operates. --usage or --help will display information similar to this manual page, then exit. Use 'nethack --usage | more' to read it a page at a time. AUTHORS - Jay Fenlason (+ Kenny Woodland, Mike Thome and Jon Payne) wrote the + Jay Fenlason (+ Kenny Woodland, Mike Thome and Jon Payne) wrote the original hack, very much like rogue (but full of bugs). - Andries Brouwer continuously deformed their sources into an entirely + Andries Brouwer continuously deformed their sources into an entirely different game. Mike Stephenson has continued the perversion of sources, adding various - warped character classes and sadistic traps with the help of many - strange people who reside in that place between the worlds, the Usenet - Zone. A number of these miscreants are immortalized in the historical + warped character classes and sadistic traps with the help of many + strange people who reside in that place between the worlds, the Usenet + Zone. A number of these miscreants are immortalized in the historical roll of dishonor and various other places. - The resulting mess is now called NetHack, to denote its development by + The resulting mess is now called NetHack, to denote its development by the Usenet. Andries Brouwer has made this request for the distinction, as he may eventually release a new version of his own. FILES - Run-time configuration options were discussed above and use a platform - specific name for a file in a platform specific location. For Unix, + Run-time configuration options were discussed above and use a platform + specific name for a file in a platform specific location. For Unix, the name is '.nethackrc' in the user's home directory. - All other files are in the playground directory, normally - /usr/games/lib/nethackdir. If DLB was defined during the compile, the - data files and special levels will be inside a larger file, normally + All other files are in the playground directory, normally + /usr/games/lib/nethackdir. If DLB was defined during the compile, the + data files and special levels will be inside a larger file, normally nhdat, instead of being separate files. nethack The program itself. @@ -244,11 +247,11 @@ FILES program is built with 'SYSCF' option enabled, ignored if not. - The location of 'sysconf' is specified at build time and can't be - changed except by updating source file "config.h" and rebuilding the + The location of 'sysconf' is specified at build time and can't be + changed except by updating source file "config.h" and rebuilding the program. - NetHack's Guidebook might not be present if whoever packaged or + NetHack's Guidebook might not be present if whoever packaged or installed the program distribution neglected to include it. In a perfect world, 'paniclog' would remain empty. @@ -265,7 +268,7 @@ ENVIRONMENT NETHACKDIR or HACKDIR Playground. NETHACKOPTIONS String predefining several NetHack options. - If the same option is specified in both NETHACKOPTIONS and .nethackrc, + If the same option is specified in both NETHACKOPTIONS and .nethackrc, the value assigned in NETHACKOPTIONS takes precedence. SHOPTYPE and SPLEVTYPE can be used in debugging (wizard) mode. @@ -278,12 +281,12 @@ BUGS Probably infinite. COPYRIGHT - This file is Copyright (C) Robert Patrick Rankin, 2022 for version - NetHack-3.7:1.31. NetHack may be freely redistributed. See license + This file is Copyright (C) Robert Patrick Rankin, 2024 for version + NetHack-3.7:1.31. NetHack may be freely redistributed. See license for details. Dungeons & Dragons is a Trademark of Wizards of the Coast, Inc. -NETHACK 21 February 2022 NETHACK(6) +Project(uc) 24 December 2024 NETHACK(6) diff --git a/doc/recover.txt b/doc/recover.txt index b19d9cb43..49c583642 100644 --- a/doc/recover.txt +++ b/doc/recover.txt @@ -1,7 +1,10 @@ +WARNING OLD LINE DOES NOT MATCH .TH RECOVER 6 OLDLINE: '.TH RE- RECOVER(6) Games Manual RECOVER(6) +COVER 6 "8 February 2022" NETHACK' + NAME recover - recover a NetHack game interrupted by disaster @@ -9,60 +12,60 @@ SYNOPSIS recover [ -d directory ] base1 base2 ... DESCRIPTION - Occasionally, a NetHack game will be interrupted by disaster when the - game or the system crashes. Prior to NetHack v3.1, these games were - lost because various information like the player's inventory was kept - only in memory. Now, all pertinent information can be written out to - disk, so such games can be recovered at the point of the last level + Occasionally, a NetHack game will be interrupted by disaster when the + game or the system crashes. Prior to NetHack v3.1, these games were + lost because various information like the player's inventory was kept + only in memory. Now, all pertinent information can be written out to + disk, so such games can be recovered at the point of the last level change. The base options tell recover which files to process. Each base option specifies recovery of a separate game. The -d option, which must be the first argument if it appears, supplies - a directory which is the NetHack playground. It overrides the value + a directory which is the NetHack playground. It overrides the value from NETHACKDIR, HACKDIR, or the directory specified by the game admin- istrator during compilation (usually /usr/games/lib/nethackdir). - For recovery to be possible, nethack must have been compiled with the - INSURANCE option, and the run-time option checkpoint must also have - been on. NetHack normally writes out files for levels as the player + For recovery to be possible, nethack must have been compiled with the + INSURANCE option, and the run-time option checkpoint must also have + been on. NetHack normally writes out files for levels as the player leaves them, so they will be ready for return visits. When checkpoint- - ing, NetHack also writes out the level entered and the current game - state on every level change. This naturally slows level changes down + ing, NetHack also writes out the level entered and the current game + state on every level change. This naturally slows level changes down somewhat. - The level file names are of the form base.nn, where nn is an internal - bookkeeping number for the level. The file base.0 is used for game - identity, locking, and, when checkpointing, for the game state. Vari- - ous OSes use different strategies for constructing the base name. Mi- - crocomputers use the character name, possibly truncated and modified to - be a legal filename on that system. Multi-user systems use the (modi- - fied) character name prefixed by a user number to avoid conflicts, or - "xlock" if the number of concurrent players is being limited. It may - be necessary to look in the playground to find the correct base name of - the interrupted game. recover will transform these level files into a - save file of the same name as nethack would have used. + The level file names are of the form base.nn, where nn is an internal + bookkeeping number for the level. The file base.0 is used for game + identity, locking, and, when checkpointing, for the game state. Vari- + ous OSes use different strategies for constructing the base name. + Microcomputers use the character name, possibly truncated and modified + to be a legal filename on that system. Multi-user systems use the + (modified) character name prefixed by a user number to avoid conflicts, + or "xlock" if the number of concurrent players is being limited. It + may be necessary to look in the playground to find the correct base + name of the interrupted game. recover will transform these level files + into a save file of the same name as nethack would have used. Since recover must be able to read and delete files from the playground and create files in the save directory, it has interesting interactions - with game security. Giving ordinary players access to recover through - setuid or setgid is tantamount to leaving the playground world- - writable, with respect to both cheating and messing up other players. - For a single-user system, this of course does not change anything, so + with game security. Giving ordinary players access to recover through + setuid or setgid is tantamount to leaving the playground world- + writable, with respect to both cheating and messing up other players. + For a single-user system, this of course does not change anything, so some of the microcomputer ports install recover by default. For a multi-user system, the game administrator may want to arrange for - all .0 files in the playground to be fed to recover when the host ma- - chine boots, and handle game crashes individually. If the user popula- - tion is sufficiently trustworthy, recover can be installed with the - same permissions the nethack executable has. In either case, recover + all .0 files in the playground to be fed to recover when the host + machine boots, and handle game crashes individually. If the user popu- + lation is sufficiently trustworthy, recover can be installed with the + same permissions the nethack executable has. In either case, recover is easily compiled from the distribution utility directory. NOTES - Like nethack itself, recover will overwrite existing savefiles of the - same name. Savefiles created by recover are uncompressed; they may be - compressed afterwards if desired, but even a compression-using nethack + Like nethack itself, recover will overwrite existing savefiles of the + same name. Savefiles created by recover are uncompressed; they may be + compressed afterwards if desired, but even a compression-using nethack will find them in the uncompressed form. SEE ALSO @@ -70,17 +73,17 @@ SEE ALSO BUGS recover makes no attempt to find out if a base name specifies a game in - progress. If multiple machines share a playground, this would be im- - possible to determine. + progress. If multiple machines share a playground, this would be + impossible to determine. - recover should be taught to use the nethack playground locking mecha- + recover should be taught to use the nethack playground locking mecha- nism to avoid conflicts. COPYRIGHT - This file is Copyright (C) Kenneth Lorber, 2022 for version - NetHack-3.7:1.12. NetHack may be freely redistributed. See license + This file is Copyright (C) Kenneth Lorber, 2024 for version + NetHack-3.7:1.12. NetHack may be freely redistributed. See license for details. -NETHACK 8 February 2022 RECOVER(6) +Project(uc) 24 December 2024 RECOVER(6) From 09693f618f4648fd4ff15a84496e5b9a2e2a68e5 Mon Sep 17 00:00:00 2001 From: nhkeni Date: Tue, 24 Dec 2024 19:24:15 -0500 Subject: [PATCH 241/791] Fix header spelling error "DATE" -> "Date"; force update dates. --- doc/Guidebook.mn | 4 ++-- doc/dlb.6 | 10 +++++----- doc/makedefs.6 | 8 ++++---- doc/nethack.6 | 8 ++++---- doc/recover.6 | 8 ++++---- 5 files changed, 19 insertions(+), 19 deletions(-) diff --git a/doc/Guidebook.mn b/doc/Guidebook.mn index 7d5eabde2..574bed82b 100644 --- a/doc/Guidebook.mn +++ b/doc/Guidebook.mn @@ -1,4 +1,4 @@ -.\" $NHDT-Branch: keni-gitset $:$NHDT-Revision: 1.593 $ $NHDT-Date: 1730681007 2024/11/04 00:43:27 $ +.\" $NHDT-Branch: master $:$NHDT-Revision: 1.596 $ $NHDT-Date: 1735103892 2024/12/25 00:18:12 $ .\" .\" This is an excerpt from the 'roff' man page from the 'groff' package. .\"+-- @@ -47,7 +47,7 @@ .ds f0 \*(vr .ds f1 \" empty .\"DO NOT REMOVE NH_DATESUB .ds f2 Date(%B %-d, %Y) -.ds f2 November 16, 2024 +.ds f2 December 25, 2024 . .\" A note on some special characters: .\" \(lq = left double quote diff --git a/doc/dlb.6 b/doc/dlb.6 index f70a3da41..653e17210 100644 --- a/doc/dlb.6 +++ b/doc/dlb.6 @@ -1,8 +1,8 @@ -.\" $NHDT-Branch: keni-gitset $:$NHDT-Revision: 1.13 $ $NHDT-Date: 1730949315 2024/11/06 22:15:15 $ -.\"DO NOT REMOVE NH_DATESUB .TH DLB 6 "DATE(%-d %B %Y)" Project(uc) -.TH DLB 6 "DATE(%-d %B %Y)" NETHACK -.\"DO NOT REMOVE NH_DATESUB .ds Nd DATE(%Y) -.ds Nd DATE(%Y) +.\" $NHDT-Branch: master $:$NHDT-Revision: 1.14 $ $NHDT-Date: 1735103831 2024/12/25 00:17:11 $ +.\"DO NOT REMOVE NH_DATESUB .TH DLB 6 "Date(%-d %B %Y)" Project(uc) +.TH DLB 6 "25 December 2024" NETHACK +.\"DO NOT REMOVE NH_DATESUB .ds Nd Date(%Y) +.ds Nd 2024 .de NB .ds Nb \\$2 .. diff --git a/doc/makedefs.6 b/doc/makedefs.6 index 4da8c4b43..136084473 100644 --- a/doc/makedefs.6 +++ b/doc/makedefs.6 @@ -1,7 +1,7 @@ -.\"DO NOT REMOVE NH_DATESUB .TH MAKEDEFS 6 "DATE(%-d %B %Y)" Project(uc) -.TH MAKEDEFS 6 "8 February 2022" NETHACK -.\"DO NOT REMOVE NH_DATESUB .ds Nd DATE(%Y) -.ds Nd 2022 +.\"DO NOT REMOVE NH_DATESUB .TH MAKEDEFS 6 "Date(%-d %B %Y)" Project(uc) +.TH MAKEDEFS 6 "25 December 2024" NETHACK +.\"DO NOT REMOVE NH_DATESUB .ds Nd Date(%Y) +.ds Nd 2024 .de NB .ds Nb \\$2 .. diff --git a/doc/nethack.6 b/doc/nethack.6 index 3c1c7f6c9..3605423ca 100644 --- a/doc/nethack.6 +++ b/doc/nethack.6 @@ -1,7 +1,7 @@ -.\"DO NOT REMOVE NH_DATESUB .TH NETHACK 6 "DATE(%-d %B %Y)" Project(uc) -.TH NETHACK 6 "21 February 2022" NETHACK -.\"DO NOT REMOVE NH_DATESUB .ds Nd DATE(%Y) -.ds Nd 2022 +.\"DO NOT REMOVE NH_DATESUB .TH NETHACK 6 "Date(%-d %B %Y)" Project(uc) +.TH NETHACK 6 "25 December 2024" NETHACK +.\"DO NOT REMOVE NH_DATESUB .ds Nd Date(%Y) +.ds Nd 2024 .de NB .ds Nb \\$2 .. diff --git a/doc/recover.6 b/doc/recover.6 index 488e9e33b..f291917f9 100644 --- a/doc/recover.6 +++ b/doc/recover.6 @@ -1,7 +1,7 @@ -.\"DO NOT REMOVE NH_DATESUB .TH RECOVER 6 "DATE(%-d %B %Y)" Project(uc) -.TH RECOVER 6 "8 February 2022" NETHACK -.\"DO NOT REMOVE NH_DATESUB .ds Nd DATE(%Y) -.ds Nd 2022 +.\"DO NOT REMOVE NH_DATESUB .TH RECOVER 6 "Date(%-d %B %Y)" Project(uc) +.TH RECOVER 6 "25 December 2024" NETHACK +.\"DO NOT REMOVE NH_DATESUB .ds Nd Date(%Y) +.ds Nd 2024 .de NB .ds Nb \\$2 .. From a331a667e58c1dc2a5f99e932a0effd9f3e8fb8a Mon Sep 17 00:00:00 2001 From: keni Date: Wed, 25 Dec 2024 14:58:48 -0500 Subject: [PATCH 242/791] 3.7 setup for autodocs --- doc/.gitattributes | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/doc/.gitattributes b/doc/.gitattributes index 5edfa047f..45adbe48d 100644 --- a/doc/.gitattributes +++ b/doc/.gitattributes @@ -11,5 +11,6 @@ fixes* NH_header=no *.txt NH_header=no * NH_filestag=(file%s_for_all_versions) Guidebook.tex NH_DATESUB -Guidebook.mn NH_DATESUB -*.6 NH_DATESUB +Guidebook.mn NH_DATESUB NHAUTODOCS +*.6 NH_DATESUB NHAUTODOCS +*.7 NH_DATESUB NHAUTODOCS From 47ccaf3f26635062220c8c20f4fc02f4ecb9ef89 Mon Sep 17 00:00:00 2001 From: keni Date: Wed, 25 Dec 2024 20:23:00 -0500 Subject: [PATCH 243/791] more .gitattributes --- doc/.gitattributes | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/.gitattributes b/doc/.gitattributes index 45adbe48d..1d1afaeab 100644 --- a/doc/.gitattributes +++ b/doc/.gitattributes @@ -14,3 +14,4 @@ Guidebook.tex NH_DATESUB Guidebook.mn NH_DATESUB NHAUTODOCS *.6 NH_DATESUB NHAUTODOCS *.7 NH_DATESUB NHAUTODOCS +fixes* -NHAUTODOCS From e6e0913878f69a47ade98acbea5b87ca9554ae8c Mon Sep 17 00:00:00 2001 From: nhmall Date: Thu, 26 Dec 2024 17:34:18 -0500 Subject: [PATCH 244/791] doc/* from cron job --- doc/Guidebook.txt | 230 +++++++++++++++++++++++----------------------- doc/dlb.txt | 29 +++--- doc/makedefs.txt | 69 +++++++------- doc/nethack.txt | 201 ++++++++++++++++++++-------------------- doc/recover.txt | 71 +++++++------- 5 files changed, 294 insertions(+), 306 deletions(-) diff --git a/doc/Guidebook.txt b/doc/Guidebook.txt index 480c55893..73e12bdb0 100644 --- a/doc/Guidebook.txt +++ b/doc/Guidebook.txt @@ -15,7 +15,7 @@ Original version - Eric S. Raymond (Edited and expanded for NetHack 3.7.0 by Mike Stephenson and others) - November 16, 2024 + December 25, 2024 @@ -126,7 +126,7 @@ - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -192,7 +192,7 @@ NetHack continues this fine tradition. Unlike text adventure games - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -258,7 +258,7 @@ - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -324,7 +324,7 @@ - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -390,7 +390,7 @@ - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -456,7 +456,7 @@ The number of turns elapsed so far, displayed if you have the - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -522,7 +522,7 @@ - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -588,7 +588,7 @@ - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -654,7 +654,7 @@ - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -720,7 +720,7 @@ instead. Only these one-step movement commands cause you to - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -786,7 +786,7 @@ ing . ^ is used as shorthand elsewhere in the - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -852,7 +852,7 @@ - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -918,7 +918,7 @@ - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -984,7 +984,7 @@ - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -1050,7 +1050,7 @@ at an adjacent "remembered, unseen monster" marker. - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -1116,7 +1116,7 @@ - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -1182,7 +1182,7 @@ (R)UNIX is a registered trademark of The Open Group. - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -1248,7 +1248,7 @@ menu_next_page, and menu_last_page keys (`^', `<', `>', `|' by - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -1314,7 +1314,7 @@ doesn't and give that name to the result, while splitting (count - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -1380,7 +1380,7 @@ - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -1446,7 +1446,7 @@ extinct. - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -1512,7 +1512,7 @@ - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -1578,7 +1578,7 @@ - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -1644,7 +1644,7 @@ right away.) Since using this command by accident can cause - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -1710,7 +1710,7 @@ Default key is `M-R'. - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -1776,7 +1776,7 @@ (worn blindfold or towel or lenses, lit lamp(s) and/or candle(s), - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -1842,7 +1842,7 @@ - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -1908,7 +1908,7 @@ line will show "(no travel path)" if your character does not know - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -1974,7 +1974,7 @@ - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -2040,7 +2040,7 @@ Set one or more intrinsic attributes. Autocompletes. Debug mode - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -2106,7 +2106,7 @@ "high"] bit), you can invoke many extended commands by meta-ing the - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -2172,7 +2172,7 @@ - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -2238,7 +2238,7 @@ - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -2304,7 +2304,7 @@ - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -2370,7 +2370,7 @@ them). Some monsters who can open doors can also use unlocking tools. - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -2436,7 +2436,7 @@ been nullified, giving access to whatever is beyond them. In the - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -2502,7 +2502,7 @@ play. - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -2568,7 +2568,7 @@ - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -2634,7 +2634,7 @@ attack, when guessing where an unseen monster is or when deliberately - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -2700,7 +2700,7 @@ noid_confirmation:attack option to require a response of "yes" - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -2766,7 +2766,7 @@ - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -2832,7 +2832,7 @@ are encumbered, one of the conditions Burdened, Stressed, Strained, - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -2898,7 +2898,7 @@ - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -2964,7 +2964,7 @@ `X' command to engage or disengage that. Only some types of charac- - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -3030,7 +3030,7 @@ - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -3096,7 +3096,7 @@ you'll be told that you feel more confident in your skills. At that - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -3162,7 +3162,7 @@ - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -3228,7 +3228,7 @@ what you eat." - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -3294,7 +3294,7 @@ ever, for this is often unwise. Other types of wands don't require a - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -3360,7 +3360,7 @@ - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -3426,7 +3426,7 @@ play the entire game without being able to see (a self-imposed chal- - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -3492,7 +3492,7 @@ - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -3558,7 +3558,7 @@ set the goldX option if you prefer to have gold pieces be treated as - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -3624,7 +3624,7 @@ eating such items still counts against foodless conduct. - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -3690,7 +3690,7 @@ "X" (the traditional signature of an illiterate person). Reading an - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -3756,7 +3756,7 @@ - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -3822,7 +3822,7 @@ achievement. - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -3888,7 +3888,7 @@ (the closing `]' can be followed by whitespace and then an arbitrary - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -3954,7 +3954,7 @@ problems is kept. Defaults to HACKDIR, must be writable. - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -4020,7 +4020,7 @@ Custom symbols for the rogue level's symbol set. See SYMBOLS below. - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -4086,7 +4086,7 @@ You turn one of these on by adding the name of the option to the list, - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -4152,7 +4152,7 @@ and the non-human races restrict which alignments are allowed. See - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -4218,7 +4218,7 @@ wielded weapon (if you omit untrap or decline to attempt - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -4284,7 +4284,7 @@ If this option is on, items you dropped will not be automatically - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -4350,7 +4350,7 @@ Name your starting dog (for example "dogname:Fang"). Cannot be set - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -4416,7 +4416,7 @@ blessed or cursed, but it is not described as "uncursed" even when - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -4482,7 +4482,7 @@ - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -4548,7 +4548,7 @@ response to the Drop (aka droptype) command, for instance). The - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -4614,7 +4614,7 @@ - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -4680,7 +4680,7 @@ - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -4746,7 +4746,7 @@ are filled in at the end from the previous order. - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -4812,7 +4812,7 @@ new entries and remove some old ones, you can use multiple para- - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -4878,7 +4878,7 @@ Persistent. - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -4944,7 +4944,7 @@ - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -5010,7 +5010,7 @@ trol+direction and so forth, or via the travel command or mouse - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -5076,7 +5076,7 @@ ants, or you are making screenshots or streaming video. Using the - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -5142,7 +5142,7 @@ others; - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -5208,7 +5208,7 @@ - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -5274,7 +5274,7 @@ on a doorway, it will consider the area on the side of the door you - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -5340,7 +5340,7 @@ right) - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -5406,7 +5406,7 @@ - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -5472,7 +5472,7 @@ - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -5538,7 +5538,7 @@ - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -5604,7 +5604,7 @@ - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -5670,7 +5670,7 @@ strokes that the operating system returns to NetHack to help compen- - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -5736,7 +5736,7 @@ - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -5802,7 +5802,7 @@ The menu control or accelerator keys can also be rebound via OPTIONS - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -5868,7 +5868,7 @@ - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -5934,7 +5934,7 @@ ing for more info, and exit the location asking loop. Default is - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -6000,7 +6000,7 @@ - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -6066,7 +6066,7 @@ - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -6132,7 +6132,7 @@ cause the hitpoints field to display in the color red if your hit- - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -6198,7 +6198,7 @@ - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -6264,7 +6264,7 @@ - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -6330,7 +6330,7 @@ value, and the ^ prefix causes the following character to be treated - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -6396,7 +6396,7 @@ - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -6462,7 +6462,7 @@ - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -6528,7 +6528,7 @@ - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -6594,7 +6594,7 @@ - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -6660,7 +6660,7 @@ - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -6726,7 +6726,7 @@ seen via the "#attributes" command. - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -6792,7 +6792,7 @@ - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -6858,7 +6858,7 @@ the livelog file if one is present. The sample sysconf file accom- - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -6924,7 +6924,7 @@ are left for the trepid reader to discover. - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -6990,7 +6990,7 @@ 1.4 in 1987. He then coordinated a cast of thousands in enhancing and - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -7056,7 +7056,7 @@ NetHack 3.1 to the Atari. Pat Rankin, with help from Joshua - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -7122,7 +7122,7 @@ Slash'EM, and with the help of Kevin Hugo, added more features. Kevin - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -7188,7 +7188,7 @@ the Macintosh port of 3.4. - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -7254,7 +7254,7 @@ - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -7320,7 +7320,7 @@ - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -7386,7 +7386,7 @@ - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -7452,7 +7452,7 @@ - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -7518,7 +7518,7 @@ - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 @@ -7584,7 +7584,7 @@ - NetHack 3.7.0 November 16, 2024 + NetHack 3.7.0 December 25, 2024 diff --git a/doc/dlb.txt b/doc/dlb.txt index 9e59bfd21..412c19820 100644 --- a/doc/dlb.txt +++ b/doc/dlb.txt @@ -1,10 +1,7 @@ -WARNING OLD LINE DOES NOT MATCH .TH DLB 6 OLDLINE: '.TH DLB 6 DLB(6) Games Manual DLB(6) -"DATE(%-d %B %Y)" NETHACK' - NAME dlb - NetHack data librarian @@ -12,18 +9,18 @@ SYNOPSIS dlb { xct } [ vfIC ] arguments... [ files... ] DESCRIPTION - Dlb is a file archiving tool in the spirit (and tradition) of tar for - NetHack version 3.1 and higher. It is used to maintain the archive - files from which NetHack reads special level files and other read-only - information. Note that like tar the command and option specifiers are - specified as a continuous string and are followed by any arguments + Dlb is a file archiving tool in the spirit (and tradition) of tar for + NetHack version 3.1 and higher. It is used to maintain the archive + files from which NetHack reads special level files and other read-only + information. Note that like tar the command and option specifiers are + specified as a continuous string and are followed by any arguments required in the same order as the option specifiers. This facility is optional and may be excluded during NetHack configura- tion. COMMANDS - The x command causes dlb to extract the contents of the archive into + The x command causes dlb to extract the contents of the archive into the current directory. The c command causes dlb to create a new archive from files in the cur- @@ -37,11 +34,11 @@ OPTIONS AND ARGUMENTS f archive specify the archive. Default if f not specified is LIBFILE (usually the nhdat file in the playground). - I lfile specify the file containing the list of files to put in to + I lfile specify the file containing the list of files to put in to or extract from the archive if no files are listed on the command line. Default for archive creation if no files are listed is LIBLISTFILE. - C dir change directory. Changes directory before trying to read + C dir change directory. Changes directory before trying to read any files (including the archive and the lfile). EXAMPLES @@ -58,16 +55,16 @@ SEE ALSO nethack(6), tar(1) BUGS - Not a good tar emulation; - does not mean stdin or stdout. Should - include an optional compression facility. Not all read-only files for + Not a good tar emulation; - does not mean stdin or stdout. Should + include an optional compression facility. Not all read-only files for NetHack can be read out of an archive; examining the source is the only way to know which files can be. COPYRIGHT - This file is Copyright (C) Kenneth Lorber, 2024 for version keni-git- - set:1.13. NetHack may be freely redistributed. See license for + This file is Copyright (C) Kenneth Lorber, 2024 for version keni-git- + set:1.13. NetHack may be freely redistributed. See license for details. -Project(uc) 24 December 2024 DLB(6) +NETHACK 25 December 2024 DLB(6) diff --git a/doc/makedefs.txt b/doc/makedefs.txt index e8c3a6c81..e784946c3 100644 --- a/doc/makedefs.txt +++ b/doc/makedefs.txt @@ -1,10 +1,7 @@ -WARNING OLD LINE DOES NOT MATCH .TH MAKEDEFS 6 OLDLINE: '.TH MAKEDEFS(6) Games Manual MAKEDEFS(6) -MAKEDEFS 6 "8 February 2022" NETHACK' - NAME makedefs - NetHack miscellaneous build-time functions @@ -14,11 +11,11 @@ SYNOPSIS makedefs --input file --output file --command DESCRIPTION - Makedefs is a build-time tool used for a variety of NetHack(6) source + Makedefs is a build-time tool used for a variety of NetHack(6) source file creation and modification tasks. For historical reasons, makedefs - takes two types of command lines. When invoked with a short option, - the files operated on are determined when makedefs is compiled. When - invoked with a long option, the --input and --output options are used + takes two types of command lines. When invoked with a short option, + the files operated on are determined when makedefs is compiled. When + invoked with a long option, the --input and --output options are used to specify the files for the --command. Each command is only available in one of the two formats. @@ -29,11 +26,11 @@ SHORT COMMANDS -d Generate data.base. - -e Generate dungeon.pdf. The input file dungeon.def is passed - through the same logic as that used by the --grep command; see + -e Generate dungeon.pdf. The input file dungeon.def is passed + through the same logic as that used by the --grep command; see the MDGREP FUNCTIONS section below for details. - -m Generate date.h and options file. It will read dat/gitinfo.txt, + -m Generate date.h and options file. It will read dat/gitinfo.txt, only if it is present, to obtain githash= and gitbranch= info and include related preprocessor #defines in date.h file. @@ -56,7 +53,7 @@ LONG COMMANDS Show debugging output. --make [command] - Execute a short command. Command is given without preceding + Execute a short command. Command is given without preceding dash. --input file @@ -64,66 +61,66 @@ LONG COMMANDS is - standard input is read. --output file - Specify the output file for the command (if needed). If the + Specify the output file for the command (if needed). If the file is - standard output is written. --svs [delimiter] - Generate a version string to standard output without a trailing - newline. If specified, the delimiter is used between each part + Generate a version string to standard output without a trailing + newline. If specified, the delimiter is used between each part of the version string. - --grep Filter the input file to the output file. See the MDGREP FUNC- + --grep Filter the input file to the output file. See the MDGREP FUNC- TIONS section below for information on controlling the filtering operation. --grep-showvars - Show the name and value for each variable known to the grep + Show the name and value for each variable known to the grep option. --grep-trace - Turn on debug tracing for the grep function ( --grep must be + Turn on debug tracing for the grep function ( --grep must be specified as well). --grep-defined symbol - Exit shell true (0) if symbol is known and defined, otherwise + Exit shell true (0) if symbol is known and defined, otherwise exit shell false (1). --grep-define symbol - Force the value of symbol to be "defined." Symbol must already + Force the value of symbol to be "defined." Symbol must already be known to makedefs. --grep-undef symbol - Force the definition of symbol to be "undefined." Symbol must + Force the definition of symbol to be "undefined." Symbol must already be known to makedefs. MDGREP FUNCTIONS - The --grep command (and certain other commands) filter their input, on - a line-by-line basis, according to control lines embedded in the input - and on information gleaned from the NetHack(6) configuration. This - allows certain changes such as embedding platform-specific documenta- + The --grep command (and certain other commands) filter their input, on + a line-by-line basis, according to control lines embedded in the input + and on information gleaned from the NetHack(6) configuration. This + allows certain changes such as embedding platform-specific documenta- tion into the master documentation files. Rules: - The default conditional state is printing enabled. - - Any line NOT starting with a caret (^) is either suppressed - or passed through unchanged depending on the current condi- + - Any line NOT starting with a caret (^) is either suppressed + or passed through unchanged depending on the current condi- tional state. - - Any line starting with a caret is a control line; as in C, - zero or more spaces may be embedded in the line almost any- - where (except immediately after the caret); however the + - Any line starting with a caret is a control line; as in C, + zero or more spaces may be embedded in the line almost any- + where (except immediately after the caret); however the caret must be in column 1. - Conditionals may be nested. - - Makedefs will exit with an error code if any errors are - detected; processing will continue (if it can) to allow as + - Makedefs will exit with an error code if any errors are + detected; processing will continue (if it can) to allow as many errors as possible to be detected. - - Unknown identifiers are treated as both TRUE and as an - error. Note that --undef or #undef in the NetHack(6) con- + - Unknown identifiers are treated as both TRUE and as an + error. Note that --undef or #undef in the NetHack(6) con- figuration are different from unknown. Control lines: @@ -146,10 +143,10 @@ AUTHOR The NetHack Development Team COPYRIGHT - This file is Copyright (C) Kenneth Lorber, 2024 for version - NetHack-3.7:1.22. NetHack may be freely redistributed. See license + This file is Copyright (C) Kenneth Lorber, 2024 for version + NetHack-3.7:1.22. NetHack may be freely redistributed. See license for details. -Project(uc) 24 December 2024 MAKEDEFS(6) +NETHACK 25 December 2024 MAKEDEFS(6) diff --git a/doc/nethack.txt b/doc/nethack.txt index 80c7870f2..ca120c3e0 100644 --- a/doc/nethack.txt +++ b/doc/nethack.txt @@ -1,10 +1,7 @@ -WARNING OLD LINE DOES NOT MATCH .TH NETHACK 6 OLDLINE: '.TH NETHACK(6) Games Manual NETHACK(6) -NETHACK 6 "21 February 2022" NETHACK' - NAME nethack - Exploring The Mazes of Menace @@ -23,84 +20,84 @@ SYNOPSIS [ --version[:copy|:dump|:show] ] DESCRIPTION - NetHack is a display oriented Dungeons & Dragons(tm) - like game. The + NetHack is a display oriented Dungeons & Dragons(tm) - like game. The standard tty display and command structure resemble rogue. Other, more graphical display options exist for most platforms. - To get started you really only need to know two commands. The command - ? will give you a list of the available commands (as well as other - information) and the command / will identify the things you see on the + To get started you really only need to know two commands. The command + ? will give you a list of the available commands (as well as other + information) and the command / will identify the things you see on the screen. - To win the game (as opposed to merely playing to beat other people's - high scores) you must locate the Amulet of Yendor which is somewhere + To win the game (as opposed to merely playing to beat other people's + high scores) you must locate the Amulet of Yendor which is somewhere below the 20th level of the dungeon and get it out. Few people achieve - this; most never do. Those who have done so go down in history as - heroes among heroes -- and then they find ways of making the game even - harder. See the Guidebook section on Conduct if this game has gotten + this; most never do. Those who have done so go down in history as + heroes among heroes -- and then they find ways of making the game even + harder. See the Guidebook section on Conduct if this game has gotten too easy for you. - When the game ends, whether by your dying, quitting, or escaping from - the caves, NetHack will give you (a fragment of) the list of top scor- - ers. The scoring is based on many aspects of your behavior, but a + When the game ends, whether by your dying, quitting, or escaping from + the caves, NetHack will give you (a fragment of) the list of top scor- + ers. The scoring is based on many aspects of your behavior, but a rough estimate is obtained by taking the amount of gold you've found in - the cave plus four times your (real) experience. Precious stones may - be worth a lot of gold when brought to the exit. There is a 10% pen- + the cave plus four times your (real) experience. Precious stones may + be worth a lot of gold when brought to the exit. There is a 10% pen- alty for getting yourself killed. - The environment variable NETHACKOPTIONS can be used to initialize many - run-time options. The ? command provides a description of these - options and syntax. (The -dec and -ibm command line options are mutu- - ally exclusive and are equivalent to the decgraphics and ibmgraphics - run-time options described there, and are provided purely for conve- + The environment variable NETHACKOPTIONS can be used to initialize many + run-time options. The ? command provides a description of these + options and syntax. (The -dec and -ibm command line options are mutu- + ally exclusive and are equivalent to the decgraphics and ibmgraphics + run-time options described there, and are provided purely for conve- nience on systems supporting multiple types of terminals.) - Because the option list can be very long, options may also be included + Because the option list can be very long, options may also be included in a configuration file. The default is located in your home directory - and named .nethackrc on UNIX systems (including descendants such as + and named .nethackrc on UNIX systems (including descendants such as linux, NetBSD, and macOS). On Windows, the name is also .nethackrc but - the location can vary (see --showpaths below). On other systems, the + the location can vary (see --showpaths below). On other systems, the default may be different, possibly NetHack.cnf. On MS-DOS, the name is defaults.nh in NetHack's directory (folder), while on VMS|OpenVMS it is nethack.ini in your home directory. The default configuration file may - be overridden via the --nethackrc:rc-file command line option or by + be overridden via the --nethackrc:rc-file command line option or by setting NETHACKOPTIONS in your environment to a string consisting of an @ character followed by the path and filename. - The -u playername option supplies the answer to the question "Who are - you?". It overrides any name from the options or configuration file, - USER, LOGNAME, or getlogin(), which will otherwise be tried in order. - If none of these provides a useful name, the player will be asked for + The -u playername option supplies the answer to the question "Who are + you?". It overrides any name from the options or configuration file, + USER, LOGNAME, or getlogin(), which will otherwise be tried in order. + If none of these provides a useful name, the player will be asked for one. Player names (in conjunction with uids) are used to identify save files, so you can have several saved games under different names. Con- - versely, you must use the appropriate player name to restore a saved + versely, you must use the appropriate player name to restore a saved game. A playername suffix can be used to specify the profession, race, align- ment and/or gender of the character. The full syntax of the playername - that includes a suffix is "name-ppp-rrr-aaa-ggg". "ppp" are at least - the first three letters of the profession (this can also be specified - using a separate -p profession option). "rrr" are at least the first + that includes a suffix is "name-ppp-rrr-aaa-ggg". "ppp" are at least + the first three letters of the profession (this can also be specified + using a separate -p profession option). "rrr" are at least the first three letters of the character's race (this can also be specified using a separate -r race option). "aaa" are at least the first three letters - of the character's alignment, and "ggg" are at least the first three - letters of the character's gender. Any of the parts of the suffix may + of the character's alignment, and "ggg" are at least the first three + letters of the character's gender. Any of the parts of the suffix may be left out. - -p profession can be used to determine the character profession, also - known as the role. You can specify either the male or female name for - the character role, or the first three characters of the role as an + -p profession can be used to determine the character profession, also + known as the role. You can specify either the male or female name for + the character role, or the first three characters of the role as an abbreviation. Likewise, -r race can be used to explicitly request that a race be cho- sen. The -A|-Arc | -B|-Bar | -C|-Cav | -H|-Hea | -K|-Kni | -M|-Mon | -P|-Pri - | -R|-Rog | -Ran | -S|-Sam | -T|-Tou | -V|-Val | -W|-Wiz options for - role selection are maintained for compatibility with older versions of - the program. They are mutually exclusive and the single-letter form - must be uppercase. Ranger has no single-letter choice because -R is + | -R|-Rog | -Ran | -S|-Sam | -T|-Tou | -V|-Val | -W|-Wiz options for + role selection are maintained for compatibility with older versions of + the program. They are mutually exclusive and the single-letter form + must be uppercase. Ranger has no single-letter choice because -R is already used for the Rogue role. -@ tells nethack to choose any omitted characteristics (profes- @@ -111,97 +108,97 @@ DESCRIPTION The -n option suppresses printing of any news from the game administra- tor. - The -X option will start the game in a special non-scoring discovery - mode (also known as explore mode). -D will start the game in debug - mode (also known as wizard mode) after changing the character name to - "wizard", if the player is allowed. Otherwise it will switch to -X. - Control of who is allowed to use debug mode is done via the "WIZARDS=" + The -X option will start the game in a special non-scoring discovery + mode (also known as explore mode). -D will start the game in debug + mode (also known as wizard mode) after changing the character name to + "wizard", if the player is allowed. Otherwise it will switch to -X. + Control of who is allowed to use debug mode is done via the "WIZARDS=" line in nethack's sysconf file. - The -d or --directory option, which must be the first argument if it - appears, supplies a directory which is to serve as the playground. It - overrides the value from NETHACKDIR, HACKDIR, or the directory speci- - fied by the game administrator during compilation (usually - /usr/games/lib/nethackdir). This option is usually only useful to the - game administrator. The playground must contain several auxiliary - files such as help files, the list of top scorers, and a subdirectory + The -d or --directory option, which must be the first argument if it + appears, supplies a directory which is to serve as the playground. It + overrides the value from NETHACKDIR, HACKDIR, or the directory speci- + fied by the game administrator during compilation (usually + /usr/games/lib/nethackdir). This option is usually only useful to the + game administrator. The playground must contain several auxiliary + files such as help files, the list of top scorers, and a subdirectory save where games are saved. - The -w or --windowtype interface option can be used to specify which - interface to use if the program has been built with support for more - than one. Specifying a value on the command line overrides any value - specified in the run-time configuration file. NetHack's #version com- + The -w or --windowtype interface option can be used to specify which + interface to use if the program has been built with support for more + than one. Specifying a value on the command line overrides any value + specified in the run-time configuration file. NetHack's #version com- mand shows available interfaces. - The --nethackrc:RC-file option will use RC-file instead of the default - run-time configuration file (typically ~/.nethackrc) and the - --no-nethackrc option can be used to skip any run-time configuration + The --nethackrc:RC-file option will use RC-file instead of the default + run-time configuration file (typically ~/.nethackrc) and the + --no-nethackrc option can be used to skip any run-time configuration file. Some options provide feedback and then exit rather than play the game: - The -s or --scores option alone will print out the list of your scores - on the current version. An immediately following -v reports on all + The -s or --scores option alone will print out the list of your scores + on the current version. An immediately following -v reports on all versions present in the score file. '-s|-s -v' may also be followed by - arguments -p profession and -r race to print the scores of particular - roles and races only. Either can be specified multiple times to + arguments -p profession and -r race to print the scores of particular + roles and races only. Either can be specified multiple times to include more than one role or more than one race. When both are speci- - fied, score entries which match either the role or the race (or both) - are printed rather than just entries which match both. '-s|-s -v' may - be followed by one or more player names to print the scores of the - players mentioned, by 'all' to print out all scores, or by a number to - print that many top scores. Combining names with role or race or both - will report entries which match any of those rather than just the ones + fied, score entries which match either the role or the race (or both) + are printed rather than just entries which match both. '-s|-s -v' may + be followed by one or more player names to print the scores of the + players mentioned, by 'all' to print out all scores, or by a number to + print that many top scores. Combining names with role or race or both + will report entries which match any of those rather than just the ones which match all. - --version or --version:show can be used to cause NetHack to show the - version number, the date and time that the program was built from its - source code, and possibly some auxiliary information about that source + --version or --version:show can be used to cause NetHack to show the + version number, the date and time that the program was built from its + source code, and possibly some auxiliary information about that source code, then exit. The optional auxiliary information is git commit hash - (reflecting the source code's most recent modification when extracted - from the git version control system, if that is in use) if available - when the program was built. On some platforms such as Windows and - macOS, a variation, --version:copy, can be used to cause NetHack to - show the version information, then exit, while also leaving a copy of - that information in the paste buffer or clipboard for potential inser- + (reflecting the source code's most recent modification when extracted + from the git version control system, if that is in use) if available + when the program was built. On some platforms such as Windows and + macOS, a variation, --version:copy, can be used to cause NetHack to + show the version information, then exit, while also leaving a copy of + that information in the paste buffer or clipboard for potential inser- tion into things like bug reports. On any platform, --version:dump can be used to show most of the data used when checking whether a save file or bones file is compatible with the program. The program will display a line containing five numbers expressed in hexadecimal, then exit. - --showpaths can be used to cause NetHack to show where it is expecting - to find various files. Among other things it shows the path to and - name for the player's run-time configuration file, a text file which + --showpaths can be used to cause NetHack to show where it is expecting + to find various files. Among other things it shows the path to and + name for the player's run-time configuration file, a text file which can be edited to customize aspects of how the game operates. --usage or --help will display information similar to this manual page, then exit. Use 'nethack --usage | more' to read it a page at a time. AUTHORS - Jay Fenlason (+ Kenny Woodland, Mike Thome and Jon Payne) wrote the + Jay Fenlason (+ Kenny Woodland, Mike Thome and Jon Payne) wrote the original hack, very much like rogue (but full of bugs). - Andries Brouwer continuously deformed their sources into an entirely + Andries Brouwer continuously deformed their sources into an entirely different game. Mike Stephenson has continued the perversion of sources, adding various - warped character classes and sadistic traps with the help of many - strange people who reside in that place between the worlds, the Usenet - Zone. A number of these miscreants are immortalized in the historical + warped character classes and sadistic traps with the help of many + strange people who reside in that place between the worlds, the Usenet + Zone. A number of these miscreants are immortalized in the historical roll of dishonor and various other places. - The resulting mess is now called NetHack, to denote its development by + The resulting mess is now called NetHack, to denote its development by the Usenet. Andries Brouwer has made this request for the distinction, as he may eventually release a new version of his own. FILES - Run-time configuration options were discussed above and use a platform - specific name for a file in a platform specific location. For Unix, + Run-time configuration options were discussed above and use a platform + specific name for a file in a platform specific location. For Unix, the name is '.nethackrc' in the user's home directory. - All other files are in the playground directory, normally - /usr/games/lib/nethackdir. If DLB was defined during the compile, the - data files and special levels will be inside a larger file, normally + All other files are in the playground directory, normally + /usr/games/lib/nethackdir. If DLB was defined during the compile, the + data files and special levels will be inside a larger file, normally nhdat, instead of being separate files. nethack The program itself. @@ -247,11 +244,11 @@ FILES program is built with 'SYSCF' option enabled, ignored if not. - The location of 'sysconf' is specified at build time and can't be - changed except by updating source file "config.h" and rebuilding the + The location of 'sysconf' is specified at build time and can't be + changed except by updating source file "config.h" and rebuilding the program. - NetHack's Guidebook might not be present if whoever packaged or + NetHack's Guidebook might not be present if whoever packaged or installed the program distribution neglected to include it. In a perfect world, 'paniclog' would remain empty. @@ -268,7 +265,7 @@ ENVIRONMENT NETHACKDIR or HACKDIR Playground. NETHACKOPTIONS String predefining several NetHack options. - If the same option is specified in both NETHACKOPTIONS and .nethackrc, + If the same option is specified in both NETHACKOPTIONS and .nethackrc, the value assigned in NETHACKOPTIONS takes precedence. SHOPTYPE and SPLEVTYPE can be used in debugging (wizard) mode. @@ -281,12 +278,12 @@ BUGS Probably infinite. COPYRIGHT - This file is Copyright (C) Robert Patrick Rankin, 2024 for version - NetHack-3.7:1.31. NetHack may be freely redistributed. See license + This file is Copyright (C) Robert Patrick Rankin, 2024 for version + NetHack-3.7:1.31. NetHack may be freely redistributed. See license for details. Dungeons & Dragons is a Trademark of Wizards of the Coast, Inc. -Project(uc) 24 December 2024 NETHACK(6) +NETHACK 25 December 2024 NETHACK(6) diff --git a/doc/recover.txt b/doc/recover.txt index 49c583642..09e05f4fd 100644 --- a/doc/recover.txt +++ b/doc/recover.txt @@ -1,10 +1,7 @@ -WARNING OLD LINE DOES NOT MATCH .TH RECOVER 6 OLDLINE: '.TH RE- RECOVER(6) Games Manual RECOVER(6) -COVER 6 "8 February 2022" NETHACK' - NAME recover - recover a NetHack game interrupted by disaster @@ -12,60 +9,60 @@ SYNOPSIS recover [ -d directory ] base1 base2 ... DESCRIPTION - Occasionally, a NetHack game will be interrupted by disaster when the - game or the system crashes. Prior to NetHack v3.1, these games were - lost because various information like the player's inventory was kept - only in memory. Now, all pertinent information can be written out to - disk, so such games can be recovered at the point of the last level + Occasionally, a NetHack game will be interrupted by disaster when the + game or the system crashes. Prior to NetHack v3.1, these games were + lost because various information like the player's inventory was kept + only in memory. Now, all pertinent information can be written out to + disk, so such games can be recovered at the point of the last level change. The base options tell recover which files to process. Each base option specifies recovery of a separate game. The -d option, which must be the first argument if it appears, supplies - a directory which is the NetHack playground. It overrides the value + a directory which is the NetHack playground. It overrides the value from NETHACKDIR, HACKDIR, or the directory specified by the game admin- istrator during compilation (usually /usr/games/lib/nethackdir). - For recovery to be possible, nethack must have been compiled with the - INSURANCE option, and the run-time option checkpoint must also have - been on. NetHack normally writes out files for levels as the player + For recovery to be possible, nethack must have been compiled with the + INSURANCE option, and the run-time option checkpoint must also have + been on. NetHack normally writes out files for levels as the player leaves them, so they will be ready for return visits. When checkpoint- - ing, NetHack also writes out the level entered and the current game - state on every level change. This naturally slows level changes down + ing, NetHack also writes out the level entered and the current game + state on every level change. This naturally slows level changes down somewhat. - The level file names are of the form base.nn, where nn is an internal - bookkeeping number for the level. The file base.0 is used for game - identity, locking, and, when checkpointing, for the game state. Vari- - ous OSes use different strategies for constructing the base name. - Microcomputers use the character name, possibly truncated and modified - to be a legal filename on that system. Multi-user systems use the + The level file names are of the form base.nn, where nn is an internal + bookkeeping number for the level. The file base.0 is used for game + identity, locking, and, when checkpointing, for the game state. Vari- + ous OSes use different strategies for constructing the base name. + Microcomputers use the character name, possibly truncated and modified + to be a legal filename on that system. Multi-user systems use the (modified) character name prefixed by a user number to avoid conflicts, - or "xlock" if the number of concurrent players is being limited. It - may be necessary to look in the playground to find the correct base + or "xlock" if the number of concurrent players is being limited. It + may be necessary to look in the playground to find the correct base name of the interrupted game. recover will transform these level files into a save file of the same name as nethack would have used. Since recover must be able to read and delete files from the playground and create files in the save directory, it has interesting interactions - with game security. Giving ordinary players access to recover through - setuid or setgid is tantamount to leaving the playground world- - writable, with respect to both cheating and messing up other players. - For a single-user system, this of course does not change anything, so + with game security. Giving ordinary players access to recover through + setuid or setgid is tantamount to leaving the playground world- + writable, with respect to both cheating and messing up other players. + For a single-user system, this of course does not change anything, so some of the microcomputer ports install recover by default. For a multi-user system, the game administrator may want to arrange for - all .0 files in the playground to be fed to recover when the host + all .0 files in the playground to be fed to recover when the host machine boots, and handle game crashes individually. If the user popu- - lation is sufficiently trustworthy, recover can be installed with the - same permissions the nethack executable has. In either case, recover + lation is sufficiently trustworthy, recover can be installed with the + same permissions the nethack executable has. In either case, recover is easily compiled from the distribution utility directory. NOTES - Like nethack itself, recover will overwrite existing savefiles of the - same name. Savefiles created by recover are uncompressed; they may be - compressed afterwards if desired, but even a compression-using nethack + Like nethack itself, recover will overwrite existing savefiles of the + same name. Savefiles created by recover are uncompressed; they may be + compressed afterwards if desired, but even a compression-using nethack will find them in the uncompressed form. SEE ALSO @@ -73,17 +70,17 @@ SEE ALSO BUGS recover makes no attempt to find out if a base name specifies a game in - progress. If multiple machines share a playground, this would be + progress. If multiple machines share a playground, this would be impossible to determine. - recover should be taught to use the nethack playground locking mecha- + recover should be taught to use the nethack playground locking mecha- nism to avoid conflicts. COPYRIGHT - This file is Copyright (C) Kenneth Lorber, 2024 for version - NetHack-3.7:1.12. NetHack may be freely redistributed. See license + This file is Copyright (C) Kenneth Lorber, 2024 for version + NetHack-3.7:1.12. NetHack may be freely redistributed. See license for details. -Project(uc) 24 December 2024 RECOVER(6) +NETHACK 25 December 2024 RECOVER(6) From 556f1c9839ee7f20e401026f97c6f0b81d85caa4 Mon Sep 17 00:00:00 2001 From: nhmall Date: Thu, 26 Dec 2024 17:38:03 -0500 Subject: [PATCH 245/791] Windows: remove troublesome template lines Closes #1345 --- sys/windows/nethackrc.template | 4 ---- 1 file changed, 4 deletions(-) diff --git a/sys/windows/nethackrc.template b/sys/windows/nethackrc.template index 7cfdd1b4b..60db0ba77 100644 --- a/sys/windows/nethackrc.template +++ b/sys/windows/nethackrc.template @@ -135,10 +135,6 @@ OPTIONS=hilite_pet,!toptenwin # window, windowframe, windowtext. #OPTIONS=windowcolors:status windowtext/window message windowtext/window -# "Nethack mode" colors -OPTIONS=windowcolors:status white/#000000 message white/#000000 text white/#000000 menu white/#000000 menutext white/#000000 -OPTIONS=vary_msgcount:4 - # *** LOCATIONS *** # IMPORTANT: If you change any of these locations, the directories they # point at must exist. NetHack will not create them for you. From 959cc4766596fbf5ad8dd5ea1e0fb6efa67a9233 Mon Sep 17 00:00:00 2001 From: nhmall Date: Thu, 26 Dec 2024 19:55:08 -0500 Subject: [PATCH 246/791] set but not used warning in reveal_paths() --- src/files.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/files.c b/src/files.c index 76f7197ee..61a375007 100644 --- a/src/files.c +++ b/src/files.c @@ -4567,7 +4567,9 @@ debugcore(const char *filename, boolean wildcards) void reveal_paths(int code) { +#if defined(SYSCF) boolean skip_sysopt = FALSE; +#endif const char *fqn, *nodumpreason; char buf[BUFSZ]; @@ -4721,6 +4723,7 @@ reveal_paths(int code) } #endif /* ?DUMPLOG */ +#ifdef SYSCF #ifdef WIN32 if (!skip_sysopt) { if (sysopt.portable_device_paths) { @@ -4735,6 +4738,7 @@ reveal_paths(int code) } } } +#endif #endif /* personal configuration file */ @@ -4793,6 +4797,12 @@ reveal_paths(int code) #if defined(WIN32) && !defined(WIN32CON) wait_synch(); #endif +#ifndef DUMPLOG +#ifdef SYSCF + nhUse(skip_sysopt); +#endif + nhUse(nodumpreason); +#endif } /* ---------- BEGIN TRIBUTE ----------- */ From bb57c38e24f2fcf1b8114cd4caf5295f9be85b18 Mon Sep 17 00:00:00 2001 From: nhkeni Date: Fri, 27 Dec 2024 18:17:49 -0500 Subject: [PATCH 247/791] Option formatting cleanup. --- doc/dlb.6 | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/doc/dlb.6 b/doc/dlb.6 index 653e17210..80ca26861 100644 --- a/doc/dlb.6 +++ b/doc/dlb.6 @@ -70,22 +70,28 @@ The .B t command lists the files in the archive. .SH OPTIONS AND ARGUMENTS -.DT -.ta \w'f archive\ \ \ 'u -v verbose output +.TP 12em +\fBv +verbose output .br .sp 1 -f archive specify the archive. Default if f not specified is +.TP +\fBf\fI\ archive +specify the archive. Default if f not specified is LIBFILE (usually the nhdat file in the playground). .br .sp 1 -I lfile specify the file containing the list of files to +.TP +\fBI\fI\ lfile +specify the file containing the list of files to put in to or extract from the archive if no files are listed on the command line. Default for archive creation if no files are listed is LIBLISTFILE. .br .sp 1 -C dir change directory. Changes directory before trying to +.TP +\fBC\fI\ dir +change directory. Changes directory before trying to read any files (including the archive and the lfile). .br .SH EXAMPLES From 6530951fd5d22eeb04b3332f4798f40f3e09ea69 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sat, 28 Dec 2024 19:38:55 +0200 Subject: [PATCH 248/791] Impossible timer after dipping a lit potion of oil Dipping a lit potion of oil into another potion could turn the potion of oil into another potion; this resulted in "burn_object: unexpected obj" impossible after the lit timer ran out. Just make an explosion if trying to dip a lit potion of oil. --- src/potion.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/potion.c b/src/potion.c index 25989fff5..9d5a89fc8 100644 --- a/src/potion.c +++ b/src/potion.c @@ -2495,7 +2495,8 @@ potion_dip(struct obj *obj, struct obj *potion) useup(potion); /* now gone */ /* Mixing potions is dangerous... KMH, balance patch -- acid is particularly unstable */ - if (obj->cursed || obj->otyp == POT_ACID || !rn2(10)) { + if (obj->cursed || obj->otyp == POT_ACID + || (obj->otyp == POT_OIL && obj->lamplit) || !rn2(10)) { /* it would be better to use up the whole stack in advance of the message, but we can't because we need to keep it around for potionbreathe() [and we can't set obj->in_use From 66d0307e958c371ff2c3135491586d93af65185f Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sat, 28 Dec 2024 19:43:10 +0200 Subject: [PATCH 249/791] Impossible timer after vault guard entered Fuzzer encountered impossible "timer sanity: melt timer on non-ice", when vault guard entered the vault, changing the vault wall unconditionally into room floor; in this case the vault wall was ice with a melting timer attached. Delete any melting ice timers on that location when turning it into floor. --- src/vault.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vault.c b/src/vault.c index 44052f545..65fcf7a18 100644 --- a/src/vault.c +++ b/src/vault.c @@ -608,6 +608,7 @@ invault(void) EGD(guard)->fakecorr[0].ftyp = typ; EGD(guard)->fakecorr[0].flags = levl[x][y].flags; /* guard's entry point where confrontation with hero takes place */ + spot_stop_timers(x, y, MELT_ICE_AWAY); levl[x][y].typ = DOOR; levl[x][y].doormask = D_NODOOR; unblock_point(x, y); /* empty doorway doesn't block light */ From d11747899ef3113a6743ab26c02fdbb851f81215 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sat, 28 Dec 2024 20:30:11 +0200 Subject: [PATCH 250/791] Fix boulder-over-pit sanity after landmine blows up --- src/trap.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/trap.c b/src/trap.c index 0ee5db704..d87f4131f 100644 --- a/src/trap.c +++ b/src/trap.c @@ -3133,6 +3133,7 @@ blow_up_landmine(struct trap *trap) } } } + fill_pit(x, y); spot_checks(x, y, old_typ); } From 72fb06a40a782517d7ccb86cecd338662e7afcc2 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sat, 28 Dec 2024 20:31:45 +0200 Subject: [PATCH 251/791] Unhide monster moving over to teleport trap --- src/muse.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/muse.c b/src/muse.c index 865ae5d05..7bf92b313 100644 --- a/src/muse.c +++ b/src/muse.c @@ -1130,6 +1130,7 @@ use_defensive(struct monst *mtmp) place_monster(mtmp, gt.trapx, gt.trapy); if (mtmp->wormno) worm_move(mtmp); + maybe_unhide_at(mtmp->mx, mtmp->my); newsym(gt.trapx, gt.trapy); /* 0: 'no object' rather than STRANGE_OBJECT; FALSE: obj not seen */ m_tele(mtmp, vismon, FALSE, 0); From 454978fadd1693a7a6e5a5506a15ea268ed01098 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sat, 28 Dec 2024 20:33:15 +0200 Subject: [PATCH 252/791] Avoid boulder-over-pit sanity when filling empty maze This shouldn't happen unless doing special level commands in strange order, but handle it anyway... --- src/sp_lev.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/sp_lev.c b/src/sp_lev.c index 135a72dec..16adaf345 100644 --- a/src/sp_lev.c +++ b/src/sp_lev.c @@ -2924,7 +2924,12 @@ fill_empty_maze(void) TRUE); } for (x = rnd((int) (12 * mapfact) / 100); x; x--) { + struct trap *ttmp; + maze1xy(&mm, DRY); + if ((ttmp = t_at(mm.x, mm.y)) != 0 + && (is_pit(ttmp->ttyp) || is_hole(ttmp->ttyp))) + continue; (void) mksobj_at(BOULDER, mm.x, mm.y, TRUE, FALSE); } for (x = rn2(2); x; x--) { From 767a20e21f5b541b189e9b83ffbbc8c83121dc3f Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sat, 28 Dec 2024 20:41:35 +0200 Subject: [PATCH 253/791] Hacky fix for pline recursion outputting raw_print When glyph updates are on, pline can be called recursively when the vision is being fully recalculated. This caused the recursively called pline to output raw_pline text. Not sure if this is the correct way to fix it, but can't really turn off or block the glyph update notices either ... --- src/pline.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/pline.c b/src/pline.c index 2e0257284..13ec79924 100644 --- a/src/pline.c +++ b/src/pline.c @@ -257,8 +257,13 @@ vpline(const char *line, va_list the_args) goto pline_done; } - if (gv.vision_full_recalc) + if (gv.vision_full_recalc) { + int tmp_in_pline = in_pline; + + in_pline = 0; vision_recalc(0); + in_pline = tmp_in_pline; + } if (u.ux) flush_screen((gp.pline_flags & NO_CURS_ON_U) ? 0 : 1); /* %% */ From 5f958315262d260ebb79f74a0e866b32e9b0c946 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sat, 28 Dec 2024 20:52:35 +0200 Subject: [PATCH 254/791] Creating a pit in a wall message tweak "A pit appears in the wall" sounds a bit silly, so change it to "The wall crumbles into a pit" --- src/dig.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/dig.c b/src/dig.c index 826be653a..cb064c53c 100644 --- a/src/dig.c +++ b/src/dig.c @@ -715,7 +715,10 @@ digactualhole(coordxy x, coordxy y, struct monst *madeby, int ttyp) pline("%s digs %s %s the %s.", Monnam(madeby), an(tname), in_thru, surface_type); } else if (cansee(x, y) && flags.verbose) { - pline("%s appears in the %s.", An(tname), surface_type); + if (IS_STWALL(old_typ)) + pline_The("%s crumbles into %s.", surface_type, an(tname)); + else + pline("%s appears in the %s.", An(tname), surface_type); } if (IS_FURNITURE(old_typ) && cansee(x, y)) pline_The("%s falls into the %s!", furniture, tname); From 6c895ab6f6e502eea22d067e6a71f1078573dd93 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sat, 28 Dec 2024 20:54:36 +0200 Subject: [PATCH 255/791] Boulder-over-pit sanity when breaking wand of digging --- src/apply.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/apply.c b/src/apply.c index f927f7085..2446f2ed8 100644 --- a/src/apply.c +++ b/src/apply.c @@ -4020,6 +4020,7 @@ do_break_wand(struct obj *obj) && !levl[x][y].candig)) ? PIT : HOLE); } } + fill_pit(x, y); continue; } else if (obj->otyp == WAN_CREATE_MONSTER) { /* u.ux,u.uy creates it near you--x,y might create it in rock */ From 1282863f5cf35184a0c7ed42930e565829fba549 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sun, 29 Dec 2024 18:17:53 +0200 Subject: [PATCH 256/791] Fix breaking wand of digging not touching boulders Applying a wand of digging skipped all the affected locations with any boulders on them. --- src/apply.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/apply.c b/src/apply.c index 2446f2ed8..60384c3aa 100644 --- a/src/apply.c +++ b/src/apply.c @@ -3991,8 +3991,9 @@ do_break_wand(struct obj *obj) if (obj->otyp == WAN_DIGGING) { schar typ; + enum digcheck_result dcres = dig_check(BY_OBJECT, x, y); - if (dig_check(BY_OBJECT, x, y) < DIGCHECK_FAILED) { + if (dcres < DIGCHECK_FAILED || dcres == DIGCHECK_FAIL_BOULDER) { if (IS_WALL(levl[x][y].typ) || IS_DOOR(levl[x][y].typ)) { /* normally, pits and holes don't anger guards, but they * do if it's a wall or door that's being dug */ From 7b4445f040b09c1982594f60c840066cb2c262cc Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 29 Dec 2024 12:11:03 -0500 Subject: [PATCH 257/791] make msdos lib/djgpp/target folder more hierarchical Instead of flat, have bin, lib and include folders for the native DOS pieces. If you have been cross-compiling for MSDOS, you will need to carry out the following to bring things up-to-date: sys/msdos/fetch-cross-compiler.sh make CROSS_TO_MSDOS=1 WANT_DEBUG=1 package --- sys/msdos/fetch-cross-compiler.sh | 20 +++++++++++++++++--- sys/unix/hints/include/cross-post.370 | 6 +++--- sys/unix/hints/include/cross-pre2.370 | 16 ++++++++-------- 3 files changed, 28 insertions(+), 14 deletions(-) diff --git a/sys/msdos/fetch-cross-compiler.sh b/sys/msdos/fetch-cross-compiler.sh index d5f956b38..95afc69f8 100755 --- a/sys/msdos/fetch-cross-compiler.sh +++ b/sys/msdos/fetch-cross-compiler.sh @@ -139,12 +139,22 @@ if [ ! -d djgpp/djgpp-patch ]; then cd ../../ fi -# create a directory to hold some native DOS executables that might get deployed +# create a directories to hold some native DOS pieces that might get deployed if [ ! -d djgpp/target ]; then cd djgpp mkdir -p target cd ../ fi +if [ ! -d djgpp/target/bin ]; then + mkdir -p djgpp/target/bin +fi +if [ ! -d djgpp/target/lib ]; then + mkdir -p djgpp/target/lib +fi +if [ ! -d djgpp/target/include ]; then + mkdir -p djgpp/target/include +fi + # These 4 arrays must have their elements kept in synch. # @@ -160,8 +170,9 @@ ziplocal=( ) # name of file after extraction from zip file exesought=( - "symify.exe" - "gdb.exe" + "bin/symify.exe" + "bin/gdb.exe" + ) # stored full path inside zip file exepathinzip=( @@ -196,11 +207,14 @@ if [ -d djgpp/target ]; then fi count=$(( $count + 1 )) done + echo "Native DOS executables in lib/djgpp/target:" ls -l *.exe + # cd ../../ fi + FONT_VERSION="4.49" FONT_FILE="terminus-font-$FONT_VERSION" FONT_LFILE="$FONT_FILE.1" diff --git a/sys/unix/hints/include/cross-post.370 b/sys/unix/hints/include/cross-post.370 index 5c4c9ba08..6d12f8abd 100644 --- a/sys/unix/hints/include/cross-post.370 +++ b/sys/unix/hints/include/cross-post.370 @@ -65,10 +65,10 @@ dospkg: dodata dosfonts $(GAMEBIN) $(TARGETPFX)recover.exe ../dat/nhtiles.bmp cp $(DOSFONT)/ter-u28b.psf $(TARGETPFX)pkg/TER-U28B.PSF cp $(DOSFONT)/ter-u32b.psf $(TARGETPFX)pkg/TER-U32B.PSF cp ../lib/djgpp/cwsdpmi/bin/CWSDPMI.EXE $(TARGETPFX)pkg/CWSDPMI.EXE - ( if [ -f ../lib/djgpp/target/symify.exe ]; then \ - cp ../lib/djgpp/target/symify.exe $(TARGETPFX)pkg/SYMIFY.EXE; \ + ( if [ -f ../lib/djgpp/target/bin/symify.exe ]; then \ + cp ../lib/djgpp/target/bin/symify.exe $(TARGETPFX)pkg/SYMIFY.EXE; \ else \ - pwd; echo "../lib/djgpp/target/symify.exe not found"; \ + pwd; echo "../lib/djgpp/target/bin/symify.exe not found"; \ fi; ) ifeq "$(WANT_DEBUG)" "1" ( if [ -f $(GDBEXE) ]; \ diff --git a/sys/unix/hints/include/cross-pre2.370 b/sys/unix/hints/include/cross-pre2.370 index e1ade8fb3..a0d5a6072 100644 --- a/sys/unix/hints/include/cross-pre2.370 +++ b/sys/unix/hints/include/cross-pre2.370 @@ -133,6 +133,13 @@ override TARGET_CC = $(TOOLTOP1)/i586-pc-msdosdjgpp-gcc override TARGET_CXX = $(TOOLTOP1)/i586-pc-msdosdjgpp-g++ override TARGET_AR = $(TOOLTOP1)/i586-pc-msdosdjgpp-gcc-ar override TARGET_STUBEDIT = ../lib/djgpp/i586-pc-msdosdjgpp/bin/stubedit +ifdef MAKEFILE_SRC +FLDR=../ +endif +ifdef MAKEFILE_TOP +FLDR= +endif +dostargetexes=$(FLDR)lib/djgpp/target/bin/ # ifdef DOSBOX dosbox=$(DOSBOX) @@ -144,13 +151,6 @@ dosboxnhfolder=$(dosboxtop)/$(dosboxgameid) dosboxnhsrc=$(dosboxnhfolder)/NHSRC dosboxconfigfile=NETHACK.CNF dosgdburl=http://www.mirrorservice.org/sites/ftp.delorie.com/pub/djgpp/current/v2gnu/gdb801b.zip -ifdef MAKEFILE_SRC -FLDR=../ -endif -ifdef MAKEFILE_TOP -FLDR= -endif -dostargetexes=$(FLDR)lib/djgpp/target WANT_DEBUG=1 DEPLOY=deploytodosbox endif # dosbox @@ -231,7 +231,7 @@ override PACKAGE = dospkg override PREGAME += mkdir -p $(TARGETDIR) ; make $(TARGETPFX)exceptn.o ; override CLEANMORE += rm -f -r $(TARGETDIR) ; rm -f -r $(FONTTARGETS) ; ifeq "$(WANT_DEBUG)" "1" -GDBEXE=../lib/djgpp/target/gdb.exe +GDBEXE=$(dostargetexes)gdb.exe GDBBAT=NHGDB.BAT GDBCMDLINE=directory nhsrc/src nhsrc/include nhsrc/sys/msdos \ nhsrc/sys/share nhsrc/win/share nhsrc/win/curses \ From 50aff17f94b77b224cedaa5dcb83d53a063db9a9 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 29 Dec 2024 13:54:06 -0500 Subject: [PATCH 258/791] follow-up bit for sys/msdos/fetch-cross-compiler.sh --- sys/msdos/fetch-cross-compiler.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/msdos/fetch-cross-compiler.sh b/sys/msdos/fetch-cross-compiler.sh index 95afc69f8..36558a00c 100755 --- a/sys/msdos/fetch-cross-compiler.sh +++ b/sys/msdos/fetch-cross-compiler.sh @@ -209,7 +209,7 @@ if [ -d djgpp/target ]; then done echo "Native DOS executables in lib/djgpp/target:" - ls -l *.exe + ls -l bin/*.exe # cd ../../ fi From ecbb7cff4dfe414d5be73a3740a55b4604528445 Mon Sep 17 00:00:00 2001 From: PatR Date: Mon, 30 Dec 2024 03:12:06 -0800 Subject: [PATCH 259/791] fix issue #1339 - shop purchase warnings Issue reported by ars3niy: with the relatively new container handling, buying multiple items when some were inside a container sometimes triggered impossible "unpaid_cost: object wasn't on any bill" warnings and not buy all intended items. Once that occurred, subsequent inventory display would repeat the warning. A couple weeks back, I managed to produce a save file which would reproduce the problem when 'p' was issued, but failed to figure out why that was happening. I accidentally deleted that save file and it took quite a lot of further attempts to get another one. I still don't understand why this fix is needed, but with it in place the save file no longer triggers any problems. I'm marking the issue fixed but that could be premature. Fixes #1339 --- doc/fixes3-7-0.txt | 2 ++ src/shk.c | 15 ++++++++++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index 773720728..4fa4c3d7f 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -2081,6 +2081,8 @@ farlook of /e or /E stopped reporting engraving and headstone text after a fix for the situation where // or ; reported such text when there was an object or monster in the way message was garbled when lightning or acid breath hit iron bars +shop bug: buying a container with unpaid items in it could produce impossible + "unpaid_cost: object not on any bill" warnings Fixes to 3.7.0-x Platform and/or Interface Problems Exposed Via git Repository diff --git a/src/shk.c b/src/shk.c index d9077322f..0b8d508c5 100644 --- a/src/shk.c +++ b/src/shk.c @@ -27,7 +27,7 @@ enum billitem_status { KnownContainer = 5, /* container->cknown==1, holding unpaid item(s) */ UndisclosedContainer = 6, /* container->cknown==0 */ }; -/* this is similar to sortloot; the shop bill gets converted into a array of +/* this is similar to sortloot; the shop bill gets converted into an array of struct sortbill_item so that sorting and traversal don't need to access the original bill or even the shk; the array gets sorted by usedup vs unpaid and by cost within each of those two categories */ @@ -1570,7 +1570,8 @@ make_itemized_bill( } ibill[n].bidx = -1; /* end of list; not strictly needed */ - /* ibill[0..n-1] contains data, ibill[n] has Null obj and -1 bidx */ + /* ibill[0..n-1] contains data, ibill[n] has Null obj and -1 bidx and + is excluded from the sort */ if (n > 1) qsort((genericptr_t) ibill, n, sizeof *ibill, sortbill_cmp); return n; @@ -2116,9 +2117,13 @@ update_bill( } newebillct = eshkp->billct - 1; *bp = eshkp->bill_p[newebillct]; +#if 0 /* [this is responsible for github issue #1339; it's not clear why] */ for (j = 0; j < ibillct; ++j) if (ibill[j].bidx == newebillct) ibill[j].bidx = bidx; +#else + nhUse(bidx); +#endif eshkp->billct = newebillct; /* eshkp->billct - 1 */ } return; @@ -2294,9 +2299,13 @@ buy_container( otmp = bp_to_obj(bp); buy = dopayobj(shkp, bp, otmp, 1, FALSE, sightunseen); - if (buy != PAY_BUY) + if (buy != PAY_BUY) { impossible("Buying %s contents failed unexpectedly (#%u %d).", simpleonames(container), otmp->o_id, buy); + continue; + } + /* [updating cost here is not necessary but useful when debugging] */ + ibill[indx].cost -= (bp->price * bp->bquan); /* update container */ update_bill(indx, ibillct, ibill, eshkp, bp, otmp); ++buycount; } From a65c012f4563dbfb3c5cda215e6a5782520644a6 Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 30 Dec 2024 12:48:52 -0500 Subject: [PATCH 260/791] shorten up a Makefile.src line --- sys/unix/Makefile.src | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sys/unix/Makefile.src b/sys/unix/Makefile.src index f21982f66..7532dc098 100644 --- a/sys/unix/Makefile.src +++ b/sys/unix/Makefile.src @@ -764,8 +764,9 @@ $(TARGETPFX)sfstruct.o: sfstruct.c $(HACK_H) # date.c should be recompiled any time any of the source or include code # is modified. +DATECFLAGS = $(TARGET_CFLAGS) $(GITHASH) $(GITBRANCH) $(GITPREFIX) $(TARGETPFX)date.o: date.c $(HACK_H) $(HACKCSRC) $(HOBJ) $(TARGET_HACKLIB) - $(TARGET_CC) $(TARGET_CFLAGS) $(GITHASH) $(GITBRANCH) $(GITPREFIX) -c -o $@ date.c + $(TARGET_CC) $(DATECFLAGS) -c -o $@ date.c # date.h should be remade any time any of the source or include code # is modified. Unfortunately, this would make the contents of this From ac50b7fecc5356d6dd35871a4d6bcad704b5e387 Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 30 Dec 2024 12:52:35 -0500 Subject: [PATCH 261/791] update the msdos cross-compile date.c wasn't always being recompiled. A couple of other bits. --- sys/unix/hints/include/cross-post.370 | 10 +++++++--- sys/unix/hints/include/cross-pre2.370 | 9 +++++---- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/sys/unix/hints/include/cross-post.370 b/sys/unix/hints/include/cross-post.370 index 6d12f8abd..1c7eac9ee 100644 --- a/sys/unix/hints/include/cross-post.370 +++ b/sys/unix/hints/include/cross-post.370 @@ -19,12 +19,16 @@ $(TARGETPFX)vidvesa.o : ../sys/msdos/vidvesa.c ../sys/msdos/portio.h \ $(TARGETPFX)vidstub.o : ../sys/msdos/vidvesa.c ../sys/msdos/portio.h \ $(HACK_H) $(TARGETPFX)tile.o : tile.c +ifeq "$(DOSSOUND)" "1" +#$(info DOSSOUND=$(DOSSOUND)) +$(TARGETPFX)dossound.o: ../sound/dossound/dossound.c $(HACK_H) +endif $(TARGETPFX)exceptn.o : ../lib/djgpp/djgpp-patch/src/libc/go32/exceptn.S $(TARGET_CC) -c -o $@ ../lib/djgpp/djgpp-patch/src/libc/go32/exceptn.S $(TARGET_AR) ru ../lib/djgpp/i586-pc-msdosdjgpp/lib/libc.a $(TARGETPFX)exceptn.o -$(GAMEBIN) : $(HOBJ) $(HACKLIB) $(LUACROSSLIB) - $(TARGET_LINK) $(TARGET_LFLAGS) -o $(GAMEBIN) \ - $(HOBJ) $(HACKLIB) $(WINLIB) $(TARGET_LIBS) +$(GAMEBIN) : $(HOBJ) $(TARGETPFX)date.o $(TARGET_HACKLIB) $(LUACROSSLIB) + $(TARGET_LINK) $(TARGET_LFLAGS) -o $@ \ + $(HOBJ) $(TARGET_HACKLIB) $(WINLIB) $(TARGET_LIBS) $(DOSFONT)/ter-u16b.psf: $(FONTTOP)/ter-u16b.bdf $(DOSFONT)/nh-u16b.bdf $(DOSFONT)/makefont.lua $(LUABIN) $(LUABIN) $(DOSFONT)/makefont.lua $(FONTTOP)/ter-u16b.bdf $(DOSFONT)/nh-u16b.bdf $@ $(DOSFONT)/ter-u16v.psf: $(FONTTOP)/ter-u16v.bdf $(DOSFONT)/nh-u16v.bdf $(DOSFONT)/makefont.lua $(LUABIN) diff --git a/sys/unix/hints/include/cross-pre2.370 b/sys/unix/hints/include/cross-pre2.370 index a0d5a6072..eda6829fd 100644 --- a/sys/unix/hints/include/cross-pre2.370 +++ b/sys/unix/hints/include/cross-pre2.370 @@ -35,7 +35,8 @@ LUACROSSLIB = $(TARGETPFX)lua$(subst .,,$(LUA_VERSION)).a LUAINCL = -I$(LUASRCDIR) override BUILDMORE += $(LUACROSSLIB) override CLEANMORE += rm -f $(LUACROSSLIB) ; -override TARGET_LIBS += $(LUACROSSLIB) -lm +override TARGET_LIBS += $(LUACROSSLIB) +LIBLM = -lm else LUAINCL= endif # BUILD_TARGET_LUA @@ -178,12 +179,12 @@ MSDOS_TARGET_CFLAGS = -c -O $(DBGFLAGS) -I../include -I../sys/msdos -I../win/sha $(LUAINCL) -DDLB $(PDCURSESDEF) -DTILES_IN_GLYPHMAP \ -DCROSSCOMPILE -DCROSSCOMPILE_TARGET -DCROSS_TO_MSDOS \ -D_NAIVE_DOS_REGS \ - $(MSDOS_GCC_CFLAGS) + $(MSDOS_GCC_CFLAGS) $(SNDCFLAGS) MSDOS_TARGET_CXXFLAGS = -c -O $(DBGFLAGS) -I../include -I../sys/msdos -I../win/share \ $(LUAINCL) -DDLB $(PDCURSESDEF) \ -DUSE_TILES -DCROSSCOMPILE -DCROSSCOMPILE_TARGET -DCROSS_TO_MSDOS \ -D_NAIVE_DOS_REGS \ - $(MSDOS_GPP_CFLAGS) + $(MSDOS_GPP_CFLAGS) $(SNDCFLAGS) PDCINCL += -I$(PDCPORT) PDC_TARGET_CFLAGS = $(MSDOS_TARGET_CFLAGS) -Wno-unused-parameter \ -Wno-missing-prototypes @@ -204,7 +205,7 @@ else override TARGET_LINK = $(TOOLTOP1)/i586-pc-msdosdjgpp-gcc endif override TARGET_LFLAGS= -override TARGET_LIBS += -lpc +override TARGET_LIBS += -lpc $(LIBLM) override SYSSRC = ../sys/share/pcmain.c ../sys/msdos/msdos.c \ ../sys/share/pcsys.c ../sys/share/pctty.c \ ../sys/share/pcunix.c ../sys/msdos/video.c \ From eacfa202d9ce5e15bf67da80419237c20a2b4976 Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 30 Dec 2024 12:54:12 -0500 Subject: [PATCH 262/791] soundlib selection in config file wasn't working When there was more than one option #define'd selection was not working correctly. --- include/extern.h | 1 + src/options.c | 3 +++ src/sounds.c | 15 +++++++++++++++ 3 files changed, 19 insertions(+) diff --git a/include/extern.h b/include/extern.h index 760ad30e2..e3e0ac152 100644 --- a/include/extern.h +++ b/include/extern.h @@ -2932,6 +2932,7 @@ extern char *get_sound_effect_filename(int32_t seidint, extern char *base_soundname_to_filename(char *, char *, size_t, int32_t) NONNULLARG1; extern void set_voice(struct monst *, int32_t, int32_t, int32_t) NO_NNARGS; extern void sound_speak(const char *) NO_NNARGS; +extern enum soundlib_ids soundlib_id_from_opt(char *); /* ### sp_lev.c ### */ diff --git a/src/options.c b/src/options.c index 30d7709f4..b8b192fd2 100644 --- a/src/options.c +++ b/src/options.c @@ -3741,8 +3741,11 @@ optfn_soundlib( */ if ((op = string_for_env_opt(allopt[optidx].name, opts, FALSE)) != empty_optstr) { + enum soundlib_ids option_id; get_soundlib_name(soundlibbuf, WINTYPELEN); + option_id = soundlib_id_from_opt(op); + gc.chosen_soundlib = option_id; assign_soundlib(gc.chosen_soundlib); } else return optn_err; diff --git a/src/sounds.c b/src/sounds.c index 5a5e9fd66..9ca6b199d 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -1879,6 +1879,21 @@ get_soundlib_name(char *dest, int maxlen) *dest = '\0'; } +enum soundlib_ids +soundlib_id_from_opt(char *op) +{ + int idx; + struct sound_procs *defproc = &nosound_procs, + *sp = 0; + + for (idx = 0; idx < SIZE(soundlib_choices); ++idx) { + sp = soundlib_choices[idx].sndprocs; + if (!strcmp(sp->soundname, op)) + return sp->soundlib_id; + } + return defproc->soundlib_id; +} + /* * The default sound interface * From e20908fa4f194e6404bd0ee2e33b92a400bad5ea Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 30 Dec 2024 12:59:00 -0500 Subject: [PATCH 263/791] remove an unused part of msdos cross-compile --- sys/unix/hints/include/cross-post.370 | 4 ---- 1 file changed, 4 deletions(-) diff --git a/sys/unix/hints/include/cross-post.370 b/sys/unix/hints/include/cross-post.370 index 1c7eac9ee..93f01f9dc 100644 --- a/sys/unix/hints/include/cross-post.370 +++ b/sys/unix/hints/include/cross-post.370 @@ -19,10 +19,6 @@ $(TARGETPFX)vidvesa.o : ../sys/msdos/vidvesa.c ../sys/msdos/portio.h \ $(TARGETPFX)vidstub.o : ../sys/msdos/vidvesa.c ../sys/msdos/portio.h \ $(HACK_H) $(TARGETPFX)tile.o : tile.c -ifeq "$(DOSSOUND)" "1" -#$(info DOSSOUND=$(DOSSOUND)) -$(TARGETPFX)dossound.o: ../sound/dossound/dossound.c $(HACK_H) -endif $(TARGETPFX)exceptn.o : ../lib/djgpp/djgpp-patch/src/libc/go32/exceptn.S $(TARGET_CC) -c -o $@ ../lib/djgpp/djgpp-patch/src/libc/go32/exceptn.S $(TARGET_AR) ru ../lib/djgpp/i586-pc-msdosdjgpp/lib/libc.a $(TARGETPFX)exceptn.o From 01b2ea12f7109be0927c262f874fd8856558c425 Mon Sep 17 00:00:00 2001 From: "G. Branden Robinson" Date: Sat, 28 Dec 2024 10:55:11 -0600 Subject: [PATCH 264/791] doc/dlb.6: Use correct scaling unit for ems In *roff numeric expressions, ems are spelled "m", not "em". https://www.gnu.org/software/groff/manual/groff.html.node/Measurements.html --- doc/dlb.6 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/dlb.6 b/doc/dlb.6 index 80ca26861..e16edaed1 100644 --- a/doc/dlb.6 +++ b/doc/dlb.6 @@ -70,7 +70,7 @@ The .B t command lists the files in the archive. .SH OPTIONS AND ARGUMENTS -.TP 12em +.TP 12m \fBv verbose output .br From dc14fb131feb51ad4496dfa6649a43100c0c5ab4 Mon Sep 17 00:00:00 2001 From: "G. Branden Robinson" Date: Sat, 28 Dec 2024 11:05:04 -0600 Subject: [PATCH 265/791] doc/{dlb,recover}.6: Disable dead dynamic code Portions of these man pages seem at one time to have been dynamically selected, but the mechanism for doing so appears to be commented out in the source tree: see "NHGREP" in sys/{unix,vms}/Makefile.doc. Wrap them in *roff "ignore blocks" to keep their noise from cluttering the man page actually seen by the users. --- doc/dlb.6 | 2 ++ doc/recover.6 | 2 ++ 2 files changed, 4 insertions(+) diff --git a/doc/dlb.6 b/doc/dlb.6 index e16edaed1..5505bc3f8 100644 --- a/doc/dlb.6 +++ b/doc/dlb.6 @@ -40,6 +40,7 @@ archive files from which NetHack reads special level files and other read-only information. Note that like tar the command and option specifiers are specified as a continuous string and are followed by any arguments required in the same order as the option specifiers. +.ig .PP ^?ALLDOCS This facility is optional and may be excluded during NetHack @@ -53,6 +54,7 @@ This facility is optional and was excluded from this NetHack configuration. ^. ^. +.. .SH COMMANDS The .B x diff --git a/doc/recover.6 b/doc/recover.6 index f291917f9..3829760e9 100644 --- a/doc/recover.6 +++ b/doc/recover.6 @@ -48,6 +48,7 @@ supplies a directory which is the NetHack playground. It overrides the value from NETHACKDIR, HACKDIR, or the directory specified by the game administrator during compilation (usually /usr/games/lib/nethackdir). +.ig .PP ^?ALLDOCS For recovery to be possible, @@ -69,6 +70,7 @@ This configuration of was created without support for recovery. ^. ^. +.. NetHack normally writes out files for levels as the player leaves them, so they will be ready for return visits. When checkpointing, NetHack also writes out the level entered and From 0dc5d8c2f1389e6df1742da15337216a1f530671 Mon Sep 17 00:00:00 2001 From: "G. Branden Robinson" Date: Sat, 28 Dec 2024 11:07:59 -0600 Subject: [PATCH 266/791] doc/dlb.6: Revise synopsis Follow Unix idioms and the guidelines presented in groff_man_style(7).[1] * Present multiple synopses since the command has multiple operation modes accessed via mutually inexpressible command letters. See the POSIX standard for copious precedent. * Stop implying that file name arguments are accepted alongside the `I` option; see line 236 of util/dlb_main.c. * Stop spacing around synopsis punctuation where unnecessary. * Set metasyntactic variables (parameters) in italics, not roman or bold. * Spell ellipsis idiomatically for pleasant typesetting. * Use `\c` escape sequence to force adjacency of tar-like option letters to the mandatory operation letter. * Use singular, not plural, for repeatable argument. The ellipsis does the grammatical work of pluralization for us. [1] Full disclosure: I wrote much of (the current form of) that man page. --- doc/dlb.6 | 39 ++++++++++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/doc/dlb.6 b/doc/dlb.6 index 5505bc3f8..75b77637e 100644 --- a/doc/dlb.6 +++ b/doc/dlb.6 @@ -21,18 +21,35 @@ dlb \- NetHack data librarian .SH SYNOPSIS .B dlb -{ -.B xct -} -[ -.B vfIC -] -arguments... -[ -.B files... -] -.SH DESCRIPTION +.\" We'd use `RB` with 7 arguments, but Unix troff man(7) has a limit of +.\" 6 arguments to its macros. +{\c +.BR c | t | x\c +}\c +.RB [ v ]\c +.RB [ C +.IR directory ] +.RI [ file ] +\&.\|.\|. .PP +.B dlb +{\c +.BR c | t | x\c +}\c +.RB [ v ]\c +.B I +.IR list-file +.PP +.B dlb +{\c +.BR c | t | x\c +}\c +.RB [ v ]\c +.RB [ f +.IR archive-file-name ] +.RI [ file ] +\&.\|.\|. +.SH DESCRIPTION .I Dlb is a file archiving tool in the spirit (and tradition) of tar for NetHack version 3.1 and higher. It is used to maintain the From a6a32170ee2db092b5fbdb489902bbb8cf15e22c Mon Sep 17 00:00:00 2001 From: "G. Branden Robinson" Date: Sat, 28 Dec 2024 11:44:02 -0600 Subject: [PATCH 267/791] doc/dlb.6: Revise description MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Content: * Document that the command has a default file list. * Demote "COMMANDS" section to "Operations" subsection. The former term is (1) too easily confused with Unix commands and (2) not a widely used section heading in man pages. Style: * Italicize command names. * Italicize file names. * Use idiomatic man page cross references. * Present operation and option letters in alphabetical order. * Render option descriptions as full sentences. * Set bug list as a bulleted list. Markup: * Break input lines at sentence boundaries. * Favor use of man(7) font selection and alternation macros over roff(7) font selection escape sequences. * Drop numerous extraneous paragraphing macro calls. See subsection "Horizontal and vertical spacing" of groff_man(7). * Replace use of *roff requests to break lines and vertically space with calls of paragraphing macros, which is what they're for. Two things the page author didn't know: `.sp 1` already implies a break, so the preceding `.br` was redundant. `.sp 1` without an argument already means to vertically space by 1 vee; that is, the "1" argument was superfluous. It was a bad idea anyway because the default inter-paragraph spacing in man(7) is not one vee, but 0.4v--this matters when typesetting. It has also been the case since 1979. * Use `RS` and `RE` macros instead of a literal tab to achieve a relative inset. Use of the macros is more idiomatic. * Use `EX` and `EE` to attempt to set the examples in a monospaced font family. These are extensions and are silently ignored by formatters that don't support them. groff_man(7): .EX .EE Begin and end example. After .EX, filling is disabled and a constant‐width (monospaced) font is selected. Calling .EE enables filling and restores the previous font. .EX and .EE are extensions introduced in Ninth Edition Unix. Documenter’s Workbench, Heirloom Doctools, and Plan 9 troffs, and mandoc (since 1.12.2) also support them. Solaris troff does not. See subsection “Use of extensions” in groff_man_style(7). * Kill off useless trailing space on input line. --- doc/dlb.6 | 120 +++++++++++++++++++++++++++++++----------------------- 1 file changed, 69 insertions(+), 51 deletions(-) diff --git a/doc/dlb.6 b/doc/dlb.6 index 75b77637e..b58b12164 100644 --- a/doc/dlb.6 +++ b/doc/dlb.6 @@ -51,12 +51,22 @@ dlb \- NetHack data librarian \&.\|.\|. .SH DESCRIPTION .I Dlb -is a file archiving tool in the spirit (and tradition) of tar for -NetHack version 3.1 and higher. It is used to maintain the -archive files from which NetHack reads special level files and other -read-only information. Note that like tar the command and option -specifiers are specified as a continuous string and are followed -by any arguments required in the same order as the option specifiers. +is a file archiving tool in the spirit (and tradition) of +.IR tar (1) +for +.IR nethack (6) +version 3.1 and higher. +It is used to maintain the +archive files from which the game reads special level files and other +read-only information. +Note that like +.IR tar , +the letters specifying the operation and options +are expressed as a continuous string. +Unlike +.IR tar , +.I dlb +is configured with a default set of file names to process. .ig .PP ^?ALLDOCS @@ -72,67 +82,75 @@ configuration. ^. ^. .. -.SH COMMANDS -The -.B x -command causes -.I dlb -to extract the contents of the archive into the current directory. -.PP -The +.SS Operations .B c -command causes +causes .I dlb to create a new archive from files in the current directory. .PP -The .B t -command lists the files in the archive. -.SH OPTIONS AND ARGUMENTS -.TP 12m -\fBv -verbose output -.br -.sp 1 +lists the files in the archive. +.PP +.B x +causes +.I dlb +to extract the contents of the archive into the current directory. +.SH OPTIONS +.TP 13n \" "I list-file" + 2n +.BI "C " dir +Change directory to +.I dir +before trying to +read any files. .TP -\fBf\fI\ archive -specify the archive. Default if f not specified is -LIBFILE (usually the nhdat file in the playground). -.br -.sp 1 +.BI "f " archive +Read from or write to +.I archive +instead of LIBFILE +(usually the +.I nhdat +file in the playground). .TP -\fBI\fI\ lfile -specify the file containing the list of files to -put in to or extract from the archive if no files are listed -on the command line. Default for archive creation if no files -are listed is LIBLISTFILE. -.br -.sp 1 +.BI "I " list-file +Read from +.I list-file +the names of files to emplace within or extract from the archive. +The default for archive creation is LIBLISTFILE. .TP -\fBC\fI\ dir -change directory. Changes directory before trying to -read any files (including the archive and the lfile). -.br +.B v +Operate verbosely. .SH EXAMPLES Create the default archive from the default file list: -.br - dlb c -.sp 1 -List the contents of the archive 'foo': -.br - dlb tf foo -.SH AUTHOR +.RS +.EX +dlb c +.EE +.RE .PP +List the contents of the archive +.IR foo : +.RS +.EX +dlb tf foo +.EE +.RE +.SH AUTHOR Kenneth Lorber .SH "SEE ALSO" -.PP -nethack(6), tar(1) +.IR nethack (6), +.IR tar (1) .SH BUGS -.PP -Not a good tar emulation; - does not mean stdin or stdout. +.IP \(bu 2n +Not a good +.I tar +emulation; +.B - +does not mean stdin or stdout. +.IP \(bu Should include an optional compression facility. +.IP \(bu Not all read-only files for NetHack can be read out of an archive; -examining the source is the only way to know which files can be. +examining the source is the only way to know which files can be. .SH COPYRIGHT This file is Copyright (C) \*(Na, \*(Nd for version \*(Nb:\*(Nr. NetHack may be freely redistributed. See license for details. From d329a4ce8ac2a293b3b4b04e45afe28ef23c25b6 Mon Sep 17 00:00:00 2001 From: keni Date: Tue, 31 Dec 2024 17:15:11 -0500 Subject: [PATCH 268/791] update tamc.nh docs (mnh.7) --- doc/mnh.7 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/mnh.7 b/doc/mnh.7 index daed16283..df7fe5856 100644 --- a/doc/mnh.7 +++ b/doc/mnh.7 @@ -76,6 +76,7 @@ and the second for Macro What Initial Note \0 Explanation Name It Is Value .sp .3 +nH num 0 \- avoid processing multiple times _BR mac \- \- hard line break with vertical padding inserted bR num \- i _CC \*Y mac \- \- aligned one char key \*x with \fIshort\fP definition \*y @@ -92,4 +93,5 @@ PX num \- i PY num \- i _SD \*X mac \- \- .sd with options c-center i-indent n-no indent SF num \- i +UR mac \- \- URL passthrough for HTML generator _UX mac \- \- .ux with updated trademark owner From fea3c85471d5f63104e89bb3f9d3e16fb194da63 Mon Sep 17 00:00:00 2001 From: PatR Date: Tue, 31 Dec 2024 18:54:27 -0800 Subject: [PATCH 269/791] fix issue #1350 - shop purchasing Aka issue #1339 take II For hero-owned container with some unpaid items, the itemized shopping bill had a spurious index into the traditional shopping bill (since it wasn't in that bill due not being unpaid). When mixed with unpaid items that weren't in the container, that could cause bill corruption while updating the traditional bill during payment, leading to impossible warnings. Fixes #1339 Fixes #1350 --- src/shk.c | 51 ++++++++++++++++++++++++++++----------------------- 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/src/shk.c b/src/shk.c index 0b8d508c5..103ca22da 100644 --- a/src/shk.c +++ b/src/shk.c @@ -33,11 +33,15 @@ enum billitem_status { unpaid and by cost within each of those two categories */ struct sortbill_item { struct obj *obj; - long cost; - long quan; - int bidx; - int8 usedup; /* small but signed */ - boolean queuedpay; + long cost; /* full amount for current quantity, not per-unit amount */ + long quan; /* count for this entry; subset if this is partly used or + * partly intact */ + int bidx; /* index into ESHK(shkp)->bill_p[]; hero-owned container, + * which isn't in bill_p[], uses bidx == -1 */ + int8 usedup; /* billitem_status, small but needs to be signed for qsort() + * [for an earlier edition; 'signed' no longer necessary] */ + boolean queuedpay; /* buy without asking when containers are involved + * or purchase targets have been picked via menu */ }; typedef struct sortbill_item Bill; @@ -1457,6 +1461,7 @@ cheapest_item(int ibillct, Bill *ibill) return gmin; } + /* for itemized purchasing, create an alternate shop bill that hides container contents */ staticfn int /* returns number of entries */ @@ -1469,7 +1474,7 @@ make_itemized_bill( struct bill_x *bp; struct obj *otmp; struct eshk *eshkp = ESHK(shkp); - int i, n, ebillct = eshkp->billct; + int i, n, bidx, ebillct = eshkp->billct; int8 used; long quan, cost; @@ -1491,6 +1496,7 @@ make_itemized_bill( impossible("Can't find shop bill entry for #%d", bp->bo_id); continue; } + bidx = i; /* index into bill_p[], except for hero-owner container */ if (otmp->quan == 0L || otmp->where == OBJ_ONBILL) { /* item is completely used up; restore quantity from when it @@ -1506,7 +1512,7 @@ make_itemized_bill( ibill[n].obj = otmp; ibill[n].quan = bp->bquan - otmp->quan; ibill[n].cost = bp->price * ibill[n].quan; - ibill[n].bidx = i; /* duplicate index into eshkp->bill_p[] */ + ibill[n].bidx = bidx; /* duplicate index into eshkp->bill_p[] */ ibill[n].usedup = PartlyUsedUp; /* for sorting */ ++n; /* intact portion will be a separate entry, next */ } @@ -1547,6 +1553,8 @@ make_itemized_bill( /* include 1 container containing unpaid item(s) */ quan = 1L; cost = unpaid_cost(otmp, COST_CONTENTS); + if (!otmp->unpaid) + bidx = -1; /* an unpaid container without any unpaid contents is classified as 'FullyIntact'; a container with unpaid contents will be '*Container' regardless of whether it is unpaid itself */ @@ -1564,7 +1572,7 @@ make_itemized_bill( ibill[n].obj = otmp; ibill[n].quan = quan; ibill[n].cost = cost; - ibill[n].bidx = i; + ibill[n].bidx = bidx; ibill[n].usedup = used; ++n; } @@ -2034,11 +2042,7 @@ pay_billed_items( if (queuedpay && !ibill[indx].queuedpay) continue; - bidx = ibill[indx].bidx; - bp = &eshkp->bill_p[bidx]; - otmp = ibill[indx].obj; - pass = (ibill[indx].usedup <= PartlyUsedUp) ? 0 : 1; - + otmp = ibill[indx].obj; /* ordinary object or outermost container */ if (ibill[indx].usedup >= KnownContainer) { /* when successfull, buy_container() will call both dopayobj() and update_bill(), possibly multiple times */ @@ -2054,6 +2058,10 @@ pay_billed_items( buy = PAY_CANT; } } else { + bidx = ibill[indx].bidx; + bp = &eshkp->bill_p[bidx]; + pass = (ibill[indx].usedup <= PartlyUsedUp) ? 0 : 1; + buy = dopayobj(shkp, bp, otmp, pass, itemize, FALSE); if (buy == PAY_BUY) @@ -2091,12 +2099,11 @@ update_bill( struct obj *paiditem) { int j, newebillct; - int bidx = ibill[indx].bidx; /* remove from eshkp->bill_p[] unless this was the used up portion of partly used item (since removal would take out both; note: can't buy PartlyIntact until PartlyUsedUp has been paid for) */ - if (ibill[indx].usedup == PartlyUsedUp) { + if (indx >= 0 && ibill[indx].usedup == PartlyUsedUp) { /* 'paiditem' points to the partly intact portion still in invent or inside a container (ibill[indx].obj points to the container) */ bp->bquan = paiditem->quan; @@ -2117,13 +2124,11 @@ update_bill( } newebillct = eshkp->billct - 1; *bp = eshkp->bill_p[newebillct]; -#if 0 /* [this is responsible for github issue #1339; it's not clear why] */ - for (j = 0; j < ibillct; ++j) - if (ibill[j].bidx == newebillct) - ibill[j].bidx = bidx; -#else - nhUse(bidx); -#endif + if (indx >= 0) { + for (j = 0; j < ibillct; ++j) + if (ibill[j].bidx == newebillct) + ibill[j].bidx = ibill[indx].bidx; + } eshkp->billct = newebillct; /* eshkp->billct - 1 */ } return; @@ -2306,7 +2311,7 @@ buy_container( } /* [updating cost here is not necessary but useful when debugging] */ ibill[indx].cost -= (bp->price * bp->bquan); /* update container */ - update_bill(indx, ibillct, ibill, eshkp, bp, otmp); + update_bill(-1, ibillct, ibill, eshkp, bp, otmp); ++buycount; } if (buycount && sightunseen) { From 35f2ca44e237f8007a5bc36556fbe8e25c874143 Mon Sep 17 00:00:00 2001 From: nhmall Date: Wed, 1 Jan 2025 08:46:41 -0500 Subject: [PATCH 270/791] update year in COPYRIGHT_BANNER_A to 2025 --- include/patchlevel.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/patchlevel.h b/include/patchlevel.h index 4bfe37f3d..f29a68d9a 100644 --- a/include/patchlevel.h +++ b/include/patchlevel.h @@ -36,7 +36,7 @@ #define DEBUG #endif -#define COPYRIGHT_BANNER_A "NetHack, Copyright 1985-2024" +#define COPYRIGHT_BANNER_A "NetHack, Copyright 1985-2025" #define COPYRIGHT_BANNER_B \ " By Stichting Mathematisch Centrum and M. Stephenson." /* nomakedefs.copyright_banner_c is generated at runtime */ From 0a58b7a540441c1bb82ef6060caede68041366fe Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Wed, 1 Jan 2025 21:37:28 +0200 Subject: [PATCH 271/791] Tweak tourist xp gain from new monsters Remove the XP gain for tourist seeing a new type of monster nearby, as it apparently made tourists a bit harder by forcing early level gains. Monsters next to hero are still marked as seen close-up, but fix the code so it doesn't count undetected monsters. Tourists still gain XP from "taking photos" of new types of monsters, but only if they haven't seen the monster close up before. (No actual photos are taken.) --- doc/fixes3-7-0.txt | 2 +- src/mon.c | 11 ++++------- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index 4fa4c3d7f..5944b188e 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -2749,7 +2749,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, and +tourists gain experience by "taking photos" of new creatures, and going to new dungeon levels healers gain experience by healing pets blessed scroll of destroy armor asks which armor to destroy diff --git a/src/mon.c b/src/mon.c index 93aad677a..545283c8d 100644 --- a/src/mon.c +++ b/src/mon.c @@ -5804,7 +5804,8 @@ adj_erinys(unsigned abuse) pm->difficulty = min(10 + (u.ualign.abuse / 3), 25); } -/* mark monster type as seen from close-up */ +/* mark monster type as seen from close-up, + if we haven't seen it nearby before */ void see_monster_closeup(struct monst *mtmp) { @@ -5823,17 +5824,13 @@ see_nearby_monsters(void) { coordxy x, y; - /* currently used only for tourists ... */ - 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)) - see_monster_closeup(mtmp); + if (canspotmon(mtmp) && !mtmp->mundetected && !M_AP_TYPE(mtmp)) + svm.mvitals[monsndx(mtmp->data)].seen_close = TRUE; } } From 114f99867eced260f668d00319732143e0703ae8 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Wed, 1 Jan 2025 23:43:12 +0200 Subject: [PATCH 272/791] Fix unicorn movement special handling My commit 82f0b1e8ea4e54 to make monsters which had nowhere to move would panic attack the hero if possible, broke the special unicorn handling; they avoid being in-line with hero, so often had nowhere to move... Fixes #1344 --- src/monmove.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/monmove.c b/src/monmove.c index 61afc0d35..ceb4927a1 100644 --- a/src/monmove.c +++ b/src/monmove.c @@ -1898,7 +1898,7 @@ m_move(struct monst *mtmp, int after) coord poss[9]; cnt = mfndpos(mtmp, poss, info, flag); - if (cnt == 0) { + if (cnt == 0 && !is_unicorn(mtmp->data)) { if (find_defensive(mtmp, TRUE) && use_defensive(mtmp)) return MMOVE_DONE; return MMOVE_NOMOVES; From 41d95d43251bf5c89639c26fad34cd3ab3d6b265 Mon Sep 17 00:00:00 2001 From: copperwater Date: Wed, 1 Jan 2025 11:08:00 -0500 Subject: [PATCH 273/791] Fix some bigroom wall corners to how they display in-game Noticed a few corners in some bigroom maps were | instead of -, which doesn't have any gameplay effect but was mildly annoying for what I was doing at the time (copying the maps out into documentation that is supposed to show what the maps look like in-game). There are other special levels out there that still use | for corners; this doesn't address those, only the bigrooms. --- dat/bigrm-4.lua | 28 ++++++++++++++-------------- dat/bigrm-6.lua | 2 +- dat/bigrm-7.lua | 4 ++-- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/dat/bigrm-4.lua b/dat/bigrm-4.lua index 777eeb30f..a6b9340d1 100644 --- a/dat/bigrm-4.lua +++ b/dat/bigrm-4.lua @@ -9,20 +9,20 @@ des.level_flags("mazelevel", "noflip"); des.map([[ ----------- ----------- |.........| |.........| -|.........|-----------| |-----------|.........| -|-|...................|----------| |----------|...................|-| - -|.............................|-------|.............................|- - -|.................................................................|- - -|...............................................................|- - -|......LLLLL.......................................LLLLL......|- - -|.....LLLLL.......................................LLLLL.....|- - -|.....LLLLL.......................................LLLLL.....|- - -|......LLLLL.......................................LLLLL......|- - -|...............................................................|- - -|.................................................................|- - -|.............................|-------|.............................|- -|-|...................|----------| |----------|...................|-| -|.........|-----------| |-----------|.........| +|.........------------- -------------.........| +---...................------------ ------------...................--- + --.............................---------.............................-- + --.................................................................-- + --...............................................................-- + --......LLLLL.......................................LLLLL......-- + --.....LLLLL.......................................LLLLL.....-- + --.....LLLLL.......................................LLLLL.....-- + --......LLLLL.......................................LLLLL......-- + --...............................................................-- + --.................................................................-- + --.............................---------.............................-- +---...................------------ ------------...................--- +|.........------------- -------------.........| |.........| |.........| ----------- ----------- ]]); diff --git a/dat/bigrm-6.lua b/dat/bigrm-6.lua index f67cc1638..c6063a818 100644 --- a/dat/bigrm-6.lua +++ b/dat/bigrm-6.lua @@ -12,7 +12,7 @@ des.map([[ --...........-- --...........-- --...........-- --...........-- --.............-- --.............-- --.............-- --.............-- -...............- -...............- -...............- -...............- -|-...............---...............---...............---...............-- +--...............---...............---...............---...............-- |.................-.................-.................-.................| |........T.................T.................T.................T........| |.......................................................................| diff --git a/dat/bigrm-7.lua b/dat/bigrm-7.lua index 6dc828c83..07038d8d6 100644 --- a/dat/bigrm-7.lua +++ b/dat/bigrm-7.lua @@ -14,11 +14,11 @@ des.map([[ ---------.................................--- ---------...........................................--- ---------.....................................................--- -|--------...............................................................--| +---------...............................................................--- |.........................................................................| |.L.....................................................................L.| |.........................................................................| -|--...............................................................--------| +---...............................................................--------- ---.....................................................--------- ---...........................................--------- ---.................................--------- From 292957407ffb97642912691bad4137e395f3fabc Mon Sep 17 00:00:00 2001 From: copperwater Date: Wed, 1 Jan 2025 11:14:30 -0500 Subject: [PATCH 274/791] Fix: ravens specified as hostile on Medusa's Island could be peaceful Noticed when testing the recent bec de corbin change which makes ravens generate as peaceful; if you happened to enter medusa-3 while wielding one, all the ravens are peaceful. Even without one, if you entered the level as a neutral character, some of them would randomly be peaceful due to matching alignment. But in the medusa-3.lua file, the ravens are all unconditionally flagged as hostile. The reason for this behavior is that the lua loading code does not recognize "hostile" (instead peaceful=0 needs to be set), so it does nothing and leaves the ravens to generate as if it had been unspecified. It appeared to affect only these ravens; no other des.monster() uses hostile=1 instead of peaceful=0. This bug has been around in the 3.7 development branch since the change to Lua, but doesn't happen in 3.6 because the des parser does interpret "hostile" as meaning never peaceful. I considered augmenting lspo_monster so that it could handle "hostile" and treat it like peaceful=0, but figure it's probably better not to have two different booleans that control the same flag (what if someone specified peaceful = 1 and hostile = 1?) --- dat/medusa-3.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dat/medusa-3.lua b/dat/medusa-3.lua index 4419117f7..282d3668b 100644 --- a/dat/medusa-3.lua +++ b/dat/medusa-3.lua @@ -132,7 +132,7 @@ des.monster("water nymph") des.monster("water nymph") for i=1,30 do - des.monster({ id = "raven", hostile = 1 }) + des.monster({ id = "raven", peaceful = 0 }) end --#medusa-3.lua From 171d48c8819653b6b4d796788b54596f706584ec Mon Sep 17 00:00:00 2001 From: copperwater Date: Wed, 1 Jan 2025 11:41:52 -0500 Subject: [PATCH 275/791] Fix: brides of Dracula not generating in their niches When the des.monster() statements for the vampire ladies were changed to use the lua-table form, the coordinate argument was not given the coord= name in the table, so the lua loader was ignoring it and the vampire ladies were placed on random spaces on the level. Fix this by supplying the coord=; testing shows that they now appear back in the niches. Also lowercase the monster species id "Vampire Lady" to "vampire lady". The uppercase didn't affect the species being generated but having the id be the same case as in monsters.h is consistent with how it's done everywhere else. --- dat/tower1.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dat/tower1.lua b/dat/tower1.lua index 8aab0a7ad..eae3016b3 100644 --- a/dat/tower1.lua +++ b/dat/tower1.lua @@ -42,9 +42,9 @@ 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 }) +des.monster({ id="vampire lady", coord=niches[4], name=Vnames[1], waiting=1 }) +des.monster({ id="vampire lady", coord=niches[5], name=Vnames[2], waiting=1 }) +des.monster({ id="vampire lady", coord=niches[6], name=Vnames[3], waiting=1 }) -- The doors des.door("closed",08,03) des.door("closed",10,03) From 2d4f9893ad5fc0011b98726f3233afa9ff862e96 Mon Sep 17 00:00:00 2001 From: copperwater Date: Wed, 1 Jan 2025 19:56:49 -0500 Subject: [PATCH 276/791] Enable more ways to specify monster inventory in special levels This originated with a bug in NerfHack in which the developer specified an inventory for a quest nemesis, but neglected to include the Bell of Opening in it. Since monsters' inventory contents from makemon() were tossed out completely, this caused a situation where the Bell was deleted and the game was unwinnable. The first part of this change is guarding against that by adding mdrop_special_objs before discarding the inventory. This does create a possibility where if the programmer *does* specify a nemesis get the Bell item in their inventory, while neglecting to remove its special case generation in makemon.c, it would generate twice - but two Bells is better than none. Working on that fix led me to think about a limitation of the current sp_lev.c behavior. You could either have a monster generate with its species-typical inventory by not specifying an inventory for it, or you could have it generate with custom inventory but then have to use that to clumsily reproduce the normal inventory's complex chances and conditionals in mongets(). So the remainder of this commit implements another flag for des.monster(), keep_default_invent, that allows for more flexibility in two ways: 1. When des.monster() contains an inventory function and keep_default_invent is true, the monster will retain everything it gets from makemon() and the objects in the inventory function are in ADDITION to those. This is useful for augmenting a monster's default kit with something to make them more threatening, or just more loot. 2. When des.monster contains no inventory function and keep_default_invent is false, the monster will get NO inventory even if its species is normally supposed to. I'm not sure where exactly this would be used, but it doesn't hurt to have it available. When keep_default_invent is not specified at all, the behavior remains the same as it is now - if inventory is provided, default items are discarded, and if not, they are kept. --- doc/lua.adoc | 3 ++- include/sp_lev.h | 5 +++++ src/sp_lev.c | 31 ++++++++++++++++++++++++++----- 3 files changed, 33 insertions(+), 6 deletions(-) diff --git a/doc/lua.adoc b/doc/lua.adoc index e9962a174..0d63041ea 100644 --- a/doc/lua.adoc +++ b/doc/lua.adoc @@ -794,7 +794,8 @@ The hash parameter accepts the following keys: | ignorewater | boolean | ignore water when choosing location for the monster | countbirth | boolean | do we count this monster as generated | appear_as | string | monster can appear as object, monster, or terrain. Add "obj:", "mon:", or "ter:" prefix to the value. | -| inventory | function | objects generated in the function are given to the monster +| inventory | function | objects generated in the function are given to the monster (any random inventory it gets is discarded unless keep_default_invent is true) +| keep_default_invent | boolean | if inventory is specified and this is true, those items are in addition to random inventory for this species; if inventory is not specified and this is false, monster gets no starting inventory |=== Example: diff --git a/include/sp_lev.h b/include/sp_lev.h index 3a9a18d34..769c6a1c7 100644 --- a/include/sp_lev.h +++ b/include/sp_lev.h @@ -74,6 +74,11 @@ enum lvlinit_types { #define NO_LOC_WARN 0x20 /* no complaints and set x & y to -1, if no loc */ #define SPACELOC 0x40 /* like DRY, but accepts furniture too */ +/* has_invent flags */ +#define NO_INVENT 0 /* monster doesn't get any invent */ +#define CUSTOM_INVENT 0x01 /* monster gets items specified in lua */ +#define DEFAULT_INVENT 0x02 /* monster gets items from makemon() */ + #define SP_COORD_X(l) (l & 0xff) #define SP_COORD_Y(l) ((l >> 16) & 0xff) #define SP_COORD_PACK(x, y) (((x) & 0xff) + (((y) & 0xff) << 16)) diff --git a/src/sp_lev.c b/src/sp_lev.c index 16adaf345..f18f795e9 100644 --- a/src/sp_lev.c +++ b/src/sp_lev.c @@ -2165,8 +2165,14 @@ create_monster(monster *m, struct mkroom *croom) if (vampshifted(mtmp) && m->appear != M_AP_MONSTER) (void) newcham(mtmp, &mons[mtmp->cham], NO_NC_FLAGS); } - if (m->has_invent) { + if (!(m->has_invent & DEFAULT_INVENT)) { + /* guard against someone accidentally specifying e.g. quest nemesis + * with custom inventory that lacks Bell or quest artifact but + * forgetting to flag them as receiving their default inventory */ + mdrop_special_objs(mtmp); discard_minvent(mtmp, TRUE); + } + if (m->has_invent & CUSTOM_INVENT) { invent_carrying_monster = mtmp; } } @@ -3217,7 +3223,7 @@ lspo_monster(lua_State *L) tmpmons.stunned = 0; tmpmons.confused = 0; tmpmons.seentraps = 0; - tmpmons.has_invent = 0; + tmpmons.has_invent = DEFAULT_INVENT; tmpmons.waiting = 0; tmpmons.mm_flags = NO_MM_FLAGS; @@ -3265,6 +3271,7 @@ lspo_monster(lua_State *L) : (mgend == MALE) ? MALE : rn2(2); } } else { + int keep_default_invent = -1; /* -1 = unspecified */ lcheck_param_table(L); tmpmons.peaceful = get_table_boolean_opt(L, "peaceful", BOOL_RANDOM); @@ -3285,7 +3292,8 @@ lspo_monster(lua_State *L) tmpmons.confused = get_table_boolean_opt(L, "confused", FALSE); tmpmons.waiting = get_table_boolean_opt(L, "waiting", FALSE); tmpmons.seentraps = 0; /* TODO: list of trap names to bitfield */ - tmpmons.has_invent = 0; + keep_default_invent = + get_table_boolean_opt(L, "keep_default_invent", -1); if (!get_table_boolean_opt(L, "tail", TRUE)) tmpmons.mm_flags |= MM_NOTAIL; @@ -3334,7 +3342,19 @@ lspo_monster(lua_State *L) lua_getfield(L, 1, "inventory"); if (!lua_isnil(L, -1)) { - tmpmons.has_invent = 1; + /* overwrite DEFAULT_INVENT - most times inventory is specified, + * the monster should not get its species' default inventory. Only + * provide it if explicitly requested. */ + tmpmons.has_invent = CUSTOM_INVENT; + if (keep_default_invent == TRUE) + tmpmons.has_invent |= DEFAULT_INVENT; + } + else { + /* if keep_default_invent was not specified (-1), keep has_invent as + * DEFAULT_INVENT and provide the species' default inventory. + * But if it was explicitly set to false, provide *no* inventory. */ + if (keep_default_invent == FALSE) + tmpmons.has_invent = NO_INVENT; } } @@ -3348,7 +3368,8 @@ lspo_monster(lua_State *L) create_monster(&tmpmons, gc.coder->croom); - if (tmpmons.has_invent && lua_type(L, -1) == LUA_TFUNCTION) { + if ((tmpmons.has_invent & CUSTOM_INVENT) + && lua_type(L, -1) == LUA_TFUNCTION) { lua_remove(L, -2); nhl_pcall_handle(L, 0, 0, "lspo_monster", NHLpa_panic); spo_end_moninvent(); From d3c57e1b427bfbf83424c59628b3b7581113d419 Mon Sep 17 00:00:00 2001 From: nhmall Date: Thu, 2 Jan 2025 11:46:15 -0500 Subject: [PATCH 277/791] fix reported crash of TTY_PERM_INVENT segfaulting Options processing can be early, even before ttyDisplay is allocated. If we find that TTY_PERM_INVENT initialization is happening too early, just set a marker (iflags.perm_invent_pending) to try again a bit later. The changes in win/share are just to be able to sucessfully reproduce the original issue on Windows. It was easily reproduced on Unix, just by building with TTY_PERM_INVENT in include/config.h and setting OPTIONS=perm_invent in config file. --- include/extern.h | 3 +++ include/flag.h | 1 + include/wintype.h | 1 + src/allmain.c | 4 ++++ src/invent.c | 6 ++++++ src/options.c | 20 +++++++++++++++++++- win/share/safeproc.c | 10 ++++++++++ win/tty/wintty.c | 45 +++++++++++++++++++++++++++++--------------- 8 files changed, 74 insertions(+), 16 deletions(-) diff --git a/include/extern.h b/include/extern.h index e3e0ac152..5b0f69b8b 100644 --- a/include/extern.h +++ b/include/extern.h @@ -2262,6 +2262,9 @@ extern int msgtype_type(const char *, boolean) NONNULLARG1; extern void hide_unhide_msgtypes(boolean, int); extern void msgtype_free(void); extern void options_free_window_colors(void); +#ifdef TTY_PERM_INVENT +extern void check_perm_invent_again(void); +#endif /* ### pager.c ### */ diff --git a/include/flag.h b/include/flag.h index 4fbfad0e7..01ad42fb0 100644 --- a/include/flag.h +++ b/include/flag.h @@ -319,6 +319,7 @@ struct instance_flags { boolean news; /* print news */ boolean num_pad; /* use numbers for movement commands */ boolean perm_invent; /* display persistent inventory window */ + boolean perm_invent_pending; /* need to try again */ boolean renameallowed; /* can change hero name during role selection */ boolean renameinprogress; /* we are changing hero name */ boolean sounds; /* master on/off switch for using soundlib */ diff --git a/include/wintype.h b/include/wintype.h index e3b38a959..095c1aa60 100644 --- a/include/wintype.h +++ b/include/wintype.h @@ -205,6 +205,7 @@ enum to_core_flags { too_small = 0x002, prohibited = 0x004, no_init_done = 0x008, + too_early = 0x010, }; enum from_core_requests { diff --git a/src/allmain.c b/src/allmain.c index 18e163b5a..0efec2ac9 100644 --- a/src/allmain.c +++ b/src/allmain.c @@ -720,6 +720,10 @@ init_sound_disp_gamewindows(void) display_nhwindow(WIN_MESSAGE, FALSE); clear_glyph_buffer(); display_nhwindow(WIN_MAP, FALSE); +#ifdef TTY_PERM_INVENT + if (iflags.perm_invent_pending) + check_perm_invent_again(); +#endif } void diff --git a/src/invent.c b/src/invent.c index 11bff7d23..4c9468366 100644 --- a/src/invent.c +++ b/src/invent.c @@ -6149,6 +6149,12 @@ sync_perminvent(void) || in_perm_invent_toggled) { wri = ctrl_nhwindow(WIN_INVEN, request_settings, &wri_info); if (wri != 0) { + if ((wri->tocore.tocore_flags & (too_early)) != 0) { + /* don't be too noisy about this as it's really + * a startup timing issue. Just set a marker. */ + iflags.perm_invent_pending = TRUE; + return; + } if ((wri->tocore.tocore_flags & (too_small | prohibited)) != 0) { /* sizes aren't good enough */ diff --git a/src/options.c b/src/options.c index b8b192fd2..805efe3d4 100644 --- a/src/options.c +++ b/src/options.c @@ -5384,7 +5384,11 @@ can_set_perm_invent(void) iflags.perminv_mode = InvOptOn; #ifdef TTY_PERM_INVENT - if (WINDOWPORT(tty) && !go.opt_initial) { + if ((WINDOWPORT(tty) +#ifdef WIN32 + || WINDOWPORT(safestartup) +#endif + ) && !go.opt_initial) { perm_invent_toggled(FALSE); /* perm_invent_toggled() -> sync_perminvent() @@ -5401,6 +5405,20 @@ can_set_perm_invent(void) return TRUE; } + +#ifdef TTY_PERM_INVENT +void +check_perm_invent_again(void) +{ + if (iflags.perm_invent_pending) { + iflags.perm_invent = FALSE; + if (can_set_perm_invent()) + iflags.perm_invent = TRUE; + iflags.perm_invent_pending = FALSE; + } +} +#endif + staticfn int handler_menustyle(void) { diff --git a/win/share/safeproc.c b/win/share/safeproc.c index aa2b3c478..efcb76097 100644 --- a/win/share/safeproc.c +++ b/win/share/safeproc.c @@ -510,13 +510,23 @@ safe_update_inventory(int arg UNUSED) return; } +#ifdef WIN32CON +extern win_request_info *tty_ctrl_nhwindow(winid window UNUSED, + int request UNUSED, + win_request_info *wri UNUSED); +#endif + win_request_info * safe_ctrl_nhwindow( winid window UNUSED, int request UNUSED, win_request_info *wri UNUSED) { +#ifdef WIN32CON + return (*tty_ctrl_nhwindow)(window, request, wri); +#else return (win_request_info *) 0; +#endif } /************************************************************** diff --git a/win/tty/wintty.c b/win/tty/wintty.c index 207f396ac..81fc0630a 100644 --- a/win/tty/wintty.c +++ b/win/tty/wintty.c @@ -2861,22 +2861,29 @@ tty_ctrl_nhwindow( wri->tocore = zero_tocore; tty_ok = assesstty(ttyinvmode, &offx, &offy, &rows, &cols, &maxcol, &minrow, &maxrow); - wri->tocore.needrows = (int) (minrow + 1 + ROWNO + StatusRows()); - wri->tocore.needcols = (int) tty_perminv_mincol; - wri->tocore.haverows = (int) ttyDisplay->rows; - wri->tocore.havecols = (int) ttyDisplay->cols; - if (!tty_ok) { -#ifdef RESIZABLE - /* terminal isn't big enough right now but player might resize it - and then use 'm O' to try to set 'perm_invent' again */ - wri->tocore.tocore_flags |= too_small; -#else - wri->tocore.tocore_flags |= prohibited; -#endif + if (!tty_ok && rows == 0 && cols == 0) { + /* something is terribly wrong, possibly too early in startup */ + wri->tocore.tocore_flags |= too_early; } else { - maxslot = (maxrow - 2) * (!inuse_only ? 2 : 1); - wri->tocore.maxslot = maxslot; - } + wri->tocore.needrows = (int) (minrow + 1 + ROWNO + StatusRows()); + wri->tocore.needcols = (int) tty_perminv_mincol; + wri->tocore.haverows = (int) ttyDisplay->rows; + wri->tocore.havecols = (int) ttyDisplay->cols; + if (!tty_ok) { +#ifdef RESIZABLE + /* terminal isn't big enough right now but player might + * resize it and then use 'm O' to try to set 'perm_invent' + * again + */ + wri->tocore.tocore_flags |= too_small; +#else + wri->tocore.tocore_flags |= prohibited; +#endif + } else { + maxslot = (maxrow - 2) * (!inuse_only ? 2 : 1); + wri->tocore.maxslot = maxslot; + } + } #endif /* TTY_PERM_INVENT */ break; case set_menu_promptstyle: @@ -3542,6 +3549,14 @@ assesstty( show_gold = (invmode & InvShowGold) != 0 && !inuse_only; int perminv_minrow = tty_perminv_minrow + (show_gold ? 1 : 0); + if (!ttyDisplay) { + /* too early */ + *offx = *offy = *rows = *cols = 0; + *maxcol = 0; + *minrow = *maxrow = 0; + return !(*rows < perminv_minrow || *cols < tty_perminv_mincol); + } + *offx = 0; /* topline + map rows + status lines */ *offy = 1 + ROWNO + StatusRows(); /* 1 + 21 + (2 or 3) */ From ce947600e50b9226a7b5f678ec27d11467dfb20d Mon Sep 17 00:00:00 2001 From: PatR Date: Thu, 2 Jan 2025 23:12:15 -0800 Subject: [PATCH 278/791] discoverying water walking boots If water walking boots haven't been discovered yet and underwater hero rises to the surface when putting a pair on, discover them. (Sinking while removing such on water already discovers them.) --- doc/fixes3-7-0.txt | 2 ++ include/decl.h | 3 +++ src/decl.c | 2 ++ src/do_wear.c | 17 +++++++++++++++++ 4 files changed, 24 insertions(+) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index 5944b188e..fb9527610 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -959,6 +959,8 @@ a hero on the quest home level who runs or travels past the quest leader and gets tossed out of the quest for some reason would keep running on the far side of the quest portal allow rush/run over water if wearing discovered water walking boots +wearing water walking boots while underwater (maybe via magical breathing) + and rising to surface wasn't causing the boots to become discovered flying pets wouldn't target underwater food but if they happened to fly over such food they could and would eat it praying on an altar with pet corpse on it can revive the pet diff --git a/include/decl.h b/include/decl.h index fb444cbf6..2d2aabef9 100644 --- a/include/decl.h +++ b/include/decl.h @@ -1044,6 +1044,9 @@ struct instance_globals_w { int warn_obj_cnt; /* count of monsters meeting criteria */ long wailmsg; + /* do_wear.c */ + uint8 wasinwater; + /* symbols.c */ nhsym warnsyms[WARNCOUNT]; /* the current warning display symbols */ diff --git a/src/decl.c b/src/decl.c index e21cfc8db..31d1baa8c 100644 --- a/src/decl.c +++ b/src/decl.c @@ -851,6 +851,8 @@ static const struct instance_globals_w g_init_w = { /* decl.c */ 0, /* warn_obj_cnt */ 0L, /* wailmsg */ + /* do_wear.c */ + 0U, /* symbols.c */ DUMMY, /* warnsyms */ /* files.c */ diff --git a/src/do_wear.c b/src/do_wear.c index 977b51846..0655cc764 100644 --- a/src/do_wear.c +++ b/src/do_wear.c @@ -196,8 +196,22 @@ Boots_on(void) case KICKING_BOOTS: break; case WATER_WALKING_BOOTS: + /* + * Sequencing issue? If underwater (perhaps via magical breathing), + * putting on water walking boots produces "you slowly rise above + * the surface" then "you finish your dressing maneuver". + */ + + /* spoteffects() doesn't get called here; pooleffects() is called + during movement and u.uinwater is already False after setworn() */ if (u.uinwater) spoteffects(TRUE); + /* init'd in accessory_or_armor_on() and only used here */ + if (gw.wasinwater) { + if (!u.uinwater) + makeknown(WATER_WALKING_BOOTS); + gw.wasinwater = 0U; + } /* (we don't need a lava check here since boots can't be put on while feet are stuck) */ break; @@ -2338,6 +2352,7 @@ accessory_or_armor_on(struct obj *obj) * obj->known = 1; */ + gw.wasinwater = u.uinwater; /* for WWALKING; Boots_on() is too late */ setworn(obj, mask); /* if there's no delay, we'll execute 'afternmv' immediately */ if (obj == uarm) @@ -2367,6 +2382,8 @@ accessory_or_armor_on(struct obj *obj) on_msg(obj); } svc.context.takeoff.mask = svc.context.takeoff.what = 0L; + /* gw.wasinwater = 0U; // can't clear this yet; Boots_on() needs it + * and gets called via afternmv() after this routine has returned */ } else { /* not armor */ if (ring) { /* Ring_on() expects ring to already be worn as uleft or uright */ From bf3654dbe2e1833b22052899d38720c4b0d3e5f0 Mon Sep 17 00:00:00 2001 From: PatR Date: Fri, 3 Jan 2025 08:33:03 -0800 Subject: [PATCH 279/791] \#wizintrinsic bit --- src/wizcmds.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/wizcmds.c b/src/wizcmds.c index fd0d9858b..948b63fe6 100644 --- a/src/wizcmds.c +++ b/src/wizcmds.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 wizcmds.c $NHDT-Date: 1723580901 2024/08/13 20:28:21 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.12 $ */ +/* NetHack 3.7 wizcmds.c $NHDT-Date: 1735950605 2025/01/03 16:30:05 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.19 $ */ /*-Copyright (c) Robert Patrick Rankin, 2024. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1081,6 +1081,10 @@ wiz_intrinsic(void) float_vs_flight(); else if (p == PROT_FROM_SHAPE_CHANGERS) rescham(); + if (p == WWALKING || p == LEVITATION || p == FLYING) { + if (u.uinwater) + (void) pooleffects(FALSE); + } } if (n >= 1) free((genericptr_t) pick_list); From ba731a346b4dce48cddb5c69b58e52b516b84217 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Fri, 3 Jan 2025 17:34:24 +0200 Subject: [PATCH 280/791] Fix shop steal when teleporting your swallower Picking up a shop item and not paying it, getting swallowed by a monster, and then teleporting the monster out of the shop with you in it, the shopkeeper didn't notice the theft. But the object was not marked as paid either. Also prevent giving a message of the swallower disappearing and appearing when it was teleported. (Although now there's no message given, so something should be added ...) --- src/teleport.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/teleport.c b/src/teleport.c index 422a087ac..3b3a483f1 100644 --- a/src/teleport.c +++ b/src/teleport.c @@ -1643,6 +1643,7 @@ rloc_to_core( if (u.ustuck == mtmp) { if (u.uswallow) { u_on_newpos(mtmp->mx, mtmp->my); + check_special_room(FALSE); docrt(); } else if (!m_next2u(mtmp)) { unstuck(mtmp); @@ -1652,7 +1653,7 @@ rloc_to_core( maybe_unhide_at(x, y); newsym(x, y); /* update new location */ set_apparxy(mtmp); /* orient monster */ - if (domsg && (canspotmon(mtmp) || appearmsg)) { + if (domsg && (canspotmon(mtmp) || appearmsg) && (u.ustuck != mtmp)) { int du = distu(x, y), olddu; const char *next = (du <= 2) ? " next to you" : 0, /* next2u() */ *nearu = (du <= BOLT_LIM * BOLT_LIM) ? " close by" : 0; From 9313fb7747622f863d7fa026f40d940bdd7b05ae Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Fri, 3 Jan 2025 22:21:11 +0200 Subject: [PATCH 281/791] Clear tin-eating struct when object goes away The tin-eating context was pointing to a non-existent object, causing an error when the fuzzer somehow managed to continue eating the freed tin object. Clear the pointer when the tin leaves inventory or the object is deleted. --- src/invent.c | 5 +++++ src/mkobj.c | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/src/invent.c b/src/invent.c index 4c9468366..6f2cc2528 100644 --- a/src/invent.c +++ b/src/invent.c @@ -1373,6 +1373,11 @@ freeinv_core(struct obj *obj) } else if (obj->otyp == FIGURINE && obj->timed) { (void) stop_timer(FIG_TRANSFORM, obj_to_any(obj)); } + + if (obj == svc.context.tin.tin) { + svc.context.tin.tin = (struct obj *) 0; + svc.context.tin.o_id = 0; + } } /* remove an object from the hero's inventory */ diff --git a/src/mkobj.c b/src/mkobj.c index 1ec69aa7d..e6d55fcf3 100644 --- a/src/mkobj.c +++ b/src/mkobj.c @@ -2711,6 +2711,10 @@ dealloc_obj(struct obj *obj) gt.thrownobj = 0; if (obj == gk.kickedobj) gk.kickedobj = 0; + if (obj == svc.context.tin.tin) { + svc.context.tin.tin = (struct obj *) 0; + svc.context.tin.o_id = 0; + } /* if obj came from the most recent splitobj(), it's no longer eligible for unsplitobj(); perform inline clear_splitobjs() */ From 2ebe8915f6ad7e66cbaebfacd5754397ed3dd1d1 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sat, 4 Jan 2025 16:05:03 +0200 Subject: [PATCH 282/791] Prevent melting ice destroying necessary traps A magic portal ended up on a melting ice. --- src/trap.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/trap.c b/src/trap.c index d87f4131f..9c0ec1304 100644 --- a/src/trap.c +++ b/src/trap.c @@ -7064,7 +7064,8 @@ trap_ice_effects(coordxy x, coordxy y, boolean ice_is_melting) int otyp = (ttmp->ttyp == LANDMINE) ? LAND_MINE : BEARTRAP; cnv_trap_obj(otyp, 1, ttmp, TRUE); } else { - deltrap(ttmp); + if (!undestroyable_trap(ttmp->ttyp)) + deltrap(ttmp); } } } From 1ef3167ca0bdcbccb969c085ae7fc84e57599a07 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sat, 4 Jan 2025 16:37:11 +0200 Subject: [PATCH 283/791] Steed #monster breath feedback Using #monster to make the steed use the breath weapon often failed because the steed did not want to breathe at weak or too strong monsters. Make #monster force the steed use the breath, and if there is no targets available, make the steed make some noise as feedback. --- include/extern.h | 3 ++- src/cmd.c | 2 +- src/dogmove.c | 17 +++++++++-------- src/sounds.c | 3 +-- 4 files changed, 13 insertions(+), 12 deletions(-) diff --git a/include/extern.h b/include/extern.h index 5b0f69b8b..8a4c66ccb 100644 --- a/include/extern.h +++ b/include/extern.h @@ -762,7 +762,7 @@ extern struct obj *droppables(struct monst *) NONNULLARG1; extern int dog_nutrition(struct monst *, struct obj *) NONNULLPTRS; extern int dog_eat(struct monst *, struct obj *, coordxy, coordxy, boolean) NONNULLPTRS; -extern int pet_ranged_attk(struct monst *) NONNULLARG1; +extern int pet_ranged_attk(struct monst *, boolean) NONNULLARG1; extern int dog_move(struct monst *, int) NONNULLARG1; extern boolean could_reach_item(struct monst *, coordxy, coordxy) NONNULLARG1; extern void finish_meating(struct monst *) NONNULLARG1; @@ -2911,6 +2911,7 @@ extern void whimper(struct monst *) NONNULLARG1; extern void beg(struct monst *) NONNULLARG1; extern const char *maybe_gasp(struct monst *) NONNULLARG1; extern const char *cry_sound(struct monst *) NONNULLARG1; +extern int domonnoise(struct monst *) NONNULLARG1; extern int dotalk(void); extern int tiphat(void); #ifdef USER_SOUNDS diff --git a/src/cmd.c b/src/cmd.c index 557edffd2..6db62f9af 100644 --- a/src/cmd.c +++ b/src/cmd.c @@ -934,7 +934,7 @@ domonability(void) } else if (is_vampire(uptr) || is_vampshifter(&gy.youmonst)) { return dopoly(); } else if (u.usteed && can_breathe(u.usteed->data)) { - (void) pet_ranged_attk(u.usteed); + (void) pet_ranged_attk(u.usteed, TRUE); return ECMD_TIME; } else if (Upolyd) { pline("Any special ability you may have is purely reflexive."); diff --git a/src/dogmove.c b/src/dogmove.c index b0fe44864..6eba6c089 100644 --- a/src/dogmove.c +++ b/src/dogmove.c @@ -17,7 +17,7 @@ staticfn int dog_invent(struct monst *, struct edog *, int); staticfn int dog_goal(struct monst *, struct edog *, int, int, int); staticfn struct monst *find_targ(struct monst *, int, int, int); staticfn int find_friends(struct monst *, struct monst *, int); -staticfn struct monst *best_target(struct monst *); +staticfn struct monst *best_target(struct monst *, boolean); staticfn long score_targ(struct monst *, struct monst *); staticfn boolean can_reach_location(struct monst *, coordxy, coordxy, coordxy, coordxy) NONNULLARG1; @@ -819,7 +819,7 @@ score_targ(struct monst *mtmp, struct monst *mtarg) } staticfn struct monst * -best_target(struct monst *mtmp) /* Pet */ +best_target(struct monst *mtmp, boolean forced) /* Pet */ { int dx, dy; long bestscore = -40000L, currscore; @@ -862,7 +862,7 @@ best_target(struct monst *mtmp) /* Pet */ } /* Filter out targets the pet doesn't like */ - if (bestscore < 0L) + if (!forced && bestscore < 0L) best_targ = 0; return best_targ; @@ -870,7 +870,7 @@ best_target(struct monst *mtmp) /* Pet */ /* Pet considers and maybe executes a ranged attack */ int -pet_ranged_attk(struct monst *mtmp) +pet_ranged_attk(struct monst *mtmp, boolean forced) { struct monst *mtarg; int hungry = 0; @@ -885,7 +885,7 @@ pet_ranged_attk(struct monst *mtmp) /* Identify the best target in a straight line from the pet; * if there is such a target, we'll let the pet attempt an attack. */ - mtarg = best_target(mtmp); + mtarg = best_target(mtmp, forced); /* Hungry pets are unlikely to use breath/spit attacks */ if (mtarg && (!hungry || !rn2(5))) { @@ -945,7 +945,8 @@ pet_ranged_attk(struct monst *mtmp) */ if (mstatus != M_ATTK_MISS) return MMOVE_DONE; - } + } else if (forced) + (void) domonnoise(mtmp); return MMOVE_NOTHING; } @@ -1119,7 +1120,7 @@ dog_move( || (touch_petrifies(mtmp2->data) && !resists_ston(mtmp))) { /* only skip this foe if a ranged attack isn't viable */ if (dist2(mtmp->mx, mtmp->my, mtmp2->mx, mtmp2->my) <= 2 - || best_target(mtmp) != mtmp2) + || best_target(mtmp, FALSE) != mtmp2) continue; ranged_only = TRUE; } @@ -1254,7 +1255,7 @@ dog_move( * now's the time for ranged attacks. Note that the pet can move * after it performs its ranged attack. Should this be changed? */ - if ((i = pet_ranged_attk(mtmp)) != MMOVE_NOTHING) + if ((i = pet_ranged_attk(mtmp, FALSE)) != MMOVE_NOTHING) return i; newdogpos: diff --git a/src/sounds.c b/src/sounds.c index 9ca6b199d..5b7d2baae 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -10,7 +10,6 @@ staticfn boolean morgue_mon_sound(struct monst *); staticfn boolean zoo_mon_sound(struct monst *); staticfn boolean temple_priest_sound(struct monst *); staticfn boolean mon_is_gecko(struct monst *); -staticfn int domonnoise(struct monst *); staticfn int dochat(void); staticfn struct monst *responsive_mon_at(int, int); staticfn int mon_in_room(struct monst *, int); @@ -675,7 +674,7 @@ mon_is_gecko(struct monst *mon) DISABLE_WARNING_FORMAT_NONLITERAL -staticfn int /* check calls to this */ +int /* check calls to this */ domonnoise(struct monst *mtmp) { char verbuf[BUFSZ]; From e8ad3b4c19bd827064398f3e1c38412d806d432d Mon Sep 17 00:00:00 2001 From: copperwater Date: Thu, 2 Jan 2025 19:47:11 -0500 Subject: [PATCH 284/791] Fix: quantum mechanics' tele attack had inverted negation check Noticed when I summoned a quantum mechanic in wizard mode with a starting character who should have no armor protection against their teleport attack, but every touch resulted in "You are not affected". It turns out the if statement checking for armor protection is backwards, so you were never affected when you have no protection and were almost always affected when you had good protection. This appears to date back to when the all-purpose 'negated' variable was removed and "You are not affected" moved to after the negation check; the new conditional kept the ! by mistake. --- src/uhitm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/uhitm.c b/src/uhitm.c index 47a8aef23..513b697a9 100644 --- a/src/uhitm.c +++ b/src/uhitm.c @@ -2813,7 +2813,7 @@ mhitm_ad_tlpt( int tmphp; hitmsg(magr, mattk); - if (!mhitm_mgc_atk_negated(magr, mdef, FALSE)) { + if (mhitm_mgc_atk_negated(magr, mdef, FALSE)) { You("are not affected."); } else { if (flags.verbose) From 2a502345650fe0b02bbe463c594b490cfd7fcdbd Mon Sep 17 00:00:00 2001 From: copperwater Date: Thu, 2 Jan 2025 19:56:10 -0500 Subject: [PATCH 285/791] Remove dented pot encyclopedia matching on 'helmet' Dented pots got their own encyclopedia entry, so they shouldn't still match to "helmet". Even without this change, they match the "dented pot" entry correctly, but only by virtue of it appearing earlier in the encyclopedia. Inverting the match to "~dented pot" isn't necessary since it isn't something that would otherwise match "helmet", so just remove it. --- dat/data.base | 1 - 1 file changed, 1 deletion(-) diff --git a/dat/data.base b/dat/data.base index 505c1b17d..a36f2b5fe 100644 --- a/dat/data.base +++ b/dat/data.base @@ -2395,7 +2395,6 @@ hell hound* ~helm of * ~crystal helmet helm* -dented pot * helmet A piece of armor designed to protect the head. (What were you expecting?) From 7982c72e8b884d38b07d44fa8a5f06f14d94c3c0 Mon Sep 17 00:00:00 2001 From: PatR Date: Sat, 4 Jan 2025 13:59:06 -0800 Subject: [PATCH 286/791] fix github issue #1360 - autounlock=Kick Issue reported by ostrosablin: having Kick enabled as one of the values for the 'autounlock' option succeeded it prompting "kick it?" when walking into a locked closed door, but answering "yes" behaved the same as answering "no". There's bound to be a better way of fixing this, but this works. Fixes #1360 --- doc/fixes3-7-0.txt | 2 ++ src/hack.c | 18 +++++++++++++++--- src/lock.c | 8 +++++--- 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index fb9527610..02767912e 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -2085,6 +2085,8 @@ farlook of /e or /E stopped reporting engraving and headstone text after a fix message was garbled when lightning or acid breath hit iron bars shop bug: buying a container with unpaid items in it could produce impossible "unpaid_cost: object not on any bill" warnings +when walking into/against a locked closed door, 'autounlock'==kick didn't + execute kick when player answered yes to "Door is locked. Kick it?" Fixes to 3.7.0-x Platform and/or Interface Problems Exposed Via git Repository diff --git a/src/hack.c b/src/hack.c index cf6ad1a0f..14eea831a 100644 --- a/src/hack.c +++ b/src/hack.c @@ -1073,8 +1073,18 @@ test_move( " but can't squeeze your possessions through."); if (flags.autoopen && !svc.context.run && !Confusion && !Stunned && !Fumbling) { - (void) doopen_indir(x, y); - svc.context.door_opened = !closed_door(x, y); + int tmp = doopen_indir(x, y); + /* if 'autounlock' includes Kick, we might have a + kick at the door queued up after doopen_indir() */ + struct _cmd_queue *cq = cmdq_peek(CQ_CANNED); + + if (tmp == ECMD_OK && cq && cq->typ == CMDQ_EXTCMD + && cq->ec_entry == ext_func_tab_from_func(dokick)) + /* door hasn't been opened, but fake it so that + canned kick will be executed as next command */ + svc.context.door_opened = TRUE; + else + svc.context.door_opened = !closed_door(x, y); svc.context.move = (ux != u.ux || uy != u.uy); } else if (x == ux || y == uy) { if (Blind || Stunned || ACURR(A_DEX) < 10 @@ -2057,7 +2067,9 @@ domove_fight_web(coordxy x, coordxy y) /* maybe swap places with a pet? returns TRUE if swapped places */ staticfn boolean -domove_swap_with_pet(struct monst *mtmp, coordxy x, coordxy y) +domove_swap_with_pet( + struct monst *mtmp, + coordxy x, coordxy y) { struct trap *trap; /* if it turns out we can't actually move */ diff --git a/src/lock.c b/src/lock.c index 640083041..364031635 100644 --- a/src/lock.c +++ b/src/lock.c @@ -880,13 +880,15 @@ doopen_indir(coordxy x, coordxy y) && (unlocktool = autokey(TRUE)) != 0) { res = pick_lock(unlocktool, cc.x, cc.y, (struct obj *) 0) ? ECMD_TIME : ECMD_OK; - } else if (!u.usteed - && (flags.autounlock & AUTOUNLOCK_KICK) != 0 + } else if ((flags.autounlock & AUTOUNLOCK_KICK) != 0 + && !u.usteed /* kicking is different when mounted */ && ynq("Kick it?") == 'y') { cmdq_add_ec(CQ_CANNED, dokick); cmdq_add_dir(CQ_CANNED, sgn(cc.x - u.ux), sgn(cc.y - u.uy), 0); - res = ECMD_TIME; + /* this was 'ECMD_TIME', but time shouldn't elapse until + the canned kick takes place */ + res = ECMD_OK; } } return res; From 37758c7e48a15731720347ce28ad1fd3ff4325e0 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 4 Jan 2025 19:01:34 -0500 Subject: [PATCH 287/791] some tty updates Add a note about NO_TERMS to include/wintty.h for clarity. Rename tty_startup and tty_shutdown to term_startup() and term_shutdown(). They are found in termcap.c for !NO_TERMS like most of the other term_ routines, as well as having versions for several of the NO_TERMS platforms. They aren't part of the tty_interface called from the core. The tty implementation does call and rely on them. Remove some conditional #ifdef's around term_shutdown() (formerly tty_shutdown()) and just ensure that all the tty platforms have an implementation that they can link with, even if it is just a stub presently. Put the protype for nethack_exit in extern.h to reduce maintenance to a single spot, and remove it from other locations. A warning in the msdos cross-compile led to this change. --- include/extern.h | 10 +++- include/windconf.h | 1 - include/wintty.h | 80 +++++++++++++++------------ outdated/sys/mac/mttymain.c | 2 +- src/end.c | 6 -- sys/msdos/pcvideo.h | 11 +++- sys/msdos/video.c | 61 +++++++++++++++++++- sys/msdos/vidtxt.c | 67 ++++++++++++++++++++++ sys/msdos/vidvesa.c | 12 +++- sys/msdos/vidvga.c | 12 +++- sys/share/pcmain.c | 6 -- sys/share/pcsys.c | 6 +- sys/unix/hints/include/cross-pre2.370 | 4 +- sys/windows/consoletty.c | 65 ++++++++++++++++++---- sys/windows/windmain.c | 1 - win/tty/termcap.c | 10 +++- win/tty/wintty.c | 38 ++++++------- win/win32/NetHackW.c | 1 - 18 files changed, 293 insertions(+), 100 deletions(-) diff --git a/include/extern.h b/include/extern.h index 8a4c66ccb..e6939d7a1 100644 --- a/include/extern.h +++ b/include/extern.h @@ -2098,6 +2098,7 @@ extern void consoletty_open(int); extern void consoletty_rubout(void); extern int tgetch(void); extern int console_poskey(coordxy *, coordxy *, int *); +void console_g_putch(int in_ch); extern void set_output_mode(int); extern void synch_cursor(void); extern void nethack_enter_consoletty(void); @@ -2302,7 +2303,14 @@ extern int getlock(void); extern const char *get_portable_device(void); #endif -/* ### pcsys.c ### */ +/* ### pcsys.c, windsys.c ### */ +#if defined(MICRO) || defined(WIN32) +ATTRNORETURN extern void nethack_exit(int) NORETURN; +#else +#define nethack_exit exit +#endif + +/* ### pcsys.c ### */ #if defined(MICRO) || defined(WIN32) extern void flushout(void); diff --git a/include/windconf.h b/include/windconf.h index 55b68dfa5..c3b6d4e05 100644 --- a/include/windconf.h +++ b/include/windconf.h @@ -268,7 +268,6 @@ extern int alternative_palette(char *); #endif #define nethack_enter(argc, argv) nethack_enter_windows() -ATTRNORETURN extern void nethack_exit(int) NORETURN; extern boolean file_exists(const char *); extern boolean file_newer(const char *, const char *); #ifndef SYSTEM_H diff --git a/include/wintty.h b/include/wintty.h index ec29c112b..97d439a89 100644 --- a/include/wintty.h +++ b/include/wintty.h @@ -129,6 +129,8 @@ struct tty_status_fields { #endif #define NHW_BASE (NHW_LAST_TYPE + 1) +/* external declarations */ + extern struct window_procs tty_procs; /* port specific variable declarations */ @@ -144,24 +146,53 @@ extern char defmorestr[]; /* default --more-- prompt */ /* port specific external function references */ /* ### getline.c ### */ + extern void xwaitforspace(const char *); /* ### termcap.c, video.c ### */ -extern void tty_startup(int *, int *); -#ifndef NO_TERMS -extern void tty_shutdown(void); -#endif -extern int xputc(int); -extern void xputs(const char *); -#if defined(SCREEN_VGA) || defined(SCREEN_8514) || defined(SCREEN_VESA) -extern void xputg(const glyph_info *, const glyph_info *); -#endif +/* + * TERM or NO_TERMS + * + * The tty windowport interface relies on lower-level support routines + * to actually manipulate the terminal/display. Those are the right place + * for doing strange and arcane things such as outputting escape sequences + * to select a color or whatever. wintty.c should concern itself with WHERE + * to put stuff in a window. + + * The TERM routines are found in: + * + * !NO_TERMS: termcap.c + * + * NO_TERMS: + * WINCON sys/windows/consoletty.c + * MSDOS sys/msdos/video.c + * + */ +extern void backsp(void); extern void cl_end(void); -extern void term_clear_screen(void); +extern void cl_eos(void); +extern void graph_on(void); +extern void graph_off(void); extern void home(void); extern void standoutbeg(void); extern void standoutend(void); +extern int term_attr_fixup(int); +extern void term_clear_screen(void); +extern void term_curs_set(int); +extern void term_end_attr(int attr); +extern void term_end_color(void); +extern void term_end_extracolor(void); +extern void term_end_raw_bold(void); +extern void term_start_attr(int attr); +extern void term_start_bgcolor(int color); +extern void term_start_color(int color); +extern void term_start_extracolor(uint32, uint16); +extern void term_start_raw_bold(void); +extern void term_startup(int *, int *); +extern void term_shutdown(void); +extern int xputc(int); +extern void xputs(const char *); #if 0 extern void revbeg(void); extern void boldbeg(void); @@ -169,29 +200,9 @@ extern void blinkbeg(void); extern void dimbeg(void); extern void m_end(void); #endif -extern void backsp(void); -extern void graph_on(void); -extern void graph_off(void); -extern void cl_eos(void); - -/* - * termcap.c (or facsimiles in other ports) is the right place for doing - * strange and arcane things such as outputting escape sequences to select - * a color or whatever. wintty.c should concern itself with WHERE to put - * stuff in a window. - */ -extern int term_attr_fixup(int); -extern void term_start_attr(int attr); -extern void term_end_attr(int attr); -extern void term_start_raw_bold(void); -extern void term_end_raw_bold(void); - -extern void term_end_color(void); -extern void term_start_color(int color); -extern void term_start_bgcolor(int color); -extern void term_start_extracolor(uint32, uint16); -extern void term_end_extracolor(void); /* termcap.c, consoletty.c */ -extern void term_curs_set(int); +#if defined(SCREEN_VGA) || defined(SCREEN_8514) || defined(SCREEN_VESA) +extern void xputg(const glyph_info *, const glyph_info *); +#endif /* ### topl.c ### */ @@ -203,6 +214,7 @@ extern void update_topl(const char *); extern void putsyms(const char *); /* ### wintty.c ### */ + #ifdef CLIPPING extern void setclipped(void); #endif @@ -217,7 +229,7 @@ extern void g_pututf8(uint8 *); extern void erase_tty_screen(void); extern void win_tty_init(int); -/* external declarations */ +/* tty interface */ extern void tty_init_nhwindows(int *, char **); extern void tty_preference_update(const char *); extern void tty_player_selection(void); diff --git a/outdated/sys/mac/mttymain.c b/outdated/sys/mac/mttymain.c index 2cd59a9d2..1d1460df8 100644 --- a/outdated/sys/mac/mttymain.c +++ b/outdated/sys/mac/mttymain.c @@ -541,7 +541,7 @@ setftty(void) } void -tty_startup(int *width, int *height) +term_startup(int *width, int *height) { _mt_init_stuff(); *width = CO; diff --git a/src/end.c b/src/end.c index 1bacb7547..b4370f049 100644 --- a/src/end.c +++ b/src/end.c @@ -36,12 +36,6 @@ staticfn void fixup_death(int); staticfn int wordcount(char *); staticfn void bel_copy1(char **, char *); -#if defined(__BEOS__) || defined(MICRO) || defined(OS2) || defined(WIN32) -ATTRNORETURN extern void nethack_exit(int) NORETURN; -#else -#define nethack_exit exit -#endif - #define done_stopprint program_state.stopprint /* diff --git a/sys/msdos/pcvideo.h b/sys/msdos/pcvideo.h index dfd9fc1c2..7aeb453d1 100644 --- a/sys/msdos/pcvideo.h +++ b/sys/msdos/pcvideo.h @@ -55,6 +55,7 @@ #endif #define GETCURPOS 0x03 /* Get Cursor Position */ +#define SETCURTYP 0x01 /* Set Cursor Type */ #define GETMODE 0x0f /* Get Video Mode */ #define SETMODE 0x00 /* Set Video Mode */ #define SETPAGE 0x05 /* Set Video Page */ @@ -248,6 +249,8 @@ extern void txt_nhbell(void); extern void txt_startup(int *, int *); extern void txt_xputs(const char *, int, int); extern void txt_xputc(char, int); +extern void txt_hide_cursor(void); +extern void txt_show_cursor(void); /* ### vidvga.c ### */ @@ -258,6 +261,8 @@ extern void vga_clear_screen(int); extern void vga_cl_end(int, int); extern void vga_cl_eos(int); extern int vga_detect(void); +extern void vga_hide_cursor(void); +extern void vga_show_cursor(void); #ifdef SIMULATE_CURSOR extern void vga_DrawCursor(void); #endif @@ -273,7 +278,7 @@ extern void vga_HideCursor(void); #endif extern void vga_Init(void); extern void vga_tty_end_screen(void); -extern void vga_tty_startup(int *, int *); +extern void vga_term_startup(int *, int *); extern void vga_xputs(const char *, int, int); extern void vga_xputc(char, int); extern void vga_xputg(const glyph_info *, const glyph_info *); @@ -288,6 +293,8 @@ extern void vesa_clear_screen(int); extern void vesa_cl_end(int, int); extern void vesa_cl_eos(int); extern int vesa_detect(void); +extern void vesa_hide_cursor(void); +extern void vesa_show_cursor(void); #ifdef SIMULATE_CURSOR extern void vesa_DrawCursor(void); #endif @@ -302,7 +309,7 @@ extern void vesa_HideCursor(void); #endif extern void vesa_Init(void); extern void vesa_tty_end_screen(void); -extern void vesa_tty_startup(int *, int *); +extern void vesa_term_startup(int *, int *); extern void vesa_xputs(const char *, int, int); extern void vesa_xputc(char, int); extern void vesa_xputg(const glyph_info *, const glyph_info *); diff --git a/sys/msdos/video.c b/sys/msdos/video.c index a849027eb..a6b5bfe59 100644 --- a/sys/msdos/video.c +++ b/sys/msdos/video.c @@ -146,6 +146,61 @@ boolean traditional = FALSE; /* traditional TTY character mode */ boolean inmap = FALSE; /* in the map window */ char ttycolors[CLR_MAX]; /* also used/set in options.c */ +/* for linkage from wintty.c */ + +void +term_shutdown(void) +{ +} + +#ifdef ASCIIGRAPH +void +graph_on(void) +{ +} + +void +graph_off(void) +{ +} +#endif + +void +term_curs_set(int visibility) +{ + static int vis = -1; + + if (vis == visibility) + return; + + if (!visibility) { + if (!iflags.grmode) { + txt_hide_cursor(); +#ifdef SCREEN_VGA + } else if (iflags.usevga) { + vga_hide_cursor(); +#endif +#ifdef SCREEN_VESA + } else if (iflags.usevesa) { + vesa_hide_cursor(); + } +#endif + } else if (visibility) { + if (!iflags.grmode) { + txt_show_cursor(); +#ifdef SCREEN_VGA + } else if (iflags.usevga) { + vga_show_cursor(); +#endif +#ifdef SCREEN_VESA + } else if (iflags.usevesa) { + vesa_show_cursor(); + } +#endif + } + vis = visibility; +} + void backsp(void) { @@ -447,7 +502,7 @@ tty_number_pad(int state) } void -tty_startup(int *wid, int *hgt) +term_startup(int *wid, int *hgt) { /* code to sense display adapter is required here - MJA */ @@ -461,12 +516,12 @@ tty_startup(int *wid, int *hgt) #ifdef SCREEN_VGA if (iflags.usevga) { - vga_tty_startup(wid, hgt); + vga_term_startup(wid, hgt); } else #endif #ifdef SCREEN_VESA if (iflags.usevesa) { - vesa_tty_startup(wid, hgt); + vesa_term_startup(wid, hgt); } else #endif txt_startup(wid, hgt); diff --git a/sys/msdos/vidtxt.c b/sys/msdos/vidtxt.c index 35b314b26..680f23e3c 100644 --- a/sys/msdos/vidtxt.c +++ b/sys/msdos/vidtxt.c @@ -38,6 +38,14 @@ extern int attrib_gr_normal; /* graphics mode normal attribute */ extern int attrib_text_intense; /* text mode intense attribute */ extern int attrib_gr_intense; /* graphics mode intense attribute */ +#if defined(SCREEN_BIOS) && !defined(PC9800) +static unsigned char cursor_info = 0, + cursor_start_scanline = 6, cursor_end_scanline = 7; + +static void get_cursinfo(unsigned char *start, unsigned char *end, + unsigned char *flg); +#endif + void txt_get_scr_size(void) { @@ -80,6 +88,7 @@ txt_get_scr_size(void) LI = regs.h.dl + 1; CO = regs.h.ah; + #endif /* PC9800 */ } @@ -260,6 +269,9 @@ txt_startup(int *wid, int *hgt) attrib_gr_normal = attrib_text_normal; attrib_gr_intense = attrib_text_intense; g_attribute = attrib_text_normal; /* Give it a starting value */ + get_cursinfo(&cursor_start_scanline, + &cursor_end_scanline, + &cursor_info); } /* @@ -400,6 +412,61 @@ void txt_get_cursor(int *x, int *y) (void) int86(VIDEO_BIOS, ®s, ®s); /* Get Cursor Position */ *x = regs.h.dl; *y = regs.h.dh; + if (!cursor_info) { + cursor_start_scanline = regs.h.ch; + cursor_end_scanline = regs.h.cl; + cursor_info = 1; + } +} + +void txt_hide_cursor(void) +{ + union REGS regs; + + regs.x.dx = 0; + regs.h.ah = SETCURTYP; /* set cursor type */ + regs.h.ch = 0x3F; /* starting scanline */ + regs.h.cl = 0; /* ending scanline */ + regs.x.bx = 0; + (void) int86(VIDEO_BIOS, ®s, ®s); +} + +void txt_show_cursor(void) +{ + union REGS regs; + + regs.x.dx = 0; + regs.h.ah = SETCURTYP; /* set cursor type */ + if (cursor_info) { + regs.h.ch = cursor_start_scanline; /* starting scanline */ + regs.h.cl = cursor_end_scanline; /* ending scanline */ + } else { + regs.h.ch = 6; /* starting scanline */ + regs.h.cl = 7; /* ending scanline */ + } + regs.x.bx = 0; + (void) int86(VIDEO_BIOS, ®s, ®s); +} + +static void +get_cursinfo(uchar *start, uchar *end, uchar *flg) +{ + union REGS regs; + + regs.x.dx = 0; + regs.h.ah = GETCURPOS; /* get cursor position */ + regs.x.cx = 0; + regs.x.bx = 0; + (void) int86(VIDEO_BIOS, ®s, ®s); /* Get Cursor Position */ + + if (regs.h.ch != 0x3f) { + *start = regs.h.ch; + *end = regs.h.cl; + } else { + *start = 6; + *end = 7; + } + *flg = 1; } #endif /* SCREEN_BIOS && !PC9800 */ diff --git a/sys/msdos/vidvesa.c b/sys/msdos/vidvesa.c index 08d92b7a3..4cc594bcf 100644 --- a/sys/msdos/vidvesa.c +++ b/sys/msdos/vidvesa.c @@ -603,7 +603,7 @@ vesa_tty_end_screen(void) } void -vesa_tty_startup(int *wid, int *hgt) +vesa_term_startup(int *wid, int *hgt) { /* code to sense display adapter is required here - MJA */ @@ -2042,6 +2042,16 @@ vesa_SetSoftPalette(const struct Pixel *palette) return TRUE; } +void +vesa_hide_cursor(void) +{ +} + +void +vesa_show_cursor(void) +{ +} + #ifdef POSITIONBAR #define PBAR_ROW (LI - 4) diff --git a/sys/msdos/vidvga.c b/sys/msdos/vidvga.c index 506068ac9..02b9f444f 100644 --- a/sys/msdos/vidvga.c +++ b/sys/msdos/vidvga.c @@ -297,7 +297,7 @@ vga_tty_end_screen(void) } void -vga_tty_startup(int *wid, int *hgt) +vga_term_startup(int *wid, int *hgt) { /* code to sense display adapter is required here - MJA */ @@ -1159,6 +1159,16 @@ vga_SetPalette(const struct Pixel *p) } } +void +vga_hide_cursor(void) +{ +} + +void +vga_show_cursor(void) +{ +} + /*static unsigned char colorbits[]={0x01,0x02,0x04,0x08}; */ /* wrong */ static unsigned char colorbits[] = { 0x08, 0x04, 0x02, 0x01 }; diff --git a/sys/share/pcmain.c b/sys/share/pcmain.c index 0bb30b488..5d60053cd 100644 --- a/sys/share/pcmain.c +++ b/sys/share/pcmain.c @@ -22,12 +22,6 @@ #include /* for getcwd() prototype */ #endif -#if defined(MICRO) || defined(OS2) -ATTRNORETURN void nethack_exit(int) NORETURN; -#else -#define nethack_exit exit -#endif - char *exepath(char *); char orgdir[PATHLEN]; /* also used in pcsys.c, amidos.c */ diff --git a/sys/share/pcsys.c b/sys/share/pcsys.c index ed779a284..07cab8e42 100644 --- a/sys/share/pcsys.c +++ b/sys/share/pcsys.c @@ -27,11 +27,6 @@ #define filesize filesize_nh #endif -#if defined(MICRO) || defined(OS2) -ATTRNORETURN void nethack_exit(int) NORETURN; -#else -#define nethack_exit exit -#endif static void msexit(void); #ifdef MOVERLAY @@ -276,6 +271,7 @@ msexit(void) restore_colors(); #endif wait_synch(); + term_curs_set(1); return; } #endif /* MICRO || OS2 */ diff --git a/sys/unix/hints/include/cross-pre2.370 b/sys/unix/hints/include/cross-pre2.370 index eda6829fd..b1018dc5a 100644 --- a/sys/unix/hints/include/cross-pre2.370 +++ b/sys/unix/hints/include/cross-pre2.370 @@ -235,8 +235,8 @@ ifeq "$(WANT_DEBUG)" "1" GDBEXE=$(dostargetexes)gdb.exe GDBBAT=NHGDB.BAT GDBCMDLINE=directory nhsrc/src nhsrc/include nhsrc/sys/msdos \ - nhsrc/sys/share nhsrc/win/share nhsrc/win/curses \ - nhsrc/win/tty nhsrc/util + nhsrc/sys/share nhsrc/win/curses \ + nhsrc/win/tty else GDBEXE= GDBBAT= diff --git a/sys/windows/consoletty.c b/sys/windows/consoletty.c index 0ffe4f8dc..c89e2c8ed 100644 --- a/sys/windows/consoletty.c +++ b/sys/windows/consoletty.c @@ -1079,7 +1079,7 @@ setftty(void) } void -tty_startup(int *wid, int *hgt) +term_startup(int *wid, int *hgt) { *wid = console.width; *hgt = console.height; @@ -1092,6 +1092,36 @@ tty_number_pad(int state UNUSED) // do nothing } +/* stub tcap replacements for linkage from wintty.c */ + +void +term_shutdown(void) +{ + consoletty_exit(); +} + +#ifdef ASCIIGRAPH +void +graph_on(void) +{ +} + +void +graph_off(void) +{ +} +#endif + +void +tty_end_screen(void) +{ + term_clear_screen(); + really_move_cursor(); + buffer_fill_to_end(console.back_buffer, &clear_cell, 0, 0); + back_buffer_flip(); + FlushConsoleInputBuffer(console.hConIn); +} + void tty_start_screen(void) { @@ -1107,16 +1137,6 @@ tty_start_screen(void) #endif /* VIRTUAL_TERMINAL_SEQUENCES */ } -void -tty_end_screen(void) -{ - term_clear_screen(); - really_move_cursor(); - buffer_fill_to_end(console.back_buffer, &clear_cell, 0, 0); - back_buffer_flip(); - FlushConsoleInputBuffer(console.hConIn); -} - static BOOL CtrlHandler(DWORD ctrltype) { @@ -1251,6 +1271,7 @@ console_poskey(coordxy *x, coordxy *y, int *mod) if (gc.Cmd.swap_yz) numberpad |= 0x10; #endif + term_curs_set(1); ch = (program_state.done_hup) ? '\033' : keyboard_handling.pCheckInput( @@ -1262,6 +1283,7 @@ console_poskey(coordxy *x, coordxy *y, int *mod) *x = cc.x; *y = cc.y; } + term_curs_set(0); return ch; } @@ -1462,7 +1484,7 @@ xputc_core(int ch) */ #endif void -g_putch(int in_ch) +console_g_putch(int in_ch) { unsigned char ch; cell_t cell; @@ -1644,6 +1666,25 @@ term_clear_screen(void) home(); } +void +term_curs_set(int visibility) +{ + static int vis = -1; + + if (vis == visibility) + return; + + static CONSOLE_CURSOR_INFO cursorinfo = { 0, 0 }; + + if (!cursorinfo.dwSize) { + GetConsoleCursorInfo(console.hConOut, &cursorinfo); + vis = cursorinfo.bVisible ? 1 : 0; + } + cursorinfo.bVisible = visibility ? (BOOL) TRUE : (BOOL) FALSE; + SetConsoleCursorInfo(console.hConOut, &cursorinfo); + vis = visibility; +} + void home(void) { diff --git a/sys/windows/windmain.c b/sys/windows/windmain.c index 15cb8442f..eaef359b9 100644 --- a/sys/windows/windmain.c +++ b/sys/windows/windmain.c @@ -25,7 +25,6 @@ char *translate_path_variables(const char *, char *); char *exename(void); boolean fakeconsole(void); void freefakeconsole(void); -ATTRNORETURN extern void nethack_exit(int) NORETURN; #if defined(MSWIN_GRAPHICS) extern void mswin_destroy_reg(void); #endif diff --git a/win/tty/termcap.c b/win/tty/termcap.c index 2c6a5bd88..66ed2b6a2 100644 --- a/win/tty/termcap.c +++ b/win/tty/termcap.c @@ -78,7 +78,7 @@ static char tgotobuf[20]; static char tty_standout_on[16], tty_standout_off[16]; void -tty_startup(int *wid, int *hgt) +term_startup(int *wid, int *hgt) { #ifdef TERMLIB const char *term; @@ -336,7 +336,7 @@ tty_startup(int *wid, int *hgt) */ /* deallocate resources prior to final termination */ void -tty_shutdown(void) +term_shutdown(void) { /* we only attempt to clean up a few individual termcap variables */ #if defined(TERMLIB) || defined(ANSI_DEFAULT) @@ -1494,10 +1494,16 @@ term_start_bgcolor(int color) void term_curs_set(int visibility) { + static int vis = -1; + + if (vis == visibility) + return; + if (!visibility && nh_VI) xputs(nh_VI); else if (visibility && nh_VE) xputs(nh_VE); + vis = visibility; } #ifdef CHANGE_COLOR diff --git a/win/tty/wintty.c b/win/tty/wintty.c index 81fc0630a..7703b9648 100644 --- a/win/tty/wintty.c +++ b/win/tty/wintty.c @@ -197,7 +197,7 @@ static int clipy = 0, clipymax = 0; extern void adjust_cursor_flags(struct WinDesc *); #endif -#if defined(ASCIIGRAPH) && !defined(NO_TERMS) +#if defined(ASCIIGRAPH) boolean GFlag = FALSE; boolean HE_resets_AS; /* see termcap.c */ #endif @@ -518,9 +518,9 @@ tty_init_nhwindows(int *argcp UNUSED, char **argv UNUSED) /* * Remember tty modes, to be restored on exit. * - * gettty() must be called before tty_startup() + * gettty() must be called before term_startup() * due to ordering of LI/CO settings - * tty_startup() must be called before initoptions() + * term_startup() must be called before initoptions() * due to ordering of graphics settings */ #if defined(UNIX) || defined(VMS) @@ -529,7 +529,7 @@ tty_init_nhwindows(int *argcp UNUSED, char **argv UNUSED) gettty(); /* to port dependant tty setup */ - tty_startup(&wid, &hgt); + term_startup(&wid, &hgt); setftty(); /* calls start_screen */ term_curs_set(0); @@ -840,12 +840,7 @@ tty_exit_nhwindows(const char *str) ttyDisplay = (struct DisplayDesc *) 0; #endif -#ifndef NO_TERMS /*(until this gets added to the window interface)*/ - tty_shutdown(); /* cleanup termcap/terminfo/whatever */ -#endif -#ifdef WIN32CON - consoletty_exit(); -#endif + term_shutdown(); /* cleanup termcap/terminfo/whatever */ iflags.window_inited = 0; } @@ -3720,15 +3715,15 @@ end_glyphout(void) } } -#ifndef WIN32CON void g_putch(int in_ch) { char ch = (char) in_ch; +#ifndef WIN32CON HUPSKIP(); -#if defined(ASCIIGRAPH) && !defined(NO_TERMS) +#if defined(ASCIIGRAPH) if (SYMHANDLING(H_UTF8)) { (void) putchar(ch); } else if (SYMHANDLING(H_IBM) @@ -3762,14 +3757,16 @@ g_putch(int in_ch) (void) putchar(ch); } -#else +#else /* ?ASCIIGRAPH */ (void) putchar(ch); -#endif /* ASCIIGRAPH && !NO_TERMS */ - +#endif /* ASCIIGRAPH */ +#else /* WIN32CON */ + console_g_putch(in_ch); + nhUse(ch); +#endif /* WIN32CON */ return; } -#endif /* !WIN32CON */ #if defined(UNIX) || defined(VMS) #if defined(ENHANCED_SYMBOLS) @@ -3867,9 +3864,9 @@ tty_print_glyph( #ifndef NO_TERMS if (ul_hack && ch == '_') { /* non-destructive underscore */ - (void) putchar((char) ' '); - backsp(); - } + (void) putchar((char) ' '); + backsp(); + } #endif if (iflags.use_color) { ttyDisplay->colorflags = NH_BASIC_COLOR; @@ -3965,13 +3962,12 @@ term_start_bgcolor(int color) { /* placeholder for now */ } -#endif /* !MSDOS && !WIN32 */ - void term_curs_set(int visibility UNUSED) { /* nothing */ } +#endif #ifdef CHANGE_COLOR void diff --git a/win/win32/NetHackW.c b/win/win32/NetHackW.c index 02b537cbd..45f8bf709 100644 --- a/win/win32/NetHackW.c +++ b/win/win32/NetHackW.c @@ -53,7 +53,6 @@ Version _WIN_32IE Platform/IE /*#define COMCTL_URL * "http://www.microsoft.com/msdownload/ieplatform/ie/comctrlx86.asp"*/ -ATTRNORETURN extern void nethack_exit(int) NORETURN; static TCHAR *_get_cmd_arg(TCHAR *pCmdLine); static HRESULT GetComCtlVersion(LPDWORD pdwMajor, LPDWORD pdwMinor); BOOL WINAPI From b767e1e0700d9ee692564c491defcc4aa32a2d78 Mon Sep 17 00:00:00 2001 From: PatR Date: Sat, 4 Jan 2025 16:03:56 -0800 Subject: [PATCH 288/791] missing gw.wasinwater comment --- src/decl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/decl.c b/src/decl.c index 31d1baa8c..4afe5544a 100644 --- a/src/decl.c +++ b/src/decl.c @@ -852,7 +852,7 @@ static const struct instance_globals_w g_init_w = { 0, /* warn_obj_cnt */ 0L, /* wailmsg */ /* do_wear.c */ - 0U, + 0U, /* wasinwater */ /* symbols.c */ DUMMY, /* warnsyms */ /* files.c */ From 428665c613b2fb016933346eb3323c3c7799c75a Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 4 Jan 2025 19:16:02 -0500 Subject: [PATCH 289/791] fixes entry update for another part of commit 37758c7e --- doc/fixes3-7-0.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index 02767912e..839625bea 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -2412,7 +2412,10 @@ tty: add support for petattr tty: if a ^C interrupt occurred while DECgraphics characters were being drawn on the map, the "Really quit?" prompt would be illegible due to being rendered with VT line drawing characters -tty: hide cursor unless waiting for user input +tty: hide cursor unless waiting for user input; now extended to include tty + platforms that define NO_TERMS, rather than just on those using + termcap/terminfo, namely Windows console and msdos (text-mode + implemented; vga and vesa just have stubs currently) Unix: when user name is used as default character name, keep hyphenated value intact instead stripping off dash and whatever follows as if that specified role/race/&c (worked once upon a time; broken since 3.3.0) From 63dfb84d001aa9a90714f4fc67dc6dde8fd52d42 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 4 Jan 2025 19:30:37 -0500 Subject: [PATCH 290/791] follow-up: whitespace clean-up for wintty.c Some tabs to spaces. Also restore a comment that was inadvertantly deleted. --- win/tty/wintty.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/win/tty/wintty.c b/win/tty/wintty.c index 7703b9648..ea9006af7 100644 --- a/win/tty/wintty.c +++ b/win/tty/wintty.c @@ -2866,10 +2866,10 @@ tty_ctrl_nhwindow( wri->tocore.havecols = (int) ttyDisplay->cols; if (!tty_ok) { #ifdef RESIZABLE - /* terminal isn't big enough right now but player might - * resize it and then use 'm O' to try to set 'perm_invent' - * again - */ + /* terminal isn't big enough right now but player might + * resize it and then use 'm O' to try to set 'perm_invent' + * again + */ wri->tocore.tocore_flags |= too_small; #else wri->tocore.tocore_flags |= prohibited; @@ -2878,7 +2878,7 @@ tty_ctrl_nhwindow( maxslot = (maxrow - 2) * (!inuse_only ? 2 : 1); wri->tocore.maxslot = maxslot; } - } + } #endif /* TTY_PERM_INVENT */ break; case set_menu_promptstyle: @@ -3396,7 +3396,7 @@ ttyinv_populate_slot( if (cell->color != color + 1) { /* offset color by 1 so 0 is not valid */ if (ccnt >= (col + clroffset)) - cell->color = color + 1; + cell->color = color + 1; else cell->color = NO_COLOR + 1; cell->refresh = 1; @@ -3546,10 +3546,10 @@ assesstty( if (!ttyDisplay) { /* too early */ - *offx = *offy = *rows = *cols = 0; + *offx = *offy = *rows = *cols = 0; *maxcol = 0; - *minrow = *maxrow = 0; - return !(*rows < perminv_minrow || *cols < tty_perminv_mincol); + *minrow = *maxrow = 0; + return !(*rows < perminv_minrow || *cols < tty_perminv_mincol); } *offx = 0; @@ -3864,9 +3864,9 @@ tty_print_glyph( #ifndef NO_TERMS if (ul_hack && ch == '_') { /* non-destructive underscore */ - (void) putchar((char) ' '); - backsp(); - } + (void) putchar((char) ' '); + backsp(); + } #endif if (iflags.use_color) { ttyDisplay->colorflags = NH_BASIC_COLOR; From be5143bb743bf4e6be26bfd92e0a1880665e4cca Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 4 Jan 2025 23:38:34 -0500 Subject: [PATCH 291/791] window-port updates Remove start_screen() and end_screen() from the Window-port interface. They were only ever used by tty, and there was a comment carried to several window-ports about how they "really should go away. They are tty-specific" term_start_screen() and term_end_screen() are part of terminal/NO_TERMS supporting routines now. --- doc/window.txt | 8 -------- include/winX.h | 4 ---- include/wincurs.h | 2 -- include/winprocs.h | 14 -------------- include/wintty.h | 7 +++---- outdated/include/trampoli.h | 4 ++-- outdated/include/wingem.h | 4 ---- outdated/sys/mac/macwin.c | 3 --- outdated/sys/mac/mttymain.c | 4 ++-- outdated/sys/msdos/SCHEMA35.MSC | 6 +++--- outdated/sys/msdos/schema3.MSC | 6 +++--- outdated/sys/wince/mswproc.c | 28 +--------------------------- outdated/sys/wince/winMS.h | 2 -- outdated/win/Qt3/qt3_win.cpp | 13 ------------- outdated/win/Qt3/qt3_win.h | 2 -- outdated/win/gem/wingem.c | 13 +------------ outdated/win/gnome/gnbind.c | 26 +------------------------- outdated/win/gnome/gnbind.h | 2 -- src/symbols.c | 8 ++++---- src/windows.c | 2 -- sys/msdos/pcvideo.h | 4 ++-- sys/msdos/video.c | 8 ++++---- sys/msdos/vidvesa.c | 2 +- sys/msdos/vidvga.c | 2 +- sys/share/pctty.c | 6 +++--- sys/share/unixtty.c | 14 +++++++++++--- sys/vms/vmstty.c | 4 ++-- sys/windows/consoletty.c | 8 ++++---- sys/windows/windsys.c | 4 +++- win/Qt/qt_bind.cpp | 12 ------------ win/Qt/qt_bind.h | 2 -- win/X11/winX.c | 16 ---------------- win/chain/wc_chainin.c | 18 ------------------ win/chain/wc_chainout.c | 22 ---------------------- win/chain/wc_trace.c | 30 ------------------------------ win/curses/cursmain.c | 23 ----------------------- win/share/safeproc.c | 14 +------------- win/shim/winshim.c | 5 +---- win/tty/termcap.c | 4 ++-- win/tty/wintty.c | 7 +++---- win/win32/mswproc.c | 28 +--------------------------- win/win32/winMS.h | 2 -- 42 files changed, 59 insertions(+), 334 deletions(-) diff --git a/doc/window.txt b/doc/window.txt index 0bad7062c..45593eb88 100644 --- a/doc/window.txt +++ b/doc/window.txt @@ -649,14 +649,6 @@ can_suspend() -- Tell the core if the window system will allow the game to be suspended now. If unconditionally yes or no, use genl_can_suspend_yes() or genl_can_suspend_no(). -start_screen() -- Only used on Unix tty ports, but must be declared for - completeness. Sets up the tty to work in full-screen - graphics mode. Look at win/tty/termcap.c for an - example. If your window-port does not need this function - just declare an empty function. -end_screen() -- Only used on Unix tty ports, but must be declared for - completeness. The complement of start_screen(). - outrip(winid, int, time_t) -- The tombstone code. If you want the traditional code use genl_outrip for the value and check the #if in rip.c. diff --git a/include/winX.h b/include/winX.h index b43e442ac..3da329d7d 100644 --- a/include/winX.h +++ b/include/winX.h @@ -489,10 +489,6 @@ extern void X11_status_enablefield(int, const char *, const char *, boolean); extern void X11_status_update(int, genericptr_t, int, int, int, unsigned long *); -/* other defs that really should go away (they're tty specific) */ -extern void X11_start_screen(void); -extern void X11_end_screen(void); - #ifdef GRAPHIC_TOMBSTONE extern void X11_outrip(winid, int, time_t); #else diff --git a/include/wincurs.h b/include/wincurs.h index 98ac5ae9e..4c5b7f19c 100644 --- a/include/wincurs.h +++ b/include/wincurs.h @@ -108,8 +108,6 @@ extern void curses_getlin(const char *question, char *input); extern int curses_get_ext_cmd(void); extern void curses_number_pad(int state); extern void curses_delay_output(void); -extern void curses_start_screen(void); -extern void curses_end_screen(void); extern void curses_outrip(winid wid, int how, time_t when); extern void genl_outrip(winid tmpwin, int how, time_t when); extern void curses_preference_update(const char *pref); diff --git a/include/winprocs.h b/include/winprocs.h index 8fc078e6c..5e0bc675f 100644 --- a/include/winprocs.h +++ b/include/winprocs.h @@ -80,10 +80,6 @@ struct window_procs { char *(*win_get_color_string)(void); #endif - /* other defs that really should go away (they're tty specific) */ - void (*win_start_screen)(void); - void (*win_end_screen)(void); - void (*win_outrip)(winid, int, time_t); void (*win_preference_update)(const char *); char *(*win_getmsghistory)(boolean); @@ -177,10 +173,6 @@ extern */ /* #define yn_function (*windowprocs.win_yn_function) */ -/* other defs that really should go away (they're tty specific) */ -#define start_screen (*windowprocs.win_start_screen) -#define end_screen (*windowprocs.win_end_screen) - #define outrip (*windowprocs.win_outrip) #define preference_update (*windowprocs.win_preference_update) #define getmsghistory (*windowprocs.win_getmsghistory) @@ -404,10 +396,6 @@ struct chain_procs { char *(*win_get_color_string)(CARGS); #endif - /* other defs that really should go away (they're tty specific) */ - void (*win_start_screen)(CARGS); - void (*win_end_screen)(CARGS); - void (*win_outrip)(CARGS, winid, int, time_t); void (*win_preference_update)(CARGS, const char *); char *(*win_getmsghistory)(CARGS, boolean); @@ -481,8 +469,6 @@ extern short safe_set_font_name(winid, char *); #endif extern char *safe_get_color_string(void); #endif -extern void safe_start_screen(void); -extern void safe_end_screen(void); extern void safe_outrip(winid, int, time_t); extern void safe_preference_update(const char *); extern char *safe_getmsghistory(boolean); diff --git a/include/wintty.h b/include/wintty.h index 97d439a89..c98db6958 100644 --- a/include/wintty.h +++ b/include/wintty.h @@ -184,13 +184,16 @@ extern void term_end_attr(int attr); extern void term_end_color(void); extern void term_end_extracolor(void); extern void term_end_raw_bold(void); +extern void term_end_screen(void); extern void term_start_attr(int attr); extern void term_start_bgcolor(int color); extern void term_start_color(int color); extern void term_start_extracolor(uint32, uint16); extern void term_start_raw_bold(void); +extern void term_start_screen(void); extern void term_startup(int *, int *); extern void term_shutdown(void); + extern int xputc(int); extern void xputs(const char *); #if 0 @@ -287,10 +290,6 @@ extern void tty_status_init(void); extern void tty_status_update(int, genericptr_t, int, int, int, unsigned long *); -/* other defs that really should go away (they're tty specific) */ -extern void tty_start_screen(void); -extern void tty_end_screen(void); - extern void genl_outrip(winid, int, time_t); extern char *tty_getmsghistory(boolean); diff --git a/outdated/include/trampoli.h b/outdated/include/trampoli.h index 344dacc93..f45d3bb98 100644 --- a/outdated/include/trampoli.h +++ b/outdated/include/trampoli.h @@ -241,8 +241,8 @@ #define tty_nhbell() tty_nhbell_() #define tty_number_pad(x) tty_number_pad_(x) #define tty_delay_output() tty_delay_output_() -#define tty_start_screen() tty_start_screen_() -#define tty_end_screen() tty_end_screen_() +#define term_start_screen() term_start_screen_() +#define term_end_screen() term_end_screen_() /* ### topl.c ### */ #define tty_doprev_message() tty_doprev_message_() diff --git a/outdated/include/wingem.h b/outdated/include/wingem.h index 86b3f6ba3..c7a935ef2 100644 --- a/outdated/include/wingem.h +++ b/outdated/include/wingem.h @@ -101,10 +101,6 @@ extern void Gem_change_color(int color, long rgb, int reverse); extern char *Gem_get_color_string(void); #endif -/* other defs that really should go away (they're tty specific) */ -extern void Gem_start_screen(void); -extern void Gem_end_screen(void); - extern void genl_outrip(winid, int, time_t); diff --git a/outdated/sys/mac/macwin.c b/outdated/sys/mac/macwin.c index 1da056a89..517b7f5a6 100644 --- a/outdated/sys/mac/macwin.c +++ b/outdated/sys/mac/macwin.c @@ -3275,9 +3275,6 @@ struct window_procs mac_procs = { tty_change_color, tty_change_background, set_tty_font_name, tty_get_color_string, #endif - /* other defs that really should go away (they're tty specific) */ - 0, // mac_start_screen, - 0, // mac_end_screen, genl_outrip, genl_preference_update, genl_can_suspend_no, }; diff --git a/outdated/sys/mac/mttymain.c b/outdated/sys/mac/mttymain.c index 1d1460df8..0020dccd1 100644 --- a/outdated/sys/mac/mttymain.c +++ b/outdated/sys/mac/mttymain.c @@ -581,13 +581,13 @@ tty_number_pad(int arg) } void -tty_start_screen(void) +term_start_screen(void) { iflags.cbreak = 1; } void -tty_end_screen(void) +term_end_screen(void) { } diff --git a/outdated/sys/msdos/SCHEMA35.MSC b/outdated/sys/msdos/SCHEMA35.MSC index 5d9392e69..400dc2f1a 100644 --- a/outdated/sys/msdos/SCHEMA35.MSC +++ b/outdated/sys/msdos/SCHEMA35.MSC @@ -254,10 +254,10 @@ functions:230 _thrwmu _tileview _timed_occupation _timer_is_local _timer_sanity_ functions:231 _topl_putsym _topologize _topten _topten_print _topten_print_bold _toss_up _toss_wsegs _touch_artifact functions:232 _touchfood _trap_detect _trickery _try_disarm _try_lift _trycall _tt_oname _tty_add_menu functions:233 _tty_askname _tty_clear_nhwindow _tty_cliparound -functions:234 _tty_display_file _tty_display_nhwindow _tty_doprev_message _tty_end_menu _tty_end_screen _tty_exit_nhwindows _tty_get_ext_cmd _tty_get_nh_event +functions:234 _tty_display_file _tty_display_nhwindow _tty_doprev_message _tty_end_menu _term_end_screen _tty_exit_nhwindows _tty_get_ext_cmd _tty_get_nh_event functions:235 _tty_getlin _tty_init_nhwindows _tty_mark_synch _tty_message_menu _tty_nh_poskey _tty_nhbell _tty_nhgetch _tty_number_pad functions:236 _tty_player_selection _tty_raw_print _tty_raw_print_bold _tty_resume_nhwindows _tty_select_menu -functions:237 _tty_start_menu _tty_start_screen _tty_startup _tty_suspend_nhwindows _tty_update_inventory _tty_yn_function +functions:237 _tty_start_menu _term_start_screen _tty_startup _tty_suspend_nhwindows _tty_update_inventory _tty_yn_function functions:238 _txt_backsp _txt_cl_end _txt_cl_eos _txt_clear_screen _txt_get_scr_size _txt_monoadapt_check functions:239 _txt_nhbell _txt_startup _u_entered_shop _u_gname _u_init functions:240 _u_left_shop _u_on_dnstairs _u_on_newpos _u_on_sstairs _u_on_upstairs _u_slip_free _u_slow_down _u_teleport_mon @@ -272,7 +272,7 @@ functions:248 _use_unicorn_horn _use_whip _use_whistle _useup _useupall _useupf functions:249 _uwepgone _vault_occupied _vault_tele _verbalize _vga_backsp _vga_cl_end _vga_cl_eos _vga_clear_screen functions:250 _vga_cliparound _vga_detect _vga_DisplayCell _vga_DisplayCell_O _vga_DrawCursor _vga_Finish _vga_FontPtrs _vga_get_scr_size functions:251 _vga_gotoloc _vga_HideCursor _vga_Init _vga_overview _vga_redrawmap _vga_refresh _vga_SetPalette _vga_SwitchMode -functions:252 _vga_traditional _vga_tty_end_screen _vga_tty_startup _vga_update_positionbar _vga_userpan _vga_WriteChar _vga_WriteStr _vga_xputc +functions:252 _vga_traditional _vga_term_end_screen _vga_term_startup _vga_update_positionbar _vga_userpan _vga_WriteChar _vga_WriteStr _vga_xputc functions:254 _vision_reset _dodiscovered _dodoor _dodown _dodrink _dodrop _doeat _doengrave functions:255 _wallification _wallify_map _wallify_vault _wantdoor _watch_on_duty _water_damage _water_friction functions:256 _water_prayer _weapon_dam_bonus _weapon_hit_bonus _weapon_type _wearing_armor _weffects _weight diff --git a/outdated/sys/msdos/schema3.MSC b/outdated/sys/msdos/schema3.MSC index ab9353f67..1e8670872 100644 --- a/outdated/sys/msdos/schema3.MSC +++ b/outdated/sys/msdos/schema3.MSC @@ -254,10 +254,10 @@ functions:230 _thrwmu _tileview _timed_occupation _timer_is_local _timer_sanity_ functions:231 _topl_putsym _topologize _topten _topten_print _topten_print_bold _toss_up _toss_wsegs _touch_artifact functions:232 _touchfood _trap_detect _trickery _try_disarm _try_lift _trycall _tt_oname _tty_add_menu functions:233 _tty_askname _tty_clear_nhwindow _tty_cliparound -functions:234 _tty_display_file _tty_display_nhwindow _tty_doprev_message _tty_end_menu _tty_end_screen _tty_exit_nhwindows _tty_get_ext_cmd _tty_get_nh_event +functions:234 _tty_display_file _tty_display_nhwindow _tty_doprev_message _tty_end_menu _term_end_screen _tty_exit_nhwindows _tty_get_ext_cmd _tty_get_nh_event functions:235 _tty_getlin _tty_init_nhwindows _tty_mark_synch _tty_message_menu _tty_nh_poskey _tty_nhbell _tty_nhgetch _tty_number_pad functions:236 _tty_player_selection _tty_raw_print _tty_raw_print_bold _tty_resume_nhwindows _tty_select_menu -functions:237 _tty_start_menu _tty_start_screen _tty_startup _tty_suspend_nhwindows _tty_update_inventory _tty_yn_function +functions:237 _tty_start_menu _term_start_screen _term_startup _tty_suspend_nhwindows _tty_update_inventory _tty_yn_function functions:238 _txt_backsp _txt_cl_end _txt_cl_eos _txt_clear_screen _txt_get_scr_size _txt_monoadapt_check functions:239 _txt_nhbell _txt_startup _u_entered_shop _u_gname _u_init functions:240 _u_left_shop _u_on_dnstairs _u_on_newpos _u_on_sstairs _u_on_upstairs _u_slip_free _u_slow_down _u_teleport_mon @@ -272,7 +272,7 @@ functions:248 _use_unicorn_horn _use_whip _use_whistle _useup _useupall _useupf functions:249 _uwepgone _vault_occupied _vault_tele _verbalize _vga_backsp _vga_cl_end _vga_cl_eos _vga_clear_screen functions:250 _vga_cliparound _vga_detect _vga_DisplayCell _vga_DisplayCell_O _vga_DrawCursor _vga_Finish _vga_FontPtrs _vga_get_scr_size functions:251 _vga_gotoloc _vga_HideCursor _vga_Init _vga_overview _vga_redrawmap _vga_refresh _vga_SetPalette _vga_SwitchMode -functions:252 _vga_traditional _vga_tty_end_screen _vga_tty_startup _vga_update_positionbar _vga_userpan _vga_WriteChar _vga_WriteStr _vga_xputc +functions:252 _vga_traditional _vga_term_end_screen _vga_term_startup _vga_update_positionbar _vga_userpan _vga_WriteChar _vga_WriteStr _vga_xputc functions:254 _vision_reset _dodiscovered _dodoor _dodown _dodrink _dodrop _doeat _doengrave functions:255 _wallification _wallify_map _wallify_vault _wantdoor _watch_on_duty _water_damage _water_friction functions:256 _water_prayer _weapon_dam_bonus _weapon_hit_bonus _weapon_type _wearing_armor _weffects _weight diff --git a/outdated/sys/wince/mswproc.c b/outdated/sys/wince/mswproc.c index e84dab8e1..8011991bc 100644 --- a/outdated/sys/wince/mswproc.c +++ b/outdated/sys/wince/mswproc.c @@ -71,8 +71,7 @@ struct window_procs mswin_procs = { #ifdef CHANGE_COLOR /* only a Mac option currently */ mswin, mswin_change_background, #endif - /* other defs that really should go away (they're tty specific) */ - mswin_start_screen, mswin_end_screen, mswin_outrip, + mswin_outrip, mswin_preference_update, genl_getmsghistory, genl_putmsghistory, genl_status_init, genl_status_finish, genl_status_enablefield, genl_status_update, @@ -1537,31 +1536,6 @@ mswin_get_color_string() return (""); } -/* -start_screen() -- Only used on Unix tty ports, but must be declared for - completeness. Sets up the tty to work in full-screen - graphics mode. Look at win/tty/termcap.c for an - example. If your window-port does not need this function - just declare an empty function. -*/ -void -mswin_start_screen() -{ - /* Do Nothing */ - logDebug("mswin_start_screen()\n"); -} - -/* -end_screen() -- Only used on Unix tty ports, but must be declared for - completeness. The complement of start_screen(). -*/ -void -mswin_end_screen() -{ - /* Do Nothing */ - logDebug("mswin_end_screen()\n"); -} - /* outrip(winid, int, when) -- The tombstone code. If you want the traditional code use diff --git a/outdated/sys/wince/winMS.h b/outdated/sys/wince/winMS.h index 3ee5622df..0ff0dd916 100644 --- a/outdated/sys/wince/winMS.h +++ b/outdated/sys/wince/winMS.h @@ -152,8 +152,6 @@ void mswin_number_pad(int state); void mswin_delay_output(void); void mswin_change_color(void); char *mswin_get_color_string(void); -void mswin_start_screen(void); -void mswin_end_screen(void); void mswin_outrip(winid wid, int how, time_t when); void mswin_preference_update(const char *pref); diff --git a/outdated/win/Qt3/qt3_win.cpp b/outdated/win/Qt3/qt3_win.cpp index 483761cfd..26e46c4bb 100644 --- a/outdated/win/Qt3/qt3_win.cpp +++ b/outdated/win/Qt3/qt3_win.cpp @@ -5152,16 +5152,6 @@ void NetHackQtBind::qt_delay_output() delay.wait(); } -void NetHackQtBind::qt_start_screen() -{ - // Ignore. -} - -void NetHackQtBind::qt_end_screen() -{ - // Ignore. -} - void NetHackQtBind::qt_outrip(winid wid, int how, time_t when) { NetHackQtWindow* window=id_to_window[wid]; @@ -5285,9 +5275,6 @@ struct window_procs Qt_procs = { donull, donull, #endif - /* other defs that really should go away (they're tty specific) */ - NetHackQtBind::qt_start_screen, - NetHackQtBind::qt_end_screen, #ifdef GRAPHIC_TOMBSTONE NetHackQtBind::qt_outrip, #else diff --git a/outdated/win/Qt3/qt3_win.h b/outdated/win/Qt3/qt3_win.h index 522f57d69..c5548e37c 100644 --- a/outdated/win/Qt3/qt3_win.h +++ b/outdated/win/Qt3/qt3_win.h @@ -877,8 +877,6 @@ class NetHackQtBind : NetHackQtBindBase static int qt_get_ext_cmd(); static void qt_number_pad(int); static void qt_delay_output(); - static void qt_start_screen(); - static void qt_end_screen(); static void qt_outrip(winid wid, int how, time_t when); static int qt_kbhit(); diff --git a/outdated/win/gem/wingem.c b/outdated/win/gem/wingem.c index df8d1d81c..15024f853 100644 --- a/outdated/win/gem/wingem.c +++ b/outdated/win/gem/wingem.c @@ -69,8 +69,7 @@ struct window_procs Gem_procs = { Gem_get_color_string, #endif - /* other defs that really should go away (they're tty specific) */ - Gem_start_screen, Gem_end_screen, Gem_outrip, Gem_preference_update, + Gem_outrip, Gem_preference_update, genl_getmsghistory, genl_putmsghistory genl_status_init, genl_status_finish, genl_status_enablefield, genl_status_update, @@ -523,16 +522,6 @@ Gem_resume_nhwindows() { } -void -Gem_end_screen() -{ -} - -void -Gem_start_screen() -{ -} - extern void mar_exit_nhwindows(void); extern boolean run_from_desktop; diff --git a/outdated/win/gnome/gnbind.c b/outdated/win/gnome/gnbind.c index 6fb043e21..a298af5a0 100644 --- a/outdated/win/gnome/gnbind.c +++ b/outdated/win/gnome/gnbind.c @@ -44,8 +44,7 @@ struct window_procs Gnome_procs = { #ifdef CHANGE_COLOR /* only a Mac option currently */ donull, donull, #endif - /* other defs that really should go away (they're tty specific) */ - gnome_start_screen, gnome_end_screen, gnome_outrip, + gnome_outrip, genl_preference_update, genl_getmsghistory, genl_putmsghistory, genl_status_init, genl_status_finish, genl_status_enablefield, genl_status_update, @@ -1132,29 +1131,6 @@ gnome_delay_output() } } -/* -start_screen() -- Only used on Unix tty ports, but must be declared for - completeness. Sets up the tty to work in full-screen - graphics mode. Look at win/tty/termcap.c for an - example. If your window-port does not need this function - just declare an empty function. -*/ -void -gnome_start_screen() -{ - /* Do Nothing */ -} - -/* -end_screen() -- Only used on Unix tty ports, but must be declared for - completeness. The complement of start_screen(). -*/ -void -gnome_end_screen() -{ - /* Do Nothing */ -} - /* outrip(winid, int, when) -- The tombstone code. If you want the traditional code use diff --git a/outdated/win/gnome/gnbind.h b/outdated/win/gnome/gnbind.h index b0f56e035..e39a56380 100644 --- a/outdated/win/gnome/gnbind.h +++ b/outdated/win/gnome/gnbind.h @@ -80,8 +80,6 @@ void gnome_getlin(const char *question, char *input); int gnome_get_ext_cmd(void); void gnome_number_pad(int state); void gnome_delay_output(void); -void gnome_start_screen(void); -void gnome_end_screen(void); void gnome_outrip(winid wid, int how, time_t when); void gnome_delete_nhwindow_by_reference(GtkWidget *menuWin); diff --git a/src/symbols.c b/src/symbols.c index d9de7b8db..ff352d214 100644 --- a/src/symbols.c +++ b/src/symbols.c @@ -11,12 +11,12 @@ staticfn struct _savedsym *savedsym_find(const char *, int); extern const uchar def_r_oc_syms[MAXOCLASSES]; /* drawing.c */ #if defined(TERMLIB) || defined(CURSES_GRAPHICS) -void (*decgraphics_mode_callback)(void) = 0; /* set in tty_start_screen() */ +void (*decgraphics_mode_callback)(void) = 0; /* set in term_start_screen() */ #endif /* TERMLIB || CURSES */ #ifdef PC9800 -void (*ibmgraphics_mode_callback)(void) = 0; /* set in tty_start_screen() */ -void (*ascgraphics_mode_callback)(void) = 0; /* set in tty_start_screen() */ +void (*ibmgraphics_mode_callback)(void) = 0; /* set in term_start_screen() */ +void (*ascgraphics_mode_callback)(void) = 0; /* set in term_start_screen() */ #endif #ifdef CURSES_GRAPHICS void (*cursesgraphics_mode_callback)(void) = 0; @@ -25,7 +25,7 @@ void (*cursesgraphics_mode_callback)(void) = 0; void (*ibmgraphics_mode_callback)(void) = 0; #endif #ifdef ENHANCED_SYMBOLS -void (*utf8graphics_mode_callback)(void) = 0; /* set in tty_start_screen and +void (*utf8graphics_mode_callback)(void) = 0; /* set in term_start_screen and * found in unixtty,windtty,&c */ #endif diff --git a/src/windows.c b/src/windows.c index d763f7eaf..a5924b2ae 100644 --- a/src/windows.c +++ b/src/windows.c @@ -598,8 +598,6 @@ static struct window_procs hup_procs = { #endif hup_get_color_string, #endif /* CHANGE_COLOR */ - hup_void_ndecl, /* start_screen */ - hup_void_ndecl, /* end_screen */ hup_outrip, genl_preference_update, genl_getmsghistory, genl_putmsghistory, hup_void_ndecl, /* status_init */ diff --git a/sys/msdos/pcvideo.h b/sys/msdos/pcvideo.h index 7aeb453d1..1d889a8b2 100644 --- a/sys/msdos/pcvideo.h +++ b/sys/msdos/pcvideo.h @@ -277,7 +277,7 @@ extern void vga_update_positionbar(char *); extern void vga_HideCursor(void); #endif extern void vga_Init(void); -extern void vga_tty_end_screen(void); +extern void vga_term_end_screen(void); extern void vga_term_startup(int *, int *); extern void vga_xputs(const char *, int, int); extern void vga_xputc(char, int); @@ -308,7 +308,7 @@ extern void vesa_update_positionbar(char *); extern void vesa_HideCursor(void); #endif extern void vesa_Init(void); -extern void vesa_tty_end_screen(void); +extern void vesa_term_end_screen(void); extern void vesa_term_startup(int *, int *); extern void vesa_xputs(const char *, int, int); extern void vesa_xputc(char, int); diff --git a/sys/msdos/video.c b/sys/msdos/video.c index a6b5bfe59..916a3518d 100644 --- a/sys/msdos/video.c +++ b/sys/msdos/video.c @@ -471,7 +471,7 @@ tty_delay_output(void) } void -tty_end_screen(void) +term_end_screen(void) { if (!iflags.grmode) { txt_clear_screen(); @@ -480,11 +480,11 @@ tty_end_screen(void) #endif #ifdef SCREEN_VGA } else if (iflags.usevga) { - vga_tty_end_screen(); + vga_term_end_screen(); #endif #ifdef SCREEN_VESA } else if (iflags.usevesa) { - vesa_tty_end_screen(); + vesa_term_end_screen(); #endif } } @@ -546,7 +546,7 @@ term_startup(int *wid, int *hgt) } void -tty_start_screen(void) +term_start_screen(void) { #ifdef PC9800 fputs("\033[>1h", stdout); diff --git a/sys/msdos/vidvesa.c b/sys/msdos/vidvesa.c index 4cc594bcf..8a3423bc0 100644 --- a/sys/msdos/vidvesa.c +++ b/sys/msdos/vidvesa.c @@ -596,7 +596,7 @@ vesa_cl_eos(int cy) } void -vesa_tty_end_screen(void) +vesa_term_end_screen(void) { vesa_clear_screen(BACKGROUND_VESA_COLOR); vesa_SwitchMode(MODETEXT); diff --git a/sys/msdos/vidvga.c b/sys/msdos/vidvga.c index 02b9f444f..140b816a5 100644 --- a/sys/msdos/vidvga.c +++ b/sys/msdos/vidvga.c @@ -290,7 +290,7 @@ void vga_cl_eos(int cy) } void -vga_tty_end_screen(void) +vga_term_end_screen(void) { vga_clear_screen(BACKGROUND_VGA_COLOR); vga_SwitchMode(MODETEXT); diff --git a/sys/share/pctty.c b/sys/share/pctty.c index 6b718d66a..fee616980 100644 --- a/sys/share/pctty.c +++ b/sys/share/pctty.c @@ -38,7 +38,7 @@ settty(const char *s) #if defined(MSDOS) && defined(NO_TERMS) gr_finish(); #endif - end_screen(); + term_end_screen(); if (s) raw_print(s); #if !defined(TOS) @@ -50,7 +50,7 @@ settty(const char *s) void setftty(void) { - start_screen(); + term_start_screen(); } #if defined(TIMED_DELAY) && defined(_MSC_VER) @@ -77,7 +77,7 @@ VA_DECL(const char *, s) VA_INIT(s, const char *); /* error() may get called before tty is initialized */ if (iflags.window_inited) - end_screen(); + term_end_screen(); putchar('\n'); Vprintf(s, VA_ARGS); putchar('\n'); diff --git a/sys/share/unixtty.c b/sys/share/unixtty.c index 44fbadc6a..c5f849e5c 100644 --- a/sys/share/unixtty.c +++ b/sys/share/unixtty.c @@ -11,6 +11,7 @@ #define NEED_VARARGS #include "hack.h" +#include "wintty.h" /* * The distinctions here are not BSD - rest but rather USG - rest, as @@ -229,7 +230,10 @@ gettty(void) void settty(const char *s) { - end_screen(); +#ifdef TTY_GRAPHICS + if (WINDOWPORT(tty)) + term_end_screen(); +#endif if (s) raw_print(s); if (STTY(&inittyb) < 0 || STTY2(&inittyb2) < 0) @@ -306,7 +310,11 @@ setftty(void) if (change) setctty(); - start_screen(); + +#ifdef TTY_GRAPHICS + if (WINDOWPORT(tty)) + term_start_screen(); +#endif } void intron(void) /* enable kbd interrupts if enabled when game started */ @@ -480,7 +488,7 @@ RESTORE_WARNING_FORMAT_NONLITERAL #ifdef ENHANCED_SYMBOLS /* - * set in tty_start_screen() and allows + * set in term_start_screen() and allows * OS-specific changes that may be * required for support of utf8. */ diff --git a/sys/vms/vmstty.c b/sys/vms/vmstty.c index 9bd26a9a5..b6dd2013e 100644 --- a/sys/vms/vmstty.c +++ b/sys/vms/vmstty.c @@ -513,7 +513,7 @@ setftty(void) sg.sm.tt2_char = tt2_char_active; setctty(); - start_screen(); + term_start_screen(); settty_needed = TRUE; } @@ -601,7 +601,7 @@ getwindowsz(void) #ifdef ENHANCED_SYMBOLS /* - * set in tty_start_screen() and allows + * set in term_start_screen() and allows * OS-specific changes that may be * required for support of utf8. * Currently a placeholder for VMS. diff --git a/sys/windows/consoletty.c b/sys/windows/consoletty.c index c89e2c8ed..b7fb0cf50 100644 --- a/sys/windows/consoletty.c +++ b/sys/windows/consoletty.c @@ -1052,7 +1052,7 @@ void settty(const char *s) { cmov(ttyDisplay->curx, ttyDisplay->cury); - end_screen(); + term_end_screen(); if (s) raw_print(s); restore_original_console_font(); @@ -1075,7 +1075,7 @@ settty(const char *s) void setftty(void) { - start_screen(); + term_start_screen(); } void @@ -1113,7 +1113,7 @@ graph_off(void) #endif void -tty_end_screen(void) +term_end_screen(void) { term_clear_screen(); really_move_cursor(); @@ -1123,7 +1123,7 @@ tty_end_screen(void) } void -tty_start_screen(void) +term_start_screen(void) { if (iflags.num_pad) tty_number_pad(1); /* make keypad send digits */ diff --git a/sys/windows/windsys.c b/sys/windows/windsys.c index 05b073a45..24dd6ed60 100644 --- a/sys/windows/windsys.c +++ b/sys/windows/windsys.c @@ -231,8 +231,10 @@ VA_DECL(const char *, s) VA_START(s); VA_INIT(s, const char *); /* error() may get called before tty is initialized */ +#ifdef TTY_GRAPHICS if (iflags.window_inited) - end_screen(); + term_end_screen(); +#endif if (WINDOWPORT(tty)) { buf[0] = '\n'; (void) vsnprintf(&buf[1], sizeof buf - (1 + sizeof "\n"), s, VA_ARGS); diff --git a/win/Qt/qt_bind.cpp b/win/Qt/qt_bind.cpp index e6546447c..91dcf65fc 100644 --- a/win/Qt/qt_bind.cpp +++ b/win/Qt/qt_bind.cpp @@ -966,16 +966,6 @@ NetHackQtBind::qt_get_color_string(void) #endif -void NetHackQtBind::qt_start_screen() -{ - // Ignore. -} - -void NetHackQtBind::qt_end_screen() -{ - // Ignore. -} - void NetHackQtBind::qt_outrip(winid wid, int how, time_t when) { NetHackQtWindow* window=id_to_window[(int)wid]; @@ -1232,8 +1222,6 @@ struct window_procs Qt_procs = { nethack_qt_::NetHackQtBind::qt_get_color_string, #endif /* other defs that really should go away (they're tty specific) */ - nethack_qt_::NetHackQtBind::qt_start_screen, - nethack_qt_::NetHackQtBind::qt_end_screen, #ifdef GRAPHIC_TOMBSTONE nethack_qt_::NetHackQtBind::qt_outrip, #else diff --git a/win/Qt/qt_bind.h b/win/Qt/qt_bind.h index 6535e637b..d0c71759c 100644 --- a/win/Qt/qt_bind.h +++ b/win/Qt/qt_bind.h @@ -85,8 +85,6 @@ public: static int qt_get_ext_cmd(); static void qt_number_pad(int); static void qt_delay_output(); - static void qt_start_screen(); - static void qt_end_screen(); static void qt_preference_update(const char *optname); static char *qt_getmsghistory(boolean init); diff --git a/win/X11/winX.c b/win/X11/winX.c index f808541d5..d9a7cacf4 100644 --- a/win/X11/winX.c +++ b/win/X11/winX.c @@ -146,8 +146,6 @@ struct window_procs X11_procs = { #ifdef CHANGE_COLOR /* only a Mac option currently */ donull, donull, #endif - /* other defs that really should go away (they're tty specific) */ - X11_start_screen, X11_end_screen, #ifdef GRAPHIC_TOMBSTONE X11_outrip, #else @@ -1396,20 +1394,6 @@ X11_number_pad(int state) /* called from options.c */ return; } -/* called from setftty() in unixtty.c */ -void -X11_start_screen(void) -{ - return; -} - -/* called from settty() in unixtty.c */ -void -X11_end_screen(void) -{ - return; -} - #ifdef GRAPHIC_TOMBSTONE void X11_outrip(winid window, int how, time_t when) diff --git a/win/chain/wc_chainin.c b/win/chain/wc_chainin.c index 6573fe826..ab63cf3c7 100644 --- a/win/chain/wc_chainin.c +++ b/win/chain/wc_chainin.c @@ -59,9 +59,6 @@ short chainin_set_font_name(winid, char *); char *chainin_get_color_string(void); #endif - /* other defs that really should go away (they're tty specific) */ -void chainin_start_screen(void); -void chainin_end_screen(void); void chainin_outrip(winid, int, time_t); void chainin_preference_update(const char *); char *chainin_getmsghistory(boolean); @@ -489,19 +486,6 @@ trace_get_color_string(void) #endif -/* other defs that really should go away (they're tty specific) */ -void -chainin_start_screen(void) -{ - (*cibase->nprocs->win_start_screen)(cibase->ndata); -} - -void -chainin_end_screen(void) -{ - (*cibase->nprocs->win_end_screen)(cibase->ndata); -} - void chainin_outrip( winid tmpwin, @@ -629,8 +613,6 @@ struct window_procs chainin_procs = { chainin_get_color_string, #endif - chainin_start_screen, chainin_end_screen, - chainin_outrip, chainin_preference_update, chainin_getmsghistory, chainin_putmsghistory, chainin_status_init, chainin_status_finish, chainin_status_enablefield, diff --git a/win/chain/wc_chainout.c b/win/chain/wc_chainout.c index a0198173c..72459b883 100644 --- a/win/chain/wc_chainout.c +++ b/win/chain/wc_chainout.c @@ -59,9 +59,6 @@ short chainout_set_font_name(void *,winid, char *); char *chainout_get_color_string(void *); #endif - /* other defs that really should go away (they're tty specific) */ -void chainout_start_screen(void *); -void chainout_end_screen(void *); void chainout_outrip(void *,winid, int, time_t); void chainout_preference_update(void *,const char *); char *chainout_getmsghistory(void *,boolean); @@ -582,23 +579,6 @@ trace_get_color_string(void *vp) #endif -/* other defs that really should go away (they're tty specific) */ -void -chainout_start_screen(void *vp) -{ - struct chainout_data *tdp = vp; - - (*tdp->nprocs->win_start_screen)(); -} - -void -chainout_end_screen(void *vp) -{ - struct chainout_data *tdp = vp; - - (*tdp->nprocs->win_end_screen)(); -} - void chainout_outrip( void *vp, @@ -755,8 +735,6 @@ struct chain_procs chainout_procs = { chainout_get_color_string, #endif - chainout_start_screen, chainout_end_screen, - chainout_outrip, chainout_preference_update, chainout_getmsghistory, chainout_putmsghistory, chainout_status_init, chainout_status_finish, chainout_status_enablefield, diff --git a/win/chain/wc_trace.c b/win/chain/wc_trace.c index 2048a05c4..7287e82a4 100644 --- a/win/chain/wc_trace.c +++ b/win/chain/wc_trace.c @@ -91,9 +91,6 @@ short trace_set_font_name(void *,winid, char *); char *trace_get_color_string(void *); #endif - /* other defs that really should go away (they're tty specific) */ -void trace_start_screen(void *); -void trace_end_screen(void *); void trace_outrip(void *,winid, int, time_t); void trace_preference_update(void *,const char *); char *trace_getmsghistory(void *,boolean); @@ -1011,31 +1008,6 @@ trace_get_color_string(void *vp) #endif -/* other defs that really should go away (they're tty specific) */ -void -trace_start_screen(void *vp) -{ - struct trace_data *tdp = vp; - - fprintf(wc_tracelogf, "%sstart_screen()\n", INDENT); - - PRE; - (*tdp->nprocs->win_start_screen)(tdp->ndata); - POST; -} - -void -trace_end_screen(void *vp) -{ - struct trace_data *tdp = vp; - - fprintf(wc_tracelogf, "%send_screen()\n", INDENT); - - PRE; - (*tdp->nprocs->win_end_screen)(tdp->ndata); - POST; -} - void trace_outrip( void *vp, @@ -1245,8 +1217,6 @@ struct chain_procs trace_procs = { trace_get_color_string, #endif - trace_start_screen, trace_end_screen, - trace_outrip, trace_preference_update, trace_getmsghistory, trace_putmsghistory, trace_status_init, trace_status_finish, trace_status_enablefield, diff --git a/win/curses/cursmain.c b/win/curses/cursmain.c index 5dee9900b..89491434e 100644 --- a/win/curses/cursmain.c +++ b/win/curses/cursmain.c @@ -126,8 +126,6 @@ struct window_procs curses_procs = { #endif curses_get_color_string, #endif - curses_start_screen, - curses_end_screen, genl_outrip, curses_preference_update, curses_getmsghistory, @@ -1207,27 +1205,6 @@ curses_delay_output(void) #endif } -/* -start_screen() -- Only used on Unix tty ports, but must be declared for - completeness. Sets up the tty to work in full-screen - graphics mode. Look at win/tty/termcap.c for an - example. If your window-port does not need this function - just declare an empty function. -*/ -void -curses_start_screen(void) -{ -} - -/* -end_screen() -- Only used on Unix tty ports, but must be declared for - completeness. The complement of start_screen(). -*/ -void -curses_end_screen(void) -{ -} - /* outrip(winid, int) -- The tombstone code. We use genl_outrip() from rip.c diff --git a/win/share/safeproc.c b/win/share/safeproc.c index efcb76097..19e9aa9b6 100644 --- a/win/share/safeproc.c +++ b/win/share/safeproc.c @@ -123,7 +123,7 @@ struct window_procs safe_procs = { #endif safe_get_color_string, #endif - safe_start_screen, safe_end_screen, safe_outrip, + safe_outrip, safe_preference_update, safe_getmsghistory, safe_putmsghistory, safe_status_init, @@ -440,18 +440,6 @@ safe_delay_output(void) return; } -void -safe_start_screen(void) -{ - return; -} - -void -safe_end_screen(void) -{ - return; -} - void safe_outrip(winid tmpwin UNUSED, int how UNUSED, time_t when UNUSED) { diff --git a/win/shim/winshim.c b/win/shim/winshim.c index dbc3ef5d7..ed09d0b27 100644 --- a/win/shim/winshim.c +++ b/win/shim/winshim.c @@ -159,8 +159,6 @@ DECLCB(short, set_shim_font_name,(winid window_type, char *font_name),"2is", A2P DECLCB(char *,shim_get_color_string,(void),"sv") /* other defs that really should go away (they're tty specific) */ -VDECLCB(shim_start_screen, (void), "v") -VDECLCB(shim_end_screen, (void), "v") VDECLCB(shim_preference_update, (const char *pref), "vp", P2V pref) DECLCB(char *,shim_getmsghistory, (boolean init), "sb", A2P init) VDECLCB(shim_putmsghistory, (const char *msg, boolean restoring_msghist), "vsb", P2V msg, A2P restoring_msghist) @@ -247,8 +245,7 @@ struct window_procs shim_procs = { shim_get_color_string, #endif - /* other defs that really should go away (they're tty specific) */ - shim_start_screen, shim_end_screen, genl_outrip, + genl_outrip, shim_preference_update, shim_getmsghistory, shim_putmsghistory, shim_status_init, diff --git a/win/tty/termcap.c b/win/tty/termcap.c index 66ed2b6a2..3af6333f9 100644 --- a/win/tty/termcap.c +++ b/win/tty/termcap.c @@ -505,7 +505,7 @@ tty_ascgraphics_hilite_fixup(void) #endif /* PC9800 */ void -tty_start_screen(void) +term_start_screen(void) { xputs(TI); xputs(VS); @@ -537,7 +537,7 @@ tty_start_screen(void) } void -tty_end_screen(void) +term_end_screen(void) { term_clear_screen(); xputs(VE); diff --git a/win/tty/wintty.c b/win/tty/wintty.c index ea9006af7..288653e5c 100644 --- a/win/tty/wintty.c +++ b/win/tty/wintty.c @@ -148,8 +148,7 @@ struct window_procs tty_procs = { tty_get_color_string, #endif - /* other defs that really should go away (they're tty specific) */ - tty_start_screen, tty_end_screen, genl_outrip, + genl_outrip, tty_preference_update, tty_getmsghistory, tty_putmsghistory, tty_status_init, @@ -530,7 +529,7 @@ tty_init_nhwindows(int *argcp UNUSED, char **argv UNUSED) /* to port dependant tty setup */ term_startup(&wid, &hgt); - setftty(); /* calls start_screen */ + setftty(); /* calls term_start_screen */ term_curs_set(0); /* set up tty descriptor */ @@ -793,7 +792,7 @@ void tty_resume_nhwindows(void) { gettty(); - setftty(); /* calls start_screen */ + setftty(); /* calls term_start_screen */ term_curs_set(0); docrt(); } diff --git a/win/win32/mswproc.c b/win/win32/mswproc.c index 1103233c2..8f5c4cc45 100644 --- a/win/win32/mswproc.c +++ b/win/win32/mswproc.c @@ -119,8 +119,7 @@ struct window_procs mswin_procs = { #ifdef CHANGE_COLOR /* only a Mac option currently */ mswin_change_color, mswin_get_color_string, #endif - /* other defs that really should go away (they're tty specific) */ - mswin_start_screen, mswin_end_screen, mswin_outrip, + mswin_outrip, mswin_preference_update, mswin_getmsghistory, mswin_putmsghistory, mswin_status_init, mswin_status_finish, mswin_status_enablefield, mswin_status_update, @@ -1924,31 +1923,6 @@ mswin_get_color_string(void) return (char *) ""; } -/* -start_screen() -- Only used on Unix tty ports, but must be declared for - completeness. Sets up the tty to work in full-screen - graphics mode. Look at win/tty/termcap.c for an - example. If your window-port does not need this function - just declare an empty function. -*/ -void -mswin_start_screen(void) -{ - /* Do Nothing */ - logDebug("mswin_start_screen()\n"); -} - -/* -end_screen() -- Only used on Unix tty ports, but must be declared for - completeness. The complement of start_screen(). -*/ -void -mswin_end_screen(void) -{ - /* Do Nothing */ - logDebug("mswin_end_screen()\n"); -} - /* outrip(winid, int, when) -- The tombstone code. If you want the traditional code use diff --git a/win/win32/winMS.h b/win/win32/winMS.h index 682fbc3ee..1de3db042 100644 --- a/win/win32/winMS.h +++ b/win/win32/winMS.h @@ -188,8 +188,6 @@ void mswin_number_pad(int state); void mswin_delay_output(void); void mswin_change_color(int color, long rgb, int reverse); char *mswin_get_color_string(void); -void mswin_start_screen(void); -void mswin_end_screen(void); void mswin_outrip(winid wid, int how, time_t when); void mswin_preference_update(const char *pref); char *mswin_getmsghistory(boolean init); From ffadd254d712668fa15a6cc34ffedc9bb5452584 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 4 Jan 2025 23:51:34 -0500 Subject: [PATCH 292/791] follow-up: missed comment and an outdated interface --- outdated/sys/amiga/winami.c | 6 ++---- win/Qt/qt_bind.cpp | 1 - win/shim/winshim.c | 1 - 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/outdated/sys/amiga/winami.c b/outdated/sys/amiga/winami.c index fc860d603..4b7866346 100644 --- a/outdated/sys/amiga/winami.c +++ b/outdated/sys/amiga/winami.c @@ -62,8 +62,7 @@ struct window_procs amii_procs = { #ifdef CHANGE_COLOR /* only a Mac option currently */ amii_change_color, amii_get_color_string, #endif - /* other defs that really should go away (they're tty specific) */ - amii_delay_output, amii_delay_output, amii_outrip, genl_preference_update, + amii_outrip, genl_preference_update, genl_getmsghistory, genl_putmsghistory, genl_status_init, genl_status_finish, genl_status_enablefield, genl_status_update, @@ -97,8 +96,7 @@ struct window_procs amiv_procs = { #ifdef CHANGE_COLOR /* only a Mac option currently */ amii_change_color, amii_get_color_string, #endif - /* other defs that really should go away (they're tty specific) */ - amii_delay_output, amii_delay_output, amii_outrip, genl_preference_update, + amii_outrip, genl_preference_update, genl_getmsghistory, genl_putmsghistory, genl_status_init, genl_status_finish, genl_status_enablefield, genl_status_update, diff --git a/win/Qt/qt_bind.cpp b/win/Qt/qt_bind.cpp index 91dcf65fc..75a3620c1 100644 --- a/win/Qt/qt_bind.cpp +++ b/win/Qt/qt_bind.cpp @@ -1221,7 +1221,6 @@ struct window_procs Qt_procs = { #endif nethack_qt_::NetHackQtBind::qt_get_color_string, #endif - /* other defs that really should go away (they're tty specific) */ #ifdef GRAPHIC_TOMBSTONE nethack_qt_::NetHackQtBind::qt_outrip, #else diff --git a/win/shim/winshim.c b/win/shim/winshim.c index ed09d0b27..81bc7411d 100644 --- a/win/shim/winshim.c +++ b/win/shim/winshim.c @@ -158,7 +158,6 @@ VDECLCB(shim_change_background,(int white_or_black), "vi", A2P white_or_black) DECLCB(short, set_shim_font_name,(winid window_type, char *font_name),"2is", A2P window_type, P2V font_name) DECLCB(char *,shim_get_color_string,(void),"sv") -/* other defs that really should go away (they're tty specific) */ VDECLCB(shim_preference_update, (const char *pref), "vp", P2V pref) DECLCB(char *,shim_getmsghistory, (boolean init), "sb", A2P init) VDECLCB(shim_putmsghistory, (const char *msg, boolean restoring_msghist), "vsb", P2V msg, A2P restoring_msghist) From a7152ad54e362b5c53d6ef17cf9fc71f0d2b2d0a Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 5 Jan 2025 05:42:24 -0500 Subject: [PATCH 293/791] CROSS_TO_WASM build fix A couple of option processing functions, one of which was called in file.c, were recently added to sys/unix/unixmain.c, but the wasm build does not include unixmain.c, it uses sys/libnh/libnhmain.c. Transcribe the functions into sys/libnh/libnhmain.c. Also, do not #include "wintty.h" for NOTTYGRAPHICS builds. --- sys/libnh/libnhmain.c | 27 +++++++++++++++++++++++++++ sys/share/unixtty.c | 2 ++ 2 files changed, 29 insertions(+) diff --git a/sys/libnh/libnhmain.c b/sys/libnh/libnhmain.c index 289ee2c5f..562de1c78 100644 --- a/sys/libnh/libnhmain.c +++ b/sys/libnh/libnhmain.c @@ -51,6 +51,7 @@ extern void init_linux_cons(void); static void wd_message(void); static struct passwd *get_unix_pw(void); +ATTRNORETURN static void opt_terminate(void) NORETURN; #ifdef __EMSCRIPTEN__ /* if WebAssembly, export this API and don't optimize it out */ @@ -768,6 +769,32 @@ sys_random_seed(void) return seed; } +/* for command-line options that perform some immediate action and then + terminate the program without starting play, like 'nethack --version' + or 'nethack -s Zelda'; do some cleanup before that termination */ +ATTRNORETURN static void +opt_terminate(void) +{ + config_error_done(); /* free memory allocated by config_error_init() */ + + nh_terminate(EXIT_SUCCESS); + /*NOTREACHED*/ +} + +/* show the sysconf file name, playground directory, run-time configuration + file name, dumplog file name if applicable, and some other things */ +ATTRNORETURN void +after_opt_showpaths(const char *dir) +{ +#ifdef CHDIR + chdirx(dir, FALSE); +#else + nhUse(dir); +#endif + opt_terminate(); + /*NOTREACHED*/ +} + #ifdef __EMSCRIPTEN__ /*** * Helpers diff --git a/sys/share/unixtty.c b/sys/share/unixtty.c index c5f849e5c..3dce02269 100644 --- a/sys/share/unixtty.c +++ b/sys/share/unixtty.c @@ -11,7 +11,9 @@ #define NEED_VARARGS #include "hack.h" +#if defined(TTY_GRAPHICS) && !defined(NOTTYGRAPHICS) #include "wintty.h" +#endif /* * The distinctions here are not BSD - rest but rather USG - rest, as From 57bf003c267aec76c6c87fa062ac371fc91b908a Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sun, 5 Jan 2025 13:35:18 +0200 Subject: [PATCH 294/791] Fix rolling boulder not unblocking sight at wall of water A rolling boulder that destroys a wall of water did not unblock the vision at that point. --- src/do.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/do.c b/src/do.c index 43376b529..1baddb56e 100644 --- a/src/do.c +++ b/src/do.c @@ -74,6 +74,7 @@ boulder_hits_pool( levl[rx][ry].drawbridgemask &= ~DB_UNDER; /* clear lava */ levl[rx][ry].drawbridgemask |= DB_FLOOR; } else { + unblock_point(rx, ry); levl[rx][ry].typ = ROOM, levl[rx][ry].flags = 0; } /* 3.7: normally DEADMONSTER() is used when traversing the fmon From b2c108b4166b3da14f8eeaa588ebbc74a6ac828e Mon Sep 17 00:00:00 2001 From: PatR Date: Sun, 5 Jan 2025 10:19:31 -0800 Subject: [PATCH 295/791] teleporting of engulfer Commit ba731a346b4dce48cddb5c69b58e52b516b84217 "fix shop steal when teleporting your engulfer" mentioned that there was no longer any message given if engulfer+hero got teleported. Add such. It is a bit lame but the situation is rare enough that it should suffice. --- src/teleport.c | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/src/teleport.c b/src/teleport.c index 3b3a483f1..fdebacffe 100644 --- a/src/teleport.c +++ b/src/teleport.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 teleport.c $NHDT-Date: 1685863331 2023/06/04 07:22:11 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.206 $ */ +/* NetHack 3.7 teleport.c $NHDT-Date: 1736129950 2025/01/05 18:19:10 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.235 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2011. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1653,14 +1653,16 @@ rloc_to_core( maybe_unhide_at(x, y); newsym(x, y); /* update new location */ set_apparxy(mtmp); /* orient monster */ - if (domsg && (canspotmon(mtmp) || appearmsg) && (u.ustuck != mtmp)) { + if (domsg && (canspotmon(mtmp) || appearmsg || mtmp == u.ustuck)) { int du = distu(x, y), olddu; const char *next = (du <= 2) ? " next to you" : 0, /* next2u() */ *nearu = (du <= BOLT_LIM * BOLT_LIM) ? " close by" : 0; set_msg_xy(x, y); mtmp->mstrategy &= ~STRAT_APPEARMSG; /* one chance only */ - if (telemsg && (couldsee(x, y) || sensemon(mtmp))) { + if (mtmp == u.ustuck && !u_at(u.ux0, u.uy0)) { + You("and %s teleport together.", mon_nam(mtmp)); + } else if (telemsg && (couldsee(x, y) || sensemon(mtmp))) { pline("%s vanishes and reappears%s.", Monnam(mtmp), next ? next @@ -1675,11 +1677,18 @@ rloc_to_core( !Blind ? "appears" : "arrives", next ? next : nearu ? nearu : ""); } + /* wand discovery only happens if a messaage is delivered (bug?); + if spell or q.mechanic attack or artifact #invoke for banish + then current_wand will be Null */ + if (gc.current_wand && gc.current_wand->otyp == WAN_TELEPORTATION) + makeknown(WAN_TELEPORTATION); } /* shopkeepers will only teleport if you zap them with a wand of teleportation or if they've been transformed into a jumpy monster; - the latter only happens if you've attacked them with polymorph */ + the latter only happens if you've attacked them with polymorph + [FIXME? or they've been hit by a genetic engineer, which won't + necessarily be due to Conflict by hero] */ if (resident_shk && !inhishop(mtmp)) make_angry_shk(mtmp, oldx, oldy); @@ -2200,7 +2209,9 @@ random_teleport_level(void) /* you teleport a monster (via wand, spell, or poly'd q.mechanic attack); return false iff the attempt fails */ boolean -u_teleport_mon(struct monst *mtmp, boolean give_feedback) +u_teleport_mon( + struct monst *mtmp, + boolean give_feedback) { coord cc; @@ -2215,10 +2226,12 @@ u_teleport_mon(struct monst *mtmp, boolean give_feedback) if (!rloc(mtmp, RLOC_MSG)) m_into_limbo(mtmp); } else if ((is_rider(mtmp->data) || control_teleport(mtmp->data)) - && rn2(13) && enexto(&cc, u.ux, u.uy, mtmp->data)) + && rn2(13) && enexto(&cc, u.ux, u.uy, mtmp->data)) { rloc_to(mtmp, cc.x, cc.y); - else - (void) rloc(mtmp, RLOC_MSG); + } else { + if (!rloc(mtmp, RLOC_MSG)) + return FALSE; + } return TRUE; } From 7cc118365c4e7807adcca1d6d6316ceb521d9eba Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 5 Jan 2025 15:51:11 -0500 Subject: [PATCH 296/791] quiet down mips cross-compile Even though most of these are cast to void (but not all), the mips cross-compiler seems determined to warn about them anyway. Suppress that particular warning altogether to quiet the build. That is not the ideal approach, but if the normal way of whitelisting individual cases isn't working, I'm not sure of another course of action. --- sys/unix/hints/include/cross-pre2.370 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sys/unix/hints/include/cross-pre2.370 b/sys/unix/hints/include/cross-pre2.370 index b1018dc5a..9730be4da 100644 --- a/sys/unix/hints/include/cross-pre2.370 +++ b/sys/unix/hints/include/cross-pre2.370 @@ -415,7 +415,8 @@ MIPS_TARGET_CFLAGS = -c -O -I../include -I../sys/unix -I../win/share \ -Wall -Wextra -Wno-missing-field-initializers -Wreturn-type -Wunused \ -Wformat -Wswitch -Wshadow -Wwrite-strings \ -Wimplicit -Wimplicit-function-declaration -Wimplicit-int \ - -Wmissing-parameter-type -Wold-style-definition -Wstrict-prototypes + -Wmissing-parameter-type -Wold-style-definition -Wstrict-prototypes \ + -Wno-unused-result MIPS_TARGET_CXXFLAGS = -c -O -I../include -I../sys/unix -I../win/share \ $(LUAINCL) -DDLB \ -DUSE_TILES -DCROSSCOMPILE -DCROSSCOMPILE_TARGET -DCROSS_TO_MIPS \ From d807436c107aae30aa5fb2070bbddce5ca7465df Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 6 Jan 2025 03:26:54 -0500 Subject: [PATCH 297/791] Windows: broken saved game restore Apparently, restoring of saved games on Windows has been broken since 1f36b98b, 'selectsaved' extension from Oct 10. That change was altering the names of the files saved on disk to a new format introduced at that time, but the game was not opening a savefile with that same name, and the restore failed. The code that renamed the savefile to match the internal name was not part of 1f36b98b, it already existed prior to the new internally-stored format. To get things functional, this commit disables the code that carries out the renaming of the on-disk savefile to match the internal name in the savefile entirely, at least for now. This relates to GitHub issue #1346 item 2. --- src/files.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/files.c b/src/files.c index 61a375007..20a25c95d 100644 --- a/src/files.c +++ b/src/files.c @@ -1300,8 +1300,10 @@ get_saved_games(void) { char *foundfile; const char *fq_save; +#if 0 const char *fq_new_save; const char *fq_old_save; +#endif char **files = 0; int i, count_failures = 0; @@ -1339,6 +1341,12 @@ get_saved_games(void) r = plname_from_file(files[i], SUPPRESS_WAITSYNCH_PERFILE); if (r) { + /* this renaming of the savefile is not compatible + * with 1f36b98b, 'selectsaved' extension from + * Oct 10, 2024. Disable the renaming for the time + * being. + */ +#if 0 /* rename file if it is not named as expected */ Strcpy(svp.plname, r); set_savefile_name(TRUE); @@ -1348,7 +1356,7 @@ get_saved_games(void) if (strcmp(fq_old_save, fq_new_save) != 0 && !file_exists(fq_new_save)) (void) rename(fq_old_save, fq_new_save); - +#endif result[j++] = r; } else { count_failures++; From 4392f5fa4ea6bb0f80d490d1eb11b2da9edf1a12 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Mon, 6 Jan 2025 19:46:35 +0200 Subject: [PATCH 298/791] Fix vision in some cases with boulder falling into pool We can't just unconditionally unblock vision for a location when a boulder falls into a pool, because the location may also have a (poison) cloud on it. --- include/extern.h | 1 + src/do.c | 2 +- src/vision.c | 12 +++++++++++- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/include/extern.h b/include/extern.h index e6939d7a1..3a0c6183f 100644 --- a/include/extern.h +++ b/include/extern.h @@ -3508,6 +3508,7 @@ extern void vision_reset(void); extern void vision_recalc(int); extern void block_point(int, int); extern void unblock_point(int, int); +extern void recalc_block_point(coordxy, coordxy); extern boolean clear_path(int, int, int, int); extern void do_clear_area(coordxy, coordxy, int, void(*)(coordxy, coordxy, void *), genericptr_t); diff --git a/src/do.c b/src/do.c index 1baddb56e..e9be24ca0 100644 --- a/src/do.c +++ b/src/do.c @@ -74,8 +74,8 @@ boulder_hits_pool( levl[rx][ry].drawbridgemask &= ~DB_UNDER; /* clear lava */ levl[rx][ry].drawbridgemask |= DB_FLOOR; } else { - unblock_point(rx, ry); levl[rx][ry].typ = ROOM, levl[rx][ry].flags = 0; + recalc_block_point(rx, ry); } /* 3.7: normally DEADMONSTER() is used when traversing the fmon list--dead monsters usually aren't still at specific map diff --git a/src/vision.c b/src/vision.c index 4d4ac98cf..e3d771a04 100644 --- a/src/vision.c +++ b/src/vision.c @@ -887,7 +887,17 @@ unblock_point(int x, int y) gv.vision_full_recalc = 1; } -/*==========================================================================*\ +/* recalc if point should be blocked or unblocked */ +void +recalc_block_point(coordxy x, coordxy y) +{ + if (does_block(x, y, &levl[x][y])) + block_point(x, y); + else + unblock_point(x, y); +} + +/*==========================================================================* \ : : : Everything below this line uses (y,x) instead of (x,y) --- the : : algorithms are faster if they are less recursive and can scan : From 274b15cd772a73b58b8918933418e6d288d07185 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Mon, 6 Jan 2025 20:11:32 +0200 Subject: [PATCH 299/791] Fix vision when xorn digs down on a wall A xorn inside a wall using a wand of digging to dig down, the vision was still blocked at that location. --- src/muse.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/muse.c b/src/muse.c index 7bf92b313..22948330a 100644 --- a/src/muse.c +++ b/src/muse.c @@ -931,11 +931,13 @@ use_defensive(struct monst *mtmp) surface(mtmp->mx, mtmp->my)); } fill_pit(mtmp->mx, mtmp->my); + recalc_block_point(mtmp->mx, mtmp->my); return (mintrap(mtmp, FORCEBUNGLE) == Trap_Killed_Mon) ? 1 : 2; } t = maketrap(mtmp->mx, mtmp->my, HOLE); if (!t) return 2; + recalc_block_point(mtmp->mx, mtmp->my); seetrap(t); if (vis) { pline_mon(mtmp, "%s has made a hole in the %s.", Monnam(mtmp), From f4cd5ed0651e8cff9b3250ffdddfc4bd85d47274 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Mon, 6 Jan 2025 20:22:51 +0200 Subject: [PATCH 300/791] Fix vision with pushing a boulder and temp clouds remove_object cleared the vision when the last boulder was removed from a location, without considering temporary [poison] clouds. This particular case happened when pushing a boulder. --- src/mkobj.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/mkobj.c b/src/mkobj.c index e6d55fcf3..d57d8fa80 100644 --- a/src/mkobj.c +++ b/src/mkobj.c @@ -2443,9 +2443,8 @@ remove_object(struct obj *otmp) panic("remove_object: obj not on floor"); extract_nexthere(otmp, &svl.level.objects[x][y]); extract_nobj(otmp, &fobj); - /* update vision iff this was the only boulder at its spot */ - if (otmp->otyp == BOULDER && !sobj_at(BOULDER, x, y)) - unblock_point(x, y); /* vision */ + if (otmp->otyp == BOULDER) + recalc_block_point(x, y); /* vision */ if (otmp->timed) obj_timer_checks(otmp, x, y, 0); } From a118869262ddc68dfc3bbf9a4b808bd344604f9e Mon Sep 17 00:00:00 2001 From: PatR Date: Mon, 6 Jan 2025 11:01:18 -0800 Subject: [PATCH 301/791] rephrase a recent fixes entry --- doc/fixes3-7-0.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index 839625bea..4e4b02a2c 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -959,7 +959,7 @@ a hero on the quest home level who runs or travels past the quest leader and gets tossed out of the quest for some reason would keep running on the far side of the quest portal allow rush/run over water if wearing discovered water walking boots -wearing water walking boots while underwater (maybe via magical breathing) +putting on water walking boots while underwater (maybe via magical breathing) and rising to surface wasn't causing the boots to become discovered flying pets wouldn't target underwater food but if they happened to fly over such food they could and would eat it From 108d975694c426aaecc947065580e900fd49a32a Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Tue, 7 Jan 2025 10:51:57 +0200 Subject: [PATCH 302/791] Fix vision in guard created corridor ... when hero angers the guard, the guard's previous location didn't get the vision blocking fixed. --- src/vault.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vault.c b/src/vault.c index 65fcf7a18..e395465a9 100644 --- a/src/vault.c +++ b/src/vault.c @@ -959,6 +959,7 @@ gd_move(struct monst *grd) mnexto(grd, RLOC_NOMSG); levl[m][n].typ = egrd->fakecorr[0].ftyp; levl[m][n].flags = egrd->fakecorr[0].flags; + recalc_block_point(m, n); del_engr_at(m, n); newsym(m, n); return -1; From b27c9102f63b74972cb4e0b00c4f3685f2ad7098 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Tue, 7 Jan 2025 15:14:24 +0200 Subject: [PATCH 303/791] Fix vision when opening a door If a monster or hero opened a door with a temporary (poison) cloud on it, the location could be seen through even with the cloud. --- src/lock.c | 2 +- src/monmove.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lock.c b/src/lock.c index 364031635..1165e63ce 100644 --- a/src/lock.c +++ b/src/lock.c @@ -911,7 +911,7 @@ doopen_indir(coordxy x, coordxy y) } else door->doormask = D_ISOPEN; feel_newsym(cc.x, cc.y); /* the hero knows she opened it */ - unblock_point(cc.x, cc.y); /* vision: new see through there */ + recalc_block_point(cc.x, cc.y); /* vision: new see through there */ } else { exercise(A_STR, TRUE); set_msg_xy(cc.x, cc.y); diff --git a/src/monmove.c b/src/monmove.c index ceb4927a1..a460e9841 100644 --- a/src/monmove.c +++ b/src/monmove.c @@ -1502,7 +1502,7 @@ postmov( do { \ (where)->doormask = (what); \ newsym((who)->mx, (who)->my); \ - unblock_point((who)->mx, (who)->my); \ + recalc_block_point((who)->mx, (who)->my); \ vision_recalc(0); \ /* update cached value since it might change */ \ canseeit = didseeit || cansee((who)->mx, (who)->my); \ From 85965b1b32b3df4b24ff637a8bbbc728e1fd056c Mon Sep 17 00:00:00 2001 From: nhmall Date: Tue, 7 Jan 2025 10:00:28 -0500 Subject: [PATCH 304/791] Visual Studio project files:directory name cleanup --- sys/windows/vs/NetHackW/NetHackW.vcxproj | 2 +- sys/windows/vs/hacklib/hacklib.vcxproj | 30 +++++------ sys/windows/vs/lualib/lualib.vcxproj | 66 ++++++++++++------------ sys/windows/vs/makedefs/makedefs.vcxproj | 10 ++-- 4 files changed, 53 insertions(+), 55 deletions(-) diff --git a/sys/windows/vs/NetHackW/NetHackW.vcxproj b/sys/windows/vs/NetHackW/NetHackW.vcxproj index 97980d2d7..c4a065c03 100644 --- a/sys/windows/vs/NetHackW/NetHackW.vcxproj +++ b/sys/windows/vs/NetHackW/NetHackW.vcxproj @@ -81,7 +81,6 @@ - @@ -232,6 +231,7 @@ + diff --git a/sys/windows/vs/hacklib/hacklib.vcxproj b/sys/windows/vs/hacklib/hacklib.vcxproj index 4ec744f5c..3be14bb62 100644 --- a/sys/windows/vs/hacklib/hacklib.vcxproj +++ b/sys/windows/vs/hacklib/hacklib.vcxproj @@ -25,23 +25,23 @@ - - + + - - - - - - - - - - - - - + + + + + + + + + + + + + 17.0 diff --git a/sys/windows/vs/lualib/lualib.vcxproj b/sys/windows/vs/lualib/lualib.vcxproj index 52d96e5cb..537be7191 100644 --- a/sys/windows/vs/lualib/lualib.vcxproj +++ b/sys/windows/vs/lualib/lualib.vcxproj @@ -25,7 +25,7 @@ - + 4701;4702;4244;4310;4774 4701;4702;4244;4310;4774 4701;4702;4244;4310;4774 @@ -35,7 +35,7 @@ %(AdditionalOptions) /wd4774 %(AdditionalOptions) /wd4774 - + 4701;4702;4244;4310;4774 4701;4702;4244;4310;4774 4701;4702;4244;4310;4774 @@ -45,7 +45,7 @@ %(AdditionalOptions) /wd4774 %(AdditionalOptions) /wd4774 - + 4701;4702;4244;4310;4774 4701;4702;4244;4310;4774 4701;4702;4244;4310;4774 @@ -55,7 +55,7 @@ %(AdditionalOptions) /wd4774 %(AdditionalOptions) /wd4774 - + 4701;4702;4244;4310;4774 4701;4702;4244;4310;4774 4701;4702;4244;4310;4774 @@ -65,7 +65,7 @@ %(AdditionalOptions) /wd4774 %(AdditionalOptions) /wd4774 - + 4701;4702;4244;4310;4774 4701;4702;4244;4310;4774 4701;4702;4244;4310;4774 @@ -75,7 +75,7 @@ %(AdditionalOptions) /wd4774 %(AdditionalOptions) /wd4774 - + 4701;4702;4244;4310;4774 4701;4702;4244;4310;4774 4701;4702;4244;4310;4774 @@ -85,7 +85,7 @@ %(AdditionalOptions) /wd4774 %(AdditionalOptions) /wd4774 - + 4701;4702;4244;4310;4774 4701;4702;4244;4310;4774 4701;4702;4244;4310;4774 @@ -95,7 +95,7 @@ %(AdditionalOptions) /wd4774 %(AdditionalOptions) /wd4774 - + 4701;4702;4244;4310;4774 4701;4702;4244;4310;4774 4701;4702;4244;4310;4774 @@ -105,7 +105,7 @@ %(AdditionalOptions) /wd4774 %(AdditionalOptions) /wd4774 - + 4701;4702;4244;4310;4774 4701;4702;4244;4310;4774 4701;4702;4244;4310;4774 @@ -115,7 +115,7 @@ %(AdditionalOptions) /wd4774 %(AdditionalOptions) /wd4774 - + 4701;4702;4244;4310;4774 4701;4702;4244;4310;4774 4701;4702;4244;4310;4774 @@ -125,7 +125,7 @@ %(AdditionalOptions) /wd4774 %(AdditionalOptions) /wd4774 - + 4701;4702;4244;4310;4774 4701;4702;4244;4310;4774 4701;4702;4244;4310;4774 @@ -135,7 +135,7 @@ %(AdditionalOptions) /wd4774 %(AdditionalOptions) /wd4774 - + 4701;4702;4244;4310;4774 4701;4702;4244;4310;4774 4701;4702;4244;4310;4774 @@ -145,7 +145,7 @@ %(AdditionalOptions) /wd4774 %(AdditionalOptions) /wd4774 - + 4701;4702;4244;4310;4774 4701;4702;4244;4310;4774 4701;4702;4244;4310;4774 @@ -155,7 +155,7 @@ %(AdditionalOptions) /wd4774 %(AdditionalOptions) /wd4774 - + 4701;4702;4244;4310;4774 4701;4702;4244;4310;4774 4701;4702;4244;4310;4774 @@ -165,7 +165,7 @@ %(AdditionalOptions) /wd4774 %(AdditionalOptions) /wd4774 - + 4701;4702;4244;4310;4774 4701;4702;4244;4310;4774 4701;4702;4244;4310;4774 @@ -175,7 +175,7 @@ %(AdditionalOptions) /wd4774 %(AdditionalOptions) /wd4774 - + 4701;4702;4244;4310;4774 4701;4702;4244;4310;4774 4701;4702;4244;4310;4774 @@ -185,7 +185,7 @@ %(AdditionalOptions) /wd4774 %(AdditionalOptions) /wd4774 - + 4701;4702;4244;4310;4774 4701;4702;4244;4310;4774 4701;4702;4244;4310;4774 @@ -195,7 +195,7 @@ %(AdditionalOptions) /wd4774 %(AdditionalOptions) /wd4774 - + 4701;4702;4244;4310;4774 4701;4702;4244;4310;4774 4701;4702;4244;4310;4774 @@ -205,7 +205,7 @@ %(AdditionalOptions) /wd4774 %(AdditionalOptions) /wd4774 - + 4701;4702;4244;4310;4774 4701;4702;4244;4310;4774 4701;4702;4244;4310;4774 @@ -215,7 +215,7 @@ %(AdditionalOptions) /wd4774 %(AdditionalOptions) /wd4774 - + 4701;4702;4244;4310;4774 4701;4702;4244;4310;4774 4701;4702;4244;4310;4774 @@ -225,7 +225,7 @@ %(AdditionalOptions) /wd4774 %(AdditionalOptions) /wd4774 - + 4701;4702;4244;4310;4774 4701;4702;4244;4310;4774 4701;4702;4244;4310;4774 @@ -235,7 +235,7 @@ %(AdditionalOptions) /wd4774 %(AdditionalOptions) /wd4774 - + 4701;4702;4244;4310;4774 4701;4702;4244;4310;4774 4701;4702;4244;4310;4774 @@ -245,7 +245,7 @@ %(AdditionalOptions) /wd4774 %(AdditionalOptions) /wd4774 - + 4701;4702;4244;4310;4774 4701;4702;4244;4310;4774 4701;4702;4244;4310;4774 @@ -255,7 +255,7 @@ %(AdditionalOptions) /wd4774 %(AdditionalOptions) /wd4774 - + 4701;4702;4244;4310;4774 4701;4702;4244;4310;4774 4701;4702;4244;4310;4774 @@ -265,7 +265,7 @@ %(AdditionalOptions) /wd4774 %(AdditionalOptions) /wd4774 - + 4701;4702;4244;4310;4774 4701;4702;4244;4310;4774 4701;4702;4244;4310;4774 @@ -275,7 +275,7 @@ %(AdditionalOptions) /wd4774 %(AdditionalOptions) /wd4774 - + 4701;4702;4244;4310;4774 4701;4702;4244;4310;4774 4701;4702;4244;4310;4774 @@ -285,7 +285,7 @@ %(AdditionalOptions) /wd4774 %(AdditionalOptions) /wd4774 - + 4701;4702;4244;4310;4774 4701;4702;4244;4310;4774 4701;4702;4244;4310;4774 @@ -295,7 +295,7 @@ %(AdditionalOptions) /wd4774 %(AdditionalOptions) /wd4774 - + 4701;4702;4244;4310;4774 4701;4702;4244;4310;4774 4701;4702;4244;4310;4774 @@ -305,7 +305,7 @@ %(AdditionalOptions) /wd4774 %(AdditionalOptions) /wd4774 - + 4701;4702;4244;4310;4774 4701;4702;4244;4310;4774 4701;4702;4244;4310;4774 @@ -315,7 +315,7 @@ %(AdditionalOptions) /wd4774 %(AdditionalOptions) /wd4774 - + 4701;4702;4244;4310;4774 4701;4702;4244;4310;4774 4701;4702;4244;4310;4774 @@ -325,7 +325,7 @@ %(AdditionalOptions) /wd4774 %(AdditionalOptions) /wd4774 - + 4701;4702;4244;4310;4774 4701;4702;4244;4310;4774 4701;4702;4244;4310;4774 @@ -335,7 +335,7 @@ %(AdditionalOptions) /wd4774 %(AdditionalOptions) /wd4774 - + 4701;4702;4244;4310;4774 4701;4702;4244;4310;4774 4701;4702;4244;4310;4774 @@ -345,8 +345,6 @@ %(AdditionalOptions) /wd4774 %(AdditionalOptions) /wd4774 - - 17.0 diff --git a/sys/windows/vs/makedefs/makedefs.vcxproj b/sys/windows/vs/makedefs/makedefs.vcxproj index c5bd6c0dd..5b3c90584 100644 --- a/sys/windows/vs/makedefs/makedefs.vcxproj +++ b/sys/windows/vs/makedefs/makedefs.vcxproj @@ -37,11 +37,11 @@ - - - - - + + + + + From ae1a86d7be7a026e1b276cae6054f9d70462c42c Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Tue, 7 Jan 2025 17:39:43 +0200 Subject: [PATCH 305/791] Fix vision when door is destroyed by ray effect A door was destroyed and vision unblocked without considering temporary (poison) clouds. --- src/zap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/zap.c b/src/zap.c index d0e8fa077..b367722f3 100644 --- a/src/zap.c +++ b/src/zap.c @@ -5404,7 +5404,7 @@ zap_over_floor( add_damage(x, y, 0L); } lev->doormask = new_doormask; - unblock_point(x, y); /* vision */ + recalc_block_point(x, y); /* vision */ if (see_it) { pline1(see_txt); newsym(x, y); From 9b71efe69e05be6e62f602417437248eeada451c Mon Sep 17 00:00:00 2001 From: nhw_cron Date: Tue, 7 Jan 2025 11:24:08 -0500 Subject: [PATCH 306/791] This is cron-daily v1-Apr-1-2024. 005manpages updated: recover.txt --- doc/recover.txt | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/doc/recover.txt b/doc/recover.txt index 09e05f4fd..e13d2995f 100644 --- a/doc/recover.txt +++ b/doc/recover.txt @@ -22,15 +22,11 @@ DESCRIPTION The -d option, which must be the first argument if it appears, supplies a directory which is the NetHack playground. It overrides the value from NETHACKDIR, HACKDIR, or the directory specified by the game admin- - istrator during compilation (usually /usr/games/lib/nethackdir). - - For recovery to be possible, nethack must have been compiled with the - INSURANCE option, and the run-time option checkpoint must also have - been on. NetHack normally writes out files for levels as the player - leaves them, so they will be ready for return visits. When checkpoint- - ing, NetHack also writes out the level entered and the current game - state on every level change. This naturally slows level changes down - somewhat. + istrator during compilation (usually /usr/games/lib/nethackdir). + NetHack normally writes out files for levels as the player leaves them, + so they will be ready for return visits. When checkpointing, NetHack + also writes out the level entered and the current game state on every + level change. This naturally slows level changes down somewhat. The level file names are of the form base.nn, where nn is an internal bookkeeping number for the level. The file base.0 is used for game From 256b820fe34299048304e08f01369e3fcb33caba Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Wed, 8 Jan 2025 12:49:15 +0200 Subject: [PATCH 307/791] Fix impossible no_charge obj in untended shop Sanity checking was complaining about a no_charge obj in untended shop. Angry shopkeeper was accepting thrown items as no_charge objects: To reproduce the impossible, kick down the shop door angering the shopkeeper. While the shopkeeper is still in their shop, throw an item they don't want into the shop. Wait for the shopkeeper to get out of the shop. Move the anger checking before the sell auto-accept code, so the shopkeeper will charge for the object. --- doc/fixes3-7-0.txt | 1 + src/shk.c | 30 +++++++++++++++--------------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index 4e4b02a2c..4d9b7173a 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -1498,6 +1498,7 @@ remember box is trapped after finding the trap when you hear a monster incant a scroll, ensure that the 'I' invisible monster indicator doesn't trump telepathy briefly proceed with showpaths option even if the sysconf file is missing +angry shopkeeper was not charging for thrown items Fixes to 3.7.0-x General Problems Exposed Via git Repository diff --git a/src/shk.c b/src/shk.c index 103ca22da..315b4002d 100644 --- a/src/shk.c +++ b/src/shk.c @@ -3886,6 +3886,21 @@ sellobj( offer = ltmp + cltmp; + /* you dropped something of your own - probably want to sell it */ + rouse_shk(shkp, TRUE); /* wake up sleeping or paralyzed shk */ + eshkp = ESHK(shkp); + + if (ANGRY(shkp)) { /* they become shop-objects, no pay */ + if (!Deaf && !muteshk(shkp)) { + SetVoice(shkp, 0, 80, 0); + verbalize("Thank you, scum!"); + } else { + pline("%s smirks with satisfaction.", Shknam(shkp)); + } + subfrombill(obj, shkp); + return; + } + /* get one case out of the way: nothing to sell, and no gold */ if (!(isgold || cgold) && ((offer + gltmp) == 0L || gs.sell_how == SELL_DONTSELL)) { @@ -3906,21 +3921,6 @@ sellobj( return; } - /* you dropped something of your own - probably want to sell it */ - rouse_shk(shkp, TRUE); /* wake up sleeping or paralyzed shk */ - eshkp = ESHK(shkp); - - if (ANGRY(shkp)) { /* they become shop-objects, no pay */ - if (!Deaf && !muteshk(shkp)) { - SetVoice(shkp, 0, 80, 0); - verbalize("Thank you, scum!"); - } else { - pline("%s smirks with satisfaction.", Shknam(shkp)); - } - subfrombill(obj, shkp); - return; - } - if (eshkp->robbed) { /* bones; shop robbed by previous customer */ if (isgold) offer = obj->quan; From c956e3e2155386c1f40c6c41863bc91a0c974aeb Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Wed, 8 Jan 2025 13:59:50 +0200 Subject: [PATCH 308/791] Fix vision when applying a wand of digging --- src/trap.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/trap.c b/src/trap.c index 9c0ec1304..38b970aa6 100644 --- a/src/trap.c +++ b/src/trap.c @@ -561,6 +561,7 @@ maketrap(coordxy x, coordxy y, int typ) lev->flags = 0; /* set_levltyp doesn't take care of this [yet?] */ unearth_objs(x, y); + recalc_block_point(x, y); break; case TELEP_TRAP: if (isok(gl.launchplace.x, gl.launchplace.y)) { From 83c0d430c938acdf4856984c3fdb3219b62cb778 Mon Sep 17 00:00:00 2001 From: PatR Date: Wed, 8 Jan 2025 13:46:28 -0800 Subject: [PATCH 309/791] suppress sanity_check after invalid command Entering an invalid command, particularly , while there is some circumstance triggering sanity check warnings, becomes too verbose. --- src/cmd.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/cmd.c b/src/cmd.c index 6db62f9af..d6ac2c580 100644 --- a/src/cmd.c +++ b/src/cmd.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 cmd.c $NHDT-Date: 1717967336 2024/06/09 21:08:56 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.729 $ */ +/* NetHack 3.7 cmd.c $NHDT-Date: 1736401574 2025/01/08 21:46:14 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.744 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2013. */ /* NetHack may be freely redistributed. See license for details. */ @@ -3595,6 +3595,7 @@ rhack(int key) custompline(SUPPRESS_HISTORY, "Unknown command '%s'.", visctrl(key)); cmdq_clear(CQ_CANNED); cmdq_clear(CQ_REPEAT); + iflags.sanity_no_check = iflags.sanity_check; /* skip sanity check */ } /* didn't move */ svc.context.move = FALSE; From 843b02ec1df488612ca6e8c70a89bdb1e601cbaa Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Thu, 9 Jan 2025 17:26:58 +0200 Subject: [PATCH 310/791] Add vision sanity checking, fix more vision - Add a vision sanity checking routine - Recalc block point when digging a door for temporary clouds - Add recalc_block_point after cvt_sdoor_to_door, because doorways on the Rogue level have no doors, and otherwise the sanity checking would complain. This doesn't actually change how the Rogue level vision works, as it uses a different vision system - Monster using a trap in a secret corridor revealed the corridor, but didn't unblock the vision unless you saw the location --- include/extern.h | 1 + src/apply.c | 1 + src/detect.c | 2 ++ src/dig.c | 3 ++- src/muse.c | 3 +-- src/read.c | 5 ++++- src/vision.c | 9 +++++++++ src/wizcmds.c | 18 ++++++++++++++++++ src/zap.c | 2 ++ 9 files changed, 40 insertions(+), 4 deletions(-) diff --git a/include/extern.h b/include/extern.h index 3a0c6183f..f6063cef9 100644 --- a/include/extern.h +++ b/include/extern.h @@ -3502,6 +3502,7 @@ extern int assign_videocolors(char *) NONNULLARG1; /* ### vision.c ### */ +extern boolean get_viz_clear(int, int); extern void vision_init(void); extern int does_block(int, int, struct rm *) NONNULLARG3; extern void vision_reset(void); diff --git a/src/apply.c b/src/apply.c index 60384c3aa..676d97137 100644 --- a/src/apply.c +++ b/src/apply.c @@ -452,6 +452,7 @@ use_stethoscope(struct obj *obj) Soundeffect(se_hollow_sound, 100); You_hear(hollow_str, "door"); cvt_sdoor_to_door(lev); /* ->typ = DOOR */ + recalc_block_point(rx, ry); feel_newsym(rx, ry); return res; case SCORR: diff --git a/src/detect.c b/src/detect.c index ccede5c5d..cb6dc2458 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1651,6 +1651,7 @@ findone(coordxy zx, coordxy zy, genericptr_t whatfound) flash_glyph_at(zx, zy, cmap_to_glyph(sym), FOUND_FLASH_COUNT); cvt_sdoor_to_door(lev); /* set lev->typ = DOOR */ + recalc_block_point(zx, zy); magic_map_background(zx, zy, 0); foundone(zx, zy, back_to_glyph(zx, zy)); found_p->num_sdoors++; @@ -2040,6 +2041,7 @@ dosearch0(int aflag) /* intrinsic autosearch vs explicit searching */ if (rnl(7 - fund)) continue; cvt_sdoor_to_door(&levl[x][y]); /* .typ = DOOR */ + recalc_block_point(x, y); exercise(A_WIS, TRUE); nomul(0); feel_location(x, y); /* make sure it shows up */ diff --git a/src/dig.c b/src/dig.c index cb064c53c..2e028b035 100644 --- a/src/dig.c +++ b/src/dig.c @@ -541,6 +541,7 @@ dig(void) if (IS_DOOR(lev->typ) && (lev->doormask & D_TRAPPED)) { lev->doormask = D_NODOOR; b_trapped("door", NO_PART); + recalc_block_point(dpx, dpy); newsym(dpx, dpy); } cleanup: @@ -1682,7 +1683,7 @@ zap_dig(void) pline_The("door is razed!"); watch_dig((struct monst *) 0, zx, zy, TRUE); room->doormask = D_NODOOR; - unblock_point(zx, zy); /* vision */ + recalc_block_point(zx, zy); /* vision */ digdepth -= 2; if (maze_dig) break; diff --git a/src/muse.c b/src/muse.c index 22948330a..264d6b9ab 100644 --- a/src/muse.c +++ b/src/muse.c @@ -758,8 +758,7 @@ reveal_trap(struct trap *t, boolean seeit) if (lev->typ == SCORR) { lev->typ = CORR, lev->flags = 0; /* set_levltyp(,,CORR) */ - if (seeit) - unblock_point(t->tx, t->ty); + unblock_point(t->tx, t->ty); } if (seeit) seetrap(t); diff --git a/src/read.c b/src/read.c index 47c4d2594..831d85118 100644 --- a/src/read.c +++ b/src/read.c @@ -2035,8 +2035,11 @@ seffect_magic_mapping(struct obj **sobjp) for (x = 1; x < COLNO; x++) for (y = 0; y < ROWNO; y++) - if (levl[x][y].typ == SDOOR) + if (levl[x][y].typ == SDOOR) { cvt_sdoor_to_door(&levl[x][y]); + if (Is_rogue_level(&u.uz)) + unblock_point(x, y); + } /* do_mapping() already reveals secret passages */ } gk.known = TRUE; diff --git a/src/vision.c b/src/vision.c index e3d771a04..3f33d726c 100644 --- a/src/vision.c +++ b/src/vision.c @@ -100,6 +100,15 @@ staticfn void rogue_vision(seenV **, coordxy *, coordxy *); #define sign(z) ((z) < 0 ? -1 : ((z) ? 1 : 0)) #define v_abs(z) ((z) < 0 ? -(z) : (z)) /* don't use abs -- it may exist */ +/* expose viz_clear[][] for sanity checking */ +boolean +get_viz_clear(int x, int y) +{ + if (isok(x,y) && !viz_clear[y][x]) + return TRUE; + return FALSE; +} + /* * vision_init() * diff --git a/src/wizcmds.c b/src/wizcmds.c index 948b63fe6..a22b6883d 100644 --- a/src/wizcmds.c +++ b/src/wizcmds.c @@ -20,6 +20,7 @@ staticfn void mon_chain(winid, const char *, struct monst *, boolean, long *, staticfn void contained_stats(winid, const char *, long *, long *); staticfn void misc_stats(winid, long *, long *); staticfn void you_sanity_check(void); +staticfn void levl_sanity_check(void); staticfn void makemap_unmakemon(struct monst *, boolean); staticfn int QSORTCALLBACK migrsort_cmp(const genericptr, const genericptr); staticfn void list_migrating_mons(d_level *); @@ -1437,6 +1438,22 @@ you_sanity_check(void) (void) check_invent_gold("invent"); } +staticfn void +levl_sanity_check(void) +{ + coordxy x, y; + + if (Underwater) + return; /* Underwater uses different vision */ + + for (y = 0; y < ROWNO; y++) { + for (x = 1; x < COLNO; x++) { + if ((does_block(x, y, &levl[x][y]) ? 1 : 0) != get_viz_clear(x, y)) + impossible("levl[%i][%i] vision blocking", x, y); + } + } +} + void sanity_check(void) { @@ -1457,6 +1474,7 @@ sanity_check(void) bc_sanity_check(); trap_sanity_check(); engraving_sanity_check(); + levl_sanity_check(); program_state.in_sanity_check--; } diff --git a/src/zap.c b/src/zap.c index b367722f3..7fc54146e 100644 --- a/src/zap.c +++ b/src/zap.c @@ -3707,6 +3707,7 @@ zap_map( /* secret door gets revealed, converted into regular door */ if (ltyp == SDOOR) { cvt_sdoor_to_door(&levl[x][y]); /* .typ = DOOR */ + recalc_block_point(x, y); newsym(x, y); if (cansee(x, y)) { pline("Probing reveals a secret door."); @@ -5331,6 +5332,7 @@ zap_over_floor( /* secret door gets revealed, converted into regular door */ if (levl[x][y].typ == SDOOR) { cvt_sdoor_to_door(&levl[x][y]); /* .typ = DOOR */ + recalc_block_point(x, y); /* target spot will now pass closed_door() test below (except on rogue level) */ newsym(x, y); From de38ce2c900c571f551869400fa794bc6134e54e Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Thu, 9 Jan 2025 19:44:21 +0200 Subject: [PATCH 311/791] Fix vision: force bolt breaking door with temp cloud --- src/lock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lock.c b/src/lock.c index 1165e63ce..b95e98707 100644 --- a/src/lock.c +++ b/src/lock.c @@ -1232,7 +1232,7 @@ doorlock(struct obj *otmp, coordxy x, coordxy y) } sawit = cansee(x, y); door->doormask = D_BROKEN; - unblock_point(x, y); + recalc_block_point(x, y); seeit = cansee(x, y); newsym(x, y); if (flags.verbose) { From 5d7d00484674137b3d12910a6b9a146d03eb3625 Mon Sep 17 00:00:00 2001 From: PatR Date: Thu, 9 Jan 2025 21:40:46 -0800 Subject: [PATCH 312/791] fix issue #1352 - another try at #1339 The attempt to simplify shop handling of containers keeps getting more complicated. Fixes #1352 --- src/shk.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/shk.c b/src/shk.c index 315b4002d..2828d5efe 100644 --- a/src/shk.c +++ b/src/shk.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 shk.c $NHDT-Date: 1720717993 2024/07/11 17:13:13 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.298 $ */ +/* NetHack 3.7 shk.c $NHDT-Date: 1736516428 2025/01/10 05:40:28 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.306 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -2091,7 +2091,7 @@ pay_billed_items( /* update shk's bill and augmented bill after an item has been purchased */ staticfn void update_bill( - int indx, + int indx, /* index into ibill[]; -1 for unpaid contained item */ int ibillct, Bill *ibill, struct eshk *eshkp, @@ -2117,18 +2117,16 @@ update_bill( from shop bill; if it was used up, remove it from the billobjs list and delete it; update shop's bill by moving last bill_p[] entry into vacated slot; also update ibill[] indices for that */ - paiditem->unpaid = 0; /* set before maybe deallocating */ + paiditem->unpaid = 0; /* clear before maybe deallocating */ if (paiditem->where == OBJ_ONBILL) { obj_extract_self(paiditem); dealloc_obj(paiditem); } newebillct = eshkp->billct - 1; *bp = eshkp->bill_p[newebillct]; - if (indx >= 0) { - for (j = 0; j < ibillct; ++j) - if (ibill[j].bidx == newebillct) - ibill[j].bidx = ibill[indx].bidx; - } + for (j = 0; j < ibillct; ++j) + if (ibill[j].bidx == newebillct) + ibill[j].bidx = (int) (bp - eshkp->bill); eshkp->billct = newebillct; /* eshkp->billct - 1 */ } return; @@ -2145,7 +2143,7 @@ dopayobj( struct monst *shkp, struct bill_x *bp, struct obj *obj, - int which /* 0 => used-up item, 1 => other (unpaid or lost) */, + int which, /* 0 => used-up item, 1 => other (unpaid or lost) */ boolean itemize, boolean unseen) { @@ -2311,7 +2309,8 @@ buy_container( } /* [updating cost here is not necessary but useful when debugging] */ ibill[indx].cost -= (bp->price * bp->bquan); /* update container */ - update_bill(-1, ibillct, ibill, eshkp, bp, otmp); + update_bill((boid == container->o_id) ? indx : -1, + ibillct, ibill, eshkp, bp, otmp); ++buycount; } if (buycount && sightunseen) { From a490ce57593445f75db3b32b8712cea0ead8ddd0 Mon Sep 17 00:00:00 2001 From: PatR Date: Fri, 10 Jan 2025 01:30:49 -0800 Subject: [PATCH 313/791] remove trailing spaces from src/*.c, include/*.h --- include/hack.h | 3 +-- include/winprocs.h | 13 ++++++------- src/decl.c | 4 ++-- src/dig.c | 4 ++-- src/explode.c | 4 ++-- src/hack.c | 4 ++-- src/music.c | 4 ++-- src/restore.c | 4 ++-- src/shknam.c | 4 ++-- src/sounds.c | 10 +++++----- src/symbols.c | 4 ++-- src/wizcmds.c | 4 ++-- src/worn.c | 4 ++-- 13 files changed, 32 insertions(+), 34 deletions(-) diff --git a/include/hack.h b/include/hack.h index 09e41407e..643075129 100644 --- a/include/hack.h +++ b/include/hack.h @@ -1,4 +1,4 @@ -/* NetHack 3.7 hack.h $NHDT-Date: 1725653009 2024/09/06 20:03:29 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.262 $ */ +/* NetHack 3.7 hack.h $NHDT-Date: 1736530208 2025/01/10 09:30:08 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.266 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Pasi Kallinen, 2017. */ /* NetHack may be freely redistributed. See license for details. */ @@ -347,7 +347,6 @@ enum digcheck_result { DIGCHECK_FAIL_OBJ_POOL_OR_TRAP }; - /* Dismount: causes for why you are no longer riding */ enum dismount_types { diff --git a/include/winprocs.h b/include/winprocs.h index 5e0bc675f..c77288891 100644 --- a/include/winprocs.h +++ b/include/winprocs.h @@ -1,4 +1,4 @@ -/* NetHack 3.7 winprocs.h $NHDT-Date: 1725653017 2024/09/06 20:03:37 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.81 $ */ +/* NetHack 3.7 winprocs.h $NHDT-Date: 1736530208 2025/01/10 09:30:08 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.83 $ */ /* Copyright (c) David Cohrs, 1992 */ /* NetHack may be freely redistributed. See license for details. */ @@ -10,7 +10,7 @@ #include "color.h" #endif -enum wp_ids { wp_tty = 1, wp_X11, wp_Qt, wp_mswin, wp_curses, +enum wp_ids { wp_tty = 1, wp_X11, wp_Qt, wp_mswin, wp_curses, wp_chainin, wp_chainout, wp_safestartup, wp_shim, wp_hup, wp_guistubs, wp_ttystubs, #ifdef OUTDATED_STUFF @@ -124,10 +124,9 @@ extern #define display_file (*windowprocs.win_display_file) #define start_menu (*windowprocs.win_start_menu) #define end_menu (*windowprocs.win_end_menu) -/* 3.7: There are real add_menu() and select_menu - * in the core now. +/* 3.7: There are real add_menu() and select_menu in the core now. * add_menu does some common activities, such as menu_colors. - * select_menu does some before and after activities. + * select_menu does some before and after activities. * add_menu() and select_menu() are in windows.c */ /* #define add_menu (*windowprocs.win_add_menu) */ @@ -185,10 +184,10 @@ extern #define ctrl_nhwindow (*windowprocs.win_ctrl_nhwindow) /* - * + * */ #define WPID(name) #name, wp_##name -#define WPIDMINUS(name) "-" #name, wp_##name +#define WPIDMINUS(name) "-" #name, wp_##name /* * WINCAP diff --git a/src/decl.c b/src/decl.c index 4afe5544a..fe16b2b44 100644 --- a/src/decl.c +++ b/src/decl.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 decl.c $NHDT-Date: 1725138480 2024/08/31 21:08:00 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.337 $ */ +/* NetHack 3.7 decl.c $NHDT-Date: 1736530208 2025/01/10 09:30:08 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.341 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2009. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1168,7 +1168,7 @@ decl_globals_init(void) gv.valuables[1].size = SIZE(ga.amulets); gv.valuables[2].list = NULL; gv.valuables[2].size = 0; - + #if 0 MAGICCHECK(g_init); #endif diff --git a/src/dig.c b/src/dig.c index 2e028b035..00f2f0422 100644 --- a/src/dig.c +++ b/src/dig.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 dig.c $NHDT-Date: 1724613307 2024/08/25 19:15:07 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.219 $ */ +/* NetHack 3.7 dig.c $NHDT-Date: 1736530208 2025/01/10 09:30:08 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.225 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -898,7 +898,7 @@ dighole(boolean pit_only, boolean by_magic, coord *cc) coordxy dig_x, dig_y; boolean nohole, retval = FALSE; enum digcheck_result dig_check_result; - + if (!cc) { dig_x = u.ux; dig_y = u.uy; diff --git a/src/explode.c b/src/explode.c index 2aff34776..18bf8d53c 100644 --- a/src/explode.c +++ b/src/explode.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 explode.c $NHDT-Date: 1619553210 2021/04/27 19:53:30 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.77 $ */ +/* NetHack 3.7 explode.c $NHDT-Date: 1736530208 2025/01/10 09:30:08 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.122 $ */ /* Copyright (C) 1990 by Ken Arromdee */ /* NetHack may be freely redistributed. See license for details. */ @@ -794,7 +794,7 @@ scatter(coordxy sx, coordxy sy, /* location of objects to scatter */ if (cansee(sx, sy)) { pline("%s.", Tobjnam(otmp, "crumble")); } else { - Soundeffect(se_stone_crumbling, 100); + Soundeffect(se_stone_crumbling, 100); You_hear("stone crumbling."); } (void) break_statue(otmp); diff --git a/src/hack.c b/src/hack.c index 14eea831a..c7dcf0c24 100644 --- a/src/hack.c +++ b/src/hack.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 hack.c $NHDT-Date: 1723410639 2024/08/11 21:10:39 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.452 $ */ +/* NetHack 3.7 hack.c $NHDT-Date: 1736530208 2025/01/10 09:30:08 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.477 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Derek S. Ray, 2015. */ /* NetHack may be freely redistributed. See license for details. */ @@ -962,7 +962,7 @@ invocation_pos(coordxy x, coordxy y) && x == svi.inv_pos.x && y == svi.inv_pos.y); } -/* return TRUE if (ux+dx,ux+dy) is an OK place to move; +/* return TRUE if (ux+dx,uy+dy) is an OK place to move; mode is one of DO_MOVE, TEST_MOVE, TEST_TRAV, or TEST_TRAP */ boolean test_move( diff --git a/src/music.c b/src/music.c index 82fe8abcc..374b848ab 100644 --- a/src/music.c +++ b/src/music.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 music.c $NHDT-Date: 1702349065 2023/12/12 02:44:25 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.102 $ */ +/* NetHack 3.7 music.c $NHDT-Date: 1736530208 2025/01/10 09:30:08 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.120 $ */ /* Copyright (c) 1989 by Jean-Christophe Collet */ /* NetHack may be freely redistributed. See license for details. */ @@ -733,7 +733,7 @@ staticfn char * improvised_notes(boolean *same_as_last_time) { static const char notes[7] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G' }; - /* target buffer has to be in svc.context, otherwise saving game + /* target buffer has to be in svc.context, otherwise saving game * between improvised recitals would not be able to maintain * the same_as_last_time context. */ diff --git a/src/restore.c b/src/restore.c index fcf31f3fb..b8e0988aa 100644 --- a/src/restore.c +++ b/src/restore.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 restore.c $NHDT-Date: 1717878585 2024/06/08 20:29:45 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.228 $ */ +/* NetHack 3.7 restore.c $NHDT-Date: 1736530208 2025/01/10 09:30:08 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.234 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2009. */ /* NetHack may be freely redistributed. See license for details. */ @@ -578,7 +578,7 @@ restgamestate(NHFILE *nhfp) /* savefile has wizard or explore mode, but player is no longer authorized to access either; can't downgrade mode any further, so fail restoration. */ - u.uhp = 0; + u.uhp = 0; } if (nhfp->structlevel) diff --git a/src/shknam.c b/src/shknam.c index 7bd9f4e21..5aaeefcca 100644 --- a/src/shknam.c +++ b/src/shknam.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 shknam.c $NHDT-Date: 1715203028 2024/05/08 21:17:08 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.78 $ */ +/* NetHack 3.7 shknam.c $NHDT-Date: 1736530208 2025/01/10 09:30:08 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.82 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2011. */ /* NetHack may be freely redistributed. See license for details. */ @@ -201,7 +201,7 @@ static const char *const shkhealthfoods[] = { * *_CLASS enum value) or a specific object enum value. * In the latter case, prepend it with a unary minus so the code can know * (by testing the sign) whether to use mkobj() or mksobj(). - * shtypes[] is externally referenced from mkroom.c, mon.c and shk.c. + * shtypes[] is externally referenced from mkroom.c, mon.c and shk.c. * * The second, usually shorter, store type name is used in automatically * generated annotations for #overview. If Null, the first name gets used. diff --git a/src/sounds.c b/src/sounds.c index 5b7d2baae..ec5d2aae2 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 sounds.c $NHDT-Date: 1674548234 2023/01/24 08:17:14 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.134 $ */ +/* NetHack 3.7 sounds.c $NHDT-Date: 1736530208 2025/01/10 09:30:08 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.165 $ */ /* Copyright (c) 1989 Janet Walz, Mike Threepoint */ /* NetHack may be freely redistributed. See license for details. */ @@ -1230,7 +1230,7 @@ domonnoise(struct monst *mtmp) and without quotation marks */ char tmpbuf[BUFSZ]; pline1(ucase(strcpy(tmpbuf, verbl_msg))); - SetVoice((struct monst *) 0, 0, 80, voice_death); + SetVoice((struct monst *) 0, 0, 80, voice_death); sound_speak(tmpbuf); } else { SetVoice(mtmp, 0, 80, 0); @@ -2169,14 +2169,14 @@ set_voice( if (gv.voice.nameid) free((genericptr_t) gv.voice.nameid); gv.voice.gender = gender; - gv.voice.serialno = mtmp ? mtmp->m_id + gv.voice.serialno = mtmp ? mtmp->m_id : ((moreinfo & voice_talking_artifact) != 0) ? 3 : ((moreinfo & voice_deity) != 0) ? 4 : 2; gv.voice.tone = tone; gv.voice.volume = volume; gv.voice.moreinfo = moreinfo; gv.voice.nameid = (const char *) 0; - gp.pline_flags |= PLINE_SPEECH; + gp.pline_flags |= PLINE_SPEECH; #endif } @@ -2213,7 +2213,7 @@ sound_speak(const char *text SPEECHONLY) *cpdst = '\0'; } (*soundprocs.sound_verbal)(buf, gv.voice.gender, gv.voice.tone, - gv.voice.volume, gv.voice.moreinfo); + gv.voice.volume, gv.voice.moreinfo); } #endif } diff --git a/src/symbols.c b/src/symbols.c index ff352d214..7c32af3e3 100644 --- a/src/symbols.c +++ b/src/symbols.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 symbols.c $NHDT-Date: 1711477037 2024/03/26 18:17:17 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.120 $ */ +/* NetHack 3.7 symbols.c $NHDT-Date: 1736530208 2025/01/10 09:30:08 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.123 $ */ /* Copyright (c) NetHack Development Team 2020. */ /* NetHack may be freely redistributed. See license for details. */ @@ -371,7 +371,7 @@ symset_is_compatible( * particular types of symset "handling", define a * H_XXX macro in include/sym.h and add the name * to this array at the matching offset. - * Externally referenced from files.c, options.c, utf8map.c. + * Externally referenced from files.c, options.c, utf8map.c. */ const char *const known_handling[] = { "UNKNOWN", /* H_UNK */ diff --git a/src/wizcmds.c b/src/wizcmds.c index a22b6883d..6cee64b36 100644 --- a/src/wizcmds.c +++ b/src/wizcmds.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 wizcmds.c $NHDT-Date: 1735950605 2025/01/03 16:30:05 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.19 $ */ +/* NetHack 3.7 wizcmds.c $NHDT-Date: 1736530208 2025/01/10 09:30:08 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.21 $ */ /*-Copyright (c) Robert Patrick Rankin, 2024. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1887,7 +1887,7 @@ wiz_custom(void) if (wizard) { static const char wizcustom[] = "#wizcustom"; winid win; - char buf[BUFSZ], bufa[BUFSZ]; + char buf[BUFSZ], bufa[BUFSZ]; int n; #if 0 int j, glyph; diff --git a/src/worn.c b/src/worn.c index 7e545370c..b7db2d94a 100644 --- a/src/worn.c +++ b/src/worn.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 worn.c $NHDT-Date: 1715109581 2024/05/07 19:19:41 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.109 $ */ +/* NetHack 3.7 worn.c $NHDT-Date: 1736530208 2025/01/10 09:30:08 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.116 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2013. */ /* NetHack may be freely redistributed. See license for details. */ @@ -162,7 +162,7 @@ setnotworn(struct obj *obj) *(wp->w_obj) = (struct obj *) 0; p = objects[obj->otyp].oc_oprop; u.uprops[p].extrinsic = u.uprops[p].extrinsic & ~wp->w_mask; - monstunseesu_prop(p); /* remove this extrinsic from seenres */ + monstunseesu_prop(p); /* remove this extrinsic from seenres */ obj->owornmask &= ~wp->w_mask; if (obj->oartifact) set_artifact_intrinsic(obj, 0, wp->w_mask); From 1928a3e12b91432f9f0ccfc00caf375db07de11c Mon Sep 17 00:00:00 2001 From: PatR Date: Fri, 10 Jan 2025 01:40:02 -0800 Subject: [PATCH 314/791] get rid of trailing space in generated tile.c --- win/share/tilemap.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/win/share/tilemap.c b/win/share/tilemap.c index 4842fc7a8..7ce828abe 100644 --- a/win/share/tilemap.c +++ b/win/share/tilemap.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 tilemap.c $NHDT-Date: 1640987372 2021/12/31 21:49:32 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.64 $ */ +/* NetHack 3.7 tilemap.c $NHDT-Date: 1736530790 2025/01/10 09:39:50 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.86 $ */ /* Copyright (c) 2016 by Michael Allison */ /* NetHack may be freely redistributed. See license for details. */ @@ -1362,7 +1362,7 @@ main(int argc UNUSED, char *argv[] UNUSED) #ifdef ENHANCED_SYMBOLS enhanced = ", 0"; /* replace ", utf8rep" since we're done with that */ #endif - Fprintf(ofp, "const glyph_info nul_glyphinfo = { \n"); + Fprintf(ofp, "const glyph_info nul_glyphinfo = {\n"); Fprintf(ofp, "%sNO_GLYPH, ' ', NO_COLOR,\n", indent); Fprintf(ofp, "%s%s/* glyph_map */\n", indent, indent); Fprintf(ofp, "%s%s{ %s, TILE_UNEXPLORED%s }\n", indent, indent, From 0e04988fec97bd48bb13750f401c264cb88c1d6d Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Fri, 10 Jan 2025 15:46:04 +0200 Subject: [PATCH 315/791] Fix another no_charge in untended shop This time the no_charge object was being carried by a pet. To trigger, drop an object into shop, decline to sell it, pick up an object belonging to shopkeeper, decline to buy it, wait for your pet to pick up the no_charge object you dropped, teleport out of the shop, wait for shopkeeper to walk out of the shop. --- src/shk.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/shk.c b/src/shk.c index 2828d5efe..dda59b9b8 100644 --- a/src/shk.c +++ b/src/shk.c @@ -74,6 +74,7 @@ staticfn void clear_unpaid_obj(struct monst *, struct obj *); staticfn void clear_unpaid(struct monst *, struct obj *); staticfn void clear_no_charge_obj(struct monst *, struct obj *); staticfn void clear_no_charge(struct monst *, struct obj *); +staticfn void clear_no_charge_pets(struct monst *); staticfn long check_credit(long, struct monst *); staticfn void pay(long, struct monst *); staticfn long get_cost(struct obj *, struct monst *); @@ -383,6 +384,17 @@ clear_no_charge(struct monst *shkp, struct obj *list) } } +/* clear no_charge from objects in pets' inventories belonging to shkp */ +staticfn void +clear_no_charge_pets(struct monst *shkp) +{ + struct monst *mtmp; + + for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) + if (mtmp->mtame && mtmp->minvent) + clear_no_charge(shkp, mtmp->minvent); +} + /* either you paid or left the shop or the shopkeeper died */ void setpaid(struct monst *shkp) @@ -1383,6 +1395,7 @@ hot_pursuit(struct monst *shkp) floor of this level (including inside containers on floor), even those that are in other shopkeepers' shops */ clear_no_charge((struct monst *) NULL, fobj); + clear_no_charge_pets(shkp); } /* Used when the shkp is teleported or falls (ox == 0) out of his shop, or From aa12620376a5c4a1354ea9146543003bc168fee9 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Fri, 10 Jan 2025 15:49:16 +0200 Subject: [PATCH 316/791] Fix vision with temporary clouds over pools Vision wasn't cleared correctly when a temporary [poison] cloud was over a pool and hero was under water while the cloud disappeared. --- src/region.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/region.c b/src/region.c index b38f0487f..60001f866 100644 --- a/src/region.c +++ b/src/region.c @@ -357,11 +357,14 @@ remove_region(NhRegion *reg) reg->ttl = -2L; /* for visible_region_at */ if (reg->visible) { int pass; + boolean tmp_uinwater = u.uinwater; /* need to process the region's spots twice, first unblocking all locations which no longer block line-of-sight, then redrawing spots within revised line-of-sight; skip second pass if blind */ for (pass = 1; pass <= (Blind ? 1 : 2); ++pass) { + u.uinwater = (pass == 1) ? 0 : tmp_uinwater; + for (x = reg->bounding_box.lx; x <= reg->bounding_box.hx; x++) for (y = reg->bounding_box.ly; y <= reg->bounding_box.hy; y++) if (isok(x, y) && inside_region(reg, x, y)) { @@ -374,6 +377,7 @@ remove_region(NhRegion *reg) } } } + u.uinwater = tmp_uinwater; } free_region(reg); } From 539f039a83f95b94569a91b72709d28e0c9c2b48 Mon Sep 17 00:00:00 2001 From: PatR Date: Fri, 10 Jan 2025 14:14:00 -0800 Subject: [PATCH 317/791] maybe fix #K4316 - segfault stumbling onto mimic I couldn't reproduce the reported problem but the backtrace suggests that defsyms[monst->mappearance] was probably out of bounds so that nh_snprintf() got bad data. That might conceivably happen if the glyph didn't match the mimic's mappearance, but I not sure how that would occur. This avoids using mappearance as an index into defsyms[] and should give an impossible if that situation does come up. --- src/uhitm.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/uhitm.c b/src/uhitm.c index 513b697a9..006dfc46b 100644 --- a/src/uhitm.c +++ b/src/uhitm.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 uhitm.c $NHDT-Date: 1732979463 2024/11/30 07:11:03 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.451 $ */ +/* NetHack 3.7 uhitm.c $NHDT-Date: 1736575153 2025/01/10 21:59:13 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.461 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -6070,12 +6070,20 @@ that_is_a_mimic( else if (M_AP_TYPE(mtmp) == M_AP_MONSTER) what = a_monnam(mtmp); /* differs from what was sensed */ } else { - int glyph = levl[u.ux + u.dx][u.uy + u.dy].glyph; + int glyph = glyph_at(u.ux + u.dx, u.uy + u.dy); if (glyph_is_cmap(glyph)) { + int sym = glyph_to_cmap(glyph); + +#ifdef EXTRA_SANITY_CHECKS + if (iflags.sanity_check && (int) mtmp->mappearance != sym) + impossible("mimic appearance %u does not match" + " map feature %d (glyph=%d)", + mtmp->mappearance, sym, glyph); +#endif /* note: defsyms[stairs] yields singular "staircase {up|down}" */ Snprintf(fmtbuf, sizeof fmtbuf, "That %s actually is %%s!", - defsyms[mtmp->mappearance].explanation); + defsyms[sym].explanation); } else if (glyph_is_object(glyph)) { boolean fakeobj; const char *otmp_name; From 0fe42a67d0d47e24aabff6c93aa5e0ec38517e22 Mon Sep 17 00:00:00 2001 From: PatR Date: Fri, 10 Jan 2025 20:52:25 -0800 Subject: [PATCH 318/791] eshkp->bill_p vs eshkp->bill Use ESHK(shkp)->bill_p consistently. The bill[] array field is used to initialize the bill_p pointer field rather than be used directly when manipulating shop bills. While in there, get rid of some '#if DUMB' from pre-standard C days. --- src/shk.c | 43 ++++++++++--------------------------------- 1 file changed, 10 insertions(+), 33 deletions(-) diff --git a/src/shk.c b/src/shk.c index dda59b9b8..8a521cb26 100644 --- a/src/shk.c +++ b/src/shk.c @@ -1173,19 +1173,12 @@ obfree(struct obj *obj, struct obj *merge) merge->unpaid ? 1 : 0); return; } else { + struct eshk *eshkp = ESHK(shkp); + /* this was a merger */ bpm->bquan += bp->bquan; - ESHK(shkp)->billct--; -#ifdef DUMB - { - /* DRS/NS 2.2.6 messes up -- Peter Kendell */ - int indx = ESHK(shkp)->billct; - - *bp = ESHK(shkp)->bill_p[indx]; - } -#else - *bp = ESHK(shkp)->bill_p[ESHK(shkp)->billct]; -#endif + eshkp->billct--; + *bp = eshkp->bill_p[eshkp->billct]; } } else { /* not on bill; if the item is being merged away rather than @@ -2139,7 +2132,7 @@ update_bill( *bp = eshkp->bill_p[newebillct]; for (j = 0; j < ibillct; ++j) if (ibill[j].bidx == newebillct) - ibill[j].bidx = (int) (bp - eshkp->bill); + ibill[j].bidx = (int) (bp - eshkp->bill_p); eshkp->billct = newebillct; /* eshkp->billct - 1 */ } return; @@ -3153,7 +3146,7 @@ gem_learned(int oindx) for (shkp = next_shkp(fmon, TRUE); shkp; shkp = next_shkp(shkp->nmon, TRUE)) { ct = ESHK(shkp)->billct; - bp = ESHK(shkp)->bill; + bp = ESHK(shkp)->bill_p; while (--ct >= 0) { obj = find_oid(bp->bo_id); if (!obj) /* shouldn't happen */ @@ -3593,6 +3586,7 @@ staticfn void sub_one_frombill(struct obj *obj, struct monst *shkp) { struct bill_x *bp; + struct eshk *eshkp; if ((bp = onbill(obj, shkp, FALSE)) != 0) { struct obj *otmp; @@ -3610,17 +3604,9 @@ sub_one_frombill(struct obj *obj, struct monst *shkp) add_to_billobjs(otmp); return; } - ESHK(shkp)->billct--; -#ifdef DUMB - { - /* DRS/NS 2.2.6 messes up -- Peter Kendell */ - int indx = ESHK(shkp)->billct; - - *bp = ESHK(shkp)->bill_p[indx]; - } -#else - *bp = ESHK(shkp)->bill_p[ESHK(shkp)->billct]; -#endif + eshkp = ESHK(shkp); + eshkp->billct--; + *bp = eshkp->bill_p[eshkp->billct]; return; } else if (obj->unpaid) { impossible("sub_one_frombill: unpaid object not on bill"); @@ -5954,16 +5940,7 @@ globby_bill_fixup(struct obj *obj_absorber, struct obj *obj_absorbed) /* the glob being absorbed has a billing record */ amount = bp->price; eshkp->billct--; -#ifdef DUMB - { - /* DRS/NS 2.2.6 messes up -- Peter Kendell */ - int indx = eshkp->billct; - - *bp = eshkp->bill_p[indx]; - } -#else *bp = eshkp->bill_p[eshkp->billct]; -#endif clear_unpaid_obj(shkp, obj_absorbed); if (bp_absorber) { From cba032d187837708d03ccc9e4a222c0c8d2b93c3 Mon Sep 17 00:00:00 2001 From: PatR Date: Sat, 11 Jan 2025 02:22:23 -0800 Subject: [PATCH 319/791] another mimic fix The report (sent directly to devteam) stated that the bump-into-mimic code might crash when bumping into a mimic that is masqueraing as some other monster. Mimics don't actually do that, but the Wizard of Yendor mimics another monster via Double Trouble. All I got from it though is |Wait! That's ! which won't crash but is a fairly useless message. This changes it to be |Wait! That is ! which seems a bit bland but provides useful information. --- src/uhitm.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/uhitm.c b/src/uhitm.c index 006dfc46b..bd4ce823d 100644 --- a/src/uhitm.c +++ b/src/uhitm.c @@ -6099,12 +6099,27 @@ that_is_a_mimic( otmp->where = OBJ_FREE; /* object_from_map set to OBJ_FLOOR */ dealloc_obj(otmp); } + } else if (glyph_is_monster(glyph)) { + const char *mtmp_name; + int sym = glyph_to_mon(glyph); + +#ifdef EXTRA_SANITY_CHECKS + if (iflags.sanity_check && (int) mtmp->mappearance != sym) + impossible("mimic appearance %u does not match" + " monster #%d (glyph=%d)", + mtmp->mappearance, sym, glyph); +#endif + mtmp_name = pmname(&mons[sym], Mgender(mtmp)); + Snprintf(fmtbuf, sizeof fmtbuf, + "Wait! That %s is %%s!", mtmp_name); } /* cloned Wiz starts out mimicking some other monster and might make himself invisible before being revealed */ if (mtmp->minvis && !See_invisible) what = generic; + else if (M_AP_TYPE(mtmp) == M_AP_MONSTER) + what = x_monnam(mtmp, ARTICLE_A, (char *) NULL, EXACT_NAME, TRUE); else if (mtmp->data->mlet == S_MIMIC && (M_AP_TYPE(mtmp) == M_AP_OBJECT || M_AP_TYPE(mtmp) == M_AP_FURNITURE) From 59f49fda1b77eeb58c6a7a187910935a5d104875 Mon Sep 17 00:00:00 2001 From: PatR Date: Sat, 11 Jan 2025 12:24:54 -0800 Subject: [PATCH 320/791] replace the mimic-as-monster fix The new EXTRA_SANITY_CHECK for a monster mimicking a monster. It falsely triggered if the hero was hallucinating. Just add an assertion that the monster index is within valid range. --- src/uhitm.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/uhitm.c b/src/uhitm.c index bd4ce823d..3b233c152 100644 --- a/src/uhitm.c +++ b/src/uhitm.c @@ -6101,17 +6101,12 @@ that_is_a_mimic( } } else if (glyph_is_monster(glyph)) { const char *mtmp_name; - int sym = glyph_to_mon(glyph); + int mndx = glyph_to_mon(glyph); -#ifdef EXTRA_SANITY_CHECKS - if (iflags.sanity_check && (int) mtmp->mappearance != sym) - impossible("mimic appearance %u does not match" - " monster #%d (glyph=%d)", - mtmp->mappearance, sym, glyph); -#endif - mtmp_name = pmname(&mons[sym], Mgender(mtmp)); + assert(mndx >= LOW_PM && mndx <= HIGH_PM); + mtmp_name = pmname(&mons[mndx], Mgender(mtmp)); Snprintf(fmtbuf, sizeof fmtbuf, - "Wait! That %s is %%s!", mtmp_name); + "Wait! That %s is really %%s!", mtmp_name); } /* cloned Wiz starts out mimicking some other monster and From 9b7bcf67ba2168eca6924f772dcfa87030c5a15e Mon Sep 17 00:00:00 2001 From: SHIRAKATA Kentaro Date: Sun, 12 Jan 2025 14:37:13 +0900 Subject: [PATCH 321/791] change the type of xytod()'s return value to int xytod()'s return value is an index, so its type should be int, not coordxy. --- include/extern.h | 2 +- src/cmd.c | 2 +- src/trap.c | 3 ++- src/zap.c | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/include/extern.h b/include/extern.h index f6063cef9..e8a4f29d9 100644 --- a/include/extern.h +++ b/include/extern.h @@ -414,7 +414,7 @@ extern int enter_explore_mode(void); extern boolean bind_mousebtn(int, const char *); extern boolean bind_key(uchar, const char *); extern void dokeylist(void); -extern coordxy xytod(coordxy, coordxy); +extern int xytod(coordxy, coordxy); extern void dtoxy(coord *, int); extern int movecmd(char, int); extern int dxdy_moveok(void); diff --git a/src/cmd.c b/src/cmd.c index d6ac2c580..51524a199 100644 --- a/src/cmd.c +++ b/src/cmd.c @@ -3604,7 +3604,7 @@ rhack(int key) } /* convert an x,y pair into a direction code */ -coordxy +int xytod(coordxy x, coordxy y) { int dd; diff --git a/src/trap.c b/src/trap.c index 38b970aa6..2664fbf0a 100644 --- a/src/trap.c +++ b/src/trap.c @@ -6436,7 +6436,8 @@ conjoined_pits( struct trap *trap1, boolean u_entering_trap2) { - coordxy dx, dy, diridx, adjidx; + coordxy dx, dy; + int diridx, adjidx; if (!trap1 || !trap2) return FALSE; diff --git a/src/zap.c b/src/zap.c index 7fc54146e..a9e63105d 100644 --- a/src/zap.c +++ b/src/zap.c @@ -4126,7 +4126,7 @@ boomhit(struct obj *obj, coordxy dx, coordxy dy) gb.bhitpos.x = u.ux; gb.bhitpos.y = u.uy; boom = counterclockwise ? S_boomleft : S_boomright; - i = (int) xytod(dx, dy); + i = xytod(dx, dy); tmp_at(DISP_FLASH, cmap_to_glyph(boom)); for (ct = 0; ct < 10; ct++) { i = DIR_CLAMP(i); From f0a0a74dcc793189be7f799d95a34016e23c4110 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sun, 12 Jan 2025 16:42:33 +0200 Subject: [PATCH 322/791] Hero polyed into slithy monster and sitting --- src/sit.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/sit.c b/src/sit.c index 1f919d922..324e1d75c 100644 --- a/src/sit.c +++ b/src/sit.c @@ -316,7 +316,10 @@ dosit(void) } else if (obj->otyp == TOWEL) { pline("It's probably not a good time for a picnic..."); } else { - You("sit on %s.", the(xname(obj))); + if (slithy(gy.youmonst.data)) + You("coil up around %s.", the(xname(obj))); + else + You("sit on %s.", the(xname(obj))); if (obj->otyp == CORPSE && amorphous(&mons[obj->corpsenm])) pline("It's squishy..."); else if (obj->otyp == CREAM_PIE) { From 97e0e934e81d2f63376fb1d40524c244efd38533 Mon Sep 17 00:00:00 2001 From: Alex Smith Date: Sun, 12 Jan 2025 18:20:13 +0000 Subject: [PATCH 323/791] Use a common funcion for all monster healing Previously, the code for monster healing was repeated every time it was needed; this commit sends it all through a common function, which will make it easier to make changes to how monster healing works in the future. This is just a code reorganisation and won't have any gameplay effect unless I made a mistake. --- include/extern.h | 1 + src/artifact.c | 8 ++------ src/do.c | 2 +- src/dog.c | 5 +---- src/mcastu.c | 3 +-- src/mhitm.c | 6 ++---- src/mon.c | 49 ++++++++++++++++++++++++++++++++++++++++-------- src/muse.c | 10 +++------- src/potion.c | 6 ++---- src/uhitm.c | 4 +--- src/were.c | 2 +- src/wizard.c | 2 +- src/zap.c | 7 ++----- 13 files changed, 59 insertions(+), 46 deletions(-) diff --git a/include/extern.h b/include/extern.h index f6063cef9..27168a3c3 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1756,6 +1756,7 @@ extern struct monst *get_iter_mons(boolean (*)(struct monst *)); extern struct monst *get_iter_mons_xy(boolean (*)(struct monst *, coordxy, coordxy), coordxy, coordxy); +extern int healmon(struct monst *, int, int) NONNULLARG1; extern void rescham(void); extern void restartcham(void); extern void restore_cham(struct monst *) NONNULLARG1; diff --git a/src/artifact.c b/src/artifact.c index 446e4ab95..7b9c3864f 100644 --- a/src/artifact.c +++ b/src/artifact.c @@ -1636,9 +1636,7 @@ artifact_hit( healup(drain, 0, FALSE, FALSE); } else { assert(magr != 0); - magr->mhp += drain; - if (magr->mhp > magr->mhpmax) - magr->mhp = magr->mhpmax; + healmon(magr, drain, 0); } } return vis; @@ -1664,9 +1662,7 @@ artifact_hit( } losexp("life drainage"); if (magr && magr->mhp < magr->mhpmax) { - magr->mhp += (abs(oldhpmax - u.uhpmax) + 1) / 2; - if (magr->mhp > magr->mhpmax) - magr->mhp = magr->mhpmax; + healmon(magr, (abs(oldhpmax - u.uhpmax) + 1) / 2, 0); } return TRUE; } diff --git a/src/do.c b/src/do.c index e9be24ca0..4f633979a 100644 --- a/src/do.c +++ b/src/do.c @@ -876,7 +876,7 @@ engulfer_digests_food(struct obj *obj) } else if (could_grow) { (void) grow_up(u.ustuck, (struct monst *) 0); } else if (could_heal) { - u.ustuck->mhp = u.ustuck->mhpmax; + healmon(u.ustuck, u.ustuck->mhpmax, 0); /* False: don't realize that sight is cured from inside */ mcureblindness(u.ustuck, FALSE); } diff --git a/src/dog.c b/src/dog.c index 53d3aea66..4b523db7c 100644 --- a/src/dog.c +++ b/src/dog.c @@ -675,10 +675,7 @@ mon_catchup_elapsed_time( /* recover lost hit points */ if (!regenerates(mtmp->data)) imv /= 20; - if (mtmp->mhp + imv >= mtmp->mhpmax) - mtmp->mhp = mtmp->mhpmax; - else - mtmp->mhp += imv; + healmon(mtmp, imv, 0); set_mon_lastmove(mtmp); } diff --git a/src/mcastu.c b/src/mcastu.c index 4ac28f956..95e9a1c65 100644 --- a/src/mcastu.c +++ b/src/mcastu.c @@ -363,8 +363,7 @@ m_cure_self(struct monst *mtmp, int dmg) if (canseemon(mtmp)) pline_mon(mtmp, "%s looks better.", Monnam(mtmp)); /* note: player healing does 6d4; this used to do 1d8 */ - if ((mtmp->mhp += d(3, 6)) > mtmp->mhpmax) - mtmp->mhp = mtmp->mhpmax; + healmon(mtmp, d(3, 6), 0); dmg = 0; } return dmg; diff --git a/src/mhitm.c b/src/mhitm.c index eb3bcccda..1380148ed 100644 --- a/src/mhitm.c +++ b/src/mhitm.c @@ -1093,7 +1093,7 @@ mdamagem( return (M_ATTK_DEF_DIED | (!DEADMONSTER(magr) ? 0 : M_ATTK_AGR_DIED)); } else if (pd == &mons[PM_NURSE]) { - magr->mhp = magr->mhpmax; + healmon(magr, magr->mhpmax, 0); } mon_givit(magr, pd); } @@ -1390,9 +1390,7 @@ passivemm( } if (canseemon(magr)) pline_mon(magr, "%s is suddenly very cold!", Monnam(magr)); - mdef->mhp += tmp / 2; - if (mdef->mhpmax < mdef->mhp) - mdef->mhpmax = mdef->mhp; + healmon(mdef, tmp/2, tmp/2); if (mdef->mhpmax > ((int) (mdef->m_lev + 1) * 8)) (void) split_mon(mdef, magr); break; diff --git a/src/mon.c b/src/mon.c index 545283c8d..a59b1a13a 100644 --- a/src/mon.c +++ b/src/mon.c @@ -1351,9 +1351,7 @@ m_consume_obj(struct monst *mtmp, struct obj *otmp) /* non-pet: Heal up to the object's weight in hp */ if (!ispet && mtmp->mhp < mtmp->mhpmax) { - mtmp->mhp += objects[otmp->otyp].oc_weight; - if (mtmp->mhp > mtmp->mhpmax) - mtmp->mhp = mtmp->mhpmax; + healmon(mtmp, objects[otmp->otyp].oc_weight, 0); } if (Has_contents(otmp)) meatbox(mtmp, otmp); @@ -1398,7 +1396,7 @@ m_consume_obj(struct monst *mtmp, struct obj *otmp) } } if (heal) - mtmp->mhp = mtmp->mhpmax; + healmon(mtmp, mtmp->mhpmax, 0); if ((eyes || heal) && !mtmp->mcansee) mcureblindness(mtmp, canseemon(mtmp)); if (ispet && deadmimic) @@ -4462,6 +4460,44 @@ get_iter_mons_xy( } +/* Heal the given monster by amt hitpoints, unless it is somehow prevented + from healing. "overheal" is the maximum amount by which the max HP will + increase to allow for the healing (the resulting HP caps at max HP + + overheal, and the max HP stays the some unless it needs to increase to + accommodate the new HP). Overhealing the player is not currently + implemented by this method. + + This function should only be used for situations which are conceptually + heals, rather than other situations where a monster's HP is set, so that + "prevent healing" effects work correctly. In particular, it should not + be used for cases where a monster's HP is restored upon revival, or when + a monster is created. It also shouldn't be used for lifesaving, which + overrides "cannot heal" effects. + + amt and overheal must not be negative (0 is allowed, and a very common + amount for overheal). Returns the number of hitpoints healed. */ +int +healmon(struct monst *mtmp, int amt, int overheal) +{ + if (mtmp == &gy.youmonst) { + int oldhp = Upolyd ? u.mh : u.uhp; + healup(amt, 0, 0, 0); + return (Upolyd ? u.mh : u.uhp) - oldhp; + } else { + int oldhp = mtmp->mhp; + if (mtmp->mhp + amt > mtmp->mhpmax + overheal) { + mtmp->mhpmax += overheal; + mtmp->mhp = mtmp->mhpmax; + } else { + mtmp->mhp += amt; + if (mtmp->mhp > mtmp->mhpmax) + mtmp->mhpmax = mtmp->mhp; + } + return mtmp->mhp - oldhp; + } +} + + /* force all chameleons and mimics to become themselves and werecreatures to revert to human form; called when Protection_from_shape_changers gets activated via wearing or eating ring or via #wizintrinsic */ @@ -5535,10 +5571,7 @@ golemeffects(struct monst *mon, int damtype, int dam) mon_adjust_speed(mon, -1, (struct obj *) 0); } if (heal) { - if (mon->mhp < mon->mhpmax) { - mon->mhp += heal; - if (mon->mhp > mon->mhpmax) - mon->mhp = mon->mhpmax; + if (healmon(mon, heal, 0)) { if (cansee(mon->mx, mon->my)) pline_mon(mon, "%s seems healthier.", Monnam(mon)); } diff --git a/src/muse.c b/src/muse.c index 264d6b9ab..54c92f4d0 100644 --- a/src/muse.c +++ b/src/muse.c @@ -1139,9 +1139,7 @@ use_defensive(struct monst *mtmp) case MUSE_POT_HEALING: mquaffmsg(mtmp, otmp); i = d(6 + 2 * bcsign(otmp), 4); - mtmp->mhp += i; - if (mtmp->mhp > mtmp->mhpmax) - mtmp->mhp = ++mtmp->mhpmax; + healmon(mtmp, i, 1); if (!otmp->cursed && !mtmp->mcansee) mcureblindness(mtmp, vismon); if (vismon) @@ -1153,9 +1151,7 @@ use_defensive(struct monst *mtmp) case MUSE_POT_EXTRA_HEALING: mquaffmsg(mtmp, otmp); i = d(6 + 2 * bcsign(otmp), 8); - mtmp->mhp += i; - if (mtmp->mhp > mtmp->mhpmax) - mtmp->mhp = (mtmp->mhpmax += (otmp->blessed ? 5 : 2)); + healmon(mtmp, i, otmp->blessed ? 5 : 2); if (!mtmp->mcansee) mcureblindness(mtmp, vismon); if (vismon) @@ -1168,7 +1164,7 @@ use_defensive(struct monst *mtmp) mquaffmsg(mtmp, otmp); if (otmp->otyp == POT_SICKNESS) unbless(otmp); /* Pestilence */ - mtmp->mhp = (mtmp->mhpmax += (otmp->blessed ? 8 : 4)); + healmon(mtmp, mtmp->mhpmax, otmp->blessed ? 8 : 4); if (!mtmp->mcansee && otmp->otyp != POT_SICKNESS) mcureblindness(mtmp, vismon); if (vismon) diff --git a/src/potion.c b/src/potion.c index 9d5a89fc8..7bec2fcea 100644 --- a/src/potion.c +++ b/src/potion.c @@ -1740,7 +1740,7 @@ potionhit(struct monst *mon, struct obj *obj, int how) do_healing: angermon = FALSE; if (mon->mhp < mon->mhpmax) { - mon->mhp = mon->mhpmax; + healmon(mon, mon->mhpmax, 0); if (canseemon(mon)) pline("%s looks sound and hale again.", Monnam(mon)); } @@ -1827,9 +1827,7 @@ potionhit(struct monst *mon, struct obj *obj, int how) angermon = FALSE; if (canseemon(mon)) pline("%s looks healthier.", Monnam(mon)); - mon->mhp += d(2, 6); - if (mon->mhp > mon->mhpmax) - mon->mhp = mon->mhpmax; + healmon(mon, d(2, 6), 0); if (is_were(mon->data) && is_human(mon->data) && !Protection_from_shape_changers) new_were(mon); /* transform into beast */ diff --git a/src/uhitm.c b/src/uhitm.c index 3b233c152..b3b470c00 100644 --- a/src/uhitm.c +++ b/src/uhitm.c @@ -5931,9 +5931,7 @@ passive( You("are suddenly very cold!"); mdamageu(mon, tmp); /* monster gets stronger with your heat! */ - mon->mhp += (tmp + rn2(2)) / 2; - if (mon->mhpmax < mon->mhp) - mon->mhpmax = mon->mhp; + healmon(mon, (tmp + rn2(2)) / 2, (tmp + 1) / 2); /* at a certain point, the monster will reproduce! */ if (mon->mhpmax > (((int) mon->m_lev) + 1) * 8) (void) split_mon(mon, &gy.youmonst); diff --git a/src/were.c b/src/were.c index 0832555f1..9baa4155e 100644 --- a/src/were.c +++ b/src/were.c @@ -123,7 +123,7 @@ new_were(struct monst *mon) mon->mcanmove = 1; } /* regenerate by 1/4 of the lost hit points */ - mon->mhp += (mon->mhpmax - mon->mhp) / 4; + healmon(mon, (mon->mhpmax - mon->mhp) / 4, 0); newsym(mon->mx, mon->my); mon_break_armor(mon, FALSE); possibly_unwield(mon, FALSE); diff --git a/src/wizard.c b/src/wizard.c index ce064615c..3e28a6360 100644 --- a/src/wizard.c +++ b/src/wizard.c @@ -396,7 +396,7 @@ tactics(struct monst *mtmp) /* if you're not around, cast healing spells */ if (distu(mx, my) > (BOLT_LIM * BOLT_LIM)) if (mtmp->mhp <= mtmp->mhpmax - 8) { - mtmp->mhp += rnd(8); + healmon(mtmp, rnd(8), 0); return 1; } FALLTHROUGH; diff --git a/src/zap.c b/src/zap.c index 7fc54146e..f83604778 100644 --- a/src/zap.c +++ b/src/zap.c @@ -434,9 +434,7 @@ bhitm(struct monst *mtmp, struct obj *otmp) int delta = mtmp->mhpmax - mtmp->mhp; wake = FALSE; /* wakeup() makes the target angry */ - mtmp->mhp += healamt; - if (mtmp->mhp > mtmp->mhpmax) - mtmp->mhp = mtmp->mhpmax; + healmon(mtmp, healamt, 0); /* plain healing must be blessed to cure blindness; extra healing only needs to not be cursed, so spell always cures [potions quaffed by monsters behave slightly differently; @@ -4250,10 +4248,9 @@ zhitm( case ZT_DEATH: /* death/disintegration */ if (abs(type) != ZT_BREATH(ZT_DEATH)) { /* death */ if (mon->data == &mons[PM_DEATH]) { - mon->mhpmax += mon->mhpmax / 2; + healmon(mon, mon->mhpmax * 3 / 2, mon->mhpmax / 2); if (mon->mhpmax >= MAGIC_COOKIE) mon->mhpmax = MAGIC_COOKIE - 1; - mon->mhp = mon->mhpmax; tmp = 0; break; } From a8be0219137d39ed45165ca783f6bf2b06a516d5 Mon Sep 17 00:00:00 2001 From: Alex Smith Date: Sun, 12 Jan 2025 18:28:59 +0000 Subject: [PATCH 324/791] Change monster regeneration over time to use healmon(), too I missed this one. --- src/monmove.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/monmove.c b/src/monmove.c index a460e9841..fb8adfd48 100644 --- a/src/monmove.c +++ b/src/monmove.c @@ -295,9 +295,8 @@ onscary(coordxy x, coordxy y, struct monst *mtmp) void mon_regen(struct monst *mon, boolean digest_meal) { - if (mon->mhp < mon->mhpmax - && (svm.moves % 20 == 0 || regenerates(mon->data))) - mon->mhp++; + if (svm.moves % 20 == 0 || regenerates(mon->data)) + healmon(mon, 1, 0); if (mon->mspec_used) mon->mspec_used--; if (digest_meal) { From bee21e34470eed7f2d8566b3e70e42afc51cc5c1 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 12 Jan 2025 13:50:25 -0500 Subject: [PATCH 325/791] fix K4318 Reported by paxed. A potion of oil, that was already in the midst of exploding, got picked up through spot_effects(), which led to it merging with another potion of oil and the freeing of the original obj. The original obj pointer was still held by breakobj(), and breakobj() proceeded to delete the obj (again). Function nesting: 1 spelleffects() 2 -> weffects() 3 -> bhit() 4 -> bhitpile() 5 -> bhito(obj ...) 6 -> hero_breaks(obj ...) 7 -> breakobj(obj ...) 8 -> explode_oil(obj ...) 9 -> splatter_burning_oil() 10 -> explode() 11 -> zap_over_floor() 12 -> melt_ice() 13 -> spot_effects() 14 -> pickup() 15 -> pickup_object(obj ...) 16 -> pick_obj(obj ...) 17 -> addinv(obj ...) 18 -> addinv_core0(obj ...) 19 -> merged(obj ...) 20 -> obfree(obj ...) 21 -> dealloc_obj(obj ...) 8 -> delobj(obj ...) 9 -> delobj_core(obj ...) 10 -> obfree(obj ...) 11 -> dealloc_obj(obj ...) 12 -> impossible("obj already deleted) This marks the exploding potion with LOST_EXPLODING, so that it won't get picked up, or merged with another object during the long sequence of functions, and that should take care of 15-21 above. --- include/obj.h | 10 ++++++---- src/explode.c | 1 + src/invent.c | 2 ++ src/pickup.c | 6 ++++-- 4 files changed, 13 insertions(+), 6 deletions(-) diff --git a/include/obj.h b/include/obj.h index f841725ef..ccab26f6e 100644 --- a/include/obj.h +++ b/include/obj.h @@ -469,10 +469,12 @@ struct obj { #define POTHIT_OTHER_THROW 3 /* propelled by some other means [scatter()] */ /* tracking how an item left your inventory via how_lost field */ -#define LOST_NONE 0 /* still in inventory, or method not covered below */ -#define LOST_THROWN 1 /* thrown or fired by the hero */ -#define LOST_DROPPED 2 /* dropped or tipped out of a container by the hero */ -#define LOST_STOLEN 3 /* stolen from hero's inventory by a monster */ +#define LOST_NONE 0 /* still in inventory, or method not covered below */ +#define LOST_THROWN 1 /* thrown or fired by the hero */ +#define LOST_DROPPED 2 /* dropped or tipped out of a container by the hero */ +#define LOST_STOLEN 3 /* stolen from hero's inventory by a monster */ +#define LOSTOVERRIDEMASK 0x3 +#define LOST_EXPLODING 4 /* the object is exploding (i.e. POT_OIL) */ /* tracking how a name got acquired by an object in named_how field */ #define NAMED_PLAIN 0 /* nothing special, typical naming */ diff --git a/src/explode.c b/src/explode.c index 18bf8d53c..36c3aca59 100644 --- a/src/explode.c +++ b/src/explode.c @@ -976,6 +976,7 @@ explode_oil(struct obj *obj, coordxy x, coordxy y) if (!obj->lamplit) impossible("exploding unlit oil"); end_burn(obj, TRUE); + obj->how_lost = LOST_EXPLODING; splatter_burning_oil(x, y, diluted_oil); } diff --git a/src/invent.c b/src/invent.c index 6f2cc2528..c3e46faad 100644 --- a/src/invent.c +++ b/src/invent.c @@ -4943,6 +4943,8 @@ mergable( if (obj->cursed != otmp->cursed || obj->blessed != otmp->blessed) return FALSE; + if ((obj->how_lost & LOSTOVERRIDEMASK) != 0) + return FALSE; #if 0 /* don't require 'bypass' to match; that results in items dropped * via 'D' not stacking with compatible items already on the floor; * caller who wants that behavior should use 'nomerge' instead */ diff --git a/src/pickup.c b/src/pickup.c index a1c2ccb78..a01283cde 100644 --- a/src/pickup.c +++ b/src/pickup.c @@ -950,6 +950,8 @@ autopick_testobj(struct obj *otmp, boolean calc_costly) return TRUE; if (flags.nopick_dropped && otmp->how_lost == LOST_DROPPED) return FALSE; + if (otmp->how_lost == LOST_EXPLODING) + return FALSE; /* check for pickup_types */ pickit = (!*otypes || strchr(otypes, otmp->oclass)); @@ -1866,7 +1868,7 @@ pickup_object( couldn't pick up a thrown, stolen, or dropped item that was split off from a carried stack even while still carrying the rest of the stack unless we have at least one free slot available */ - obj->how_lost = LOST_NONE; /* affects merge_choice() */ + obj->how_lost &= ~LOSTOVERRIDEMASK; /* affects merge_choice() */ res = lift_object(obj, (struct obj *) 0, &count, telekinesis); obj->how_lost = save_how_lost; /* even when res > 0, * in case we call splitobj() below */ @@ -1879,7 +1881,7 @@ pickup_object( if (obj->quan != count && obj->otyp != LOADSTONE) obj = splitobj(obj, count); - obj->how_lost = LOST_NONE; + obj->how_lost &= ~LOSTOVERRIDEMASK; obj = pick_obj(obj); if (uwep && uwep == obj) From 25558e1e01aaa390a1c2df3a0da8e9bcfe17c991 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 12 Jan 2025 13:58:13 -0500 Subject: [PATCH 326/791] follow-up Check the correct bits before returning. --- src/invent.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/invent.c b/src/invent.c index c3e46faad..ed0652dc9 100644 --- a/src/invent.c +++ b/src/invent.c @@ -4943,7 +4943,7 @@ mergable( if (obj->cursed != otmp->cursed || obj->blessed != otmp->blessed) return FALSE; - if ((obj->how_lost & LOSTOVERRIDEMASK) != 0) + if ((obj->how_lost & ~LOSTOVERRIDEMASK) != 0) return FALSE; #if 0 /* don't require 'bypass' to match; that results in items dropped * via 'D' not stacking with compatible items already on the floor; From e08a9671dc40c6e13ca65157cb6a4fd9153d336e Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 12 Jan 2025 14:08:15 -0500 Subject: [PATCH 327/791] another follow-up: another bit is needed breaks savefiles and bones. --- include/obj.h | 6 +++--- include/patchlevel.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/obj.h b/include/obj.h index ccab26f6e..56a29a358 100644 --- a/include/obj.h +++ b/include/obj.h @@ -142,7 +142,7 @@ struct obj { Bitfield(bypass, 1); /* mark this as an object to be skipped by bhito() */ Bitfield(pickup_prev, 1); /* was picked up previously */ Bitfield(ghostly, 1); /* it just got placed into a bones file */ - Bitfield(how_lost, 2); /* stolen by mon or thrown, dropped by hero */ + Bitfield(how_lost, 3); /* stolen by mon or thrown, dropped by hero, etc */ Bitfield(named_how, 1); /* source of name per TODO in resetobjs() */ #if 0 @@ -150,9 +150,9 @@ struct obj { Bitfield(eknown, 1); /* effect known for wands zapped or rings worn when * not seen yet after being picked up while blind * [maybe for remaining stack of used potion too] */ - /* 6 free bits */ + /* 5 free bits */ #else - /* 7 free bits */ + /* 6 free bits */ #endif int corpsenm; /* type of corpse is mons[corpsenm] */ diff --git a/include/patchlevel.h b/include/patchlevel.h index f29a68d9a..643ffba38 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 114 +#define EDITLEVEL 115 /* * Development status possibilities. From 36443c965b2af160ffd3711b40aa1dc78d0f0343 Mon Sep 17 00:00:00 2001 From: SHIRAKATA Kentaro Date: Sun, 12 Jan 2025 18:26:01 +0900 Subject: [PATCH 328/791] second argument of check_version() can take NULL There is a code path starting at restore.c line 830. (void) validate(nhfp, (char *) 0, FALSE); --- include/extern.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/extern.h b/include/extern.h index 27168a3c3..8b9abd848 100644 --- a/include/extern.h +++ b/include/extern.h @@ -3476,7 +3476,7 @@ extern int doextversion(void); extern boolean comp_times(long); #endif extern boolean check_version(struct version_info *, const char *, boolean, - unsigned long) NONNULLARG12; + unsigned long) NONNULLARG1; extern boolean uptodate(NHFILE *, const char *, unsigned long) NONNULLARG1; extern void store_formatindicator(NHFILE *) NONNULLARG1; extern void store_version(NHFILE *) NONNULLARG1; From 8ee014f5d13c00bccaf2578a7159b58d58047835 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 12 Jan 2025 23:57:56 -0500 Subject: [PATCH 329/791] update credits --- doc/fixes3-7-0.txt | 4 ++-- win/share/monsters.txt | 52 +++++++++++++++++++++--------------------- 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index 4d9b7173a..a4db52429 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -2859,7 +2859,7 @@ always print a message when the hero teleports (pr #265 by copperwater) always print a message when the hero level teleports (pr #265 by copperwater) remove Sokoban luck penalties for actions you can't cheat with (pr #260 by copperwater) -sounds for minotaurs (pr #298 by NullCGT) +sounds for minotaurs (pr #298 by Kestrel Gregorich-Trevor) correct the Guidebook descriptions for msdos video_width and video_height to state that they work with video:vesa; the video:vga setting that was described there forces the 640x480x16 mode where video_width and @@ -2873,7 +2873,7 @@ allow themed rooms constrained by level difficulty (pr #344 by copperwater) add a varied form of LIBNH nethack library contribution (pr #385, #403 by apowers313) add cross-compile to WASM (pr #385, #403, #412 by apowers313) -differentiating gendered monster tiles (pr #430 by NullCGT) +differentiating gendered monster tiles (pr #430 by Kestrel Gregorich-Trevor) check bones data directly for deja vu messages (pr #374 by entrez) unify code for extracting an object from a monster's inventory (pr #455 by copperwater) diff --git a/win/share/monsters.txt b/win/share/monsters.txt index 1a655b6dd..acc435a2f 100644 --- a/win/share/monsters.txt +++ b/win/share/monsters.txt @@ -50,7 +50,7 @@ Z = (195, 195, 195) ................ } # -# Contributing artist: NullCGT 27-Dec-2020 +# Contributing artist: Kestrel Gregorich-Trevor 27-Dec-2020 # Female ants are slightly larger than male ants, just like in real # life. I could have added wings to the male ants, but I felt that # doing so would lead to some confusion. @@ -816,7 +816,7 @@ Z = (195, 195, 195) ................ } # -# Contributing artist: NullCGT 27-Dec-2020 +# Contributing artist: Kestrel Gregorich-Trevor 27-Dec-2020 # Female wolves are slightly smaller than male wolves. # There wasn't a great way to show this without making winter wolves # look very similar to winter wolf cubs, so I just made the female @@ -860,7 +860,7 @@ Z = (195, 195, 195) ...L.LLAA..PP... .....LL......... } -# Contributing artist: NullCGT 27-Dec-2020 +# Contributing artist: Kestrel Gregorich-Trevor 27-Dec-2020 # Female werewolves wear slightly different clothing. # # tile 43 (werewolf,female) @@ -1395,7 +1395,7 @@ Z = (195, 195, 195) .....CCA...CA... ................ } -# Contributing artist: NullCGT 27-Dec-2020 +# Contributing artist: Kestrel Gregorich-Trevor 27-Dec-2020 # Calico cats are almost exclusively female, so I turned the female cats # into calico cats. The other piece of logic behind this choice was that # players will probably really enjoy seeing different variants of their @@ -1781,7 +1781,7 @@ Z = (195, 195, 195) ....LLL.LLL..... ................ } -# Contributing artist: NullCGT 27-Dec-2020 +# Contributing artist: Kestrel Gregorich-Trevor 27-Dec-2020 # Female hobbits wear slightly different clothing. # # tile 91 (hobbit,female) @@ -1803,7 +1803,7 @@ Z = (195, 195, 195) ....LLL.LLL..... ................ } -# Note from contributing artist: NullCGT 27-Dec-2020 +# Note from contributing artist: Kestrel Gregorich-Trevor 27-Dec-2020 # Male and female dwarfs are not differentiated in any way whatsoever. # According to Terry Pratchett (in Unseen Academicals, if I remember # correctly) it is almost impossible to tell what gender a dwarf is, @@ -2551,7 +2551,7 @@ Z = (195, 195, 195) ................ ................ } -# Contributing artist: NullCGT 27-Dec-2020 +# Contributing artist: Kestrel Gregorich-Trevor 27-Dec-2020 # Female leprechauns are clean-shaven. Although of course not one # hundred percent accurate, it's convenient visual shorthand. # @@ -4797,7 +4797,7 @@ Z = (195, 195, 195) ..BF.LLAALLAFB.. ................ } -# Contributing artist: NullCGT 27-Dec-2020 +# Contributing artist: Kestrel Gregorich-Trevor 27-Dec-2020 # Female Aleax wears slightly different clothing. # # tile 249 (Aleax,female) @@ -4914,7 +4914,7 @@ Z = (195, 195, 195) ................ ................ } -# Contributing artist: NullCGT 27-Dec-2020 +# Contributing artist: Kestrel Gregorich-Trevor 27-Dec-2020 # Female archons are clean-shaven. Although of course not one # hundred percent accurate, it's convenient visual shorthand. # @@ -5108,7 +5108,7 @@ Z = (195, 195, 195) ....CA...C...... ................ } -# Note from contributing artist: NullCGT 27-Dec-2020 +# Note from contributing artist: Kestrel Gregorich-Trevor 27-Dec-2020 # Centaur tiles have no differentiation because the different types of # centaurs are already extremely difficult to tell apart from one another. # @@ -6518,7 +6518,7 @@ Z = (195, 195, 195) ................ ................ } -# Contributing artist: NullCGT 27-Dec-2020 +# Contributing artist: Kestrel Gregorich-Trevor 27-Dec-2020 # Female gnomes are clean-shaven. Although of course not one # hundred percent accurate, it's convenient visual shorthand. # @@ -6560,7 +6560,7 @@ Z = (195, 195, 195) ................ ................ } -# Contributing artist: NullCGT 27-Dec-2020 +# Contributing artist: Kestrel Gregorich-Trevor 27-Dec-2020 # Female gnome leaders are clean-shaven. Although of course not one # hundred percent accurate, it's convenient visual shorthand. # @@ -6640,7 +6640,7 @@ Z = (195, 195, 195) ................ ................ } -# Contributing artist: NullCGT 27-Dec-2020 +# Contributing artist: Kestrel Gregorich-Trevor 27-Dec-2020 # Female gnome rulers are clean-shaven. Although of course not one # hundred percent accurate, it's convenient visual shorthand. # @@ -6834,7 +6834,7 @@ Z = (195, 195, 195) .....CLJACLJAAAA ...LLLLJ.CLLLKAA } -# Contributing artist: NullCGT 27-Dec-2020 +# Contributing artist: Kestrel Gregorich-Trevor 27-Dec-2020 # Female frost giants are clean-shaven. Although of course not one # hundred percent accurate, it's convenient visual shorthand. # @@ -6990,7 +6990,7 @@ Z = (195, 195, 195) ....CLCACLCAAAAA ..LLLLL.LLLLLAA. } -# Contributing artist: NullCGT 27-Dec-2020 +# Contributing artist: Kestrel Gregorich-Trevor 27-Dec-2020 # Female minotaurs wear slightly different clothing. # # tile 363 (minotaur,female) @@ -7449,7 +7449,7 @@ Z = (195, 195, 195) ................ ................ } -# Contributing artist: NullCGT 27-Dec-2020 +# Contributing artist: Kestrel Gregorich-Trevor 27-Dec-2020 # Female gnome mummies are clean-shaven. Although of course not one # hundred percent accurate, it's convenient visual shorthand. # @@ -8099,7 +8099,7 @@ Z = (195, 195, 195) ....CJJJCLAAAAAA ..LLLLL.LLLLLAA. } -# Contributing artist: NullCGT 27-Dec-2020 +# Contributing artist: Kestrel Gregorich-Trevor 27-Dec-2020 # Female ogre tyrants have slightly different crowns. # # tile 421 (ogre tyrant,female) @@ -8292,7 +8292,7 @@ Z = (195, 195, 195) ....NAAEBAANN... ................ } -# Contributing artist: NullCGT 27-Dec-2020 +# Contributing artist: Kestrel Gregorich-Trevor 27-Dec-2020 # Female quantum mechanics have a different hairstyle and no beard. # # tile 431 (quantum mechanic,female) @@ -8314,7 +8314,7 @@ Z = (195, 195, 195) ....NAAEBAANN... ................ } -# Note from contributing artist: NullCGT 27-Dec-2020 +# Note from contributing artist: Kestrel Gregorich-Trevor 27-Dec-2020 # Male and female genetic engineers look the same, because the genetic # engineer tile is perfect. # @@ -9059,7 +9059,7 @@ Z = (195, 195, 195) .J.....LLAA..... ................ } -# Contributing artist: NullCGT 27-Dec-2020 +# Contributing artist: Kestrel Gregorich-Trevor 27-Dec-2020 # Female barrow wights look like old grandmothers with flyaway hair. I # kept the hair color the same and used a similar quantity of pixels so # that they look similar enough to the males that you can tell they are @@ -10243,7 +10243,7 @@ Z = (195, 195, 195) ................ ................ } -# Contributing artist: NullCGT 27-Dec-2020 +# Contributing artist: Kestrel Gregorich-Trevor 27-Dec-2020 # Female humans wear slightly different clothing. # # tile 533 (human,female) @@ -10322,7 +10322,7 @@ Z = (195, 195, 195) ................ ................ } -# Contributing artist: NullCGT 27-Dec-2020 +# Contributing artist: Kestrel Gregorich-Trevor 27-Dec-2020 # Female werejackals wear slightly different clothing. # # tile 537 (werejackal,female) @@ -10363,7 +10363,7 @@ Z = (195, 195, 195) ................ ................ } -# Contributing artist: NullCGT 27-Dec-2020 +# Contributing artist: Kestrel Gregorich-Trevor 27-Dec-2020 # Female werewolves wear slightly different clothing. # # tile 539 (werewolf,female) @@ -10594,7 +10594,7 @@ Z = (195, 195, 195) ................ ................ } -# Contributing artist: NullCGT 27-Dec-2020 +# Contributing artist: Kestrel Gregorich-Trevor 27-Dec-2020 # Female elven monarchs have slightly different crowns. # # tile 551 (elven monarch,female) @@ -10711,7 +10711,7 @@ Z = (195, 195, 195) .....BPPABPPAAAA ....BPPP.BPPPAAA } -# Contributing artist: NullCGT 27-Dec-2020 +# Contributing artist: Kestrel Gregorich-Trevor 27-Dec-2020 # Female guards are clean-shaven. Although of course not one # hundred percent accurate, it's convenient visual shorthand. # @@ -12995,7 +12995,7 @@ Z = (195, 195, 195) .....CJJ.JKJ.... ................ } -# Contributing artist: NullCGT 27-Dec-2020 +# Contributing artist: Kestrel Gregorich-Trevor 27-Dec-2020 # Female archeologist tile is a reference to a certain archeologist # known for raiding tombs. # From 34159d42e50c23ac31364639075e05dc8bcb9fc4 Mon Sep 17 00:00:00 2001 From: PatR Date: Mon, 13 Jan 2025 05:48:20 -0800 Subject: [PATCH 330/791] more PR #1364 --- src/version.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/version.c b/src/version.c index 6678b8d1e..fa4dd3d9b 100644 --- a/src/version.c +++ b/src/version.c @@ -362,6 +362,13 @@ check_version( boolean complain, unsigned long utdflags) { + if (!filename) { +#ifdef EXTRA_SANITY_CHECKS + impossible("check_version() called with" + " 'complain'=True but 'filename'=Null"); +#endif + complain = FALSE; /* 'complain' requires 'filename' for pline("%s") */ + } if ( #ifdef VERSION_COMPATIBILITY /* patchlevel.h */ version_data->incarnation < VERSION_COMPATIBILITY From 7e8a04b35a0ff0487a76f84efcf311d2919ee07a Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 13 Jan 2025 09:36:48 -0500 Subject: [PATCH 331/791] eliminate a couple of build warnings (noticed with clang) 2025-01-12T19:08:53.4759829Z ../win/curses/cursinvt.c:191:5: warning: unannotated fall-through between switch labels [-Wimplicit-fallthrough] 2025-01-12T19:08:53.4760198Z 191 | case KEY_RIGHT: 2025-01-12T19:08:53.4767986Z | ^ 2025-01-12T19:08:53.4967354Z ../win/curses/cursinvt.c:191:5: note: insert '__attribute__((fallthrough));' to silence this warning 2025-01-12T19:08:53.4967860Z 191 | case KEY_RIGHT: 2025-01-12T19:08:53.4968026Z | ^ 2025-01-12T19:08:53.4968219Z | __attribute__((fallthrough)); 2025-01-12T19:08:53.4968404Z ../win/curses/cursinvt.c:191:5: note: insert 'break;' to avoid fall-through 2025-01-12T19:08:53.4968583Z 191 | case KEY_RIGHT: 2025-01-12T19:08:53.4968709Z | ^ 2025-01-12T19:08:53.4968820Z | break; 2025-01-12T19:08:53.5099063Z 1 warning generated. 2025-01-12T19:08:53.8002074Z ../win/X11/winX.c:995:5: warning: unannotated fall-through between switch labels [-Wimplicit-fallthrough] 2025-01-12T19:08:53.8008155Z 995 | case NHW_TEXT: 2025-01-12T19:08:53.8008513Z | ^ 2025-01-12T19:08:53.8032511Z ../win/X11/winX.c:995:5: note: insert '__attribute__((fallthrough));' to silence this warning 2025-01-12T19:08:53.8032899Z 995 | case NHW_TEXT: 2025-01-12T19:08:53.8033057Z | ^ 2025-01-12T19:08:53.8033219Z | __attribute__((fallthrough)); 2025-01-12T19:08:53.8033395Z ../win/X11/winX.c:995:5: note: insert 'break;' to avoid fall-through 2025-01-12T19:08:53.8033644Z 995 | case NHW_TEXT: 2025-01-12T19:08:53.8033783Z | ^ 2025-01-12T19:08:53.8033912Z | break; 2025-01-12T19:08:53.8800783Z 1 warning generated. --- win/X11/winX.c | 3 ++- win/curses/cursinvt.c | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/win/X11/winX.c b/win/X11/winX.c index d9a7cacf4..db95dea15 100644 --- a/win/X11/winX.c +++ b/win/X11/winX.c @@ -991,7 +991,8 @@ X11_putstr(winid window, int attr, const char *str) X11_destroy_nhwindow(window); *wp = window_list[new_win]; window_list[new_win].type = NHW_NONE; /* allow re-use */ - /* fall through */ + FALLTHROUGH; + /*FALLTHRU*/ case NHW_TEXT: add_to_text_window(wp, attr, str); break; diff --git a/win/curses/cursinvt.c b/win/curses/cursinvt.c index 3b0749d5c..4095ceb5a 100644 --- a/win/curses/cursinvt.c +++ b/win/curses/cursinvt.c @@ -187,6 +187,7 @@ curs_scroll_invt(WINDOW *win UNUSED) res = 1; break; } + FALLTHROUGH; /*FALLTHRU*/ case KEY_RIGHT: case KEY_NPAGE: From 0a401253ce87878ec68e4e1b21e1baa6bd5cb9cb Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 13 Jan 2025 11:47:00 -0500 Subject: [PATCH 332/791] test CI warnings --- azure-pipelines.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index cdec5d7d5..fd6676566 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -165,6 +165,7 @@ steps: sudo apt-get -qq -y install libx11-dev libxaw7-dev xfonts-utils qtbase5-dev qtmultimedia5-dev qtbase5-dev-tools condition: and(eq( variables['Agent.OS'], 'Linux' ), eq( variables.buildTarget, 'all')) workingDirectory: $(Agent.BuildDirectory)/$(netHackPath) + warningTaskFilters: '\[\-W+.+\]|^((vs|ms)build|ant(\s+.+)?|gradle(w)?(\s+.+)?|grunt|gulp|maven(\s+.+)?|xamarin(android|ios)|xcode(\s+.+)?|cmake|build\s+.+)$' displayName: 'Getting linux build dependencies' - bash: | From 1a8395002f219310abb9c3c1f869be053274be19 Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 13 Jan 2025 11:47:57 -0500 Subject: [PATCH 333/791] Revert "eliminate a couple of build warnings (noticed with clang)" This reverts commit 7e8a04b35a0ff0487a76f84efcf311d2919ee07a. --- win/X11/winX.c | 3 +-- win/curses/cursinvt.c | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/win/X11/winX.c b/win/X11/winX.c index db95dea15..d9a7cacf4 100644 --- a/win/X11/winX.c +++ b/win/X11/winX.c @@ -991,8 +991,7 @@ X11_putstr(winid window, int attr, const char *str) X11_destroy_nhwindow(window); *wp = window_list[new_win]; window_list[new_win].type = NHW_NONE; /* allow re-use */ - FALLTHROUGH; - /*FALLTHRU*/ + /* fall through */ case NHW_TEXT: add_to_text_window(wp, attr, str); break; diff --git a/win/curses/cursinvt.c b/win/curses/cursinvt.c index 4095ceb5a..3b0749d5c 100644 --- a/win/curses/cursinvt.c +++ b/win/curses/cursinvt.c @@ -187,7 +187,6 @@ curs_scroll_invt(WINDOW *win UNUSED) res = 1; break; } - FALLTHROUGH; /*FALLTHRU*/ case KEY_RIGHT: case KEY_NPAGE: From 6dad19a4f6df1dd85a9605e0d6383c2dc3ceffba Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 13 Jan 2025 11:48:46 -0500 Subject: [PATCH 334/791] Revert "Revert "eliminate a couple of build warnings (noticed with clang)"" This reverts commit 1a8395002f219310abb9c3c1f869be053274be19. --- win/X11/winX.c | 3 ++- win/curses/cursinvt.c | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/win/X11/winX.c b/win/X11/winX.c index d9a7cacf4..db95dea15 100644 --- a/win/X11/winX.c +++ b/win/X11/winX.c @@ -991,7 +991,8 @@ X11_putstr(winid window, int attr, const char *str) X11_destroy_nhwindow(window); *wp = window_list[new_win]; window_list[new_win].type = NHW_NONE; /* allow re-use */ - /* fall through */ + FALLTHROUGH; + /*FALLTHRU*/ case NHW_TEXT: add_to_text_window(wp, attr, str); break; diff --git a/win/curses/cursinvt.c b/win/curses/cursinvt.c index 3b0749d5c..4095ceb5a 100644 --- a/win/curses/cursinvt.c +++ b/win/curses/cursinvt.c @@ -187,6 +187,7 @@ curs_scroll_invt(WINDOW *win UNUSED) res = 1; break; } + FALLTHROUGH; /*FALLTHRU*/ case KEY_RIGHT: case KEY_NPAGE: From 92340296adbdefd128cb6be8d1239af9903e4ccb Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 13 Jan 2025 12:01:16 -0500 Subject: [PATCH 335/791] azure-pipelines warning filter take 2 --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index fd6676566..b3dca41fd 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -8,6 +8,7 @@ strategy: imageName: 'ubuntu-24.04' toolchainName: clang buildTargetName: all + warningTaskFilters: '\[\-W+.+\]|^((vs|ms)build|ant(\s+.+)?|gradle(w)?(\s+.+)?|grunt|gulp|maven(\s+.+)?|xamarin(android|ios)|xcode(\s+.+)?|cmake|build\s+.+)$' linux_jammy_gcc9_all: imageName: 'ubuntu-22.04' toolchainName: gcc9 @@ -165,7 +166,6 @@ steps: sudo apt-get -qq -y install libx11-dev libxaw7-dev xfonts-utils qtbase5-dev qtmultimedia5-dev qtbase5-dev-tools condition: and(eq( variables['Agent.OS'], 'Linux' ), eq( variables.buildTarget, 'all')) workingDirectory: $(Agent.BuildDirectory)/$(netHackPath) - warningTaskFilters: '\[\-W+.+\]|^((vs|ms)build|ant(\s+.+)?|gradle(w)?(\s+.+)?|grunt|gulp|maven(\s+.+)?|xamarin(android|ios)|xcode(\s+.+)?|cmake|build\s+.+)$' displayName: 'Getting linux build dependencies' - bash: | From fd919c156062f86187c1d23f8a2834e33fdd47b5 Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 13 Jan 2025 12:13:06 -0500 Subject: [PATCH 336/791] Revert "Revert "Revert "eliminate a couple of build warnings (noticed with clang)""" This reverts commit 6dad19a4f6df1dd85a9605e0d6383c2dc3ceffba. --- win/X11/winX.c | 3 +-- win/curses/cursinvt.c | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/win/X11/winX.c b/win/X11/winX.c index db95dea15..d9a7cacf4 100644 --- a/win/X11/winX.c +++ b/win/X11/winX.c @@ -991,8 +991,7 @@ X11_putstr(winid window, int attr, const char *str) X11_destroy_nhwindow(window); *wp = window_list[new_win]; window_list[new_win].type = NHW_NONE; /* allow re-use */ - FALLTHROUGH; - /*FALLTHRU*/ + /* fall through */ case NHW_TEXT: add_to_text_window(wp, attr, str); break; diff --git a/win/curses/cursinvt.c b/win/curses/cursinvt.c index 4095ceb5a..3b0749d5c 100644 --- a/win/curses/cursinvt.c +++ b/win/curses/cursinvt.c @@ -187,7 +187,6 @@ curs_scroll_invt(WINDOW *win UNUSED) res = 1; break; } - FALLTHROUGH; /*FALLTHRU*/ case KEY_RIGHT: case KEY_NPAGE: From 3c224fc49dcd35b7d7486993d2a5f487e16c120f Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 13 Jan 2025 12:31:57 -0500 Subject: [PATCH 337/791] update azure-pipelines.yml --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index b3dca41fd..e72e5d3e0 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -8,7 +8,7 @@ strategy: imageName: 'ubuntu-24.04' toolchainName: clang buildTargetName: all - warningTaskFilters: '\[\-W+.+\]|^((vs|ms)build|ant(\s+.+)?|gradle(w)?(\s+.+)?|grunt|gulp|maven(\s+.+)?|xamarin(android|ios)|xcode(\s+.+)?|cmake|build\s+.+)$' + checkWarnings: true linux_jammy_gcc9_all: imageName: 'ubuntu-22.04' toolchainName: gcc9 From ea647f3adb443d30c32394e043c2914bcbdd50f6 Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 13 Jan 2025 12:52:32 -0500 Subject: [PATCH 338/791] test custom warning filter in CI --- azure-pipelines.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index e72e5d3e0..c0a250eb5 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -9,6 +9,7 @@ strategy: toolchainName: clang buildTargetName: all checkWarnings: true + warningTaskFilters: '\[\-W+.+\]|^((vs|ms)build|ant(\s+.+)?|gradle(w)?(\s+.+)?|grunt|gulp|maven(\s+.+)?|xamarin(android|ios)|xcode(\s+.+)?|cmake|build\s+.+)$' linux_jammy_gcc9_all: imageName: 'ubuntu-22.04' toolchainName: gcc9 From 1b8bc6fc291a85a998c7d8c4350c8ddde83cfc9b Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 13 Jan 2025 13:12:40 -0500 Subject: [PATCH 339/791] finished CI testing; put things back --- azure-pipelines.yml | 2 -- win/X11/winX.c | 3 ++- win/curses/cursinvt.c | 1 + 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index c0a250eb5..cdec5d7d5 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -8,8 +8,6 @@ strategy: imageName: 'ubuntu-24.04' toolchainName: clang buildTargetName: all - checkWarnings: true - warningTaskFilters: '\[\-W+.+\]|^((vs|ms)build|ant(\s+.+)?|gradle(w)?(\s+.+)?|grunt|gulp|maven(\s+.+)?|xamarin(android|ios)|xcode(\s+.+)?|cmake|build\s+.+)$' linux_jammy_gcc9_all: imageName: 'ubuntu-22.04' toolchainName: gcc9 diff --git a/win/X11/winX.c b/win/X11/winX.c index d9a7cacf4..db95dea15 100644 --- a/win/X11/winX.c +++ b/win/X11/winX.c @@ -991,7 +991,8 @@ X11_putstr(winid window, int attr, const char *str) X11_destroy_nhwindow(window); *wp = window_list[new_win]; window_list[new_win].type = NHW_NONE; /* allow re-use */ - /* fall through */ + FALLTHROUGH; + /*FALLTHRU*/ case NHW_TEXT: add_to_text_window(wp, attr, str); break; diff --git a/win/curses/cursinvt.c b/win/curses/cursinvt.c index 3b0749d5c..4095ceb5a 100644 --- a/win/curses/cursinvt.c +++ b/win/curses/cursinvt.c @@ -187,6 +187,7 @@ curs_scroll_invt(WINDOW *win UNUSED) res = 1; break; } + FALLTHROUGH; /*FALLTHRU*/ case KEY_RIGHT: case KEY_NPAGE: From f32e32d4470c7e34ab985e277e7c97f2b6b51a1c Mon Sep 17 00:00:00 2001 From: PatR Date: Mon, 13 Jan 2025 16:55:58 -0800 Subject: [PATCH 340/791] still more PR #1364 Earlier commit left out an intended line, resulting in the sanity check being bogus because the incomplete test wasn't impossible. --- src/version.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/version.c b/src/version.c index fa4dd3d9b..34085a8af 100644 --- a/src/version.c +++ b/src/version.c @@ -364,8 +364,9 @@ check_version( { if (!filename) { #ifdef EXTRA_SANITY_CHECKS - impossible("check_version() called with" - " 'complain'=True but 'filename'=Null"); + if (complain) + impossible("check_version() called with" + " 'complain'=True but 'filename'=Null"); #endif complain = FALSE; /* 'complain' requires 'filename' for pline("%s") */ } From 2354fef2d6a8cb86203bad60891e2b0669985a46 Mon Sep 17 00:00:00 2001 From: nhmall Date: Tue, 14 Jan 2025 10:32:36 -0500 Subject: [PATCH 341/791] be more consistent with coordxy in mkmap.c Also closes #1365 --- include/decl.h | 8 +-- include/extern.h | 4 +- src/mkmap.c | 142 +++++++++++++++++++++++------------------------ 3 files changed, 76 insertions(+), 78 deletions(-) diff --git a/include/decl.h b/include/decl.h index 2d2aabef9..19f6b2b94 100644 --- a/include/decl.h +++ b/include/decl.h @@ -619,10 +619,10 @@ struct instance_globals_m { boolean made_branch; /* used only during level creation */ /* mkmap.c */ - int min_rx; /* rectangle bounds for regions */ - int max_rx; - int min_ry; - int max_ry; + coordxy min_rx; /* rectangle bounds for regions */ + coordxy max_rx; + coordxy min_ry; + coordxy max_ry; /* mkobj.c */ boolean mkcorpstat_norevive; /* for trolls */ diff --git a/include/extern.h b/include/extern.h index 590320b9e..1a71e505e 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1547,8 +1547,8 @@ extern void mineralize(int, int, int, int, boolean); /* ### mkmap.c ### */ -extern void flood_fill_rm(int, int, int, boolean, boolean); -extern void remove_rooms(int, int, int, int); +extern void flood_fill_rm(coordxy, coordxy, int, boolean, boolean); +extern void remove_rooms(coordxy, coordxy, coordxy, coordxy); extern boolean litstate_rnd(int); /* ### mkmaze.c ### */ diff --git a/src/mkmap.c b/src/mkmap.c index 26c3d3836..2c5fb53ec 100644 --- a/src/mkmap.c +++ b/src/mkmap.c @@ -10,7 +10,7 @@ staticfn void init_map(schar); staticfn void init_fill(schar, schar); -staticfn schar get_map(int, int, schar); +staticfn schar get_map(coordxy, coordxy, schar); staticfn void pass_one(schar, schar); staticfn void pass_two(schar, schar); staticfn void pass_three(schar, schar); @@ -23,36 +23,36 @@ void mkmap(lev_init *); staticfn void init_map(schar bg_typ) { - int i, j; + coordxy x, y; - for (i = 1; i < COLNO; i++) - for (j = 0; j < ROWNO; j++) { - levl[i][j].roomno = NO_ROOM; - levl[i][j].typ = bg_typ; - levl[i][j].lit = FALSE; + for (x = 1; x < COLNO; x++) + for (y = 0; y < ROWNO; y++) { + levl[x][y].roomno = NO_ROOM; + levl[x][y].typ = bg_typ; + levl[x][y].lit = FALSE; } } staticfn void init_fill(schar bg_typ, schar fg_typ) { - int i, j; + coordxy x, y; long limit, count; limit = (WIDTH * HEIGHT * 2) / 5; count = 0; while (count < limit) { - i = rn1(WIDTH - 1, 2); - j = rnd(HEIGHT - 1); - if (levl[i][j].typ == bg_typ) { - levl[i][j].typ = fg_typ; + x = (coordxy) rn1(WIDTH - 1, 2); + y = (coordxy) rnd(HEIGHT - 1); + if (levl[x][y].typ == bg_typ) { + levl[x][y].typ = fg_typ; count++; } } } staticfn schar -get_map(int col, int row, schar bg_typ) +get_map(coordxy col, coordxy row, schar bg_typ) { if (col <= 0 || row < 0 || col > WIDTH || row >= HEIGHT) return bg_typ; @@ -67,13 +67,13 @@ staticfn const int dirs[16] = { staticfn void pass_one(schar bg_typ, schar fg_typ) { - int i, j; + coordxy x, y; short count, dr; - for (i = 2; i <= WIDTH; i++) - for (j = 1; j < HEIGHT; j++) { + for (x = 2; x <= WIDTH; x++) + for (y = 1; y < HEIGHT; y++) { for (count = 0, dr = 0; dr < 8; dr++) - if (get_map(i + dirs[dr * 2], j + dirs[(dr * 2) + 1], bg_typ) + if (get_map(x + dirs[dr * 2], y + dirs[(dr * 2) + 1], bg_typ) == fg_typ) count++; @@ -81,13 +81,13 @@ pass_one(schar bg_typ, schar fg_typ) case 0: /* death */ case 1: case 2: - levl[i][j].typ = bg_typ; + levl[x][y].typ = bg_typ; break; case 5: case 6: case 7: case 8: - levl[i][j].typ = fg_typ; + levl[x][y].typ = fg_typ; break; default: break; @@ -100,47 +100,47 @@ pass_one(schar bg_typ, schar fg_typ) staticfn void pass_two(schar bg_typ, schar fg_typ) { - int i, j; + coordxy x, y; short count, dr; - for (i = 2; i <= WIDTH; i++) - for (j = 1; j < HEIGHT; j++) { + for (x = 2; x <= WIDTH; x++) + for (y = 1; y < HEIGHT; y++) { for (count = 0, dr = 0; dr < 8; dr++) - if (get_map(i + dirs[dr * 2], j + dirs[(dr * 2) + 1], bg_typ) + if (get_map(x + dirs[dr * 2], y + dirs[(dr * 2) + 1], bg_typ) == fg_typ) count++; if (count == 5) - new_loc(i, j) = bg_typ; + new_loc(x, y) = bg_typ; else - new_loc(i, j) = get_map(i, j, bg_typ); + new_loc(x, y) = get_map(x, y, bg_typ); } - for (i = 2; i <= WIDTH; i++) - for (j = 1; j < HEIGHT; j++) - levl[i][j].typ = new_loc(i, j); + for (x = 2; x <= WIDTH; x++) + for (y = 1; y < HEIGHT; y++) + levl[x][y].typ = new_loc(x, y); } staticfn void pass_three(schar bg_typ, schar fg_typ) { - int i, j; + coordxy x, y; short count, dr; - for (i = 2; i <= WIDTH; i++) - for (j = 1; j < HEIGHT; j++) { + for (x = 2; x <= WIDTH; x++) + for (y = 1; y < HEIGHT; y++) { for (count = 0, dr = 0; dr < 8; dr++) - if (get_map(i + dirs[dr * 2], j + dirs[(dr * 2) + 1], bg_typ) + if (get_map(x + dirs[dr * 2], y + dirs[(dr * 2) + 1], bg_typ) == fg_typ) count++; if (count < 3) - new_loc(i, j) = bg_typ; + new_loc(x, y) = bg_typ; else - new_loc(i, j) = get_map(i, j, bg_typ); + new_loc(x, y) = get_map(x, y, bg_typ); } - for (i = 2; i <= WIDTH; i++) - for (j = 1; j < HEIGHT; j++) - levl[i][j].typ = new_loc(i, j); + for (x = 2; x <= WIDTH; x++) + for (y = 1; y < HEIGHT; y++) + levl[x][y].typ = new_loc(x, y); } /* @@ -151,14 +151,13 @@ pass_three(schar bg_typ, schar fg_typ) */ void flood_fill_rm( - int sx, - int sy, + coordxy sx, + coordxy sy, int rmno, boolean lit, boolean anyroom) { - int i; - int nx; + coordxy i, nx; schar fg_typ = levl[sx][sy].typ; /* back up to find leftmost uninitialized location */ @@ -179,7 +178,7 @@ flood_fill_rm( levl[i][sy].lit = lit; if (anyroom) { /* add walls to room as well */ - int ii, jj; + coordxy ii, jj; for (ii = (i == sx ? i - 1 : i); ii <= i + 1; ii++) for (jj = sy - 1; jj <= sy + 1; jj++) if (isok(ii, jj) && (IS_WALL(levl[ii][jj].typ) @@ -260,19 +259,18 @@ join_map(schar bg_typ, schar fg_typ) { struct mkroom *croom, *croom2; - int i, j; - int sx, sy; + coordxy x, y, sx, sy; coord sm, em; /* first, use flood filling to find all of the regions that need joining */ - for (i = 2; i <= WIDTH; i++) - for (j = 1; j < HEIGHT; j++) { - if (levl[i][j].typ == fg_typ && levl[i][j].roomno == NO_ROOM) { - gm.min_rx = gm.max_rx = i; - gm.min_ry = gm.max_ry = j; + for (x = 2; x <= WIDTH; x++) + for (y = 1; y < HEIGHT; y++) { + if (levl[x][y].typ == fg_typ && levl[x][y].roomno == NO_ROOM) { + gm.min_rx = gm.max_rx = x; + gm.min_ry = gm.max_ry = y; gn.n_loc_filled = 0; - flood_fill_rm(i, j, svn.nroom + ROOMOFFSET, FALSE, FALSE); + flood_fill_rm(x, y, svn.nroom + ROOMOFFSET, FALSE, FALSE); if (gn.n_loc_filled > 3) { add_room(gm.min_rx, gm.min_ry, gm.max_rx, gm.max_ry, FALSE, OROOM, TRUE); @@ -337,30 +335,30 @@ finish_map( boolean walled, boolean icedpools) { - int i, j; + coordxy x, y; if (walled) wallify_map(1, 0, COLNO-1, ROWNO-1); if (lit) { - for (i = 1; i < COLNO; i++) - for (j = 0; j < ROWNO; j++) - if ((!IS_OBSTRUCTED(fg_typ) && levl[i][j].typ == fg_typ) - || (!IS_OBSTRUCTED(bg_typ) && levl[i][j].typ == bg_typ) - || (bg_typ == TREE && levl[i][j].typ == bg_typ) - || (walled && IS_WALL(levl[i][j].typ))) - levl[i][j].lit = TRUE; - for (i = 0; i < svn.nroom; i++) - svr.rooms[i].rlit = 1; + for (x = 1; x < COLNO; x++) + for (y = 0; y < ROWNO; y++) + if ((!IS_OBSTRUCTED(fg_typ) && levl[x][y].typ == fg_typ) + || (!IS_OBSTRUCTED(bg_typ) && levl[x][y].typ == bg_typ) + || (bg_typ == TREE && levl[x][y].typ == bg_typ) + || (walled && IS_WALL(levl[x][y].typ))) + levl[x][y].lit = TRUE; + for (x = 0; x < svn.nroom; x++) + svr.rooms[x].rlit = 1; } /* light lava even if everything's otherwise unlit; ice might be frozen pool rather than frozen moat */ - for (i = 1; i < COLNO; i++) - for (j = 0; j < ROWNO; j++) { - if (levl[i][j].typ == LAVAPOOL) - levl[i][j].lit = TRUE; - else if (levl[i][j].typ == ICE) - levl[i][j].icedpool = icedpools ? ICED_POOL : ICED_MOAT; + for (x = 1; x < COLNO; x++) + for (y = 0; y < ROWNO; y++) { + if (levl[x][y].typ == LAVAPOOL) + levl[x][y].lit = TRUE; + else if (levl[x][y].typ == ICE) + levl[x][y].icedpool = icedpools ? ICED_POOL : ICED_MOAT; } } @@ -378,7 +376,7 @@ finish_map( * region are all set. */ void -remove_rooms(int lx, int ly, int hx, int hy) +remove_rooms(coordxy lx, coordxy ly, coordxy hx, coordxy hy) { int i; struct mkroom *croom; @@ -415,7 +413,7 @@ remove_room(unsigned int roomno) { struct mkroom *croom = &svr.rooms[roomno]; struct mkroom *maxroom = &svr.rooms[--svn.nroom]; - int i, j; + coordxy x, y; unsigned oroomno; if (croom != maxroom) { @@ -427,10 +425,10 @@ remove_room(unsigned int roomno) /* since maxroom moved, update affected level roomno values */ oroomno = svn.nroom + ROOMOFFSET; roomno += ROOMOFFSET; - for (i = croom->lx; i <= croom->hx; ++i) - for (j = croom->ly; j <= croom->hy; ++j) { - if (levl[i][j].roomno == oroomno) - levl[i][j].roomno = roomno; + for (x = croom->lx; x <= croom->hx; ++x) + for (y = croom->ly; y <= croom->hy; ++y) { + if (levl[x][y].roomno == oroomno) + levl[x][y].roomno = roomno; } } From a513b41748680e9cf38c96c9478d29326d24259d Mon Sep 17 00:00:00 2001 From: nhmall Date: Tue, 14 Jan 2025 11:17:41 -0500 Subject: [PATCH 342/791] more coordxy consistency, mklev.c --- include/extern.h | 8 +++++--- src/mklev.c | 6 ++++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/include/extern.h b/include/extern.h index 1a71e505e..ccab64021 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1519,9 +1519,11 @@ extern void gain_guardian_angel(void); /* ### mklev.c ### */ extern void sort_rooms(void); -extern void add_room(int, int, int, int, boolean, schar, boolean); -extern void add_subroom(struct mkroom *, int, int, int, int, boolean, schar, - boolean) NONNULLARG1; +extern void add_room(coordxy, coordxy, coordxy, coordxy, + boolean, schar, boolean); +extern void add_subroom(struct mkroom *, + coordxy, coordxy, coordxy, coordxy, + boolean, schar, boolean) NONNULLARG1; extern void free_luathemes(enum lua_theme_group); extern void makecorridors(void); extern void add_door(coordxy, coordxy, struct mkroom *) NONNULLARG3; diff --git a/src/mklev.c b/src/mklev.c index a209cf371..def62d5e0 100644 --- a/src/mklev.c +++ b/src/mklev.c @@ -215,7 +215,7 @@ do_room_or_subroom(struct mkroom *croom, } void -add_room(int lowx, int lowy, int hix, int hiy, +add_room(coordxy lowx, coordxy lowy, coordxy hix, coordxy hiy, boolean lit, schar rtype, boolean special) { struct mkroom *croom; @@ -229,7 +229,9 @@ add_room(int lowx, int lowy, int hix, int hiy, } void -add_subroom(struct mkroom *proom, int lowx, int lowy, int hix, int hiy, +add_subroom(struct mkroom *proom, + coordxy lowx, coordxy lowy, + coordxy hix, coordxy hiy, boolean lit, schar rtype, boolean special) { struct mkroom *croom; From b2f4b687c1c60ef30728deb7028411f6dca8f9c7 Mon Sep 17 00:00:00 2001 From: nhmall Date: Tue, 14 Jan 2025 11:33:30 -0500 Subject: [PATCH 343/791] yet another coordxy bit --- include/decl.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/decl.h b/include/decl.h index 19f6b2b94..6298e0621 100644 --- a/include/decl.h +++ b/include/decl.h @@ -953,8 +953,8 @@ struct instance_globals_t { const char *this_title; /* title for inventory list of specific type */ /* muse.c */ - int trapx; - int trapy; + coordxy trapx; + coordxy trapy; /* rumors.c */ long true_rumor_size; /* rumor size variables are signed so that value -1 From d2aff9a9b240da5b078d6ff88a11ae446f9d9398 Mon Sep 17 00:00:00 2001 From: nhmall Date: Tue, 14 Jan 2025 12:13:39 -0500 Subject: [PATCH 344/791] remove some xchar vestiges --- outdated/include/wingem.h | 2 +- outdated/sys/amiga/winami.p | 2 +- outdated/sys/amiga/winfuncs.c | 5 ++--- outdated/sys/amiga/winproto.h | 2 +- outdated/sys/mac/mrecover.c | 4 ++-- outdated/win/gem/wingem.c | 8 ++++---- outdated/win/gem/wingem1.c | 3 +-- win/tty/wintty.c | 3 +-- 8 files changed, 13 insertions(+), 16 deletions(-) diff --git a/outdated/include/wingem.h b/outdated/include/wingem.h index c7a935ef2..4c1378c0e 100644 --- a/outdated/include/wingem.h +++ b/outdated/include/wingem.h @@ -83,7 +83,7 @@ extern void Gem_cliparound(int, int); #ifdef POSITIONBAR extern void Gem_update_positionbar(char *); #endif -extern void Gem_print_glyph(winid, xchar, xchar, const glyph_info *, +extern void Gem_print_glyph(winid, coordxy, coordxy, const glyph_info *, const glyph_info *); extern void Gem_raw_print(const char *); extern void Gem_raw_print_bold(const char *); diff --git a/outdated/sys/amiga/winami.p b/outdated/sys/amiga/winami.p index 0fd69a38f..2e26cfb10 100644 --- a/outdated/sys/amiga/winami.p +++ b/outdated/sys/amiga/winami.p @@ -35,7 +35,7 @@ int amii_doprev_message (void); void amii_display_nhwindow(winid , boolean ); void amii_display_file(const char * , boolean ); void amii_curs(winid , int , int ); -void amii_print_glyph(winid , xchar , xchar , int, int ); +void amii_print_glyph(winid , coordxy , coordxy , int, int ); void DoMenuScroll(int , int ); void DisplayData(int , int , int ); void SetPropInfo(struct Window * , struct Gadget * , long , long , long ); diff --git a/outdated/sys/amiga/winfuncs.c b/outdated/sys/amiga/winfuncs.c index 3624e3815..28a811ba7 100644 --- a/outdated/sys/amiga/winfuncs.c +++ b/outdated/sys/amiga/winfuncs.c @@ -1515,8 +1515,7 @@ boolean blocking; void amii_curs(window, x, y) winid window; -register int x, y; /* not xchar: perhaps xchar is unsigned and - curx-x would be unsigned as well */ +register int x, y; { register struct amii_WinDesc *cw; register struct Window *w; @@ -1954,7 +1953,7 @@ port_help() void amii_print_glyph(win, x, y, glyph, bkglyph) winid win; -xchar x, y; +coordxy x, y; int glyph, bkglyph; { struct amii_WinDesc *cw; diff --git a/outdated/sys/amiga/winproto.h b/outdated/sys/amiga/winproto.h index eb2b588d8..efa1e9b58 100644 --- a/outdated/sys/amiga/winproto.h +++ b/outdated/sys/amiga/winproto.h @@ -101,7 +101,7 @@ void amii_resume_nhwindows(void); void amii_bell(void); void removetopl(int cnt); void port_help(void); -void amii_print_glyph(winid win, xchar x, xchar y, int glyph, int bkglyph); +void amii_print_glyph(winid win, coordxy x, coordxy y, int glyph, int bkglyph); void amii_raw_print(const char *s); void amii_raw_print_bold(const char *s); void amii_update_inventory(void); diff --git a/outdated/sys/mac/mrecover.c b/outdated/sys/mac/mrecover.c index 01ea7587b..9a42c4889 100644 --- a/outdated/sys/mac/mrecover.c +++ b/outdated/sys/mac/mrecover.c @@ -1192,7 +1192,7 @@ restore_savefile() { static int savelev; long saveTemp, lev; - xchar levc; + xint8 levc; struct version_info version_data; /* level 0 file contains: @@ -1264,7 +1264,7 @@ restore_savefile() levRefNum = open_levelfile(lev); if (levRefNum >= 0) { /* any or all of these may not exist */ - levc = (xchar) lev; + levc = (xint8) lev; (void) write_savefile(saveRefNum, (Ptr) &levc, sizeof(levc)); diff --git a/outdated/win/gem/wingem.c b/outdated/win/gem/wingem.c index 15024f853..078a2d2a7 100644 --- a/outdated/win/gem/wingem.c +++ b/outdated/win/gem/wingem.c @@ -880,7 +880,7 @@ int x, y; * position and glyph are always correct (checked there)! */ -void mar_print_gl_char(winid, xchar, xchar, int); +void mar_print_gl_char(winid, coordxy, coordxy, int); extern int mar_set_rogue(int); @@ -889,7 +889,7 @@ extern void mar_add_pet_sign(winid, int, int); void Gem_print_glyph(window, x, y, glyph, bkglyph) winid window; -xchar x, y; +coordxy x, y; int glyph, bkglyph; { /* Move the cursor. */ @@ -908,12 +908,12 @@ int glyph, bkglyph; mar_print_gl_char(window, x, y, glyph); } -void mar_print_char(winid, xchar, xchar, char, int); +void mar_print_char(winid, coordxy, coordxy, char, int); void mar_print_gl_char(window, x, y, glyph) winid window; -xchar x, y; +coordxy x, y; int glyph; { int ch; diff --git a/outdated/win/gem/wingem1.c b/outdated/win/gem/wingem1.c index 75c96918d..594c3ccbf 100644 --- a/outdated/win/gem/wingem1.c +++ b/outdated/win/gem/wingem1.c @@ -26,11 +26,10 @@ typedef signed char schar; #define CHAR_P char #define SCHAR_P schar #define UCHAR_P uchar -#define XCHAR_P xchar +#define COORDXY_P coordxy #define SHORT_P short #define BOOLEAN_P boolean #define ALIGNTYP_P aligntyp -typedef signed char xchar; #include "wingem.h" #undef CHAR_P #undef SCHAR_P diff --git a/win/tty/wintty.c b/win/tty/wintty.c index 288653e5c..dbdf57363 100644 --- a/win/tty/wintty.c +++ b/win/tty/wintty.c @@ -2036,8 +2036,7 @@ erase_tty_screen(void) void tty_curs( winid window, - int x, int y) /* not xchar: perhaps xchar is unsigned - * then curx-x would be unsigned too */ + int x, int y) /* coordinates (and curx-x) must be signed */ { struct WinDesc *cw = 0; int cx = ttyDisplay->curx; From 88a571fab85ac36970eed9398ac3935ce504ed67 Mon Sep 17 00:00:00 2001 From: SHIRAKATA Kentaro Date: Sun, 12 Jan 2025 15:43:46 +0900 Subject: [PATCH 345/791] add sanity check on parse_status_hl2() dt is initialized with -1, and it's not so obvious that it will be always overwritten later. --- src/botl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/botl.c b/src/botl.c index 51f15f19d..e714fbb8f 100644 --- a/src/botl.c +++ b/src/botl.c @@ -2830,6 +2830,7 @@ parse_status_hl2(char (*s)[QBUFSZ], boolean from_configfile) else hilite.behavior = BL_TH_NONE; + assert(dt >= 0); hilite.anytype = dt; if (hilite.behavior == BL_TH_TEXTMATCH && txt) { From b4f912e3c41d1e6f988fc7557a812ac77bb8ffd0 Mon Sep 17 00:00:00 2001 From: PatR Date: Wed, 15 Jan 2025 15:44:09 -0800 Subject: [PATCH 346/791] add a couple cf comments --- src/do_name.c | 4 ++-- src/pager.c | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/do_name.c b/src/do_name.c index d1d53f36e..d5b7d7852 100644 --- a/src/do_name.c +++ b/src/do_name.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 do_name.c $NHDT-Date: 1720895738 2024/07/13 18:35:38 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.320 $ */ +/* NetHack 3.7 do_name.c $NHDT-Date: 1737013431 2025/01/15 23:43:51 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.326 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Pasi Kallinen, 2018. */ /* NetHack may be freely redistributed. See license for details. */ @@ -750,7 +750,7 @@ namefloorobj(void) } if (fakeobj) { obj->where = OBJ_FREE; /* object_from_map() sets it to OBJ_FLOOR */ - dealloc_obj(obj); + dealloc_obj(obj); /* has no contents */ } } diff --git a/src/pager.c b/src/pager.c index 465659bd2..eb5956061 100644 --- a/src/pager.c +++ b/src/pager.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 pager.c $NHDT-Date: 1732979463 2024/11/30 07:11:03 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.282 $ */ +/* NetHack 3.7 pager.c $NHDT-Date: 1737013431 2025/01/15 23:43:51 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.287 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2018. */ /* NetHack may be freely redistributed. See license for details. */ @@ -226,7 +226,7 @@ mhidden_description( if (fakeobj && otmp) { otmp->where = OBJ_FREE; /* object_from_map set to OBJ_FLOOR */ - dealloc_obj(otmp); + dealloc_obj(otmp); /* has no contents */ } } else { Strcat(outbuf, something); @@ -375,7 +375,7 @@ look_at_object( : obj_descr[STRANGE_OBJECT].oc_name); if (fakeobj) { otmp->where = OBJ_FREE; /* object_from_map set it to OBJ_FLOOR */ - dealloc_obj(otmp), otmp = 0; + dealloc_obj(otmp), otmp = NULL; /* has no contents */ } } else Strcpy(buf, something); /* sanity precaution */ From c0a1ed9c41895136b3195f10486773b201c17c1b Mon Sep 17 00:00:00 2001 From: PatR Date: Thu, 16 Jan 2025 12:51:40 -0800 Subject: [PATCH 347/791] another stab at stumble_onto_mimic The unreliable sanity check is removed. --- src/pager.c | 6 +++++- src/uhitm.c | 18 +++++++----------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/pager.c b/src/pager.c index eb5956061..e964554f2 100644 --- a/src/pager.c +++ b/src/pager.c @@ -289,7 +289,11 @@ object_from_map( boolean fakeobj = FALSE, mimic_obj = FALSE; struct monst *mtmp; struct obj *otmp; - int glyphotyp = glyph_to_obj(glyph); + int glyphotyp = glyph_is_object(glyph) ? glyph_to_obj(glyph) + /* if not an object, probably a detected chest trap */ + : glyph_is_cmap(glyph) /* assume trapped chest|door */ + ? (sobj_at(CHEST, x, y) ? CHEST : LARGE_BOX) + : STRANGE_OBJECT; *obj_p = (struct obj *) 0; /* TODO: check inside containers in case glyph came from detection */ diff --git a/src/uhitm.c b/src/uhitm.c index b3b470c00..dc7264af1 100644 --- a/src/uhitm.c +++ b/src/uhitm.c @@ -6068,26 +6068,22 @@ that_is_a_mimic( else if (M_AP_TYPE(mtmp) == M_AP_MONSTER) what = a_monnam(mtmp); /* differs from what was sensed */ } else { - int glyph = glyph_at(u.ux + u.dx, u.uy + u.dy); + coordxy x = u.ux + u.dx, y = u.uy + u.dy; + int glyph = glyph_at(x, y); if (glyph_is_cmap(glyph)) { int sym = glyph_to_cmap(glyph); -#ifdef EXTRA_SANITY_CHECKS - if (iflags.sanity_check && (int) mtmp->mappearance != sym) - impossible("mimic appearance %u does not match" - " map feature %d (glyph=%d)", - mtmp->mappearance, sym, glyph); -#endif - /* note: defsyms[stairs] yields singular "staircase {up|down}" */ - Snprintf(fmtbuf, sizeof fmtbuf, "That %s actually is %%s!", - defsyms[sym].explanation); + if (M_AP_TYPE(mtmp) == M_AP_FURNITURE + || (M_AP_TYPE(mtmp) == M_AP_OBJECT && sym == S_trapped_chest)) + Snprintf(fmtbuf, sizeof fmtbuf, "That %s actually is %%s!", + defsyms[sym].explanation); } else if (glyph_is_object(glyph)) { boolean fakeobj; const char *otmp_name; struct obj *otmp = NULL; - fakeobj = object_from_map(glyph, mtmp->mx, mtmp->my, &otmp); + fakeobj = object_from_map(glyph, x, y, &otmp); otmp_name = (otmp && otmp->otyp != STRANGE_OBJECT) ? simpleonames(otmp) : "strange object"; Snprintf(fmtbuf, sizeof fmtbuf, "%s %s %s %%s!", From 6df83cb67790093b9eaaccfbeff0d5a47e9098d2 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Fri, 17 Jan 2025 17:07:04 +0200 Subject: [PATCH 348/791] Fix pet data being reset when charm monster was cast Casting charm monster with pets nearby could reset the edog struct. If the pet ate a mimic corpse and was pretending to be something else when that edog reset happened, the sanity checking would issue an impossible. The error happened because meating was reset, but the pet appearance was not, but the edog struct reset is the part being wrong. Lets not do that. To reproduce, turn on sanity checking, create a tame dog, give it a mimic corpse to eat, #wizcast charm monster next to it. --- src/dog.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/dog.c b/src/dog.c index 4b523db7c..38bd92fd9 100644 --- a/src/dog.c +++ b/src/dog.c @@ -1208,8 +1208,10 @@ tamedog( return FALSE; /* add the pet extension */ - newedog(mtmp); - initedog(mtmp); + if (!has_edog(mtmp)) { + newedog(mtmp); + initedog(mtmp); + } if (obj) { /* thrown food */ /* defer eating until the edog extension has been set up */ From fc7fdd7f0831a44edf666a0645a204ec09035abd Mon Sep 17 00:00:00 2001 From: nhmall Date: Fri, 17 Jan 2025 14:26:03 -0500 Subject: [PATCH 349/791] get rid of a compiler gripe --- src/wizcmds.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wizcmds.c b/src/wizcmds.c index 6cee64b36..17dc08c5b 100644 --- a/src/wizcmds.c +++ b/src/wizcmds.c @@ -69,7 +69,7 @@ RESTORE_WARNING_FORMAT_NONLITERAL /* used when wiz_makemap() gets rid of monsters for the old incarnation of a level before creating a new incarnation of it */ -void +staticfn void makemap_unmakemon(struct monst *mtmp, boolean migratory) { int ndx = monsndx(mtmp->data); From e48824223f194452c927d44d146dc7f04d580837 Mon Sep 17 00:00:00 2001 From: PatR Date: Fri, 17 Jan 2025 13:20:59 -0800 Subject: [PATCH 350/791] fix static analyzer complaints for shk.c This cleans up analyzer feedback in shk.c, based on the set of warnings specified by hints/MacOS.370 and the lower level hints it applies, rather than anything specified during periodic 'onefile' processing. shk.c is the only file I've analyzed, to try again to figure out how to suppress the old complaint that has been causing a special case in Genonefile. It isn't triggering during my testing but that might be due to something in use by onefile but not by normal hints. I'm running ccc-analyzer from llvm-16; I don't know whether that matches Genonefile. --- src/shk.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/shk.c b/src/shk.c index 8a521cb26..31aec5c8b 100644 --- a/src/shk.c +++ b/src/shk.c @@ -120,7 +120,7 @@ staticfn uint8 litter_getpos(uint8 *, coordxy, coordxy, struct monst *); staticfn void litter_scatter(uint8 *, coordxy, coordxy, struct monst *); staticfn void litter_newsyms(uint8 *, coordxy, coordxy); staticfn int repair_damage(struct monst *, struct damage *, boolean); -staticfn void sub_one_frombill(struct obj *, struct monst *); +staticfn void sub_one_frombill(struct obj *, struct monst *) NONNULLPTRS; staticfn void add_one_tobill(struct obj *, boolean, struct monst *); staticfn void dropped_container(struct obj *, struct monst *, boolean); staticfn void add_to_billobjs(struct obj *); @@ -1731,6 +1731,7 @@ dopay(void) shkp = next_shkp(shkp->nmon, FALSE)) if (canspotmon(shkp)) break; + assert(shkp != NULL); /* seensk==1 => traversal will spot one shk */ if (shkp != resident && !m_next2u(shkp)) { pline("%s is not near enough to receive your payment.", Shknam(shkp)); @@ -2243,9 +2244,8 @@ buy_container( unsigned boid, boids[BILLSZ]; int i, j, buy, buycount = 0, boidsct = 0; struct eshk *eshkp = ESHK(shkp); - int bidx = ibill[indx].bidx, - ebillct = eshkp->billct; - struct bill_x *bp = &eshkp->bill_p[bidx]; + int ebillct = eshkp->billct; + struct bill_x *bp; struct obj *otmp, *otop, *container = ibill[indx].obj; unsigned unpaidcontainer = container->unpaid; @@ -3654,6 +3654,7 @@ stolen_container( /* billable() returns false for objects already on bill */ if ((bp = onbill(otmp, shkp, FALSE)) == 0) continue; + assert(shkp != NULL); /* onbill() found shkp so it's not Null */ /* this assumes that we're being called by stolen_value() (or by a recursive call to self on behalf of it) where the cost of this object is about to be added to shop @@ -3707,6 +3708,7 @@ stolen_value( /* things already on the bill yield a not-billable result, so we need to check bill before deciding that shk doesn't care */ if ((bp = onbill(obj, shkp, FALSE)) != 0) { + assert(shkp != NULL); /* onbill() found shkp so it's not Null */ /* shk does care; take obj off bill to avoid double billing */ billamt = bp->bquan * bp->price; sub_one_frombill(obj, shkp); @@ -4461,9 +4463,8 @@ discard_damage_owned_by(struct monst *shkp) prevdam->next = dam2; if (dam == svl.level.damagelist) svl.level.damagelist = dam2; - (void) memset(dam, 0, sizeof(struct damage)); - free((genericptr_t) dam); - dam = dam2; + (void) memset(dam, 0, sizeof *dam); + free((genericptr_t) dam), dam = (struct damage *) NULL; } else { prevdam = dam; dam2 = dam->next; From 34dc5d7acfbcc637eebbf1a9ebb220d427d4be4f Mon Sep 17 00:00:00 2001 From: PatR Date: Fri, 17 Jan 2025 21:26:32 -0800 Subject: [PATCH 351/791] static analyzer changes for trap.c Picked arbitrarily; there weren't any unresolved analyzer complaints for trap.c. I wonder why the onefile analysis isn't complaining here. 'in_sight' may have been relevant before the trapeffect_xyz() code was split apart, but it isn't useful for trapeffect_hole() despite the comment about it. release_holding_trap() is fairly convoluted and the complaints being addressed here were relevant. --- src/trap.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/trap.c b/src/trap.c index 2664fbf0a..3097a2e6f 100644 --- a/src/trap.c +++ b/src/trap.c @@ -2028,8 +2028,6 @@ trapeffect_hole( if (in_sight) { pline_mon(mtmp, "%s seems to be yanked down!", Monnam(mtmp)); - /* suppress message in mlevel_tele_trap() */ - in_sight = FALSE; seetrap(trap); } } else @@ -6003,7 +6001,7 @@ openholdingtrap( boolean *noticed) /* set to true iff hero notices the effect; * otherwise left with its previous value intact */ { - struct trap *t; + struct trap *t, tdummy; char buf[BUFSZ], whichbuf[20]; const char *trapdescr = 0, *which = 0; boolean ishero = (mon == &gy.youmonst); @@ -6016,7 +6014,15 @@ openholdingtrap( t = t_at(ishero ? u.ux : mon->mx, ishero ? u.uy : mon->my); if (ishero && u.utrap) { /* all u.utraptype values are holding traps */ + /* there might not be any trap at hero's spot for tt_buriedball; + conversely, there might be an unrelated trap at that spot */ + if (!t) { + t = &tdummy; + (void) memset(t, 0, sizeof *t), t->ntrap = NULL; + /* fallback 't' is now nonNull, t->tseen and t->madeby_u are 0 */ + } which = the_your[(!t || !t->tseen || !t->madeby_u) ? 0 : 1]; + switch (u.utraptype) { case TT_LAVA: trapdescr = "molten lava"; @@ -6032,7 +6038,9 @@ openholdingtrap( case TT_BEARTRAP: case TT_PIT: case TT_WEB: - trapdescr = 0; /* use defsyms[].explanation */ + trapdescr = defsyms[(u.utraptype == TT_WEB) ? S_web + : (u.utraptype == TT_PIT) ? S_pit + : S_bear_trap].explanation; break; default: /* lint suppression in case 't' is unexpectedly Null @@ -6044,10 +6052,9 @@ openholdingtrap( /* if no trap here or it's not a holding trap, we're done */ if (!t || (t->ttyp != BEAR_TRAP && t->ttyp != WEB)) return FALSE; - } - - if (!trapdescr) trapdescr = trapname(t->ttyp, FALSE); + } + assert(t != NULL); if (!which) which = t->tseen ? the_your[t->madeby_u] : strchr(vowels, *trapdescr) ? "an" : "a"; From 7f36a5db3c15a592e5812146feb78fef94dd72a8 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sat, 18 Jan 2025 19:30:10 +0200 Subject: [PATCH 352/791] Fix vision when guard moves a monster --- src/vault.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vault.c b/src/vault.c index e395465a9..c6169dfac 100644 --- a/src/vault.c +++ b/src/vault.c @@ -731,6 +731,7 @@ gd_mv_monaway(struct monst *grd, int nx, int ny) } if (!rloc(mtmp, RLOC_ERR | RLOC_MSG) || MON_AT(nx, ny)) m_into_limbo(mtmp); + recalc_block_point(nx, ny); } } From 6a457056a3c0b3b8dc79d2ece96fbd02cb20924b Mon Sep 17 00:00:00 2001 From: PatR Date: Sat, 18 Jan 2025 16:36:51 -0800 Subject: [PATCH 353/791] analyzer lint and stale comment for apply.c --- src/apply.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/apply.c b/src/apply.c index 676d97137..1de989ac3 100644 --- a/src/apply.c +++ b/src/apply.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 apply.c $NHDT-Date: 1720128162 2024/07/04 21:22:42 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.449 $ */ +/* NetHack 3.7 apply.c $NHDT-Date: 1737275719 2025/01/19 00:35:19 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.464 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -232,8 +232,7 @@ its_dead(coordxy rx, coordxy ry, int *resp) /* (most corpses don't retain the monster's sex, so we're usually forced to use generic pronoun here) */ if (mtmp) { - mptr = mtmp->data = &mons[mtmp->mnum]; - /* TRUE: override visibility check--it's not on the map */ + mtmp->data = &mons[mtmp->mnum]; gndr = pronoun_gender(mtmp, PRONOUN_NO_IT); } else { mptr = &mons[corpse->corpsenm]; From ba8076b142b59a6a7a4e48089d6b8edc4f13aeda Mon Sep 17 00:00:00 2001 From: PatR Date: Sat, 18 Jan 2025 18:04:09 -0800 Subject: [PATCH 354/791] static ananlyzer issue for alloc.c Verifying that strlen(string) isn't too long, then allocating and copying strlen(string)+1 draws a complaint about strcpy() overflowing its output buffer. Not an issue for regular play, but could matter for config file and sysconf manipulation. --- src/alloc.c | 14 +++++++++++--- win/share/tile2bmp.c | 4 +--- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/alloc.c b/src/alloc.c index f8f89a952..72faa160b 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 alloc.c $NHDT-Date: 1706213795 2024/01/25 20:16:35 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.34 $ */ +/* NetHack 3.7 alloc.c $NHDT-Date: 1737281026 2025/01/19 02:03:46 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.38 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -221,6 +221,10 @@ nhdupstr(const char *string, const char *file, int line) /* we've got some info about the caller, so use it instead of __func__ */ unsigned len = FITSuint_(strlen(string), file, line); + if (FITSuint(len + 1, file, line) < len) + panic("nhdupstr: string length overflow, line %d of %s", + line, file); + return strcpy((char *) nhalloc(len + 1, file, line), string); } #undef dupstr @@ -233,7 +237,11 @@ nhdupstr(const char *string, const char *file, int line) char * dupstr(const char *string) { - unsigned len = FITSuint_(strlen(string), __func__, (int) __LINE__); + size_t len = strlen(string); + + /* make sure len+1 doesn't overflow plain unsigned (for alloc()) */ + if (len > (unsigned) (~0U - 1U)) + panic("dupstr: string length overflow"); return strcpy((char *) alloc(len + 1), string); } @@ -245,7 +253,7 @@ dupstr_n(const char *string, unsigned int *lenout) size_t len = strlen(string); if (len >= LARGEST_INT) - panic("string too long"); + panic("dupstr_n: string too long"); *lenout = (unsigned int) len; return strcpy((char *) alloc(len + 1), string); } diff --git a/win/share/tile2bmp.c b/win/share/tile2bmp.c index 10561a2e7..4b7312aff 100644 --- a/win/share/tile2bmp.c +++ b/win/share/tile2bmp.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 tile2bmp.c $NHDT-Date: 1596498340 2020/08/03 23:45:40 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.32 $ */ +/* NetHack 3.7 tile2bmp.c $NHDT-Date: 1737281026 2025/01/19 02:03:46 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.51 $ */ /* Copyright (c) NetHack PC Development Team 1995 */ /* NetHack may be freely redistributed. See license for details. */ @@ -60,8 +60,6 @@ lelong(int32_t x) #endif } -unsigned FITSuint_(unsigned long long, const char *, int); - #ifdef __GNUC__ typedef struct tagBMIH { uint32_t biSize; From 3418c871b1d13e01de29fde5883085d19af17d0d Mon Sep 17 00:00:00 2001 From: PatR Date: Sat, 18 Jan 2025 18:35:21 -0800 Subject: [PATCH 355/791] static analyzer lint for cmd.c --- src/cmd.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/cmd.c b/src/cmd.c index 51524a199..c038e6765 100644 --- a/src/cmd.c +++ b/src/cmd.c @@ -805,7 +805,7 @@ extcmd_via_menu(void) * ('w' in wizard mode) */ /* -3: two line menu header, 1 line menu footer (for prompt) */ one_per_line = (nchoices < ROWNO - 3); - accelerator = prevaccelerator = 0; + prevaccelerator = 0; acount = 0; for (i = 0; choices[i]; ++i) { accelerator = choices[i]->ef_txt[matchlevel]; @@ -3479,7 +3479,6 @@ rhack(int key) } res = ECMD_FAIL; prefix_seen = 0; - was_m_prefix = FALSE; } else { /* we discard 'const' because some compilers seem to have trouble with the pointer passed to set_occupation() */ @@ -3526,7 +3525,6 @@ rhack(int key) return; } prefix_seen = tlist; - bad_command = FALSE; cmdq_ec = NULL; if (func == do_reqmenu) was_m_prefix = TRUE; @@ -3561,7 +3559,6 @@ rhack(int key) return; } prefix_seen = 0; - was_m_prefix = FALSE; } /* it is possible to have a result of (ECMD_TIME|ECMD_CANCEL) [for example, using 'f'ire, manually filling quiver with From e8d9331f14d68f7fd70a9dd9009c86327a6f7494 Mon Sep 17 00:00:00 2001 From: PatR Date: Sat, 18 Jan 2025 19:36:06 -0800 Subject: [PATCH 356/791] static analyzer lint for coloratt.c --- src/coloratt.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/coloratt.c b/src/coloratt.c index e2053e238..436e9274e 100644 --- a/src/coloratt.c +++ b/src/coloratt.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 coloratt.c $NHDT-Date: 1710792438 2024/03/18 20:07:18 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.2 $ */ +/* NetHack 3.7 coloratt.c $NHDT-Date: 1737286550 2025/01/19 03:35:50 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.14 $ */ /* Copyright (c) Pasi Kallinen, 2024 */ /* NetHack may be freely redistributed. See license for details. */ @@ -812,7 +812,6 @@ rgbstr_to_int32(const char *rgbstr) rgbstr ? rgbstr : ""); if (*buf && onlyhexdigits(buf)) { - r = g = b = 0; c_g = c_b = (char *) 0; c_r = cp = buf; while (*cp) { From c97bb2c0a480b61846dc69b1b884be4c7e6a23f3 Mon Sep 17 00:00:00 2001 From: PatR Date: Sat, 18 Jan 2025 19:58:30 -0800 Subject: [PATCH 357/791] static analyzer lint for dig.c, do.c --- src/dig.c | 1 + src/do.c | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/dig.c b/src/dig.c index 00f2f0422..c0c341248 100644 --- a/src/dig.c +++ b/src/dig.c @@ -1642,6 +1642,7 @@ zap_dig(void) if (diridx != DIR_ERR && !conjoined_pits(adjpit, trap_with_u, FALSE)) { digdepth = 0; /* limited to the adjacent location only */ + nhUse(digdepth); if (!(adjpit && is_pit(adjpit->ttyp))) { char buf[BUFSZ]; diff --git a/src/do.c b/src/do.c index 4f633979a..41828b8ac 100644 --- a/src/do.c +++ b/src/do.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 do.c $NHDT-Date: 1704225560 2024/01/02 19:59:20 $ $NHDT-Branch: keni-luabits2 $:$NHDT-Revision: 1.376 $ */ +/* NetHack 3.7 do.c $NHDT-Date: 1737287889 2025/01/19 03:58:09 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.399 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Derek S. Ray, 2015. */ /* NetHack may be freely redistributed. See license for details. */ @@ -224,6 +224,7 @@ flooreffects( } if (!DEADMONSTER(mtmp) && !is_whirly(mtmp->data)) res = FALSE; /* still alive, boulder still intact */ + nhUse(res); } mtmp->mtrapped = 0; } else { From 9e2d862ba9a44cdcb368d5c2639750d7cb219d7d Mon Sep 17 00:00:00 2001 From: PatR Date: Sat, 18 Jan 2025 20:04:26 -0800 Subject: [PATCH 358/791] static analyzer fix for dog.c The missing break meant that executation fell through to the default case and reset xlocale and ylocale to 0. The comment states that this is for the fuzzer; I have no idea whether this fix matters to it. --- src/dog.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/dog.c b/src/dog.c index 38bd92fd9..a80b3679d 100644 --- a/src/dog.c +++ b/src/dog.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 dog.c $NHDT-Date: 1725227804 2024/09/01 21:56:44 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.164 $ */ +/* NetHack 3.7 dog.c $NHDT-Date: 1737287993 2025/01/19 03:59:53 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.178 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2011. */ /* NetHack may be freely redistributed. See license for details. */ @@ -520,6 +520,7 @@ mon_arrive(struct monst *mtmp, int when) && (stway = stairway_find_dir(!builds_up(&u.uz))) != 0) { /* debugfuzzer returns from or enters another branch */ xlocale = stway->sx, ylocale = stway->sy; + break; } else if (!(u.uevent.qexpelled && (Is_qstart(&u.uz0) || Is_qstart(&u.uz)))) { impossible("mon_arrive: no corresponding portal?"); From 7ce0751a6c9fb2575bb02485a4241934e8e7b40d Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sun, 19 Jan 2025 18:56:59 +0200 Subject: [PATCH 359/791] Fix breaking wand of digging and boulders next to lava If one or more boulders were next to lava and hero broke a wand of digging next to that location, the boulder(s) stayed over the lava causing a sanity checking error. --- src/apply.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/apply.c b/src/apply.c index 1de989ac3..376f41b2c 100644 --- a/src/apply.c +++ b/src/apply.c @@ -42,6 +42,7 @@ staticfn void display_grapple_positions(boolean); staticfn int use_grapple(struct obj *); staticfn void discard_broken_wand(void); staticfn void broken_wand_explode(struct obj *, int, int); +staticfn void maybe_dunk_boulders(coordxy, coordxy); staticfn int do_break_wand(struct obj *); staticfn int apply_ok(struct obj *); staticfn int flip_through_book(struct obj *); @@ -3854,6 +3855,18 @@ broken_wand_explode(struct obj *obj, int dmg, int expltype) discard_broken_wand(); } +/* if x,y has lava or water, dunk any boulders at that location into it */ +staticfn void +maybe_dunk_boulders(coordxy x, coordxy y) +{ + struct obj *otmp; + + while (is_pool_or_lava(x, y) && (otmp = sobj_at(BOULDER, x, y)) != 0) { + obj_extract_self(otmp); + (void) boulder_hits_pool(otmp, x,y, FALSE); + } +} + /* return 1 if the wand is broken, hence some time elapsed */ staticfn int do_break_wand(struct obj *obj) @@ -4022,6 +4035,8 @@ do_break_wand(struct obj *obj) } } fill_pit(x, y); + maybe_dunk_boulders(x, y); + recalc_block_point(x, y); continue; } else if (obj->otyp == WAN_CREATE_MONSTER) { /* u.ux,u.uy creates it near you--x,y might create it in rock */ From 663ab8aa89dbf6678567ca0b20ce4f53f046c08e Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sun, 19 Jan 2025 21:16:27 +0200 Subject: [PATCH 360/791] Fix wall spines outside map bounds --- src/zap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/zap.c b/src/zap.c index 9b84caa9e..99729f82c 100644 --- a/src/zap.c +++ b/src/zap.c @@ -5201,7 +5201,7 @@ zap_over_floor( else lev->typ = HWALL; fix_wall_spines(max(0,x-1), max(0,y-1), - min(COLNO,x+1), min(ROWNO,y+1)); + min(COLNO-1,x+1), min(ROWNO-1,y+1)); } else { lev->typ = lava ? ROOM : ICE; } From d8d4f18a00efff9d16c57dda437307616f39c582 Mon Sep 17 00:00:00 2001 From: PatR Date: Sun, 19 Jan 2025 11:23:05 -0800 Subject: [PATCH 361/791] analyzer lint for do_wear.c, dothrow.c --- src/do_wear.c | 4 ++-- src/dothrow.c | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/do_wear.c b/src/do_wear.c index 0655cc764..058d903d7 100644 --- a/src/do_wear.c +++ b/src/do_wear.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 do_wear.c $NHDT-Date: 1727251255 2024/09/25 08:00:55 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.191 $ */ +/* NetHack 3.7 do_wear.c $NHDT-Date: 1737343372 2025/01/19 19:22:52 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.201 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -3017,7 +3017,7 @@ doddoremarm(void) if (flags.menu_style != MENU_TRADITIONAL || (result = ggetobj("take off", select_off, 0, FALSE, (unsigned *) 0)) < -1) - result = menu_remarm(result); + (void) menu_remarm(result); if (svc.context.takeoff.mask) { (void) strncpy(svc.context.takeoff.disrobing, diff --git a/src/dothrow.c b/src/dothrow.c index 57dd5757c..6d99854e7 100644 --- a/src/dothrow.c +++ b/src/dothrow.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 dothrow.c $NHDT-Date: 1709969638 2024/03/09 07:33:58 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.285 $ */ +/* NetHack 3.7 dothrow.c $NHDT-Date: 1737343372 2025/01/19 19:22:52 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.300 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2013. */ /* NetHack may be freely redistributed. See license for details. */ @@ -252,6 +252,7 @@ throw_obj(struct obj *obj, int shotlimit) gm.m_shot.n = multishot; for (gm.m_shot.i = 1; gm.m_shot.i <= gm.m_shot.n; gm.m_shot.i++) { twoweap = u.twoweap; + assert(obj != NULL); /* m_shot.i <= m_shot.n guarantees this */ /* split this object off from its slot if necessary */ if (obj->quan > 1L) { otmp = splitobj(obj, 1L); @@ -2102,6 +2103,7 @@ thitmonst( if (!next2u) sho_obj_return_to_u(obj); obj = addinv(obj); /* back into your inventory */ + nhUse(obj); (void) encumber_msg(); } return 1; /* caller doesn't need to place it */ From 49a28518827fabd353fc91a6806fc76f1b64f8d5 Mon Sep 17 00:00:00 2001 From: PatR Date: Sun, 19 Jan 2025 11:24:40 -0800 Subject: [PATCH 362/791] static analyzer fix for dungeon.c I'm not really sure about this one. insert_branch(branch,) is specified as not accepting a Null pointer and doesn't have any defense against it, but the know level setup seems to allow a null pointer through. I'm not sure whether this is the right fix. --- src/dungeon.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/dungeon.c b/src/dungeon.c index dc8557ed4..47f6e2c49 100644 --- a/src/dungeon.c +++ b/src/dungeon.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 dungeon.c $NHDT-Date: 1715203022 2024/05/08 21:17:02 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.222 $ */ +/* NetHack 3.7 dungeon.c $NHDT-Date: 1737343478 2025/01/19 19:24:38 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.228 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1153,10 +1153,11 @@ fixup_level_locations(void) if (on_level(&br->end2, &knox_level)) break; - if (br) + if (br) { br->end1.dnum = svn.n_dgns; - /* adjust the branch's position on the list */ - insert_branch(br, TRUE); + /* adjust the branch's position on the list */ + insert_branch(br, TRUE); + } } } } @@ -2747,7 +2748,7 @@ overview_stats( char buf[BUFSZ], hdrbuf[QBUFSZ]; long ocount, osize, bcount, bsize, acount, asize; struct cemetery *ce; - mapseen *mptr = find_mapseen(&u.uz); + mapseen *mptr; ocount = bcount = acount = osize = bsize = asize = 0L; for (mptr = svm.mapseenchn; mptr; mptr = mptr->next) { From 047ae6f68ed65206a4ec9c1572d2dec35bd704bd Mon Sep 17 00:00:00 2001 From: PatR Date: Sun, 19 Jan 2025 11:42:02 -0800 Subject: [PATCH 363/791] analyzer lint for zap.c --- src/zap.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/zap.c b/src/zap.c index 99729f82c..ae4a16889 100644 --- a/src/zap.c +++ b/src/zap.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 zap.c $NHDT-Date: 1732979463 2024/11/30 07:11:03 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.551 $ */ +/* NetHack 3.7 zap.c $NHDT-Date: 1737344505 2025/01/19 19:41:45 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.562 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2013. */ /* NetHack may be freely redistributed. See license for details. */ @@ -2076,6 +2076,7 @@ stone_to_flesh_obj(struct obj *obj) /* nonnull */ res = 0; break; } + nhUse(obj); /* avoid 'assigned value not used' for poly_obj() calls */ if (smell) { /* non-meat eaters smell meat, meat eaters smell its flavor; @@ -3215,7 +3216,7 @@ zap_updown(struct obj *obj) /* wand or spell, nonnull */ we need to call it before probing for buried objects */ ltyp = SURFACE_AT(x, y); zap_map(x, y, obj); - map_zapped = TRUE; + /*map_zapped = TRUE; // not needed due to early return*/ if (ltyp == ICE || IS_FURNITURE(ltyp)) { surf = "it"; if (svl.lastseentyp[x][y] != rememberedltyp) @@ -3872,7 +3873,8 @@ bhit( && hits_bars(pobj, x - ddx, y - ddy, x, y, point_blank ? 0 : !rn2(5), 1)) { /* caveat: obj might now be null... */ - obj = *pobj; + obj = *pobj; /* not currently needed due to 'break'; keep */ + nhUse(obj); /* in case usage gets added after the loop */ gb.bhitpos.x -= ddx; gb.bhitpos.y -= ddy; break; From ec855a93c22aab576e40b5fc9ef95c4dbe89cca8 Mon Sep 17 00:00:00 2001 From: PatR Date: Sun, 19 Jan 2025 11:52:44 -0800 Subject: [PATCH 364/791] static analyzer lint for w*.c --- src/windows.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/windows.c b/src/windows.c index a5924b2ae..b929cf62f 100644 --- a/src/windows.c +++ b/src/windows.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 windows.c $NHDT-Date: 1700012891 2023/11/15 01:48:11 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.109 $ */ +/* NetHack 3.7 windows.c $NHDT-Date: 1737345149 2025/01/19 19:52:29 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.138 $ */ /* Copyright (c) D. Cohrs, 1993. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1653,12 +1653,11 @@ choose_classes_menu(const char *prompt, char buf[BUFSZ]; const char *text = 0; boolean selected; - int ret, i, n, next_accelerator, accelerator; + int ret, i, n, next_accelerator, accelerator = 0; int clr = NO_COLOR; if (!class_list || !class_select) return 0; - accelerator = 0; next_accelerator = 'a'; any = cg.zeroany; win = create_nhwindow(NHW_MENU); From 1907dd9cd89fb7e7fa000a41937d475ddf929c83 Mon Sep 17 00:00:00 2001 From: PatR Date: Sun, 19 Jan 2025 11:59:48 -0800 Subject: [PATCH 365/791] analyzer lint for e*.c --- src/engrave.c | 3 ++- src/extralev.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/engrave.c b/src/engrave.c index a11d8bc4c..9db32403d 100644 --- a/src/engrave.c +++ b/src/engrave.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 engrave.c $NHDT-Date: 1713657576 2024/04/20 23:59:36 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.157 $ */ +/* NetHack 3.7 engrave.c $NHDT-Date: 1737345573 2025/01/19 19:59:33 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.165 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1348,6 +1348,7 @@ engrave(void) obj_extract_self(stylus); stylus = hold_another_object(stylus, "You drop one %s!", doname(stylus), (char *) NULL); + nhUse(stylus); } else if (dulled && stylus->known) { /* reflect change in stylus->spe; not needed for splitstack since hold_another_object() does this */ diff --git a/src/extralev.c b/src/extralev.c index 971bf08c1..e0c2afc84 100644 --- a/src/extralev.c +++ b/src/extralev.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 extralev.c $NHDT-Date: 1596498169 2020/08/03 23:42:49 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.19 $ */ +/* NetHack 3.7 extralev.c $NHDT-Date: 1737345573 2025/01/19 19:59:33 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.28 $ */ /* Copyright 1988, 1989 by Ken Arromdee */ /* NetHack may be freely redistributed. See license for details. */ @@ -301,6 +301,7 @@ makerogueghost(void) return; ghost->msleeping = 1; ghost = christen_monst(ghost, roguename()); + nhUse(ghost); if (rn2(4)) { ghostobj = mksobj_at(FOOD_RATION, x, y, FALSE, FALSE); From e0f6c6987b67f665200ceda919d1622914743ca4 Mon Sep 17 00:00:00 2001 From: PatR Date: Sun, 19 Jan 2025 12:16:16 -0800 Subject: [PATCH 366/791] analyzer lint for files.c Not sure about 'do_historical' since it isn't used--or implicitly is always used--without the field-by-field save and restore as an alternative. --- src/files.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/files.c b/src/files.c index 20a25c95d..21dc4f5f0 100644 --- a/src/files.c +++ b/src/files.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 files.c $NHDT-Date: 1717449127 2024/06/03 21:12:07 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.399 $ */ +/* NetHack 3.7 files.c $NHDT-Date: 1737346561 2025/01/19 20:16:01 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.416 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Derek S. Ray, 2015. */ /* NetHack may be freely redistributed. See license for details. */ @@ -348,7 +348,6 @@ fname_decode(char quotechar, char *s, char *callerbuf, int bufsz) sp = s; op = callerbuf; *op = '\0'; - calc = 0; while (*sp) { /* Do we have room for one more character? */ @@ -1096,6 +1095,7 @@ create_savefile(void) nhfp->mode = WRITING; if (program_state.in_self_recover || do_historical) { do_historical = TRUE; /* force it */ + nhUse(do_historical); nhfp->structlevel = TRUE; nhfp->fieldlevel = FALSE; nhfp->addinfo = FALSE; @@ -1150,6 +1150,7 @@ open_savefile(void) nhfp->mode = READING; if (program_state.in_self_recover || do_historical) { do_historical = TRUE; /* force it */ + nhUse(do_historical); nhfp->structlevel = TRUE; nhfp->fieldlevel = FALSE; nhfp->addinfo = FALSE; From e317436e8dd02eb7e0f000a25181c9b5870b9a98 Mon Sep 17 00:00:00 2001 From: PatR Date: Sun, 19 Jan 2025 12:40:28 -0800 Subject: [PATCH 367/791] static analyzer lint for glyphs.c --- src/glyphs.c | 35 ++++++++++++++++------------------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/src/glyphs.c b/src/glyphs.c index d95764060..8b6a77854 100644 --- a/src/glyphs.c +++ b/src/glyphs.c @@ -121,6 +121,7 @@ glyphrep_to_custom_map_entries( if (!glyphid_cache) reslt = 1; /* for debugger use only; no cache available */ + nhUse(reslt); Snprintf(buf, sizeof buf, "%s", op); c_unicode = c_colorval = (char *) 0; @@ -470,6 +471,7 @@ glyphrep(const char *op) if (!glyphid_cache) reslt = 1; /* for debugger use only; no cache available */ + nhUse(reslt); reslt = glyphrep_to_custom_map_entries(op, &glyph); if (reslt) return 1; @@ -908,30 +910,26 @@ parse_id( } else if (glyph_is_body(glyph)) { /* buf2 will hold the distinguishing prefix */ /* buf3 will hold the base name */ - buf2 = ""; /* superfluous */ + buf2 = glyph_is_body_piletop(glyph) + ? "piletop_body_" + : "body_"; buf3 = monsdump[glyph_to_body_corpsenm(glyph)].nm; - if (glyph_is_body_piletop(glyph)) { - buf2 = "piletop_body_"; - } else { - buf2 = "body_"; - } Strcpy(buf[0], "G_"); Strcat(buf[0], buf2); Strcat(buf[0], buf3); } else if (glyph_is_statue(glyph)) { /* buf2 will hold the distinguishing prefix */ /* buf3 will hold the base name */ - buf2 = ""; + buf2 = glyph_is_fem_statue_piletop(glyph) + ? "piletop_statue_of_female_" + : glyph_is_fem_statue(glyph) + ? "statue_of_female_" + : glyph_is_male_statue_piletop(glyph) + ? "piletop_statue_of_male_" + : glyph_is_male_statue(glyph) + ? "statue_of_male_" + : ""; /* shouldn't happen */ buf3 = monsdump[glyph_to_statue_corpsenm(glyph)].nm; - if (glyph_is_fem_statue_piletop(glyph)) { - buf2 = "piletop_statue_of_female_"; - } else if (glyph_is_fem_statue(glyph)) { - buf2 = "statue_of_female_"; - } else if (glyph_is_male_statue_piletop(glyph)) { - buf2 = "piletop_statue_of_male_"; - } else if (glyph_is_male_statue(glyph)) { - buf2 = "statue_of_male_"; - } Strcpy(buf[0], "G_"); Strcat(buf[0], buf2); Strcat(buf[0], buf3); @@ -939,8 +937,6 @@ parse_id( i = glyph_to_obj(glyph); /* buf2 will hold the distinguishing prefix */ /* buf3 will hold the base name */ - buf2 = ""; - buf3 = ""; if (((i > SCR_STINKING_CLOUD) && (i < SCR_MAIL)) || ((i > WAN_LIGHTNING) && (i < GOLD_PIECE))) skip_this_one = TRUE; @@ -960,6 +956,8 @@ parse_id( buf2 = "ring of "; else if (i == LAND_MINE) buf2 = "unset "; + else + buf2 = ""; buf3 = (i == SCR_BLANK_PAPER) ? "blank scroll" : (i == SPE_BLANK_PAPER) ? "blank spellbook" : (i == SLIME_MOLD) ? "slime mold" @@ -1049,7 +1047,6 @@ parse_id( j = glyph - GLYPH_SWALLOW_OFF; cmap = glyph_to_swallow(glyph); mnum = j / ((S_sw_br - S_sw_tl) + 1); - i = cmap - S_sw_tl; Strcpy(buf[3], "swallow "); Strcat(buf[3], monsdump[mnum].nm); Strcat(buf[3], " "); From 3221665f5a98cd21aea5db62c0dd53260ce8020e Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 19 Jan 2025 20:51:46 -0500 Subject: [PATCH 368/791] updates to tradstdc.h Define a macro NH_C to provide a shorter & simpler way to test for which C standard the build is being carried out under (c99 or c23). NH_C > 202300L Being compiled under C23 or greater NH_C > 199900L Being compiled under C99 or greater NH_C > 198900L Being compiled under C89 or greater, or C std could not be determined. While NetHack only requires c99, we've been taking advantage of some c23 features (attributes), if they are available, to allow the use of ATTRNORETURN/NORETURN and FALLTHROUGH on compilers other than gcc. Also add some comment documentation to tradstdc.h about NetHack's use of c99. The sys/unix/Makefile.top change overcomes a warning in the Makefile-generated nhlua.h. That warning arises under some compilers that rely on attribute [[noreturn]] ahead of a declaration (NetHack macro ATTRNORETURN), rather than the trailing gcc __attribute((noreturn)) (NetHack macro NORETURN). The sed command is modified to include ATTRNORETURN at the start of the declaration in addition to the NORETURN at the end of the declaration, in the generated file. That's the same combination that's used for the declaration of other functions that don't return. --- include/tradstdc.h | 145 ++++++++++++++++++++++++++++++++---------- sys/unix/Makefile.top | 5 +- 2 files changed, 116 insertions(+), 34 deletions(-) diff --git a/include/tradstdc.h b/include/tradstdc.h index b607d4a99..ddbf040fb 100644 --- a/include/tradstdc.h +++ b/include/tradstdc.h @@ -317,6 +317,89 @@ typedef genericptr genericptr_t; /* (void *) or (char *) */ #undef signed #endif +/* + * Language + * Standard + * + * NetHack 3.7 range + * / + * / + * C2y X NetHack 3.6 and earlier range + * C23 X / + * C17 X X + * C11 X X + * C99 X X + * C89 X + * + * + * The NetHack 3.7 source code currently makes use of the following + * C99 (and above) language features: + * + * commas at the end of enumerator lists + * variable declarations in for loop initializers + * mixing declarations and code + * variable declaration in for loop + * variadic macros + * 'long long' + * + * The NetHack 3.7 source code adheres to the following greater-than C99 + * language restrictions: + * + * Removal of K&R function definitions + * Removal of implicit int + */ + +/* + * Provide a shorthand way of checking for a certain C standard + * in the NetHack header files by always setting NH_C to one + * of three possible values (as of January 2025): + * + * NH_C > 202300L Being compiled under C23 or greater + * NH_C > 199900L Being compiled under C99 or greater + * NH_C > 198900L Being compiled under C89 or greater, + * or C std could not be determined. + */ +#if defined(__STDC_VERSION__) || defined(__cplusplus) +#if (__STDC_VERSION__ >= 202000L) || defined(__cplusplus) +#define NH_C 202300L +#else +#define NH_C 199900L +#endif /* C23 or C99 */ +#else /* __STDC_VERSION not defined */ +#define NH_C 198900L +#endif /* __STDC_VERSION not defined */ +#ifndef NH_C +#define NH_C 198900L +#endif + +/* NH_C is now defined to 198900L or 199900L or 202300L */ + +#if NH_C >= 202300L +/* Give first priority to standard */ +#ifndef __has_c_attribute +#define __has_c_attribute(x) 0 +#endif +/* + * noreturn + */ +#ifndef ATTRNORETURN +#define ATTRNORETURN [[noreturn]] +/* #warning [[noreturn]] from C23 */ +#endif /* ATTRNORETURN not defined */ +/* + * fallthrough + */ +#if __has_c_attribute(fallthrough) +/* Standard attribute is available, use it. */ +#define FALLTHROUGH [[fallthrough]] +/* #warning [[fallthrough]] from C23 */ +#endif /* __has_c_attribute(fallthrough) */ +#endif /* NH_C >= 202300L */ + +/* + * Compiler-specific + */ + #ifdef __clang__ /* clang's gcc emulation is sufficient for nethack's usage */ #ifndef __GNUC__ @@ -325,26 +408,10 @@ typedef genericptr genericptr_t; /* (void *) or (char *) */ #endif /* - * Give first priority to standard - */ -#if defined(__STDC_VERSION__) || defined(__cplusplus) -#if (__STDC_VERSION__ > 202300L) || defined(__cplusplus) -#ifndef ATTRNORETURN -#define ATTRNORETURN [[noreturn]] -#endif -#ifndef __has_c_attribute -#define __has_c_attribute(x) 0 -#endif /* __has_c_attribute */ -#if __has_c_attribute(fallthrough) -/* Standard attribute is available, use it. */ -#define FALLTHROUGH [[fallthrough]] -#endif /* __has_c_attribute(fallthrough) */ -#endif /* __STDC_VERSION__ gt 202300L || __cplusplus */ -#endif /* __STDC_VERSION || __cplusplus */ - -/* - * Allow gcc2 to check parameters of printf-like calls with -Wformat; - * append this to a prototype declaration (see pline() in extern.h). + * gcc (and also clang which masquerades as__GNUC__==5 due to #define above) + * + * Allow gcc2 and above to check parameters of printf-like calls with + * -Wformat; append this to a prototype declaration (see pline() in extern.h). */ #ifdef __GNUC__ #if (__GNUC__ >= 2) && !defined(USE_OLDARGS) @@ -358,15 +425,10 @@ typedef genericptr genericptr_t; /* (void *) or (char *) */ #ifndef ATTRNORETURN #ifndef NORETURN #define NORETURN __attribute__((noreturn)) -#endif -#endif -#if (!defined(__linux__) && !defined(MACOS)) || defined(GCC_URWARN) -/* disable gcc's __attribute__((__warn_unused_result__)) since explicitly - discarding the result by casting to (void) is not accepted as a 'use' */ -#define __warn_unused_result__ /*empty*/ -#define warn_unused_result /*empty*/ -#endif -#endif +/* #warning NORETURN __attribute__((noreturn)) from __GNUC__ >= 3 */ +#endif /* NORETURN */ +#endif /* ATTRNORETURN */ +#endif /* __GNUC__ >= 3 */ #if __GNUC__ >= 5 #ifndef NONNULLS_DEFINED #define DO_DEFINE_NONNULLS @@ -374,13 +436,24 @@ typedef genericptr genericptr_t; /* (void *) or (char *) */ /* #pragma message is available */ #define NH_PRAGMA_MESSAGE 1 #endif /* __GNUC__ greater than or equal to 5 */ -#endif /* __GNUC__ */ +#if (!defined(__linux__) && !defined(MACOS)) || defined(GCC_URWARN) +/* disable gcc's __attribute__((__warn_unused_result__)) since explicitly + discarding the result by casting to (void) is not accepted as a 'use' */ +#define __warn_unused_result__ /*empty*/ +#define warn_unused_result /*empty*/ +#endif /* GCC_URWARN || !__linux || !MACOS */ +#endif /* __GNUC__ || clang masquerading as __GNUC__==5 */ +/* + * clang-specific + * + */ #if defined(__clang__) #ifndef FALLTHROUGH #if defined(__clang_major__) #if __clang_major__ >= 9 #define FALLTHROUGH __attribute__((fallthrough)) +/* #warning FALLTHROUGH __attribute__((fallthrough)) from clang */ #endif /* __clang_major__ greater than or equal to 9 */ #endif /* __clang_major__ is defined */ #endif /* FALLTHROUGH */ @@ -389,6 +462,9 @@ typedef genericptr genericptr_t; /* (void *) or (char *) */ #endif #endif /* __clang__ */ +/* + * NONNULL args + */ #if defined(DO_DEFINE_NONNULLS) && !defined(NONNULLS_DEFINED) #define NONNULL __attribute__((returns_nonnull)) #define NONNULLPTRS __attribute__((nonnull)) @@ -411,15 +487,20 @@ typedef genericptr genericptr_t; /* (void *) or (char *) */ #define NONNULLARG45 __attribute__((nonnull (4, 5))) /* do_screen_descri... */ #define NONNULLS_DEFINED #undef DO_DEFINE_NONNULLS -#endif /* __clang__ && !NONNULLS_DEFINED */ +#endif /* DO_DEFINE_NONNULLS && !NONNULLS_DEFINED */ +/* + * Microsoft compiler + */ #ifdef _MSC_VER #ifndef ATTRNORETURN #define ATTRNORETURN __declspec(noreturn) +/* #warning ATTRNORETURN __declspec(noreturn) from _MSC_VER */ #endif /* #pragma message is available */ #define NH_PRAGMA_MESSAGE 1 -#endif +#endif /* _MSC_VER */ + /* Fallback implementations */ #ifndef PRINTF_F diff --git a/sys/unix/Makefile.top b/sys/unix/Makefile.top index 45cd7330a..3d7b54727 100644 --- a/sys/unix/Makefile.top +++ b/sys/unix/Makefile.top @@ -150,8 +150,9 @@ $(TOPLUALIB): $(LUATOP)/liblua.a include/nhlua.h: $(TOPLUALIB) echo '/* nhlua.h - generated by top Makefile */' > $@ @echo '#include "../$(LUAHEADERS)/lua.h"' >> $@ - @sed -e '/(lua_error)/!d' -e '/(lua_error)/s/;/ NORETURN;/1' \ - < $(LUAHEADERS)/lua.h >> $@ + @sed -e '/(lua_error)/!d' \ + -e '/(lua_error)/s/LUA_API/ATTRNORETURN LUA_API/1' \ + -e '/(lua_error)/s/;/ NORETURN;/1' < $(LUAHEADERS)/lua.h >> $@ @echo '#include "../$(LUAHEADERS)/lualib.h"' >> $@ @echo '#include "../$(LUAHEADERS)/lauxlib.h"' >> $@ @echo '/*nhlua.h*/' >> $@ From d992155f1fe9a902ee9f7aa83800794c6d7e2fa3 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 19 Jan 2025 21:20:52 -0500 Subject: [PATCH 369/791] follow-up for tradstdc.h remove a duplicate comment --- include/tradstdc.h | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/include/tradstdc.h b/include/tradstdc.h index ddbf040fb..7a89e2775 100644 --- a/include/tradstdc.h +++ b/include/tradstdc.h @@ -338,7 +338,6 @@ typedef genericptr genericptr_t; /* (void *) or (char *) */ * commas at the end of enumerator lists * variable declarations in for loop initializers * mixing declarations and code - * variable declaration in for loop * variadic macros * 'long long' * @@ -354,9 +353,9 @@ typedef genericptr genericptr_t; /* (void *) or (char *) */ * in the NetHack header files by always setting NH_C to one * of three possible values (as of January 2025): * - * NH_C > 202300L Being compiled under C23 or greater - * NH_C > 199900L Being compiled under C99 or greater - * NH_C > 198900L Being compiled under C89 or greater, + * NH_C >= 202300L Being compiled under C23 or greater + * NH_C >= 199900L Being compiled under C99 or greater + * NH_C >= 198900L Being compiled under C89 or greater, * or C std could not be determined. */ #if defined(__STDC_VERSION__) || defined(__cplusplus) From 9da836fb4a4b634835828b7972bc7da3047bcff7 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 19 Jan 2025 21:55:36 -0500 Subject: [PATCH 370/791] more follow-up: Qt build fix --- include/tradstdc.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/tradstdc.h b/include/tradstdc.h index 7a89e2775..f2ebeb74e 100644 --- a/include/tradstdc.h +++ b/include/tradstdc.h @@ -358,8 +358,8 @@ typedef genericptr genericptr_t; /* (void *) or (char *) */ * NH_C >= 198900L Being compiled under C89 or greater, * or C std could not be determined. */ -#if defined(__STDC_VERSION__) || defined(__cplusplus) -#if (__STDC_VERSION__ >= 202000L) || defined(__cplusplus) +#if defined(__STDC_VERSION__) +#if (__STDC_VERSION__ >= 202000L) #define NH_C 202300L #else #define NH_C 199900L From 8de3aa564f202c7c74cf51032d3d4b2e33db1489 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 19 Jan 2025 22:02:43 -0500 Subject: [PATCH 371/791] update tested versions of Visual Studio 2025-01-19 --- sys/windows/Makefile.nmake | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sys/windows/Makefile.nmake b/sys/windows/Makefile.nmake index 51969c9c3..4c11ff77f 100644 --- a/sys/windows/Makefile.nmake +++ b/sys/windows/Makefile.nmake @@ -1,5 +1,5 @@ # NetHack 3.7 Makefile.nmake -# Copyright (c) NetHack Development Team 1993-2024 +# Copyright (c) NetHack Development Team 1993-2025 # #============================================================================== # Build Tools Environment @@ -9,7 +9,7 @@ # # Visual Studio Compilers Tested: # - Microsoft Visual Studio 2019 Community Edition v 16.11.42 -# - Microsoft Visual Studio 2022 Community Edition v 17.12.2 +# - Microsoft Visual Studio 2022 Community Edition v 17.12.4 # #============================================================================== # This is used for building two distinct executables of NetHack: @@ -1177,7 +1177,7 @@ rc=Rc.exe # # Recently tested versions: TESTEDVS2019 = 14.29.30157.0 -TESTEDVS2022 = 14.42.34435.0 +TESTEDVS2022 = 14.42.34436.0 VS2019CUR = $(TESTEDVS2019:.=) VS2022CUR = $(TESTEDVS2022:.=) From 3a64b404e370d109c8fb7d277bb192a68eb9d8f6 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 19 Jan 2025 22:36:38 -0500 Subject: [PATCH 372/791] Remove an unused macro that conflicts with pdcursesmod In file included from ../include/config.h:723:0, from ../include/hack.h:10, from files.c:8: ../include/global.h:519:24: error: expected ')' before '<=' token #define unctrl(c) ((c) <= C('z') ? (0x60 | (c)) : (c)) ^ ../lib/pdcursesmod/curses.h:1686:16: note: in expansion of macro 'unctrl' PDCEX char *unctrl(chtype); ^~~~~~ --- include/global.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/global.h b/include/global.h index 197a92da1..77740213b 100644 --- a/include/global.h +++ b/include/global.h @@ -512,7 +512,6 @@ extern struct nomakedefs_s nomakedefs; #define C(c) (0x1f & (c)) #endif -#define unctrl(c) ((c) <= C('z') ? (0x60 | (c)) : (c)) #define unmeta(c) (0x7f & (c)) /* Game log message type flags */ From 6368bf2e7303836d3bfdfbcff3b1298acbebf45c Mon Sep 17 00:00:00 2001 From: PatR Date: Sun, 19 Jan 2025 22:53:03 -0800 Subject: [PATCH 373/791] analyzer lint for i*.c --- src/insight.c | 5 +++-- src/invent.c | 13 +++++++------ 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/insight.c b/src/insight.c index 96ce1e0b8..0000db937 100644 --- a/src/insight.c +++ b/src/insight.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 insight.c $NHDT-Date: 1724094296 2024/08/19 19:04:56 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.115 $ */ +/* NetHack 3.7 insight.c $NHDT-Date: 1737384766 2025/01/20 06:52:46 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.128 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1073,7 +1073,8 @@ status_enlightenment(int mode, int final) || strcmp(MGIVENNAME(u.ustuck), "it") != 0)) Strcpy(heldmon, "an unseen creature"); } - if (u.uswallow) { /* implies u.ustuck is non-Null */ + if (u.uswallow) { + assert(u.ustuck != NULL); /* implied by u.uswallow */ Snprintf(buf, sizeof buf, "%s by %s", digests(u.ustuck->data) ? "swallowed" : "engulfed", heldmon); diff --git a/src/invent.c b/src/invent.c index ed0652dc9..aa1e0de67 100644 --- a/src/invent.c +++ b/src/invent.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 invent.c $NHDT-Date: 1724094299 2024/08/19 19:04:59 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.516 $ */ +/* NetHack 3.7 invent.c $NHDT-Date: 1737384766 2025/01/20 06:52:46 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.531 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Derek S. Ray, 2015. */ /* NetHack may be freely redistributed. See license for details. */ @@ -2804,7 +2804,7 @@ xprname( char suffix[80]; /* plenty of room for count and hallucinatory currency */ int sfxlen, txtlen; /* signed int for %*s formatting */ const char *fmt; - boolean use_invlet = (flags.invlet_constant + boolean use_invlet = (flags.invlet_constant && obj != NULL && let != CONTAINED_SYM && let != HANDS_SYM); long savequan = 0L; @@ -2819,8 +2819,10 @@ xprname( * > Then the object is contained and doesn't have an inventory letter. */ fmt = "%c - %.*s%s"; - if (!txt) + if (!txt) { + assert(obj != NULL); txt = doname(obj); + } txtlen = (int) strlen(txt); if (cost != 0L || let == '*') { @@ -3632,11 +3634,10 @@ display_pickinv( Loot *sortedinvent, *srtinv; int8_t prevorderclass; boolean (*filter)(struct obj *) = (boolean (*)(OBJ_P)) 0; - boolean wizid = (wizard && iflags.override_ID), gotsomething = FALSE; int clr = NO_COLOR, menu_behavior = MENU_BEHAVE_STANDARD; boolean show_gold = TRUE, inuse_only = FALSE, skipped_gold = FALSE, - doing_perm_invent = FALSE, save_flags_sortpack = flags.sortpack, + doing_perm_invent = FALSE, save_flags_sortpack, usextra = (xtra_choice && allowxtra); if (lets && !*lets) @@ -4231,7 +4232,7 @@ dounpaid( } win = create_nhwindow(NHW_MENU); - cost = totcost = 0; + totcost = 0L; num_so_far = 0; /* count of # printed so far */ if (!flags.invlet_constant) reassign(); From 41f65826905c18693f26406c7fd41814470bd6b1 Mon Sep 17 00:00:00 2001 From: PatR Date: Sun, 19 Jan 2025 23:06:38 -0800 Subject: [PATCH 374/791] analyzer lint for hack.c --- src/hack.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hack.c b/src/hack.c index c7dcf0c24..1eaf39caf 100644 --- a/src/hack.c +++ b/src/hack.c @@ -2254,6 +2254,7 @@ domove_fight_empty(coordxy x, coordxy y) map_object(boulder, TRUE); newsym(x, y); glyph = glyph_at(x, y); /* might have just changed */ + nhUse(glyph); if (boulder) { Strcpy(buf, ansimpleoname(boulder)); From f2c4396641f8c425811fe3a7bb4465ff574918b9 Mon Sep 17 00:00:00 2001 From: PatR Date: Sun, 19 Jan 2025 23:31:26 -0800 Subject: [PATCH 375/791] analyzer lint for m[a-k]*.c --- src/mklev.c | 15 ++++++++------- src/mkmaze.c | 3 +-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/mklev.c b/src/mklev.c index def62d5e0..6cffe2a52 100644 --- a/src/mklev.c +++ b/src/mklev.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 mklev.c $NHDT-Date: 1728168518 2024/10/05 22:48:38 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.191 $ */ +/* NetHack 3.7 mklev.c $NHDT-Date: 1737387068 2025/01/20 07:31:08 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.194 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Alex Smith, 2017. */ /* NetHack may be freely redistributed. See license for details. */ @@ -90,7 +90,10 @@ door_into_nonjoined(coordxy x, coordxy y) } staticfn boolean -finddpos(coord *cc, coordxy xl, coordxy yl, coordxy xh, coordxy yh) +finddpos( + coord *cc, + coordxy xl, coordxy yl, + coordxy xh, coordxy yh) { coordxy x, y; @@ -109,8 +112,8 @@ finddpos(coord *cc, coordxy xl, coordxy yl, coordxy xh, coordxy yh) if (IS_DOOR(levl[x][y].typ) || levl[x][y].typ == SDOOR) goto gotit; /* cannot find something reasonable -- strange */ - x = xl; - y = yh; + cc->x = xl; + cc->y = yh; return FALSE; gotit: cc->x = x; @@ -1535,7 +1538,6 @@ place_branch( coord m = {0}; d_level *dest; boolean make_stairs; - struct mkroom *br_room; /* * Return immediately if there is no branch to make or we have @@ -1546,14 +1548,13 @@ place_branch( if (!br || gm.made_branch) return; - nhUse(br_room); if (!x) { /* find random coordinates for branch */ /* br_room = find_branch_room(&m); */ (void) find_branch_room(&m); /* sets m via mazexy() or somexy() */ x = m.x; y = m.y; } else { - br_room = pos_to_room(x, y); + (void) pos_to_room(x, y); } if (on_level(&br->end1, &u.uz)) { diff --git a/src/mkmaze.c b/src/mkmaze.c index e43b34caf..df83d2136 100644 --- a/src/mkmaze.c +++ b/src/mkmaze.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 mkmaze.c $NHDT-Date: 1712454188 2024/04/07 01:43:08 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.163 $ */ +/* NetHack 3.7 mkmaze.c $NHDT-Date: 1737387068 2025/01/20 07:31:08 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.176 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Pasi Kallinen, 2018. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1009,7 +1009,6 @@ create_maze(int corrwid, int wallthick, boolean rmdeadends) mx = (x % 2) ? corrwid : (x == 2 || x == rdx * 2) ? 1 : wallthick; ry = y = 2; while (ry < gy.y_maze_max) { - dx = dy = 0; my = (y % 2) ? corrwid : (y == 2 || y == rdy * 2) ? 1 : wallthick; From df06fc36f253905ac8d9e3c8f15751ef4be2e628 Mon Sep 17 00:00:00 2001 From: PatR Date: Mon, 20 Jan 2025 00:58:06 -0800 Subject: [PATCH 376/791] analyzer lint for m[o-u]*.c The changes to muse.c are more extensive that most. The many new panic calls could be simplified by assigning a dummy object for the trap cases. --- src/monmove.c | 3 ++- src/mthrowu.c | 12 ++++++---- src/muse.c | 65 +++++++++++++++++++++++++++++++++++++++++++-------- 3 files changed, 64 insertions(+), 16 deletions(-) diff --git a/src/monmove.c b/src/monmove.c index fb8adfd48..9c2191f65 100644 --- a/src/monmove.c +++ b/src/monmove.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 monmove.c $NHDT-Date: 1722116054 2024/07/27 21:34:14 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.255 $ */ +/* NetHack 3.7 monmove.c $NHDT-Date: 1737392015 2025/01/20 08:53:35 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.266 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2006. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1471,6 +1471,7 @@ postmov( if (vamp_shift(mtmp, &mons[PM_FOG_CLOUD], ((seenflgs & 1) != 0) ? TRUE : FALSE)) { ptr = mtmp->data; /* update cached value */ + nhUse(ptr); } if (seenflgs) { remove_monster(omx, omy); diff --git a/src/mthrowu.c b/src/mthrowu.c index 1d3e749ef..6dc82377e 100644 --- a/src/mthrowu.c +++ b/src/mthrowu.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 mthrowu.c $NHDT-Date: 1629497158 2021/08/20 22:05:58 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.117 $ */ +/* NetHack 3.7 mthrowu.c $NHDT-Date: 1737392015 2025/01/20 08:53:35 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.173 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Pasi Kallinen, 2016. */ /* NetHack may be freely redistributed. See license for details. */ @@ -196,7 +196,9 @@ drop_throw( /* calculate multishot volley count for mtmp throwing otmp (if not ammo) or shooting otmp with mwep (if otmp is ammo and mwep appropriate launcher) */ staticfn int -monmulti(struct monst *mtmp, struct obj *otmp, struct obj *mwep) +monmulti( + struct monst *mtmp, + struct obj *otmp, struct obj *mwep) { int multishot = 1; @@ -238,11 +240,11 @@ monmulti(struct monst *mtmp, struct obj *otmp, struct obj *mwep) /* racial bonus */ if ((is_elf(mtmp->data) && otmp->otyp == ELVEN_ARROW - && mwep->otyp == ELVEN_BOW) + && mwep && mwep->otyp == ELVEN_BOW) || (is_orc(mtmp->data) && otmp->otyp == ORCISH_ARROW - && mwep->otyp == ORCISH_BOW) + && mwep && mwep->otyp == ORCISH_BOW) || (is_gnome(mtmp->data) && otmp->otyp == CROSSBOW_BOLT - && mwep->otyp == CROSSBOW)) + && mwep && mwep->otyp == CROSSBOW)) multishot++; } diff --git a/src/muse.c b/src/muse.c index 54c92f4d0..5715e9342 100644 --- a/src/muse.c +++ b/src/muse.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 muse.c $NHDT-Date: 1715109270 2024/05/07 19:14:30 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.218 $ */ +/* NetHack 3.7 muse.c $NHDT-Date: 1737392015 2025/01/20 08:53:35 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.234 $ */ /* Copyright (C) 1990 by Ken Arromdee */ /* NetHack may be freely redistributed. See license for details. */ @@ -15,10 +15,10 @@ */ staticfn int precheck(struct monst *, struct obj *); -staticfn void mzapwand(struct monst *, struct obj *, boolean); -staticfn void mplayhorn(struct monst *, struct obj *, boolean); -staticfn void mreadmsg(struct monst *, struct obj *); -staticfn void mquaffmsg(struct monst *, struct obj *); +staticfn void mzapwand(struct monst *, struct obj *, boolean) NONNULLPTRS; +staticfn void mplayhorn(struct monst *, struct obj *, boolean) NONNULLPTRS; +staticfn void mreadmsg(struct monst *, struct obj *) NONNULLPTRS; +staticfn void mquaffmsg(struct monst *, struct obj *) NONNULLPTRS; staticfn boolean m_use_healing(struct monst *); staticfn boolean m_sees_sleepy_soldier(struct monst *); staticfn void m_tele(struct monst *, boolean, boolean, int); @@ -793,6 +793,7 @@ mon_escape(struct monst *mtmp, boolean vismon) int use_defensive(struct monst *mtmp) { + static const char MissingDefensiveItem[] = "use_defensive: no %s"; int i, fleetim; struct obj *otmp = gm.m.defensive; boolean vis, vismon, oseen; @@ -815,6 +816,8 @@ use_defensive(struct monst *mtmp) switch (gm.m.has_defense) { case MUSE_UNICORN_HORN: + if (!otmp) + panic(MissingDefensiveItem, "unicorn horn"); if (vismon) { if (otmp) pline_mon(mtmp, "%s uses a unicorn horn!", Monnam(mtmp)); @@ -831,6 +834,8 @@ use_defensive(struct monst *mtmp) impossible("No need for unicorn horn?"); return 2; case MUSE_BUGLE: + if (!otmp) + panic(MissingDefensiveItem, "bugle"); if (vismon) { pline_mon(mtmp, "%s plays %s!", Monnam(mtmp), doname(otmp)); } else if (!Deaf) { @@ -840,6 +845,8 @@ use_defensive(struct monst *mtmp) awaken_soldiers(mtmp); return 2; case MUSE_WAN_TELEPORTATION_SELF: + if (!otmp) + panic(MissingDefensiveItem, "wand of teleportation"); if ((mtmp->isshk && inhishop(mtmp)) || mtmp->isgd || mtmp->ispriest) return 2; m_flee(mtmp); @@ -847,6 +854,8 @@ use_defensive(struct monst *mtmp) m_tele(mtmp, vismon, oseen, WAN_TELEPORTATION); return 2; case MUSE_WAN_TELEPORTATION: + if (!otmp) + panic(MissingDefensiveItem, "wand of teleportation"); gz.zap_oseen = oseen; mzapwand(mtmp, otmp, FALSE); gm.m_using = TRUE; @@ -857,8 +866,11 @@ use_defensive(struct monst *mtmp) gm.m_using = FALSE; return 2; case MUSE_SCR_TELEPORTATION: { - int obj_is_cursed = otmp->cursed; + int obj_is_cursed; + if (!otmp) + panic(MissingDefensiveItem, "scroll of teleportation"); + obj_is_cursed = otmp->cursed; if (mtmp->isshk || mtmp->isgd || mtmp->ispriest) return 2; m_flee(mtmp); @@ -901,6 +913,8 @@ use_defensive(struct monst *mtmp) return 2; } case MUSE_WAN_DIGGING: + if (!otmp) + panic(MissingDefensiveItem, "wand of digging"); m_flee(mtmp); mzapwand(mtmp, otmp, FALSE); if (oseen) @@ -954,6 +968,8 @@ use_defensive(struct monst *mtmp) (coord *) 0); return 2; case MUSE_WAN_UNDEAD_TURNING: + if (!otmp) + panic(MissingDefensiveItem, "wand of undead turning"); gz.zap_oseen = oseen; mzapwand(mtmp, otmp, FALSE); gm.m_using = TRUE; @@ -967,6 +983,8 @@ use_defensive(struct monst *mtmp) struct permonst *pm = !is_pool(mtmp->mx, mtmp->my) ? 0 : &mons[u.uinwater ? PM_GIANT_EEL : PM_CROCODILE]; + if (!otmp) + panic(MissingDefensiveItem, "wand of create monster"); if (!enexto(&cc, mtmp->mx, mtmp->my, pm)) return 0; mzapwand(mtmp, otmp, FALSE); @@ -982,6 +1000,8 @@ use_defensive(struct monst *mtmp) struct monst *mon; boolean known = FALSE; + if (!otmp) + panic(MissingDefensiveItem, "scroll of create monster"); if (!rn2(73)) cnt += rnd(4); if (mtmp->mconf || otmp->cursed) @@ -1051,8 +1071,8 @@ use_defensive(struct monst *mtmp) if (Inhell && mon_has_amulet(mtmp) && !rn2(4) && (dunlev(&u.uz) < dunlevs_in_dungeon(&u.uz) - 3)) { if (vismon) - pline( - "As %s climbs the stairs, a mysterious force momentarily surrounds %s...", + pline("As %s climbs the stairs, a mysterious force" + " momentarily surrounds %s...", mon_nam(mtmp), mhim(mtmp)); /* simpler than for the player; this will usually be the Wizard and he'll immediately go right to the @@ -1137,6 +1157,8 @@ use_defensive(struct monst *mtmp) m_tele(mtmp, vismon, FALSE, 0); return 2; case MUSE_POT_HEALING: + if (!otmp) + panic(MissingDefensiveItem, "potioh of healing"); mquaffmsg(mtmp, otmp); i = d(6 + 2 * bcsign(otmp), 4); healmon(mtmp, i, 1); @@ -1149,6 +1171,8 @@ use_defensive(struct monst *mtmp) m_useup(mtmp, otmp); return 2; case MUSE_POT_EXTRA_HEALING: + if (!otmp) + panic(MissingDefensiveItem, "potioh of extra healing"); mquaffmsg(mtmp, otmp); i = d(6 + 2 * bcsign(otmp), 8); healmon(mtmp, i, otmp->blessed ? 5 : 2); @@ -1161,6 +1185,8 @@ use_defensive(struct monst *mtmp) m_useup(mtmp, otmp); return 2; case MUSE_POT_FULL_HEALING: + if (!otmp) + panic(MissingDefensiveItem, "potioh of full healing"); mquaffmsg(mtmp, otmp); if (otmp->otyp == POT_SICKNESS) unbless(otmp); /* Pestilence */ @@ -1174,6 +1200,8 @@ use_defensive(struct monst *mtmp) m_useup(mtmp, otmp); return 2; case MUSE_LIZARD_CORPSE: + if (!otmp) + panic(MissingDefensiveItem, "lizard corpse"); /* not actually called for its unstoning effect */ mon_consume_unstone(mtmp, otmp, FALSE, FALSE); return 2; @@ -2242,8 +2270,10 @@ mloot_container( if (!rn2(nitems + 1)) break; nitems = rn2(nitems); - for (xobj = container->cobj; nitems > 0; xobj = xobj->nobj) - --nitems; + for (xobj = container->cobj; xobj != 0; xobj = xobj->nobj) + if (--nitems < 0) + break; + assert(xobj != NULL); container->cknown = 0; /* hero no longer knows container's contents * even if [attempted] removal is observed */ @@ -2304,6 +2334,7 @@ DISABLE_WARNING_UNREACHABLE_CODE int use_misc(struct monst *mtmp) { + static const char MissingMiscellaneousItem[] = "use_misc: no %s"; char nambuf[BUFSZ]; boolean vis, vismon, vistrapspot, oseen; int i; @@ -2318,6 +2349,8 @@ use_misc(struct monst *mtmp) switch (gm.m.has_misc) { case MUSE_POT_GAIN_LEVEL: + if (!otmp) + panic(MissingMiscellaneousItem, "potion of gain level"); mquaffmsg(mtmp, otmp); if (otmp->cursed) { if (Can_rise_up(mtmp->mx, mtmp->my, &u.uz)) { @@ -2359,6 +2392,8 @@ use_misc(struct monst *mtmp) return 2; case MUSE_WAN_MAKE_INVISIBLE: case MUSE_POT_INVISIBILITY: + if (!otmp) + panic(MissingMiscellaneousItem, "potion of invisibility"); if (otmp->otyp == WAN_MAKE_INVISIBLE) { mzapwand(mtmp, otmp, TRUE); } else @@ -2386,10 +2421,14 @@ use_misc(struct monst *mtmp) } return 2; case MUSE_WAN_SPEED_MONSTER: + if (!otmp) + panic(MissingMiscellaneousItem, "wand of speed monster"); mzapwand(mtmp, otmp, TRUE); mon_adjust_speed(mtmp, 1, otmp); return 2; case MUSE_POT_SPEED: + if (!otmp) + panic(MissingMiscellaneousItem, "potion of speed"); mquaffmsg(mtmp, otmp); /* note difference in potion effect due to substantially different methods of maintaining speed ratings: @@ -2399,6 +2438,8 @@ use_misc(struct monst *mtmp) m_useup(mtmp, otmp); return 2; case MUSE_WAN_POLYMORPH: + if (!otmp) + panic(MissingMiscellaneousItem, "wand of polymorph"); mzapwand(mtmp, otmp, TRUE); (void) newcham(mtmp, muse_newcham_mon(mtmp), NC_VIA_WAND_OR_SPELL | NC_SHOW_MSG); @@ -2406,6 +2447,8 @@ use_misc(struct monst *mtmp) makeknown(WAN_POLYMORPH); return 2; case MUSE_POT_POLYMORPH: + if (!otmp) + panic(MissingMiscellaneousItem, "potion of polymorph"); mquaffmsg(mtmp, otmp); m_useup(mtmp, otmp); if (vismon) @@ -2441,6 +2484,8 @@ use_misc(struct monst *mtmp) (void) newcham(mtmp, (struct permonst *) 0, NC_SHOW_MSG); return 2; case MUSE_BAG: + if (!otmp) + panic(MissingMiscellaneousItem, "container"); return mloot_container(mtmp, otmp, vismon); case MUSE_BULLWHIP: /* attempt to disarm hero */ From 8fe02c2a7cb0222fa22c2f7021b708b01b179cae Mon Sep 17 00:00:00 2001 From: PatR Date: Mon, 20 Jan 2025 08:39:33 -0800 Subject: [PATCH 377/791] analyzer "lint" for muse.c fix Overzealous change yesterday. For use_defensive(), the unicorn horn case already has guards for Null item and the added one issues bogus panic() when a unicorn or ki-rin uses its own horn. --- src/muse.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/muse.c b/src/muse.c index 5715e9342..b044af098 100644 --- a/src/muse.c +++ b/src/muse.c @@ -816,8 +816,7 @@ use_defensive(struct monst *mtmp) switch (gm.m.has_defense) { case MUSE_UNICORN_HORN: - if (!otmp) - panic(MissingDefensiveItem, "unicorn horn"); + /* unlike most defensive cases, unicorn horn object is optional */ if (vismon) { if (otmp) pline_mon(mtmp, "%s uses a unicorn horn!", Monnam(mtmp)); @@ -830,8 +829,9 @@ use_defensive(struct monst *mtmp) mtmp->mconf = mtmp->mstun = 0; if (vismon) pline_mon(mtmp, "%s seems steadier now.", Monnam(mtmp)); - } else + } else { impossible("No need for unicorn horn?"); + } return 2; case MUSE_BUGLE: if (!otmp) From 0c187929168f97d0678abfc3c0170670d9fc737d Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Mon, 20 Jan 2025 19:24:09 +0200 Subject: [PATCH 378/791] Fix vision when vault guard clears corridor --- src/vault.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/vault.c b/src/vault.c index c6169dfac..9335c4ac6 100644 --- a/src/vault.c +++ b/src/vault.c @@ -99,8 +99,7 @@ clear_fcorr(struct monst *grd, boolean forceshow) } del_engr_at(fcx, fcy); map_location(fcx, fcy, 1); /* bypass vision */ - if (!ACCESSIBLE(lev->typ)) - block_point(fcx, fcy); + recalc_block_point(fcx, fcy); gv.vision_full_recalc = 1; egrd->fcbeg++; } From 991a1dbe4305ca1f8547b22bc8f8c8616104aa5f Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Mon, 20 Jan 2025 19:26:08 +0200 Subject: [PATCH 379/791] Fix exploding landmine and boulders next to lava Same issue as with breaking a wand of digging in commit 7ce0751a --- include/extern.h | 1 + src/apply.c | 3 +-- src/trap.c | 2 ++ 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/include/extern.h b/include/extern.h index ccab64021..6db547e30 100644 --- a/include/extern.h +++ b/include/extern.h @@ -128,6 +128,7 @@ extern void reset_trapset(void); extern int use_whip(struct obj *) NONNULLPTRS; extern boolean could_pole_mon(void); extern int use_pole(struct obj *, boolean) NONNULLPTRS; +extern void maybe_dunk_boulders(coordxy, coordxy); extern void fig_transform(union any *, long) NONNULLARG1; extern int unfixable_trouble_count(boolean); diff --git a/src/apply.c b/src/apply.c index 376f41b2c..6bf45b266 100644 --- a/src/apply.c +++ b/src/apply.c @@ -42,7 +42,6 @@ staticfn void display_grapple_positions(boolean); staticfn int use_grapple(struct obj *); staticfn void discard_broken_wand(void); staticfn void broken_wand_explode(struct obj *, int, int); -staticfn void maybe_dunk_boulders(coordxy, coordxy); staticfn int do_break_wand(struct obj *); staticfn int apply_ok(struct obj *); staticfn int flip_through_book(struct obj *); @@ -3856,7 +3855,7 @@ broken_wand_explode(struct obj *obj, int dmg, int expltype) } /* if x,y has lava or water, dunk any boulders at that location into it */ -staticfn void +void maybe_dunk_boulders(coordxy x, coordxy y) { struct obj *otmp; diff --git a/src/trap.c b/src/trap.c index 3097a2e6f..06e54791e 100644 --- a/src/trap.c +++ b/src/trap.c @@ -3133,6 +3133,8 @@ blow_up_landmine(struct trap *trap) } } fill_pit(x, y); + maybe_dunk_boulders(x, y); + recalc_block_point(x, y); spot_checks(x, y, old_typ); } From 1acc272718f445d39b15332c38dd4e7532345724 Mon Sep 17 00:00:00 2001 From: PatR Date: Mon, 20 Jan 2025 10:24:12 -0800 Subject: [PATCH 380/791] fix memory leak for knight's starting pony makemon() has a 1% chance to bestow a worn saddle when creating any rideable monster. If that chance kicked in on a knight's starting pony, an extra saddle would end up being created but not worn nor in inventory nor on floor so not be freed when the game ended. That 1% chance also overrode saddle suppression for pauper knights. There wouldn't be any extra saddle but their pony could start with one, against intent. Have makedog() (which is only used for starting pet) tell makemon() to suppress inventory when creating the initial pet. --- doc/fixes3-7-0.txt | 3 +++ src/dog.c | 9 +++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index a4db52429..befaae8f6 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -2088,6 +2088,9 @@ shop bug: buying a container with unpaid items in it could produce impossible "unpaid_cost: object not on any bill" warnings when walking into/against a locked closed door, 'autounlock'==kick didn't execute kick when player answered yes to "Door is locked. Kick it?" +having a 1% chance of creating rideable monsters with worn saddle gave knights + a 1% chance of creating an extra saddle for starting pony; it wasn't + tracked with other objects so produced a trivial memory leak Fixes to 3.7.0-x Platform and/or Interface Problems Exposed Via git Repository diff --git a/src/dog.c b/src/dog.c index a80b3679d..7fffb6da9 100644 --- a/src/dog.c +++ b/src/dog.c @@ -217,7 +217,12 @@ makedog(void) petname = "Sirius"; /* Orion's dog */ } - mtmp = makemon(&mons[pettype], u.ux, u.uy, MM_EDOG); + /* specifying NO_MINVENT prevents makemon() from having a 1% chance + of creating a pony with an already worn saddle; dogs and cats + aren't affected because they don't have any initial inventory + [if anybody adds stranger pets that are expected to have such, + they'll need to modify this] */ + mtmp = makemon(&mons[pettype], u.ux, u.uy, MM_EDOG | NO_MINVENT); if (!mtmp) return ((struct monst *) 0); /* pets were genocided [how?] */ @@ -225,7 +230,7 @@ makedog(void) if (!svc.context.startingpet_mid) { svc.context.startingpet_mid = mtmp->m_id; if (!u.uroleplay.pauper) { - /* initial horses already wear saddle (unless hero is a pauper) */ + /* initial horses start wearing a saddle (pauper hero excluded) */ if (pettype == PM_PONY && (otmp = mksobj(SADDLE, TRUE, FALSE)) != 0) { /* pseudo initial inventory; saddle is not actually in hero's From 61f969e88b3bb7b4f8187b917876b0e13247805f Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 20 Jan 2025 14:36:28 -0500 Subject: [PATCH 381/791] follow-up for put_saddle_on_mon() Commit 1acc2727 helped ensure that the which_armor(mtmp, W_SADDLE) test at the top of put_saddle_on_mon() wouldn't lead to an obj leak. This commit covers off the adjacent can_saddle() test in put_saddle_on_mon(), because if that failed, it could also lead to a memory leak of the saddle obj passed by the caller. - have put_saddle_on_mon() create and use its own saddle obj if a NULL saddle obj is passed, instead of having to do that in the caller. - where an existing saddle obj needs to be passed from the caller, ensure that the caller has done its own can_saddle(mon) check prior to calling put_saddle_on_mon(), so that the can_saddle() test in put_saddle_on_mon() won't fail. - lastly, add an impossible() to put_saddle_on_mon() to catch a failure when a saddle obj is passed from the caller and either test has failed, just in case. That should not happen with any of the existing cases now, but it will provide some bullet-proofing for new code, new callers. --- include/extern.h | 2 +- src/dog.c | 11 ++++------- src/makemon.c | 6 +++--- src/read.c | 6 +++--- src/sp_lev.c | 2 +- src/steed.c | 14 +++++++++++++- 6 files changed, 25 insertions(+), 16 deletions(-) diff --git a/include/extern.h b/include/extern.h index 6db547e30..d14e6d30c 100644 --- a/include/extern.h +++ b/include/extern.h @@ -3056,7 +3056,7 @@ extern struct obj *findgold(struct obj *) NO_NNARGS; extern void rider_cant_reach(void); extern boolean can_saddle(struct monst *) NONNULLARG1; extern int use_saddle(struct obj *) NONNULLARG1; -extern void put_saddle_on_mon(struct obj *, struct monst *) NONNULLARG12; +extern void put_saddle_on_mon(struct obj *, struct monst *) NONNULLARG2; extern boolean can_ride(struct monst *) NONNULLARG1; extern int doride(void); extern boolean mount_steed(struct monst *, boolean) NO_NNARGS; diff --git a/src/dog.c b/src/dog.c index 7fffb6da9..07336ef71 100644 --- a/src/dog.c +++ b/src/dog.c @@ -191,7 +191,6 @@ struct monst * makedog(void) { struct monst *mtmp; - struct obj *otmp; const char *petname; int pettype; @@ -231,12 +230,10 @@ makedog(void) svc.context.startingpet_mid = mtmp->m_id; if (!u.uroleplay.pauper) { /* initial horses start wearing a saddle (pauper hero excluded) */ - if (pettype == PM_PONY - && (otmp = mksobj(SADDLE, TRUE, FALSE)) != 0) { - /* pseudo initial inventory; saddle is not actually in hero's - * invent so assume that update_inventory() isn't needed */ - fully_identify_obj(otmp); - put_saddle_on_mon(otmp, mtmp); + if (pettype == PM_PONY) { + /* NULL obj arg means put_saddle_on_mon() + * will carry out the saddle creation */ + put_saddle_on_mon((struct obj *) 0, mtmp); } } } else { diff --git a/src/makemon.c b/src/makemon.c index 9ff2c2da5..a7e52bf47 100644 --- a/src/makemon.c +++ b/src/makemon.c @@ -1439,9 +1439,9 @@ makemon( if (!rn2(100) && is_domestic(ptr) && can_saddle(mtmp) && !which_armor(mtmp, W_SADDLE)) { - struct obj *otmp = mksobj(SADDLE, TRUE, FALSE); - - put_saddle_on_mon(otmp, mtmp); + /* NULL obj arg means put_saddle_on_mon() + * will create the saddle itself */ + put_saddle_on_mon((struct obj *) 0, mtmp); } } else { diff --git a/src/read.c b/src/read.c index 831d85118..b8cbdc881 100644 --- a/src/read.c +++ b/src/read.c @@ -3237,9 +3237,9 @@ create_particular_creation( set_malign(mtmp); } if (d->saddled && can_saddle(mtmp) && !which_armor(mtmp, W_SADDLE)) { - struct obj *otmp = mksobj(SADDLE, TRUE, FALSE); - - put_saddle_on_mon(otmp, mtmp); + /* NULL obj arg means put_saddle_on_mon() + * will create the saddle itself */ + put_saddle_on_mon((struct obj *) 0, mtmp); } if (d->hidden && ((is_hider(mtmp->data) && mtmp->data->mlet != S_MIMIC) diff --git a/src/sp_lev.c b/src/sp_lev.c index f18f795e9..62f83909c 100644 --- a/src/sp_lev.c +++ b/src/sp_lev.c @@ -2307,7 +2307,7 @@ create_object(object *o, struct mkroom *croom) ; /* ['otmp' remains on floor] */ } else { remove_object(otmp); - if (otmp->otyp == SADDLE) + if (otmp->otyp == SADDLE && can_saddle(invent_carrying_monster)) put_saddle_on_mon(otmp, invent_carrying_monster); else (void) mpickobj(invent_carrying_monster, otmp); diff --git a/src/steed.c b/src/steed.c index 84a6e9287..48d537b99 100644 --- a/src/steed.c +++ b/src/steed.c @@ -131,6 +131,7 @@ use_saddle(struct obj *otmp) if (otmp->owornmask) remove_worn_item(otmp, FALSE); freeinv(otmp); + /* !can_saddle(mtmp) already eliminated above */ put_saddle_on_mon(otmp, mtmp); } else pline("%s resists!", Monnam(mtmp)); @@ -140,8 +141,19 @@ use_saddle(struct obj *otmp) void put_saddle_on_mon(struct obj *saddle, struct monst *mtmp) { - if (!can_saddle(mtmp) || which_armor(mtmp, W_SADDLE)) + if (!can_saddle(mtmp) || which_armor(mtmp, W_SADDLE)) { + if (saddle) + impossible("put_saddle_on_mon: saddle obj could get orphaned"); return; + } + if (!saddle) { + if ((saddle = mksobj(SADDLE, TRUE, FALSE)) != 0) { + fully_identify_obj(saddle); + /* mpickobj can later override identification if out-of-view */ + } else { + return; + } + } if (mpickobj(mtmp, saddle)) panic("merged saddle?"); mtmp->misc_worn_check |= W_SADDLE; From 2c1f2c1cb11a92a3a29e37a269dc585b370d4c7f Mon Sep 17 00:00:00 2001 From: PatR Date: Tue, 21 Jan 2025 14:55:05 -0800 Subject: [PATCH 382/791] clear "next" from "next boulder" sooner Clear "next" boulder so that when pushing a pile of boulders, only the first message for each of the 2nd, 3rd, &c will be formatted as "next boulder". If any of them trigger additional messages, those messages will use normal "boulder". --- src/mkobj.c | 4 +++- src/objnam.c | 5 ++++- src/shk.c | 2 ++ 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/mkobj.c b/src/mkobj.c index d57d8fa80..2555386e3 100644 --- a/src/mkobj.c +++ b/src/mkobj.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 mkobj.c $NHDT-Date: 1725138481 2024/08/31 21:08:01 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.304 $ */ +/* NetHack 3.7 mkobj.c $NHDT-Date: 1737528890 2025/01/21 22:54:50 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.315 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Derek S. Ray, 2015. */ /* NetHack may be freely redistributed. See license for details. */ @@ -2673,6 +2673,8 @@ container_weight(struct obj *object) void dealloc_obj(struct obj *obj) { + if (obj->otyp == BOULDER) + obj->next_boulder = 0; if (obj->where == OBJ_DELETED) { impossible("dealloc_obj: obj already deleted (type=%d)", obj->otyp); return; diff --git a/src/objnam.c b/src/objnam.c index b566778e7..8340f752b 100644 --- a/src/objnam.c +++ b/src/objnam.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 objnam.c $NHDT-Date: 1732979463 2024/11/30 07:11:03 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.439 $ */ +/* NetHack 3.7 objnam.c $NHDT-Date: 1737528848 2025/01/21 22:54:08 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.444 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2011. */ /* NetHack may be freely redistributed. See license for details. */ @@ -810,6 +810,9 @@ xname_flags( more robust because the default value for that overloaded field (obj->corpsenm) is NON_PM (-1) rather than 0 */ Strcat(strcpy(buf, "next "), actualn); /* "next boulder" */ + /* once "next boulder" occurs, subsequent messages should just + use ordinary "boulder" */ + obj->next_boulder = 0; } else { Strcpy(buf, actualn); /* "boulder" or "statue" */ } diff --git a/src/shk.c b/src/shk.c index 31aec5c8b..3463effbd 100644 --- a/src/shk.c +++ b/src/shk.c @@ -1131,6 +1131,8 @@ obfree(struct obj *obj, struct obj *merge) delete_contents(obj); if (Is_container(obj)) maybe_reset_pick(obj); + if (obj->otyp == BOULDER) + obj->next_boulder = 0; shkp = 0; if (obj->unpaid) { From dc5c098cb566c0f8922f65efdf4bd4ce1c1e5680 Mon Sep 17 00:00:00 2001 From: PatR Date: Tue, 21 Jan 2025 19:39:35 -0800 Subject: [PATCH 383/791] analyzer lint for n*.c --- src/nhlsel.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/nhlsel.c b/src/nhlsel.c index 2d0f92b4c..f700a9ea3 100644 --- a/src/nhlsel.c +++ b/src/nhlsel.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 nhlua.c $NHDT-Date: 1704225560 2024/01/02 19:59:20 $ $NHDT-Branch: keni-luabits2 $:$NHDT-Revision: 1.61 $ */ +/* NetHack 3.7 nhlua.c $NHDT-Date: 1737545957 2025/01/22 03:39:17 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.64 $ */ /* Copyright (c) 2018 by Pasi Kallinen */ /* NetHack may be freely redistributed. See license for details. */ @@ -266,7 +266,7 @@ l_selection_not(lua_State *L) sel = l_selection_check(L, 1); selection_clear(sel, 1); } else { - sel = l_selection_check(L, 1); + (void) l_selection_check(L, 1); (void) l_selection_clone(L); sel2 = l_selection_check(L, 2); selection_not(sel2); @@ -629,15 +629,17 @@ l_selection_randline(lua_State *L) staticfn int l_selection_grow(lua_State *L) { - const char *const growdirs[] = { + static const char *const growdirs[] = { "all", "random", "north", "west", "east", "south", NULL }; - const int growdirs2i[] = { + static const int growdirs2i[] = { W_ANY, W_RANDOM, W_NORTH, W_WEST, W_EAST, W_SOUTH, 0 }; - int argc = lua_gettop(L); - struct selectionvar *sel = l_selection_check(L, 1); - int dir = growdirs2i[luaL_checkoption(L, 2, "all", growdirs)]; + struct selectionvar *sel; + int dir, argc = lua_gettop(L); + + (void) l_selection_check(L, 1); + dir = growdirs2i[luaL_checkoption(L, 2, "all", growdirs)]; if (argc == 2) lua_pop(L, 1); /* get rid of growdir */ From 3109e706e9e69267a8429f979f0f3aa3373d4363 Mon Sep 17 00:00:00 2001 From: PatR Date: Tue, 21 Jan 2025 22:42:23 -0800 Subject: [PATCH 384/791] static analysis for o*.c This construct triggered several complaints about passing Null to Strcpy(simpleoname, obufp = the(simpleoname)); Changing that to obufp = the(simpleoname); Strcpy(simpleoname, obufp); prevents it, but the original complaint is bogus and the "fix" doesn't do anything to deal with Null arguments. A couple of other changes introduce different code in order to get different behavior. I updated from llvm-16 to llvm-19 but didn't eliminate any of the spurious complaints. --- src/objnam.c | 27 +++++++++++++++++---------- src/options.c | 9 ++++----- 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/src/objnam.c b/src/objnam.c index 8340f752b..d71dd5897 100644 --- a/src/objnam.c +++ b/src/objnam.c @@ -32,9 +32,9 @@ struct _readobjnam_data { char fruitbuf[BUFSZ]; }; -staticfn char *strprepend(char *, const char *); -staticfn char *nextobuf(void); -staticfn void releaseobuf(char *); +staticfn char *strprepend(char *, const char *) NONNULL NONNULLARG1; +staticfn char *nextobuf(void) NONNULL; +staticfn void releaseobuf(char *) NONNULLARG1; staticfn void xcalled(char *, int, const char *, const char *); staticfn char *xname_flags(struct obj *, unsigned); staticfn char *minimal_xname(struct obj *); @@ -122,15 +122,16 @@ static const struct Jitem Japanese_items[] = { staticfn char * strprepend(char *s, const char *pref) { + char star_s = *s; int i = (int) strlen(pref); if (i > PREFIX) { impossible("PREFIX too short (for %d).", i); return s; } - s -= i; - (void) strncpy(s, pref, i); /* do not copy trailing 0 */ - return s; + copynchars(s - i, pref, i + 1); + *s = star_s; + return s - i; } /* manage a pool of BUFSZ buffers, so callers don't have to */ @@ -2406,6 +2407,8 @@ ansimpleoname(struct obj *obj) char *obufp, *simpleoname = simpleonames(obj); int otyp = obj->otyp; + if (strlen(simpleoname) > BUFSZ - sizeof "the ") + simpleoname[sizeof "the "] = '\0'; /* prefix with "the" if a unique item, or a fake one imitating same, has been formatted with its actual name (we let minimal_xname() handle any `known' and `dknown' checking necessary) */ @@ -2414,12 +2417,14 @@ ansimpleoname(struct obj *obj) if (objects[otyp].oc_unique && OBJ_NAME(objects[otyp]) && !strcmp(simpleoname, OBJ_NAME(objects[otyp]))) { /* the() will allocate another obuf[]; we want to avoid using two */ - Strcpy(simpleoname, obufp = the(simpleoname)); + obufp = the(simpleoname); + Strcpy(simpleoname, obufp); releaseobuf(obufp); } else if (obj->quan == 1L) { /* simpleoname[] is singular if quan==1, plural otherwise; an() will allocate another obuf[]; we want to avoid using two */ - Strcpy(simpleoname, obufp = an(simpleoname)); + obufp = an(simpleoname); + Strcpy(simpleoname, obufp); releaseobuf(obufp); } return simpleoname; @@ -2432,7 +2437,8 @@ thesimpleoname(struct obj *obj) char *obufp, *simpleoname = simpleonames(obj); /* the() will allocate another obuf[]; we want to avoid using two */ - Strcpy(simpleoname, obufp = the(simpleoname)); + obufp = the(simpleoname); + Strcpy(simpleoname, obufp); releaseobuf(obufp); return simpleoname; } @@ -3513,7 +3519,7 @@ wizterrainwish(struct _readobjnam_data *d) int trap; unsigned oldtyp, ltyp; coordxy x = u.ux, y = u.uy; - char *bp = d->bp, *p = d->p; + char *bp = d->bp, *p; for (trap = NO_TRAP + 1; trap < TRAPNUM; trap++) { struct trap *t; @@ -5586,6 +5592,7 @@ safe_qbuf( lenlimit = QBUFSZ - 1; endp = qbuf + lenlimit; + assert(endp != NULL); /* workaround for static analyzer issue */ /* sanity check, aimed mainly at paniclog (it's conceivable for the result of short_oname() to be shorter than the length of the last resort string, but we ignore that possibility here) */ diff --git a/src/options.c b/src/options.c index 805efe3d4..468f8be00 100644 --- a/src/options.c +++ b/src/options.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 options.c $NHDT-Date: 1710792444 2024/03/18 20:07:24 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.723 $ */ +/* NetHack 3.7 options.c $NHDT-Date: 1737556914 2025/01/22 06:41:54 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.753 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2008. */ /* NetHack may be freely redistributed. See license for details. */ @@ -7768,7 +7768,7 @@ parse_role_opt( char **opp) { static char neg_opt[] = "!"; /* not 'const' but never modified */ - char *preval, *op = *opp; + char *preval, *op; int which = (optidx == opt_role) ? RS_ROLE : (optidx == opt_race) ? RS_RACE : (optidx == opt_gender) ? RS_GENDER @@ -7855,7 +7855,7 @@ parse_role_opt( if it's ok, replace it with canonical form */ saveoptstr(optidx, op); *opp = op; - ok = TRUE; + /*ok = TRUE; // redundant*/ /* don't return yet; value might be a list that follows this with something else which might make it invalid */ } @@ -9095,7 +9095,6 @@ handle_add_list_remove(const char *optname, int numtotal) }; int clr = NO_COLOR; - opt_idx = 0; tmpwin = create_nhwindow(NHW_MENU); start_menu(tmpwin, MENU_BEHAVE_STANDARD); any = cg.zeroany; @@ -9615,7 +9614,7 @@ next_opt(winid datawin, const char *str) if (!*str) { s = eos(buf); if (s > &buf[1] && s[-2] == ',') - Strcpy(s - 2, "."); /* replace last ", " */ + s[-2] = '.', s[-1] = '\0'; /* replace ending ", " with "." */ i = COLNO; /* (greater than COLNO - 2) */ } else { i = Strlen(buf) + Strlen(str) + 2; From c1d9ba9ce7c667eb954e7407e1ed1f6e7bceb08f Mon Sep 17 00:00:00 2001 From: PatR Date: Wed, 22 Jan 2025 12:15:39 -0800 Subject: [PATCH 385/791] analyzer lint for p*.c --- src/pager.c | 8 +++----- src/potion.c | 3 ++- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/pager.c b/src/pager.c index e964554f2..0b83c4910 100644 --- a/src/pager.c +++ b/src/pager.c @@ -1493,11 +1493,11 @@ do_screen_description( x_str = def_warnsyms[i].explanation; if (sym == (looked ? gw.warnsyms[i] : def_warnsyms[i].sym)) { if (!found) { - Sprintf(out_str, "%s%s", prefix, def_warnsyms[i].explanation); - *firstmatch = def_warnsyms[i].explanation; + Sprintf(out_str, "%s%s", prefix, x_str); + *firstmatch = x_str;; found++; } else { - found += append_str(out_str, def_warnsyms[i].explanation); + found += append_str(out_str, x_str); } /* Kludge: warning trumps boulders on the display. Reveal the boulder too or player can get confused */ @@ -1678,7 +1678,6 @@ do_look(int mode, coord *click_cc) if (!clicklook) { if (quick) { - from_screen = TRUE; /* yes, we want to use the cursor */ i = 'y'; } else { menu_item *pick_list = (menu_item *) 0; @@ -1843,7 +1842,6 @@ do_look(int mode, coord *click_cc) do { /* Reset some variables. */ pm = (struct permonst *) 0; - found = 0; out_str[0] = '\0'; if (from_screen || clicklook) { diff --git a/src/potion.c b/src/potion.c index 7bec2fcea..86a0545a9 100644 --- a/src/potion.c +++ b/src/potion.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 potion.c $NHDT-Date: 1726356849 2024/09/14 23:34:09 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.270 $ */ +/* NetHack 3.7 potion.c $NHDT-Date: 1737605675 2025/01/22 20:14:35 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.274 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2013. */ /* NetHack may be freely redistributed. See license for details. */ @@ -2236,6 +2236,7 @@ hold_potion( obj_extract_self(potobj); /* re-insert into inventory, possibly merging with compatible stack */ potobj = hold_another_object(potobj, drop_fmt, drop_arg, hold_msg); + nhUse(potobj); flags.pickup_burden = save_pickup_burden; update_inventory(); return; From 9a88efb20b3adb1af5925263615e35d4a8ba62af Mon Sep 17 00:00:00 2001 From: PatR Date: Wed, 22 Jan 2025 12:39:35 -0800 Subject: [PATCH 386/791] analysis lint for r*.c --- src/role.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/role.c b/src/role.c index 03fa64402..6d4ce709a 100644 --- a/src/role.c +++ b/src/role.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 role.c $NHDT-Date: 1711734229 2024/03/29 17:43:49 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.100 $ */ +/* NetHack 3.7 role.c $NHDT-Date: 1737607158 2025/01/22 20:39:18 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.107 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985-1999. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1562,7 +1562,7 @@ root_plselection_prompt( if (donefirst) Strcat(buf, " "); Strcat(buf, "character"); - donefirst = TRUE; + /*donefirst = TRUE;*/ } /* || * || From 5cd20d5389342407192492711d02b862e9e8fc57 Mon Sep 17 00:00:00 2001 From: PatR Date: Wed, 22 Jan 2025 13:16:42 -0800 Subject: [PATCH 387/791] finding data.base entry for stairs When testing the analyzer lint fixes for pager.c, I noticed that // wasn't finding the data.base entry for stairs when examining the up stairs on level 1. It is labelled "branch stairs up" which doesn't match "stair*". --- dat/data.base | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dat/data.base b/dat/data.base index a36f2b5fe..df3fd0f73 100644 --- a/dat/data.base +++ b/dat/data.base @@ -1,5 +1,5 @@ # NetHack 3.7 data.base -# $NHDT-Date: 1684001509 2023/05/13 18:11:49 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.106 $ +# $NHDT-Date: 1737609388 2025/01/22 21:16:28 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.141 $ # Copyright (c) 1994, 1995, 1996 by the NetHack Development Team # Copyright (c) 1994 by Boudewijn Wayers # NetHack may be freely redistributed. See license for details. @@ -5229,6 +5229,7 @@ squeaky board additionally gives the wielder the power of regeneration. When invoked it performs healing magic. stair* +branch stair* Up he went -- very quickly at first -- then more slowly -- then in a little while even more slowly than that -- and finally, after many minutes of climbing up the endless stairway, one From f86bb9b7b6dc792b6f6ee239ac92245b78c09d78 Mon Sep 17 00:00:00 2001 From: PatR Date: Wed, 22 Jan 2025 13:29:44 -0800 Subject: [PATCH 388/791] analysis lint for s*.c shk.c was dealt with previously. --- src/save.c | 6 +++--- src/shknam.c | 4 ++-- src/sp_lev.c | 5 ++--- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/save.c b/src/save.c index 933a0b0f8..a178fbdcd 100644 --- a/src/save.c +++ b/src/save.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 save.c $NHDT-Date: 1706079844 2024/01/24 07:04:04 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.214 $ */ +/* NetHack 3.7 save.c $NHDT-Date: 1737610109 2025/01/22 21:28:29 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.232 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2009. */ /* NetHack may be freely redistributed. See license for details. */ @@ -17,7 +17,7 @@ int dotcnt, dotrow; /* also used in restore */ #endif staticfn void savelevchn(NHFILE *); -staticfn void savelevl(NHFILE *,boolean); +staticfn void savelevl(NHFILE *, boolean); staticfn void savedamage(NHFILE *); staticfn void save_bubbles(NHFILE *, xint8); staticfn void save_stairs(NHFILE *); @@ -702,7 +702,7 @@ savedamage(NHFILE *nhfp) if (nhfp->structlevel) bwrite(nhfp->fd, (genericptr_t) &xl, sizeof xl); } - while (xl--) { + while (damageptr) { if (perform_bwrite(nhfp)) { if (nhfp->structlevel) bwrite(nhfp->fd, (genericptr_t) damageptr, sizeof *damageptr); diff --git a/src/shknam.c b/src/shknam.c index 5aaeefcca..61016d56e 100644 --- a/src/shknam.c +++ b/src/shknam.c @@ -411,8 +411,8 @@ shkveg(void) char oclass = FOOD_CLASS; int ok[NUM_OBJECTS]; + (void) memset((genericptr_t) ok, 0, sizeof ok); /* lint suppression */ j = maxprob = 0; - ok[0] = 0; /* lint suppression */ for (i = svb.bases[(int) oclass]; i < NUM_OBJECTS; ++i) { if (objects[i].oc_class != oclass) break; @@ -511,7 +511,7 @@ nameshk(struct monst *shk, const char *const *nlp) for (names_avail = 0; nlp[names_avail]; names_avail++) continue; - + assert(names_avail > 0); name_wanted = name_wanted % names_avail; for (trycnt = 0; trycnt < 50; trycnt++) { diff --git a/src/sp_lev.c b/src/sp_lev.c index 62f83909c..66c6d2c87 100644 --- a/src/sp_lev.c +++ b/src/sp_lev.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 sp_lev.c $NHDT-Date: 1709921020 2024/03/08 18:03:40 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.359 $ */ +/* NetHack 3.7 sp_lev.c $NHDT-Date: 1737610109 2025/01/22 21:28:29 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.373 $ */ /* Copyright (c) 1989 by Jean-Christophe Collet */ /* NetHack may be freely redistributed. See license for details. */ @@ -2515,9 +2515,8 @@ search_door( yy = croom->ly; break; default: - dx = dy = xx = yy = 0; panic("search_door: Bad wall!"); - break; + /*NOTREACHED*/ } while (xx <= croom->hx + 1 && yy <= croom->hy + 1) { if (IS_DOOR(levl[xx][yy].typ) || levl[xx][yy].typ == SDOOR) { From ffc43610f03aa35cfc5c18f87143ee225f33339f Mon Sep 17 00:00:00 2001 From: PatR Date: Wed, 22 Jan 2025 16:34:05 -0800 Subject: [PATCH 389/791] analysis lint for u*.c One actual bug: mhitm_ad_ench() could pass Null to drain_item() which was not prepared to deal with that. --- src/u_init.c | 3 ++- src/uhitm.c | 11 ++++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/u_init.c b/src/u_init.c index 58040518f..1d0913f80 100644 --- a/src/u_init.c +++ b/src/u_init.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 u_init.c $NHDT-Date: 1725227809 2024/09/01 21:56:49 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.111 $ */ +/* NetHack 3.7 u_init.c $NHDT-Date: 1737620595 2025/01/23 00:23:15 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.113 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2017. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1329,6 +1329,7 @@ ini_inv(struct trobj *trop) * it was UNDEF_TYP or not after this. */ otyp = ini_inv_obj_substitution(trop, obj); + nhUse(otyp); /* nudist gets no armor */ if (u.uroleplay.nudist && obj->oclass == ARMOR_CLASS) { diff --git a/src/uhitm.c b/src/uhitm.c index dc7264af1..d40f712c0 100644 --- a/src/uhitm.c +++ b/src/uhitm.c @@ -1813,8 +1813,10 @@ hmon_hitmon( hmon_hitmon_msg_hit(&hmd, mon, obj); - if (hmd.dryit) /* dryit implies wet towel, so 'obj' is still intact */ + if (hmd.dryit) { /* dryit implies wet towel, so 'obj' is still intact */ + assert(obj != NULL); dry_a_towel(obj, -1, TRUE); + } if (hmd.silvermsg) hmon_hitmon_msg_silver(&hmd, mon, obj); @@ -1826,8 +1828,10 @@ hmon_hitmon( obj->opoisoned was cleared above and any message referring to "poisoned " has now been given; we want just "" for last message, so reformat while obj is still accessible */ - if (hmd.unpoisonmsg) + if (hmd.unpoisonmsg) { + assert(obj != NULL); Strcpy(hmd.saved_oname, cxname(obj)); + } /* [note: thrown obj might go away during killed()/xkilled() call (via 'thrownobj'; if swallowed, it gets added to engulfer's @@ -3508,6 +3512,7 @@ mhitm_ad_slim( mhm->damage = 0; } } + nhUse(pd); } void @@ -3549,7 +3554,7 @@ mhitm_ad_ench( break; } } - if (drain_item(obj, FALSE)) { + if (obj && drain_item(obj, FALSE)) { pline("%s less effective.", Yobjnam2(obj, "seem")); } } From bac7cd73659210ff1a75cb68659c53c0c45a5307 Mon Sep 17 00:00:00 2001 From: PatR Date: Wed, 22 Jan 2025 16:58:04 -0800 Subject: [PATCH 390/791] analyzer lint for v*.c --- src/vault.c | 5 +++-- src/version.c | 4 +++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/vault.c b/src/vault.c index 9335c4ac6..31002f65f 100644 --- a/src/vault.c +++ b/src/vault.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 vault.c $NHDT-Date: 1657868307 2022/07/15 06:58:27 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.91 $ */ +/* NetHack 3.7 vault.c $NHDT-Date: 1737622664 2025/01/23 00:57:44 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.113 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2011. */ /* NetHack may be freely redistributed. See license for details. */ @@ -888,7 +888,7 @@ gd_move(struct monst *grd) if (!on_level(&(egrd->gdlevel), &u.uz)) return -1; - nx = ny = m = n = 0; + if (semi_dead || !grd->mx || egrd->gddone) { egrd->gddone = 1; return gd_move_cleanup(grd, semi_dead, FALSE); @@ -1033,6 +1033,7 @@ gd_move(struct monst *grd) } } } + m = n = 0; for (fci = egrd->fcbeg; fci < egrd->fcend; fci++) if (g_at(egrd->fakecorr[fci].fx, egrd->fakecorr[fci].fy)) { m = egrd->fakecorr[fci].fx; diff --git a/src/version.c b/src/version.c index 34085a8af..e6b675ed3 100644 --- a/src/version.c +++ b/src/version.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 version.c $NHDT-Date: 1655402415 2022/06/16 18:00:15 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.92 $ */ +/* NetHack 3.7 version.c $NHDT-Date: 1737622664 2025/01/23 00:57:44 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.105 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2018. */ /* NetHack may be freely redistributed. See license for details. */ @@ -416,6 +416,8 @@ uptodate(NHFILE *nhfp, const char *name, unsigned long utdflags) if (nhfp->structlevel) { rlen = read(nhfp->fd, (genericptr_t) &indicator, sizeof indicator); + if (rlen != sizeof indicator) + return FALSE; rlen = read(nhfp->fd, (genericptr_t) &filecmc, sizeof filecmc); if (rlen == 0) return FALSE; From 29f7580fc1e622340069cd6da5a15bcd24e1e72b Mon Sep 17 00:00:00 2001 From: PatR Date: Thu, 23 Jan 2025 12:01:46 -0800 Subject: [PATCH 391/791] analyzer lint for sys/unix/*.c sys/share/*.c win/tty/*.c Actually only ioctl.c for sys/share. And with all of these, only for the conditionals used by MacOS. --- sys/share/pmatchregex.c | 12 ++++++------ win/tty/wintty.c | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/sys/share/pmatchregex.c b/sys/share/pmatchregex.c index 95dc4de11..53c5ef531 100644 --- a/sys/share/pmatchregex.c +++ b/sys/share/pmatchregex.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 pmatchregex.c $NHDT-Date: 1596498285 2020/08/03 23:44:45 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.4 $ */ +/* NetHack 3.7 pmatchregex.c $NHDT-Date: 1737691300 2025/01/23 20:01:40 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.10 $ */ /* Copyright (c) Sean Hunt 2015. */ /* NetHack may be freely redistributed. See license for details. */ @@ -59,11 +59,11 @@ regex_match(const char *s, struct nhregex *re) void regex_free(struct nhregex *re) { - if (re) { - if (re->pat) - free((genericptr_t) re->pat); - free((genericptr_t) re); - } + assert(re != NULL); /* regex_free() is declared with NONNULLPTR1 */ + + if (re->pat) + free((genericptr_t) re->pat); + free((genericptr_t) re); } /*pmatchregex.c*/ diff --git a/win/tty/wintty.c b/win/tty/wintty.c index dbdf57363..46f32d353 100644 --- a/win/tty/wintty.c +++ b/win/tty/wintty.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 wintty.c $NHDT-Date: 1717967340 2024/06/09 21:09:00 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.410 $ */ +/* NetHack 3.7 wintty.c $NHDT-Date: 1737691300 2025/01/23 20:01:40 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.420 $ */ /* Copyright (c) David Cohrs, 1991 */ /* NetHack may be freely redistributed. See license for details. */ @@ -5107,7 +5107,7 @@ render_status(void) if (hpbar_crit_hp) repad_with_dashes(bar); bar_len = (int) strlen(bar); /* always 30 */ - tlth = bar_len + 2; + /*tlth = bar_len + 2; // not needed within this 'if'*/ attrmask = 0; /* for the second part only case: dead */ /* when at full HP, the whole title will be highlighted; when injured or dead, there will be a second portion From 150b331189026ff1462a92cb7b13a3344fb75241 Mon Sep 17 00:00:00 2001 From: PatR Date: Thu, 23 Jan 2025 13:52:19 -0800 Subject: [PATCH 392/791] analyzer lint for win/curses/*.c There is still an issue in cursmesg.c. The last diff band (curses_putch) isn't related to static analysis. --- win/curses/cursdial.c | 16 +++++++--------- win/curses/cursmesg.c | 2 ++ win/curses/cursstat.c | 1 + win/curses/curswins.c | 15 +++++++++++---- 4 files changed, 21 insertions(+), 13 deletions(-) diff --git a/win/curses/cursdial.c b/win/curses/cursdial.c index dddfd400e..dc34805b7 100644 --- a/win/curses/cursdial.c +++ b/win/curses/cursdial.c @@ -449,7 +449,6 @@ curses_ext_cmd(void) letter = pgetchar(); /* pgetchar(cmd.c) implements do-again */ curs_set(0); prompt_width = (int) strlen(cur_choice); - matches = 0; if (letter == '\033' || letter == ERR) { ret = -1; @@ -667,7 +666,7 @@ curs_pad_menu( boolean do_pad UNUSED) { nhmenu_item *menu_item_ptr; - int numpages = current_menu->num_pages; + int numpages; /* caller has already called menu_win_size() */ menu_determine_pages(current_menu); /* sets 'menu->num_pages' */ @@ -942,7 +941,7 @@ menu_is_multipage(nhmenu *menu, int width, int height) int curline = 0, accel_per_page = 0; nhmenu_item *menu_item_ptr = menu->entries; - if (*menu->prompt) { + if (menu->prompt && *menu->prompt) { curline += curses_num_lines(menu->prompt, width) + 1; } @@ -978,13 +977,12 @@ menu_determine_pages(nhmenu *menu) int tmpline, num_lines, accel_per_page; int curline = 0; int page_num = 1; - nhmenu_item *menu_item_ptr = menu->entries; + nhmenu_item *menu_item_ptr; int width = menu->width; int height = menu->height; int page_end = height; - - if (*menu->prompt) { + if (menu->prompt && *menu->prompt) { curline += curses_num_lines(menu->prompt, width) + 1; } tmpline = curline; @@ -1032,6 +1030,7 @@ menu_win_size(nhmenu *menu) int maxheaderwidth = menu->prompt ? (int) strlen(menu->prompt) : 0; nhmenu_item *menu_item_ptr, *last_item_ptr = NULL; +#if 0 /* maxwidth is set below, so the value calculated here isn't used */ if (program_state.gameover) { /* for final inventory disclosure, use full width */ maxwidth = term_cols - 2; /* +2: borders assumed */ @@ -1046,6 +1045,7 @@ menu_win_size(nhmenu *menu) if ((term_cols / 2) > maxwidth) maxwidth = (term_cols / 2); /* Half the screen */ } +#endif maxheight = menu_max_height(); /* First, determine the width of the longest menu entry */ @@ -1475,8 +1475,6 @@ curs_nonselect_menu_action( } menu_item_ptr = menu_item_ptr->next_item; } - - menu_item_ptr = menu->entries; break; } /* case MENU_SEARCH */ default: @@ -1500,7 +1498,7 @@ menu_get_selections(WINDOW *win, nhmenu *menu, int how) int num_selected = 0; boolean dismiss = FALSE; char selectors[256], groupaccels[256]; - nhmenu_item *menu_item_ptr = menu->entries; + nhmenu_item *menu_item_ptr; activemenu = win; menu_display_page(win, menu, curpage, selectors, groupaccels); diff --git a/win/curses/cursmesg.c b/win/curses/cursmesg.c index 6a30c159c..9d9eceb1f 100644 --- a/win/curses/cursmesg.c +++ b/win/curses/cursmesg.c @@ -932,6 +932,8 @@ mesg_add_line(const char *mline) } else { /* instead of discarding list element being forced out, reuse it */ current_mesg = first_mesg; + assert(current_mesg != NULL); + assert(current_mesg->str != NULL); /* whenever new 'mline' is shorter, extra allocation size of the original element will be frittered away, until eventually we'll discard this 'str' and dupstr() a replacement; we could easily diff --git a/win/curses/cursstat.c b/win/curses/cursstat.c index 90a9d93c9..67691bb59 100644 --- a/win/curses/cursstat.c +++ b/win/curses/cursstat.c @@ -173,6 +173,7 @@ curses_status_update( /* decode once instead of every time it's displayed */ status_vals[BL_GOLD][0] = ' '; text = decode_mixed(&status_vals[BL_GOLD][1], text); + nhUse(text); } else if ((fldidx == BL_HUNGER || fldidx == BL_CAP) && (!*text || !strcmp(text, " "))) { /* fieldfmt[] is " %s"; avoid lone space when empty */ diff --git a/win/curses/curswins.c b/win/curses/curswins.c index 19c6c380a..f7f9e1d96 100644 --- a/win/curses/curswins.c +++ b/win/curses/curswins.c @@ -508,20 +508,27 @@ curs_destroy_all_wins(void) { curses_count_window((char *) 0); /* clean up orphan */ +#if 0 /* this works but confuses the static analyzer (from llvm-19, + * which reports "warning: Use of memory after it is freed") */ while (nhwids) curses_del_wid(nhwids->nhwid); +#lse + while (nhwids) { + nethack_wid *tmpptr = nhwids; + + curses_del_wid(tmpptr->nhwid); + } +#endif } /* Print a single character in the given window at the given coordinates */ void -#ifdef ENHANCED_SYMBOLS curses_putch(winid wid, int x, int y, int ch, +#ifdef ENHANCED_SYMBOLS struct unicode_representation *unicode_representation, - int color, int framecolor, int attr) -#else -curses_putch(winid wid, int x, int y, int ch, int color, int framecolor, int attr) #endif + int color, int framecolor, int attr) { static boolean map_initted = FALSE; int sx, sy, ex, ey; From 349f3871be6476ec38990927f6abc9a48574a469 Mon Sep 17 00:00:00 2001 From: nhmall Date: Thu, 23 Jan 2025 19:37:19 -0500 Subject: [PATCH 393/791] preproc fix --- win/curses/curswins.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/win/curses/curswins.c b/win/curses/curswins.c index f7f9e1d96..9fe04edd4 100644 --- a/win/curses/curswins.c +++ b/win/curses/curswins.c @@ -512,7 +512,7 @@ curs_destroy_all_wins(void) * which reports "warning: Use of memory after it is freed") */ while (nhwids) curses_del_wid(nhwids->nhwid); -#lse +#else while (nhwids) { nethack_wid *tmpptr = nhwids; From 6ac0be46f6bf51da700ee0793a686ee01032276e Mon Sep 17 00:00:00 2001 From: PatR Date: Thu, 23 Jan 2025 17:30:27 -0800 Subject: [PATCH 394/791] last analyzer bit for win/curses/cursmesg.c I got confused and thought that this one (actually pair) was more complicated than it actually is. have_mixed_leadin is used in an ordinary way, but resetting it to false happens in spots where it can't be used again. The analyzer complains that the assignments don't do anything useful. --- win/curses/cursmesg.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/win/curses/cursmesg.c b/win/curses/cursmesg.c index 9d9eceb1f..9608c1158 100644 --- a/win/curses/cursmesg.c +++ b/win/curses/cursmesg.c @@ -213,8 +213,9 @@ curses_message_win_puts(const char *message, boolean recursed) mvwadd_wch(win, my, mx, mixed_leadin_cchar); ++mx; message_length--; - have_mixed_leadin = FALSE; mesg_mixed = 0; + have_mixed_leadin = FALSE; + nhUse(have_mixed_leadin); } #endif mvwprintw(win, my, mx, "%s", tmpstr), mx += (int) strlen(tmpstr); @@ -234,8 +235,9 @@ curses_message_win_puts(const char *message, boolean recursed) mvwadd_wch(win, my, mx, mixed_leadin_cchar); ++mx; message_length--; - have_mixed_leadin = FALSE; mesg_mixed = 0; + have_mixed_leadin = FALSE; + nhUse(have_mixed_leadin); } #endif mvwprintw(win, my, mx, "%s", message), mx += message_length; From 858bf3b30d3884fb808f3277448c6c602e32034b Mon Sep 17 00:00:00 2001 From: PatR Date: Thu, 23 Jan 2025 20:15:40 -0800 Subject: [PATCH 395/791] analysis lint for tilemap.c --- win/share/tilemap.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/win/share/tilemap.c b/win/share/tilemap.c index 7ce828abe..a28cd8c76 100644 --- a/win/share/tilemap.c +++ b/win/share/tilemap.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 tilemap.c $NHDT-Date: 1736530790 2025/01/10 09:39:50 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.86 $ */ +/* NetHack 3.7 tilemap.c $NHDT-Date: 1737720923 2025/01/24 04:15:23 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.87 $ */ /* Copyright (c) 2016 by Michael Allison */ /* NetHack may be freely redistributed. See license for details. */ @@ -193,14 +193,14 @@ struct conditionals_t { const char * tilename(int set, const int file_entry, int gend UNUSED) { - int i, k, cmap, condnum, tilenum, gendnum; + int i, k, cmap, condnum, tilenum; static char buf[BUFSZ]; #if 0 - int offset; + int offset, gendnum; #endif (void) def_char_to_objclass(']'); - condnum = tilenum = gendnum = 0; + tilenum = 0; buf[0] = '\0'; if (set == MON_GLYPH) { @@ -316,7 +316,7 @@ tilename(int set, const int file_entry, int gend UNUSED) /* cmap A */ for (cmap = S_ndoor; cmap <= S_brdnladder; cmap++) { - i = cmap - S_ndoor; + i = cmap - S_ndoor; nhUse(i); if (tilenum == file_entry) { if (*defsyms[cmap].explanation) { return defsyms[cmap].explanation; @@ -364,7 +364,7 @@ tilename(int set, const int file_entry, int gend UNUSED) /* cmap B */ for (cmap = S_grave; cmap < S_arrow_trap + MAXTCHARS; cmap++) { - i = cmap - S_grave; + i = cmap - S_grave; nhUse(i); if (tilenum == file_entry) { if (*defsyms[cmap].explanation) { return defsyms[cmap].explanation; @@ -421,7 +421,7 @@ tilename(int set, const int file_entry, int gend UNUSED) /* cmap C */ for (cmap = S_digbeam; cmap <= S_goodpos; cmap++) { - i = cmap - S_digbeam; + i = cmap - S_digbeam; nhUse(i); if (tilenum == file_entry) { if (*defsyms[cmap].explanation) { return defsyms[cmap].explanation; @@ -467,7 +467,7 @@ tilename(int set, const int file_entry, int gend UNUSED) /* explosions */ for (k = expl_dark; k <= expl_frosty; k++) { for (cmap = S_expl_tl; cmap <= S_expl_br; cmap++) { - i = cmap - S_expl_tl; + i = cmap - S_expl_tl; nhUse(i); if (tilenum == file_entry) { /* substitute "explosion " in the tilelabel with "explosion dark " etc */ From 9313e819dee3a6558bd3dd1a0ef9da22dc0df44d Mon Sep 17 00:00:00 2001 From: nhkeni Date: Fri, 24 Jan 2025 10:57:40 -0500 Subject: [PATCH 396/791] nhgitset.pl: leftover tid --- DEVEL/nhgitset.pl | 1 + 1 file changed, 1 insertion(+) diff --git a/DEVEL/nhgitset.pl b/DEVEL/nhgitset.pl index e235a33ce..b20b5c57c 100755 --- a/DEVEL/nhgitset.pl +++ b/DEVEL/nhgitset.pl @@ -353,6 +353,7 @@ sub do_dir_hooksdir { sub do_file_nhgitset { my $infile = "DEVEL/nhgitset.pl"; + $infile = "$DEVhooksdir/../nhgitset.pl" unless(-f $infile); my $outfile = ".git/hooks/gitsetdocs"; open IN, "<", $infile or die "Can't open $infile:$!"; open OUT, ">", $outfile or die "Can't open $outfile:$!"; From c9abc92dd7d48502f4d6529ec5774955c3f59a7b Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Fri, 24 Jan 2025 19:04:17 +0200 Subject: [PATCH 397/791] Fix lua.adoc --- doc/lua.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/lua.adoc b/doc/lua.adoc index 0d63041ea..f75de0b1d 100644 --- a/doc/lua.adoc +++ b/doc/lua.adoc @@ -793,7 +793,7 @@ The hash parameter accepts the following keys: | adjacentok | boolean | is adjacent location ok, if given one is not suitable? | ignorewater | boolean | ignore water when choosing location for the monster | countbirth | boolean | do we count this monster as generated -| appear_as | string | monster can appear as object, monster, or terrain. Add "obj:", "mon:", or "ter:" prefix to the value. | +| appear_as | string | monster can appear as object, monster, or terrain. Add "obj:", "mon:", or "ter:" prefix to the value. | inventory | function | objects generated in the function are given to the monster (any random inventory it gets is discarded unless keep_default_invent is true) | keep_default_invent | boolean | if inventory is specified and this is true, those items are in addition to random inventory for this species; if inventory is not specified and this is false, monster gets no starting inventory |=== From 02102de396856c6699d6761984180fd0e3f4f8fe Mon Sep 17 00:00:00 2001 From: nhmall Date: Fri, 24 Jan 2025 17:06:17 -0500 Subject: [PATCH 398/791] attempt to resolve issue #1368 Resolve #1368 --- src/dog.c | 2 +- src/dogmove.c | 11 +++++++++-- src/restore.c | 4 ++++ 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/dog.c b/src/dog.c index 07336ef71..4e7d7aedb 100644 --- a/src/dog.c +++ b/src/dog.c @@ -51,7 +51,7 @@ initedog(struct monst *mtmp) mtmp->meating = 0; EDOG(mtmp)->droptime = 0; EDOG(mtmp)->dropdist = 10000; - EDOG(mtmp)->apport = ACURR(A_CHA); + EDOG(mtmp)->apport = max(1, ACURR(A_CHA)); EDOG(mtmp)->whistletime = 0; EDOG(mtmp)->hungrytime = 1000 + svm.moves; EDOG(mtmp)->ogoal.x = -1; /* force error if used before set */ diff --git a/src/dogmove.c b/src/dogmove.c index 6eba6c089..fe98fa551 100644 --- a/src/dogmove.c +++ b/src/dogmove.c @@ -311,9 +311,16 @@ dog_eat(struct monst *mtmp, } else { /* It's a reward if it's DOGFOOD and the player dropped/threw it. We know the player had it if invlet is set. -dlc */ - if (dogfood(mtmp, obj) == DOGFOOD && obj->invlet) + if (dogfood(mtmp, obj) == DOGFOOD && obj->invlet) { edog->apport += (int) (200L / ((long) edog->dropdist + svm.moves - edog->droptime)); + if (edog->apport <= 0) { + impossible("dog_eat: pet apport <= 0 (%d, %d, %ld, %ld)", + edog->apport, edog->dropdist, edog->droptime, + svm.moves); + edog->apport = 1; + } + } if (obj->unpaid) { /* edible item owned by shop has been thrown or kicked by hero and caught by tame or food-tameable monst */ @@ -399,7 +406,7 @@ dog_invent(struct monst *mtmp, struct edog *edog, int udist) * Use udist+1 so steed won't cause divide by zero. */ if (droppables(mtmp)) { - if (!rn2(udist + 1) || !rn2(edog->apport)) + if (!rn2(udist + 1) || (edog->apport && !rn2(edog->apport))) if (rn2(10) < edog->apport) { relobj(mtmp, (int) mtmp->minvis, TRUE); if (edog->apport > 1) diff --git a/src/restore.c b/src/restore.c index b8e0988aa..67be7cebb 100644 --- a/src/restore.c +++ b/src/restore.c @@ -365,6 +365,10 @@ restmon(NHFILE *nhfp, struct monst *mtmp) newedog(mtmp); if (nhfp->structlevel) Mread(nhfp->fd, EDOG(mtmp), sizeof (struct edog)); + /* sanity check to prevent rn2(0) */ + if (EDOG(mtmp)->apport <= 0) { + EDOG(mtmp)->apport = 1; + } } /* mcorpsenm - obj->corpsenm for mimic posing as corpse or statue (inline int rather than pointer to something) */ From 3c824cd866072a57326b75eac21d8845c41413d2 Mon Sep 17 00:00:00 2001 From: PatR Date: Fri, 24 Jan 2025 14:50:53 -0800 Subject: [PATCH 399/791] fix incorrect lint fix > if (strlen(simpleoname) > BUFSZ - sizeof "the ") > simpleoname[sizeof "the "] = '\0'; The second line should have been | simpleoname[strlen(simpleoname) - sizeof "the "] = '\0'; but fixing that isn't adequate. The BUFSZ limit is not valid when dealing with object names since xname() leaves room for a prefix so doesn't return the start of a BUFSZ-sized buffer. Strangely enough, the complaint that caused me to add those two lines isn't being triggered any more. Some other change at the same time, perhaps splitting Strcpy(simpleoname, obufp = the(simpleoname)); into obufp = the(simpleoname); Strcpy(simpleoname, obufp); pacified the analyzer. However, it didn't resolve the valid complaint that inserting "the " might result in overflow. I've added a comment about simpleonames(), ansimpleoname(), and thesimpleoname() about the possible overflow, but I don't think that such overflow can actually happen when user-applied object name is being suppressed. --- src/objnam.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/objnam.c b/src/objnam.c index d71dd5897..df6b29167 100644 --- a/src/objnam.c +++ b/src/objnam.c @@ -2382,6 +2382,22 @@ Ysimple_name2(struct obj *obj) return s; } + /* + * FIXME: + * simpleonames(), ansimpleoname(), and thesimpleoname() need to + * know the beginning of the obuf[] they use so that they can + * guard against buffer overflow when pluralizing (is that an + * actual word?) or inserting "an" or "the". + * + * minimal_xname() returns a call to xname() which writes into + * the middle of its obuf[] then backs up to accomodate a prefix, + * so BUFSZ is not a reliable limit for the length of the result. + * + * [Overflow likely moot. Since the formatted object name has + * user-supplied name suppressed, the length is sure to be short + * enough to added plural suffix or "an" or "the" prefix.] + */ + /* "scroll" or "scrolls" */ char * simpleonames(struct obj *obj) @@ -2407,8 +2423,6 @@ ansimpleoname(struct obj *obj) char *obufp, *simpleoname = simpleonames(obj); int otyp = obj->otyp; - if (strlen(simpleoname) > BUFSZ - sizeof "the ") - simpleoname[sizeof "the "] = '\0'; /* prefix with "the" if a unique item, or a fake one imitating same, has been formatted with its actual name (we let minimal_xname() handle any `known' and `dknown' checking necessary) */ From dc938b7acf0c875ee3a2da96cfe1bec0239dc176 Mon Sep 17 00:00:00 2001 From: nhmall Date: Fri, 24 Jan 2025 18:24:26 -0500 Subject: [PATCH 400/791] don't hide the zero value of apport It was pointed out that it might not be a good idea to hide the illegal value of apport. --- src/dogmove.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/dogmove.c b/src/dogmove.c index fe98fa551..fb214c54e 100644 --- a/src/dogmove.c +++ b/src/dogmove.c @@ -406,7 +406,8 @@ dog_invent(struct monst *mtmp, struct edog *edog, int udist) * Use udist+1 so steed won't cause divide by zero. */ if (droppables(mtmp)) { - if (!rn2(udist + 1) || (edog->apport && !rn2(edog->apport))) + assert(edog->apport > 0); + if (!rn2(udist + 1) || !rn2(edog->apport)) if (rn2(10) < edog->apport) { relobj(mtmp, (int) mtmp->minvis, TRUE); if (edog->apport > 1) From ed44da351e0fda24bf50675369dd61927dd01393 Mon Sep 17 00:00:00 2001 From: nhmall Date: Fri, 24 Jan 2025 18:26:56 -0500 Subject: [PATCH 401/791] more follow-up, less hiding of illegal values Catch it prior to the rn2() call instead. We need to be aware of the issue. --- src/dog.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dog.c b/src/dog.c index 4e7d7aedb..07336ef71 100644 --- a/src/dog.c +++ b/src/dog.c @@ -51,7 +51,7 @@ initedog(struct monst *mtmp) mtmp->meating = 0; EDOG(mtmp)->droptime = 0; EDOG(mtmp)->dropdist = 10000; - EDOG(mtmp)->apport = max(1, ACURR(A_CHA)); + EDOG(mtmp)->apport = ACURR(A_CHA); EDOG(mtmp)->whistletime = 0; EDOG(mtmp)->hungrytime = 1000 + svm.moves; EDOG(mtmp)->ogoal.x = -1; /* force error if used before set */ From 3cca4f27076e92a3be2ee9286813c18d8813311e Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 26 Jan 2025 11:55:48 -0500 Subject: [PATCH 402/791] avoid mk_artifact()-related memory leaks Reported directly to devteam after being discovered in nerfhack. --- src/artifact.c | 47 +++++++++++++++++++++++++++++++---------------- src/mkobj.c | 21 +++++++++++++++------ src/mplayer.c | 1 + src/pray.c | 1 + 4 files changed, 48 insertions(+), 22 deletions(-) diff --git a/src/artifact.c b/src/artifact.c index 7b9c3864f..7b69820b8 100644 --- a/src/artifact.c +++ b/src/artifact.c @@ -35,6 +35,7 @@ staticfn uchar abil_to_adtyp(long *) NONNULLARG1; staticfn int glow_strength(int); staticfn boolean untouchable(struct obj *, boolean); staticfn int count_surround_traps(coordxy, coordxy); +staticfn void dispose_of_orig_obj(struct obj *); /* The amount added to the victim's total hit points to insure that the victim will be killed even after damage bonus/penalty adjustments. @@ -154,6 +155,7 @@ mk_artifact( uchar max_giftvalue, /* cap on generated giftvalue */ boolean adjust_spe) /* whether to add spe to situational artifacts */ { + struct obj *artiobj; const struct artifact *a; int m, n, altn; boolean by_align = (alignment != A_NONE); @@ -237,37 +239,50 @@ mk_artifact( m = eligible[rn2(n)]; /* [0..n-1] */ a = &artilist[m]; - /* make an appropriate object if necessary, then christen it */ - otmp = mksobj((int) a->otyp, TRUE, FALSE); + /* make an appropriate object, then christen it */ + artiobj = mksobj((int) a->otyp, TRUE, FALSE); if (adjust_spe) { int new_spe; - /* Adjust otmp->spe by a->gen_spe. (This is a no-op for + /* Adjust artiobj->spe by a->gen_spe. (This is a no-op for non-weapons, which always have a gen_spe of 0, and for many weapons, too.) The result is clamped into the "normal" range to prevent an outside chance of +12 artifacts generating. */ - new_spe = (int)otmp->spe + a->gen_spe; + new_spe = (int)artiobj->spe + a->gen_spe; if (new_spe >= -10 && new_spe < 10) - otmp->spe = new_spe; - } - - if (otmp) { - /* prevent erosion from generating */ - otmp->oeroded = otmp->oeroded2 = 0; - otmp = oname(otmp, a->name, ONAME_NO_FLAGS); - otmp->oartifact = m; - /* set existence and reason for creation bits */ - artifact_origin(otmp, ONAME_RANDOM); /* 'random' is default */ + artiobj->spe = new_spe; } + /* prevent erosion from generating */ + artiobj->oeroded = artiobj->oeroded2 = 0; + artiobj = oname(artiobj, a->name, ONAME_NO_FLAGS); + artiobj->oartifact = m; + /* set existence and reason for creation bits */ + artifact_origin(artiobj, ONAME_RANDOM); /* 'random' is default */ + if (otmp) + dispose_of_orig_obj(otmp); + otmp = artiobj; } else { /* nothing appropriate could be found; return original object */ - if (by_align) - otmp = 0; /* (there was no original object) */ + if (by_align && otmp) { + /* (there shouldn't have been an original object) */ + dispose_of_orig_obj(otmp); + otmp = 0; + } } return otmp; } +void +dispose_of_orig_obj(struct obj *obj) +{ + if (!obj) + return; + + obj_extract_self(obj); + obfree(obj, (struct obj *) 0); +} + /* * Returns the full name (with articles and correct capitalization) of an * artifact named "name" if one exists, or NULL, it not. diff --git a/src/mkobj.c b/src/mkobj.c index 2555386e3..d76e65f1b 100644 --- a/src/mkobj.c +++ b/src/mkobj.c @@ -9,7 +9,7 @@ staticfn boolean may_generate_eroded(struct obj *); staticfn void mkobj_erosions(struct obj *); staticfn void mkbox_cnts(struct obj *); staticfn unsigned nextoid(struct obj *, struct obj *); -staticfn void mksobj_init(struct obj *, boolean); +staticfn void mksobj_init(struct obj **, boolean); staticfn int item_on_ice(struct obj *); staticfn void shrinking_glob_gone(struct obj *); staticfn void obj_timer_checks(struct obj *, coordxy, coordxy, int); @@ -861,9 +861,10 @@ unknow_object(struct obj *obj) /* do some initialization to newly created object; otyp must already be set */ staticfn void -mksobj_init(struct obj *otmp, boolean artif) +mksobj_init(struct obj **obj, boolean artif) { int mndx, tryct; + struct obj *otmp = *obj; char let = objects[otmp->otyp].oc_class; switch (let) { @@ -880,8 +881,11 @@ mksobj_init(struct obj *otmp, boolean artif) if (is_poisonable(otmp) && !rn2(100)) otmp->opoisoned = 1; - if (artif && !rn2(20 + (10 * nartifact_exist()))) + if (artif && !rn2(20 + (10 * nartifact_exist()))) { + /* mk_artifact() with otmp and A_NONE will never return NULL */ otmp = mk_artifact(otmp, (aligntyp) A_NONE, 99, TRUE); + *obj = otmp; + } break; case FOOD_CLASS: otmp->oeaten = 0; @@ -1085,8 +1089,11 @@ mksobj_init(struct obj *otmp, boolean artif) otmp->spe = rne(3); } else blessorcurse(otmp, 10); - if (artif && !rn2(40 + (10 * nartifact_exist()))) + if (artif && !rn2(40 + (10 * nartifact_exist()))) { + /* mk_artifact() with otmp and A_NONE will never return NULL */ otmp = mk_artifact(otmp, (aligntyp) A_NONE, 99, TRUE); + *obj = otmp; + } /* simulate lacquered armor for samurai */ if (Role_if(PM_SAMURAI) && otmp->otyp == SPLINT_MAIL && (svm.moves <= 1 || In_quest(&u.uz))) { @@ -1176,7 +1183,7 @@ mksobj(int otyp, boolean init, boolean artif) otmp->pickup_prev = 0; if (init) - mksobj_init(otmp, artif); + mksobj_init(&otmp, artif); /* some things must get done (corpsenm, timers) even if init = 0 */ switch ((otmp->oclass == POTION_CLASS && otmp->otyp != POT_OIL) @@ -1231,8 +1238,10 @@ mksobj(int otyp, boolean init, boolean artif) } /* unique objects may have an associated artifact entry */ - if (objects[otyp].oc_unique && !otmp->oartifact) + if (objects[otyp].oc_unique && !otmp->oartifact) { + /* mk_artifact() with otmp and A_NONE will never return NULL */ otmp = mk_artifact(otmp, (aligntyp) A_NONE, 99, FALSE); + } otmp->owt = weight(otmp); return otmp; } diff --git a/src/mplayer.c b/src/mplayer.c index 9e839b8fd..70b94b0f5 100644 --- a/src/mplayer.c +++ b/src/mplayer.c @@ -261,6 +261,7 @@ mk_mplayer(struct permonst *ptr, coordxy x, coordxy y, boolean special) otmp->oerodeproof = 1; else if (!rn2(2)) otmp->greased = 1; + /* mk_artifact() with otmp and A_NONE will never return NULL */ if (special && rn2(2)) otmp = mk_artifact(otmp, A_NONE, 99, FALSE); /* usually increase stack size if stackable weapon */ diff --git a/src/pray.c b/src/pray.c index 827b03226..ba700c4dd 100644 --- a/src/pray.c +++ b/src/pray.c @@ -1793,6 +1793,7 @@ bestow_artifact(uchar max_giftvalue) if (do_bestow) { struct obj *otmp; + /* mk_artifact() with NULL obj and a_align() arg can return NULL */ otmp = mk_artifact((struct obj *) 0, a_align(u.ux, u.uy), max_giftvalue, TRUE); if (otmp) { From ee0d955050c89c4c69e46cdaecf3a02e655b3ae8 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 26 Jan 2025 12:25:27 -0500 Subject: [PATCH 403/791] follow-up: make definition match proto staticfn --- src/artifact.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/artifact.c b/src/artifact.c index 7b69820b8..e519595aa 100644 --- a/src/artifact.c +++ b/src/artifact.c @@ -273,7 +273,7 @@ mk_artifact( return otmp; } -void +staticfn void dispose_of_orig_obj(struct obj *obj) { if (!obj) From f75e4a13b7e5216f06a5cdc2ab341c8d50f4df9f Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 26 Jan 2025 21:38:37 -0500 Subject: [PATCH 404/791] more follow-up for mk_artifact() --- src/artifact.c | 49 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/src/artifact.c b/src/artifact.c index e519595aa..b95bce4b8 100644 --- a/src/artifact.c +++ b/src/artifact.c @@ -150,12 +150,12 @@ artiname(int artinum) */ struct obj * mk_artifact( - struct obj *otmp, /* existing object; ignored if alignment specified */ + struct obj *otmp, /* existing object; ignored and disposed of + * if alignment specified */ aligntyp alignment, /* target alignment, or A_NONE */ uchar max_giftvalue, /* cap on generated giftvalue */ boolean adjust_spe) /* whether to add spe to situational artifacts */ { - struct obj *artiobj; const struct artifact *a; int m, n, altn; boolean by_align = (alignment != A_NONE); @@ -239,9 +239,31 @@ mk_artifact( m = eligible[rn2(n)]; /* [0..n-1] */ a = &artilist[m]; - /* make an appropriate object, then christen it */ - artiobj = mksobj((int) a->otyp, TRUE, FALSE); + /* make an appropriate object if necessary, then christen it */ + if (by_align) { + /* 'by_align' indicates that an alignment was passed as + * an argument, but also that the 'otmp' argument is not + * relevant */ + struct obj *artiobj = mksobj((int) a->otyp, TRUE, FALSE); + if (artiobj) { + /* nonnull value of 'otmp' is unexpected. Cope. */ + if (otmp) /* just in case; avoid orphaning */ + dispose_of_orig_obj(otmp); + otmp = artiobj; + } + } + /* + * otmp should be nonnull at this point: + * either the passed argument (if !by_align == A_NONE), or + * the result of mksobj() just above if by_align is an alignment. */ + assert(otmp != 0); + /* prevent erosion from generating */ + otmp->oeroded = otmp->oeroded2 = 0; + otmp = oname(otmp, a->name, ONAME_NO_FLAGS); + otmp->oartifact = m; /* probably already set by this point, but */ + /* set existence and reason for creation bits */ + artifact_origin(otmp, ONAME_RANDOM); /* 'random' is default */ if (adjust_spe) { int new_spe; @@ -249,26 +271,19 @@ mk_artifact( non-weapons, which always have a gen_spe of 0, and for many weapons, too.) The result is clamped into the "normal" range to prevent an outside chance of +12 artifacts generating. */ - new_spe = (int)artiobj->spe + a->gen_spe; + new_spe = (int)otmp->spe + a->gen_spe; if (new_spe >= -10 && new_spe < 10) - artiobj->spe = new_spe; + otmp->spe = new_spe; } - /* prevent erosion from generating */ - artiobj->oeroded = artiobj->oeroded2 = 0; - artiobj = oname(artiobj, a->name, ONAME_NO_FLAGS); - artiobj->oartifact = m; - /* set existence and reason for creation bits */ - artifact_origin(artiobj, ONAME_RANDOM); /* 'random' is default */ - if (otmp) - dispose_of_orig_obj(otmp); - otmp = artiobj; } else { /* nothing appropriate could be found; return original object */ if (by_align && otmp) { - /* (there shouldn't have been an original object) */ + /* (there shouldn't have been an original object). Deal with it. + * The callers that passed an alignment and a NULL otmp are + * prepared to get a potential NULL return value, so this is okay */ dispose_of_orig_obj(otmp); otmp = 0; - } + } /* otherwise, otmp has not changed; just fallthrough to return it */ } return otmp; } From b6eda143681eee78210c69f211094c3574a99f2a Mon Sep 17 00:00:00 2001 From: PatR Date: Mon, 27 Jan 2025 00:37:35 -0800 Subject: [PATCH 405/791] obj->tknown comments --- src/lock.c | 8 ++++++++ src/objnam.c | 6 +++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/lock.c b/src/lock.c index b95e98707..47e160b7a 100644 --- a/src/lock.c +++ b/src/lock.c @@ -432,6 +432,14 @@ pick_lock( boolean it; int count; + /* + * FIXME: + * (chest->otrapped && chest->tknown) is handled, to skip + * checking for a trap and continue with asking about disarm; + * (chest->tknown && !chest->otrapped) ignores tknown and will + * ask about checking for non-existant trap. + */ + if (u.dz < 0 && !autounlock) { /* beware stale u.dz value */ There("isn't any sort of lock up %s.", Levitation ? "here" : "there"); diff --git a/src/objnam.c b/src/objnam.c index df6b29167..4463a12bb 100644 --- a/src/objnam.c +++ b/src/objnam.c @@ -1338,7 +1338,11 @@ doname_base( Strcat(prefix, "uncursed "); } - /* "a large trapped box" would perhaps be more correct */ + /* "a large trapped box" would perhaps be more correct; [no!] + what about ``(obj->tknown && !obj->otrapped)''? shouldn't that + yield "a non-trapped large box"? (not "an untrapped large box"); + TODO: this should be ``(Is_box(obj) || obj->otyp == TIN) && ...'' + but at present there's no way to set obj->tknown for tins */ if (Is_box(obj) && obj->otrapped && obj->tknown && obj->dknown) Strcat(prefix,"trapped "); if (lknown && Is_box(obj)) { From 7ff7679a7690e939792ac84fc95938814f21985d Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 27 Jan 2025 10:12:10 -0500 Subject: [PATCH 406/791] remove a redundant check for NULL mksobj is declared to have a NONNULL return: extern struct obj *mksobj(int, boolean, boolean) NONNULL; Remove an unnecessary if block. --- src/artifact.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/artifact.c b/src/artifact.c index b95bce4b8..506d50ea1 100644 --- a/src/artifact.c +++ b/src/artifact.c @@ -246,12 +246,10 @@ mk_artifact( * relevant */ struct obj *artiobj = mksobj((int) a->otyp, TRUE, FALSE); - if (artiobj) { - /* nonnull value of 'otmp' is unexpected. Cope. */ - if (otmp) /* just in case; avoid orphaning */ - dispose_of_orig_obj(otmp); - otmp = artiobj; - } + /* nonnull value of 'otmp' is unexpected. Cope. */ + if (otmp) /* just in case; avoid orphaning */ + dispose_of_orig_obj(otmp); + otmp = artiobj; } /* * otmp should be nonnull at this point: From 3ffbfc724c4df10360fb2e04a058bd8656b507f5 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Tue, 28 Jan 2025 21:26:06 +0200 Subject: [PATCH 407/791] Fix another impossible no_charge object Tame earth elemental picked up a no_charge object from a shop and moved it out of the shop, causing "no_charge obj not inside tended shop" impossible. Non-tame monsters picking up no_charge items cleared that bit, so make the same happen for pets. --- src/steal.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/steal.c b/src/steal.c index 89ac7c841..f90d66a55 100644 --- a/src/steal.c +++ b/src/steal.c @@ -650,11 +650,11 @@ mpickobj(struct monst *mtmp, struct obj *otmp) pline("%s out.", Tobjnam(otmp, "go")); snuff_otmp = TRUE; } + /* for hero owned object on shop floor, mtmp is taking possession + and if it's eventually dropped in a shop, shk will claim it */ + otmp->no_charge = 0; /* some object handling is only done if mtmp isn't a pet */ if (!mtmp->mtame) { - /* for hero owned object on shop floor, mtmp is taking possession - and if it's eventually dropped in a shop, shk will claim it */ - otmp->no_charge = 0; /* if monst is unseen, some info hero knows about this object becomes lost; continual pickup and drop by pets makes this too annoying if it is applied to them; when engulfed (where monster can't be seen From cfe39900caaf03b8cd015b4c81ca6fcac36f4589 Mon Sep 17 00:00:00 2001 From: nhkeni Date: Fri, 31 Jan 2025 21:48:15 -0500 Subject: [PATCH 408/791] Demo for downloading formatted docs Written for MacOS, more useful for Windows (but I'm not writing that). --- doc/.gitignore | 8 +++++++- doc/fixes3-7-0.txt | 1 + sys/unix/Makefile.top | 19 +++++++++++++++++++ 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/doc/.gitignore b/doc/.gitignore index dfd019421..2cb6f5896 100644 --- a/doc/.gitignore +++ b/doc/.gitignore @@ -14,4 +14,10 @@ Guidebook.pdf Guidebook.ps Guidebook.dated.* *.synctex.* - +# files that might appear from "make fetch-docs" +dlb.pdf +makedefs.pdf +mn.pdf +mnh.pdf +nethack.pdf +recover.pdf diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index befaae8f6..7dd26ce21 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -2766,6 +2766,7 @@ healers gain experience by healing pets blessed scroll of destroy armor asks which armor to destroy archeologists' fedora is lucky telepathic hero can discern which particular monster just read a scroll +add "make fetch-docs" to download pre-formatted documentation Platform- and/or Interface-Specific New Features diff --git a/sys/unix/Makefile.top b/sys/unix/Makefile.top index 3d7b54727..f3bb66d23 100644 --- a/sys/unix/Makefile.top +++ b/sys/unix/Makefile.top @@ -397,6 +397,25 @@ fetch-lua-http: tar zxf lua-$(LUA_VERSION).tar.gz && \ rm -f lua-$(LUA_VERSION).tar.gz ) +# +# This is not part of the dependency build hierarchy. +# It requires an explicit "make fetch-docs". +fetch-docs: + @FDroot=https://www.nethack.org; \ + FDvmajor=`awk '/VERSION_MAJOR/{print $$3}' < include/patchlevel.h`; \ + FDvminor=`awk '/VERSION_MINOR/{print $$3}' < include/patchlevel.h`; \ + RDIR="NetHack-$${FDvmajor}.$${FDvminor}"; \ + echo "Fetching directory information for $${RDIR}"; \ + RDOCFILES=`curl --no-progress-meter $${FDroot}/cgi-bin/lsautodocs?$$RDIR`; \ + FDbase="$${FDroot}/autodocs/$${RDIR}"; \ + set -- $${RDOCFILES}; \ + echo "Fetching $$# files"; \ + while [ $$# -gt 0 ]; do \ + echo "Downloading: '$$1' from '$${FDbase}/$$1'"; \ + curl --no-progress-meter -R $${FDbase}/$$1 -o doc/$$1; \ + shift; \ + done + # 'make update' can be used to install a revised version after making # customizations or such. Unlike 'make install', it doesn't delete everything # from the target directory to have a clean start. From 6431f4727cf7ed293b6d24ce2ee2a49a8b16ebd1 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 1 Feb 2025 14:09:58 -0500 Subject: [PATCH 409/791] comment instructions in mextra.h updated --- include/mextra.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mextra.h b/include/mextra.h index 1942f9dc7..293132450 100644 --- a/include/mextra.h +++ b/include/mextra.h @@ -50,7 +50,7 @@ * src/makemon.c: if (mmflags & MM_XX) newXX(mtmp); * your new code: mon = makemon(&mons[mnum], x, y, MM_XX); * - * 7. Adjust size_monst() in src/cmd.c appropriately. + * 7. Adjust size_monst() in src/wizcmds.c appropriately. * 8. Adjust dealloc_mextra() in src/mon.c to clean up * properly during monst deallocation. * 9. Adjust copy_mextra() in src/mon.c to make duplicate From d74624abbd8bc18f16c962830abd2b92aa1bd95f Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 2 Feb 2025 08:30:48 -0500 Subject: [PATCH 410/791] add mexta field to simplify detection of overwrite Because this invalidates existing save and bones files, an increment of EDITLEVEL will accompany this. --- include/mextra.h | 5 +++++ src/dog.c | 1 + src/minion.c | 1 + src/priest.c | 1 + src/shknam.c | 1 + src/vault.c | 1 + 6 files changed, 10 insertions(+) diff --git a/include/mextra.h b/include/mextra.h index 293132450..f47010324 100644 --- a/include/mextra.h +++ b/include/mextra.h @@ -75,6 +75,7 @@ struct fakecorridor { }; struct egd { + unsigned parentmid; /* make clobber-detection possible */ int fcbeg, fcend; /* fcend: first unused pos */ int vroom; /* room number of the vault */ coordxy gdx, gdy; /* goal of guard's walk */ @@ -92,6 +93,7 @@ struct egd { ** formerly epri.h -- temple priest extension */ struct epri { + unsigned parentmid; /* make clobber-detection possible */ aligntyp shralign; /* alignment of priest's shrine */ schar shroom; /* index in rooms */ coord shrpos; /* position of shrine */ @@ -118,6 +120,7 @@ struct bill_x { }; struct eshk { + unsigned parentmid; /* make clobber-detection possible */ long robbed; /* amount stolen by most recent customer */ long credit; /* amount credited to customer */ long debit; /* amount of debt for using unpaid items */ @@ -145,6 +148,7 @@ struct eshk { ** formerly emin.h -- minion extension */ struct emin { + unsigned parentmid; /* make clobber-detection possible */ aligntyp min_align; /* alignment of minion */ boolean renegade; /* hostile co-aligned priest or Angel */ }; @@ -165,6 +169,7 @@ enum dogfood_types { }; struct edog { + unsigned parentmid; /* make clobber-detection possible */ long droptime; /* moment dog dropped object */ unsigned dropdist; /* dist of dropped obj from @ */ int apport; /* amount of training */ diff --git a/src/dog.c b/src/dog.c index 07336ef71..7c1fa5dd0 100644 --- a/src/dog.c +++ b/src/dog.c @@ -27,6 +27,7 @@ newedog(struct monst *mtmp) if (!EDOG(mtmp)) { EDOG(mtmp) = (struct edog *) alloc(sizeof(struct edog)); (void) memset((genericptr_t) EDOG(mtmp), 0, sizeof(struct edog)); + EDOG(mtmp)->parentmid = mtmp->m_id; } } diff --git a/src/minion.c b/src/minion.c index 77644e7a7..9de8bb233 100644 --- a/src/minion.c +++ b/src/minion.c @@ -21,6 +21,7 @@ newemin(struct monst *mtmp) if (!EMIN(mtmp)) { EMIN(mtmp) = (struct emin *) alloc(sizeof(struct emin)); (void) memset((genericptr_t) EMIN(mtmp), 0, sizeof(struct emin)); + EMIN(mtmp)->parentmid = mtmp->m_id; } } diff --git a/src/priest.c b/src/priest.c index 8308a96e6..10e83accc 100644 --- a/src/priest.c +++ b/src/priest.c @@ -20,6 +20,7 @@ newepri(struct monst *mtmp) if (!EPRI(mtmp)) { EPRI(mtmp) = (struct epri *) alloc(sizeof(struct epri)); (void) memset((genericptr_t) EPRI(mtmp), 0, sizeof(struct epri)); + EPRI(mtmp)->parentmid = mtmp->m_id; } } diff --git a/src/shknam.c b/src/shknam.c index 61016d56e..58a45ceea 100644 --- a/src/shknam.c +++ b/src/shknam.c @@ -561,6 +561,7 @@ neweshk(struct monst *mtmp) if (!ESHK(mtmp)) ESHK(mtmp) = (struct eshk *) alloc(sizeof(struct eshk)); (void) memset((genericptr_t) ESHK(mtmp), 0, sizeof(struct eshk)); + ESHK(mtmp)->parentmid = mtmp->m_id; ESHK(mtmp)->bill_p = (struct bill_x *) 0; } diff --git a/src/vault.c b/src/vault.c index 31002f65f..8bc79e6c7 100644 --- a/src/vault.c +++ b/src/vault.c @@ -27,6 +27,7 @@ newegd(struct monst *mtmp) if (!EGD(mtmp)) { EGD(mtmp) = (struct egd *) alloc(sizeof (struct egd)); (void) memset((genericptr_t) EGD(mtmp), 0, sizeof (struct egd)); + EGD(mtmp)->parentmid = mtmp->m_id; } } From d785f7a649af8240fa4d7b6b5b9e74d63270a09e Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 2 Feb 2025 09:00:05 -0500 Subject: [PATCH 411/791] add two unused fields for hardfought save compatability There are two hardfought code additions that render save and bones files incompatible with the upstream NetHack-3.7, and that makes testing with hardfought save and bones files more challenging than it needs to be, when investigating and troubleshooting bug reports. Add some unused fields to advance towards achieving save file parity with hardfought, which is a significant source of play-testing for NetHack-3.7. 1) the elbereth field addition to u_conduct This adds an unused placeholder field named 'hf_reserved1', at the appropriate place in u_conduct to achieve struct field parity with the one in use on hardfought. 2) hardfought adds a field to struct monst: char former_rank[25]; /* for bones' ghost rank in their former life */ Instead of adding that to every monst, this adds a new mextra struct named 'former', which currently contains the equivalent 25-character field called 'rank' which can hold the content that was in the former_rank[25] field. That way, the field will only be added when it is needed. A pull request https://github.com/k21971/NetHack37/pull/2 has been done on hardfought to do it the same way (untested there as of yet). Even though NetHack-3.7 does not utilize that information presently, this will be a further step toward allowing hardfought-generated save and bones files to be used for troubleshooting, without modification, on a similar architecture running stock NetHack-3.7 code. That savefile parity won't be achieved until the after the hardfought pull-request mentioned above (or equivalent) is merged. As this change will not be compatible with existing save and bones files, it will be accompanied with an EDITLEVEL increment. --- include/extern.h | 3 +++ include/mextra.h | 7 +++++++ include/mondata.h | 8 ++++++++ include/you.h | 1 + src/bones.c | 7 +++++++ src/botl.c | 3 +-- src/makemon.c | 22 ++++++++++++++++++++++ src/mon.c | 26 ++++++++++++++++++++++++-- src/restore.c | 9 +++++++++ src/save.c | 7 +++++++ src/wizcmds.c | 2 ++ 11 files changed, 91 insertions(+), 4 deletions(-) diff --git a/include/extern.h b/include/extern.h index d14e6d30c..265b69259 100644 --- a/include/extern.h +++ b/include/extern.h @@ -257,6 +257,7 @@ extern char *do_statusline2(void); extern void bot(void); extern void timebot(void); extern int xlev_to_rank(int); +extern const char *rank(void); extern int rank_to_xlev(int); extern const char *rank_of(int, short, boolean); extern int title_to_mon(const char *, int *, int *); @@ -1442,6 +1443,8 @@ extern void mkmonmoney(struct monst *, long) NONNULLARG1; extern int bagotricks(struct obj *, boolean, int *); extern boolean propagate(int, boolean, boolean); extern void summon_furies(int); +extern void newformer(struct monst *) NONNULLARG1; +extern void free_former(struct monst *) NONNULLARG1; /* ### mcastu.c ### */ diff --git a/include/mextra.h b/include/mextra.h index f47010324..0089991af 100644 --- a/include/mextra.h +++ b/include/mextra.h @@ -182,6 +182,10 @@ struct edog { Bitfield(killed_by_u, 1); /* you attempted to kill him */ }; +struct former_incarnation { + char rank[25]; /* for bones' ghost rank in their former life */ +}; + /*** ** mextra.h -- collection of all monster extensions */ @@ -192,6 +196,7 @@ struct mextra { struct eshk *eshk; struct emin *emin; struct edog *edog; + struct former_incarnation *former; int mcorpsenm; /* obj->corpsenm for mimic posing as statue or corpse, * obj->spe (fruit index) for one posing as a slime mold, * or an alignment mask for one posing as an altar */ @@ -203,6 +208,7 @@ struct mextra { #define ESHK(mon) ((mon)->mextra->eshk) #define EMIN(mon) ((mon)->mextra->emin) #define EDOG(mon) ((mon)->mextra->edog) +#define FORMER(mon) ((mon)->mextra->former) #define MCORPSENM(mon) ((mon)->mextra->mcorpsenm) #define has_mgivenname(mon) ((mon)->mextra && MGIVENNAME(mon)) @@ -211,6 +217,7 @@ struct mextra { #define has_eshk(mon) ((mon)->mextra && ESHK(mon)) #define has_emin(mon) ((mon)->mextra && EMIN(mon)) #define has_edog(mon) ((mon)->mextra && EDOG(mon)) +#define has_former(mon) ((mon)->mextra && FORMER(mon)) #define has_mcorpsenm(mon) ((mon)->mextra && MCORPSENM(mon) != NON_PM) #endif /* MEXTRA_H */ diff --git a/include/mondata.h b/include/mondata.h index 80a177f76..5296361fa 100644 --- a/include/mondata.h +++ b/include/mondata.h @@ -260,6 +260,14 @@ || objects[(obj)->otyp].oc_material == VEGGY \ || ((obj)->otyp == CORPSE && (obj)->corpsenm == PM_LICHEN)))) +/* is_bones_monster() is currently only used by hardfought livelog, + * but is included as part of savefile field compatibility adjustments. + */ +#define is_bones_monster(ptr) \ + ((ptr) == &mons[PM_GHOST] || (ptr) == &mons[PM_GHOUL] \ + || (ptr) == &mons[PM_VAMPIRE] || (ptr) == &mons[PM_WRAITH] \ + || (ptr) == &mons[PM_GREEN_SLIME] || (ptr)->mlet == S_MUMMY) + #ifdef PMNAME_MACROS #define pmname(ptr,g) ((((g) == MALE || (g) == FEMALE) && (ptr)->pmnames[g]) \ ? (ptr)->pmnames[g] : (ptr)->pmnames[NEUTRAL]) diff --git a/include/you.h b/include/you.h index cd734ca42..2683eec8f 100644 --- a/include/you.h +++ b/include/you.h @@ -153,6 +153,7 @@ struct u_conduct { /* number of times... */ long polyselfs; /* transformed yourself */ long wishes; /* used a wish */ long wisharti; /* wished for an artifact */ + long hf_reserved1; /* hf uses for elbereth;for hf savefile compatiblity */ long sokocheat; /* violated special 'rules' in Sokoban */ long pets; /* obtained a pet */ /* genocides already listed at end of game */ diff --git a/src/bones.c b/src/bones.c index 3ecd93125..34adac268 100644 --- a/src/bones.c +++ b/src/bones.c @@ -506,6 +506,13 @@ savebones(int how, time_t when, struct obj *corpse) mtmp->mhp = mtmp->mhpmax = u.uhpmax; mtmp->female = flags.female; mtmp->msleeping = 1; + if (!has_former(mtmp)) + newformer(mtmp); + if (has_former(mtmp)) { + Snprintf(FORMER(mtmp)->rank, + sizeof FORMER(mtmp)->rank, + "%s", rank()); + } } for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { set_ghostly_objlist(mtmp->minvent); diff --git a/src/botl.c b/src/botl.c index 51f15f19d..406796782 100644 --- a/src/botl.c +++ b/src/botl.c @@ -16,7 +16,6 @@ const char *const enc_stat[] = { "Strained", "Overtaxed", "Overloaded" }; -staticfn const char *rank(void); staticfn void bot_via_windowport(void); staticfn void stat_update_time(void); staticfn char *get_strength_str(void); @@ -361,7 +360,7 @@ rank_of(int lev, short monnum, boolean female) return "Player"; } -staticfn const char * +const char * rank(void) { return rank_of(u.ulevel, Role_switch, flags.female); diff --git a/src/makemon.c b/src/makemon.c index a7e52bf47..62de076b6 100644 --- a/src/makemon.c +++ b/src/makemon.c @@ -1070,6 +1070,28 @@ newmextra(void) return mextra; } +void +newformer(struct monst *mtmp) +{ + if (!mtmp->mextra) + mtmp->mextra = newmextra(); + if (!FORMER(mtmp)) { + FORMER(mtmp) = (struct former_incarnation *) alloc( + sizeof(struct former_incarnation *)); + (void) memset((genericptr_t) FORMER(mtmp), 0, + sizeof(struct former_incarnation *)); + } +} + +void +free_former(struct monst *mtmp) +{ + if (mtmp->mextra && FORMER(mtmp)) { + free((genericptr_t) FORMER(mtmp)); + FORMER(mtmp) = (struct former_incarnation *) 0; + } +} + staticfn boolean makemon_rnd_goodpos( struct monst *mon, diff --git a/src/mon.c b/src/mon.c index a59b1a13a..819cb7bdc 100644 --- a/src/mon.c +++ b/src/mon.c @@ -2567,6 +2567,12 @@ copy_mextra(struct monst *mtmp2, struct monst *mtmp1) assert(has_edog(mtmp2)); *EDOG(mtmp2) = *EDOG(mtmp1); } + if (FORMER(mtmp1)) { + if (!FORMER(mtmp2)) + newformer(mtmp2); + assert(has_former(mtmp2)); + *FORMER(mtmp2) = *FORMER(mtmp1); + } if (has_mcorpsenm(mtmp1)) MCORPSENM(mtmp2) = MCORPSENM(mtmp1); } @@ -2589,6 +2595,8 @@ dealloc_mextra(struct monst *m) free((genericptr_t) x->emin), x->emin = 0; if (x->edog) free((genericptr_t) x->edog), x->edog = 0; + if (x->former) + free((genericptr_t) x->former), x->former = 0; x->mcorpsenm = NON_PM; /* no allocation to release */ free((genericptr_t) x); @@ -2991,8 +2999,6 @@ logdeadmon(struct monst *mtmp, int mndx) } } -#undef livelog_mon_nam - /* monster 'mtmp' has died; maybe life-save, otherwise unshapeshift and update vanquished stats and update map */ void @@ -3635,10 +3641,26 @@ xkilled( /* malign was already adjusted for u.ualign.type and randomization */ adjalign(mtmp->malign); + +#if 0 /* HARDFOUGHT-only at present */ +#ifdef LIVELOG + if (is_bones_monster(mtmp->data) + && has_former(mtmp) && *FORMER(mtmp)->rank + && strlen(FORMER(mtmp)->rank) > 0) { + if (mtmp->data == &mons[PM_GHOST]) + livelog_printf(LL_UMONST, "destroyed %s, the former %s", + livelog_mon_nam(mtmp), FORMER(mtmp)->rank); + else + livelog_printf(LL_UMONST, "destroyed %s, and former %s", + livelog_mon_nam(mtmp), FORMER(mtmp)->rank); + } +#endif /* LIVELOG */ +#endif return; } #undef LEVEL_SPECIFIC_NOCORPSE +#undef livelog_mon_nam /* changes the monster into a stone monster of the same type this should only be called when poly_when_stoned() is true */ diff --git a/src/restore.c b/src/restore.c index 67be7cebb..5ab92311e 100644 --- a/src/restore.c +++ b/src/restore.c @@ -370,6 +370,15 @@ restmon(NHFILE *nhfp, struct monst *mtmp) EDOG(mtmp)->apport = 1; } } + /* former - info about former self, primarily for bones files */ + if (nhfp->structlevel) + Mread(nhfp->fd, &buflen, sizeof buflen); + if (buflen > 0) { + newformer(mtmp); + if (nhfp->structlevel) + Mread(nhfp->fd, FORMER(mtmp), + sizeof (struct former_incarnation)); + } /* mcorpsenm - obj->corpsenm for mimic posing as corpse or statue (inline int rather than pointer to something) */ if (nhfp->structlevel) diff --git a/src/save.c b/src/save.c index a178fbdcd..e383b52b8 100644 --- a/src/save.c +++ b/src/save.c @@ -943,6 +943,13 @@ savemon(NHFILE *nhfp, struct monst *mtmp) if (nhfp->structlevel) bwrite(nhfp->fd, (genericptr_t) EDOG(mtmp), buflen); } + buflen = FORMER(mtmp) ? (int) sizeof (struct former_incarnation) : 0; + if (nhfp->structlevel) + bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof (int)); + if (buflen > 0) { + if (nhfp->structlevel) + bwrite(nhfp->fd, (genericptr_t) FORMER(mtmp), buflen); + } /* mcorpsenm is inline int rather than pointer to something, so doesn't need to be preceded by a length field */ if (nhfp->structlevel) diff --git a/src/wizcmds.c b/src/wizcmds.c index 17dc08c5b..a37c469aa 100644 --- a/src/wizcmds.c +++ b/src/wizcmds.c @@ -1246,6 +1246,8 @@ size_monst(struct monst *mtmp, boolean incl_wsegs) sz += (int) sizeof (struct emin); if (EDOG(mtmp)) sz += (int) sizeof (struct edog); + if (FORMER(mtmp)) + sz += (int) sizeof (struct former_incarnation); /* mextra->mcorpsenm doesn't point to more memory */ } return sz; From bda3437eab1585bfeba5425c11f8e7d80c4a190e Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 2 Feb 2025 09:00:21 -0500 Subject: [PATCH 412/791] bump EDITLEVEL --- include/patchlevel.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/patchlevel.h b/include/patchlevel.h index 643ffba38..ce5efe227 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 115 +#define EDITLEVEL 116 /* * Development status possibilities. From d331029b037f98a58098c4b91b195f3de85d450c Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 2 Feb 2025 09:08:48 -0500 Subject: [PATCH 413/791] more clobber-detection --- include/mextra.h | 1 + include/patchlevel.h | 2 +- src/makemon.c | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/include/mextra.h b/include/mextra.h index 0089991af..7f0d00f46 100644 --- a/include/mextra.h +++ b/include/mextra.h @@ -183,6 +183,7 @@ struct edog { }; struct former_incarnation { + unsigned parentmid; /* make clobber-detection possible */ char rank[25]; /* for bones' ghost rank in their former life */ }; diff --git a/include/patchlevel.h b/include/patchlevel.h index ce5efe227..9149b3b5f 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 116 +#define EDITLEVEL 117 /* * Development status possibilities. diff --git a/src/makemon.c b/src/makemon.c index 62de076b6..9e62c168b 100644 --- a/src/makemon.c +++ b/src/makemon.c @@ -1080,6 +1080,7 @@ newformer(struct monst *mtmp) sizeof(struct former_incarnation *)); (void) memset((genericptr_t) FORMER(mtmp), 0, sizeof(struct former_incarnation *)); + FORMER(mtmp)->parentmid = mtmp->m_id; } } From d65d0062a9a6437bba28c1c1c8963523683abb6f Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 2 Feb 2025 12:53:58 -0500 Subject: [PATCH 414/791] follow-up: evolve placeholder content to match variant suggestion by paxed Increments EDITLEVEL again. --- include/mextra.h | 11 +++++++++-- include/mondata.h | 8 -------- include/patchlevel.h | 2 +- src/bones.c | 6 +++--- src/do_name.c | 7 +++++++ src/end.c | 9 +++++++++ src/mon.c | 16 +++++++--------- 7 files changed, 36 insertions(+), 23 deletions(-) diff --git a/include/mextra.h b/include/mextra.h index 7f0d00f46..a665b953b 100644 --- a/include/mextra.h +++ b/include/mextra.h @@ -182,9 +182,16 @@ struct edog { Bitfield(killed_by_u, 1); /* you attempted to kill him */ }; +/* for saving the hero's rank in bones monster */ +struct mon_former_rank { + int lev; + short mnum; + boolean female; +}; + struct former_incarnation { - unsigned parentmid; /* make clobber-detection possible */ - char rank[25]; /* for bones' ghost rank in their former life */ + unsigned parentmid; /* make clobber-detection possible */ + struct mon_former_rank rank; /* for bones' ghost rank in former life */ }; /*** diff --git a/include/mondata.h b/include/mondata.h index 5296361fa..80a177f76 100644 --- a/include/mondata.h +++ b/include/mondata.h @@ -260,14 +260,6 @@ || objects[(obj)->otyp].oc_material == VEGGY \ || ((obj)->otyp == CORPSE && (obj)->corpsenm == PM_LICHEN)))) -/* is_bones_monster() is currently only used by hardfought livelog, - * but is included as part of savefile field compatibility adjustments. - */ -#define is_bones_monster(ptr) \ - ((ptr) == &mons[PM_GHOST] || (ptr) == &mons[PM_GHOUL] \ - || (ptr) == &mons[PM_VAMPIRE] || (ptr) == &mons[PM_WRAITH] \ - || (ptr) == &mons[PM_GREEN_SLIME] || (ptr)->mlet == S_MUMMY) - #ifdef PMNAME_MACROS #define pmname(ptr,g) ((((g) == MALE || (g) == FEMALE) && (ptr)->pmnames[g]) \ ? (ptr)->pmnames[g] : (ptr)->pmnames[NEUTRAL]) diff --git a/include/patchlevel.h b/include/patchlevel.h index 9149b3b5f..1c688630e 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 117 +#define EDITLEVEL 118 /* * Development status possibilities. diff --git a/src/bones.c b/src/bones.c index 34adac268..7b43db3e2 100644 --- a/src/bones.c +++ b/src/bones.c @@ -509,9 +509,9 @@ savebones(int how, time_t when, struct obj *corpse) if (!has_former(mtmp)) newformer(mtmp); if (has_former(mtmp)) { - Snprintf(FORMER(mtmp)->rank, - sizeof FORMER(mtmp)->rank, - "%s", rank()); + FORMER(mtmp)->rank.lev = mtmp->m_lev; + FORMER(mtmp)->rank.mnum = Role_switch; + FORMER(mtmp)->rank.female = flags.female; } } for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { diff --git a/src/do_name.c b/src/do_name.c index d5b7d7852..f690a2984 100644 --- a/src/do_name.c +++ b/src/do_name.c @@ -954,6 +954,10 @@ x_monnam( } else if (do_name && has_mgivenname(mtmp)) { char *name = MGIVENNAME(mtmp); +#if 0 + /* hardfought */ + if (has_former(mtmp) && FORMER(mtmp)->rank.mnum != NON_PM) { +#endif if (mdat == &mons[PM_GHOST]) { Sprintf(eos(buf), "%s ghost", s_suffix(name)); name_at_start = TRUE; @@ -976,6 +980,9 @@ x_monnam( Strcat(buf, name); name_at_start = TRUE; } +#if 0 /* hardfought */ + } +#endif } else if (is_mplayer(mdat) && !In_endgame(&u.uz)) { char pbuf[BUFSZ]; diff --git a/src/end.c b/src/end.c index b4370f049..4c916024a 100644 --- a/src/end.c +++ b/src/end.c @@ -204,7 +204,12 @@ done_in_by(struct monst *mtmp, int how) svk.killer.format = KILLED_BY; } /* _the_ ghost of Dudley */ +#if 0 + /* hardfought */ + if (has_former(mtmp) && FORMER(mtmp)->rank.mnum != NON_PM) { +#else if (mptr == &mons[PM_GHOST] && has_mgivenname(mtmp)) { +#endif Strcat(buf, "the "); svk.killer.format = KILLED_BY; } @@ -247,6 +252,10 @@ done_in_by(struct monst *mtmp, int how) : "%s imitating %s", realnm, shape); mptr = mtmp->data; /* reset for mimicker case */ +#if 0 /* hardfought */ + } else if (has_former(mtmp) && FORMER(mtmp)->rank.mnum != NON_PM) + Strcpy(buf, m_monnam(mtmp)); +#endif } else if (mptr == &mons[PM_GHOST]) { Strcat(buf, "ghost"); if (has_mgivenname(mtmp)) diff --git a/src/mon.c b/src/mon.c index 819cb7bdc..9a11354f5 100644 --- a/src/mon.c +++ b/src/mon.c @@ -3644,15 +3644,13 @@ xkilled( #if 0 /* HARDFOUGHT-only at present */ #ifdef LIVELOG - if (is_bones_monster(mtmp->data) - && has_former(mtmp) && *FORMER(mtmp)->rank - && strlen(FORMER(mtmp)->rank) > 0) { - if (mtmp->data == &mons[PM_GHOST]) - livelog_printf(LL_UMONST, "destroyed %s, the former %s", - livelog_mon_nam(mtmp), FORMER(mtmp)->rank); - else - livelog_printf(LL_UMONST, "destroyed %s, and former %s", - livelog_mon_nam(mtmp), FORMER(mtmp)->rank); + if (has_former(mtmp) && FORMER(mtmp)->rank.mnum != NON_PM) { + livelog_printf(LL_UMONST, "destroyed %s, %s former %s", + livelog_mon_nam(mtmp), + (mtmp->data == &mons[PM_GHOST]) ? "the" : "and", + rank_of(FORMER(mtmp)->rank.lev, + FORMER(mtmp)->rank.mnum, + FORMER(mtmp)->rank.female)); } #endif /* LIVELOG */ #endif From 785f78c39bfb48ff93a25658800a27a8c77d23ea Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 3 Feb 2025 00:53:06 -0500 Subject: [PATCH 415/791] avoid "You fall down a deep shaft!" if flying down Fixes #1371 --- doc/fixes3-7-0.txt | 1 + src/trap.c | 10 ++++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index befaae8f6..3c6a8e235 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -1499,6 +1499,7 @@ when you hear a monster incant a scroll, ensure that the 'I' invisible monster indicator doesn't trump telepathy briefly proceed with showpaths option even if the sysconf file is missing angry shopkeeper was not charging for thrown items +avoid "You fall down a deep shaft!" if deliberately flying down Fixes to 3.7.0-x General Problems Exposed Via git Repository diff --git a/src/trap.c b/src/trap.c index 06e54791e..f309dd595 100644 --- a/src/trap.c +++ b/src/trap.c @@ -608,6 +608,7 @@ fall_through( const char *dont_fall = 0; int newlevel; struct trap *t = (struct trap *) 0; + boolean controlled_flight = FALSE; /* we'll fall even while levitating in Sokoban; otherwise, if we won't fall and won't be told that we aren't falling, give up now */ @@ -653,12 +654,15 @@ fall_through( return; } if ((Flying || is_clinger(gy.youmonst.data)) - && (ftflags & TOOKPLUNGE) && td && t) + && (ftflags & TOOKPLUNGE) && td && t) { + if (Flying) + controlled_flight = TRUE; You("%s down %s!", Flying ? "swoop" : "deliberately drop", (t->ttyp == TRAPDOOR) ? "through the trap door" : "into the gaping hole"); + } if (*u.ushops) shopdig(1); @@ -678,7 +682,9 @@ fall_through( } dist = depth(&dtmp) - depth(&u.uz); if (dist > 1) - You("fall down a %s%sshaft!", dist > 3 ? "very " : "", + You("%s down a %s%sshaft!", + controlled_flight ? "fly" : "fall", + dist > 3 ? "very " : "", dist > 2 ? "deep " : ""); } if (!td) From a311f4b46748a8aea8f719dc850660732dfee00e Mon Sep 17 00:00:00 2001 From: PatR Date: Mon, 3 Feb 2025 11:42:36 -0800 Subject: [PATCH 416/791] fix issue #1362 - carrying Mitre of Holiness Issue reported by elunna: the definition of the Mitre of Holiness specifies that carrying it should confer fire resistance but that didn't work. The Mitre's definition (added in 3.1.0) has always included that, but such a capability had never been implemented. Wearing it didn't confer fire resistance either--its definition doesn't bother to specify a 'defend' attribute since the 'carry' one should cover that. This adds carrying capability for damage types fire, cold, sleep, disintegration, electrity, poison, acid, and petrification. Fire is still specified by the Mitre; none of the others are currently used. Fixes #1362 --- doc/fixes3-7-0.txt | 6 ++++- include/extern.h | 3 ++- include/monst.h | 27 ++++++++------------ src/mondata.c | 61 +++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 77 insertions(+), 20 deletions(-) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index 3c6a8e235..d4b8d1671 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -1,4 +1,4 @@ -NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.1484 $ $NHDT-Date: 1726862062 2024/09/20 19:54:22 $ +NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.1533 $ $NHDT-Date: 1738638877 2025/02/03 19:14:37 $ General Fixes and Modified Features ----------------------------------- @@ -1500,6 +1500,10 @@ when you hear a monster incant a scroll, ensure that the 'I' invisible proceed with showpaths option even if the sysconf file is missing angry shopkeeper was not charging for thrown items avoid "You fall down a deep shaft!" if deliberately flying down +since introduction in 3.1.0, the definition for Mitre of Holiness has specified + that carrying it provides fire resistance, but that had never been + implemented; wearing it didn't confer fire resistance either--there is + no 'defends' capability for it since carrying should encompass that Fixes to 3.7.0-x General Problems Exposed Via git Repository diff --git a/include/extern.h b/include/extern.h index 265b69259..e9988c798 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1,4 +1,4 @@ -/* NetHack 3.7 extern.h $NHDT-Date: 1723580890 2024/08/13 20:28:10 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.1435 $ */ +/* NetHack 3.7 extern.h $NHDT-Date: 1738638877 2025/02/03 19:14:37 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.1476 $ */ /* Copyright (c) Steve Creps, 1988. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1803,6 +1803,7 @@ extern boolean attacktype(struct permonst *, int) NONNULLARG1; extern boolean noattacks(struct permonst *) NONNULLARG1; extern boolean poly_when_stoned(struct permonst *) NONNULLARG1; extern boolean defended(struct monst *, int) NONNULLARG1; +extern boolean Resists_Elem(struct monst *, int) NONNULLARG1; extern boolean resists_drli(struct monst *) NONNULLARG1; extern boolean resists_magm(struct monst *) NONNULLARG1; extern boolean resists_blnd(struct monst *) NONNULLARG1; diff --git a/include/monst.h b/include/monst.h index a7f39c18e..b3f8956fd 100644 --- a/include/monst.h +++ b/include/monst.h @@ -1,4 +1,4 @@ -/* NetHack 3.7 monst.h $NHDT-Date: 1678560511 2023/03/11 18:48:31 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.54 $ */ +/* NetHack 3.7 monst.h $NHDT-Date: 1738640524 2025/02/03 19:42:04 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.67 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2016. */ /* NetHack may be freely redistributed. See license for details. */ @@ -268,22 +268,15 @@ struct monst { #endif #define mon_resistancebits(mon) \ ((mon)->data->mresists | (mon)->mextrinsics | (mon)->mintrinsics) -#define resists_fire(mon) \ - ((mon_resistancebits(mon) & MR_FIRE) != 0) -#define resists_cold(mon) \ - ((mon_resistancebits(mon) & MR_COLD) != 0) -#define resists_sleep(mon) \ - ((mon_resistancebits(mon) & MR_SLEEP) != 0) -#define resists_disint(mon) \ - ((mon_resistancebits(mon) & MR_DISINT) != 0) -#define resists_elec(mon) \ - ((mon_resistancebits(mon) & MR_ELEC) != 0) -#define resists_poison(mon) \ - ((mon_resistancebits(mon) & MR_POISON) != 0) -#define resists_acid(mon) \ - ((mon_resistancebits(mon) & MR_ACID) != 0) -#define resists_ston(mon) \ - ((mon_resistancebits(mon) & MR_STONE) != 0) +#define resists_fire(mon) Resists_Elem(mon, MR_FIRE) +#define resists_cold(mon) Resists_Elem(mon, MR_COLD) +#define resists_sleep(mon) Resists_Elem(mon, MR_SLEEP) +#define resists_disint(mon) Resists_Elem(mon, MR_DISINT) +#define resists_elec(mon) Resists_Elem(mon, MR_ELEC) +#define resists_poison(mon) Resists_Elem(mon, MR_POISON) +#define resists_acid(mon) Resists_Elem(mon, MR_ACID) +#define resists_ston(mon) Resists_Elem(mon, MR_STONE) + #define is_lminion(mon) \ (is_minion((mon)->data) && mon_aligntyp(mon) == A_LAWFUL) diff --git a/src/mondata.c b/src/mondata.c index 49a887a80..bb032bdfd 100644 --- a/src/mondata.c +++ b/src/mondata.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 mondata.c $NHDT-Date: 1711620615 2024/03/28 10:10:15 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.132 $ */ +/* NetHack 3.7 mondata.c $NHDT-Date: 1738638877 2025/02/03 19:14:37 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.140 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2011. */ /* NetHack may be freely redistributed. See license for details. */ @@ -123,6 +123,65 @@ defended(struct monst *mon, int adtyp) return FALSE; } +/* returns True if monster resists particular elemental damage; mostly used + in order to check effects of carried artifacts */ +boolean +Resists_Elem(struct monst *mon, int restyp) +{ + struct obj *o; + long slotmask; + boolean is_you = (mon == &gy.youmonst); + int u_resist, dmgtyp = 0, proptyp = 0; + + switch (restyp) { + case MR_FIRE: + case MR_COLD: + case MR_SLEEP: + case MR_DISINT: + case MR_ELEC: + case MR_POISON: + case MR_ACID: + case MR_STONE: + dmgtyp = restyp; + proptyp = dmgtyp - 1; /* valid for dmgtyp|restyp 2..9 */ + break; + + /* accept these, but we expect callers to use their routines directly */ + case ANTIMAGIC: + return resists_magm(mon); + case DRAIN_RES: + return resists_drli(mon); + case BLND_RES: + return resists_blnd(mon); + + default: + impossible("Resists_Elem(%d), unexpected resistance type", restyp); + return FALSE; + } + u_resist = u.uprops[restyp].intrinsic || u.uprops[restyp].extrinsic; + + if (is_you ? u_resist : ((mon_resistancebits(mon) & restyp) != 0)) + return TRUE; + /* check for resistance granted by wielded weapon */ + o = is_you ? uwep : MON_WEP(mon); + if (o && o->oartifact && defends(dmgtyp, o)) + return TRUE; + /* check for resistance granted by worn or carried items */ + o = is_you ? gi.invent : mon->minvent; + slotmask = W_ARMOR | W_ACCESSORY; + if (!is_you /* assumes monsters don't wield non-weapons */ + || (uwep && (uwep->oclass == WEAPON_CLASS || is_weptool(uwep)))) + slotmask |= W_WEP; + if (is_you && u.twoweap) + slotmask |= W_SWAPWEP; + for (; o; o = o->nobj) + if (((o->owornmask & slotmask) != 0L + && objects[o->otyp].oc_oprop == restyp) + || (o->oartifact && defends_when_carried(dmgtyp, o))) + return TRUE; + return FALSE; +} + /* returns True if monster is drain-life resistant */ boolean resists_drli(struct monst *mon) From b44a547153bb358570d2b124150bc6840dae0bdd Mon Sep 17 00:00:00 2001 From: PatR Date: Mon, 3 Feb 2025 23:20:07 -0800 Subject: [PATCH 417/791] fix resistance breakage The Mitre of Holiness commit broke resistance handling. This seems to work correctly. --- include/monst.h | 16 ++++++++-------- src/mondata.c | 29 ++++++++++++++--------------- 2 files changed, 22 insertions(+), 23 deletions(-) diff --git a/include/monst.h b/include/monst.h index b3f8956fd..9315d31f0 100644 --- a/include/monst.h +++ b/include/monst.h @@ -268,14 +268,14 @@ struct monst { #endif #define mon_resistancebits(mon) \ ((mon)->data->mresists | (mon)->mextrinsics | (mon)->mintrinsics) -#define resists_fire(mon) Resists_Elem(mon, MR_FIRE) -#define resists_cold(mon) Resists_Elem(mon, MR_COLD) -#define resists_sleep(mon) Resists_Elem(mon, MR_SLEEP) -#define resists_disint(mon) Resists_Elem(mon, MR_DISINT) -#define resists_elec(mon) Resists_Elem(mon, MR_ELEC) -#define resists_poison(mon) Resists_Elem(mon, MR_POISON) -#define resists_acid(mon) Resists_Elem(mon, MR_ACID) -#define resists_ston(mon) Resists_Elem(mon, MR_STONE) +#define resists_fire(mon) Resists_Elem(mon, FIRE_RES) +#define resists_cold(mon) Resists_Elem(mon, COLD_RES) +#define resists_sleep(mon) Resists_Elem(mon, SLEEP_RES) +#define resists_disint(mon) Resists_Elem(mon, DISINT_RES) +#define resists_elec(mon) Resists_Elem(mon, SHOCK_RES) +#define resists_poison(mon) Resists_Elem(mon, POISON_RES) +#define resists_acid(mon) Resists_Elem(mon, ACID_RES) +#define resists_ston(mon) Resists_Elem(mon, STONE_RES) #define is_lminion(mon) \ (is_minion((mon)->data) && mon_aligntyp(mon) == A_LAWFUL) diff --git a/src/mondata.c b/src/mondata.c index bb032bdfd..ef8f6fbc5 100644 --- a/src/mondata.c +++ b/src/mondata.c @@ -126,24 +126,24 @@ defended(struct monst *mon, int adtyp) /* returns True if monster resists particular elemental damage; mostly used in order to check effects of carried artifacts */ boolean -Resists_Elem(struct monst *mon, int restyp) +Resists_Elem(struct monst *mon, int proptyp) { struct obj *o; long slotmask; boolean is_you = (mon == &gy.youmonst); - int u_resist, dmgtyp = 0, proptyp = 0; + int u_resist = 0, dmgtyp = 0, restyp = 0; - switch (restyp) { - case MR_FIRE: - case MR_COLD: - case MR_SLEEP: - case MR_DISINT: - case MR_ELEC: - case MR_POISON: - case MR_ACID: - case MR_STONE: - dmgtyp = restyp; - proptyp = dmgtyp - 1; /* valid for dmgtyp|restyp 2..9 */ + switch (proptyp) { + case FIRE_RES: + case COLD_RES: + case SLEEP_RES: + case DISINT_RES: + case SHOCK_RES: + case POISON_RES: + case ACID_RES: + case STONE_RES: + dmgtyp = restyp = proptyp + 1; /* valid for dmgtyp|restyp 2..9 */ + u_resist = u.uprops[proptyp].intrinsic || u.uprops[proptyp].extrinsic; break; /* accept these, but we expect callers to use their routines directly */ @@ -155,10 +155,9 @@ Resists_Elem(struct monst *mon, int restyp) return resists_blnd(mon); default: - impossible("Resists_Elem(%d), unexpected resistance type", restyp); + impossible("Resists_Elem(%d), unexpected property type", proptyp); return FALSE; } - u_resist = u.uprops[restyp].intrinsic || u.uprops[restyp].extrinsic; if (is_you ? u_resist : ((mon_resistancebits(mon) & restyp) != 0)) return TRUE; From 3d02eb45d3dea5f8ed21c6de8bd542992df3f25f Mon Sep 17 00:00:00 2001 From: PatR Date: Tue, 4 Feb 2025 11:06:53 -0800 Subject: [PATCH 418/791] resistance checking again Another attempt to straighten out resistance checking.... --- src/mondata.c | 55 ++++++++++++++++++++++++++++++++------------------- 1 file changed, 35 insertions(+), 20 deletions(-) diff --git a/src/mondata.c b/src/mondata.c index ef8f6fbc5..e7710f01a 100644 --- a/src/mondata.c +++ b/src/mondata.c @@ -123,27 +123,36 @@ defended(struct monst *mon, int adtyp) return FALSE; } -/* returns True if monster resists particular elemental damage; mostly used - in order to check effects of carried artifacts */ +/* returns True if monster resists particular elemental damage; + handles 'carry' effects of artifacts as well as worn/wielded items */ boolean -Resists_Elem(struct monst *mon, int proptyp) +Resists_Elem(struct monst *mon, int propindx) { struct obj *o; long slotmask; boolean is_you = (mon == &gy.youmonst); - int u_resist = 0, dmgtyp = 0, restyp = 0; + int u_resist = 0, damgtype = 0, rsstmask = 0; - switch (proptyp) { - case FIRE_RES: - case COLD_RES: - case SLEEP_RES: - case DISINT_RES: - case SHOCK_RES: - case POISON_RES: - case ACID_RES: - case STONE_RES: - dmgtyp = restyp = proptyp + 1; /* valid for dmgtyp|restyp 2..9 */ - u_resist = u.uprops[proptyp].intrinsic || u.uprops[proptyp].extrinsic; + /* + * Main damage/resistance types, mostly matching dragon breath values. + * propindx = property index, fire (1), cold, (2) through stone (8); + * damgtype = damage type, 2 through 9 (0 and 1 aren't used here); + * rsstmask = resistance mask, 1, 2, 4, ..., 64, 128. + */ + + switch (propindx) { + case FIRE_RES: /* 1 */ + case COLD_RES: /* 2 */ + case SLEEP_RES: /* 3 */ + case DISINT_RES: /* 4 */ + case SHOCK_RES: /* 5 */ + case POISON_RES: /* 6 */ + case ACID_RES: /* 7 */ + case STONE_RES: /* 8 */ + damgtype = propindx + 1; /* valid for propindx 1..8, damgtype 2..9 */ + rsstmask = 1 << (propindx - 1); /* valid for propindx 1..8 */ + u_resist = u.uprops[propindx].intrinsic + || u.uprops[propindx].extrinsic; break; /* accept these, but we expect callers to use their routines directly */ @@ -155,15 +164,15 @@ Resists_Elem(struct monst *mon, int proptyp) return resists_blnd(mon); default: - impossible("Resists_Elem(%d), unexpected property type", proptyp); + impossible("Resists_Elem(%d), unexpected property type", propindx); return FALSE; } - if (is_you ? u_resist : ((mon_resistancebits(mon) & restyp) != 0)) + if (is_you ? u_resist : ((mon_resistancebits(mon) & rsstmask) != 0)) return TRUE; /* check for resistance granted by wielded weapon */ o = is_you ? uwep : MON_WEP(mon); - if (o && o->oartifact && defends(dmgtyp, o)) + if (o && o->oartifact && defends(damgtype, o)) return TRUE; /* check for resistance granted by worn or carried items */ o = is_you ? gi.invent : mon->minvent; @@ -175,8 +184,14 @@ Resists_Elem(struct monst *mon, int proptyp) slotmask |= W_SWAPWEP; for (; o; o = o->nobj) if (((o->owornmask & slotmask) != 0L - && objects[o->otyp].oc_oprop == restyp) - || (o->oartifact && defends_when_carried(dmgtyp, o))) + && objects[o->otyp].oc_oprop == propindx) + || ((o->owornmask & W_ARMC) == W_ARMC + /* worn apron confers a pair of resistances but + objects[ALCHEMY_SMOCK].oc_oprop can only represent one; + we check both so won't need to know which one that is */ + && o->otyp == ALCHEMY_SMOCK + && (propindx == POISON_RES || propindx == ACID_RES)) + || (o->oartifact && defends_when_carried(damgtype, o))) return TRUE; return FALSE; } From c24786430f6dd6fc1341431dafbaa17df00c46d9 Mon Sep 17 00:00:00 2001 From: nhmall Date: Tue, 4 Feb 2025 15:16:42 -0500 Subject: [PATCH 419/791] 'struct former' -> 'struct ebones' Some variants were already using a similar approach using a struct called 'ebones', so adopt the same naming so NetHack-3.7, hardfought, and some variants are using the same name. As before there are fields in the struct that are not currently used by NetHack-3.7, but the intent is that hardfought save and bones files can be loaded by NetHack-3.7 without code modification, for debugging bug reports. This invalidates existing save and bones files. --- include/extern.h | 4 +-- include/hack.h | 1 + include/mextra.h | 30 ++++++++++++---------- include/patchlevel.h | 2 +- src/bones.c | 59 +++++++++++++++++++++++++++++++++++++++----- src/do_name.c | 4 +-- src/end.c | 11 ++++++--- src/makemon.c | 23 ----------------- src/mon.c | 22 ++++++++--------- src/restore.c | 8 +++--- src/role.c | 7 +++++- src/save.c | 4 +-- src/wizcmds.c | 4 +-- 13 files changed, 108 insertions(+), 71 deletions(-) diff --git a/include/extern.h b/include/extern.h index e9988c798..7ab07ada2 100644 --- a/include/extern.h +++ b/include/extern.h @@ -248,6 +248,8 @@ extern void savebones(int, time_t, struct obj *); extern int getbones(void); extern boolean bones_include_name(const char *) NONNULLARG1; extern void fix_ghostly_obj(struct obj *) NONNULLARG1; +extern void newebones(struct monst *) NONNULLARG1; +extern void free_ebones(struct monst *) NONNULLARG1; /* ### botl.c ### */ @@ -1443,8 +1445,6 @@ extern void mkmonmoney(struct monst *, long) NONNULLARG1; extern int bagotricks(struct obj *, boolean, int *); extern boolean propagate(int, boolean, boolean); extern void summon_furies(int); -extern void newformer(struct monst *) NONNULLARG1; -extern void free_former(struct monst *) NONNULLARG1; /* ### mcastu.c ### */ diff --git a/include/hack.h b/include/hack.h index 643075129..3fb02f687 100644 --- a/include/hack.h +++ b/include/hack.h @@ -767,6 +767,7 @@ struct role_filter { boolean roles[NUM_ROLES + 1]; short mask; }; +#define NUM_RACES (5) enum saveformats { invalid = 0, diff --git a/include/mextra.h b/include/mextra.h index a665b953b..6cafb4890 100644 --- a/include/mextra.h +++ b/include/mextra.h @@ -182,16 +182,20 @@ struct edog { Bitfield(killed_by_u, 1); /* you attempted to kill him */ }; -/* for saving the hero's rank in bones monster */ -struct mon_former_rank { - int lev; - short mnum; - boolean female; -}; - -struct former_incarnation { - unsigned parentmid; /* make clobber-detection possible */ - struct mon_former_rank rank; /* for bones' ghost rank in former life */ +/*** + ** extension tracking a player's remnant monster (ghost, mummy etc.) + */ +struct ebones { + unsigned parentmid; /* make clobber-detection possible */ + uchar role; /* index into roles[] */ + uchar race; /* index into races[] */ + align oldalign; /* character alignment */ + uchar deathlevel; /* level when dying (m_lev may differ) */ + schar luck; /* luck when dying */ + short mnum; /* monster type */ + Bitfield(female, 1); /* was female */ + Bitfield(demigod, 1); /* had killed wiz or invoked */ + Bitfield(crowned, 1); /* had been crowned */ }; /*** @@ -204,7 +208,7 @@ struct mextra { struct eshk *eshk; struct emin *emin; struct edog *edog; - struct former_incarnation *former; + struct ebones *ebones; int mcorpsenm; /* obj->corpsenm for mimic posing as statue or corpse, * obj->spe (fruit index) for one posing as a slime mold, * or an alignment mask for one posing as an altar */ @@ -216,7 +220,7 @@ struct mextra { #define ESHK(mon) ((mon)->mextra->eshk) #define EMIN(mon) ((mon)->mextra->emin) #define EDOG(mon) ((mon)->mextra->edog) -#define FORMER(mon) ((mon)->mextra->former) +#define EBONES(mon) ((mon)->mextra->ebones) #define MCORPSENM(mon) ((mon)->mextra->mcorpsenm) #define has_mgivenname(mon) ((mon)->mextra && MGIVENNAME(mon)) @@ -225,7 +229,7 @@ struct mextra { #define has_eshk(mon) ((mon)->mextra && ESHK(mon)) #define has_emin(mon) ((mon)->mextra && EMIN(mon)) #define has_edog(mon) ((mon)->mextra && EDOG(mon)) -#define has_former(mon) ((mon)->mextra && FORMER(mon)) +#define has_ebones(mon) ((mon)->mextra && EBONES(mon)) #define has_mcorpsenm(mon) ((mon)->mextra && MCORPSENM(mon) != NON_PM) #endif /* MEXTRA_H */ diff --git a/include/patchlevel.h b/include/patchlevel.h index 1c688630e..0cc49ff95 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 118 +#define EDITLEVEL 119 /* * Development status possibilities. diff --git a/src/bones.c b/src/bones.c index 7b43db3e2..8675d0f9c 100644 --- a/src/bones.c +++ b/src/bones.c @@ -502,16 +502,39 @@ savebones(int how, time_t when, struct obj *corpse) (void) obj_attach_mid(corpse, mtmp->m_id); } if (mtmp) { + int i; + mtmp->m_lev = (u.ulevel ? u.ulevel : 1); mtmp->mhp = mtmp->mhpmax = u.uhpmax; mtmp->female = flags.female; mtmp->msleeping = 1; - if (!has_former(mtmp)) - newformer(mtmp); - if (has_former(mtmp)) { - FORMER(mtmp)->rank.lev = mtmp->m_lev; - FORMER(mtmp)->rank.mnum = Role_switch; - FORMER(mtmp)->rank.female = flags.female; + + if (!has_ebones(mtmp)) + newebones(mtmp); + if (has_ebones(mtmp)) { + for (i = 0; i <= NUM_ROLES; ++i) { + if (!strcmp(gu.urole.name.m, roles[i].name.m)) { + EBONES(mtmp)->role = i; + break; + } + /* impossible("savebones: bad gu.urole.name.m \"%s\"", + gu.urole.name.m); */ + } + for (i = 0; i <= NUM_RACES; ++i) { + if (!strcmp(gu.urace.noun, races[i].noun)) { + EBONES(mtmp)->race = i; + break; + } + /* impossible("savebones: bad gu.urace.noun \"%s\"", + gu.urace.noun); */ + } + EBONES(mtmp)->oldalign = u.ualign; + EBONES(mtmp)->deathlevel = u.ulevel; + EBONES(mtmp)->luck = u.uluck; /* moreluck not included */ + EBONES(mtmp)->mnum = Role_switch; + EBONES(mtmp)->female = flags.female; + EBONES(mtmp)->demigod = u.uevent.udemigod; + EBONES(mtmp)->crowned = u.uevent.uhand_of_elbereth; } } for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { @@ -783,4 +806,28 @@ fix_ghostly_obj(struct obj *obj) obj->ghostly = 0; } +void +newebones(struct monst *mtmp) +{ + if (!mtmp->mextra) + mtmp->mextra = newmextra(); + if (!EBONES(mtmp)) { + EBONES(mtmp) = (struct ebones *) alloc( + sizeof(struct ebones *)); + (void) memset((genericptr_t) EBONES(mtmp), 0, + sizeof(struct ebones *)); + EBONES(mtmp)->parentmid = mtmp->m_id; + } +} + +/* this is not currently used */ +void +free_ebones(struct monst *mtmp) +{ + if (mtmp->mextra && EBONES(mtmp)) { + free((genericptr_t) EBONES(mtmp)); + EBONES(mtmp) = (struct ebones *) 0; + } +} + /*bones.c*/ diff --git a/src/do_name.c b/src/do_name.c index f690a2984..37876700e 100644 --- a/src/do_name.c +++ b/src/do_name.c @@ -273,7 +273,7 @@ do_mgivenname(void) verbalize("I'm %s, not %s.", shkname(mtmp), buf); } } else if (mtmp->ispriest || mtmp->isminion || mtmp->isshk - || mtmp->data == &mons[PM_GHOST]) { + || mtmp->data == &mons[PM_GHOST] || has_ebones(mtmp)) { if (!alreadynamed(mtmp, monnambuf, buf)) pline("%s will not accept the name %s.", upstart(monnambuf), buf); } else { @@ -956,7 +956,7 @@ x_monnam( #if 0 /* hardfought */ - if (has_former(mtmp) && FORMER(mtmp)->rank.mnum != NON_PM) { + if (has_ebones(mtmp)) { #endif if (mdat == &mons[PM_GHOST]) { Sprintf(eos(buf), "%s ghost", s_suffix(name)); diff --git a/src/end.c b/src/end.c index 4c916024a..8909b4a8a 100644 --- a/src/end.c +++ b/src/end.c @@ -206,7 +206,7 @@ done_in_by(struct monst *mtmp, int how) /* _the_ ghost of Dudley */ #if 0 /* hardfought */ - if (has_former(mtmp) && FORMER(mtmp)->rank.mnum != NON_PM) { + if (has_ebones(mtmp) && EBONES(mtmp)->rank.mnum != NON_PM) { #else if (mptr == &mons[PM_GHOST] && has_mgivenname(mtmp)) { #endif @@ -253,7 +253,7 @@ done_in_by(struct monst *mtmp, int how) realnm, shape); mptr = mtmp->data; /* reset for mimicker case */ #if 0 /* hardfought */ - } else if (has_former(mtmp) && FORMER(mtmp)->rank.mnum != NON_PM) + } else if (has_ebones(mtmp) && EBONES(mtmp)->rank.mnum != NON_PM) Strcpy(buf, m_monnam(mtmp)); #endif } else if (mptr == &mons[PM_GHOST]) { @@ -273,8 +273,11 @@ done_in_by(struct monst *mtmp, int how) Strcat(buf, m_monnam(mtmp)); } else { Strcat(buf, pmname(mptr, Mgender(mtmp))); - if (has_mgivenname(mtmp)) - Sprintf(eos(buf), " called %s", MGIVENNAME(mtmp)); + if (has_mgivenname(mtmp)) { + Sprintf(eos(buf), " %s %s", + has_ebones(mtmp) ? "of" : "called", + MGIVENNAME(mtmp)); + } } Strcpy(svk.killer.name, buf); diff --git a/src/makemon.c b/src/makemon.c index 9e62c168b..a7e52bf47 100644 --- a/src/makemon.c +++ b/src/makemon.c @@ -1070,29 +1070,6 @@ newmextra(void) return mextra; } -void -newformer(struct monst *mtmp) -{ - if (!mtmp->mextra) - mtmp->mextra = newmextra(); - if (!FORMER(mtmp)) { - FORMER(mtmp) = (struct former_incarnation *) alloc( - sizeof(struct former_incarnation *)); - (void) memset((genericptr_t) FORMER(mtmp), 0, - sizeof(struct former_incarnation *)); - FORMER(mtmp)->parentmid = mtmp->m_id; - } -} - -void -free_former(struct monst *mtmp) -{ - if (mtmp->mextra && FORMER(mtmp)) { - free((genericptr_t) FORMER(mtmp)); - FORMER(mtmp) = (struct former_incarnation *) 0; - } -} - staticfn boolean makemon_rnd_goodpos( struct monst *mon, diff --git a/src/mon.c b/src/mon.c index 9a11354f5..33f2bedfa 100644 --- a/src/mon.c +++ b/src/mon.c @@ -2567,11 +2567,11 @@ copy_mextra(struct monst *mtmp2, struct monst *mtmp1) assert(has_edog(mtmp2)); *EDOG(mtmp2) = *EDOG(mtmp1); } - if (FORMER(mtmp1)) { - if (!FORMER(mtmp2)) - newformer(mtmp2); - assert(has_former(mtmp2)); - *FORMER(mtmp2) = *FORMER(mtmp1); + if (EBONES(mtmp1)) { + if (!EBONES(mtmp2)) + newebones(mtmp2); + assert(has_ebones(mtmp2)); + *EBONES(mtmp2) = *EBONES(mtmp1); } if (has_mcorpsenm(mtmp1)) MCORPSENM(mtmp2) = MCORPSENM(mtmp1); @@ -2595,8 +2595,8 @@ dealloc_mextra(struct monst *m) free((genericptr_t) x->emin), x->emin = 0; if (x->edog) free((genericptr_t) x->edog), x->edog = 0; - if (x->former) - free((genericptr_t) x->former), x->former = 0; + if (x->ebones) + free((genericptr_t) x->ebones), x->ebones = 0; x->mcorpsenm = NON_PM; /* no allocation to release */ free((genericptr_t) x); @@ -3644,13 +3644,13 @@ xkilled( #if 0 /* HARDFOUGHT-only at present */ #ifdef LIVELOG - if (has_former(mtmp) && FORMER(mtmp)->rank.mnum != NON_PM) { + if (has_ebones(mtmp)) { livelog_printf(LL_UMONST, "destroyed %s, %s former %s", livelog_mon_nam(mtmp), (mtmp->data == &mons[PM_GHOST]) ? "the" : "and", - rank_of(FORMER(mtmp)->rank.lev, - FORMER(mtmp)->rank.mnum, - FORMER(mtmp)->rank.female)); + rank_of(EBONES(mtmp)->deathlevel, + EBONES(mtmp)->mnum, + EBONES(mtmp)->female)); } #endif /* LIVELOG */ #endif diff --git a/src/restore.c b/src/restore.c index 5ab92311e..c15cce775 100644 --- a/src/restore.c +++ b/src/restore.c @@ -370,14 +370,14 @@ restmon(NHFILE *nhfp, struct monst *mtmp) EDOG(mtmp)->apport = 1; } } - /* former - info about former self, primarily for bones files */ + /* ebones */ if (nhfp->structlevel) Mread(nhfp->fd, &buflen, sizeof buflen); if (buflen > 0) { - newformer(mtmp); + newebones(mtmp); if (nhfp->structlevel) - Mread(nhfp->fd, FORMER(mtmp), - sizeof (struct former_incarnation)); + Mread(nhfp->fd, EBONES(mtmp), + sizeof (struct ebones)); } /* mcorpsenm - obj->corpsenm for mimic posing as corpse or statue (inline int rather than pointer to something) */ diff --git a/src/role.c b/src/role.c index 6d4ce709a..e95d3f121 100644 --- a/src/role.c +++ b/src/role.c @@ -24,6 +24,9 @@ * * God names use a leading underscore to flag goddesses. */ + +/* NUM_ROLES is defined in hack.h */ + const struct Role roles[NUM_ROLES+1] = { { { "Archeologist", 0 }, { { "Digger", 0 }, @@ -573,7 +576,9 @@ const struct Role roles[NUM_ROLES+1] = { }; /* Table of all races */ -const struct Race races[] = { + +/* NUM_RACES is defined in hack.h */ +const struct Race races[NUM_RACES + 1] = { { "human", "human", diff --git a/src/save.c b/src/save.c index e383b52b8..ad5f52773 100644 --- a/src/save.c +++ b/src/save.c @@ -943,12 +943,12 @@ savemon(NHFILE *nhfp, struct monst *mtmp) if (nhfp->structlevel) bwrite(nhfp->fd, (genericptr_t) EDOG(mtmp), buflen); } - buflen = FORMER(mtmp) ? (int) sizeof (struct former_incarnation) : 0; + buflen = EBONES(mtmp) ? (int) sizeof (struct ebones) : 0; if (nhfp->structlevel) bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof (int)); if (buflen > 0) { if (nhfp->structlevel) - bwrite(nhfp->fd, (genericptr_t) FORMER(mtmp), buflen); + bwrite(nhfp->fd, (genericptr_t) EBONES(mtmp), buflen); } /* mcorpsenm is inline int rather than pointer to something, so doesn't need to be preceded by a length field */ diff --git a/src/wizcmds.c b/src/wizcmds.c index a37c469aa..6dd756880 100644 --- a/src/wizcmds.c +++ b/src/wizcmds.c @@ -1246,8 +1246,8 @@ size_monst(struct monst *mtmp, boolean incl_wsegs) sz += (int) sizeof (struct emin); if (EDOG(mtmp)) sz += (int) sizeof (struct edog); - if (FORMER(mtmp)) - sz += (int) sizeof (struct former_incarnation); + if (EBONES(mtmp)) + sz += (int) sizeof (struct ebones); /* mextra->mcorpsenm doesn't point to more memory */ } return sz; From 6c0e755573562a11631413eb311f9338c5ae4ca7 Mon Sep 17 00:00:00 2001 From: nhmall Date: Tue, 4 Feb 2025 15:33:38 -0500 Subject: [PATCH 420/791] follow-up for ebones --- src/end.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/end.c b/src/end.c index 8909b4a8a..befaec963 100644 --- a/src/end.c +++ b/src/end.c @@ -206,7 +206,7 @@ done_in_by(struct monst *mtmp, int how) /* _the_ ghost of Dudley */ #if 0 /* hardfought */ - if (has_ebones(mtmp) && EBONES(mtmp)->rank.mnum != NON_PM) { + if (has_ebones(mtmp)) { #else if (mptr == &mons[PM_GHOST] && has_mgivenname(mtmp)) { #endif @@ -253,7 +253,7 @@ done_in_by(struct monst *mtmp, int how) realnm, shape); mptr = mtmp->data; /* reset for mimicker case */ #if 0 /* hardfought */ - } else if (has_ebones(mtmp) && EBONES(mtmp)->rank.mnum != NON_PM) + } else if (has_ebones(mtmp)) Strcpy(buf, m_monnam(mtmp)); #endif } else if (mptr == &mons[PM_GHOST]) { From 88107193db684a24ea8a427e56033e96dbe746b8 Mon Sep 17 00:00:00 2001 From: nhmall Date: Tue, 4 Feb 2025 15:36:36 -0500 Subject: [PATCH 421/791] another follow-up, in commented-out code --- src/end.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/end.c b/src/end.c index befaec963..90ea4a3ea 100644 --- a/src/end.c +++ b/src/end.c @@ -253,7 +253,7 @@ done_in_by(struct monst *mtmp, int how) realnm, shape); mptr = mtmp->data; /* reset for mimicker case */ #if 0 /* hardfought */ - } else if (has_ebones(mtmp)) + } else if (has_ebones(mtmp)) { Strcpy(buf, m_monnam(mtmp)); #endif } else if (mptr == &mons[PM_GHOST]) { From d611da42ccc8fcbb07ebd09d4ed6dc2c0a467512 Mon Sep 17 00:00:00 2001 From: PatR Date: Wed, 5 Feb 2025 00:01:07 -0800 Subject: [PATCH 422/791] enlightenment for armor's effect on spell casting Report the effect of suit and/or robe on spell casting during attribute enlightenment. Doesn't attempt to include other armor slots. That's complicated and would end up being too verbose. --- src/insight.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/insight.c b/src/insight.c index 0000db937..815f1113d 100644 --- a/src/insight.c +++ b/src/insight.c @@ -1782,6 +1782,23 @@ attributes_enlightenment( enlght_halfdmg(HALF_SPDAM, final); if (Half_gas_damage) enl_msg(You_, "take", "took", " reduced poison gas damage", ""); + if (spellid(0) > NO_SPELL) { /* skip if no spells are known yet */ + /* greatly simplified edition of percent_success(spell.c)--may need + to be suppressed if oversimplification leads to player confusion */ + char cast_adj[QBUFSZ]; + boolean suit = uarm && is_metallic(uarm), + robe = uarmc && uarmc->otyp == ROBE; + + *cast_adj = '\0'; + if (suit) /* omit "wearing" to shorten the text */ + Sprintf(cast_adj, " impaired by metallic armor%s", + robe ? ", mitigated by your robe" : ""); + else if (robe) + Strcpy(cast_adj, " enhanced by wearing a robe"); + + if (*cast_adj) + enl_msg("Your spell casting ", "is", "was", cast_adj, ""); + } /* polymorph and other shape change */ if (Protection_from_shape_changers) you_are("protected from shape changers", From 0d543a8fae41bf8689e94f45d0e395748b227fe6 Mon Sep 17 00:00:00 2001 From: nhmall Date: Wed, 5 Feb 2025 07:57:25 -0500 Subject: [PATCH 423/791] remove a set_uasmon() call from iter_mons() processing Reported by hackemslashem. --- include/decl.h | 1 + src/allmain.c | 6 ++++++ src/decl.c | 1 + src/were.c | 5 +++-- 4 files changed, 11 insertions(+), 2 deletions(-) diff --git a/include/decl.h b/include/decl.h index 6298e0621..4e674d6a2 100644 --- a/include/decl.h +++ b/include/decl.h @@ -1061,6 +1061,7 @@ struct instance_globals_w { /* new */ struct win_settings wsettings; /* wintype.h */ + long were_changes; /* were.c, allmain.c */ boolean havestate; unsigned long magic; /* validate that structure layout is preserved */ diff --git a/src/allmain.c b/src/allmain.c index 0efec2ac9..918da029a 100644 --- a/src/allmain.c +++ b/src/allmain.c @@ -201,6 +201,7 @@ moveloop_core(void) struct monst *mtmp; /* set up for a new turn */ + gw.were_changes = 0L; mcalcdistress(); /* adjust monsters' trap, blind, etc */ /* reallocate movement rations to monsters; don't need @@ -324,6 +325,11 @@ moveloop_core(void) (void) dosearch0(1); if (Warning) warnreveal(); + if (gw.were_changes) { + /* update innate intrinsics (mainly Drain_resistance) */ + set_uasmon(); + gw.were_changes = 0L; + } mkot_trap_warn(); dosounds(); do_storms(); diff --git a/src/decl.c b/src/decl.c index fe16b2b44..d06dcf9b6 100644 --- a/src/decl.c +++ b/src/decl.c @@ -863,6 +863,7 @@ static const struct instance_globals_w g_init_w = { UNDEFINED_PTR, /* wportal */ /* new */ { wdmode_traditional, NO_COLOR }, /* wsettings */ + 0L, /* were.c, allmain.c */ TRUE, /* havestate*/ IVMAGIC /* w_magic to validate that structure layout has been preserved */ }; diff --git a/src/were.c b/src/were.c index 9baa4155e..551ad46e6 100644 --- a/src/were.c +++ b/src/were.c @@ -16,6 +16,7 @@ were_change(struct monst *mon) && !rn2(night() ? (flags.moonphase == FULL_MOON ? 3 : 30) : (flags.moonphase == FULL_MOON ? 10 : 50))) { new_were(mon); /* change into animal form */ + gw.were_changes++; if (!Deaf && !canseemon(mon)) { const char *howler; @@ -39,9 +40,8 @@ were_change(struct monst *mon) } } else if (!rn2(30) || Protection_from_shape_changers) { new_were(mon); /* change back into human form */ + gw.were_changes++; } - /* update innate intrinsics (mainly Drain_resistance) */ - set_uasmon(); /* new_were() doesn't do this */ } int @@ -203,6 +203,7 @@ you_were(void) return; } (void) polymon(u.ulycn); + gw.were_changes++; } void From a065ced14a018b58f58c7d1884ed4fe7f58b8f36 Mon Sep 17 00:00:00 2001 From: nhmall Date: Wed, 5 Feb 2025 08:13:35 -0500 Subject: [PATCH 424/791] follow-up for gw.were_changes --- src/allmain.c | 1 - src/polyself.c | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/allmain.c b/src/allmain.c index 918da029a..87235a252 100644 --- a/src/allmain.c +++ b/src/allmain.c @@ -328,7 +328,6 @@ moveloop_core(void) if (gw.were_changes) { /* update innate intrinsics (mainly Drain_resistance) */ set_uasmon(); - gw.were_changes = 0L; } mkot_trap_warn(); dosounds(); diff --git a/src/polyself.c b/src/polyself.c index 623bf1976..625d00720 100644 --- a/src/polyself.c +++ b/src/polyself.c @@ -120,6 +120,8 @@ set_uasmon(void) if (VIA_WINDOWPORT()) status_initialize(REASSESS_ONLY); #endif + /* we can reset this now, having just done what it is meant to trigger */ + gw.were_changes = 0L; } /* Levitation overrides Flying; set or clear BFlying|I_SPECIAL */ From c9729bf838ab24ffc283a12ec553eafb7096e1eb Mon Sep 17 00:00:00 2001 From: nhmall Date: Wed, 5 Feb 2025 08:18:29 -0500 Subject: [PATCH 425/791] one more follow-up --- src/were.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/were.c b/src/were.c index 551ad46e6..b38bf0ed0 100644 --- a/src/were.c +++ b/src/were.c @@ -202,8 +202,8 @@ you_were(void) if (!paranoid_query(ParanoidWerechange, qbuf)) return; } - (void) polymon(u.ulycn); gw.were_changes++; + (void) polymon(u.ulycn); } void From c1516666b3a3c0f16bebddf2a22d3d8bde2d4775 Mon Sep 17 00:00:00 2001 From: nhmall Date: Wed, 5 Feb 2025 17:26:15 -0500 Subject: [PATCH 426/791] ebones follow-up fix #1 --- src/bones.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bones.c b/src/bones.c index 8675d0f9c..e0a809de9 100644 --- a/src/bones.c +++ b/src/bones.c @@ -813,9 +813,9 @@ newebones(struct monst *mtmp) mtmp->mextra = newmextra(); if (!EBONES(mtmp)) { EBONES(mtmp) = (struct ebones *) alloc( - sizeof(struct ebones *)); + sizeof (struct ebones)); (void) memset((genericptr_t) EBONES(mtmp), 0, - sizeof(struct ebones *)); + sizeof (struct ebones)); EBONES(mtmp)->parentmid = mtmp->m_id; } } From fe4cb7a6262da8286d61027e269117541ced8a2a Mon Sep 17 00:00:00 2001 From: nhmall Date: Wed, 5 Feb 2025 20:03:06 -0500 Subject: [PATCH 427/791] make rank() static again --- include/extern.h | 1 - src/botl.c | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/extern.h b/include/extern.h index 7ab07ada2..9960e47f4 100644 --- a/include/extern.h +++ b/include/extern.h @@ -259,7 +259,6 @@ extern char *do_statusline2(void); extern void bot(void); extern void timebot(void); extern int xlev_to_rank(int); -extern const char *rank(void); extern int rank_to_xlev(int); extern const char *rank_of(int, short, boolean); extern int title_to_mon(const char *, int *, int *); diff --git a/src/botl.c b/src/botl.c index 406796782..51f15f19d 100644 --- a/src/botl.c +++ b/src/botl.c @@ -16,6 +16,7 @@ const char *const enc_stat[] = { "Strained", "Overtaxed", "Overloaded" }; +staticfn const char *rank(void); staticfn void bot_via_windowport(void); staticfn void stat_update_time(void); staticfn char *get_strength_str(void); @@ -360,7 +361,7 @@ rank_of(int lev, short monnum, boolean female) return "Player"; } -const char * +staticfn const char * rank(void) { return rank_of(u.ulevel, Role_switch, flags.female); From f228a790b038f862dc4b8d2ef3fa0ad572369c6f Mon Sep 17 00:00:00 2001 From: copperwater Date: Thu, 6 Feb 2025 20:09:18 -0500 Subject: [PATCH 428/791] Clean up hardcoded material constant in water vault themerm This implements a TODO to return an object's material as text rather than as an int when a Lua file requests all the details about an object's objclass. That is as simple as looking it up in materialnm[]. With that done, it's possible to clean up the one use where a Lua file looks up the material of an object it generated, in the "water-surrounded vault" themed room, previously an inflexible 19 but which can now be compared directly to "glass". It also enables shortening the comments that follow since the branches of the if statement are now obvious. --- dat/themerms.lua | 6 +++--- src/nhlobj.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dat/themerms.lua b/dat/themerms.lua index 75145eefb..454059125 100644 --- a/dat/themerms.lua +++ b/dat/themerms.lua @@ -686,12 +686,12 @@ xx|.....|xx local itm = obj.new(escape_items[math.random(#escape_items)]); local itmcls = itm:class() local box - if itmcls[ "material" ] == 19 then -- GLASS==19 - -- item is made of glass so explicitly force chest to be unlocked + if itmcls[ "material" ] == "glass" then + -- explicitly force chest to be unlocked box = des.object({ id = "chest", coord = chest_spots[1], olocked = "no" }); else - -- item isn't made of glass; accept random locked/unlocked state + -- accept random locked/unlocked state box = des.object({ id = "chest", coord = chest_spots[1] }); end; box:addcontent(itm); diff --git a/src/nhlobj.c b/src/nhlobj.c index 6e97c3b87..e06fc4b59 100644 --- a/src/nhlobj.c +++ b/src/nhlobj.c @@ -219,7 +219,7 @@ l_obj_objects_to_table(lua_State *L) /* TODO: oc_bimanual, oc_bulky */ nhl_add_table_entry_int(L, "tough", o->oc_tough); nhl_add_table_entry_int(L, "dir", o->oc_dir); /* TODO: convert to text */ - nhl_add_table_entry_int(L, "material", o->oc_material); /* TODO: convert to text */ + nhl_add_table_entry_str(L, "material", materialnm[o->oc_material]); /* TODO: oc_subtyp, oc_skill, oc_armcat */ nhl_add_table_entry_int(L, "oprop", o->oc_oprop); nhl_add_table_entry_char(L, "class", From 6c9d4df4a6e874c888fe4b734fac2b0b4c55dea6 Mon Sep 17 00:00:00 2001 From: copperwater Date: Thu, 6 Feb 2025 20:44:55 -0500 Subject: [PATCH 429/791] Fix: gremlin cry of pain could be heard while deaf Main problem was there was no condition applied to this message, so anyone would hear it even if they were deaf. Even assuming a cry of pain is something that could be seen, the message was still printed when the hero couldn't see the gremlin. This puts both a deafness check and a range check on that cry (if a gremlin somehow takes light damage on the other side of the map behind many walls, it doesn't make much sense to hear its cry), and provides an alternate message if the hero can't hear it, but can see it. The alternate message does rely on the hero being able to /see/, not just spot, the gremlin and the light it's shying away from -- if you can only sense it, there is no special message. --- src/uhitm.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/uhitm.c b/src/uhitm.c index d40f712c0..e68f1a60f 100644 --- a/src/uhitm.c +++ b/src/uhitm.c @@ -6264,8 +6264,14 @@ flash_hits_mon( void light_hits_gremlin(struct monst *mon, int dmg) { - pline_mon(mon, "%s %s!", Monnam(mon), - (dmg > mon->mhp / 2) ? "wails in agony" : "cries out in pain"); + if (!Deaf && mdistu(mon) <= 90) { + /* cry of pain can be heard somewhat farther than the waking radius */ + pline_mon(mon, "%s %s!", Monnam(mon), + (dmg > mon->mhp / 2) ? "wails in agony" + : "cries out in pain"); + } else if (canseemon(mon)) { + pline_mon(mon, "%s recoils from the light!", Monnam(mon)); + } mon->mhp -= dmg; wake_nearto(mon->mx, mon->my, 30); if (DEADMONSTER(mon)) { From 10e5d2121c5eb21d696e9f3f0c726a4136aaa439 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 9 Feb 2025 10:52:21 -0500 Subject: [PATCH 430/791] fix typo reported in b9ff8068 from Sept 2024 --- src/hack.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hack.c b/src/hack.c index 1eaf39caf..f28877e47 100644 --- a/src/hack.c +++ b/src/hack.c @@ -4107,7 +4107,7 @@ saving_grace(int dmg) to phrase this though; classifying it as a spoiler will hide it from #chronicle during play but show it to livelog observers */ livelog_printf(LL_CONDUCT | LL_SPOILER, "%s (%d damage, %d/%d HP)", - "survived one-shot death via saving-grave", + "survived one-shot death via saving-grace", dmg, u.uhp, u.uhpmax); /* note: this could reduce dmg to 0 if u.uhpmax==1 */ From d1f0cfce929988939a67ebd403e52bd21501c0c7 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Mon, 10 Feb 2025 17:47:57 +0200 Subject: [PATCH 431/791] No hangup save while in tutorial Tutorial code doesn't handle saving and reloading the game gracefully, and manually saving has been disabled in there already. Also disable automatic saving in the tutorial when the terminal goes away. --- src/cmd.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/cmd.c b/src/cmd.c index c038e6765..1bcb1d4fd 100644 --- a/src/cmd.c +++ b/src/cmd.c @@ -4924,6 +4924,9 @@ end_of_input(void) program_state.something_worth_saving = 0; /* don't save */ #endif + if (In_tutorial(&u.uz)) + program_state.something_worth_saving = 0; /* don't save in tutorial */ + #ifndef SAFERHANGUP if (!program_state.done_hup++) #endif From 1317c850b3c2f9ee050cc9adb315d3e58a891c57 Mon Sep 17 00:00:00 2001 From: nhmall Date: Tue, 11 Feb 2025 08:02:10 -0500 Subject: [PATCH 432/791] fix output of --dumpenums --- src/allmain.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/allmain.c b/src/allmain.c index 87235a252..160320b79 100644 --- a/src/allmain.c +++ b/src/allmain.c @@ -1139,6 +1139,7 @@ timet_delta(time_t etim, time_t stim) /* end and start times */ /* monsdump[] and objdump[] are also used in utf8map.c */ #define DUMP_ENUMS +#define UNPREFIXED_COUNT (5) struct enum_dump monsdump[] = { #include "monsters.h" { NUMMONS, "NUMMONS" }, @@ -1277,7 +1278,7 @@ dump_enums(void) for (i = 0; i < NUM_ENUM_DUMPS; ++ i) { raw_printf("enum %s = {", titles[i]); for (j = 0; j < szd[i]; ++j) { - int unprefixed_count = (i == monsters_enum) ? 4 : 1; + int unprefixed_count = (i == monsters_enum) ? UNPREFIXED_COUNT : 1; nmprefix = (j >= szd[i] - unprefixed_count) ? "" : pfx[i]; /* "" or "PM_" */ nmwidth = 27 - (int) strlen(nmprefix); /* 27 or 24 */ @@ -1299,6 +1300,7 @@ dump_enums(void) } raw_print(""); } +#undef UNPREFIXED_COUNT #endif /* NODUMPENUMS */ void From 563340093ccd96c451153680055c909e9e3d91d4 Mon Sep 17 00:00:00 2001 From: nhmall Date: Tue, 11 Feb 2025 08:50:30 -0500 Subject: [PATCH 433/791] stop keeping 5 arrays in sync in dumpenums code --- src/allmain.c | 52 +++++++++++++++++++++++++-------------------------- 1 file changed, 25 insertions(+), 27 deletions(-) diff --git a/src/allmain.c b/src/allmain.c index 160320b79..aad9ab1f0 100644 --- a/src/allmain.c +++ b/src/allmain.c @@ -1220,12 +1220,6 @@ dump_enums(void) arti_enum, NUM_ENUM_DUMPS }; - static const char *const titles[NUM_ENUM_DUMPS] = { - "monnums", "objects_nums" , "misc_object_nums", - "cmap_symbols", "mon_syms", "mon_defchars", - "objclass_defchars", "objclass_classes", - "objclass_syms", "artifacts_nums", - }; #define dump_om(om) { om, #om } static const struct enum_dump omdump[] = { @@ -1246,6 +1240,7 @@ dump_enums(void) dump_om(MAX_GLYPH), }; #undef dump_om + static const struct enum_dump *const ed[NUM_ENUM_DUMPS] = { monsdump, objdump, omdump, defsym_cmap_dump, defsym_mon_syms_dump, @@ -1255,34 +1250,37 @@ dump_enums(void) objclass_syms_dump, arti_enum_dump, }; - static const char *const pfx[NUM_ENUM_DUMPS] = { - "PM_", "", "", "", "", "", "", "", "", "" - }; - /* 0 = dump numerically only, 1 = add 'char' comment */ - static const int dumpflgs[NUM_ENUM_DUMPS] = { - 0, 0, 0, 0, 0, 1, 1, 0, 0, 0 - }; - static int szd[NUM_ENUM_DUMPS] = { SIZE(monsdump), SIZE(objdump), - SIZE(omdump), SIZE(defsym_cmap_dump), - SIZE(defsym_mon_syms_dump), - SIZE(defsym_mon_defchars_dump), - SIZE(objclass_defchars_dump), - SIZE(objclass_classes_dump), - SIZE(objclass_syms_dump), - SIZE(arti_enum_dump), + + static const struct de_params { + const char *const title; + const char *const pfx; + int unprefixed_count; + int dumpflgs; + int szd; + } edmp[NUM_ENUM_DUMPS] = { + { "monnums", "PM_", UNPREFIXED_COUNT, 0, SIZE(monsdump) }, + { "objects_nums", "", 1, 0, SIZE(objdump) }, + { "misc_object_nums", "", 1, 0, SIZE(omdump) }, + { "cmap_symbols", "", 1, 0, SIZE(defsym_cmap_dump) }, + { "mon_syms", "", 1, 0, SIZE(defsym_mon_syms_dump) }, + { "mon_defchars", "", 1, 1, SIZE(defsym_mon_defchars_dump) }, + { "objclass_defchars", "", 1, 1, SIZE(objclass_defchars_dump) }, + { "objclass_classes", "", 1, 0, SIZE(objclass_classes_dump) }, + { "objclass_syms", "", 1, 0, SIZE(objclass_syms_dump) }, + { "artifacts_nums", "", 1, 0, SIZE(arti_enum_dump) }, }; + const char *nmprefix; int i, j, nmwidth; char comment[BUFSZ]; for (i = 0; i < NUM_ENUM_DUMPS; ++ i) { - raw_printf("enum %s = {", titles[i]); - for (j = 0; j < szd[i]; ++j) { - int unprefixed_count = (i == monsters_enum) ? UNPREFIXED_COUNT : 1; - nmprefix = (j >= szd[i] - unprefixed_count) - ? "" : pfx[i]; /* "" or "PM_" */ + raw_printf("enum %s = {", edmp[i].title); + for (j = 0; j < edmp[i].szd; ++j) { + nmprefix = (j >= edmp[i].szd - edmp[i].unprefixed_count) + ? "" : edmp[i].pfx; /* "" or "PM_" */ nmwidth = 27 - (int) strlen(nmprefix); /* 27 or 24 */ - if (dumpflgs[i] > 0) { + if (edmp[i].dumpflgs > 0) { Snprintf(comment, sizeof comment, " /* '%c' */", (ed[i][j].val >= 32 && ed[i][j].val <= 126) From 907c0fbece1773b7d553898f0f1d81a96603edc9 Mon Sep 17 00:00:00 2001 From: nhmall Date: Tue, 11 Feb 2025 09:29:32 -0500 Subject: [PATCH 434/791] follow-up: put back a comment that got removed --- src/allmain.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/allmain.c b/src/allmain.c index aad9ab1f0..9ffb6dacc 100644 --- a/src/allmain.c +++ b/src/allmain.c @@ -1255,12 +1255,12 @@ dump_enums(void) const char *const title; const char *const pfx; int unprefixed_count; - int dumpflgs; + int dumpflgs; /* 0 = dump numerically only, 1 = add 'char' comment */ int szd; } edmp[NUM_ENUM_DUMPS] = { { "monnums", "PM_", UNPREFIXED_COUNT, 0, SIZE(monsdump) }, { "objects_nums", "", 1, 0, SIZE(objdump) }, - { "misc_object_nums", "", 1, 0, SIZE(omdump) }, + { "misc_object_nums", "", 1, 0, SIZE(omdump) }, { "cmap_symbols", "", 1, 0, SIZE(defsym_cmap_dump) }, { "mon_syms", "", 1, 0, SIZE(defsym_mon_syms_dump) }, { "mon_defchars", "", 1, 1, SIZE(defsym_mon_defchars_dump) }, From f8773f65db113d88e011189ba0892db6a8489989 Mon Sep 17 00:00:00 2001 From: nhmall Date: Tue, 11 Feb 2025 19:50:08 -0500 Subject: [PATCH 435/791] update tested versions of Visual Studio 2025-02-11 --- sys/windows/Makefile.nmake | 4 ++-- sys/windows/vs/uudecode/uudecode.vcxproj | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sys/windows/Makefile.nmake b/sys/windows/Makefile.nmake index 4c11ff77f..b3a1c4bb6 100644 --- a/sys/windows/Makefile.nmake +++ b/sys/windows/Makefile.nmake @@ -9,7 +9,7 @@ # # Visual Studio Compilers Tested: # - Microsoft Visual Studio 2019 Community Edition v 16.11.42 -# - Microsoft Visual Studio 2022 Community Edition v 17.12.4 +# - Microsoft Visual Studio 2022 Community Edition v 17.13.0 # #============================================================================== # This is used for building two distinct executables of NetHack: @@ -1177,7 +1177,7 @@ rc=Rc.exe # # Recently tested versions: TESTEDVS2019 = 14.29.30157.0 -TESTEDVS2022 = 14.42.34436.0 +TESTEDVS2022 = 14.43.34808.0 VS2019CUR = $(TESTEDVS2019:.=) VS2022CUR = $(TESTEDVS2022:.=) diff --git a/sys/windows/vs/uudecode/uudecode.vcxproj b/sys/windows/vs/uudecode/uudecode.vcxproj index 5b85f9979..0975cacdf 100644 --- a/sys/windows/vs/uudecode/uudecode.vcxproj +++ b/sys/windows/vs/uudecode/uudecode.vcxproj @@ -26,7 +26,7 @@ - $(IncDir);$(SysShareDir); + $(IncDir);$(SysShareDir);$(WinWin32Dir) @@ -44,4 +44,4 @@ - + \ No newline at end of file From a68bc3b3fbe3da5998971d2fb384f08c137337c0 Mon Sep 17 00:00:00 2001 From: nhmall Date: Wed, 12 Feb 2025 23:26:03 -0500 Subject: [PATCH 436/791] fix tamed pet issue #1379 fixes #1379 --- include/extern.h | 2 +- src/dog.c | 38 +++++++++++++++++++++----------------- src/mhitu.c | 2 +- src/read.c | 2 +- 4 files changed, 24 insertions(+), 20 deletions(-) diff --git a/include/extern.h b/include/extern.h index 9960e47f4..b39db3219 100644 --- a/include/extern.h +++ b/include/extern.h @@ -743,7 +743,7 @@ extern int count_worn_armor(void); extern void newedog(struct monst *) NONNULLARG1; extern void free_edog(struct monst *) NONNULLARG1; -extern void initedog(struct monst *) NONNULLARG1; +extern void initedog(struct monst *, boolean) NONNULLARG1; extern struct monst *make_familiar(struct obj *, coordxy, coordxy, boolean); extern struct monst *makedog(void); extern void update_mlstmv(void); diff --git a/src/dog.c b/src/dog.c index 7c1fa5dd0..570b73c2a 100644 --- a/src/dog.c +++ b/src/dog.c @@ -42,25 +42,27 @@ free_edog(struct monst *mtmp) } void -initedog(struct monst *mtmp) +initedog(struct monst *mtmp, boolean everything) { mtmp->mtame = is_domestic(mtmp->data) ? 10 : 5; mtmp->mpeaceful = 1; mtmp->mavenge = 0; set_malign(mtmp); /* recalc alignment now that it's tamed */ - mtmp->mleashed = 0; - mtmp->meating = 0; - EDOG(mtmp)->droptime = 0; - EDOG(mtmp)->dropdist = 10000; - EDOG(mtmp)->apport = ACURR(A_CHA); - EDOG(mtmp)->whistletime = 0; - EDOG(mtmp)->hungrytime = 1000 + svm.moves; - EDOG(mtmp)->ogoal.x = -1; /* force error if used before set */ - EDOG(mtmp)->ogoal.y = -1; - EDOG(mtmp)->abuse = 0; - EDOG(mtmp)->revivals = 0; - EDOG(mtmp)->mhpmax_penalty = 0; - EDOG(mtmp)->killed_by_u = 0; + if (everything) { + mtmp->mleashed = 0; + mtmp->meating = 0; + EDOG(mtmp)->droptime = 0; + EDOG(mtmp)->dropdist = 10000; + EDOG(mtmp)->apport = ACURR(A_CHA); + EDOG(mtmp)->whistletime = 0; + EDOG(mtmp)->hungrytime = 1000 + svm.moves; + EDOG(mtmp)->ogoal.x = -1; /* force error if used before set */ + EDOG(mtmp)->ogoal.y = -1; + EDOG(mtmp)->abuse = 0; + EDOG(mtmp)->revivals = 0; + EDOG(mtmp)->mhpmax_penalty = 0; + EDOG(mtmp)->killed_by_u = 0; + } u.uconduct.pets++; } @@ -155,7 +157,7 @@ make_familiar(struct obj *otmp, coordxy x, coordxy y, boolean quietly) if (is_pool(mtmp->mx, mtmp->my) && minliquid(mtmp)) return (struct monst *) 0; - initedog(mtmp); + initedog(mtmp, TRUE); mtmp->msleeping = 0; if (otmp) { /* figurine; resulting monster might not become a pet */ chance = rn2(10); /* 0==tame, 1==peaceful, 2==hostile */ @@ -244,7 +246,7 @@ makedog(void) if (!gp.petname_used++ && *petname) mtmp = christen_monst(mtmp, petname); - initedog(mtmp); + initedog(mtmp, TRUE); return mtmp; } @@ -1214,7 +1216,9 @@ tamedog( /* add the pet extension */ if (!has_edog(mtmp)) { newedog(mtmp); - initedog(mtmp); + initedog(mtmp, TRUE); + } else { + initedog(mtmp, FALSE); } if (obj) { /* thrown food */ diff --git a/src/mhitu.c b/src/mhitu.c index 31289282b..904321a51 100644 --- a/src/mhitu.c +++ b/src/mhitu.c @@ -2572,7 +2572,7 @@ cloneu(void) return NULL; mon->mcloned = 1; mon = christen_monst(mon, svp.plname); - initedog(mon); + initedog(mon, TRUE); mon->m_lev = gy.youmonst.data->mlevel; mon->mhpmax = u.mhmax; mon->mhp = u.mh / 2; diff --git a/src/read.c b/src/read.c index b8cbdc881..4344f319a 100644 --- a/src/read.c +++ b/src/read.c @@ -1680,7 +1680,7 @@ seffect_light(struct obj **sobjp) mon = makemon(&mons[pm], u.ux, u.uy, MM_EDOG | NO_MINVENT | MM_NOMSG); if (mon) { - initedog(mon); + initedog(mon, TRUE); mon->msleeping = 0; mon->mcan = TRUE; if (canspotmon(mon)) From e26102f66d1eeb076702b7aa834fe7e01b3edf73 Mon Sep 17 00:00:00 2001 From: nhmall Date: Thu, 13 Feb 2025 00:18:39 -0500 Subject: [PATCH 437/791] leashed food ration fix Noticed while testing an earlier fix - after your pet consumes a large mimic corpse don't have it remain leashed once it begins to mimic something that isn't leashable --- src/dogmove.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/dogmove.c b/src/dogmove.c index fb214c54e..50f40f135 100644 --- a/src/dogmove.c +++ b/src/dogmove.c @@ -21,6 +21,7 @@ staticfn struct monst *best_target(struct monst *, boolean); staticfn long score_targ(struct monst *, struct monst *); staticfn boolean can_reach_location(struct monst *, coordxy, coordxy, coordxy, coordxy) NONNULLARG1; +staticfn boolean mnum_leashable(int); /* pick a carried item for pet to drop */ struct obj * @@ -1449,10 +1450,23 @@ finish_meating(struct monst *mtmp) } } +/* + * variation of leashable() that takes a PM_ index */ +staticfn boolean +mnum_leashable(int mnum) +{ + return ((mnum >= LOW_PM && mnum <= HIGH_PM) + && mnum != PM_LONG_WORM && !unsolid(&mons[mnum]) + && (!nolimbs(&mons[mnum]) || has_head(&mons[mnum]))) + ? TRUE + : FALSE; +} + void quickmimic(struct monst *mtmp) { int idx = 0, trycnt = 5, spotted, seeloc; + boolean was_leashed = mtmp->mleashed; char buf[BUFSZ]; if (Protection_from_shape_changers || !mtmp->meating) @@ -1502,6 +1516,12 @@ quickmimic(struct monst *mtmp) : something; newsym(mtmp->mx, mtmp->my); + if (was_leashed + && (M_AP_TYPE(mtmp) != M_AP_MONSTER + || !mnum_leashable(mtmp->mappearance))) { + Your("leash goes slack."); + m_unleash(mtmp, FALSE); + } if (glyph_at(mtmp->mx, mtmp->my) != prev_glyph) You("%s %s %s where %s was!", seeloc ? "see" : "sense that", From 027bf78f28a117046c4fd3bfa2987c398edb148b Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Thu, 13 Feb 2025 17:09:22 +0200 Subject: [PATCH 438/791] Sort monsters for mkclass An assumption of monster generating code is that monsters within a class appear in increasing order of difficulty. This wasn't the case with some monsters, but swapping the monsters around is rather intrusive, and doesn't really lend to changing monster difficulties when needed. As a result, for example ghouls would not randomly generate when they should have at certain level difficulties (where a ghoul is weak enough to generate but an ettin zombie would be too strong). Keep a separate array of monster indexes sorted correctly, generate it when required by mkclass() Description of this bug via copperwater --- src/makemon.c | 97 +++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 86 insertions(+), 11 deletions(-) diff --git a/src/makemon.c b/src/makemon.c index a7e52bf47..76e52a85e 100644 --- a/src/makemon.c +++ b/src/makemon.c @@ -16,6 +16,9 @@ staticfn boolean uncommon(int); staticfn int align_shift(struct permonst *); staticfn int temperature_shift(struct permonst *); staticfn boolean mk_gen_ok(int, unsigned, unsigned); +staticfn int QSORTCALLBACK cmp_init_mongen_order(const void *, const void *); +staticfn void check_mongen_order(void); +staticfn void init_mongen_order(void); staticfn boolean wrong_elem_type(struct permonst *); staticfn void m_initgrp(struct monst *, coordxy, coordxy, int, mmflags_nht); staticfn void m_initthrow(struct monst *, int, int); @@ -1742,6 +1745,71 @@ mk_gen_ok(int mndx, unsigned mvflagsmask, unsigned genomask) return TRUE; } +/* monsters in order by mlet & difficulty for mkclass() */ +static int mongen_order[NUMMONS]; +static boolean mongen_order_init = FALSE; + +staticfn int QSORTCALLBACK +cmp_init_mongen_order(const void *p1, const void *p2) +{ + const int *pi1 = p1; + const int *pi2 = p2; + int i1 = *pi1, i2 = *pi2; + + if (((mons[i1].geno & (G_NOGEN|G_UNIQ)) != 0) + || ((mons[i2].geno & (G_NOGEN|G_UNIQ)) != 0)) + return 0; + if (mons[i1].mlet != mons[i2].mlet) + return 0; + return (int)(mons[i1].difficulty - mons[i2].difficulty); +} + +/* check that monsters are in correct difficulty order for mkclass() */ +staticfn void +check_mongen_order(void) +{ + int i, diff = 0; + char mlet = '\0'; + for (i = LOW_PM; i < SPECIAL_PM; i++) { + if (i != mongen_order[i]) { + debugpline2("changed:%s=>%s", mons[i].pmnames[NEUTRAL], mons[mongen_order[i]].pmnames[NEUTRAL]); + } + + if (mlet == mons[mongen_order[i]].mlet) { + if (mons[mongen_order[i]].difficulty < diff) + debugpline1("%s", mons[mongen_order[i]].pmnames[NEUTRAL]); + diff = mons[mongen_order[i]].difficulty; + } + if (!mlet || mlet != mons[mongen_order[i]].mlet) { + mlet = mons[mongen_order[i]].mlet; + diff = 0; + } + } +} + +/* initialize monster order for mkclass */ +staticfn void +init_mongen_order(void) +{ + int i; + + if (mongen_order_init) + return; + + mongen_order_init = TRUE; + for (i = LOW_PM; i <= SPECIAL_PM; i++) + mongen_order[i] = i; + +#if (NH_DEVEL_STATUS != NH_STATUS_RELEASED) + check_mongen_order(); +#endif + qsort((genericptr_t) mongen_order, NUMMONS, sizeof(int), cmp_init_mongen_order); +#if (NH_DEVEL_STATUS != NH_STATUS_RELEASED) + check_mongen_order(); +#endif +} + + /* Make one of the multiple types of a given monster class. The second parameter specifies a special casing bit mask to allow the normal genesis masks to be deactivated. @@ -1752,6 +1820,8 @@ mkclass(char class, int spc) return mkclass_aligned(class, spc, A_NONE); } +#define MONSi(i) (mongen_order[i]) + /* mkclass() with alignment restrictions; used by ndemon() */ struct permonst * mkclass_aligned(char class, int spc, /* special mons[].geno handling */ @@ -1768,6 +1838,9 @@ mkclass_aligned(char class, int spc, /* special mons[].geno handling */ impossible("mkclass called with bad class!"); return (struct permonst *) 0; } + + init_mongen_order(); + /* Assumption #1: monsters of a given class are contiguous in the * mons[] array. Player monsters and quest denizens * are an exception; mkclass() won't pick them. @@ -1775,7 +1848,7 @@ mkclass_aligned(char class, int spc, /* special mons[].geno handling */ * regular monsters from the exceptions. */ for (first = LOW_PM; first < SPECIAL_PM; first++) - if (mons[first].mlet == class) + if (mons[MONSi(first)].mlet == class) break; if (first == SPECIAL_PM) { impossible("mkclass found no class %d monsters", class); @@ -1792,9 +1865,9 @@ mkclass_aligned(char class, int spc, /* special mons[].geno handling */ /* Assumption #2: monsters of a given class are presented in ascending * order of strength. */ - for (last = first; last < SPECIAL_PM && mons[last].mlet == class; + for (last = first; last < SPECIAL_PM && mons[MONSi(last)].mlet == class; last++) { - if (atyp != A_NONE && sgn(mons[last].maligntyp) != sgn(atyp)) + if (atyp != A_NONE && sgn(mons[MONSi(last)].maligntyp) != sgn(atyp)) continue; /* traditionally mkclass() ignored hell-only and never-in-hell; now we usually honor those but not all the time, mostly so that @@ -1806,17 +1879,17 @@ mkclass_aligned(char class, int spc, /* special mons[].geno handling */ gn_mask |= (gehennom ? G_NOHELL : G_HELL); gn_mask &= ~spc; - if (mk_gen_ok(last, mv_mask, gn_mask)) { + if (mk_gen_ok(MONSi(last), mv_mask, gn_mask)) { /* consider it; don't reject a toostrong() monster if we don't have anything yet (num==0) or if it is the same (or lower) difficulty as preceding candidate (non-zero 'num' implies last > first so mons[last-1] is safe); sometimes accept it even if high difficulty */ - if (num && montoostrong(last, maxmlev) - && mons[last].difficulty > mons[last - 1].difficulty + if (num && montoostrong(MONSi(last), maxmlev) + && mons[MONSi(last)].difficulty > mons[MONSi(last - 1)].difficulty && rn2(2)) break; - if ((k = (mons[last].geno & G_FREQ)) > 0) { + if ((k = (mons[MONSi(last)].geno & G_FREQ)) > 0) { /* skew towards lower value monsters at lower exp. levels (this used to be done in the next loop, but that didn't work well when multiple species had the same level and @@ -1826,8 +1899,8 @@ mkclass_aligned(char class, int spc, /* special mons[].geno handling */ being picked nearly twice as often as succubus); we need the '+1' in case the entire set is too high level (really low svl.level hero) */ - nums[last] = k + 1 - (adj_lev(&mons[last]) > (u.ulevel * 2)); - num += nums[last]; + nums[MONSi(last)] = k + 1 - (adj_lev(&mons[MONSi(last)]) > (u.ulevel * 2)); + num += nums[MONSi(last)]; } } } @@ -1837,11 +1910,13 @@ mkclass_aligned(char class, int spc, /* special mons[].geno handling */ /* the hard work has already been done; 'num' should hit 0 before first reaches last (which is actually one past our last candidate) */ for (num = rnd(num); first < last; first++) - if ((num -= nums[first]) <= 0) + if ((num -= nums[MONSi(first)]) <= 0) break; - return nums[first] ? &mons[first] : (struct permonst *) 0; + return nums[MONSi(first)] ? &mons[MONSi(first)] : (struct permonst *) 0; } +#undef MONSi + /* like mkclass(), but excludes difficulty considerations; used when player with polycontrol picks a class instead of a specific type; From f1be2eaffa59e7fb1ce8c8dfd063ecb53e21dffc Mon Sep 17 00:00:00 2001 From: nhmall Date: Fri, 14 Feb 2025 09:38:29 -0500 Subject: [PATCH 439/791] add --dumpmongen to view mongen_order[] array --- include/extern.h | 1 + include/hack.h | 1 + src/allmain.c | 4 ++++ src/makemon.c | 37 +++++++++++++++++++++++++++++++++++-- sys/unix/unixmain.c | 3 +++ sys/windows/windmain.c | 3 +++ 6 files changed, 47 insertions(+), 2 deletions(-) diff --git a/include/extern.h b/include/extern.h index b39db3219..c5b0b0af9 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1444,6 +1444,7 @@ extern void mkmonmoney(struct monst *, long) NONNULLARG1; extern int bagotricks(struct obj *, boolean, int *); extern boolean propagate(int, boolean, boolean); extern void summon_furies(int); +extern void dump_mongen(void); /* ### mcastu.c ### */ diff --git a/include/hack.h b/include/hack.h index 3fb02f687..13e27653f 100644 --- a/include/hack.h +++ b/include/hack.h @@ -441,6 +441,7 @@ enum earlyarg { , ARG_DUMPENUMS #endif , ARG_DUMPGLYPHIDS + , ARG_DUMPMONGEN #ifdef WIN32 , ARG_WINDOWS #endif diff --git a/src/allmain.c b/src/allmain.c index 9ffb6dacc..f65ce13b2 100644 --- a/src/allmain.c +++ b/src/allmain.c @@ -937,6 +937,7 @@ static const struct early_opt earlyopts[] = { { ARG_DUMPENUMS, "dumpenums", 9, FALSE }, #endif { ARG_DUMPGLYPHIDS, "dumpglyphids", 12, FALSE }, + { ARG_DUMPMONGEN, "dumpmongen", 10, FALSE }, #ifdef WIN32 { ARG_WINDOWS, "windows", 4, TRUE }, #endif @@ -1038,6 +1039,9 @@ argcheck(int argc, char *argv[], enum earlyarg e_arg) case ARG_DUMPGLYPHIDS: dump_glyphids(); return 2; + case ARG_DUMPMONGEN: + dump_mongen(); + return 2; #ifdef CRASHREPORT case ARG_BIDSHOW: crashreport_bidshow(); diff --git a/src/makemon.c b/src/makemon.c index 76e52a85e..f365d643f 100644 --- a/src/makemon.c +++ b/src/makemon.c @@ -1809,6 +1809,41 @@ init_mongen_order(void) #endif } +#define MONSi(i) (mongen_order[i]) + +extern struct enum_dump monsdump[]; /* allmain.c */ + +void +dump_mongen(void) +{ + char mlet, prev_mlet = 0; + int i, nmwidth = 27, special; + char nmbuf[80]; + + monst_globals_init(); + init_mongen_order(); + raw_printf("int mongen_order[] = {"); + for (i = LOW_PM; i < SPECIAL_PM; ++i) { + special = (mons[MONSi(i)].geno & (G_NOGEN | G_UNIQ)); + mlet = def_monsyms[(int) mons[MONSi(i)].mlet].sym; + if (prev_mlet && prev_mlet != mlet) + raw_print(""); + Snprintf(nmbuf, sizeof nmbuf, "PM_%s%s", + monsdump[MONSi(i)].nm, + (i == SPECIAL_PM - 1) ? "" : ","); + raw_printf(" %*s /* %c seq=%3d, idx=%3d, sym='%c', diff=%2d %s */", + -nmwidth, nmbuf, (i == MONSi(i)) ? ' ' : '.', i, MONSi(i), + mlet, (int) mons[MONSi(i)].difficulty, + (special == (G_NOGEN | G_UNIQ)) ? "(G_NOGEN | G_UNIQ)" + : (special == G_NOGEN) ? "(G_NOGEN)" + : (special == G_UNIQ) ? "(G_UNIQ)" + : ""); + prev_mlet = mlet; + } + raw_print("};"); + raw_print(""); + freedynamicdata(); +} /* Make one of the multiple types of a given monster class. The second parameter specifies a special casing bit mask @@ -1820,8 +1855,6 @@ mkclass(char class, int spc) return mkclass_aligned(class, spc, A_NONE); } -#define MONSi(i) (mongen_order[i]) - /* mkclass() with alignment restrictions; used by ndemon() */ struct permonst * mkclass_aligned(char class, int spc, /* special mons[].geno handling */ diff --git a/sys/unix/unixmain.c b/sys/unix/unixmain.c index 617a1ef06..154c7e15b 100644 --- a/sys/unix/unixmain.c +++ b/sys/unix/unixmain.c @@ -659,6 +659,9 @@ early_options(int *argc_p, char ***argv_p, char **hackdir_p) opt_terminate(); /*NOTREACHED*/ #endif + } else if (argcheck(argc, argv, ARG_DUMPMONGEN) == 2) { + opt_terminate(); + /*NOTREACHED*/ } else { #ifdef CHDIR oldargc = argc; diff --git a/sys/windows/windmain.c b/sys/windows/windmain.c index eaef359b9..c622a707e 100644 --- a/sys/windows/windmain.c +++ b/sys/windows/windmain.c @@ -484,6 +484,9 @@ early_options(int argc, char *argv[]) } #endif #endif + if (argcheck(argc, argv, ARG_DUMPMONGEN) == 2) { + nethack_exit(EXIT_SUCCESS); + } if (argcheck(argc, argv, ARG_DEBUG) == 1) { argc--; argv++; From 8672807a5ec8fbe1834a20991a3fe390651e0405 Mon Sep 17 00:00:00 2001 From: nhmall Date: Fri, 14 Feb 2025 19:30:34 -0500 Subject: [PATCH 440/791] cmp_init_mongen_order() qsort comparison function tweaks The array was ending up ordered the same on different qsort implementations. This incorporates the mlet value into the sort value for comparison. That guarantees that everything stays ordered by mlet, followed by difficulty (and would even if something ever got misplaced in monsters.h). It means the "they are equal" zero return for differing mlet values is not required, and has been removed. This removes the "they are equal" zero returns for G_NOGEN | G_UNIQ monsters, so they will still get sorted rather than left at the whatever array element they happened to be at (which I don't think should be an issue?). --- src/makemon.c | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/src/makemon.c b/src/makemon.c index f365d643f..77ce688eb 100644 --- a/src/makemon.c +++ b/src/makemon.c @@ -1752,16 +1752,21 @@ static boolean mongen_order_init = FALSE; staticfn int QSORTCALLBACK cmp_init_mongen_order(const void *p1, const void *p2) { - const int *pi1 = p1; - const int *pi2 = p2; - int i1 = *pi1, i2 = *pi2; + int i1 = *((int *) p1), i2 = *((int *) p2); + #if 0 + /* This will cause these to be moved last in the mlet sort order */ + int offset1 = ((mons[i1].geno & (G_NOGEN | G_UNIQ)) != 0) ? 99 : 0, + offset2 = ((mons[i2].geno & (G_NOGEN | G_UNIQ)) != 0) ? 99 : 0; +#else + int offset1 = 0, offset2 = 0; +#endif - if (((mons[i1].geno & (G_NOGEN|G_UNIQ)) != 0) - || ((mons[i2].geno & (G_NOGEN|G_UNIQ)) != 0)) - return 0; - if (mons[i1].mlet != mons[i2].mlet) - return 0; - return (int)(mons[i1].difficulty - mons[i2].difficulty); + /* incorporate the mlet into the sort values for comparison */ + int difficulty1 = + ((int) mons[i1].difficulty + offset1 | ((int) mons[i1].mlet << 8)), + difficulty2 = + ((int) mons[i2].difficulty + offset2 | ((int) mons[i2].mlet << 8)); + return difficulty1 - difficulty2; } /* check that monsters are in correct difficulty order for mkclass() */ @@ -1797,13 +1802,13 @@ init_mongen_order(void) return; mongen_order_init = TRUE; - for (i = LOW_PM; i <= SPECIAL_PM; i++) + for (i = LOW_PM; i <= NUMMONS; i++) mongen_order[i] = i; #if (NH_DEVEL_STATUS != NH_STATUS_RELEASED) check_mongen_order(); #endif - qsort((genericptr_t) mongen_order, NUMMONS, sizeof(int), cmp_init_mongen_order); + qsort((genericptr_t) mongen_order, SPECIAL_PM, sizeof(int), cmp_init_mongen_order); #if (NH_DEVEL_STATUS != NH_STATUS_RELEASED) check_mongen_order(); #endif From 3cb7819c8186fd2763bbf64e27f890fe9e530e13 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sun, 16 Feb 2025 10:35:17 +0200 Subject: [PATCH 441/791] Split monster goal coordinate out of mstrategy field Instead of packing a coordinate into unsigned long, store the goal in a coord struct, making the code a bit cleaner. Monster struct is of course slightly bigger, but that should not really matter. No change in monster behaviour. Breaks saves and bones. --- include/monst.h | 6 ++---- include/patchlevel.h | 2 +- src/monmove.c | 4 ++-- src/wizard.c | 27 ++++++++++++++++----------- 4 files changed, 21 insertions(+), 18 deletions(-) diff --git a/include/monst.h b/include/monst.h index 9315d31f0..0c52e239b 100644 --- a/include/monst.h +++ b/include/monst.h @@ -180,12 +180,10 @@ struct monst { #define STRAT_PLAYER 0x01000000L #define STRAT_NONE 0x00000000L #define STRAT_STRATMASK 0x0f000000L -#define STRAT_XMASK 0x00ff0000L -#define STRAT_YMASK 0x0000ff00L + /* mstrategy unused 0x00ffff00L */ #define STRAT_GOAL 0x000000ffL -#define STRAT_GOALX(s) ((coordxy) ((s & STRAT_XMASK) >> 16)) -#define STRAT_GOALY(s) ((coordxy) ((s & STRAT_YMASK) >> 8)) + coord mgoal; /* monster strategy, target location */ long mtrapseen; /* bitmap of traps we've been trapped in */ long mlstmv; /* for catching up with lost time */ long mstate; /* debugging info on monsters stored here */ diff --git a/include/patchlevel.h b/include/patchlevel.h index 0cc49ff95..ee05d8ac0 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 119 +#define EDITLEVEL 120 /* * Development status possibilities. diff --git a/src/monmove.c b/src/monmove.c index 9c2191f65..1c10644cb 100644 --- a/src/monmove.c +++ b/src/monmove.c @@ -1750,8 +1750,8 @@ m_move(struct monst *mtmp, int after) if (is_covetous(ptr)) { /* [should this include * '&& mtmp->mstrategy != STRAT_NONE'?] */ int covetousattack; - coordxy tx = STRAT_GOALX(mtmp->mstrategy), - ty = STRAT_GOALY(mtmp->mstrategy); + coordxy tx = mtmp->mgoal.x, + ty = mtmp->mgoal.y; struct monst *intruder = isok(tx, ty) ? m_at(tx, ty) : NULL; /* * if there's a monster on the object or in possession of it, diff --git a/src/wizard.c b/src/wizard.c index 3e28a6360..1194aa80b 100644 --- a/src/wizard.c +++ b/src/wizard.c @@ -135,9 +135,6 @@ mon_has_special(struct monst *mtmp) * The strategy section decides *what* the monster is going * to attempt, the tactics section implements the decision. */ -#define STRAT(w, x, y, typ) \ - ((unsigned long) (w) | ((unsigned long) (x) << 16) \ - | ((unsigned long) (y) << 8) | (unsigned long) (typ)) #define M_Wants(mask) (mtmp->data->mflags3 & (mask)) @@ -247,17 +244,25 @@ target_on(int mask, struct monst *mtmp) otyp = which_arti(mask); if (!mon_has_arti(mtmp, otyp)) { - if (you_have(mask)) - return STRAT(STRAT_PLAYER, u.ux, u.uy, mask); - else if ((otmp = on_ground(otyp))) - return STRAT(STRAT_GROUND, otmp->ox, otmp->oy, mask); - else if ((mtmp2 = other_mon_has_arti(mtmp, otyp)) != 0 + if (you_have(mask)) { + mtmp->mgoal.x = u.ux; + mtmp->mgoal.y = u.uy; + return (STRAT_PLAYER | mask); + } else if ((otmp = on_ground(otyp))) { + mtmp->mgoal.x = otmp->ox; + mtmp->mgoal.y = otmp->oy; + return (STRAT_GROUND | mask); + } else if ((mtmp2 = other_mon_has_arti(mtmp, otyp)) != 0 /* when seeking the Amulet, avoid targeting the Wizard or temple priests (to protect Moloch's high priest) */ && (otyp != AMULET_OF_YENDOR - || (!mtmp2->iswiz && !inhistemple(mtmp2)))) - return STRAT(STRAT_MONSTR, mtmp2->mx, mtmp2->my, mask); + || (!mtmp2->iswiz && !inhistemple(mtmp2)))) { + mtmp->mgoal.x = mtmp2->mx; + mtmp->mgoal.y = mtmp2->my; + return (STRAT_MONSTR | mask); + } } + mtmp->mgoal.x = mtmp->mgoal.y = 0; return (unsigned long) STRAT_NONE; } @@ -410,7 +415,7 @@ tactics(struct monst *mtmp) default: /* kill, maim, pillage! */ { long where = (strat & STRAT_STRATMASK); - coordxy tx = STRAT_GOALX(strat), ty = STRAT_GOALY(strat); + coordxy tx = mtmp->mgoal.x, ty = mtmp->mgoal.y; int targ = (int) (strat & STRAT_GOAL); struct obj *otmp; From 495a7e78983fd55116cb4ffbc523ebd2a1722a96 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sun, 16 Feb 2025 10:50:04 +0200 Subject: [PATCH 442/791] Silence a suggested parenthesis warning --- src/makemon.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/makemon.c b/src/makemon.c index 77ce688eb..8681eefc6 100644 --- a/src/makemon.c +++ b/src/makemon.c @@ -1763,9 +1763,9 @@ cmp_init_mongen_order(const void *p1, const void *p2) /* incorporate the mlet into the sort values for comparison */ int difficulty1 = - ((int) mons[i1].difficulty + offset1 | ((int) mons[i1].mlet << 8)), + ((int) (mons[i1].difficulty + offset1) | ((int) mons[i1].mlet << 8)), difficulty2 = - ((int) mons[i2].difficulty + offset2 | ((int) mons[i2].mlet << 8)); + ((int) (mons[i2].difficulty + offset2) | ((int) mons[i2].mlet << 8)); return difficulty1 - difficulty2; } From 1da02b102513bede1695030ba019cf5232d6b844 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 16 Feb 2025 06:57:53 -0500 Subject: [PATCH 443/791] remove a cast that isn't doing anything now --- src/makemon.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/makemon.c b/src/makemon.c index 8681eefc6..90c8558ec 100644 --- a/src/makemon.c +++ b/src/makemon.c @@ -1763,9 +1763,9 @@ cmp_init_mongen_order(const void *p1, const void *p2) /* incorporate the mlet into the sort values for comparison */ int difficulty1 = - ((int) (mons[i1].difficulty + offset1) | ((int) mons[i1].mlet << 8)), + ((mons[i1].difficulty + offset1) | ((int) mons[i1].mlet << 8)), difficulty2 = - ((int) (mons[i2].difficulty + offset2) | ((int) mons[i2].mlet << 8)); + ((mons[i2].difficulty + offset2) | ((int) mons[i2].mlet << 8)); return difficulty1 - difficulty2; } From 679094ff93c15e1049b981b7be3303bb7046ae13 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 16 Feb 2025 07:30:22 -0500 Subject: [PATCH 444/791] keep tameness at or above its existing level Resolves #1380 --- src/dog.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/dog.c b/src/dog.c index 570b73c2a..a08496322 100644 --- a/src/dog.c +++ b/src/dog.c @@ -44,7 +44,9 @@ free_edog(struct monst *mtmp) void initedog(struct monst *mtmp, boolean everything) { - mtmp->mtame = is_domestic(mtmp->data) ? 10 : 5; + schar minimumtame = is_domestic(mtmp->data) ? 10 : 5; + + mtmp->mtame = max(minimumtame, mtmp->mtame); mtmp->mpeaceful = 1; mtmp->mavenge = 0; set_malign(mtmp); /* recalc alignment now that it's tamed */ From 6b2f24a443314112ba307e37a3f5874995863ceb Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 17 Feb 2025 07:24:32 -0500 Subject: [PATCH 445/791] Fix out-of-bounds makemon.c: In function 'init_mongen_order': makemon.c:1806:25: warning: iteration 383 invokes undefined behavior [-Waggressive-loop-optimizations] 1806 | mongen_order[i] = i; | ~~~~~~~~~~~~~~~~^~~ makemon.c:1805:24: note: within this loop 1805 | for (i = LOW_PM; i <= NUMMONS; i++) | ~~^~~~~~~~~~ --- src/makemon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/makemon.c b/src/makemon.c index 90c8558ec..d7eff9f71 100644 --- a/src/makemon.c +++ b/src/makemon.c @@ -1802,7 +1802,7 @@ init_mongen_order(void) return; mongen_order_init = TRUE; - for (i = LOW_PM; i <= NUMMONS; i++) + for (i = LOW_PM; i < NUMMONS; i++) mongen_order[i] = i; #if (NH_DEVEL_STATUS != NH_STATUS_RELEASED) From 372ebd9d805fcc0e442b07ac87daefd592fcc3f0 Mon Sep 17 00:00:00 2001 From: Keni Date: Mon, 17 Feb 2025 11:50:55 -0500 Subject: [PATCH 446/791] NOSTATICFN/NONOSTATICFN typos and logic fixes --- include/config.h | 4 +++- sys/unix/hints/linux.370 | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/include/config.h b/include/config.h index 11652a7c6..a7097b363 100644 --- a/include/config.h +++ b/include/config.h @@ -273,7 +273,9 @@ # endif # ifdef __linux__ # define PANICTRACE -# define NOSTATICFN +# ifndef NOSTATICFN // may be defined on command line +# define NOSTATICFN +# endif # endif // This test isn't quite right: CNG is only available from Windows 2000 on. // But we'll check that at runtime. diff --git a/sys/unix/hints/linux.370 b/sys/unix/hints/linux.370 index 39286e027..e3dec785b 100755 --- a/sys/unix/hints/linux.370 +++ b/sys/unix/hints/linux.370 @@ -360,10 +360,10 @@ POSTINSTALL+= sed -i -e 's;^GDBPATH=/usr/bin/gdb;\#GDBPATH=/usr/bin/gdb;' \ -e 's;PANICTRACE_GDB=1;PANICTRACE_GDB=0;' $(INSTDIR)/sysconf; endif -ifeq 'USENONOSTATICFN' '1' +ifeq '$(USE_NONOSTATICFN)' '1' CFLAGS += -DNONOSTATICFN else -ifeq 'USE_NOSTATICFN' '1' +ifeq '$(USE_NOSTATICFN)' '1' CFLAGS += -DNOSTATICFN endif endif From 1102a777771634cb0a9b249d272eabeaede5351c Mon Sep 17 00:00:00 2001 From: PatR Date: Tue, 25 Feb 2025 09:44:03 -0800 Subject: [PATCH 447/791] feedback about config file name on MacOS When hunting for player's run-time config file under MacOS/OSX, nethack looks for .nethackrc (or $HOME/.nethackrc), then if not found it looks for "$HOME/Library/Preferences/NetHack Defaults", and finally for "$HOME/Library/Preferences/NetHack Defaults.txt". When none of those exists, the last choice has been being left in configfile[] and can get used in messages. The menu for entering the tutorial includes a tip about setting OPTIONS=!tutorial in the config file, but it was showing the third choice rather than the first when none of them are found. Change config file name setup to remember the first name rather than the last when it represents a non-existant/not-yet-existent file, so that the tip recommnends the standard Unix name rather than the Mac-specific one. --- src/files.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/src/files.c b/src/files.c index 21dc4f5f0..444ad6503 100644 --- a/src/files.c +++ b/src/files.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 files.c $NHDT-Date: 1737346561 2025/01/19 20:16:01 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.416 $ */ +/* NetHack 3.7 files.c $NHDT-Date: 1740532826 2025/02/25 17:20:26 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.417 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Derek S. Ray, 2015. */ /* NetHack may be freely redistributed. See license for details. */ @@ -2291,18 +2291,28 @@ fopen_config_file(const char *filename, int src) set_configfile_name(tmp_config); if ((fp = fopen(configfile, "r")) != (FILE *) 0) return fp; -#if defined(__APPLE__) /* UNIX+__APPLE__ => MacOSX */ +#if defined(__APPLE__) /* UNIX+__APPLE__ => OSX || MacOS */ /* try an alternative */ if (envp) { + /* keep 'tmp_config' intact here; if alternates fail, use it to + restore configfile[] to its preferred setting (".nethackrc") */ + char alt_config[sizeof tmp_config]; + /* OSX-style configuration settings */ - Sprintf(tmp_config, "%s/%s", envp, - "Library/Preferences/NetHack Defaults"); - set_configfile_name(tmp_config); + Snprintf(alt_config, sizeof alt_config, "%s/%s", envp, + "Library/Preferences/NetHack Defaults"); + set_configfile_name(alt_config); if ((fp = fopen(configfile, "r")) != (FILE *) 0) return fp; /* may be easier for user to edit if filename has '.txt' suffix */ - Sprintf(tmp_config, "%s/%s", envp, - "Library/Preferences/NetHack Defaults.txt"); + Snprintf(alt_config, sizeof alt_config, "%s/%s", envp, + "Library/Preferences/NetHack Defaults.txt"); + set_configfile_name(alt_config); + if ((fp = fopen(configfile, "r")) != (FILE *) 0) + return fp; + /* couldn't open either of the alternate names; for use in + messages, put 'configfile' back to the normal value rather than + leaving it set to last alternate; retry open() to reset 'errno' */ set_configfile_name(tmp_config); if ((fp = fopen(configfile, "r")) != (FILE *) 0) return fp; From 76b5bbe6937da53beeb0a581e5ce4f7e2bb714e6 Mon Sep 17 00:00:00 2001 From: PatR Date: Tue, 25 Feb 2025 09:49:55 -0800 Subject: [PATCH 448/791] fix issue #1382 - stoning resistance Issue reported by elunna: nethack has become confused about resistances held by poly'd hero. resists_xxxx() got changed to check worn and carried equipment so was no longer accurate for use when changes shape. Fixes #1382 --- src/polyself.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/polyself.c b/src/polyself.c index 625d00720..4ab183113 100644 --- a/src/polyself.c +++ b/src/polyself.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 polyself.c $NHDT-Date: 1703845752 2023/12/29 10:29:12 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.207 $ */ +/* NetHack 3.7 polyself.c $NHDT-Date: 1740534595 2025/02/25 17:49:55 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.223 $ */ /* Copyright (C) 1987, 1988, 1989 by Ken Arromdee */ /* NetHack may be freely redistributed. See license for details. */ @@ -59,15 +59,16 @@ set_uasmon(void) else \ u.uprops[PropIndx].intrinsic &= ~FROMFORM; \ } while (0) +#define resist_from_form(MRtyp) ((gy.youmonst.data->mresists & (MRtyp)) != 0) - PROPSET(FIRE_RES, resists_fire(&gy.youmonst)); - PROPSET(COLD_RES, resists_cold(&gy.youmonst)); - PROPSET(SLEEP_RES, resists_sleep(&gy.youmonst)); - PROPSET(DISINT_RES, resists_disint(&gy.youmonst)); - PROPSET(SHOCK_RES, resists_elec(&gy.youmonst)); - PROPSET(POISON_RES, resists_poison(&gy.youmonst)); - PROPSET(ACID_RES, resists_acid(&gy.youmonst)); - PROPSET(STONE_RES, resists_ston(&gy.youmonst)); + PROPSET(FIRE_RES, resist_from_form(MR_FIRE)); + PROPSET(COLD_RES, resist_from_form( MR_COLD)); + PROPSET(SLEEP_RES, resist_from_form(MR_SLEEP)); + PROPSET(DISINT_RES, resist_from_form(MR_DISINT)); + PROPSET(SHOCK_RES, resist_from_form(MR_ELEC)); + PROPSET(POISON_RES, resist_from_form(MR_POISON)); + PROPSET(ACID_RES, resist_from_form(MR_ACID)); + PROPSET(STONE_RES, resist_from_form(MR_STONE)); { /* resists_drli() takes wielded weapon into account; suppress it */ struct obj *save_uwep = uwep; @@ -107,6 +108,7 @@ set_uasmon(void) PROPSET(BLND_RES, (dmgtype_fromattack(mdat, AD_BLND, AT_EXPL) || dmgtype_fromattack(mdat, AD_BLND, AT_GAZE))); #undef PROPSET +#undef resist_from_form /* whether the player is flying/floating depends on their steed, which won't be known during the restore process: but BFlying From 1fd3bb661f82c5f76b2f2924afec92bb0cc42b18 Mon Sep 17 00:00:00 2001 From: PatR Date: Tue, 25 Feb 2025 09:54:14 -0800 Subject: [PATCH 449/791] fix issue #1378 - brain eaten after flayer's death Issue reported by Umbire: if a mind flayer got turned to stone by hitting a hero who is polymorphed into a cockatrice and the first tentacle drain missed but a subsequent one hit, any remaining ones would keep being applied even though the mind flayer was dead. This works but doesn't feel right to me. A more substantial change to mhitm_ad_drin() didn't work as expected so I've settled for this. Fixes #1378 --- src/eat.c | 8 +++++++- src/mhitu.c | 9 +++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/eat.c b/src/eat.c index a73cf2080..b15f36ade 100644 --- a/src/eat.c +++ b/src/eat.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 eat.c $NHDT-Date: 1715177703 2024/05/08 14:15:03 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.334 $ */ +/* NetHack 3.7 eat.c $NHDT-Date: 1740534854 2025/02/25 17:54:14 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.344 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -610,6 +610,12 @@ eat_brains( boolean give_nutrit = FALSE; int result = M_ATTK_HIT, xtra_dmg = rnd(10); + /* previous tentacle attack might have triggered fatal passive + counterattack [callers ought to be updated to avoid this situation] */ + if (magr != &gy.youmonst && DEADMONSTER(magr)) { + return M_ATTK_AGR_DIED; + } + if (noncorporeal(pd)) { if (visflag) pline("%s brain is unharmed.", diff --git a/src/mhitu.c b/src/mhitu.c index 904321a51..32cb68a14 100644 --- a/src/mhitu.c +++ b/src/mhitu.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 mhitu.c $NHDT-Date: 1721844072 2024/07/24 18:01:12 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.318 $ */ +/* NetHack 3.7 mhitu.c $NHDT-Date: 1740534854 2025/02/25 17:54:14 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.327 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -486,7 +486,9 @@ mattacku(struct monst *mtmp) if (!ranged) nomul(0); - if (DEADMONSTER(mtmp) || (Underwater && !is_swimmer(mtmp->data))) + if (DEADMONSTER(mtmp)) + return 1; + if (Underwater && !is_swimmer(mtmp->data)) return 0; /* If swallowed, can only be affected by u.ustuck */ @@ -741,6 +743,9 @@ mattacku(struct monst *mtmp) for (i = 0; i < NATTK; i++) { sum[i] = M_ATTK_MISS; + /* counterattack against attack [i-1] might have been fatal */ + if (DEADMONSTER(mtmp)) + return 1; if (i > 0) { /* recalc in case prior attack moved hero; mtmp doesn't make another attempt to guess your location but might have From 6c42180cfcc7e9a07a7498d7d11c67ef579af65a Mon Sep 17 00:00:00 2001 From: PatR Date: Wed, 26 Feb 2025 12:15:13 -0800 Subject: [PATCH 450/791] fix issue #1383 - chopping boulder at tree spot Reported by k21971: applying an axe toward a location that contained both a tree and a boulder (or statue) would use the axe to break the boulder/statue rather than chop down the tree. Different code is used to finish the dig/chop than is used to decide whether the tool is appropriate for its target. Fixes #1383 --- doc/fixes3-7-0.txt | 4 +++- src/dig.c | 57 +++++++++++++++++++++++----------------------- 2 files changed, 31 insertions(+), 30 deletions(-) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index e54ab8cf7..a9f4960d9 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -1,4 +1,4 @@ -NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.1533 $ $NHDT-Date: 1738638877 2025/02/03 19:14:37 $ +NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.1535 $ $NHDT-Date: 1740629713 2025/02/26 20:15:13 $ General Fixes and Modified Features ----------------------------------- @@ -1504,6 +1504,8 @@ since introduction in 3.1.0, the definition for Mitre of Holiness has specified that carrying it provides fire resistance, but that had never been implemented; wearing it didn't confer fire resistance either--there is no 'defends' capability for it since carrying should encompass that +if a tree and a boulder or statue were at the same location, applying an axe + would break the boulder or statue rather than chop the tree Fixes to 3.7.0-x General Problems Exposed Via git Repository diff --git a/src/dig.c b/src/dig.c index c0c341248..195222235 100644 --- a/src/dig.c +++ b/src/dig.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 dig.c $NHDT-Date: 1736530208 2025/01/10 09:30:08 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.225 $ */ +/* NetHack 3.7 dig.c $NHDT-Date: 1740629713 2025/02/26 20:15:13 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.227 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -168,29 +168,27 @@ pick_can_reach(struct obj *pick, coordxy x, coordxy y) int dig_typ(struct obj *otmp, coordxy x, coordxy y) { - boolean ispick; + int ltyp; - if (!otmp) - return DIGTYP_UNDIGGABLE; - ispick = is_pick(otmp); - if (!ispick && !is_axe(otmp)) + if (!isok(x, y) || !otmp || (!is_pick(otmp) && !is_axe(otmp))) return DIGTYP_UNDIGGABLE; - return ((ispick && sobj_at(STATUE, x, y) - && pick_can_reach(otmp, x, y)) - ? DIGTYP_STATUE - : (ispick && sobj_at(BOULDER, x, y) - && pick_can_reach(otmp, x, y)) - ? DIGTYP_BOULDER - : closed_door(x, y) - ? DIGTYP_DOOR - : IS_TREE(levl[x][y].typ) - ? (ispick ? DIGTYP_UNDIGGABLE : DIGTYP_TREE) - : (ispick && IS_OBSTRUCTED(levl[x][y].typ) - && (!svl.level.flags.arboreal - || IS_WALL(levl[x][y].typ))) - ? DIGTYP_ROCK - : DIGTYP_UNDIGGABLE); + ltyp = levl[x][y].typ; + if (is_axe(otmp)) + return closed_door(x, y) ? DIGTYP_DOOR + : IS_TREE(ltyp) ? DIGTYP_TREE /* axe vs tree */ + : DIGTYP_UNDIGGABLE; + /*assert(is_pick(otmp));*/ + return (sobj_at(STATUE, x, y) && pick_can_reach(otmp, x, y)) + ? DIGTYP_STATUE + : (sobj_at(BOULDER, x, y) && pick_can_reach(otmp, x, y)) + ? DIGTYP_BOULDER + : closed_door(x, y) ? DIGTYP_DOOR + : IS_TREE(ltyp) ? DIGTYP_UNDIGGABLE /* pick vs tree */ + : (IS_OBSTRUCTED(ltyp) + && (!svl.level.flags.arboreal || IS_WALL(ltyp))) + ? DIGTYP_ROCK + : DIGTYP_UNDIGGABLE; } boolean @@ -441,21 +439,22 @@ dig(void) if (svc.context.digging.effort > 100) { const char *digtxt, *dmgtxt = (const char *) 0; - struct obj *obj; + struct obj *obj, *bobj; boolean shopedge = *in_rooms(dpx, dpy, SHOPBASE); + int digtyp = dig_typ(uwep, dpx, dpy); - if ((obj = sobj_at(STATUE, dpx, dpy)) != 0) { + if (digtyp == DIGTYP_STATUE + && (obj = sobj_at(STATUE, dpx, dpy)) != 0) { if (break_statue(obj)) digtxt = "The statue shatters."; else /* it was a statue trap; break_statue() - * printed a message and updated the screen - */ + printed a message and updated the screen */ digtxt = (char *) 0; - } else if ((obj = sobj_at(BOULDER, dpx, dpy)) != 0) { - struct obj *bobj; - + } else if (digtyp == DIGTYP_BOULDER + && (obj = sobj_at(BOULDER, dpx, dpy)) != 0) { fracture_rock(obj); + /*[3.7: this probably isn't necessary anymore]*/ if ((bobj = sobj_at(BOULDER, dpx, dpy)) != 0) { /* another boulder here, restack it to the top */ obj_extract_self(bobj); @@ -474,7 +473,7 @@ dig(void) goto cleanup; } } - if (IS_TREE(lev->typ)) { + if (digtyp == DIGTYP_TREE) { digtxt = "You cut down the tree."; lev->typ = ROOM, lev->flags = 0; if (!rn2(5)) From 6ff2bf099395d6391d61bdd45279956860fdb949 Mon Sep 17 00:00:00 2001 From: nhmall Date: Wed, 26 Feb 2025 21:44:21 -0500 Subject: [PATCH 451/791] convert some tabs that crept in to spaces --- src/files.c | 6 +++--- src/pray.c | 2 +- src/sounds.c | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/files.c b/src/files.c index 444ad6503..f40385d4b 100644 --- a/src/files.c +++ b/src/files.c @@ -4640,7 +4640,7 @@ reveal_paths(int code) if (code == 1) { raw_printf("NOTE: The %s above is missing or inaccessible!", SYSCONFFILE); - skip_sysopt = TRUE; + skip_sysopt = TRUE; } #else /* !SYSCF */ raw_printf("No system configuration file."); @@ -4722,8 +4722,8 @@ reveal_paths(int code) #ifdef SYSCF if (!skip_sysopt) { fqn = sysopt.dumplogfile; - if (!fqn) - nodumpreason = "DUMPLOGFILE is not set in " SYSCONFFILE; + if (!fqn) + nodumpreason = "DUMPLOGFILE is not set in " SYSCONFFILE; } else { nodumpreason = SYSCONFFILE " is missing; no DUMPLOGFILE setting"; } diff --git a/src/pray.c b/src/pray.c index ba700c4dd..066042af0 100644 --- a/src/pray.c +++ b/src/pray.c @@ -1144,7 +1144,7 @@ pleased(aligntyp g_align) fix_worst_trouble(trouble); FALLTHROUGH; /*FALLTHRU*/ - case 2: + case 2: /* up to 9 troubles */ while ((trouble = in_trouble()) > 0 && (++tryct < 10)) fix_worst_trouble(trouble); diff --git a/src/sounds.c b/src/sounds.c index ec5d2aae2..599469de8 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -1142,7 +1142,7 @@ domonnoise(struct monst *mtmp) (void) demon_talk(mtmp); break; } - FALLTHROUGH; + FALLTHROUGH; /* FALLTHRU */ case MS_CUSS: if (!mtmp->mpeaceful) From 56ebf05324b3ae4eacd09fbbc3517173ddded311 Mon Sep 17 00:00:00 2001 From: nhmall Date: Wed, 26 Feb 2025 21:51:44 -0500 Subject: [PATCH 452/791] convert some tabs to spaces in util --- util/makedefs.c | 22 +++++++++++----------- util/recover.c | 6 +++--- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/util/makedefs.c b/util/makedefs.c index cbb466848..1af34cb2e 100644 --- a/util/makedefs.c +++ b/util/makedefs.c @@ -339,7 +339,7 @@ do_makedefs(char *options) rafile(*options); break; #if defined(OLD_MAKEDEFS_OPTIONS) - case 'o': + case 'o': case 'O': do_objs(); break; @@ -361,7 +361,7 @@ do_makedefs(char *options) do_questtxt(); break; #else - case 'o': case 'O': case 'e': case 'E': case 'v': case 'V': + case 'o': case 'O': case 'e': case 'E': case 'v': case 'V': case 'p': case 'P': case 'q': case 'Q': Fprintf(stderr, "Old makedefs option.\n" "Rebuild makedefs with '-DOLD_MAKEDEFS_OPTIONS'" @@ -393,7 +393,7 @@ oldfunctionality(char sought) char ucoflet; const char *ofnam; } ofn[] = { - { 'e', 'E', DGN_O_FILE }, + { 'e', 'E', DGN_O_FILE }, { 'o', 'O', ONAME_FILE }, { 'p', 'P', MONST_FILE }, { 'q', 'Q', QTXT_O_FILE }, @@ -661,15 +661,15 @@ do_ext_makedefs(int argc, char **argv) } CONTINUE; } - IS_OPTION("grep-defined"){ - struct grep_var *p; + IS_OPTION("grep-defined"){ + struct grep_var *p; - CONSUME; - p = grepsearch(argv[0]); - // NB: Exit status is ready for the shell: - // 0=defined, 1=not defined - makedefs_exit(!(p && p->is_defined)); - } + CONSUME; + p = grepsearch(argv[0]); + // NB: Exit status is ready for the shell: + // 0=defined, 1=not defined + makedefs_exit(!(p && p->is_defined)); + } #ifdef notyet IS_OPTION("help") { } diff --git a/util/recover.c b/util/recover.c index 6619e0a70..8c701c799 100644 --- a/util/recover.c +++ b/util/recover.c @@ -357,12 +357,12 @@ restore_savefile(char *basename) if (write(sfd, (genericptr_t) &levc, sizeof levc) != sizeof levc) { res = -1; - } else { + } else { if (!copy_bytes(lfd, sfd)) { Fprintf(stderr, "file copy failed!\n"); exit(EXIT_FAILURE); - } - } + } + } Close(lfd); (void) unlink(lock); } From 1eaafddca3a23d4b7d840eeee6f6fee349e945d2 Mon Sep 17 00:00:00 2001 From: nhmall Date: Wed, 26 Feb 2025 23:10:30 -0500 Subject: [PATCH 453/791] fix dolook() on Windows console usemap boolean wasn't being set to TRUE when it should have been --- sys/windows/consoletty.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sys/windows/consoletty.c b/sys/windows/consoletty.c index b7fb0cf50..017d2bac6 100644 --- a/sys/windows/consoletty.c +++ b/sys/windows/consoletty.c @@ -1493,9 +1493,9 @@ console_g_putch(int in_ch) #else /* VIRTUAL_TERMINAL_SEQUENCES */ ccount = 0; WCHAR wch[2]; - boolean usemap = (in_ch >= 0 && in_ch < SIZE(console.cpMap)); -#endif /* VIRTUAL_TERMINAL_SEQUENCES */ ch = (unsigned char) in_ch; + boolean usemap = (ch >= 0 && ch < SIZE(console.cpMap)); +#endif /* VIRTUAL_TERMINAL_SEQUENCES */ set_console_cursor(ttyDisplay->curx, ttyDisplay->cury); #ifndef VIRTUAL_TERMINAL_SEQUENCES From d56b0a3b7a9e0449d3f66c76c91ccbbb160640f6 Mon Sep 17 00:00:00 2001 From: nhmall Date: Wed, 26 Feb 2025 23:14:52 -0500 Subject: [PATCH 454/791] follow-up bit for Windows console --- sys/windows/consoletty.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sys/windows/consoletty.c b/sys/windows/consoletty.c index 017d2bac6..7754b3d1f 100644 --- a/sys/windows/consoletty.c +++ b/sys/windows/consoletty.c @@ -1486,14 +1486,13 @@ xputc_core(int ch) void console_g_putch(int in_ch) { - unsigned char ch; + unsigned char ch = (unsigned char) in_ch; cell_t cell; #ifndef VIRTUAL_TERMINAL_SEQUENCES boolean inverse = FALSE; #else /* VIRTUAL_TERMINAL_SEQUENCES */ ccount = 0; WCHAR wch[2]; - ch = (unsigned char) in_ch; boolean usemap = (ch >= 0 && ch < SIZE(console.cpMap)); #endif /* VIRTUAL_TERMINAL_SEQUENCES */ From 83bb81c624f6b2177c8b5014756af466d78faefe Mon Sep 17 00:00:00 2001 From: SHIRAKATA Kentaro Date: Sat, 1 Mar 2025 00:12:03 +0900 Subject: [PATCH 455/791] fix Makefile.nmake when USE_DLB=N --- sys/windows/Makefile.nmake | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sys/windows/Makefile.nmake b/sys/windows/Makefile.nmake index b3a1c4bb6..2618f65b6 100644 --- a/sys/windows/Makefile.nmake +++ b/sys/windows/Makefile.nmake @@ -1731,11 +1731,10 @@ binary.tag: $(DAT)data $(DAT)rumors $(DAT)oracles $(DLB) \ copy $(DAT)bogusmon $(GAMEDIR) copy $(DAT)cmdhelp $(GAMEDIR) copy $(DAT)data $(GAMEDIR) - copy $(DAT)dungeon $(GAMEDIR) copy $(DAT)engrave $(GAMEDIR) copy $(DAT)epitaph $(GAMEDIR) copy $(DAT)help $(GAMEDIR) - copy $(DAT)hh $(GAMDEDIR) + copy $(DAT)hh $(GAMEDIR) copy $(DAT)history $(GAMEDIR) copy $(DAT)license $(GAMEDIR) copy $(DAT)optmenu $(GAMEDIR) From ce7b7710d85968f08c1097a6ae33edd5920202d0 Mon Sep 17 00:00:00 2001 From: nhmall Date: Fri, 28 Feb 2025 12:40:34 -0500 Subject: [PATCH 456/791] a fix for issue #1386 - impossible to gen ';' mon Bug description of #1386 by @copperwater on GitHub: "When generating a random monster from a class using des.monster(), the G_NOGEN in their statblock is suppressed, but because every monster of this class has frequency 0, none of them are actually eligible to get picked. mkclass ends up returning a null pointer and create_monster has to pick a random monster instead. This affects the following levels (all the ones that use random sea monsters): Healer quest start Healer quest locate Plane of Water (difficult to notice, since it has lots of specific sea monsters and only 5 random ones) This can be pretty easily viewed by going to the Healer quest start and detecting monsters: there is a shark and a giant eel, which are specifically defined, but the remaining random sea monster that should be there is absent." Add a tracking array mclass_maxf[MAXMCLASSES] (about 61 entries, the first not being used), and fill it one time in init_mongen_order() with the maximum frequency value seen of any monster in that class. Any mclass_maxf[] entry of zero represents that entire class of monsters having no positive frequency value. Detect that in mkclass_aligned(), and use it to work around the situation to produce the monster being sought by the Lua level description file. --- src/makemon.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/makemon.c b/src/makemon.c index d7eff9f71..2de8003ae 100644 --- a/src/makemon.c +++ b/src/makemon.c @@ -1747,6 +1747,7 @@ mk_gen_ok(int mndx, unsigned mvflagsmask, unsigned genomask) /* monsters in order by mlet & difficulty for mkclass() */ static int mongen_order[NUMMONS]; +static xint8 mclass_maxf[MAXMCLASSES]; static boolean mongen_order_init = FALSE; staticfn int QSORTCALLBACK @@ -1796,15 +1797,18 @@ check_mongen_order(void) staticfn void init_mongen_order(void) { - int i; + int i, mlet; if (mongen_order_init) return; mongen_order_init = TRUE; - for (i = LOW_PM; i < NUMMONS; i++) + for (i = LOW_PM; i < NUMMONS; i++) { mongen_order[i] = i; - + mlet = mons[i].mlet; + if ((xint8) (mons[i].geno & G_FREQ) > mclass_maxf[mlet]) + mclass_maxf[mlet] = (xint8) (mons[i].geno & G_FREQ); + } #if (NH_DEVEL_STATUS != NH_STATUS_RELEASED) check_mongen_order(); #endif @@ -1836,9 +1840,11 @@ dump_mongen(void) Snprintf(nmbuf, sizeof nmbuf, "PM_%s%s", monsdump[MONSi(i)].nm, (i == SPECIAL_PM - 1) ? "" : ","); - raw_printf(" %*s /* %c seq=%3d, idx=%3d, sym='%c', diff=%2d %s */", + raw_printf(" %*s /* %c seq=%3d, idx=%3d, sym='%c', diff=%2d, freq=%2d[%d] %s */", -nmwidth, nmbuf, (i == MONSi(i)) ? ' ' : '.', i, MONSi(i), mlet, (int) mons[MONSi(i)].difficulty, + (int) (mons[MONSi(i)].geno & G_FREQ), + (int) mclass_maxf[(int) mons[MONSi(i)].mlet], (special == (G_NOGEN | G_UNIQ)) ? "(G_NOGEN | G_UNIQ)" : (special == G_NOGEN) ? "(G_NOGEN)" : (special == G_UNIQ) ? "(G_UNIQ)" @@ -1869,6 +1875,7 @@ mkclass_aligned(char class, int spc, /* special mons[].geno handling */ int k, nums[SPECIAL_PM + 1]; /* +1: insurance for final return value */ int maxmlev, gehennom = Inhell != 0; unsigned mv_mask, gn_mask; + boolean zero_freq_for_entire_class; (void) memset((genericptr_t) nums, 0, sizeof nums); maxmlev = level_difficulty() >> 1; @@ -1878,6 +1885,8 @@ mkclass_aligned(char class, int spc, /* special mons[].geno handling */ } init_mongen_order(); + /* the following must come after init_mongen_order() */ + zero_freq_for_entire_class = (mclass_maxf[(int) class] == 0); /* Assumption #1: monsters of a given class are contiguous in the * mons[] array. Player monsters and quest denizens @@ -1927,7 +1936,8 @@ mkclass_aligned(char class, int spc, /* special mons[].geno handling */ && mons[MONSi(last)].difficulty > mons[MONSi(last - 1)].difficulty && rn2(2)) break; - if ((k = (mons[MONSi(last)].geno & G_FREQ)) > 0) { + if ((k = (mons[MONSi(last)].geno & G_FREQ)) > 0 + || (k = (zero_freq_for_entire_class ? 1 : 0)) > 0) { /* skew towards lower value monsters at lower exp. levels (this used to be done in the next loop, but that didn't work well when multiple species had the same level and From 82c6804516e1676c2ad76c1b6368e79d510c49e3 Mon Sep 17 00:00:00 2001 From: PatR Date: Fri, 28 Feb 2025 10:38:50 -0800 Subject: [PATCH 457/791] X11: avoid null-pointer-subtraction warnings Most recent version of XQuartz, same as before. Unfortunately, newer version of macOS => newer version of Xcode and its command line tools => newer version of clang => emulating newer version of gcc which defaults to a more recent version of StdC, I suppose, or perhaps our hints are specifying that. Whichever, it has resulted in a bunch of complaints about XtOffset() used in win/X11/winX.c: |warning: performing pointer subtraction with a null pointer has\ undefined behavior [-Wnull-pointer-subtraction] Adding -wno-null-pointer-subtraction to X11FLAGS silences them, but that would require figuring out which versions of gcc and clang added -Wnull-pointer-subtraction and its negation. Revising XtOffset() to include the ptrdiff_t casts eliminates the warnings, avoiding the need for version conditionals to deal with X11FLAGS. --- include/winX.h | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/include/winX.h b/include/winX.h index 3da329d7d..496412edc 100644 --- a/include/winX.h +++ b/include/winX.h @@ -1,4 +1,4 @@ -/* NetHack 3.7 winX.h $NHDT-Date: 1643491525 2022/01/29 21:25:25 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.52 $ */ +/* NetHack 3.7 winX.h $NHDT-Date: 1740795096 2025/02/28 18:11:36 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.65 $ */ /* Copyright (c) Dean Luick, 1992 */ /* NetHack may be freely redistributed. See license for details. */ @@ -26,6 +26,19 @@ #endif #endif +/* winX.c uses XtOffset() and the way that that macro is defined in + triggers "performing pointer subtraction with + a null pointer has undefined behavior" warnings; this modified + edition doesn't guarantee defined behavior but does silence those + warnings without needing to know whether current compiler version + supports the '-wno-null-pointer-subtraction' option */ +#ifdef XtOffset +#undef XtOffset +#define XtOffset(p_type,field) \ + ((Cardinal) (((ptrdiff_t) (char *) (&(((p_type) NULL)->field))) \ + - ((ptrdiff_t) (char *) NULL))) +#endif + /* * Generic text buffer. */ From 518842ce19d4b11682940bb10005f7eeee023d19 Mon Sep 17 00:00:00 2001 From: PatR Date: Fri, 28 Feb 2025 11:37:05 -0800 Subject: [PATCH 458/791] typo fix --- include/winX.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/winX.h b/include/winX.h index 496412edc..295abaa8d 100644 --- a/include/winX.h +++ b/include/winX.h @@ -31,7 +31,7 @@ a null pointer has undefined behavior" warnings; this modified edition doesn't guarantee defined behavior but does silence those warnings without needing to know whether current compiler version - supports the '-wno-null-pointer-subtraction' option */ + supports the '-Wno-null-pointer-subtraction' option */ #ifdef XtOffset #undef XtOffset #define XtOffset(p_type,field) \ From 963ee14528f9d038db2e07d2181179a5f0e8da4f Mon Sep 17 00:00:00 2001 From: nhmall Date: Fri, 28 Feb 2025 19:20:36 -0500 Subject: [PATCH 459/791] remove references to lev_main.c from comments --- src/drawing.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/drawing.c b/src/drawing.c index 7881e1f8e..587489053 100644 --- a/src/drawing.c +++ b/src/drawing.c @@ -83,8 +83,9 @@ const uchar def_r_oc_syms[MAXOCLASSES] = { /* * Convert the given character to an object class. If the character is not - * recognized, then MAXOCLASSES is returned. Used in detect.c, invent.c, - * objnam.c, options.c, pickup.c, sp_lev.c, lev_main.c, and tilemap.c. + * recognized, then MAXOCLASSES is returned. Used in detect.c, drawing.c, + * invent.c, o_init.c, objnam.c, options.c, pickup.c, sp_lev.c, and + * windows.c. */ int def_char_to_objclass(char ch) @@ -100,7 +101,8 @@ def_char_to_objclass(char ch) /* * Convert a character into a monster class. This returns the _first_ * match made. If there are no matches, return MAXMCLASSES. - * Used in detect.c, options.c, read.c, sp_lev.c, and lev_main.c + * Used in detect.c, drawing.c, mondata.c, options.c, pickup.c, + * sp_lev.c, and windows.c. */ int def_char_to_monclass(char ch) From bcf7bfc52effdce5ce593c7ef1a42d209d1fea42 Mon Sep 17 00:00:00 2001 From: SHIRAKATA Kentaro Date: Sat, 1 Mar 2025 15:01:14 +0900 Subject: [PATCH 460/791] add a short README for test/ --- test/README.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 test/README.md diff --git a/test/README.md b/test/README.md new file mode 100644 index 000000000..68f41b1ca --- /dev/null +++ b/test/README.md @@ -0,0 +1,7 @@ +### how to use + + * compile NetHack without DLB + * install + * copy the test lua files into the nethack playground dir + * start nethack in wizmode + * use wizloadlua extended command to load and run one of the test files. From 121e12085b3cdc629541c1035a0409bc794f54cb Mon Sep 17 00:00:00 2001 From: nhw_cron Date: Sat, 1 Mar 2025 07:24:07 -0500 Subject: [PATCH 461/791] This is cron-daily v1-Apr-1-2024. 000files updated: Files --- Files | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Files b/Files index d9706ea8e..d8bcbab2f 100644 --- a/Files +++ b/Files @@ -567,8 +567,8 @@ afteruudecode.proj uudecode.vcxproj test: (files for testing) -test_cnf.lua test_des.lua test_lev.lua test_obj.lua test_sel.lua -test_shk.lua test_src.lua testmove.lua testwish.lua +README.md test_cnf.lua test_des.lua test_lev.lua test_obj.lua +test_sel.lua test_shk.lua test_src.lua testmove.lua testwish.lua util: (files for all versions) From d2af1afb5241dc0050d98d97f9e8c25c2b29544b Mon Sep 17 00:00:00 2001 From: SHIRAKATA Kentaro Date: Sun, 14 Jul 2024 22:20:41 +0900 Subject: [PATCH 462/791] split "swallowit" on throwit() into a separate function --- src/dothrow.c | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/src/dothrow.c b/src/dothrow.c index 6d99854e7..28df7b30b 100644 --- a/src/dothrow.c +++ b/src/dothrow.c @@ -16,6 +16,7 @@ staticfn int gem_accept(struct monst *, struct obj *); staticfn boolean toss_up(struct obj *, boolean) NONNULLARG1; staticfn void sho_obj_return_to_u(struct obj * obj); staticfn void throwit_return(boolean); +staticfn void swallowit(struct obj *); staticfn struct obj *return_throw_to_inv(struct obj *, long, boolean, struct obj *); staticfn void tmiss(struct obj *, struct monst *, boolean); @@ -1456,6 +1457,15 @@ throwit_return(boolean clear_thrownobj) gt.thrownobj = (struct obj *) 0; } +staticfn void +swallowit(struct obj *obj){ + if (obj != uball) { + (void) mpickobj(u.ustuck, obj); /* clears 'gt.thrownobj' */ + throwit_return(FALSE); + } else + throwit_return(TRUE); +} + /* throw an object, NB: obj may be consumed in the process */ void throwit(struct obj *obj, @@ -1664,12 +1674,7 @@ throwit(struct obj *obj, if (tethered_weapon) tmp_at(DISP_END, 0); } else if (u.uswallow && !iflags.returning_missile) { - swallowit: - if (obj != uball) { - (void) mpickobj(u.ustuck, obj); /* clears 'gt.thrownobj' */ - throwit_return(FALSE); - } else - throwit_return(TRUE); + swallowit(obj); return; } else { /* Mjollnir must be wielded to be thrown--caller verifies this; @@ -1715,8 +1720,10 @@ throwit(struct obj *obj, KILLED_BY); } - if (u.uswallow) - goto swallowit; + if (u.uswallow) { + swallowit(obj); + return; + } if (!ship_object(obj, u.ux, u.uy, FALSE)) dropy(obj); } @@ -1734,8 +1741,10 @@ throwit(struct obj *obj, capability back anyway, quivered or not shouldn't matter */ pline("%s to return!", Tobjnam(obj, "fail")); - if (u.uswallow) - goto swallowit; + if (u.uswallow) { + swallowit(obj); + return; + } /* continue below with placing 'obj' at target location */ } } From cbd45afa5a12b2b511a03c1041e314b9c1b01fc6 Mon Sep 17 00:00:00 2001 From: copperwater Date: Thu, 6 Feb 2025 17:42:53 -0500 Subject: [PATCH 463/791] Make pline_mon work if youmonst is passed to it I was working on another patch involving a message that could be printed for either a monster or the player (using a struct monst * variable that either holds the monster or &gy.youmonst), but wasn't able to easily use pline_mon for the message since the mx and my of youmonst aren't kept updated as the hero moves. (In my testing, they were always 0, but it's not clear if they will remain 0 throughout the game, or if that's a bad assumption to make.) Allow this in the future by checking for youmonst in pline_mon and setting the coordinates to 0,0 explicitly so no relative coordinate message gets printed when it's about the hero. I'm not sure if it's a reasonable assumption that no messages that could ever be passed to pline_mon for a player would ever need to note "(here)" when accessiblemsg is turned on. If that's the case, the correct thing would be to set the coordinates to u.ux, u.uy instead of 0,0. --- src/pline.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/pline.c b/src/pline.c index 13ec79924..7a1bc1511 100644 --- a/src/pline.c +++ b/src/pline.c @@ -136,7 +136,10 @@ pline_mon(struct monst *mtmp, const char *line, ...) { va_list the_args; - set_msg_xy(mtmp->mx, mtmp->my); + if (mtmp == &gy.youmonst) + set_msg_xy(0, 0); + else + set_msg_xy(mtmp->mx, mtmp->my); va_start(the_args, line); vpline(line, the_args); From 71e562def8ec365da6a99e28c702a4a9f1dba669 Mon Sep 17 00:00:00 2001 From: copperwater Date: Thu, 6 Feb 2025 18:35:22 -0500 Subject: [PATCH 464/791] Livelog when a player breaks petless conduct If a player initially goes petless then later obtains a pet, it's absent from the game chronicle. Fix that by adding a livelog for it. This required a bit of restructuring in create_familiar() that I wanted to do anyway: removing the kludge of decrementing u.uconduct.pets when a figurine has been deployed but isn't actually going to come out tame. Calling initedog() /after/ deciding whether it's needed or not prevents a first-pet livelog being produced for a figurine that didn't come out tame. The guardian angel code, which avoids calling initedog(), can never be the hero's first pet anyway because it only appears tame when the hero has already broken petless conduct. But while checking, I noticed a duplicate comment, so I removed that. --- src/dog.c | 21 ++++++++++++++++----- src/minion.c | 4 ---- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/src/dog.c b/src/dog.c index a08496322..ce9abc706 100644 --- a/src/dog.c +++ b/src/dog.c @@ -65,6 +65,16 @@ initedog(struct monst *mtmp, boolean everything) EDOG(mtmp)->mhpmax_penalty = 0; EDOG(mtmp)->killed_by_u = 0; } + /* livelog first pet, but only if you didn't start with one (the starting + * pet will be initialized before in_moveloop is true) */ + if (!u.uconduct.pets && program_state.in_moveloop) { + /* "obtained" a pet rather than "tamed" it because it might have come + * from a figurine or some other method in which it was created tame + * using an() is safe unless it somehow becomes possible to tame a + * unique monster */ + livelog_printf(LL_CONDUCT, "obtained %s first pet (%s)", + uhis(), an(mon_pmname(mtmp))); + } u.uconduct.pets++; } @@ -118,6 +128,7 @@ make_familiar(struct obj *otmp, coordxy x, coordxy y, boolean quietly) struct permonst *pm; struct monst *mtmp = 0; int chance, trycnt = 100; + boolean reallytame = TRUE; do { mmflags_nht mmflags; @@ -159,17 +170,14 @@ make_familiar(struct obj *otmp, coordxy x, coordxy y, boolean quietly) if (is_pool(mtmp->mx, mtmp->my) && minliquid(mtmp)) return (struct monst *) 0; - initedog(mtmp, TRUE); - mtmp->msleeping = 0; if (otmp) { /* figurine; resulting monster might not become a pet */ chance = rn2(10); /* 0==tame, 1==peaceful, 2==hostile */ if (chance > 2) chance = otmp->blessed ? 0 : !otmp->cursed ? 1 : 2; /* 0,1,2: b=80%,10,10; nc=10%,80,10; c=10%,10,80 */ if (chance > 0) { - mtmp->mtame = 0; /* not tame after all */ - u.uconduct.pets--; /* doesn't count as creating a pet */ - if (chance == 2) { /* hostile (cursed figurine) */ + reallytame = FALSE; /* not tame after all */ + if (chance == 2) { /* hostile (cursed figurine) */ if (!quietly) You("get a bad feeling about this."); mtmp->mpeaceful = 0; @@ -180,6 +188,9 @@ make_familiar(struct obj *otmp, coordxy x, coordxy y, boolean quietly) if (has_oname(otmp)) mtmp = christen_monst(mtmp, ONAME(otmp)); } + if (reallytame) + initedog(mtmp, TRUE); + mtmp->msleeping = 0; set_malign(mtmp); /* more alignment changes */ newsym(mtmp->mx, mtmp->my); diff --git a/src/minion.c b/src/minion.c index 9de8bb233..6acd508a7 100644 --- a/src/minion.c +++ b/src/minion.c @@ -529,10 +529,6 @@ gain_guardian_angel(void) * the final level of the game. The angel will still appear, but * won't be tamed. */ if (u.uconduct.pets) { - /* guardian angel -- the one case mtame doesn't - * imply an edog structure, so we don't want to - * call tamedog(). - */ mtmp->mtame = 10; u.uconduct.pets++; } From 55c3a7c6c5b299d6e7528c0cb568d14d69c904e2 Mon Sep 17 00:00:00 2001 From: copperwater Date: Wed, 19 Feb 2025 16:54:19 -0500 Subject: [PATCH 465/791] Fix: sitting on bidirectional teleportation traps It is possible to create a bidirectional teleportation trap by making a pair of teleportation traps with a fixed destination of each other's coordinate. Moving or hurtling onto such a trap correctly materializes the hero on top of the other trap without triggering it, but for some reason I didn't dig into, sitting down to trigger the first trap does also trigger the second one at the destination end, causing you to counterintuitively teleport twice and end up back where you started. Fix this by stopping tele_trap() from doing anything if it's called recursively, using a static variable like spoteffects() does for the same purpose. I had to adjust a bit of other tele_trap code to remove its sole early return. --- src/teleport.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/teleport.c b/src/teleport.c index fdebacffe..3088c461c 100644 --- a/src/teleport.c +++ b/src/teleport.c @@ -1458,6 +1458,14 @@ domagicportal(struct trap *ttmp) void tele_trap(struct trap *trap) { + /* a fixed-destination teleport trap could theoretically place hero onto a + * second teleport trap; prevent the recursive call from spoteffects() from + * triggering the trap at the destination */ + static boolean in_tele_trap = FALSE; + if (in_tele_trap) + return; + + in_tele_trap = TRUE; if (In_endgame(&u.uz) || Antimagic) { if (Antimagic) shieldeff(u.ux, u.uy); @@ -1478,13 +1486,19 @@ tele_trap(struct trap *trap) /* could not find some other place to put mtmp; the level must * be nearly or completely full */ You1(shudder_for_moment); - return; } - rloc_to(mtmp, cc.x, cc.y); + else { + rloc_to(mtmp, cc.x, cc.y); + mtmp = (struct monst *) 0; /* no longer a monster at dest */ + } + } + if (!mtmp) { + teleds(trap->teledest.x, trap->teledest.y, TELEDS_TELEPORT); } - teleds(trap->teledest.x, trap->teledest.y, TELEDS_TELEPORT); } else tele(); + + in_tele_trap = FALSE; } void From 50d80b5183a89e17cd0d68fce0bbeaaf3d6cb577 Mon Sep 17 00:00:00 2001 From: copperwater Date: Thu, 27 Feb 2025 17:08:31 -0500 Subject: [PATCH 466/791] Fix: map random y-placement used its width instead of height Not sure how long this has existed without triggering any issues, but when I was testing out a themed room wider than it was tall, I ran into rn2-of-a-negative-number impossibles. Traced it to here, where it was trying to subtract the width of the mapfrag from ROWNO to figure out which y-value it should place the map on. The correct behavior is to subtract the height of the mapfrag. --- src/sp_lev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sp_lev.c b/src/sp_lev.c index 66c6d2c87..73d349515 100644 --- a/src/sp_lev.c +++ b/src/sp_lev.c @@ -6133,7 +6133,7 @@ TODO: gc.coder->croom needs to be updated if (y < 1) y = 1; } else { - y = rn2(ROWNO - mf->wid); + y = rn2(ROWNO - mf->hei); } } } From 01cdf519935b01fc62b5191b67e3c49bc1365af4 Mon Sep 17 00:00:00 2001 From: copperwater Date: Fri, 28 Feb 2025 17:27:51 -0500 Subject: [PATCH 467/791] Add a bit of detail in selection.room() documentation It wasn't clear to me how selection.room() handles room edges and unusual terrain in the room, so I looked at the code and wrote down how it behaves for posterity. I don't believe the one room currently capable of getting a random fill while already containing some odd terrain, "Blocked center", actually has unusual terrain in the room fill. This is because filler_region creates an irregular region (i.e. a room containing the ROOM points in a square ring around the blocked center). The points in the middle don't share the same roomno, so they won't be returned in the selection created by selection.room(). But there's no reason a room couldn't be added in the future which does specify some nonstandard terrain and then a themeroom fill. --- doc/lua.adoc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/lua.adoc b/doc/lua.adoc index f75de0b1d..58669e9ec 100644 --- a/doc/lua.adoc +++ b/doc/lua.adoc @@ -1319,6 +1319,8 @@ Example: === room Create a selection of locations inside the (current) room. +Does not include the edges of the room, such as its walls. +Does not do any check on terrain type, so if there are non-ROOM locations inside the room, they remain part of the selection. Example: From 90d240cbb8f6cce72fe2e335aa291925749afc4b Mon Sep 17 00:00:00 2001 From: nhmall Date: Wed, 5 Mar 2025 08:17:09 -0500 Subject: [PATCH 468/791] revert assert addition --- src/botl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/botl.c b/src/botl.c index e714fbb8f..51e9fdcd3 100644 --- a/src/botl.c +++ b/src/botl.c @@ -2830,7 +2830,7 @@ parse_status_hl2(char (*s)[QBUFSZ], boolean from_configfile) else hilite.behavior = BL_TH_NONE; - assert(dt >= 0); + /* assert(dt >= 0); */ hilite.anytype = dt; if (hilite.behavior == BL_TH_TEXTMATCH && txt) { From fd49242015f0a9c3e006523a8d79eaca34cf4e56 Mon Sep 17 00:00:00 2001 From: nhmall Date: Wed, 5 Mar 2025 08:55:27 -0500 Subject: [PATCH 469/791] botl.c follow-up --- include/wintype.h | 4 +++- src/botl.c | 3 +-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/include/wintype.h b/include/wintype.h index 095c1aa60..6bf49aabb 100644 --- a/include/wintype.h +++ b/include/wintype.h @@ -55,7 +55,9 @@ enum any_types { ANY_ULPTR, /* pointer to unsigned long */ ANY_STR, /* pointer to null-terminated char string */ ANY_NFUNC, /* pointer to function taking no args, returning int */ - ANY_MASK32 /* 32-bit mask (stored as unsigned long) */ + ANY_MASK32, /* 32-bit mask (stored as unsigned long) */ + + ANY_INVALID /* leave this last */ }; /* menu return list */ diff --git a/src/botl.c b/src/botl.c index 51e9fdcd3..b8a24c780 100644 --- a/src/botl.c +++ b/src/botl.c @@ -2562,7 +2562,7 @@ parse_status_hl2(char (*s)[QBUFSZ], boolean from_configfile) "Satiated", "", "Hungry", "Weak", "Fainting", "Fainted", "Starved" }; char *tmp, *how; - int sidx = 0, i = -1, dt = -1; + int sidx = 0, i = -1, dt = ANY_INVALID; int coloridx = -1, successes = 0; int disp_attrib = 0; boolean percent, changed, numeric, down, up, @@ -2830,7 +2830,6 @@ parse_status_hl2(char (*s)[QBUFSZ], boolean from_configfile) else hilite.behavior = BL_TH_NONE; - /* assert(dt >= 0); */ hilite.anytype = dt; if (hilite.behavior == BL_TH_TEXTMATCH && txt) { From 78ca37290bde57de8c104a81b7a896911cd54ce6 Mon Sep 17 00:00:00 2001 From: nhmall Date: Wed, 5 Mar 2025 10:29:50 -0500 Subject: [PATCH 470/791] cast style tidbit --- src/artifact.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/artifact.c b/src/artifact.c index 506d50ea1..2254b3976 100644 --- a/src/artifact.c +++ b/src/artifact.c @@ -269,7 +269,7 @@ mk_artifact( non-weapons, which always have a gen_spe of 0, and for many weapons, too.) The result is clamped into the "normal" range to prevent an outside chance of +12 artifacts generating. */ - new_spe = (int)otmp->spe + a->gen_spe; + new_spe = (int) otmp->spe + a->gen_spe; if (new_spe >= -10 && new_spe < 10) otmp->spe = new_spe; } From ceee6aff31a1aad49e1d48eff4f15f0be5bd7a08 Mon Sep 17 00:00:00 2001 From: nhmall Date: Thu, 6 Mar 2025 07:20:16 -0500 Subject: [PATCH 471/791] pointer decl style consistency; use any_types enum --- include/botl.h | 4 ++-- src/decl.c | 2 +- src/mon.c | 2 +- src/mplayer.c | 2 +- src/music.c | 2 +- src/o_init.c | 2 +- src/read.c | 2 +- src/timeout.c | 2 +- 8 files changed, 9 insertions(+), 9 deletions(-) diff --git a/include/botl.h b/include/botl.h index 3ffd6be1a..87c82d25c 100644 --- a/include/botl.h +++ b/include/botl.h @@ -249,7 +249,7 @@ enum hlattribs { struct hilite_s { enum statusfields fld; boolean set; - unsigned anytype; + enum any_types anytype; anything value; int behavior; char textmatch[MAXVALWIDTH]; @@ -271,7 +271,7 @@ struct istat_s { boolean chg; /* need to recalc time? */ boolean percent_matters; short percent_value; - unsigned anytype; + enum any_types anytype; anything a, rawval; char *val; int valwidth; diff --git a/src/decl.c b/src/decl.c index e6c6f315e..617d62e86 100644 --- a/src/decl.c +++ b/src/decl.c @@ -230,7 +230,7 @@ static const struct instance_globals_a g_init_a = { static const struct instance_globals_b g_init_b = { /* botl.c */ - { { { NULL, NULL, 0L, FALSE, FALSE, 0, 0U, { 0 }, { 0 }, NULL, 0, 0, 0 + { { { NULL, NULL, 0L, FALSE, FALSE, 0, ANY_INVALID, { 0 }, { 0 }, NULL, 0, 0, 0 #ifdef STATUS_HILITES , UNDEFINED_PTR, UNDEFINED_PTR #endif diff --git a/src/mon.c b/src/mon.c index 33f2bedfa..b1ad1b3b2 100644 --- a/src/mon.c +++ b/src/mon.c @@ -1486,7 +1486,7 @@ meatmetal(struct monst *mtmp) /* monster eats a pile of objects */ int -meatobj(struct monst* mtmp) /* for gelatinous cubes */ +meatobj(struct monst *mtmp) /* for gelatinous cubes */ { struct obj *otmp, *otmp2; struct permonst *ptr, *original_ptr = mtmp->data; diff --git a/src/mplayer.c b/src/mplayer.c index 70b94b0f5..041a997ec 100644 --- a/src/mplayer.c +++ b/src/mplayer.c @@ -69,7 +69,7 @@ dev_name(void) } staticfn void -get_mplname(struct monst* mtmp, char *nam) +get_mplname(struct monst *mtmp, char *nam) { boolean fmlkind = is_female(mtmp->data); const char *devnam; diff --git a/src/music.c b/src/music.c index 374b848ab..ca8c64f31 100644 --- a/src/music.c +++ b/src/music.c @@ -159,7 +159,7 @@ calm_nymphs(int distance) /* Awake soldiers anywhere the level (and any nearby monster). */ void -awaken_soldiers(struct monst* bugler /* monster that played instrument */) +awaken_soldiers(struct monst *bugler /* monster that played instrument */) { struct monst *mtmp; int distance, distm; diff --git a/src/o_init.c b/src/o_init.c index aeff43030..1538c298d 100644 --- a/src/o_init.c +++ b/src/o_init.c @@ -347,7 +347,7 @@ shuffle_all(void) /* Return TRUE if the provided string matches the unidentified description of * the provided object. */ boolean -objdescr_is(struct obj* obj, const char * descr) +objdescr_is(struct obj *obj, const char *descr) { const char *objdescr; diff --git a/src/read.c b/src/read.c index 4344f319a..f4cc95ac6 100644 --- a/src/read.c +++ b/src/read.c @@ -2323,7 +2323,7 @@ drop_boulder_on_monster(coordxy x, coordxy y, boolean confused, boolean byu) /* overcharging any wand or zapping/engraving cursed wand */ void -wand_explode(struct obj* obj, int chg /* recharging */) +wand_explode(struct obj *obj, int chg /* recharging */) { const char *expl = !chg ? "suddenly" : "vibrates violently and"; int dmg, n, k; diff --git a/src/timeout.c b/src/timeout.c index 443a84cc7..58c575fd1 100644 --- a/src/timeout.c +++ b/src/timeout.c @@ -2726,7 +2726,7 @@ DISABLE_WARNING_FORMAT_NONLITERAL /* to support '#stats' wizard-mode command */ void -timer_stats(const char* hdrfmt, char *hdrbuf, long *count, long *size) +timer_stats(const char *hdrfmt, char *hdrbuf, long *count, long *size) { timer_element *te; From adeb69ba82480fc45955353471be7229940379c6 Mon Sep 17 00:00:00 2001 From: nhkeni Date: Fri, 7 Mar 2025 13:34:53 -0500 Subject: [PATCH 472/791] report.c: fix HASH_BINFILE typo --- src/report.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/report.c b/src/report.c index 6e82c66c3..b3e73b45a 100644 --- a/src/report.c +++ b/src/report.c @@ -45,7 +45,7 @@ # define HASH_OFLAGS O_RDONLY # define HASH_BINFILE_DECL char *binfile = argv[0]; # if (NH_DEVEL_STATUS == NH_STATUS_BETA) -# define HASH_BINFILE \ +# define HASH_BINFILE() \ if (!binfile || !*binfile) { \ /* If this triggers, investigate CFBundleGetMainBundle */ \ /* or CFBundleCopyExecutableURL. */ \ From 6a24d5ac04d4211c2e419ee47e06b5b91a2366e3 Mon Sep 17 00:00:00 2001 From: PatR Date: Fri, 7 Mar 2025 12:07:17 -0800 Subject: [PATCH 473/791] report.c tweaks The report.c bit committed today reminded me that I had an old stashed change for that file. There should be no change in behavior. --- src/report.c | 55 ++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 38 insertions(+), 17 deletions(-) diff --git a/src/report.c b/src/report.c index b3e73b45a..3eb8fd5aa 100644 --- a/src/report.c +++ b/src/report.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 report.c $NHDT-Date: 1710525914 2024/03/15 18:05:14 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.7 $ */ +/* NetHack 3.7 report.c $NHDT-Date: 1741406837 2025/03/07 20:07:17 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.16 $ */ /* Copyright (c) Kenneth Lorber, Kensington, Maryland, 2024 */ /* NetHack may be freely redistributed. See license for details. */ @@ -253,10 +253,18 @@ swr_add_uricoded( *out = markp, *remaining = 0; **out = '\0'; return TRUE; + } else { + char chr[40]; /* [4] should suffice */ + int x; + + Sprintf(chr, "%%%02X", *in); + x = (int) strlen(chr); + if (x <= *remaining) { + Strcpy(*out, chr); + *out += x; + *remaining -= x; + } } - int x = snprintf(*out, *remaining, "%%%02X", *in); - *out += x; - *remaining -= x; } in++; if (!*remaining) { @@ -289,15 +297,20 @@ submit_web_report(int cos, const char *msg, const char *why) if (!sysopt.crashreporturl) return FALSE; SWR_ADD(sysopt.crashreporturl); + /* + * Note: all snprintf() calls here changed to sprintf() to avoid + * complaints from static analyzer. All but one were unnecessary + * since they were formatting int or unsigned into a large buffer. + */ /* cos - operation, v - version */ - Snprintf(temp, sizeof temp, "?cos=%d&v=1", cos); + Sprintf(temp, "?cos=%d&v=1", cos); SWR_ADD(temp); /* msg==NULL for #bugreport */ if (msg) { SWR_ADD("&subject="); - Snprintf(temp, sizeof temp, "%s report for NetHack %s", - msg, version_string(temp2, sizeof temp2 )); + Sprintf(temp, "%.40s report for NetHack %.40s", + msg, version_string(temp2, sizeof temp2 )); SWR_ADD_URIcoded(temp); } @@ -352,7 +365,7 @@ submit_web_report(int cos, const char *msg, const char *why) # if 0 // __linux__ // not needed for MacOS // XXX is it actually needed for linux? TBD - Snprintf(temp2, sizeof temp2, "[%02lu]\n", (unsigned long) x); + Sprintf(temp2, "[%02lu]\n", (unsigned long) x); uend--; // remove the \n we added above SWR_ADD_URIcoded(temp2); # endif // linux @@ -384,7 +397,7 @@ submit_web_report(int cos, const char *msg, const char *why) // detailrows: Guess since we can't know the // width of the window. SWR_ADD("&detailrows="); - Snprintf(temp, sizeof temp, "%d", min(count + countpp, 30)); + Sprintf(temp, "%d", min(count + countpp, 30)); SWR_ADD_URIcoded(temp); full: @@ -403,7 +416,7 @@ printf("ShellExecute returned: %p\n",rv); // >32 is ok int pid = fork(); extern char **environ; if (pid == 0) { - char err[100]; + char err[400]; # ifdef CRASHREPORT_EXEC_NOSTDERR int devnull; /* Keep the output clean - firefox spews useless errors on @@ -413,7 +426,10 @@ printf("ShellExecute returned: %p\n",rv); // >32 is ok # endif (void) execve(CRASHREPORT, (char * const *) xargv, environ); - Sprintf(err, "Can't start " CRASHREPORT ": %s", strerror(errno)); + Sprintf(err, "Can't start " CRASHREPORT ": %.*s", + (int) (sizeof err + - sizeof "Can't start " CRASHREPORT ": "), + strerror(errno)); raw_print(err); # ifdef CRASHREPORT_EXEC_NOSTDERR (void) close(devnull); @@ -446,7 +462,7 @@ dobugreport(void) pline("Unable to send bug report. Please visit %s instead.", (sysopt.crashreporturl && *sysopt.crashreporturl) ? sysopt.crashreporturl - : "https://www.nethack.org" + : DEVTEAM_URL ); } return ECMD_OK; @@ -523,15 +539,15 @@ NH_panictrace_gdb(void) if (greppath == NULL || greppath[0] == 0) return FALSE; - sprintf(buf, "%s -n -q %s %d 2>&1 | %s '^#'", - gdbpath, ARGV0, getpid(), greppath); + Snprintf(buf, sizeof buf, "%s -n -q %s %d 2>&1 | %s '^#'", + gdbpath, ARGV0, getpid(), greppath); gdb = popen(buf, "w"); if (gdb) { raw_print(" Generating more information you may report:\n"); - fprintf(gdb, "bt\nquit\ny"); - fflush(gdb); + (void) fprintf(gdb, "bt\nquit\ny"); + (void) fflush(gdb); sleep(4); /* ugly */ - pclose(gdb); + (void) pclose(gdb); return TRUE; } else { return FALSE; @@ -555,6 +571,7 @@ get_saved_pline(int lineno USED_if_dumplog) #ifdef DUMPLOG_CORE int p; int limit = DUMPLOG_MSG_COUNT; + if (lineno >= DUMPLOG_MSG_COUNT) return NULL; p = (gs.saved_pline_index - 1) % DUMPLOG_MSG_COUNT; @@ -639,4 +656,8 @@ panictrace_setsignals(boolean set) # endif /* NO_SIGNAL */ #endif /* PANICTRACE */ +/* + * FIXME: this should have a lot of '#undef's for onefile support. + */ + /*report.c*/ From a6a1e1b365bf487fc17a8f0fa93612172441a042 Mon Sep 17 00:00:00 2001 From: PatR Date: Fri, 7 Mar 2025 12:14:22 -0800 Subject: [PATCH 474/791] nasty() tuning Another old stash. Slighty weakens genocide of high level monsters. --- src/wizard.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/wizard.c b/src/wizard.c index 1194aa80b..2f4b0bdb9 100644 --- a/src/wizard.c +++ b/src/wizard.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 wizard.c $NHDT-Date: 1718303204 2024/06/13 18:26:44 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.110 $ */ +/* NetHack 3.7 wizard.c $NHDT-Date: 1741407262 2025/03/07 20:14:22 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.116 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2016. */ /* NetHack may be freely redistributed. See license for details. */ @@ -662,6 +662,9 @@ nasty(struct monst *summoner) bypos.x, bypos.y, mmflags)) != 0) { m_cls = mtmp->data->mlet; if ((difcap > 0 && mtmp->data->difficulty >= difcap + /* always capping for substitutes made wanton + genocide become too strong in the endgame */ + && rn2(In_endgame(&u.uz) ? 3 : 7) /* usually */ && attacktype(mtmp->data, AT_MAGC)) || (s_cls == S_DEMON && m_cls == S_ANGEL) || (s_cls == S_ANGEL && m_cls == S_DEMON)) @@ -670,10 +673,11 @@ nasty(struct monst *summoner) } if (mtmp) { - /* create at most one arch-lich or Archon regardless - of who is doing the summoning (note: Archon is - not in nasties[] but could be chosen as random - replacement for a genocided selection) */ + /* if creating an arch-lich or Archon, further directly + selected nasties will have to be less difficult, and + substitues for geno victims will usually be less + (note: Archon is not in nasties[] but could be chosen + as random replacement for a genocided selection) */ if (mtmp->data == &mons[PM_ARCH_LICH] || mtmp->data == &mons[PM_ARCHON]) { tmp = min(mons[PM_ARCHON].difficulty, /* A:26 */ From 49b43f760f5b85011577743530cf867cbc8e91ab Mon Sep 17 00:00:00 2001 From: copperwater Date: Sat, 8 Mar 2025 07:47:28 -0500 Subject: [PATCH 475/791] Fix: a number of unblock_points shouldn't unblock unconditionally Initially diagnosed in an xnethack fuzzer crash - unblock_point shouldn't be called when a closed door becomes non-closed, because it's possible that there's a gas cloud on the space which means it still blocks vision. These always need to be recalc_block_point. A number of them were fixed, but when I went through all the xnethack ones, I found some that were unchanged from upstream NetHack. I reproduced the sanity check impossibles usually by breathing gas at a door as an iron golem and then opening or destroying the door to trigger the unblock_point call. The use of recalc_block_point in wizterrainwish was not triggering this bug, but the previous code there basically duplicated recalc_block_point. --- src/dig.c | 2 +- src/dokick.c | 2 +- src/hack.c | 2 +- src/music.c | 2 +- src/objnam.c | 9 +-------- src/trap.c | 2 +- 6 files changed, 6 insertions(+), 13 deletions(-) diff --git a/src/dig.c b/src/dig.c index 195222235..fabafac7b 100644 --- a/src/dig.c +++ b/src/dig.c @@ -1435,7 +1435,7 @@ mdig_tunnel(struct monst *mtmp) sawit = canseemon(mtmp); /* before door state change and unblock_pt */ trapped = (here->doormask & D_TRAPPED) ? TRUE : FALSE; here->doormask = trapped ? D_NODOOR : D_BROKEN; - unblock_point(mtmp->mx, mtmp->my); /* vision */ + recalc_block_point(mtmp->mx, mtmp->my); /* vision */ newsym(mtmp->mx, mtmp->my); if (trapped) { seeit = canseemon(mtmp); diff --git a/src/dokick.c b/src/dokick.c index cf8bb405b..45d0b097c 100644 --- a/src/dokick.c +++ b/src/dokick.c @@ -949,7 +949,7 @@ kick_door(coordxy x, coordxy y, int avrg_attrib) gm.maploc->doormask = D_BROKEN; } feel_newsym(x, y); /* we know we broke it */ - unblock_point(x, y); /* vision */ + recalc_block_point(x, y); /* vision */ if (shopdoor) { add_damage(x, y, SHOP_DOOR_COST); pay_for_damage("break", FALSE); diff --git a/src/hack.c b/src/hack.c index f28877e47..71d252af5 100644 --- a/src/hack.c +++ b/src/hack.c @@ -787,7 +787,7 @@ still_chewing(coordxy x, coordxy y) lev->typ = CORR; } - unblock_point(x, y); /* vision */ + recalc_block_point(x, y); /* vision */ newsym(x, y); if (digtxt) You1(digtxt); /* after newsym */ diff --git a/src/music.c b/src/music.c index ca8c64f31..21614860d 100644 --- a/src/music.c +++ b/src/music.c @@ -463,7 +463,7 @@ do_earthquake(int force) } /* wasn't doorless, now it will be */ levl[x][y].doormask = D_NODOOR; - unblock_point(x, y); + recalc_block_point(x, y); newsym(x, y); /* before pline */ if (cansee(x, y)) pline_The("door collapses."); diff --git a/src/objnam.c b/src/objnam.c index 4463a12bb..3a1cba698 100644 --- a/src/objnam.c +++ b/src/objnam.c @@ -3862,14 +3862,7 @@ wizterrainwish(struct _readobjnam_data *d) } else { if (u.utrap && u.utraptype == TT_LAVA && !is_lava(u.ux, u.uy)) reset_utrap(FALSE); - - if (does_block(x, y, lev)) { - if (!didblock) - block_point(x, y); - } else { - if (didblock) - unblock_point(x, y); - } + recalc_block_point(x, y); } /* fixups for replaced terrain that aren't handled above */ diff --git a/src/trap.c b/src/trap.c index f309dd595..934020cd1 100644 --- a/src/trap.c +++ b/src/trap.c @@ -3443,7 +3443,7 @@ launch_obj( } levl[x][y].doormask = D_BROKEN; if (dist) - unblock_point(x, y); + recalc_block_point(x, y); } /* if about to hit something, do so now */ From d0d77ed5f482784ff2d4d9064dabe1648e79288e Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 8 Mar 2025 12:51:53 -0500 Subject: [PATCH 476/791] related comments were not updated with parameters --- src/hacklib.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/hacklib.c b/src/hacklib.c index 5b61c21ea..1fb76c37a 100644 --- a/src/hacklib.c +++ b/src/hacklib.c @@ -45,9 +45,9 @@ const char * ordin (int) char * sitoa (int) int sgn (int) - int distmin (int, int, int, int) - int dist2 (int, int, int, int) - boolean online2 (int, int) + int distmin (coordxy, coordxy, coordxy, coordxy) + int dist2 (coordxy, coordxy, coordxy, coordxy) + boolean online2 (coordxy, coordxy) int strncmpi (const char *, const char *, int) char * strstri (const char *, const char *) boolean fuzzymatch (const char *, const char *, From a3c6eec5c0f7da9101118df31a3dd1c96a23d297 Mon Sep 17 00:00:00 2001 From: PatR Date: Sat, 8 Mar 2025 13:16:27 -0800 Subject: [PATCH 477/791] enlightenment about bones "You have disabled loading of bones levels" (during play) and "You disabled loading of bones levels" (end of game disclosure) both clearly refer to the player rather than the hero. "You have never encountered a bones level" is accurate for current hero but not necessarily accurate for the player. Rephrase it. Also, if OPTIONS=!bones is set and the hero just died, extend "You disabled loading of bones levels" during disclosure to "You disabled loading and storing of bones levels" (even in the case where bones wouldn't be saved anyway). --- src/insight.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/insight.c b/src/insight.c index 815f1113d..f4d0c945f 100644 --- a/src/insight.c +++ b/src/insight.c @@ -156,7 +156,11 @@ enlght_line( /* format increased chance to hit or damage or defense (Protection) */ staticfn char * -enlght_combatinc(const char *inctyp, int incamt, int final, char *outbuf) +enlght_combatinc( + const char *inctyp, /* "to hit" or "damage" or "defense" */ + int incamt, /* amount of increment (negative if decrement) */ + int final, /* ENL_{GAMEINPROGRESS,GAMEOVERALIVE,GAMEOVERDEAD} */ + char *outbuf) { const char *modif, *bonus; boolean invrt; @@ -405,9 +409,13 @@ enlightenment( } if (!flags.bones) { - you_have_X("disabled loading of bones levels"); + /* mention not saving bones iff hero just died */ + Sprintf(buf, "disabled loading%s of bones levels", + (final == ENL_GAMEOVERDEAD) ? " and storing" : ""); + you_have_X(buf); } else if (!u.uroleplay.numbones) { - you_have_never("encountered a bones level"); + enl_msg(You_, "haven't encountered", "didn't encounter", + " any bones levels", ""); } else { Sprintf(buf, "encountered %ld bones level%s", u.uroleplay.numbones, plur(u.uroleplay.numbones)); From 3b15e4fff2e16f39d084cb33b949a165ec868caa Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 9 Mar 2025 09:51:12 -0400 Subject: [PATCH 478/791] a pair of duplicate #include statements in hack.h --- include/hack.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/hack.h b/include/hack.h index 13e27653f..f2f8d979a 100644 --- a/include/hack.h +++ b/include/hack.h @@ -29,13 +29,11 @@ #include "mkroom.h" #include "obj.h" #include "quest.h" -#include "rect.h" #include "region.h" #include "rm.h" #include "selvar.h" #include "sndprocs.h" #include "spell.h" -#include "sym.h" #include "sys.h" #include "timeout.h" #include "winprocs.h" From 0a180c52efb2f1b777a566ad0b01cf1934416cd3 Mon Sep 17 00:00:00 2001 From: PatR Date: Sun, 9 Mar 2025 14:28:50 -0700 Subject: [PATCH 479/791] more issue #1362 - carrying Mitre of Holiness Protect carried items as well as hero when carrying the Mitre of Holiness. Already handled when wearing that artifact. This might make it be too strong. At the time that it was given the carrued attribute, there was no such thing as carried items providing any protection to other carried items. --- src/zap.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/zap.c b/src/zap.c index ae4a16889..3faf11645 100644 --- a/src/zap.c +++ b/src/zap.c @@ -5614,12 +5614,16 @@ u_adtyp_resistance_obj(int dmgtyp) if (!prop) return 0; - /* Items that give an extrinsic resistance give 99% protection to - your items */ - if ((u.uprops[prop].extrinsic & (W_ARMOR | W_ACCESSORY | W_WEP)) != 0) + /* FIXME? these percentages (99 and 90) seem too high... */ + + /* items that give an extrinsic resistance when worn or wielded or + carried give 99% protection to your items */ + if ((u.uprops[prop].extrinsic & (W_ARMOR | W_ACCESSORY | W_WEP | W_ART)) + != 0L) return 99; - /* Dwarvish cloaks give a 90% protection to items against heat and cold */ + /* worn dwarvish cloaks give 90% protection against heat and cold to + carried items */ if (uarmc && uarmc->otyp == DWARVISH_CLOAK && (dmgtyp == AD_COLD || dmgtyp == AD_FIRE)) return 90; From 719166f9eca14bd01b42d6cce94f684f5dec121f Mon Sep 17 00:00:00 2001 From: PatR Date: Mon, 10 Mar 2025 09:17:41 -0700 Subject: [PATCH 480/791] fix issue #1377 - Forcefight vs displacer beasts Issue reported by elunna: Using the 'F' prefix against a displacer beast prevented swapping places. This doesn't use the suggested fix. It is quite short but there is a large diff due to change in indentation and reformatting several comments because of that. Attacking a displacer beast either with or without 'F' might miss, hit, or swap places. It won't "harmlessly attack thin air." Fixes #1377 --- doc/fixes3-7-0.txt | 2 + src/hack.c | 207 +++++++++++++++++++++++---------------------- 2 files changed, 108 insertions(+), 101 deletions(-) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index a9f4960d9..9de65026b 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -2098,6 +2098,8 @@ when walking into/against a locked closed door, 'autounlock'==kick didn't having a 1% chance of creating rideable monsters with worn saddle gave knights a 1% chance of creating an extra saddle for starting pony; it wasn't tracked with other objects so produced a trivial memory leak +hen attacking a displacer beast, using the 'F' forcefight prefix prevented it + from swapping places with the hero Fixes to 3.7.0-x Platform and/or Interface Problems Exposed Via git Repository diff --git a/src/hack.c b/src/hack.c index f28877e47..dc12f6c07 100644 --- a/src/hack.c +++ b/src/hack.c @@ -1956,9 +1956,11 @@ domove_attackmon_at( && bad_rock(gy.youmonst.data, x, u.uy0)))) && goodpos(u.ux0, u.uy0, mtmp, GP_ALLOW_U)); /* if not displacing, try to attack; note that it might evade; - also, we don't attack tame when _safepet_ */ - if (!*displaceu && do_attack(mtmp)) - return TRUE; + also, we don't attack tame or peaceful when safemon() */ + if (!*displaceu) { + if (do_attack(mtmp)) + return TRUE; + } } return FALSE; } @@ -2696,119 +2698,122 @@ domove_core(void) return; } - if (domove_fight_ironbars(x, y)) - return; + if (!displaceu) { - if (domove_fight_web(x, y)) - return; + if (domove_fight_ironbars(x, y)) + return; - if (domove_fight_empty(x, y)) - return; + if (domove_fight_web(x, y)) + return; - (void) unmap_invisible(x, y); - /* not attacking an animal, so we try to move */ - if ((u.dx || u.dy) && u.usteed && stucksteed(FALSE)) { - nomul(0); - return; - } + if (domove_fight_empty(x, y)) + return; - if (u_rooted()) - return; - - /* treat entering a visible gas cloud region like entering a trap; - there could be a known trap as well as a region at the target spot; - if so, ask about entring the region first; even though this could - lead to two consecutive confirmation prompts, the situation seems to - be too uncommon to warrant a separate case with combined trap+region - confirmation */ - if (ParanoidTrap && !Blind && !Stunned && !Confusion && !Hallucination - /* skip if player used 'm' prefix or is moving recklessly */ - && (!svc.context.nopick || svc.context.run) - /* check for region(s) */ - && (newreg = visible_region_at(x, y)) != 0 - && ((oldreg = visible_region_at(u.ux, u.uy)) == 0 - /* if moving from one region into another, only ask for - confirmation if the one potentially being entered inflicts - damage (poison gas) and the one being exited doesn't (vapor) */ - || (reg_damg(newreg) > 0 && reg_damg(oldreg) == 0)) - /* check whether attempted move will be viable */ - && test_move(u.ux, u.uy, u.dx, u.dy, TEST_MOVE) - /* we don't override confirmation for poison resistance since the - region also hinders hero's vision even if/when no damage is done */ - ) { - char qbuf[QBUFSZ]; - - Snprintf(qbuf, sizeof qbuf, "%s into that %s cloud?", - u_locomotion("step"), - (reg_damg(newreg) > 0) ? "poison gas" : "vapor"); - if (!paranoid_query(ParanoidConfirm, upstart(qbuf))) { + (void) unmap_invisible(x, y); + /* not attacking an animal, so we try to move */ + if ((u.dx || u.dy) && u.usteed && stucksteed(FALSE)) { nomul(0); - svc.context.move = 0; return; } - } - /* maybe ask player for confirmation before walking into known traps */ - if (ParanoidTrap && !Stunned && !Confusion - /* skip if player used 'm' prefix or is moving recklessly */ - && (!svc.context.nopick || svc.context.run) - /* check for discovered trap */ - && (trap = t_at(x, y)) != 0 && trap->tseen - /* check whether attempted move will be viable */ - /* - * FIXME: - * this will result in "Really step into trap?" if there is a - * peaceful or tame monster already there. - */ - && test_move(u.ux, u.uy, u.dx, u.dy, TEST_MOVE) - /* override confirmation if the trap is harmless to the hero */ - && (immune_to_trap(&gy.youmonst, trap->ttyp) != TRAP_CLEARLY_IMMUNE - /* Hallucination: all traps still show as ^, but the - hero can't tell what they are, so treat as dangerous */ - || Hallucination)) { - char qbuf[QBUFSZ]; - int traptype = (Hallucination ? rnd(TRAPNUM - 1) : (int) trap->ttyp); - boolean into = into_vs_onto(traptype); - Snprintf(qbuf, sizeof qbuf, "Really %s %s that %s?", - u_locomotion("step"), into ? "into" : "onto", - defsyms[trap_to_defsym(traptype)].explanation); - /* handled like paranoid_confirm:pray; when paranoid_confirm:trap - isn't set, don't ask at all but if it is set (checked above), - ask via y/n if parnoid_confirm:confirm isn't also set or via - yes/no if it is */ - if (!paranoid_query(ParanoidConfirm, qbuf)) { - nomul(0); - svc.context.move = 0; + if (u_rooted()) + return; + + /* treat entering a visible gas cloud region like entering a trap; + there could be a known trap as well as a region at the target spot; + if so, ask about entring the region first; even though this could + lead to two consecutive confirmation prompts, the situation seems + to be too uncommon to warrant a separate case with combined + trap+region confirmation */ + if (ParanoidTrap && !Blind && !Stunned && !Confusion && !Hallucination + /* skip if player used 'm' prefix or is moving recklessly */ + && (!svc.context.nopick || svc.context.run) + /* check for region(s) */ + && (newreg = visible_region_at(x, y)) != 0 + && ((oldreg = visible_region_at(u.ux, u.uy)) == 0 + /* if moving from one region into another, only ask for + confirmation if the one potentially being entered inflicts + damage (poison gas) and the one being exited doesn't + (vapor) */ + || (reg_damg(newreg) > 0 && reg_damg(oldreg) == 0)) + /* check whether attempted move will be viable */ + && test_move(u.ux, u.uy, u.dx, u.dy, TEST_MOVE) + /* we don't override confirmation for poison resistance since + the region also hinders hero's vision even if/when no damage + is done */ + ) { + char qbuf[QBUFSZ]; + + Snprintf(qbuf, sizeof qbuf, "%s into that %s cloud?", + u_locomotion("step"), + (reg_damg(newreg) > 0) ? "poison gas" : "vapor"); + if (!paranoid_query(ParanoidConfirm, upstart(qbuf))) { + nomul(0); + svc.context.move = 0; + return; + } + } + /* maybe ask player for confirmation before walking into known trap */ + if (ParanoidTrap && !Stunned && !Confusion + /* skip if player used 'm' prefix or is moving recklessly */ + && (!svc.context.nopick || svc.context.run) + /* check for discovered trap */ + && (trap = t_at(x, y)) != 0 && trap->tseen + /* check whether attempted move will be viable */ + && test_move(u.ux, u.uy, u.dx, u.dy, TEST_MOVE) + /* override confirmation if the trap is harmless to the hero */ + && (immune_to_trap(&gy.youmonst, trap->ttyp) != TRAP_CLEARLY_IMMUNE + /* Hallucination: all traps still show as ^, but the + hero can't tell what they are, so treat as dangerous */ + || Hallucination)) { + char qbuf[QBUFSZ]; + int traptype = (Hallucination ? rnd(TRAPNUM - 1) + : (int) trap->ttyp); + boolean into = into_vs_onto(traptype); + + Snprintf(qbuf, sizeof qbuf, "Really %s %s that %s?", + u_locomotion("step"), into ? "into" : "onto", + defsyms[trap_to_defsym(traptype)].explanation); + /* handled like paranoid_confirm:pray; when paranoid_confirm:trap + isn't set, don't ask at all but if it is set (checked above), + ask via y/n if parnoid_confirm:confirm isn't also set or via + yes/no if it is */ + if (!paranoid_query(ParanoidConfirm, qbuf)) { + nomul(0); + svc.context.move = 0; + return; + } + } + + if (u.utrap) { /* when u.utrap is True, displaceu is False */ + boolean moved = trapmove(x, y, trap); + + if (!u.utrap) { + disp.botl = TRUE; + reset_utrap(TRUE); /* might resume levitation or flight */ + } + /* might not have escaped, or did escape but remain in the same + spot */ + if (!moved) + return; + } + + if (!test_move(u.ux, u.uy, x - u.ux, y - u.uy, DO_MOVE)) { + if (!svc.context.door_opened) { + svc.context.move = 0; + nomul(0); + } return; } - } - if (u.utrap) { - boolean moved = trapmove(x, y, trap); - - if (!u.utrap) { - disp.botl = TRUE; - reset_utrap(TRUE); /* might resume levitation or flight */ - } - /* might not have escaped, or did escape but remain in same spot */ - if (!moved) - return; - } - - if (!test_move(u.ux, u.uy, x - u.ux, y - u.uy, DO_MOVE)) { - if (!svc.context.door_opened) { + /* Is it dangerous to swim in water or lava? */ + if (swim_move_danger(x, y)) { svc.context.move = 0; nomul(0); + return; } - return; - } - /* Is it dangerous to swim in water or lava? */ - if (swim_move_danger(x, y)) { - svc.context.move = 0; - nomul(0); - return; - } + } /* !dislacedu */ /* Move ball and chain. */ if (Punished) From bddca2ded548215c9a93ea32abbc5419fcf10a0f Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 10 Mar 2025 17:14:24 -0400 Subject: [PATCH 481/791] musl libc build, rather than glibc We've had reports of a couple of issues building against musl libc. Issues reported: - build procedures utilize cat for Guidebook-creation, and cat is deprecated in distros that use musl libc. - some of the CRASHREPORT code is using library functions that are not available in the musl libc environment. The reported functions were backtrace() and backtrace_symbols(), which use header file /usr/include/execinfo.h. So we'll try to accommodate this. Since we don't have a means of autodetecting the musl libc situation during the build (as of yet), the builder will have to specify 'make musl=1' on the make command line. Specifying 'musl=1' on the make command line will: 1. ensure that NOCRASHREPORT gets defined in the C preprocessor. 2. set COLCMD to be '../util/stripbs' instead of 'col -bx'. Closes #1393 --- sys/unix/Makefile.doc | 16 +++++++---- sys/unix/Makefile.top | 6 +++++ sys/unix/Makefile.utl | 5 ++++ sys/unix/hints/include/multiw-2.370 | 14 ++++++++++ util/.gitignore | 1 + util/stripbs.c | 42 +++++++++++++++++++++++++++++ 6 files changed, 79 insertions(+), 5 deletions(-) create mode 100644 util/stripbs.c diff --git a/sys/unix/Makefile.doc b/sys/unix/Makefile.doc index 92473995b..2186b15d9 100644 --- a/sys/unix/Makefile.doc +++ b/sys/unix/Makefile.doc @@ -11,6 +11,8 @@ NHSROOT=.. MAKEDEFS = ../util/makedefs +#STRIPBS ?= ../util/stripbs + # Which version do we want to build? (XXX These are not used anywhere.) GUIDEBOOK = Guidebook # regular ASCII file #GUIDEBOOK = Guidebook.ps # PostScript file @@ -21,8 +23,9 @@ GUIDEBOOK = Guidebook # regular ASCII file # recognize the option. Sigh. # # col is unnecessary, but harmless, with groff. See grotty(1). -COLCMD = col -bx -#COLCMD = col -b +COLCMD ?= col -bx +#COLCMD ?= col -b +#COLCMD ?= $(STRIPBS) # The command to use to generate a PostScript file # PSCMD = ditroff | psdit @@ -59,8 +62,8 @@ ONEPAGE_PREFORMAT = cat Gbk-1pg-pfx.mn $(GUIDEBOOK_MN) Gbk-1pg-sfx.mn \ | $(NHGREP) | tbl tmac.n - # the basic guidebook -Guidebook : $(GUIDEBOOK_MN) tmac.n tmac.nh $(NEEDMAKEDEFS) - $(GUIDECMD) > Guidebook +Guidebook : $(GUIDEBOOK_MN) tmac.n tmac.nh $(NEEDMAKEDEFS) $(STRIPBS) + -$(GUIDECMD) > Guidebook # Fancier output for those with ditroff, psdit and a PostScript printer. # Could be converted to Guidebook.pdf if tool(s) for that are available. @@ -80,7 +83,10 @@ Guidebook.dvi : $(GUIDEBOOK_TEX) # (note: 'make makedefs', not 'make $(MAKEDEFS)') $(MAKEDEFS) : ../util/makedefs.c ../include/config.h ../src/mdlib.c \ ../util/mdgrep.h - ( cd ../util ; make makedefs ) + ( cd .. ; make makedefs ) + +../util/stripbx: ../util/stripbs.c + ( cd .. ; $(MAKE) stripbs ) GAME = nethack MANDIR ?= /usr/man/man6 diff --git a/sys/unix/Makefile.top b/sys/unix/Makefile.top index f3bb66d23..9323f42c8 100644 --- a/sys/unix/Makefile.top +++ b/sys/unix/Makefile.top @@ -416,6 +416,12 @@ fetch-docs: shift; \ done +makedefs: + ( cd util ; $(MAKE) makedefs ) + +stripbs: + ( cd util ; $(MAKE) stripbs ) + # 'make update' can be used to install a revised version after making # customizations or such. Unlike 'make install', it doesn't delete everything # from the target directory to have a clean start. diff --git a/sys/unix/Makefile.utl b/sys/unix/Makefile.utl index ebe974cc1..770213255 100644 --- a/sys/unix/Makefile.utl +++ b/sys/unix/Makefile.utl @@ -293,6 +293,11 @@ dlb: $(DLBOBJS) $(HACKLIB) dlb_main.o: dlb_main.c $(CONFIG_H) ../include/dlb.h $(CC) $(CFLAGS) $(CSTD) -c dlb_main.c -o $@ +stripbs: stripbs.o + $(CC) $(LFLAGS) -o stripbs stripbs.o + +stripbs.o: stripbs.c + $(CC) $(CFLAGS) -c stripbs.c # dependencies for tile utilities # diff --git a/sys/unix/hints/include/multiw-2.370 b/sys/unix/hints/include/multiw-2.370 index 938c958f3..05cd0dae5 100644 --- a/sys/unix/hints/include/multiw-2.370 +++ b/sys/unix/hints/include/multiw-2.370 @@ -194,6 +194,20 @@ CPLUSPLUS_NEEDED = 1 endif endif +ifeq "$(musl)" "1" +MUSL=1 +endif +ifeq "$(MUSL)" "1" +ifneq "$(NOCRASHREPORT)" "1" +NOCRASHREPORT=1 +endif +WINCFLAGS += -DMUSL_LIBC +# use this instead of col -bx +COLCMD = ../util/stripbs +else +WINCFLAGS += -DGNU_LIBC +endif + ifeq "$(NOCRASHREPORT)" "1" WINCFLAGS += -DNOCRASHREPORT endif diff --git a/util/.gitignore b/util/.gitignore index 6852dfc87..56d768999 100644 --- a/util/.gitignore +++ b/util/.gitignore @@ -11,6 +11,7 @@ lev_comp dlb dlb_main recover +stripbs tilemap tileedit tile2x11 diff --git a/util/stripbs.c b/util/stripbs.c new file mode 100644 index 000000000..4c7af7fed --- /dev/null +++ b/util/stripbs.c @@ -0,0 +1,42 @@ +/* NetHack 3.7 stripbs.c */ +/* Copyright (c) Michael Allison, 2025. */ +/* NetHack may be freely redistributed. See license for details. */ + +/* + * a simple filter to strip character-backspace-character + * from stdin and write the results to stdout. + */ + +#include +#include +#include +#include + +int main(int argc, char *argv[]) +{ + int stop = 0, trouble = 0; + char buf[2]; + char *cp = &buf[0], *prev = &buf[1]; + + *prev = 0; + while (!stop) { + if ((fread(buf, 1, 1, stdin)) > 0) { + if (*cp == 8) { + *prev = 0; + } else { + if (*prev) + fputc(*prev, stdout); + *prev = *cp; + } + } else { + if (errno != EOF) + trouble = 1; + if (*prev) + fputc(*prev, stdout); + stop = 1; + } + } + fflush(stdout); + fclose(stdout); + return trouble ? EXIT_FAILURE : EXIT_SUCCESS; +} From fbb8ef2fa6cdc53890a10ded866e547948e6e8f5 Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 10 Mar 2025 17:18:58 -0400 Subject: [PATCH 482/791] follow-up: set STRIPBS in Makefiles --- sys/unix/hints/include/multiw-2.370 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sys/unix/hints/include/multiw-2.370 b/sys/unix/hints/include/multiw-2.370 index 05cd0dae5..073cc9c20 100644 --- a/sys/unix/hints/include/multiw-2.370 +++ b/sys/unix/hints/include/multiw-2.370 @@ -203,7 +203,8 @@ NOCRASHREPORT=1 endif WINCFLAGS += -DMUSL_LIBC # use this instead of col -bx -COLCMD = ../util/stripbs +COLCMD=../util/stripbs +STRIPBS=../util/stripbs else WINCFLAGS += -DGNU_LIBC endif From e300c205c6818e052f5dbafd1d634cf0c899b7e2 Mon Sep 17 00:00:00 2001 From: nhw_cron Date: Mon, 10 Mar 2025 17:24:06 -0400 Subject: [PATCH 483/791] This is cron-daily v1-Apr-1-2024. 000files updated: Files --- Files | 1 + 1 file changed, 1 insertion(+) diff --git a/Files b/Files index d8bcbab2f..07d2bfb57 100644 --- a/Files +++ b/Files @@ -573,6 +573,7 @@ test_sel.lua test_shk.lua test_src.lua testmove.lua testwish.lua util: (files for all versions) dlb_main.c makedefs.c mdgrep.h mdgrep.pl panic.c recover.c +stripbs.c win/Qt: (files for the Qt 4 or 5 widget library - X11, Windows, Mac OS X) From d6829cdcd2ad9b7efe134f98cf6c7cc7588a8013 Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 10 Mar 2025 19:54:12 -0400 Subject: [PATCH 484/791] fixes entry for musl libc build, rather than glibc We've had reports of a couple of issues building against musl libc. Issues reported: - build procedures utilize col for Guidebook-creation, and col is deprecated in distros that use musl libc - some of the CRASHREPORT code is using library functions that are not available in the musl libc environment. The reported functions were backtrace() and backtrace_symbols(), which use header file /usr/include/execinfo.h. So we'll try to accommodate this. Since we don't have a means of autodetecting the musl libc situation during the build (as of yet), the builder will have to specify 'make musl=1' on the make command line. Specifying 'musl=1' on the make command line will: 1. ensure that NOCRASHREPORT gets defined in the C preprocessor. 2. set COLCMD to be '../util/stripbs' instead of 'col -bx'. Related to GitHub #1393 --- doc/fixes3-7-0.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index 9de65026b..9895169cc 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -2440,6 +2440,8 @@ Unix: re-do command line parsing Unix: add ../include/nhlua.h to the alloc.o dependencies in Makefile.utl to match Makefile.src Unix: implement SELF_RECOVER compile-time option, on by default on linux +Unix: allow build to succeed with musl (instead of glibc), by specifying + musl=1 on the make command line user_sounds: move the message hook from inside individual window display ports to the core where it allows MSGTYP_NOSHOW msgtyp's to still trigger sounds to correct a reported github issue; also fixes a past reported From 8abd9e956435e5e1014f2f5948d12ca7a9d29bcc Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 10 Mar 2025 20:29:38 -0400 Subject: [PATCH 485/791] comment wording bit --- util/stripbs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/stripbs.c b/util/stripbs.c index 4c7af7fed..49802ade0 100644 --- a/util/stripbs.c +++ b/util/stripbs.c @@ -4,7 +4,7 @@ /* * a simple filter to strip character-backspace-character - * from stdin and write the results to stdout. + * from stdin and write the final character to stdout. */ #include From 1d22a396d4744b174b478ae7159a46207904fafd Mon Sep 17 00:00:00 2001 From: PatR Date: Mon, 10 Mar 2025 21:54:22 -0700 Subject: [PATCH 486/791] fixes3-7-0 typo --- doc/fixes3-7-0.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index 9895169cc..1658e9948 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -2098,7 +2098,7 @@ when walking into/against a locked closed door, 'autounlock'==kick didn't having a 1% chance of creating rideable monsters with worn saddle gave knights a 1% chance of creating an extra saddle for starting pony; it wasn't tracked with other objects so produced a trivial memory leak -hen attacking a displacer beast, using the 'F' forcefight prefix prevented it +when attacking a displacer beast, using the 'F' forcefight prefix prevented it from swapping places with the hero From 4a67caf3d716190cac692fd3fc726ade72e6e8ed Mon Sep 17 00:00:00 2001 From: nhmall Date: Tue, 11 Mar 2025 10:27:18 -0400 Subject: [PATCH 487/791] document musl=1 in README-hints --- sys/unix/README-hints | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sys/unix/README-hints b/sys/unix/README-hints index 5a531efbd..e564aafab 100644 --- a/sys/unix/README-hints +++ b/sys/unix/README-hints @@ -45,6 +45,11 @@ make WANT_DEFAULT=X11 Make X11 the default interface if multiple window make WANT_DEFAULT=Qt Make Qt the default interface if multiple window interfaces were specified. +make musl=1 Build with settings appropriate for linking with + musl libc, instead of glibc. This causes + NOCRASHREPORT to be defined, and avoids the use + of 'col' during the build. + make CROSS_TO_MSDOS=1 package Cross-compile for an MSDOS target package. make CROSS_TO_WASM=1 Cross-compile for a WASM target. make CROSS_TO_MIPS=1 Cross-compile for a mips target. @@ -72,3 +77,4 @@ make WANT_SOURCE_INSTALL=1 Place the results of the install/update portion tree, rather than in a system-wide shared area. make VIEWDEPRECATIONS=1 Turn off the suppression of -Wdeprecated and -Wdeprecated-declarations warnings + From 8f84f76f09653ce9b7c1d80cfd77ea1c8464e893 Mon Sep 17 00:00:00 2001 From: nhmall Date: Tue, 11 Mar 2025 10:46:08 -0400 Subject: [PATCH 488/791] stop a warning when compiling util/stripbs.c --- util/stripbs.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/util/stripbs.c b/util/stripbs.c index 49802ade0..fbe8316c6 100644 --- a/util/stripbs.c +++ b/util/stripbs.c @@ -12,7 +12,13 @@ #include #include -int main(int argc, char *argv[]) +#if defined(__GNUC__) +#define UNUSED __attribute__((unused)) +#else +#define UNUSED +#endif + +int main(int argc UNUSED, char *argv[] UNUSED) { int stop = 0, trouble = 0; char buf[2]; From 31d86a8c418f2bbe50543ef5697d126bd04da51f Mon Sep 17 00:00:00 2001 From: PatR Date: Wed, 12 Mar 2025 01:28:05 -0700 Subject: [PATCH 489/791] trapped box->tknown If 'autounlock' is set to test a chest for traps, skip "check for traps?" when tknown is set; go directly to "disarm trap?" if the chest is trapped, skip that too if it isn't. If wand of probing hits a chest, set the tknown bit. --- src/lock.c | 13 +++---------- src/zap.c | 14 +++++++++----- 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/src/lock.c b/src/lock.c index 47e160b7a..2fe2a198a 100644 --- a/src/lock.c +++ b/src/lock.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 lock.c $NHDT-Date: 1718745135 2024/06/18 21:12:15 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.137 $ */ +/* NetHack 3.7 lock.c $NHDT-Date: 1741793439 2025/03/12 07:30:39 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.145 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2011. */ /* NetHack may be freely redistributed. See license for details. */ @@ -432,14 +432,6 @@ pick_lock( boolean it; int count; - /* - * FIXME: - * (chest->otrapped && chest->tknown) is handled, to skip - * checking for a trap and continue with asking about disarm; - * (chest->tknown && !chest->otrapped) ignores tknown and will - * ask about checking for non-existant trap. - */ - if (u.dz < 0 && !autounlock) { /* beware stale u.dz value */ There("isn't any sort of lock up %s.", Levitation ? "here" : "there"); @@ -478,7 +470,8 @@ pick_lock( if (autounlock && (flags.autounlock & AUTOUNLOCK_UNTRAP) != 0 && could_untrap(FALSE, TRUE) - && (c = ynq(safe_qbuf(qbuf, "Check ", " for a trap?", + && (c = otmp->tknown ? (otmp->otrapped ? 'y' : 'n') + : ynq(safe_qbuf(qbuf, "Check ", " for a trap?", otmp, yname, ysimple_name, "this"))) != 'n') { if (c == 'q') diff --git a/src/zap.c b/src/zap.c index 3faf11645..7118ca4da 100644 --- a/src/zap.c +++ b/src/zap.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 zap.c $NHDT-Date: 1737344505 2025/01/19 19:41:45 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.562 $ */ +/* NetHack 3.7 zap.c $NHDT-Date: 1741793439 2025/03/12 07:30:39 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.564 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2013. */ /* NetHack may be freely redistributed. See license for details. */ @@ -2209,10 +2209,14 @@ bhito(struct obj *obj, struct obj *otmp) obj->dknown = 1; if (Is_container(obj) || obj->otyp == STATUE) { obj->cknown = obj->lknown = 1; - /* plural handling here is superfluous because containers - and statues don't stack */ - if (obj->otrapped) - pline("%s trapped!", Tobjnam(obj, "are")); + if (Is_box(obj) && !obj->tknown) { + /* obj->tknown applies to boxes and chests, not bags or + statues; plural handling here and the "empty" case + below are superfluous because containers don't stack */ + if (obj->otrapped) + pline("%s trapped!", Tobjnam(obj, "are")); + obj->tknown = 1; + } if (!obj->cobj) { pline("%s empty.", Tobjnam(obj, "are")); From dfe2a967fc6643190ec5e8558c61bc124266a6cc Mon Sep 17 00:00:00 2001 From: nhmall Date: Thu, 13 Mar 2025 07:40:20 -0400 Subject: [PATCH 490/791] fix a recent typo --- sys/unix/Makefile.doc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/unix/Makefile.doc b/sys/unix/Makefile.doc index 2186b15d9..56d6818c3 100644 --- a/sys/unix/Makefile.doc +++ b/sys/unix/Makefile.doc @@ -85,7 +85,7 @@ $(MAKEDEFS) : ../util/makedefs.c ../include/config.h ../src/mdlib.c \ ../util/mdgrep.h ( cd .. ; make makedefs ) -../util/stripbx: ../util/stripbs.c +../util/stripbs: ../util/stripbs.c ( cd .. ; $(MAKE) stripbs ) GAME = nethack From 67dc6662acd871f36aca39540a20956ef82f06db Mon Sep 17 00:00:00 2001 From: nhkeni Date: Thu, 13 Mar 2025 12:48:07 -0400 Subject: [PATCH 491/791] remove bogus content from template file --- doc/fixesX-X-X.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/fixesX-X-X.txt b/doc/fixesX-X-X.txt index 4ce05819f..462dd5f60 100644 --- a/doc/fixesX-X-X.txt +++ b/doc/fixesX-X-X.txt @@ -14,7 +14,6 @@ Platform- and/or Interface-Specific Fixes General New Features -------------------- -Conway's Life bigroom variant Platform- and/or Interface-Specific New Features From 9b0724f8f23aa87ed26ecbc5f623e90c7a5ff9a7 Mon Sep 17 00:00:00 2001 From: nhmall Date: Thu, 13 Mar 2025 12:57:55 -0400 Subject: [PATCH 492/791] update tested versions of Visual Studio 2025-03-13 --- sys/windows/Makefile.nmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sys/windows/Makefile.nmake b/sys/windows/Makefile.nmake index 2618f65b6..40fe46230 100644 --- a/sys/windows/Makefile.nmake +++ b/sys/windows/Makefile.nmake @@ -9,7 +9,7 @@ # # Visual Studio Compilers Tested: # - Microsoft Visual Studio 2019 Community Edition v 16.11.42 -# - Microsoft Visual Studio 2022 Community Edition v 17.13.0 +# - Microsoft Visual Studio 2022 Community Edition v 17.13.3 # #============================================================================== # This is used for building two distinct executables of NetHack: @@ -1177,7 +1177,7 @@ rc=Rc.exe # # Recently tested versions: TESTEDVS2019 = 14.29.30157.0 -TESTEDVS2022 = 14.43.34808.0 +TESTEDVS2022 = 14.43.34809.0 VS2019CUR = $(TESTEDVS2019:.=) VS2022CUR = $(TESTEDVS2022:.=) From 90717ca633685478f5a309fd697a424ac38bf5b4 Mon Sep 17 00:00:00 2001 From: PatR Date: Thu, 13 Mar 2025 13:54:56 -0700 Subject: [PATCH 493/791] more chest->tknown handling Disarming a chest trap was setting obj->tknown = 0 even though the hero just discovered that it isn't trapped. Triggering a chest trap behaved similarly. Since there are no repeating chest traps, hero should know that the chest whose trap just went off is no longer trapped. chest_trap() didn't document its return value but was clearly meant to return True if the chest was destroyed. It didn't handle that correctly when the chest was being carried. However, none of the callers actually use the return value. [This fix tracks whether the chest gets deleted; a better fix would be to destroy an exploding chest even when it is being carried.] --- doc/fixes3-7-0.txt | 3 +++ src/trap.c | 29 +++++++++++++++++++---------- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index 1658e9948..bce39a4d1 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -2100,6 +2100,9 @@ having a 1% chance of creating rideable monsters with worn saddle gave knights tracked with other objects so produced a trivial memory leak when attacking a displacer beast, using the 'F' forcefight prefix prevented it from swapping places with the hero +successfully disarming a chest trap was clearing the chest's 'tknown' bit + instead of setting it; likewise when failing to disarm triggered and + used up the trap Fixes to 3.7.0-x Platform and/or Interface Problems Exposed Via git Repository diff --git a/src/trap.c b/src/trap.c index f309dd595..53fa65f5e 100644 --- a/src/trap.c +++ b/src/trap.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 trap.c $NHDT-Date: 1720128169 2024/07/04 21:22:49 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.602 $ */ +/* NetHack 3.7 trap.c $NHDT-Date: 1741926700 2025/03/13 20:31:40 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.621 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2013. */ /* NetHack may be freely redistributed. See license for details. */ @@ -5711,7 +5711,7 @@ disarm_box(struct obj *box, boolean force, boolean confused) } else { You("disarm it!"); box->otrapped = 0; - box->tknown = 0; + box->tknown = 1; more_experienced(8, 0); newexplevel(); } @@ -6194,7 +6194,8 @@ openfallingtrap( return result; } -/* only called when the player is doing something to the chest directly */ +/* only called when the player is doing something to the chest directly; + returns True if chest is destroyed, False if it remains in play */ boolean chest_trap( struct obj *obj, @@ -6209,9 +6210,9 @@ chest_trap( if (get_obj_location(obj, &cc.x, &cc.y, 0)) /* might be carried */ obj->ox = cc.x, obj->oy = cc.y; - otmp->tknown = 0; + otmp->tknown = 0; /* for xname(); will be set to 1 below */ otmp->otrapped = 0; /* trap is one-shot; clear flag first in case - chest kills you and ends up in bones file */ + * chest kills you and ends up in bones file */ You(disarm ? "set it off!" : "trigger a trap!"); display_nhwindow(WIN_MESSAGE, FALSE); if (Luck > -13 && rn2(13 + Luck) > 7) { /* saved by luck */ @@ -6256,7 +6257,7 @@ chest_trap( case 21: { struct monst *shkp = 0; long loss = 0L; - boolean costly, insider; + boolean costly, insider, chestgone; coordxy ox = obj->ox, oy = obj->oy; /* the obj location need not be that of player */ @@ -6286,28 +6287,35 @@ chest_trap( && uball->ox == ox && uball->oy == oy))) unpunish(); /* destroy everything at the spot (the Amulet, the - invocation tools, and Rider corpses will remain intact) */ + invocation tools, and Rider corpses will remain intact); + usually the chest will be destroyed along with the stuff at + this spot, but not if it is being carried */ + chestgone = FALSE; for (otmp = svl.level.objects[ox][oy]; otmp; otmp = otmp2) { otmp2 = otmp->nexthere; if (costly) loss += stolen_value(otmp, otmp->ox, otmp->oy, (boolean) shkp->mpeaceful, TRUE); + if (otmp == obj) + chestgone = TRUE; delobj(otmp); } wake_nearby(FALSE); losehp(Maybe_Half_Phys(d(6, 6)), buf, KILLED_BY_AN); exercise(A_STR, FALSE); if (costly && loss) { - if (insider) + if (insider) { You("owe %ld %s for objects destroyed.", loss, currency(loss)); - else { + } else { You("caused %ld %s worth of damage!", loss, currency(loss)); make_angry_shk(shkp, ox, oy); } } - return TRUE; + if (chestgone) + return TRUE; + break; /* set tknown and return False */ } /* case 21 */ case 20: case 19: @@ -6392,6 +6400,7 @@ chest_trap( bot(); /* to get immediate botl re-display */ } + otmp->tknown = 1; /* hero knows chest is no longer trapped */ return FALSE; } From ef4cd7608d48481b9ad59ba42ea596e9d5a7e749 Mon Sep 17 00:00:00 2001 From: nhmall Date: Fri, 14 Mar 2025 10:34:22 -0400 Subject: [PATCH 494/791] follow-up for pull-request #1397 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix warnings objnam.c: In function ‘wizterrainwish’: objnam.c:3536:54: warning: variable ‘didblock’ set but not used [-Wunused-but-set-variable] 3536 | boolean madeterrain = FALSE, badterrain = FALSE, didblock, is_dbridge; | ^~~~~~~~ --- src/objnam.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/objnam.c b/src/objnam.c index 3a1cba698..b4e4ae8dd 100644 --- a/src/objnam.c +++ b/src/objnam.c @@ -3533,7 +3533,7 @@ staticfn struct obj * wizterrainwish(struct _readobjnam_data *d) { struct rm *lev; - boolean madeterrain = FALSE, badterrain = FALSE, didblock, is_dbridge; + boolean madeterrain = FALSE, badterrain = FALSE, is_dbridge; int trap; unsigned oldtyp, ltyp; coordxy x = u.ux, y = u.uy; @@ -3565,7 +3565,6 @@ wizterrainwish(struct _readobjnam_data *d) lev = &levl[x][y]; oldtyp = lev->typ; is_dbridge = (oldtyp == DRAWBRIDGE_DOWN || oldtyp == DRAWBRIDGE_UP); - didblock = does_block(x, y, lev); p = eos(bp); if (!BSTRCMPI(bp, p - 8, "fountain")) { lev->typ = FOUNTAIN; From 488011571ac74db4858bd5964c39ab037de28373 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sat, 15 Mar 2025 22:20:59 +0200 Subject: [PATCH 495/791] Fix vision when vault guard corridor vanishes --- src/vault.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vault.c b/src/vault.c index 8bc79e6c7..dc95128d0 100644 --- a/src/vault.c +++ b/src/vault.c @@ -978,6 +978,7 @@ gd_move(struct monst *grd) (void) rloc(grd, RLOC_MSG); levl[m][n].typ = egrd->fakecorr[0].ftyp; levl[m][n].flags = egrd->fakecorr[0].flags; + recalc_block_point(m, n); /* guard corridor goes away */ del_engr_at(m, n); newsym(m, n); grd->mpeaceful = 0; From b169b79d36a3360b7faa962980a967c2d7577fff Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 15 Mar 2025 19:55:49 -0400 Subject: [PATCH 496/791] dump monster and obj weights using --dumpweights --- include/extern.h | 1 + include/hack.h | 1 + include/objects.h | 2 +- src/allmain.c | 4 ++ src/hack.c | 101 +++++++++++++++++++++++++++++++++++++++++ sys/unix/unixmain.c | 3 ++ sys/windows/windmain.c | 3 ++ 7 files changed, 114 insertions(+), 1 deletion(-) diff --git a/include/extern.h b/include/extern.h index c5b0b0af9..3a7041556 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1194,6 +1194,7 @@ extern int near_capacity(void); extern int calc_capacity(int); extern int max_capacity(void); extern boolean check_capacity(const char *); +extern void dump_weights(void); extern int inv_cnt(boolean); /* sometimes money_cnt(gi.invent) which can be null */ extern long money_cnt(struct obj *) NO_NNARGS; diff --git a/include/hack.h b/include/hack.h index f2f8d979a..d356d64c5 100644 --- a/include/hack.h +++ b/include/hack.h @@ -440,6 +440,7 @@ enum earlyarg { #endif , ARG_DUMPGLYPHIDS , ARG_DUMPMONGEN + , ARG_DUMPWEIGHTS #ifdef WIN32 , ARG_WINDOWS #endif diff --git a/include/objects.h b/include/objects.h index 784b66c36..93866d1a5 100644 --- a/include/objects.h +++ b/include/objects.h @@ -1501,7 +1501,7 @@ COIN("gold piece", 1000, GOLD, 1, GOLD_PIECE), OBJECT(OBJ(name, desc), \ BITS(0, 1, 0, 0, 0, 0, 0, 0, 0, \ HARDGEM(mohs), 0, -P_SLING, glass), \ - 0, GEM_CLASS, prob, 0, 1, gval, 3, 3, 0, 0, nutr, color, sn) + 0, GEM_CLASS, prob, 0, wt, gval, 3, 3, 0, 0, nutr, color, sn) #define ROCK(name,desc,kn,prob,wt,gval,sdam,ldam,mgc,nutr,mohs,glass,colr,sn) \ OBJECT(OBJ(name, desc), \ BITS(kn, 1, 0, 0, mgc, 0, 0, 0, 0, \ diff --git a/src/allmain.c b/src/allmain.c index f65ce13b2..f3fe1decd 100644 --- a/src/allmain.c +++ b/src/allmain.c @@ -938,6 +938,7 @@ static const struct early_opt earlyopts[] = { #endif { ARG_DUMPGLYPHIDS, "dumpglyphids", 12, FALSE }, { ARG_DUMPMONGEN, "dumpmongen", 10, FALSE }, + { ARG_DUMPWEIGHTS, "dumpweights", 11, FALSE }, #ifdef WIN32 { ARG_WINDOWS, "windows", 4, TRUE }, #endif @@ -1042,6 +1043,9 @@ argcheck(int argc, char *argv[], enum earlyarg e_arg) case ARG_DUMPMONGEN: dump_mongen(); return 2; + case ARG_DUMPWEIGHTS: + dump_weights(); + return 2; #ifdef CRASHREPORT case ARG_BIDSHOW: crashreport_bidshow(); diff --git a/src/hack.c b/src/hack.c index 8f4a21fc9..6d282e896 100644 --- a/src/hack.c +++ b/src/hack.c @@ -49,6 +49,7 @@ staticfn void move_update(boolean); staticfn int pickup_checks(void); staticfn void maybe_wail(void); staticfn boolean water_turbulence(coordxy *, coordxy *); +staticfn int QSORTCALLBACK cmp_weights(const void *, const void *); #define IS_SHOP(x) (svr.rooms[x].rtype >= SHOPBASE) @@ -4293,6 +4294,106 @@ check_capacity(const char *str) return 0; } +struct weight_table_entry { + unsigned wtyp; /* 1 = monst, 2 = obj */ + const char *nm; + int wt, idx; + boolean unique; +}; + +static struct weight_table_entry *weightlist; + +void +dump_weights(void) +{ + int i, cnt = 0, nmwidth = 49, mcount = NUMMONS, ocount = NUM_OBJECTS; + char nmbuf[BUFSZ], nmbufbase[BUFSZ]; + struct obj o = cg.zeroobj; + + weightlist = (struct weight_table_entry *) alloc(sizeof(struct weight_table_entry) + * (mcount + ocount)); + decl_globals_init(); + init_objects(); + o.quan = 1; + o.known = o.dknown == 1; + for (i = 0; i < mcount; ++i) { + if (i != PM_LONG_WORM_TAIL) { + weightlist[cnt].idx = i; + weightlist[cnt].wtyp = 1; + weightlist[cnt].nm = dupstr(mons[i].pmnames[NEUTRAL]); + weightlist[cnt].wt = (int) mons[i].cwt; + weightlist[cnt].unique = ((mons[i].geno & G_UNIQ) != 0); + cnt++; + } + } + for (i = 0; i < ocount; ++i) { + int wt = (int) objects[i].oc_weight; + if (wt && i != SLIME_MOLD && obj_descr[i].oc_name) { + weightlist[cnt].idx = i; + o.otyp = i; + o.oclass = objects[i].oc_class; + weightlist[cnt].wtyp = 2; + weightlist[cnt].nm = dupstr(obj_descr[i].oc_name); + weightlist[cnt].wt = wt; + weightlist[cnt].unique = (objects[i].oc_unique != 0); + cnt++; + } + } + qsort((genericptr_t) weightlist, cnt, + sizeof (struct weight_table_entry), cmp_weights); + raw_printf("int all_weights[] = {"); + for (i = 0; i < cnt; ++i) { + if (weightlist[i].wtyp == 1) { + boolean cm = CapitalMon(weightlist[i].nm); + + Snprintf(nmbuf, sizeof nmbuf, "%s%s", "the body of ", + (cm) ? the(weightlist[i].nm) + : weightlist[i].unique ? weightlist[i].nm + : an(weightlist[i].nm)); + } else { + Snprintf(nmbufbase, sizeof nmbufbase, "%s%s", + objects[weightlist[i].idx].oc_class == POTION_CLASS + ? "potion of " + : objects[weightlist[i].idx].oc_class == WAND_CLASS + ? "wand of " + : objects[weightlist[i].idx].oc_class == SCROLL_CLASS + ? "scroll of " + : objects[weightlist[i].idx].oc_class == SPBOOK_CLASS + ? "spellbook of " + : "", + weightlist[i].nm); + Snprintf(nmbuf, sizeof nmbuf, "%s", + (weightlist[i].unique) ? the(nmbufbase) : an(nmbufbase)); + } + raw_printf(" %7u%s /* %*s */", weightlist[i].wt, + (i == cnt - 1) ? " " : ",", -nmwidth, nmbuf); + if (weightlist[i].nm) + free((genericptr_t) weightlist[i].nm), weightlist[i].nm = 0; + } + raw_print("};"); + raw_print(""); + free((genericptr_t) weightlist); + freedynamicdata(); +} + +staticfn int QSORTCALLBACK +cmp_weights(const void *p1, const void *p2) +{ + struct weight_table_entry *i1 = (struct weight_table_entry *) p1, + *i2 = (struct weight_table_entry *) p2; + int x1 = i1->wt << 17, x2 = i2->wt << 17, + t1 = ((i1->wtyp == 1) ? 0 : 1) << 16, + t2 = ((i2->wtyp == 1) ? 0 : 1) << 16; + + x1 |= t1 | ((i1->nm != 0) ? i1->nm[0] : 0) << 8; + x2 |= t2 | ((i2->nm != 0) ? i2->nm[0] : 0) << 8; + + x1 |= ((i1->nm != 0) ? i1->nm[1] : 0); + x2 |= ((i2->nm != 0) ? i2->nm[1] : 0); + + return (x1 - x2); +} + int inv_cnt(boolean incl_gold) { diff --git a/sys/unix/unixmain.c b/sys/unix/unixmain.c index 154c7e15b..6e943d685 100644 --- a/sys/unix/unixmain.c +++ b/sys/unix/unixmain.c @@ -662,6 +662,9 @@ early_options(int *argc_p, char ***argv_p, char **hackdir_p) } else if (argcheck(argc, argv, ARG_DUMPMONGEN) == 2) { opt_terminate(); /*NOTREACHED*/ + } else if (argcheck(argc, argv, ARG_DUMPWEIGHTS) == 2) { + opt_terminate(); + /*NOTREACHED*/ } else { #ifdef CHDIR oldargc = argc; diff --git a/sys/windows/windmain.c b/sys/windows/windmain.c index c622a707e..45282b446 100644 --- a/sys/windows/windmain.c +++ b/sys/windows/windmain.c @@ -487,6 +487,9 @@ early_options(int argc, char *argv[]) if (argcheck(argc, argv, ARG_DUMPMONGEN) == 2) { nethack_exit(EXIT_SUCCESS); } + if (argcheck(argc, argv, ARG_DUMPWEIGHTS) == 2) { + nethack_exit(EXIT_SUCCESS); + } if (argcheck(argc, argv, ARG_DEBUG) == 1) { argc--; argv++; From ef6ca6c5fa7412158950c34923b421cd02f5a746 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 15 Mar 2025 23:18:01 -0400 Subject: [PATCH 497/791] follow-up for --dumpweights Use a string compare for the sort and encode the weight at the beginning of the string --- src/hack.c | 82 +++++++++++++++++++++++++----------------------------- 1 file changed, 38 insertions(+), 44 deletions(-) diff --git a/src/hack.c b/src/hack.c index 6d282e896..2ff02af11 100644 --- a/src/hack.c +++ b/src/hack.c @@ -4296,7 +4296,7 @@ check_capacity(const char *str) struct weight_table_entry { unsigned wtyp; /* 1 = monst, 2 = obj */ - const char *nm; + const char *nm; /* 0-6 = weight in ascii; 7 - end = name */ int wt, idx; boolean unique; }; @@ -4308,34 +4308,56 @@ dump_weights(void) { int i, cnt = 0, nmwidth = 49, mcount = NUMMONS, ocount = NUM_OBJECTS; char nmbuf[BUFSZ], nmbufbase[BUFSZ]; - struct obj o = cg.zeroobj; weightlist = (struct weight_table_entry *) alloc(sizeof(struct weight_table_entry) * (mcount + ocount)); decl_globals_init(); init_objects(); - o.quan = 1; - o.known = o.dknown == 1; for (i = 0; i < mcount; ++i) { if (i != PM_LONG_WORM_TAIL) { + boolean cm; + + weightlist[cnt].wt = (int) mons[i].cwt; weightlist[cnt].idx = i; weightlist[cnt].wtyp = 1; - weightlist[cnt].nm = dupstr(mons[i].pmnames[NEUTRAL]); - weightlist[cnt].wt = (int) mons[i].cwt; weightlist[cnt].unique = ((mons[i].geno & G_UNIQ) != 0); + Snprintf(nmbuf, sizeof nmbuf, "%07u", weightlist[cnt].wt); + cm = CapitalMon(mons[i].pmnames[NEUTRAL]); + Snprintf(&nmbuf[7], sizeof nmbuf - 7, "%s%s", "the body of ", + (cm) ? the(mons[i].pmnames[NEUTRAL]) + : weightlist[cnt].unique ? mons[i].pmnames[NEUTRAL] + : an(mons[i].pmnames[NEUTRAL])); + weightlist[cnt].nm = dupstr(nmbuf); cnt++; } } for (i = 0; i < ocount; ++i) { int wt = (int) objects[i].oc_weight; + if (wt && i != SLIME_MOLD && obj_descr[i].oc_name) { weightlist[cnt].idx = i; - o.otyp = i; - o.oclass = objects[i].oc_class; + weightlist[cnt].wt = wt; weightlist[cnt].wtyp = 2; - weightlist[cnt].nm = dupstr(obj_descr[i].oc_name); weightlist[cnt].wt = wt; weightlist[cnt].unique = (objects[i].oc_unique != 0); + Snprintf( + nmbufbase, sizeof nmbufbase, "%s%s", + objects[weightlist[cnt].idx].oc_class == POTION_CLASS + ? "potion of " + : objects[weightlist[cnt].idx].oc_class == WAND_CLASS + ? "wand of " + : objects[weightlist[cnt].idx].oc_class == SCROLL_CLASS + ? "scroll of " + : (objects[weightlist[cnt].idx].oc_class == SPBOOK_CLASS + && objects[weightlist[cnt].idx].oc_name_idx != SPE_BOOK_OF_THE_DEAD) + ? "spellbook of " + : "", + obj_descr[weightlist[cnt].idx].oc_name); + Snprintf(nmbuf, sizeof nmbuf, "%07u", wt); + Snprintf(&nmbuf[7], sizeof nmbuf - 7, "%s", + (weightlist[cnt].unique) ? the(nmbufbase) + : an(nmbufbase)); + weightlist[cnt].nm = dupstr(nmbuf); cnt++; } } @@ -4343,32 +4365,12 @@ dump_weights(void) sizeof (struct weight_table_entry), cmp_weights); raw_printf("int all_weights[] = {"); for (i = 0; i < cnt; ++i) { - if (weightlist[i].wtyp == 1) { - boolean cm = CapitalMon(weightlist[i].nm); - - Snprintf(nmbuf, sizeof nmbuf, "%s%s", "the body of ", - (cm) ? the(weightlist[i].nm) - : weightlist[i].unique ? weightlist[i].nm - : an(weightlist[i].nm)); - } else { - Snprintf(nmbufbase, sizeof nmbufbase, "%s%s", - objects[weightlist[i].idx].oc_class == POTION_CLASS - ? "potion of " - : objects[weightlist[i].idx].oc_class == WAND_CLASS - ? "wand of " - : objects[weightlist[i].idx].oc_class == SCROLL_CLASS - ? "scroll of " - : objects[weightlist[i].idx].oc_class == SPBOOK_CLASS - ? "spellbook of " - : "", - weightlist[i].nm); - Snprintf(nmbuf, sizeof nmbuf, "%s", - (weightlist[i].unique) ? the(nmbufbase) : an(nmbufbase)); - } - raw_printf(" %7u%s /* %*s */", weightlist[i].wt, - (i == cnt - 1) ? " " : ",", -nmwidth, nmbuf); - if (weightlist[i].nm) + if (weightlist[i].nm) { + raw_printf(" %7u%s /* %*s */", weightlist[i].wt, + (i == cnt - 1) ? " " : ",", -nmwidth, + &weightlist[i].nm[7]); free((genericptr_t) weightlist[i].nm), weightlist[i].nm = 0; + } } raw_print("};"); raw_print(""); @@ -4381,17 +4383,9 @@ cmp_weights(const void *p1, const void *p2) { struct weight_table_entry *i1 = (struct weight_table_entry *) p1, *i2 = (struct weight_table_entry *) p2; - int x1 = i1->wt << 17, x2 = i2->wt << 17, - t1 = ((i1->wtyp == 1) ? 0 : 1) << 16, - t2 = ((i2->wtyp == 1) ? 0 : 1) << 16; - x1 |= t1 | ((i1->nm != 0) ? i1->nm[0] : 0) << 8; - x2 |= t2 | ((i2->nm != 0) ? i2->nm[0] : 0) << 8; - - x1 |= ((i1->nm != 0) ? i1->nm[1] : 0); - x2 |= ((i2->nm != 0) ? i2->nm[1] : 0); - - return (x1 - x2); + /* return (i1->wt - i2->wt); */ + return strcmp(i1->nm, i2->nm); } int From b2c071bc661907d7c4f5c7385b3c402379754d4d Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sun, 16 Mar 2025 09:46:50 +0200 Subject: [PATCH 498/791] Fix rare door in corner of room bug There were couple reports of doors being generated in a corner of a room. This happened for randomly generated irregular rooms, because the code that was deciding if a corridor starting or ending location was good did not handle irregular rooms at all. This changes the corridor code so it can now generate start and end points properly for any valid position in irregular rooms, instead of only on the edges. This means the corridor sometimes meanders a bit more than before, because it tries to find the end point away from the edge of the room rectangle. Also added is sanity checking for the randomly generated rooms and corridors level, testing for door placement and room connectivity. And another fix for a rare special case where dig_corridor created a zero-tile long corridor; the entrance door was placed, but there was nothing behind it. Fixes github #1269 and #1385 --- include/extern.h | 2 +- src/mklev.c | 246 +++++++++++++++++++++++++++++++++++++---------- src/mkmap.c | 2 +- src/sp_lev.c | 10 +- 4 files changed, 205 insertions(+), 55 deletions(-) diff --git a/include/extern.h b/include/extern.h index 3a7041556..78ca5fd26 100644 --- a/include/extern.h +++ b/include/extern.h @@ -2972,7 +2972,7 @@ extern void flip_level_rnd(int, boolean); extern boolean check_room(coordxy *, coordxy *, coordxy *, coordxy *, boolean) NONNULLPTRS; extern boolean create_room(coordxy, coordxy, coordxy, coordxy, coordxy, coordxy, xint16, xint16); -extern boolean dig_corridor(coord *, coord *, boolean, schar, schar) NONNULLARG12; +extern boolean dig_corridor(coord *, coord *, int *, boolean, schar, schar) NONNULLARG12; extern void fill_special_room(struct mkroom *) NO_NNARGS; extern void wallify_map(coordxy, coordxy, coordxy, coordxy); extern boolean load_special(const char *) NONNULLARG1; diff --git a/src/mklev.c b/src/mklev.c index 6cffe2a52..6939d3906 100644 --- a/src/mklev.c +++ b/src/mklev.c @@ -23,6 +23,8 @@ staticfn void mk_knox_portal(coordxy, coordxy); staticfn void makevtele(void); staticfn void fill_ordinary_room(struct mkroom *, boolean) NONNULLARG1; staticfn void themerooms_post_level_generate(void); +staticfn boolean chk_okdoor(coordxy, coordxy); +staticfn void mklev_sanity_check(void); staticfn void makelevel(void); staticfn boolean bydoor(coordxy, coordxy); staticfn void mktrap_victim(struct trap *); @@ -42,8 +44,10 @@ staticfn void do_room_or_subroom(struct mkroom *, coordxy, coordxy, coordxy, coordxy, boolean, schar, boolean, boolean); staticfn void makerooms(void); -staticfn boolean door_into_nonjoined(coordxy, coordxy); -staticfn boolean finddpos(coord *, coordxy, coordxy, coordxy, coordxy); +staticfn boolean good_rm_wall_doorpos(coordxy, coordxy, int, struct mkroom *); +staticfn boolean finddpos_shift(coordxy *, coordxy *, int, struct mkroom *); + +staticfn boolean finddpos(coord *, int, struct mkroom *); #define create_vault() create_room(-1, -1, 2, 2, -1, -1, VAULT, TRUE) #define init_vault() gv.vault_x = -1 @@ -63,57 +67,135 @@ mkroom_cmp(const genericptr vx, const genericptr vy) return (x->lx > y->lx); } -/* Return TRUE if a door placed at (x, y) which otherwise passes okdoor() - * checks would be connecting into an area that was declared as joined=false. - * Checking for this in finddpos() enables us to have rooms with sub-areas - * (such as shops) that will never randomly generate unwanted doors in order - * to connect them up to other areas. - */ +/* is x,y a good location for a door into room? */ staticfn boolean -door_into_nonjoined(coordxy x, coordxy y) +good_rm_wall_doorpos(coordxy x, coordxy y, int dir, struct mkroom *room) { - coordxy tx, ty, i; + coordxy tx, ty; + int rmno; - for (i = 0; i < 4; i++) { - tx = x + xdir[dirs_ord[i]]; - ty = y + ydir[dirs_ord[i]]; - if (!isok(tx, ty) || IS_OBSTRUCTED(levl[tx][ty].typ)) - continue; + if (!isok(x, y) || !room->needjoining) + return FALSE; - /* Is this connecting to a room that doesn't want joining? */ - if (levl[tx][ty].roomno >= ROOMOFFSET - && !svr.rooms[levl[tx][ty].roomno - ROOMOFFSET].needjoining) { - return TRUE; + if (!(levl[x][y].typ == HWALL + || levl[x][y].typ == VWALL + || IS_DOOR(levl[x][y].typ) + || levl[x][y].typ == SDOOR)) + return FALSE; + + if (bydoor(x, y)) + return FALSE; + + tx = x + xdir[dir]; + ty = y + ydir[dir]; + + if (!isok(tx,ty) || IS_OBSTRUCTED(levl[tx][ty].typ)) + return FALSE; + + rmno = (room - svr.rooms) + ROOMOFFSET; + + if (rmno != levl[tx][ty].roomno) + return FALSE; + + return TRUE; +} + +/* starting from x,y going towards dir, find a good location for a door */ +staticfn boolean +finddpos_shift(coordxy *x, coordxy *y, int dir, struct mkroom *aroom) +{ + coordxy dx, dy; + + dir = DIR_180(dir); + + dx = xdir[dir]; + dy = ydir[dir]; + + if (good_rm_wall_doorpos(*x, *y, dir, aroom)) + return TRUE; + + /* irregular rooms may have the room wall away from the room rectangular + area; go into the area until we encounter something */ + if (aroom->irregular) { + coordxy rx = *x, ry = *y; + boolean fail = FALSE; + + while (!fail && isok(rx, ry) + && (levl[rx][ry].typ == STONE || levl[rx][ry].typ == CORR)) { + rx += dx; + ry += dy; + if (good_rm_wall_doorpos(rx, ry, dir, aroom)) { + *x = rx; + *y = ry; + return TRUE; + } + if (!(levl[rx][ry].typ == STONE || levl[rx][ry].typ == CORR)) + fail = TRUE; + if (rx < aroom->lx || rx > aroom->hx + || ry < aroom->ly || ry > aroom->hy) + fail = TRUE; } } return FALSE; } +/* find a valid door position at room edge. + dir is the preferred edge of the room. + if found, returns TRUE and the coordinate in cc */ staticfn boolean -finddpos( - coord *cc, - coordxy xl, coordxy yl, - coordxy xh, coordxy yh) +finddpos(coord *cc, int dir, struct mkroom *aroom) { coordxy x, y; + coordxy x1, y1, x2, y2; + int tryct = 0; - x = rn1(xh - xl + 1, xl); - y = rn1(yh - yl + 1, yl); - if (okdoor(x, y) && !door_into_nonjoined(x, y)) - goto gotit; + switch (dir) { + case DIR_N: + x1 = aroom->lx; + x2 = aroom->hx; + y1 = aroom->ly - 1; + y2 = aroom->ly - 1; + break; + case DIR_S: + x1 = aroom->lx; + x2 = aroom->hx; + y1 = aroom->hy + 1; + y2 = aroom->hy + 1; + break; + case DIR_W: + x1 = aroom->lx - 1; + x2 = aroom->lx - 1; + y1 = aroom->ly; + y2 = aroom->hy; + break; + case DIR_E: + x1 = aroom->hx + 1; + x2 = aroom->hx + 1; + y1 = aroom->ly; + y2 = aroom->hy; + break; + default: + impossible("finddpos: illegal dir"); + return FALSE; + } - for (x = xl; x <= xh; x++) - for (y = yl; y <= yh; y++) - if (okdoor(x, y) && !door_into_nonjoined(x, y)) + /* try random points */ + do { + x = (x2 - x1) ? rn1(x2 - x1 + 1, x1) : x1; + y = (y2 - y1) ? rn1(y2 - y1 + 1, y1) : y1; + if (finddpos_shift(&x, &y, dir, aroom)) + goto gotit; + } while (++tryct < 20); + + /* try all the points */ + for (x = x1; x <= x2; x++) + for (y = y1; y <= y2; y++) + if (finddpos_shift(&x, &y, dir, aroom)) goto gotit; - for (x = xl; x <= xh; x++) - for (y = yl; y <= yh; y++) - if (IS_DOOR(levl[x][y].typ) || levl[x][y].typ == SDOOR) - goto gotit; /* cannot find something reasonable -- strange */ - cc->x = xl; - cc->y = yh; + cc->x = x1; + cc->y = y1; return FALSE; gotit: cc->x = x; @@ -349,6 +431,8 @@ join(int a, int b, boolean nxcor) coordxy tx, ty, xx, yy; struct mkroom *croom, *troom; int dx, dy; + int npoints; + boolean dig_result; croom = &svr.rooms[a]; troom = &svr.rooms[b]; @@ -366,36 +450,36 @@ join(int a, int b, boolean nxcor) dy = 0; xx = croom->hx + 1; tx = troom->lx - 1; - if (!finddpos(&cc, xx, croom->ly, xx, croom->hy)) + if (!finddpos(&cc, DIR_E, croom)) return; - if (!finddpos(&tt, tx, troom->ly, tx, troom->hy)) + if (!finddpos(&tt, DIR_W, troom)) return; } else if (troom->hy < croom->ly) { dy = -1; dx = 0; yy = croom->ly - 1; ty = troom->hy + 1; - if (!finddpos(&cc, croom->lx, yy, croom->hx, yy)) + if (!finddpos(&cc, DIR_N, croom)) return; - if (!finddpos(&tt, troom->lx, ty, troom->hx, ty)) + if (!finddpos(&tt, DIR_S, troom)) return; } else if (troom->hx < croom->lx) { dx = -1; dy = 0; xx = croom->lx - 1; tx = troom->hx + 1; - if (!finddpos(&cc, xx, croom->ly, xx, croom->hy)) + if (!finddpos(&cc, DIR_W, croom)) return; - if (!finddpos(&tt, tx, troom->ly, tx, troom->hy)) + if (!finddpos(&tt, DIR_E, troom)) return; } else { dy = 1; dx = 0; yy = croom->hy + 1; ty = troom->ly - 1; - if (!finddpos(&cc, croom->lx, yy, croom->hx, yy)) + if (!finddpos(&cc, DIR_S, croom)) return; - if (!finddpos(&tt, troom->lx, ty, troom->hx, ty)) + if (!finddpos(&tt, DIR_N, troom)) return; } xx = cc.x; @@ -404,16 +488,20 @@ join(int a, int b, boolean nxcor) ty = tt.y - dy; if (nxcor && levl[xx + dx][yy + dy].typ != STONE) return; - if (okdoor(xx, yy) || !nxcor) - dodoor(xx, yy, croom); org.x = xx + dx; org.y = yy + dy; dest.x = tx; dest.y = ty; - if (!dig_corridor(&org, &dest, nxcor, - svl.level.flags.arboreal ? ROOM : CORR, STONE)) + dig_result = dig_corridor(&org, &dest, &npoints, nxcor, + svl.level.flags.arboreal ? ROOM : CORR, STONE); + + /* we created at least 1 tile of corridor, even if it failed */ + if ((npoints > 0) && (okdoor(xx, yy) || !nxcor)) + dodoor(xx, yy, croom); + + if (!dig_result) return; /* we succeeded in digging the corridor */ @@ -616,13 +704,11 @@ place_niche( if (rn2(2)) { *dy = 1; - if (!finddpos(&dd, aroom->lx, aroom->hy + 1, - aroom->hx, aroom->hy + 1)) + if (!finddpos(&dd, DIR_S, aroom)) return FALSE; } else { *dy = -1; - if (!finddpos(&dd, aroom->lx, aroom->ly - 1, - aroom->hx, aroom->ly - 1)) + if (!finddpos(&dd, DIR_N, aroom)) return FALSE; } *xx = dd.x; @@ -1103,6 +1189,60 @@ themerooms_post_level_generate(void) lua_gc(themes, LUA_GCCOLLECT); } +/* if x,y is door, does it open into solid terrain */ +staticfn boolean +chk_okdoor(coordxy x, coordxy y) +{ + if (IS_DOOR(levl[x][y].typ)) { + if (levl[x][y].horizontal) { + if ((isok(x, y-1) && (levl[x][y-1].typ > TREE)) + && (isok(x, y+1) && (levl[x][y+1].typ <= TREE))) + return FALSE; + if ((isok(x, y-1) && (levl[x][y-1].typ <= TREE)) + && (isok(x, y+1) && (levl[x][y+1].typ > TREE))) + return FALSE; + } else { + if ((isok(x-1, y) && (levl[x-1][y].typ > TREE)) + && (isok(x+1, y) && (levl[x+1][y].typ <= TREE))) + return FALSE; + if ((isok(x-1, y) && (levl[x-1][y].typ <= TREE)) + && (isok(x+1, y) && (levl[x+1][y].typ > TREE))) + return FALSE; + } + return TRUE; + } + return TRUE; +} + +/* check mklev created level sanity */ +staticfn void +mklev_sanity_check(void) +{ + coordxy x, y; + int i; + int rmno = -1; + + if (!(iflags.sanity_check || iflags.debug_fuzzer)) + return; + + for (y = 0; y < ROWNO; y++) { + for (x = 1; x < COLNO; x++) { + if (!chk_okdoor(x,y)) + impossible("levl[%i][%i] door not ok", x, y); + } + } + + for (i = 0; i < svn.nroom; i++) { + if (!svr.rooms[i].needjoining) + continue; + if (rmno == -1) + rmno = gs.smeq[i]; + if (rmno != -1 && gs.smeq[i] != rmno) + impossible("room %i not connected?", i); + } +} + + staticfn void makelevel(void) { @@ -1166,6 +1306,8 @@ makelevel(void) makecorridors(); make_niches(); + mklev_sanity_check(); + /* make a secret treasure vault, not connected to the rest */ if (do_vault()) { coordxy w, h; diff --git a/src/mkmap.c b/src/mkmap.c index 2c5fb53ec..fdf50649c 100644 --- a/src/mkmap.c +++ b/src/mkmap.c @@ -313,7 +313,7 @@ join_map(schar bg_typ, schar fg_typ) em.y = croom2->ly + ((croom2->hy - croom2->ly) / 2); } - (void) dig_corridor(&sm, &em, FALSE, fg_typ, bg_typ); + (void) dig_corridor(&sm, &em, NULL, FALSE, fg_typ, bg_typ); /* choose next region to join */ /* only increment croom if croom and croom2 are non-overlapping */ diff --git a/src/sp_lev.c b/src/sp_lev.c index 73d349515..8bd135217 100644 --- a/src/sp_lev.c +++ b/src/sp_lev.c @@ -2535,10 +2535,12 @@ search_door( * Dig a corridor between two points, using terrain ftyp. * if nxcor is TRUE, he corridor may be blocked by a boulder, * or just end without reaching the destination. + * if not null, npoints has the number of map locations used */ boolean dig_corridor( coord *org, coord *dest, + int *npoints, boolean nxcor, schar ftyp, schar btyp) { @@ -2546,6 +2548,8 @@ dig_corridor( struct rm *crm; int tx, ty, xx, yy; + if (npoints) + *npoints = 0; xx = org->x; yy = org->y; tx = dest->x; @@ -2582,8 +2586,12 @@ dig_corridor( crm = &levl[xx][yy]; if (crm->typ == btyp) { if (ftyp == CORR && maybe_sdoor(100)) { + if (npoints) + (*npoints)++; crm->typ = SCORR; } else { + if (npoints) + (*npoints)++; crm->typ = ftyp; if (nxcor && !rn2(50)) (void) mksobj_at(BOULDER, xx, yy, TRUE, FALSE); @@ -2704,7 +2712,7 @@ create_corridor(corridor *c) dest.x++; break; } - (void) dig_corridor(&org, &dest, FALSE, CORR, STONE); + (void) dig_corridor(&org, &dest, NULL, FALSE, CORR, STONE); } } From e164ce0af45579644a5e8521430103696b642c74 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 16 Mar 2025 08:41:08 -0400 Subject: [PATCH 499/791] rings were missed in --dumpweights text --- src/hack.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/hack.c b/src/hack.c index 2ff02af11..d8389da4a 100644 --- a/src/hack.c +++ b/src/hack.c @@ -4348,6 +4348,8 @@ dump_weights(void) ? "wand of " : objects[weightlist[cnt].idx].oc_class == SCROLL_CLASS ? "scroll of " + : objects[weightlist[cnt].idx].oc_class == RING_CLASS + ? "ring of " : (objects[weightlist[cnt].idx].oc_class == SPBOOK_CLASS && objects[weightlist[cnt].idx].oc_name_idx != SPE_BOOK_OF_THE_DEAD) ? "spellbook of " From 53cbccdb86ba06f27fdf0a87d18c6dcb77752a10 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 16 Mar 2025 08:42:42 -0400 Subject: [PATCH 500/791] warning bit from the door fix earlier mklev.c(97,14): warning C4389: '!=': signed/unsigned mismatch --- src/mklev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mklev.c b/src/mklev.c index 6939d3906..add7d733d 100644 --- a/src/mklev.c +++ b/src/mklev.c @@ -94,7 +94,7 @@ good_rm_wall_doorpos(coordxy x, coordxy y, int dir, struct mkroom *room) rmno = (room - svr.rooms) + ROOMOFFSET; - if (rmno != levl[tx][ty].roomno) + if (rmno != (int) levl[tx][ty].roomno) return FALSE; return TRUE; From 7c4365458097600cd8220b39a56f98fabaaf347e Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sun, 16 Mar 2025 20:29:24 +0200 Subject: [PATCH 501/791] Lua: allow functions for some optional strings Those places that use get_table_str_opt() to get an optional string value can instead use a function that returns a string. This can be used for example in quest data lua table, or some table fields in the lua api bindings, or the dungeon definition. For example, in quest.lua text = "You again sense %l pleading for help.", could be replaced with text = function() return "You again sense %l pleading for help."; end, which of course allows using lua to build the string. --- src/nhlua.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/nhlua.c b/src/nhlua.c index dc2c64911..6342f949c 100644 --- a/src/nhlua.c +++ b/src/nhlua.c @@ -1021,9 +1021,18 @@ char * get_table_str_opt(lua_State *L, const char *name, char *defval) { const char *ret; + int ltyp; lua_getfield(L, -1, name); - ret = luaL_optstring(L, -1, defval); + ltyp = lua_type(L, -1); + if (ltyp == LUA_TSTRING || ltyp == LUA_TNIL) { + ret = luaL_optstring(L, -1, defval); + } else if (ltyp == LUA_TFUNCTION) { + nhl_pcall_handle(L, 0, 1, "get_table_str_opt", NHLpa_panic); + ret = luaL_optstring(L, -1, defval); + } else { + nhl_error(L, "get_table_str_opt: no string"); + } if (ret) { lua_pop(L, 1); return dupstr(ret); From 0bdf9830e60decbaf564991fa106400753cd9825 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 16 Mar 2025 15:37:49 -0400 Subject: [PATCH 502/791] throw-and-return weapons used by monsters Resolves #1338 --- include/extern.h | 2 + include/hack.h | 6 ++ include/mfndpos.h | 36 ++++----- src/dothrow.c | 7 +- src/mhitu.c | 7 +- src/monmove.c | 63 +++++++++++----- src/mthrowu.c | 182 +++++++++++++++++++++++++++++++++++++++++++--- src/weapon.c | 52 ++++++++++++- 8 files changed, 301 insertions(+), 54 deletions(-) diff --git a/include/extern.h b/include/extern.h index 78ca5fd26..2290f9711 100644 --- a/include/extern.h +++ b/include/extern.h @@ -3648,6 +3648,8 @@ extern int weapon_hit_bonus(struct obj *) NO_NNARGS; extern int weapon_dam_bonus(struct obj *) NO_NNARGS; extern void skill_init(const struct def_skill *) NONNULLARG1; extern void setmnotwielded(struct monst *, struct obj *) NONNULLARG1; +extern const struct throw_and_return_weapon *autoreturn_weapon(struct obj *) + NONNULLARG1; /* ### were.c ### */ diff --git a/include/hack.h b/include/hack.h index d356d64c5..3e0b9c306 100644 --- a/include/hack.h +++ b/include/hack.h @@ -868,6 +868,12 @@ enum stoning_checks { st_all = (st_gloves | st_corpse | st_petrifies | st_resists) }; +struct throw_and_return_weapon { + short otyp; + int range; + Bitfield(tethered, 1); +}; + struct trapinfo { struct obj *tobj; coordxy tx, ty; diff --git a/include/mfndpos.h b/include/mfndpos.h index a49f13262..762f5cdb9 100644 --- a/include/mfndpos.h +++ b/include/mfndpos.h @@ -6,26 +6,28 @@ #ifndef MFNDPOS_H #define MFNDPOS_H -#define ALLOW_MDISP 0x00001000L /* can displace a monster out of its way */ -#define ALLOW_TRAPS 0x00020000L /* can enter traps */ -#define ALLOW_U 0x00040000L /* can attack you */ -#define ALLOW_M 0x00080000L /* can attack other monsters */ -#define ALLOW_TM 0x00100000L /* can attack tame monsters */ +/* clang-format off */ +#define ALLOW_MDISP 0x00001000L /* can displace a monster out of its way */ +#define ALLOW_TRAPS 0x00020000L /* can enter traps */ +#define ALLOW_U 0x00040000L /* can attack you */ +#define ALLOW_M 0x00080000L /* can attack other monsters */ +#define ALLOW_TM 0x00100000L /* can attack tame monsters */ #define ALLOW_ALL (ALLOW_U | ALLOW_M | ALLOW_TM | ALLOW_TRAPS) -#define NOTONL 0x00200000L /* avoids direct line to player */ -#define OPENDOOR 0x00400000L /* opens closed doors */ -#define UNLOCKDOOR 0x00800000L /* unlocks locked doors */ -#define BUSTDOOR 0x01000000L /* breaks any doors */ -#define ALLOW_ROCK 0x02000000L /* pushes rocks */ -#define ALLOW_WALL 0x04000000L /* walks thru walls */ -#define ALLOW_DIG 0x08000000L /* digs */ -#define ALLOW_BARS 0x10000000L /* may pass thru iron bars */ -#define ALLOW_SANCT 0x20000000L /* enters temples */ -#define ALLOW_SSM 0x40000000L /* ignores scare monster */ +#define NOTONL 0x00200000L /* avoids direct line to player */ +#define OPENDOOR 0x00400000L /* opens closed doors */ +#define UNLOCKDOOR 0x00800000L /* unlocks locked doors */ +#define BUSTDOOR 0x01000000L /* breaks any doors */ +#define ALLOW_ROCK 0x02000000L /* pushes rocks */ +#define ALLOW_WALL 0x04000000L /* walks thru walls */ +#define ALLOW_DIG 0x08000000L /* digs */ +#define ALLOW_BARS 0x10000000L /* may pass thru iron bars */ +#define ALLOW_SANCT 0x20000000L /* enters temples */ +#define ALLOW_SSM 0x40000000L /* ignores scare monster */ #ifdef NHSTDC -#define NOGARLIC 0x80000000UL /* hates garlic */ +#define NOGARLIC 0x80000000UL /* hates garlic */ #else -#define NOGARLIC 0x80000000L /* hates garlic */ +#define NOGARLIC 0x80000000L /* hates garlic */ #endif +/* clang-format on */ #endif /* MFNDPOS_H */ diff --git a/src/dothrow.c b/src/dothrow.c index 28df7b30b..4c4665ef5 100644 --- a/src/dothrow.c +++ b/src/dothrow.c @@ -1476,10 +1476,11 @@ throwit(struct obj *obj, { struct monst *mon; int range, urange; + const struct throw_and_return_weapon *arw = autoreturn_weapon(obj); boolean crossbowing, impaired = (Confusion || Stunned || Blind || Hallucination || Fumbling), - tethered_weapon = (obj->otyp == AKLYS && (wep_mask & W_WEP) != 0); + tethered_weapon = (arw && arw->tethered && (wep_mask & W_WEP) != 0); gn.notonhead = FALSE; /* reset potentially stale value */ if ((obj->cursed || obj->greased) && (u.dx || u.dy) && !rn2(7)) { @@ -1616,9 +1617,9 @@ throwit(struct obj *obj, else if (is_art(obj, ART_MJOLLNIR)) range = (range + 1) / 2; /* it's heavy */ else if (tethered_weapon) /* primary weapon is aklys */ - /* if an aklys is going to return, range is limited by the + /* range of a tethered_weapon is limited by the length of the attached cord [implicit aspect of item] */ - range = min(range, BOLT_LIM / 2); + range = min(range, arw->range); else if (obj == uball && u.utrap && u.utraptype == TT_INFLOOR) range = 1; diff --git a/src/mhitu.c b/src/mhitu.c index 32cb68a14..363c19cd4 100644 --- a/src/mhitu.c +++ b/src/mhitu.c @@ -470,7 +470,7 @@ mattacku(struct monst *mtmp) struct permonst *mdat = mtmp->data; /* * ranged: Is it near you? Affects your actions. - * ranged2: Does it think it's near you? Affects its actions. + * range2: Does it think it's near you? Affects its actions. * foundyou: Is it attacking you or your image? * youseeit: Can you observe the attack? It might be attacking your * image around the corner, or invisible, or you might be blind. @@ -497,11 +497,10 @@ mattacku(struct monst *mtmp) return 0; u.ustuck->mux = u.ux; u.ustuck->muy = u.uy; - range2 = 0; - foundyou = 1; if (u.uinvulnerable) return 0; /* stomachs can't hurt you! */ - + range2 = 0; + foundyou = 1; } else if (u.usteed) { if (mtmp == u.usteed) /* Your steed won't attack you */ diff --git a/src/monmove.c b/src/monmove.c index 1c10644cb..17c7d7f83 100644 --- a/src/monmove.c +++ b/src/monmove.c @@ -23,7 +23,7 @@ staticfn int postmov(struct monst *, struct permonst *, coordxy, coordxy, int, unsigned, boolean, boolean, boolean) NONNULLPTRS; staticfn boolean leppie_avoidance(struct monst *); staticfn void leppie_stash(struct monst *); -staticfn boolean m_balks_at_approaching(struct monst *); +staticfn int m_balks_at_approaching(int, struct monst *, int *, int *); staticfn boolean stuff_prevents_passage(struct monst *); staticfn int vamp_shift(struct monst *, struct permonst *, boolean); staticfn void maybe_spin_web(struct monst *); @@ -1170,32 +1170,57 @@ leppie_stash(struct monst *mtmp) } } -/* does monster want to avoid you? */ -staticfn boolean -m_balks_at_approaching(struct monst *mtmp) +/* does monster want to avoid you? + * returns the original value of appr if not. + * returns -1 if so. + * returns -2 if monster wants to adhere to a particular range, + * which may actually be further away, + * and sets *pdistmin and *pdistmax to describe that range + */ +staticfn int +m_balks_at_approaching(int oldappr, struct monst *mtmp, int *pdistmin, + int *pdistmax) { + struct obj *mwep = MON_WEP(mtmp); + coordxy x = mtmp->mx, y = mtmp->my, ux = mtmp->mux, uy = mtmp->muy; + int edist = dist2(x, y, ux, uy); + const struct throw_and_return_weapon *arw; + + if (pdistmin) + *pdistmin = 0; + if (pdistmax) + *pdistmax = 0; + /* peaceful, far away, or can't see you */ - if (mtmp->mpeaceful - || (dist2(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy) >= 5*5) - || !m_canseeu(mtmp)) - return FALSE; + if (mtmp->mpeaceful || (edist >= 5 * 5) || !m_canseeu(mtmp)) + return oldappr; /* has ammo+launcher */ if (m_has_launcher_and_ammo(mtmp)) - return TRUE; + return -1; /* is using a polearm and in range */ if (MON_WEP(mtmp) && is_pole(MON_WEP(mtmp)) - && dist2(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy) <= MON_POLE_DIST) - return TRUE; + && edist <= MON_POLE_DIST) + return -1; + + /* is using a throw-and-return weapon; provide min and max preferred range + */ + if (mwep && (arw = autoreturn_weapon(mwep)) != 0) { + if (pdistmin) + *pdistmin = 2 * 2; + if (pdistmax) + *pdistmax = arw->range * arw->range; + return -2; + } /* can attack from distance, and hp loss or attack not used */ if (ranged_attk_available(mtmp) && ((mtmp->mhp < (mtmp->mhpmax+1) / 3) || !mtmp->mspec_used)) - return TRUE; + return -1; - return FALSE; + return oldappr; /* leaves appr unchanged */ } staticfn boolean @@ -1697,7 +1722,8 @@ m_move(struct monst *mtmp, int after) boolean better_with_displacing = FALSE; unsigned seenflgs; struct permonst *ptr; - int chi, mmoved = MMOVE_NOTHING; /* not strictly nec.: chi >= 0 will do */ + int chi, mmoved = MMOVE_NOTHING, /* not strictly nec.: chi >= 0 will do */ + preferredrange_min = 0, preferredrange_max = 0; long info[9]; long flag; coordxy omx = mtmp->mx, omy = mtmp->my; @@ -1848,8 +1874,7 @@ m_move(struct monst *mtmp, int after) appr = -1; /* hostiles with ranged weapon or attack try to stay away */ - if (m_balks_at_approaching(mtmp)) - appr = -1; + appr = m_balks_at_approaching(appr, mtmp, &preferredrange_min, &preferredrange_max); if (!should_see && can_track(ptr)) { coord *cp; @@ -1942,7 +1967,11 @@ m_move(struct monst *mtmp, int after) nearer = ((ndist = dist2(nx, ny, ggx, ggy)) < nidist); if ((appr == 1 && nearer) || (appr == -1 && !nearer) - || (!appr && !rn2(++chcnt)) || (mmoved == MMOVE_NOTHING)) { + || (!appr && !rn2(++chcnt)) + || (appr == -2 + && ((ndist <= preferredrange_min && !nearer) + || (ndist >= preferredrange_max && nearer))) + || (mmoved == MMOVE_NOTHING)) { nix = nx; niy = ny; nidist = ndist; diff --git a/src/mthrowu.c b/src/mthrowu.c index 6dc82377e..c22ba9340 100644 --- a/src/mthrowu.c +++ b/src/mthrowu.c @@ -12,6 +12,7 @@ staticfn const char *breathwep_name(int); staticfn boolean drop_throw(struct obj *, boolean, coordxy, coordxy); staticfn boolean blocking_terrain(coordxy, coordxy); staticfn int m_lined_up(struct monst *, struct monst *) NONNULLARG12; +staticfn void return_from_mtoss(struct monst *, struct obj *, boolean); #define URETREATING(x, y) \ (distmin(u.ux, u.uy, x, y) > distmin(u.ux0, u.uy0, x, y)) @@ -558,6 +559,10 @@ m_throw( boolean forcehit; char sym = obj->oclass; int hitu = 0, oldumort, blindinc = 0; + const struct throw_and_return_weapon *arw = autoreturn_weapon(obj); + boolean tethered_weapon = + (obj == MON_WEP(mon) && arw && arw->tethered != 0), + return_flightpath = FALSE; gb.bhitpos.x = x; gb.bhitpos.y = y; @@ -619,8 +624,30 @@ m_throw( * early to avoid the dagger bug, anyone who modifies this code should * be careful not to use either one after it's been freed. */ - if (sym) - tmp_at(DISP_FLASH, obj_to_glyph(singleobj, rn2_on_display_rng)); + if (sym) { + if (!tethered_weapon) { + tmp_at(DISP_FLASH, obj_to_glyph(singleobj, rn2_on_display_rng)); + } else { + tmp_at(DISP_TETHER, obj_to_glyph(singleobj, rn2_on_display_rng)); + /* + * Considerations for a tethered object based on in throwit()/bhit() : + * - wall of water/lava will stop items, and triggers return. + * - iron bars will stop items, and triggers return. + * - pass harmlessly through shades. + * X stops forward motion at hit monster/hero, triggers return. + * - closed door will stop item's forward motion, triggers return. + * - sinks stop forward motion, triggers fall, then return. + * - object can get tangled in a web, no return (tether snaps?). + * On return: + * X rn2(100) chance of returning to thrower's location. + * X if impaired and rn2(100) == 0, + * -50/50 chance of landing on the ground. + * -50/50 chance of hitting the thrower and causing + * rnd(3) damage. + * + */ + } + } while (range-- > 0) { /* Actually the loop is always exited by break */ singleobj->ox = gb.bhitpos.x += dx; singleobj->oy = gb.bhitpos.y += dy; @@ -730,7 +757,12 @@ m_throw( } stop_occupation(); if (hitu) { - (void) drop_throw(singleobj, hitu, u.ux, u.uy); + if (!tethered_weapon) { + (void) drop_throw(singleobj, hitu, u.ux, u.uy); + } else { + /* ready for return journey */ + return_flightpath = TRUE; + } break; } } @@ -751,8 +783,12 @@ m_throw( && (cansee(gb.bhitpos.x, gb.bhitpos.y) || (gm.marcher && canseemon(gm.marcher)))) pline("%s misses.", The(mshot_xname(singleobj))); - - (void) drop_throw(singleobj, 0, gb.bhitpos.x, gb.bhitpos.y); + if (!tethered_weapon) { + (void) drop_throw(singleobj, 0, gb.bhitpos.x, gb.bhitpos.y); + } else { + /*ready for return journey */ + return_flightpath = TRUE; + } } break; } @@ -761,7 +797,11 @@ m_throw( } tmp_at(gb.bhitpos.x, gb.bhitpos.y); nh_delay_output(); - tmp_at(DISP_END, 0); + if (arw && return_flightpath) + return_from_mtoss(mon, singleobj, tethered_weapon); + /* mon could be DEADMONSTER now */ + else + tmp_at(DISP_END, 0); gm.mesg_given = 0; /* reset */ if (blindinc) { @@ -777,6 +817,121 @@ m_throw( #undef MT_FLIGHTCHECK +staticfn void +return_from_mtoss(struct monst *magr, struct obj *otmp, boolean tethered_weapon) +{ + boolean impaired = (magr->mconf || magr->mstun || magr->mblinded), + notcaught = FALSE, hits_thrower = FALSE; + coordxy x = gb.bhitpos.x, y = gb.bhitpos.y; + int made_it_back = rn2(100), dmg = 0; + + if (otmp && made_it_back) { + /* it made it back to thrower's location */ + if (tethered_weapon) { + tmp_at(DISP_END, BACKTRACK); + } else { + int dx = sgn(x - magr->mx), + dy = sgn(y - magr->my); + + if (x != magr->mx || y != magr->my) { + tmp_at(DISP_FLASH, obj_to_glyph(otmp, rn2_on_display_rng)); + while (isok(x, y) && (x != magr->mx || y != magr->my)) { + tmp_at(x, y); + nh_delay_output(); + x -= dx; + y -= dy; + } + tmp_at(DISP_END, 0); + } + } + x = magr->mx; + y = magr->my; + if (!impaired && rn2(100)) { + static long do_not_annoy = 0; + + if (!do_not_annoy || (svm.moves - do_not_annoy) > 500) { + pline("%s to %s %s!", Tobjnam(otmp, "return"), + s_suffix(mon_nam(magr)), mbodypart(magr, HAND)); + do_not_annoy = svm.moves; + } + if (otmp) { + add_to_minv(magr, otmp); + if (tethered_weapon) { + magr->mw = otmp; + otmp->owornmask |= W_WEP; + } + } + if (cansee(x, y)) + newsym(x, y); + } else { + boolean mlevitating = FALSE; /* msg future-proofing only */ + + dmg = rn2(2); + if (!dmg) { + if (!Blind) { + pline("%s back to %s, landing %s %s %s.", + Tobjnam(otmp, "return"), mon_nam(magr), + mlevitating ? "beneath" : "at", mhis(magr), + makeplural(mbodypart(magr, FOOT))); + } else if (!Deaf) { + You_hear("%s land near %s.", Something, mon_nam(magr)); + } + } else { + dmg += rnd(3); + if (!Blind) { + pline("%s back toward %s, hitting %s %s!", + Tobjnam(otmp, "fly"), + mon_nam(magr), + mhis(magr), + body_part(ARM)); + } else if (!Deaf) { + You_hear("%s hit %s with a thud!", something, + mon_nam(magr)); + } + hits_thrower = TRUE; + } + notcaught = TRUE; + } + } else { + /* it didn't make it back to thrower's location */ + if (tethered_weapon) + tmp_at(DISP_END, 0); + You_hear("a loud snap!"); + notcaught = TRUE; + } + if (otmp) { + if (hits_thrower) { + if (otmp->oartifact) + (void) artifact_hit((struct monst *) 0, magr, otmp, &dmg, 0); + magr->mhp -= dmg; + /* magr could be a DEADMONSTER now */ + } + if (notcaught) { + (void) snuff_candle(otmp); + if (!ship_object(otmp, x, y, FALSE)) { + if (flooreffects(otmp, x, y, "drop")) { + if (cansee(x, y)) + newsym(x, y); + return; + } + place_object(otmp, x, y); + stackobj(otmp); + } + if (!Deaf && !Underwater) { + /* Some sound effects when item lands in water or lava */ + if (is_pool(x, y) || (is_lava(x, y) && !is_flammable(otmp))) { + Soundeffect(se_splash, 50); + pline((weight(otmp) > 9) ? "Splash!" : "Plop!"); + } + } + if (obj_sheds_light(otmp)) + gv.vision_full_recalc = 1; + } + } + if (cansee(x, y)) + newsym(x, y); +} + /* Monster throws item at another monster */ int thrwmm(struct monst *mtmp, struct monst *mtarg) @@ -988,6 +1143,9 @@ thrwmu(struct monst *mtmp) struct obj *otmp, *mwep; coordxy x, y; const char *onm; + int rang; + const struct throw_and_return_weapon *arw; + boolean always_toss = FALSE; /* Rearranged beginning so monsters can use polearms not in a line */ if (mtmp->weapon_check == NEED_WEAPON || !MON_WEP(mtmp)) { @@ -1003,10 +1161,10 @@ thrwmu(struct monst *mtmp) return; if (is_pole(otmp)) { - int dam, hitv, rang; + int dam, hitv; if (otmp != MON_WEP(mtmp)) - return; /* polearm must be wielded */ + return; /* polearm, aklys must be wielded */ /* * MON_POLE_DIST encompasses knight's move range (5): two spots @@ -1047,6 +1205,11 @@ thrwmu(struct monst *mtmp) (void) thitu(hitv, dam, &otmp, (char *) 0); stop_occupation(); return; + } else if ((arw = autoreturn_weapon(otmp)) != 0 && !mwelded(otmp)) { + rang = dist2(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy); + if (rang > arw->range || !couldsee(mtmp->mx, mtmp->my)) + return; /* Out of range, or intervening wall */ + always_toss = TRUE; } x = mtmp->mx; @@ -1058,7 +1221,8 @@ thrwmu(struct monst *mtmp) */ if (!lined_up(mtmp) || (URETREATING(x, y) - && rn2(BOLT_LIM - distmin(x, y, mtmp->mux, mtmp->muy)))) + && (!always_toss + && rn2(BOLT_LIM - distmin(x, y, mtmp->mux, mtmp->muy))))) return; mwep = MON_WEP(mtmp); /* wielded weapon */ diff --git a/src/weapon.c b/src/weapon.c index 82c980ec4..af6beac22 100644 --- a/src/weapon.c +++ b/src/weapon.c @@ -493,21 +493,38 @@ oselect(struct monst *mtmp, int type) return (struct obj *) 0; } -/* TODO: have monsters use aklys' throw-and-return */ static NEARDATA const int rwep[] = { DWARVISH_SPEAR, SILVER_SPEAR, ELVEN_SPEAR, SPEAR, ORCISH_SPEAR, JAVELIN, SHURIKEN, YA, SILVER_ARROW, ELVEN_ARROW, ARROW, ORCISH_ARROW, CROSSBOW_BOLT, SILVER_DAGGER, ELVEN_DAGGER, DAGGER, ORCISH_DAGGER, KNIFE, - FLINT, ROCK, LOADSTONE, LUCKSTONE, DART, - /* BOOMERANG, */ CREAM_PIE + FLINT, ROCK, LOADSTONE, LUCKSTONE, DART, CREAM_PIE, }; +/* polearms */ static NEARDATA const int pwep[] = { HALBERD, BARDICHE, SPETUM, BILL_GUISARME, VOULGE, RANSEUR, GUISARME, GLAIVE, LUCERN_HAMMER, BEC_DE_CORBIN, FAUCHARD, PARTISAN, LANCE }; +/* throw-and-return weapons */ +static NEARDATA const struct throw_and_return_weapon arwep[] = { + /* { BOOMERANG, 5, 0 }, */ + { AKLYS, (BOLT_LIM / 2), 1 }, +}; + +const struct throw_and_return_weapon * +autoreturn_weapon(struct obj *otmp) +{ + int i; + + for (i = 0; i < SIZE(arwep); i++) { + if (otmp->otyp == arwep[i].otyp) + return &arwep[i]; + } + return (struct throw_and_return_weapon *) 0; +} + /* select a ranged weapon for the monster */ struct obj * select_rwep(struct monst *mtmp) @@ -557,9 +574,31 @@ select_rwep(struct monst *mtmp) } } } + /* Next, try to select a throw-and-return weapon, since they are + * also not as expendable. Again, don't pick one if monster's + * weapon is welded. + */ + for (i = 0; i < SIZE(arwep); i++) { + const struct throw_and_return_weapon *arw = &arwep[i]; + + if (!mindless(mtmp->data) && !is_animal(mtmp->data) && !mweponly + && dist2(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy) <= arw->range + && couldsee(mtmp->mx, mtmp->my)) { + if ((((mtmp->misc_worn_check & W_ARMS) == 0) + || !objects[arw->otyp].oc_bimanual) + && (objects[arw->otyp].oc_material != SILVER + || !mon_hates_silver(mtmp))) { + if ((otmp = oselect(mtmp, arw->otyp)) != 0 + && (otmp == mwep || !mweponly)) { + gp.propellor = otmp; /* force the monster to wield it */ + return otmp; + } + } + } + } /* - * other than these two specific cases, always select the + * other than the specific cases above, always select the * most potent ranged weapon to hand. */ for (i = 0; i < SIZE(rwep); i++) { @@ -840,10 +879,15 @@ mon_wield_item(struct monst *mon) mon->weapon_check = NEED_WEAPON; if (canseemon(mon)) { boolean newly_welded; + const struct throw_and_return_weapon *arw; pline_mon(mon, "%s wields %s%c", Monnam(mon), doname(obj), exclaim ? '!' : '.'); + if ((arw = autoreturn_weapon(obj)) != 0 && arw->tethered != 0) + pline_mon(mon, "%s secures the tether on %s.", Monnam(mon), + the(xname(obj))); + /* 3.6.3: mwelded() predicate expects the object to have its W_WEP bit set in owormmask, but the pline here and for artifact_light don't want that because they'd have '(weapon From d53698baeaca2714c2e75fb7b784003fcdd108a3 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 16 Mar 2025 15:39:22 -0400 Subject: [PATCH 503/791] whitespace at end-of-line --- src/mthrowu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mthrowu.c b/src/mthrowu.c index c22ba9340..a0d462efd 100644 --- a/src/mthrowu.c +++ b/src/mthrowu.c @@ -642,9 +642,9 @@ m_throw( * X rn2(100) chance of returning to thrower's location. * X if impaired and rn2(100) == 0, * -50/50 chance of landing on the ground. - * -50/50 chance of hitting the thrower and causing + * -50/50 chance of hitting the thrower and causing * rnd(3) damage. - * + * */ } } From f7a390db11db60068fad7cff2912dc3f2f720338 Mon Sep 17 00:00:00 2001 From: PatR Date: Sun, 16 Mar 2025 19:37:40 -0700 Subject: [PATCH 504/791] fix #K4324 - Xp and Exp highlit after restore Experience-level and experience-points, if enabled, could be highlighted via 'up' or 'changed' rules in initial display after restore. I tried 'down' rule too but didn't produce with that. I don't understand what was going on but was able to reproduce it and then fix it via the trial and error method.... --- src/allmain.c | 4 ++-- src/botl.c | 18 ++++++++++-------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/allmain.c b/src/allmain.c index f3fe1decd..237ec2c06 100644 --- a/src/allmain.c +++ b/src/allmain.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 allmain.c $NHDT-Date: 1726894914 2024/09/21 05:01:54 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.261 $ */ +/* NetHack 3.7 allmain.c $NHDT-Date: 1742207239 2025/03/17 02:27:19 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.275 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -687,7 +687,7 @@ init_sound_disp_gamewindows(void) WIN_MESSAGE = create_nhwindow(NHW_MESSAGE); if (VIA_WINDOWPORT()) { - status_initialize(0); + status_initialize(FALSE); } else { WIN_STATUS = create_nhwindow(NHW_STATUS); } diff --git a/src/botl.c b/src/botl.c index b8a24c780..7cd0f3a0d 100644 --- a/src/botl.c +++ b/src/botl.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 botl.c $NHDT-Date: 1720397739 2024/07/08 00:15:39 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.264 $ */ +/* NetHack 3.7 botl.c $NHDT-Date: 1742207239 2025/03/17 02:27:19 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.274 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2006. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1325,7 +1325,10 @@ eval_notify_windowport_field( reset = FALSE; #ifdef STATUS_HILITES - if (!gu.update_all && !chg && curr->time) { + if (gu.update_all) { + chg = 0; + curr->time = prev->time = 0L; + } else if (!chg && curr->time) { reset = hilite_reset_needed(prev, gb.bl_hilite_moves); if (reset) curr->time = prev->time = 0L; @@ -1949,7 +1952,7 @@ static const struct fieldid_t { { "xp", BL_EXP }, { "exp", BL_EXP }, { "flags", BL_CONDITION }, - {0, BL_FLUSH } + { NULL, BL_FLUSH } }; /* format arguments */ @@ -2024,8 +2027,8 @@ status_eval_next_unhilite(void) long next_unhilite, this_unhilite; gb.bl_hilite_moves = svm.moves; /* simplified; at one point we used to - * try to encode fractional amounts for - * multiple moves within same turn */ + * try to encode fractional amounts for + * multiple moves within same turn */ /* figure out whether an unhilight needs to be performed now */ next_unhilite = 0L; for (i = 0; i < MAXBLSTATS; ++i) { @@ -2424,8 +2427,7 @@ has_ltgt_percentnumber(const char *str) } /* splitsubfields(): splits str in place into '+' or '&' separated strings. - * returns number of strings, or -1 if more than maxsf or MAX_SUBFIELDS - */ + returns number of strings, or -1 if more than maxsf or MAX_SUBFIELDS */ staticfn int splitsubfields(char *str, char ***sfarr, int maxsf) { @@ -2575,7 +2577,7 @@ parse_status_hl2(char (*s)[QBUFSZ], boolean from_configfile) /* Examples: 3.6.1: OPTION=hilite_status: hitpoints/<10%/red - OPTION=hilite_status: hitpoints/<10%/red/<5%/purple/1/red+blink+inverse + OPTION=hilite_status: hitpoints/<10%/red/<5%/purple/1/red&blink+inverse OPTION=hilite_status: experience/down/red/up/green OPTION=hilite_status: cap/strained/yellow/overtaxed/orange OPTION=hilite_status: title/always/blue From 4e42ae27b49082aed60e5c686fc7a00b876d44fd Mon Sep 17 00:00:00 2001 From: Greg Kennedy Date: Sun, 16 Mar 2025 21:43:49 -0500 Subject: [PATCH 505/791] Add "Murphy" to list of random ghost names "Murphy's Ghost" is a recurring fixture of the long-running "Wizardry" series of classic dungeon crawler video games. --- src/do_name.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/do_name.c b/src/do_name.c index 37876700e..9a2d2f54c 100644 --- a/src/do_name.c +++ b/src/do_name.c @@ -762,7 +762,7 @@ static const char *const ghostnames[] = { "John", "Jon", "Karnov", "Kay", "Kenny", "Kevin", "Maud", "Michiel", "Mike", "Peter", "Robert", "Ron", "Tom", "Wilmar", "Nick Danger", "Phoenix", "Jiro", "Mizue", - "Stephan", "Lance Braccus", "Shadowhawk" + "Stephan", "Lance Braccus", "Shadowhawk", "Murphy" }; /* ghost names formerly set by x_monnam(), now by makemon() instead */ From ed406dafe7dbf0d95f5806f01fe1cc075e4fbbc0 Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 17 Mar 2025 07:38:37 -0400 Subject: [PATCH 506/791] follow-up: store square of dist in arwep table Also includes some additional unrelated #undef's since one was being added. --- src/monmove.c | 2 +- src/weapon.c | 18 +++++++++++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/monmove.c b/src/monmove.c index 17c7d7f83..c16588955 100644 --- a/src/monmove.c +++ b/src/monmove.c @@ -1210,7 +1210,7 @@ m_balks_at_approaching(int oldappr, struct monst *mtmp, int *pdistmin, if (pdistmin) *pdistmin = 2 * 2; if (pdistmax) - *pdistmax = arw->range * arw->range; + *pdistmax = arw->range; return -2; } diff --git a/src/weapon.c b/src/weapon.c index af6beac22..12e5b5d99 100644 --- a/src/weapon.c +++ b/src/weapon.c @@ -507,10 +507,11 @@ static NEARDATA const int pwep[] = { HALBERD, BARDICHE, SPETUM, BEC_DE_CORBIN, FAUCHARD, PARTISAN, LANCE }; +#define AKLYS_LIM (BOLT_LIM / 2) /* throw-and-return weapons */ static NEARDATA const struct throw_and_return_weapon arwep[] = { /* { BOOMERANG, 5, 0 }, */ - { AKLYS, (BOLT_LIM / 2), 1 }, + { AKLYS, AKLYS_LIM * AKLYS_LIM, 1 }, }; const struct throw_and_return_weapon * @@ -1779,4 +1780,19 @@ setmnotwielded(struct monst *mon, struct obj *obj) obj->owornmask &= ~W_WEP; } +#undef PN_BARE_HANDED +#undef PN_RIDING +#undef PN_POLEARMS +#undef PN_SABER +#undef PN_HAMMER +#undef PN_WHIP +#undef PN_ATTACK_SPELL +#undef PN_HEALING_SPELL +#undef PN_DIVINATION_SPELL +#undef PN_ENCHANTMENT_SPELL +#undef PN_CLERIC_SPELL +#undef PN_ESCAPE_SPELL +#undef PN_MATTER_SPELL +#undef AKLYS_LIM + /*weapon.c*/ From 8c0c33aa1f664491d31ab168811fcce5455e76ad Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 17 Mar 2025 08:09:00 -0400 Subject: [PATCH 507/791] another follow-up bit --- src/dothrow.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dothrow.c b/src/dothrow.c index 4c4665ef5..dac67ba82 100644 --- a/src/dothrow.c +++ b/src/dothrow.c @@ -1619,7 +1619,7 @@ throwit(struct obj *obj, else if (tethered_weapon) /* primary weapon is aklys */ /* range of a tethered_weapon is limited by the length of the attached cord [implicit aspect of item] */ - range = min(range, arw->range); + range = min(range, isqrt(arw->range)); else if (obj == uball && u.utrap && u.utraptype == TT_INFLOOR) range = 1; From a64796e64d6da29c48ee5cbee1ddabd3a1ed38e0 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Mon, 17 Mar 2025 14:33:01 +0200 Subject: [PATCH 508/791] Flip monster goal when flipping the level --- src/sp_lev.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sp_lev.c b/src/sp_lev.c index 8bd135217..e9064f10d 100644 --- a/src/sp_lev.c +++ b/src/sp_lev.c @@ -653,6 +653,8 @@ flip_level( if (flp & 2) mtmp->mx = FlipX(mtmp->mx); + Flip_coord(mtmp->mgoal); + if (mtmp->ispriest) { Flip_coord(EPRI(mtmp)->shrpos); } else if (mtmp->isshk) { From ec6632352f1b6c407c1f0623f5eb0cfe7e6381c0 Mon Sep 17 00:00:00 2001 From: PatR Date: Tue, 18 Mar 2025 11:53:58 -0700 Subject: [PATCH 509/791] 'nethack --dumpweights' tweak In the generated comments accompanying weights, show /* a novel */ rather than /* a spellbook of novel */. --- src/hack.c | 38 +++++++++++++++++--------------------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/src/hack.c b/src/hack.c index d8389da4a..0345f2d98 100644 --- a/src/hack.c +++ b/src/hack.c @@ -4309,8 +4309,8 @@ dump_weights(void) int i, cnt = 0, nmwidth = 49, mcount = NUMMONS, ocount = NUM_OBJECTS; char nmbuf[BUFSZ], nmbufbase[BUFSZ]; - weightlist = (struct weight_table_entry *) alloc(sizeof(struct weight_table_entry) - * (mcount + ocount)); + weightlist = (struct weight_table_entry *) + alloc(sizeof (struct weight_table_entry) * (mcount + ocount)); decl_globals_init(); init_objects(); for (i = 0; i < mcount; ++i) { @@ -4332,33 +4332,29 @@ dump_weights(void) } } for (i = 0; i < ocount; ++i) { - int wt = (int) objects[i].oc_weight; + int wt = (int) objects[i].oc_weight, + ocls = objects[i].oc_class; if (wt && i != SLIME_MOLD && obj_descr[i].oc_name) { weightlist[cnt].idx = i; weightlist[cnt].wt = wt; weightlist[cnt].wtyp = 2; - weightlist[cnt].wt = wt; weightlist[cnt].unique = (objects[i].oc_unique != 0); - Snprintf( - nmbufbase, sizeof nmbufbase, "%s%s", - objects[weightlist[cnt].idx].oc_class == POTION_CLASS - ? "potion of " - : objects[weightlist[cnt].idx].oc_class == WAND_CLASS - ? "wand of " - : objects[weightlist[cnt].idx].oc_class == SCROLL_CLASS - ? "scroll of " - : objects[weightlist[cnt].idx].oc_class == RING_CLASS - ? "ring of " - : (objects[weightlist[cnt].idx].oc_class == SPBOOK_CLASS - && objects[weightlist[cnt].idx].oc_name_idx != SPE_BOOK_OF_THE_DEAD) - ? "spellbook of " - : "", - obj_descr[weightlist[cnt].idx].oc_name); + Snprintf(nmbufbase, sizeof nmbufbase, "%s%s", + (ocls == POTION_CLASS) ? "potion of " + : (ocls == WAND_CLASS) ? "wand of " + : (ocls == SCROLL_CLASS) ? "scroll of " + : (ocls == RING_CLASS) ? "ring of " + : (ocls == SPBOOK_CLASS + && objects[i].oc_name_idx != SPE_BOOK_OF_THE_DEAD + && objects[i].oc_name_idx != SPE_NOVEL) + ? "spellbook of " + : "", + obj_descr[i].oc_name); Snprintf(nmbuf, sizeof nmbuf, "%07u", wt); Snprintf(&nmbuf[7], sizeof nmbuf - 7, "%s", - (weightlist[cnt].unique) ? the(nmbufbase) - : an(nmbufbase)); + (weightlist[cnt].unique) ? the(nmbufbase) + : an(nmbufbase)); weightlist[cnt].nm = dupstr(nmbuf); cnt++; } From ef9734f1c10d145b1574bae6fa57fe54bccf5281 Mon Sep 17 00:00:00 2001 From: PatR Date: Wed, 19 Mar 2025 01:39:01 -0700 Subject: [PATCH 510/791] another 'nethack --dumpweights' tweak Don't suppress slime mold. --- src/hack.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/hack.c b/src/hack.c index 0345f2d98..6bd838e16 100644 --- a/src/hack.c +++ b/src/hack.c @@ -4332,10 +4332,12 @@ dump_weights(void) } } for (i = 0; i < ocount; ++i) { + const char *oc_name = (i == SLIME_MOLD) ? "slime mold" + : obj_descr[i].oc_name; int wt = (int) objects[i].oc_weight, ocls = objects[i].oc_class; - if (wt && i != SLIME_MOLD && obj_descr[i].oc_name) { + if (wt && oc_name) { weightlist[cnt].idx = i; weightlist[cnt].wt = wt; weightlist[cnt].wtyp = 2; @@ -4350,9 +4352,8 @@ dump_weights(void) && objects[i].oc_name_idx != SPE_NOVEL) ? "spellbook of " : "", - obj_descr[i].oc_name); - Snprintf(nmbuf, sizeof nmbuf, "%07u", wt); - Snprintf(&nmbuf[7], sizeof nmbuf - 7, "%s", + oc_name); + Snprintf(nmbuf, sizeof nmbuf, "%07u%s", wt, (weightlist[cnt].unique) ? the(nmbufbase) : an(nmbufbase)); weightlist[cnt].nm = dupstr(nmbuf); From 00a5d811eebbf93f13b20242e33a14afa4b7ea93 Mon Sep 17 00:00:00 2001 From: PatR Date: Wed, 19 Mar 2025 07:48:12 -0700 Subject: [PATCH 511/791] monmove.c: remove a couple of trailing spaces --- src/monmove.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/monmove.c b/src/monmove.c index c16588955..b8c58cc8b 100644 --- a/src/monmove.c +++ b/src/monmove.c @@ -1170,7 +1170,7 @@ leppie_stash(struct monst *mtmp) } } -/* does monster want to avoid you? +/* does monster want to avoid you? * returns the original value of appr if not. * returns -1 if so. * returns -2 if monster wants to adhere to a particular range, @@ -1723,7 +1723,7 @@ m_move(struct monst *mtmp, int after) unsigned seenflgs; struct permonst *ptr; int chi, mmoved = MMOVE_NOTHING, /* not strictly nec.: chi >= 0 will do */ - preferredrange_min = 0, preferredrange_max = 0; + preferredrange_min = 0, preferredrange_max = 0; long info[9]; long flag; coordxy omx = mtmp->mx, omy = mtmp->my; From a943c4c10b4555d9906b0f1dba738eb48405c858 Mon Sep 17 00:00:00 2001 From: nhmall Date: Wed, 19 Mar 2025 13:29:58 -0400 Subject: [PATCH 512/791] replace some weight-related magic numbers adds a header file include/nhconst.h (I'm open to a better name) --- include/hack.h | 5 +--- include/monsters.h | 50 +++++++++++++++++++------------------- include/nhconst.h | 42 ++++++++++++++++++++++++++++++++ include/permonst.h | 12 --------- src/do.c | 2 +- src/dothrow.c | 7 +++--- src/hack.c | 10 +++++--- src/monst.c | 1 + src/mthrowu.c | 6 ++--- src/objects.c | 1 + src/objnam.c | 2 +- src/read.c | 2 +- src/timeout.c | 2 +- src/trap.c | 2 +- src/weapon.c | 2 +- sys/msdos/Makefile.GCC | 10 ++++---- sys/unix/Makefile.src | 28 ++++++++++----------- sys/vms/Makefile.src | 2 +- sys/windows/Makefile.nmake | 18 +++++++------- 19 files changed, 118 insertions(+), 86 deletions(-) create mode 100644 include/nhconst.h diff --git a/include/hack.h b/include/hack.h index 3e0b9c306..9af8a3fda 100644 --- a/include/hack.h +++ b/include/hack.h @@ -12,6 +12,7 @@ #include "lint.h" #include "align.h" +#include "nhconst.h" #include "dungeon.h" #include "stairs.h" #include "objclass.h" @@ -46,7 +47,6 @@ #define ON 1 #define OFF 0 #define BOLT_LIM 8 /* from this distance ranged attacks will be made */ -#define MAX_CARR_CAP 1000 /* so that boulders can be heavier */ #define DUMMY { 0 } /* array initializer, letting [1..N-1] default */ #define DEF_NOTHING ' ' /* default symbol for NOTHING and UNEXPLORED */ @@ -65,9 +65,6 @@ #define CXN_ARTICLE 8 /* include a/an/the prefix */ #define CXN_NOCORPSE 16 /* suppress " corpse" suffix */ -/* weight increment of heavy iron ball */ -#define IRON_BALL_W_INCR 160 - /* number of turns it takes for vault guard to show up */ #define VAULT_GUARD_TIME 30 diff --git a/include/monsters.h b/include/monsters.h index 14278e339..408f4a888 100644 --- a/include/monsters.h +++ b/include/monsters.h @@ -590,7 +590,7 @@ LVL(4, 0, 8, 10, 0), (G_GENO | 2), A(ATTK(AT_NONE, AD_COLD, 0, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), - SIZ(50, 20, MS_SILENT, MZ_MEDIUM), MR_COLD | MR_POISON, + SIZ(WT_JELLY, 20, MS_SILENT, MZ_MEDIUM), MR_COLD | MR_POISON, MR_COLD | MR_POISON, M1_BREATHLESS | M1_AMORPHOUS | M1_NOEYES | M1_NOLIMBS | M1_NOHEAD | M1_MINDLESS | M1_NOTAKE, @@ -600,7 +600,7 @@ LVL(5, 0, 8, 10, 0), (G_GENO | 1), A(ATTK(AT_NONE, AD_ACID, 0, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), - SIZ(50, 20, MS_SILENT, MZ_MEDIUM), + SIZ(WT_JELLY, 20, MS_SILENT, MZ_MEDIUM), MR_ACID | MR_STONE, MR_ACID | MR_STONE, M1_BREATHLESS | M1_AMORPHOUS | M1_NOEYES | M1_NOLIMBS | M1_NOHEAD | M1_MINDLESS | M1_ACID | M1_NOTAKE, @@ -610,7 +610,7 @@ LVL(6, 3, 8, 20, 0), (G_GENO | 2), A(ATTK(AT_ENGL, AD_ACID, 3, 6), ATTK(AT_NONE, AD_ACID, 3, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), - SIZ(50, 20, MS_SILENT, MZ_MEDIUM), + SIZ(WT_JELLY, 20, MS_SILENT, MZ_MEDIUM), MR_ACID | MR_STONE, MR_ACID | MR_STONE, M1_BREATHLESS | M1_AMORPHOUS | M1_NOEYES | M1_NOLIMBS | M1_NOHEAD | M1_MINDLESS | M1_ACID | M1_NOTAKE, @@ -701,14 +701,14 @@ LVL(3, 12, 9, 20, 0), (G_GENO | 2), A(ATTK(AT_CLAW, AD_SITM, 0, 0), ATTK(AT_CLAW, AD_SEDU, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), - SIZ(600, 300, MS_SEDUCE, MZ_HUMAN), 0, 0, M1_HUMANOID | M1_TPORT, + SIZ(WT_NYMPH, 300, MS_SEDUCE, MZ_HUMAN), 0, 0, M1_HUMANOID | M1_TPORT, M2_HOSTILE | M2_FEMALE | M2_COLLECT, M3_INFRAVISIBLE, 5, CLR_GREEN, WOOD_NYMPH), MON(NAM("water nymph"), S_NYMPH, LVL(3, 12, 9, 20, 0), (G_GENO | 2), A(ATTK(AT_CLAW, AD_SITM, 0, 0), ATTK(AT_CLAW, AD_SEDU, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), - SIZ(600, 300, MS_SEDUCE, MZ_HUMAN), 0, 0, + SIZ(WT_NYMPH, 300, MS_SEDUCE, MZ_HUMAN), 0, 0, M1_HUMANOID | M1_TPORT | M1_SWIM, M2_HOSTILE | M2_FEMALE | M2_COLLECT, M3_INFRAVISIBLE, 5, CLR_BLUE, WATER_NYMPH), @@ -716,7 +716,7 @@ LVL(3, 12, 9, 20, 0), (G_GENO | 2), A(ATTK(AT_CLAW, AD_SITM, 0, 0), ATTK(AT_CLAW, AD_SEDU, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), - SIZ(600, 300, MS_SEDUCE, MZ_HUMAN), 0, 0, M1_HUMANOID | M1_TPORT, + SIZ(WT_NYMPH, 300, MS_SEDUCE, MZ_HUMAN), 0, 0, M1_HUMANOID | M1_TPORT, M2_HOSTILE | M2_FEMALE | M2_COLLECT, M3_INFRAVISIBLE, 5, CLR_BROWN, MOUNTAIN_NYMPH), /* @@ -1052,7 +1052,7 @@ LVL(3, 1, 0, 0, 0), (G_GENO | G_NOCORPSE | 2), A(ATTK(AT_ENGL, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), - SIZ(0, 0, MS_SILENT, MZ_HUGE), MR_SLEEP | MR_POISON | MR_STONE, 0, + SIZ(WT_ETHEREAL, 0, MS_SILENT, MZ_HUGE), MR_SLEEP | MR_POISON | MR_STONE, 0, M1_FLY | M1_BREATHLESS | M1_NOEYES | M1_NOLIMBS | M1_NOHEAD | M1_MINDLESS | M1_AMORPHOUS | M1_UNSOLID, M2_HOSTILE | M2_NEUTER, 0, @@ -1061,7 +1061,7 @@ LVL(4, 20, 2, 30, 0), (G_GENO | G_NOCORPSE | 2), A(ATTK(AT_ENGL, AD_BLND, 2, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), - SIZ(0, 0, MS_SILENT, MZ_HUGE), MR_SLEEP | MR_POISON | MR_STONE, 0, + SIZ(WT_ETHEREAL, 0, MS_SILENT, MZ_HUGE), MR_SLEEP | MR_POISON | MR_STONE, 0, M1_FLY | M1_BREATHLESS | M1_NOEYES | M1_NOLIMBS | M1_NOHEAD | M1_MINDLESS, M2_HOSTILE | M2_NEUTER, 0, @@ -1070,7 +1070,7 @@ LVL(5, 20, 2, 30, 0), (G_NOHELL | G_GENO | G_NOCORPSE | 1), A(ATTK(AT_ENGL, AD_COLD, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), - SIZ(0, 0, MS_SILENT, MZ_HUGE), + SIZ(WT_ETHEREAL, 0, MS_SILENT, MZ_HUGE), MR_COLD | MR_SLEEP | MR_POISON | MR_STONE, 0, M1_FLY | M1_BREATHLESS | M1_NOEYES | M1_NOLIMBS | M1_NOHEAD | M1_MINDLESS, @@ -1080,7 +1080,7 @@ LVL(6, 20, 2, 30, 0), (G_GENO | G_NOCORPSE | 1), A(ATTK(AT_ENGL, AD_ELEC, 1, 6), ATTK(AT_ENGL, AD_DREN, 2, 6), ATTK(AT_NONE, AD_ELEC, 0, 4), NO_ATTK, NO_ATTK, NO_ATTK), - SIZ(0, 0, MS_SILENT, MZ_HUGE), + SIZ(WT_ETHEREAL, 0, MS_SILENT, MZ_HUGE), MR_ELEC | MR_SLEEP | MR_DISINT | MR_POISON | MR_STONE, 0, M1_FLY | M1_BREATHLESS | M1_NOEYES | M1_NOLIMBS | M1_NOHEAD | M1_MINDLESS | M1_UNSOLID, @@ -1090,7 +1090,7 @@ LVL(7, 22, 2, 30, 0), (G_HELL | G_GENO | G_NOCORPSE | 2), A(ATTK(AT_ENGL, AD_FIRE, 1, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), - SIZ(0, 0, MS_SILENT, MZ_HUGE), + SIZ(WT_ETHEREAL, 0, MS_SILENT, MZ_HUGE), MR_FIRE | MR_SLEEP | MR_POISON | MR_STONE, 0, M1_FLY | M1_BREATHLESS | M1_NOEYES | M1_NOLIMBS | M1_NOHEAD | M1_MINDLESS | M1_UNSOLID, @@ -1100,7 +1100,7 @@ LVL(8, 22, 2, 30, 0), (G_HELL | G_GENO | G_NOCORPSE | 1), A(ATTK(AT_ENGL, AD_FIRE, 1, 10), ATTK(AT_NONE, AD_FIRE, 0, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), - SIZ(0, 0, MS_SILENT, MZ_HUGE), + SIZ(WT_ETHEREAL, 0, MS_SILENT, MZ_HUGE), MR_FIRE | MR_SLEEP | MR_POISON | MR_STONE, 0, M1_FLY | M1_BREATHLESS | M1_NOEYES | M1_NOLIMBS | M1_NOHEAD | M1_MINDLESS | M1_UNSOLID, @@ -1168,7 +1168,7 @@ LVL(3, 15, 0, 0, 0), (G_NOCORPSE | G_GENO | 4), A(ATTK(AT_EXPL, AD_BLND, 10, 20), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), - SIZ(0, 0, MS_SILENT, MZ_SMALL), + SIZ(WT_ETHEREAL, 0, MS_SILENT, MZ_SMALL), MR_FIRE | MR_COLD | MR_ELEC | MR_DISINT | MR_SLEEP | MR_POISON | MR_ACID | MR_STONE, 0, M1_FLY | M1_BREATHLESS | M1_AMORPHOUS | M1_NOEYES | M1_NOLIMBS @@ -1180,7 +1180,7 @@ LVL(5, 15, 0, 0, 0), (G_NOCORPSE | G_GENO | 2), A(ATTK(AT_EXPL, AD_HALU, 10, 12), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), - SIZ(0, 0, MS_SILENT, MZ_SMALL), + SIZ(WT_ETHEREAL, 0, MS_SILENT, MZ_SMALL), MR_FIRE | MR_COLD | MR_ELEC | MR_DISINT | MR_SLEEP | MR_POISON | MR_ACID | MR_STONE, 0, M1_FLY | M1_BREATHLESS | M1_AMORPHOUS | M1_NOEYES | M1_NOLIMBS @@ -1340,7 +1340,7 @@ LVL(12, 9, 2, 10, 0), G_GENO, A(ATTK(AT_BITE, AD_PHYS, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), - SIZ(1500, 500, MS_ROAR, MZ_HUGE), 0, 0, + SIZ(WT_BABY_DRAGON, 500, MS_ROAR, MZ_HUGE), 0, 0, M1_FLY | M1_THICK_HIDE | M1_NOHANDS | M1_CARNIVORE, M2_HOSTILE | M2_STRONG | M2_GREEDY | M2_JEWELS, 0, 13, CLR_GRAY, BABY_GRAY_DRAGON), @@ -1348,7 +1348,7 @@ LVL(12, 9, 2, 10, 0), G_GENO, A(ATTK(AT_BITE, AD_PHYS, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), - SIZ(1500, 500, MS_ROAR, MZ_HUGE), 0, 0, + SIZ(WT_BABY_DRAGON, 500, MS_ROAR, MZ_HUGE), 0, 0, M1_FLY | M1_THICK_HIDE | M1_NOHANDS | M1_CARNIVORE, M2_HOSTILE | M2_STRONG | M2_GREEDY | M2_JEWELS, M3_INFRAVISIBLE, 13, HI_GOLD, BABY_GOLD_DRAGON), @@ -1356,7 +1356,7 @@ LVL(12, 9, 2, 10, 0), G_GENO, A(ATTK(AT_BITE, AD_PHYS, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), - SIZ(1500, 500, MS_ROAR, MZ_HUGE), 0, 0, + SIZ(WT_BABY_DRAGON, 500, MS_ROAR, MZ_HUGE), 0, 0, M1_FLY | M1_THICK_HIDE | M1_NOHANDS | M1_CARNIVORE, M2_HOSTILE | M2_STRONG | M2_GREEDY | M2_JEWELS, 0, 13, DRAGON_SILVER, BABY_SILVER_DRAGON), @@ -1366,7 +1366,7 @@ LVL(12, 9, 2, 10, 0), G_GENO, A(ATTK(AT_BITE, AD_PHYS, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), - SIZ(1500, 500, MS_ROAR, MZ_HUGE), 0, 0, + SIZ(WT_BABY_DRAGON, 500, MS_ROAR, MZ_HUGE), 0, 0, M1_FLY | M1_THICK_HIDE | M1_NOHANDS | M1_CARNIVORE, M2_HOSTILE | M2_STRONG | M2_GREEDY | M2_JEWELS, 0, 13, CLR_CYAN, BABY_SHIMMERING_DRAGON), @@ -1375,7 +1375,7 @@ LVL(12, 9, 2, 10, 0), G_GENO, A(ATTK(AT_BITE, AD_PHYS, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), - SIZ(1500, 500, MS_ROAR, MZ_HUGE), MR_FIRE, 0, + SIZ(WT_BABY_DRAGON, 500, MS_ROAR, MZ_HUGE), MR_FIRE, 0, M1_FLY | M1_THICK_HIDE | M1_NOHANDS | M1_CARNIVORE, M2_HOSTILE | M2_STRONG | M2_GREEDY | M2_JEWELS, M3_INFRAVISIBLE, 13, CLR_RED, BABY_RED_DRAGON), @@ -1383,7 +1383,7 @@ LVL(12, 9, 2, 10, 0), G_GENO, A(ATTK(AT_BITE, AD_PHYS, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), - SIZ(1500, 500, MS_ROAR, MZ_HUGE), MR_COLD, 0, + SIZ(WT_BABY_DRAGON, 500, MS_ROAR, MZ_HUGE), MR_COLD, 0, M1_FLY | M1_THICK_HIDE | M1_NOHANDS | M1_CARNIVORE, M2_HOSTILE | M2_STRONG | M2_GREEDY | M2_JEWELS, 0, 13, CLR_WHITE, BABY_WHITE_DRAGON), @@ -1391,7 +1391,7 @@ LVL(12, 9, 2, 10, 0), G_GENO, A(ATTK(AT_BITE, AD_PHYS, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), - SIZ(1500, 500, MS_ROAR, MZ_HUGE), MR_SLEEP, 0, + SIZ(WT_BABY_DRAGON, 500, MS_ROAR, MZ_HUGE), MR_SLEEP, 0, M1_FLY | M1_THICK_HIDE | M1_NOHANDS | M1_CARNIVORE, M2_HOSTILE | M2_STRONG | M2_GREEDY | M2_JEWELS, 0, 13, CLR_ORANGE, BABY_ORANGE_DRAGON), @@ -1399,7 +1399,7 @@ LVL(12, 9, 2, 10, 0), G_GENO, A(ATTK(AT_BITE, AD_PHYS, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), - SIZ(1500, 500, MS_ROAR, MZ_HUGE), MR_DISINT, 0, + SIZ(WT_BABY_DRAGON, 500, MS_ROAR, MZ_HUGE), MR_DISINT, 0, M1_FLY | M1_THICK_HIDE | M1_NOHANDS | M1_CARNIVORE, M2_HOSTILE | M2_STRONG | M2_GREEDY | M2_JEWELS, 0, 13, CLR_BLACK, BABY_BLACK_DRAGON), @@ -1407,7 +1407,7 @@ LVL(12, 9, 2, 10, 0), G_GENO, A(ATTK(AT_BITE, AD_PHYS, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), - SIZ(1500, 500, MS_ROAR, MZ_HUGE), MR_ELEC, 0, + SIZ(WT_BABY_DRAGON, 500, MS_ROAR, MZ_HUGE), MR_ELEC, 0, M1_FLY | M1_THICK_HIDE | M1_NOHANDS | M1_CARNIVORE, M2_HOSTILE | M2_STRONG | M2_GREEDY | M2_JEWELS, 0, 13, CLR_BLUE, BABY_BLUE_DRAGON), @@ -1415,7 +1415,7 @@ LVL(12, 9, 2, 10, 0), G_GENO, A(ATTK(AT_BITE, AD_PHYS, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), - SIZ(1500, 500, MS_ROAR, MZ_HUGE), MR_POISON, 0, + SIZ(WT_BABY_DRAGON, 500, MS_ROAR, MZ_HUGE), MR_POISON, 0, M1_FLY | M1_THICK_HIDE | M1_NOHANDS | M1_CARNIVORE | M1_POIS, M2_HOSTILE | M2_STRONG | M2_GREEDY | M2_JEWELS, 0, 13, CLR_GREEN, BABY_GREEN_DRAGON), @@ -1423,7 +1423,7 @@ LVL(12, 9, 2, 10, 0), G_GENO, A(ATTK(AT_BITE, AD_PHYS, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), - SIZ(1500, 500, MS_ROAR, MZ_HUGE), MR_ACID | MR_STONE, 0, + SIZ(WT_BABY_DRAGON, 500, MS_ROAR, MZ_HUGE), MR_ACID | MR_STONE, 0, M1_FLY | M1_THICK_HIDE | M1_NOHANDS | M1_CARNIVORE | M1_ACID, M2_HOSTILE | M2_STRONG | M2_GREEDY | M2_JEWELS, 0, 13, CLR_YELLOW, BABY_YELLOW_DRAGON), diff --git a/include/nhconst.h b/include/nhconst.h new file mode 100644 index 000000000..2e074f3f9 --- /dev/null +++ b/include/nhconst.h @@ -0,0 +1,42 @@ +/* NetHack 3.7 nhconst.h $NHDT-Date: 1725653014 2024/09/06 20:03:34 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.26 $ */ +/* Copyright (c) Michael Allison, 2025. */ +/* NetHack may be freely redistributed. See license for details. */ + +#ifndef NHCONST_H +#define NHCONST_H + +/* weight-related constants and thresholds */ +enum weight_constants { + WT_ETHEREAL = 0, + WT_SPLASH_THRESHOLD = 9, /* weight needed to make splash in water */ + WT_WEIGHTCAP_STRCON = 25, /* str + con multiplied by this for conv to + * carrying capacity in weight_cap() */ + WT_WEIGHTCAP_SPARE = 50, /* used in weight_cap calc */ + WT_JELLY = 50, /* weight of jelly body */ + WT_WOUNDEDLEG_REDUCT = 100, /* wounded legs reduce carrcap by this */ + WT_TO_DMG = 100, /* divisor to convert weight to dmg amt */ + WT_IRON_BALL_INCR = 160, /* weight increment of heavy iron ball */ + WT_IRON_BALL_BASE = 480, /* base starting weight of iron ball */ + WT_NOISY_INV = 500, /* inv_weight() max for noisy fumbling */ + WT_NYMPH = 600, /* weight of nymph body */ + WT_TOOMUCH_DIAGONAL = 600, /* weight_cap threshold for diag squeeze */ + WT_ELF = 800, /* weight of elf body */ + WT_SQUEEZABLE_INV = 850, /* inv_weight() maximum for squeezing */ + MAX_CARR_CAP = 1000, /* max carrying capacity, so that + * boulders can be heavier */ + WT_HUMAN = 1450, /* weight of human body */ + WT_BABY_DRAGON = 1500, /* weight ob baby dragon body */ + WT_DRAGON = 4500, /* weight of dragon body */ +}; + +enum monster_speeds { + VERY_SLOW = 3, + SLOW_SPEED = 9, + NORMAL_SPEED = 12, /* movement rates */ + FAST_SPEED = 15, + VERY_FAST = 24, +}; + +#endif /* NHCONST_H */ + + diff --git a/include/permonst.h b/include/permonst.h index 9f11bb1fc..a03e36b4b 100644 --- a/include/permonst.h +++ b/include/permonst.h @@ -47,12 +47,6 @@ struct attack { #define NATTK 6 -/* Weight of human body, elf, dragon - */ -#define WT_HUMAN 1450U -#define WT_ELF 800U -#define WT_DRAGON 4500U - #ifndef ALIGN_H #include "align.h" #endif @@ -86,10 +80,4 @@ struct permonst { extern NEARDATA struct permonst mons[NUMMONS + 1]; /* the master list of * monster types */ -#define VERY_SLOW 3 -#define SLOW_SPEED 9 -#define NORMAL_SPEED 12 /* movement rates */ -#define FAST_SPEED 15 -#define VERY_FAST 24 - #endif /* PERMONST_H */ diff --git a/src/do.c b/src/do.c index 41828b8ac..2d1d7d57b 100644 --- a/src/do.c +++ b/src/do.c @@ -275,7 +275,7 @@ flooreffects( * noise. Stuff dropped near fountains always misses */ if ((Blind || (Levitation || Flying)) && !Deaf && u_at(x, y)) { if (!Underwater) { - if (weight(obj) > 9) { + if (weight(obj) > WT_SPLASH_THRESHOLD) { pline("Splash!"); } else if (Levitation || Flying) { pline("Plop!"); diff --git a/src/dothrow.c b/src/dothrow.c index dac67ba82..fbc507c3c 100644 --- a/src/dothrow.c +++ b/src/dothrow.c @@ -823,7 +823,7 @@ hurtle_step(genericptr_t arg, coordxy x, coordxy y) && bad_rock(gy.youmonst.data, u.ux, y) && bad_rock(gy.youmonst.data, x, u.uy)) { boolean too_much = (gi.invent - && (inv_weight() + weight_cap() > 600)); + && (inv_weight() + weight_cap() > WT_TOOMUCH_DIAGONAL)); if (bigmonst(gy.youmonst.data) || too_much) { why = "wedging into a narrow crevice"; @@ -1347,7 +1347,7 @@ toss_up(struct obj *obj, boolean hitsroof) &dmg, rn1(18, 2)); if (!dmg) { /* probably wasn't a weapon; base damage on weight */ - dmg = ((int) obj->owt + 99) / 100; + dmg = ((int) obj->owt + (WT_TO_DMG - 1)) / WT_TO_DMG; dmg = (dmg <= 1) ? 1 : rnd(dmg); if (dmg > 6) dmg = 6; @@ -1770,7 +1770,8 @@ throwit(struct obj *obj, || (is_lava(gb.bhitpos.x, gb.bhitpos.y) && !is_flammable(obj))) { Soundeffect(se_splash, 50); - pline((weight(obj) > 9) ? "Splash!" : "Plop!"); + pline((weight(obj) > WT_SPLASH_THRESHOLD) + ? "Splash!" : "Plop!"); } } if (flooreffects(obj, gb.bhitpos.x, gb.bhitpos.y, "fall")) { diff --git a/src/hack.c b/src/hack.c index 6bd838e16..908f9e5e9 100644 --- a/src/hack.c +++ b/src/hack.c @@ -135,7 +135,8 @@ revive_nasty(coordxy x, coordxy y, const char *msg) return revived; } -#define squeezeablylightinvent() (!gi.invent || inv_weight() <= -850) +#define squeezeablylightinvent() (!gi.invent \ + || inv_weight() <= (WT_SQUEEZABLE_INV * -1)) /* can hero move onto a spot containing one or more boulders? used for m and travel and during boulder push failure */ @@ -4195,7 +4196,8 @@ weight_cap(void) functions enough in that situation to enhance carrying capacity */ BLevitation &= ~I_SPECIAL; - carrcap = 25 * (ACURRSTR + ACURR(A_CON)) + 50; + carrcap = (WT_WEIGHTCAP_STRCON * (ACURRSTR + ACURR(A_CON))) + + WT_WEIGHTCAP_SPARE; if (Upolyd) { /* consistent with can_carry() in mon.c */ if (gy.youmonst.data->mlet == S_NYMPH) @@ -4216,9 +4218,9 @@ weight_cap(void) carrcap = MAX_CARR_CAP; if (!Flying) { if (EWounded_legs & LEFT_SIDE) - carrcap -= 100; + carrcap -= WT_WOUNDEDLEG_REDUCT; if (EWounded_legs & RIGHT_SIDE) - carrcap -= 100; + carrcap -= WT_WOUNDEDLEG_REDUCT; } } diff --git a/src/monst.c b/src/monst.c index 4b7f57fb1..30eec13b5 100644 --- a/src/monst.c +++ b/src/monst.c @@ -4,6 +4,7 @@ /* NetHack may be freely redistributed. See license for details. */ #include "config.h" +#include "nhconst.h" #include "permonst.h" #include "wintype.h" #include "sym.h" diff --git a/src/mthrowu.c b/src/mthrowu.c index a0d462efd..13a76175d 100644 --- a/src/mthrowu.c +++ b/src/mthrowu.c @@ -1439,10 +1439,10 @@ hit_bars( if (your_fault && (otmp->otyp == WAR_HAMMER || otmp->otyp == HEAVY_IRON_BALL)) { /* iron ball isn't a weapon or wep-tool so doesn't use obj->spe; - weight is normally 480 but can be increased by increments - of 160 (scrolls of punishment read while already punished) */ + weight is normally 48000 but can be increased by increments + of 16000 (scrolls of punishment read while already punished) */ int spe = ((otmp->otyp == HEAVY_IRON_BALL) /* 3+ for iron ball */ - ? ((int) otmp->owt / IRON_BALL_W_INCR) + ? ((int) otmp->owt / WT_IRON_BALL_INCR) : otmp->spe); /* chance: used in saving throw for the bars; more likely to break those when 'chance' is _lower_; acurrstr(): 3..25 */ diff --git a/src/objects.c b/src/objects.c index 45ceaeeab..f9646a54d 100644 --- a/src/objects.c +++ b/src/objects.c @@ -3,6 +3,7 @@ /* NetHack may be freely redistributed. See license for details. */ #include "config.h" +#include "nhconst.h" #include "obj.h" #include "prop.h" diff --git a/src/objnam.c b/src/objnam.c index b4e4ae8dd..d3ce48ffb 100644 --- a/src/objnam.c +++ b/src/objnam.c @@ -5357,7 +5357,7 @@ readobjnam(char *bp, struct obj *no_wish) } d.otmp->owt = weight(d.otmp); if (d.very && d.otmp->otyp == HEAVY_IRON_BALL) - d.otmp->owt += IRON_BALL_W_INCR; + d.otmp->owt += WT_IRON_BALL_INCR; return d.otmp; } diff --git a/src/read.c b/src/read.c index f4cc95ac6..9f0383de7 100644 --- a/src/read.c +++ b/src/read.c @@ -2938,7 +2938,7 @@ punish(struct obj *sobj) You("are being punished for your misbehavior!"); if (Punished) { Your("iron ball gets heavier."); - uball->owt += IRON_BALL_W_INCR * (1 + cursed_levy); + uball->owt += WT_IRON_BALL_INCR * (1 + cursed_levy); return; } if (amorphous(gy.youmonst.data) || is_whirly(gy.youmonst.data) diff --git a/src/timeout.c b/src/timeout.c index 58c575fd1..81f62d531 100644 --- a/src/timeout.c +++ b/src/timeout.c @@ -910,7 +910,7 @@ nh_timeout(void) * are to make noise when you fumble. Adjustments * to this number must be thoroughly play tested. */ - if ((inv_weight() > -500)) { + if ((inv_weight() > (WT_NOISY_INV * -1))) { if (!Deaf) You("make a lot of noise!"); wake_nearby(FALSE); diff --git a/src/trap.c b/src/trap.c index b26c471a8..21adb2314 100644 --- a/src/trap.c +++ b/src/trap.c @@ -5366,7 +5366,7 @@ try_disarm( /* duplicate tight-space checks from test_move */ if (u.dx && u.dy && bad_rock(gy.youmonst.data, u.ux, ttmp->ty) && bad_rock(gy.youmonst.data, ttmp->tx, u.uy)) { - if ((gi.invent && (inv_weight() + weight_cap() > 600)) + if ((gi.invent && (inv_weight() + weight_cap() > WT_TOOMUCH_DIAGONAL)) || bigmonst(gy.youmonst.data)) { /* don't allow untrap if they can't get thru to it */ You("are unable to reach the %s!", trapname(ttype, FALSE)); diff --git a/src/weapon.c b/src/weapon.c index 12e5b5d99..c2da65a58 100644 --- a/src/weapon.c +++ b/src/weapon.c @@ -310,7 +310,7 @@ dmgval(struct obj *otmp, struct monst *mon) int wt = (int) objects[HEAVY_IRON_BALL].oc_weight; if ((int) otmp->owt > wt) { - wt = ((int) otmp->owt - wt) / IRON_BALL_W_INCR; + wt = ((int) otmp->owt - wt) / WT_IRON_BALL_INCR; tmp += rnd(4 * wt); if (tmp > 25) tmp = 25; /* objects[].oc_wldam */ diff --git a/sys/msdos/Makefile.GCC b/sys/msdos/Makefile.GCC index 9ed3b27a2..727e56534 100644 --- a/sys/msdos/Makefile.GCC +++ b/sys/msdos/Makefile.GCC @@ -415,11 +415,11 @@ DECL_H = $(YOU_H) $(INCL)/spell.h $(INCL)/color.h \ GLOBAL_H = $(PCCONF_H) $(INCL)/coord.h $(INCL)/global.h HACK_H = $(CONFIG_H) $(INCL)/context.h $(DUNGEON_H) \ $(DECL_H) $(DISPLAY_H) $(INCL)/sym.h \ - $(INCL)/defsym.h $(INCL)/mkroom.h $(INCL)/objclass.h \ - $(INCL)/trap.h $(INCL)/flag.h $(RM_H) \ - $(INCL)/vision.h $(INCL)/wintype.h $(INCL)/engrave.h \ - $(INCL)/rect.h $(INCL)/hack.h $(REGION_H) \ - $(INCL)/sys.h + $(INCL)/defsym.h $(INCL)/mkroom.h $(INCL)/nhconst.h \ + $(INCL)/objclass.h $(INCL)/trap.h $(INCL)/flag.h \ + $(RM_H) $(INCL)/vision.h $(INCL)/wintype.h \ + $(INCL)/engrave.h $(INCL)/rect.h $(INCL)/hack.h \ + $(REGION_H) $(INCL)/sys.h DLB_H = $(INCL)/dlb.h ifeq ($(SUPPRESS_GRAPHICS),Y) diff --git a/sys/unix/Makefile.src b/sys/unix/Makefile.src index 7532dc098..92f89912e 100644 --- a/sys/unix/Makefile.src +++ b/sys/unix/Makefile.src @@ -564,11 +564,11 @@ HACKINCL = align.h artifact.h artilist.h attrib.h botl.h \ display.h dlb.h dungeon.h engrave.h extern.h flag.h fnamesiz.h \ func_tab.h global.h warnings.h hack.h lint.h mextra.h mfndpos.h \ micro.h mkroom.h monattk.h mondata.h monflag.h monst.h monsters.h \ - nhmd4.h obj.h objects.h objclass.h optlist.h patchlevel.h pcconf.h \ - permonst.h prop.h rect.h region.h selvar.h sym.h defsym.h rm.h sp_lev.h \ - spell.h sndprocs.h seffects.h stairs.h sys.h tcap.h timeout.h \ - tradstdc.h trap.h unixconf.h vision.h vmsconf.h wintty.h wincurs.h \ - winX.h winprocs.h wintype.h you.h youprop.h cstd.h + nhconst.h nhmd4.h obj.h objects.h objclass.h optlist.h patchlevel.h \ + pcconf.h permonst.h prop.h rect.h region.h selvar.h sym.h defsym.h \ + rm.h sp_lev.h spell.h sndprocs.h seffects.h stairs.h sys.h tcap.h \ + timeout.h tradstdc.h trap.h unixconf.h vision.h vmsconf.h wintty.h \ + wincurs.h winX.h winprocs.h wintype.h you.h youprop.h cstd.h HSOURCES = $(HACKINCL) dgn_file.h @@ -883,15 +883,15 @@ $(HACK_H): $(CONFIG_H) ../include/align.h ../include/artilist.h \ ../include/hack.h ../include/lint.h ../include/mextra.h \ ../include/mkroom.h ../include/monattk.h ../include/mondata.h \ ../include/monflag.h ../include/monst.h ../include/monsters.h \ - ../include/nhlua.h ../include/obj.h ../include/objclass.h \ - ../include/objects.h ../include/permonst.h ../include/prop.h \ - ../include/quest.h ../include/rect.h ../include/region.h \ - ../include/rm.h ../include/seffects.h ../include/selvar.h \ - ../include/skills.h ../include/sndprocs.h ../include/spell.h \ - ../include/stairs.h ../include/sym.h ../include/sys.h \ - ../include/timeout.h ../include/trap.h ../include/vision.h \ - ../include/winprocs.h ../include/wintype.h ../include/you.h \ - ../include/youprop.h + ../include/nhconst.h ../include/nhlua.h ../include/obj.h \ + ../include/objclass.h ../include/objects.h ../include/permonst.h \ + ../include/prop.h ../include/quest.h ../include/rect.h \ + ../include/region.h ../include/rm.h ../include/seffects.h \ + ../include/selvar.h ../include/skills.h ../include/sndprocs.h \ + ../include/spell.h ../include/stairs.h ../include/sym.h \ + ../include/sys.h ../include/timeout.h ../include/trap.h \ + ../include/vision.h ../include/winprocs.h ../include/wintype.h \ + ../include/you.h ../include/youprop.h touch $(HACK_H) # $(TARGETPFX)cppregex.o: ../sys/share/cppregex.cpp $(CONFIG_H) diff --git a/sys/vms/Makefile.src b/sys/vms/Makefile.src index df797c38c..6635a5690 100644 --- a/sys/vms/Makefile.src +++ b/sys/vms/Makefile.src @@ -393,7 +393,7 @@ $(HACK_H) : $(INC)hack.h $(CONFIG_H) $(INC)align.h \ $(INC)dungeon.h $(INC)sym.h $(INC)defsym.h $(INC)mkroom.h \ $(INC)objclass.h $(INC)youprop.h $(INC)prop.h \ $(INC)permonst.h $(INC)monattk.h \ - $(INC)monflag.h $(INC)mondata.h $(INC)pm.h \ + $(INC)monflag.h $(INC)mondata.h $(INC)nhconst.h $(INC)pm.h \ $(INC)wintype.h $(INC)context.h $(INC)decl.h $(INC)quest.h \ $(INC)spell.h $(INC)color.h $(INC)obj.h \ $(INC)you.h $(INC)attrib.h $(INC)monst.h \ diff --git a/sys/windows/Makefile.nmake b/sys/windows/Makefile.nmake index 40fe46230..b25fbb208 100644 --- a/sys/windows/Makefile.nmake +++ b/sys/windows/Makefile.nmake @@ -1121,15 +1121,15 @@ HACK_H = $(CONFIG_H) $(INCL)align.h $(INCL)artilist.h \ $(INCL)hack.h $(INCL)lint.h $(INCL)mextra.h \ $(INCL)mkroom.h $(INCL)monattk.h $(INCL)mondata.h \ $(INCL)monflag.h $(INCL)monst.h $(INCL)monsters.h \ - $(INCL)nhlua.h $(INCL)obj.h $(INCL)objclass.h \ - $(INCL)objects.h $(INCL)permonst.h $(INCL)prop.h \ - $(INCL)quest.h $(INCL)rect.h $(INCL)region.h \ - $(INCL)rm.h $(INCL)seffects.h $(INCL)selvar.h \ - $(INCL)skills.h $(INCL)sndprocs.h $(INCL)spell.h \ - $(INCL)stairs.h $(INCL)sym.h $(INCL)sys.h \ - $(INCL)timeout.h $(INCL)trap.h $(INCL)vision.h \ - $(INCL)winprocs.h $(INCL)wintype.h $(INCL)you.h \ - $(INCL)youprop.h + $(INCL)nhconst.h $(INCL)nhlua.h $(INCL)obj.h \ + $(INCL)objclass.h $(INCL)objects.h $(INCL)permonst.h \ + $(INCL)prop.h $(INCL)quest.h $(INCL)rect.h \ + $(INCL)region.h $(INCL)rm.h $(INCL)seffects.h \ + $(INCL)selvar.h $(INCL)skills.h $(INCL)sndprocs.h \ + $(INCL)spell.h $(INCL)stairs.h $(INCL)sym.h \ + $(INCL)sys.h $(INCL)timeout.h $(INCL)trap.h \ + $(INCL)vision.h $(INCL)winprocs.h $(INCL)wintype.h \ + $(INCL)you.h $(INCL)youprop.h TILE_H = $(WSHR)tile.h From e8c401acb3e221c3a8306ea0a6a1653d4332f7fc Mon Sep 17 00:00:00 2001 From: nhmall Date: Wed, 19 Mar 2025 13:38:12 -0400 Subject: [PATCH 513/791] follow-up: numeric values in comment fix --- src/mthrowu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mthrowu.c b/src/mthrowu.c index 13a76175d..4313ce8d7 100644 --- a/src/mthrowu.c +++ b/src/mthrowu.c @@ -1439,8 +1439,8 @@ hit_bars( if (your_fault && (otmp->otyp == WAR_HAMMER || otmp->otyp == HEAVY_IRON_BALL)) { /* iron ball isn't a weapon or wep-tool so doesn't use obj->spe; - weight is normally 48000 but can be increased by increments - of 16000 (scrolls of punishment read while already punished) */ + weight is normally 480 but can be increased by increments + of 160 (scrolls of punishment read while already punished) */ int spe = ((otmp->otyp == HEAVY_IRON_BALL) /* 3+ for iron ball */ ? ((int) otmp->owt / WT_IRON_BALL_INCR) : otmp->spe); From 526571b1f7b332d6fb0bc97c3a7900d8b7abfe4e Mon Sep 17 00:00:00 2001 From: nhmall Date: Wed, 19 Mar 2025 14:12:03 -0400 Subject: [PATCH 514/791] another follow-up for magic number replacement --- include/monsters.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/monsters.h b/include/monsters.h index 408f4a888..0573e882d 100644 --- a/include/monsters.h +++ b/include/monsters.h @@ -1573,7 +1573,7 @@ LVL(8, 36, 2, 30, 0), (G_NOCORPSE | 1), A(ATTK(AT_ENGL, AD_PHYS, 1, 10), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), - SIZ(0, 0, MS_SILENT, MZ_HUGE), MR_POISON | MR_STONE, 0, + SIZ(WT_ETHEREAL, 0, MS_SILENT, MZ_HUGE), MR_POISON | MR_STONE, 0, M1_NOEYES | M1_NOLIMBS | M1_NOHEAD | M1_MINDLESS | M1_BREATHLESS | M1_UNSOLID | M1_FLY, M2_STRONG | M2_NEUTER, 0, @@ -1582,7 +1582,7 @@ LVL(8, 12, 2, 30, 0), (G_NOCORPSE | 1), A(ATTK(AT_CLAW, AD_FIRE, 3, 6), ATTK(AT_NONE, AD_FIRE, 0, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), - SIZ(0, 0, MS_SILENT, MZ_HUGE), MR_FIRE | MR_POISON | MR_STONE, 0, + SIZ(WT_ETHEREAL, 0, MS_SILENT, MZ_HUGE), MR_FIRE | MR_POISON | MR_STONE, 0, M1_NOEYES | M1_NOLIMBS | M1_NOHEAD | M1_MINDLESS | M1_BREATHLESS | M1_UNSOLID | M1_FLY | M1_NOTAKE, M2_STRONG | M2_NEUTER, M3_INFRAVISIBLE, @@ -2335,7 +2335,7 @@ LVL(6, 12, 4, 15, -6), (G_GENO | 2), A(ATTK(AT_TUCH, AD_DRLI, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), - SIZ(0, 0, MS_SILENT, MZ_HUMAN), + SIZ(WT_ETHEREAL, 0, MS_SILENT, MZ_HUMAN), MR_COLD | MR_SLEEP | MR_POISON | MR_STONE, 0, M1_BREATHLESS | M1_FLY | M1_HUMANOID | M1_UNSOLID, M2_UNDEAD | M2_STALK | M2_HOSTILE, 0, From 601d03b71d8ee4dba2942e261e4328b33644f287 Mon Sep 17 00:00:00 2001 From: nhw_cron Date: Wed, 19 Mar 2025 14:24:07 -0400 Subject: [PATCH 515/791] 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 07d2bfb57..49234e7a8 100644 --- a/Files +++ b/Files @@ -94,15 +94,15 @@ dlb.h dungeon.h engrave.h extern.h flag.h fnamesiz.h func_tab.h global.h hack.h hacklib.h integer.h isaac64.h lint.h mail.h mextra.h mfndpos.h micro.h mkroom.h monattk.h mondata.h -monflag.h monst.h monsters.h nhmd4.h nhregex.h -obj.h objclass.h objects.h optlist.h patchlevel.h -pcconf.h permonst.h prop.h quest.h rect.h -region.h rm.h seffects.h selvar.h skills.h -sndprocs.h sp_lev.h spell.h stairs.h sym.h -sys.h tcap.h tileset.h timeout.h tradstdc.h -trap.h unixconf.h vision.h vmsconf.h warnings.h -winami.h wincurs.h windconf.h winprocs.h wintype.h -you.h youprop.h +monflag.h monst.h monsters.h nhconst.h nhmd4.h +nhregex.h obj.h objclass.h objects.h optlist.h +patchlevel.h pcconf.h permonst.h prop.h quest.h +rect.h region.h rm.h seffects.h selvar.h +skills.h sndprocs.h sp_lev.h spell.h stairs.h +sym.h sys.h tcap.h tileset.h timeout.h +tradstdc.h trap.h unixconf.h vision.h vmsconf.h +warnings.h winami.h wincurs.h windconf.h winprocs.h +wintype.h you.h youprop.h (file for tty versions) wintty.h From 1f99638bbfaf9f7e2a03adef83514468d22491ec Mon Sep 17 00:00:00 2001 From: nhmall Date: Wed, 19 Mar 2025 17:14:07 -0400 Subject: [PATCH 516/791] ren nhconst.h -> weight.h The speed related values were not used, except for NORMAL_SPEED, which has been moved back to permonst.h --- include/hack.h | 2 +- include/permonst.h | 2 ++ include/{nhconst.h => weight.h} | 8 ------- src/monst.c | 2 +- src/objects.c | 2 +- sys/msdos/Makefile.GCC | 10 ++++----- sys/unix/Makefile.src | 28 ++++++++++++------------ sys/vms/Makefile.src | 4 ++-- sys/vms/Makefile_src.vms | 5 +++-- sys/windows/Makefile.nmake | 16 +++++++------- sys/windows/vs/NetHack/NetHack.vcxproj | 1 + sys/windows/vs/NetHackW/NetHackW.vcxproj | 1 + sys/windows/vs/tilemap/tilemap.vcxproj | 1 + 13 files changed, 40 insertions(+), 42 deletions(-) rename include/{nhconst.h => weight.h} (91%) diff --git a/include/hack.h b/include/hack.h index 9af8a3fda..a7db0e819 100644 --- a/include/hack.h +++ b/include/hack.h @@ -12,7 +12,7 @@ #include "lint.h" #include "align.h" -#include "nhconst.h" +#include "weight.h" #include "dungeon.h" #include "stairs.h" #include "objclass.h" diff --git a/include/permonst.h b/include/permonst.h index a03e36b4b..6df66b841 100644 --- a/include/permonst.h +++ b/include/permonst.h @@ -77,6 +77,8 @@ struct permonst { uchar mcolor; /* color to use */ }; +#define NORMAL_SPEED 12 + extern NEARDATA struct permonst mons[NUMMONS + 1]; /* the master list of * monster types */ diff --git a/include/nhconst.h b/include/weight.h similarity index 91% rename from include/nhconst.h rename to include/weight.h index 2e074f3f9..2a1113fb8 100644 --- a/include/nhconst.h +++ b/include/weight.h @@ -29,14 +29,6 @@ enum weight_constants { WT_DRAGON = 4500, /* weight of dragon body */ }; -enum monster_speeds { - VERY_SLOW = 3, - SLOW_SPEED = 9, - NORMAL_SPEED = 12, /* movement rates */ - FAST_SPEED = 15, - VERY_FAST = 24, -}; - #endif /* NHCONST_H */ diff --git a/src/monst.c b/src/monst.c index 30eec13b5..b5864ecdb 100644 --- a/src/monst.c +++ b/src/monst.c @@ -4,7 +4,7 @@ /* NetHack may be freely redistributed. See license for details. */ #include "config.h" -#include "nhconst.h" +#include "weight.h" #include "permonst.h" #include "wintype.h" #include "sym.h" diff --git a/src/objects.c b/src/objects.c index f9646a54d..9389e3863 100644 --- a/src/objects.c +++ b/src/objects.c @@ -3,7 +3,7 @@ /* NetHack may be freely redistributed. See license for details. */ #include "config.h" -#include "nhconst.h" +#include "weight.h" #include "obj.h" #include "prop.h" diff --git a/sys/msdos/Makefile.GCC b/sys/msdos/Makefile.GCC index 727e56534..2828b60f3 100644 --- a/sys/msdos/Makefile.GCC +++ b/sys/msdos/Makefile.GCC @@ -415,11 +415,11 @@ DECL_H = $(YOU_H) $(INCL)/spell.h $(INCL)/color.h \ GLOBAL_H = $(PCCONF_H) $(INCL)/coord.h $(INCL)/global.h HACK_H = $(CONFIG_H) $(INCL)/context.h $(DUNGEON_H) \ $(DECL_H) $(DISPLAY_H) $(INCL)/sym.h \ - $(INCL)/defsym.h $(INCL)/mkroom.h $(INCL)/nhconst.h \ - $(INCL)/objclass.h $(INCL)/trap.h $(INCL)/flag.h \ - $(RM_H) $(INCL)/vision.h $(INCL)/wintype.h \ - $(INCL)/engrave.h $(INCL)/rect.h $(INCL)/hack.h \ - $(REGION_H) $(INCL)/sys.h + $(INCL)/defsym.h $(INCL)/mkroom.h $(INCL)/objclass.h \ + $(INCL)/trap.h $(INCL)/flag.h $(RM_H) \ + $(INCL)/vision.h $(INCL)/wintype.h $(INCL)/engrave.h \ + $(INCL)/rect.h $(INCL)/hack.h $(REGION_H) \ + $(INCL)/sys.h $(INCL)/weight.h DLB_H = $(INCL)/dlb.h ifeq ($(SUPPRESS_GRAPHICS),Y) diff --git a/sys/unix/Makefile.src b/sys/unix/Makefile.src index 92f89912e..d8283a03f 100644 --- a/sys/unix/Makefile.src +++ b/sys/unix/Makefile.src @@ -560,15 +560,15 @@ CSOURCES = $(HACKCSRC) $(HACKLIBSRC) $(SYSCSRC) $(WINCSRC) $(CHAINSRC) $(GENCSRC # and dgn_file.h, special level & dungeon files. # HACKINCL = align.h artifact.h artilist.h attrib.h botl.h \ - color.h config.h config1.h context.h coord.h decl.h \ + color.h config.h config1.h context.h coord.h cstd.h decl.h \ display.h dlb.h dungeon.h engrave.h extern.h flag.h fnamesiz.h \ func_tab.h global.h warnings.h hack.h lint.h mextra.h mfndpos.h \ micro.h mkroom.h monattk.h mondata.h monflag.h monst.h monsters.h \ - nhconst.h nhmd4.h obj.h objects.h objclass.h optlist.h patchlevel.h \ + nhmd4.h obj.h objects.h objclass.h optlist.h patchlevel.h \ pcconf.h permonst.h prop.h rect.h region.h selvar.h sym.h defsym.h \ rm.h sp_lev.h spell.h sndprocs.h seffects.h stairs.h sys.h tcap.h \ timeout.h tradstdc.h trap.h unixconf.h vision.h vmsconf.h wintty.h \ - wincurs.h winX.h winprocs.h wintype.h you.h youprop.h cstd.h + wincurs.h winX.h winprocs.h wintype.h you.h youprop.h weight.h HSOURCES = $(HACKINCL) dgn_file.h @@ -883,15 +883,15 @@ $(HACK_H): $(CONFIG_H) ../include/align.h ../include/artilist.h \ ../include/hack.h ../include/lint.h ../include/mextra.h \ ../include/mkroom.h ../include/monattk.h ../include/mondata.h \ ../include/monflag.h ../include/monst.h ../include/monsters.h \ - ../include/nhconst.h ../include/nhlua.h ../include/obj.h \ - ../include/objclass.h ../include/objects.h ../include/permonst.h \ - ../include/prop.h ../include/quest.h ../include/rect.h \ - ../include/region.h ../include/rm.h ../include/seffects.h \ - ../include/selvar.h ../include/skills.h ../include/sndprocs.h \ - ../include/spell.h ../include/stairs.h ../include/sym.h \ - ../include/sys.h ../include/timeout.h ../include/trap.h \ - ../include/vision.h ../include/winprocs.h ../include/wintype.h \ - ../include/you.h ../include/youprop.h + ../include/nhlua.h ../include/obj.h ../include/objclass.h \ + ../include/objects.h ../include/permonst.h ../include/prop.h \ + ../include/quest.h ../include/rect.h ../include/region.h \ + ../include/rm.h ../include/seffects.h ../include/selvar.h \ + ../include/skills.h ../include/sndprocs.h ../include/spell.h \ + ../include/stairs.h ../include/sym.h ../include/sys.h \ + ../include/timeout.h ../include/trap.h ../include/vision.h \ + ../include/weight.h ../include/winprocs.h \ + ../include/wintype.h ../include/you.h ../include/youprop.h touch $(HACK_H) # $(TARGETPFX)cppregex.o: ../sys/share/cppregex.cpp $(CONFIG_H) @@ -1177,7 +1177,7 @@ $(TARGETPFX)mdlib.o: mdlib.c $(CONFIG_H) ../include/align.h \ ../include/objclass.h ../include/objects.h \ ../include/permonst.h ../include/prop.h ../include/seffects.h \ ../include/skills.h ../include/sndprocs.h ../include/sym.h \ - ../include/wintype.h ../include/you.h + ../include/weight.h ../include/wintype.h ../include/you.h $(TARGETPFX)mhitm.o: mhitm.c $(HACK_H) ../include/artifact.h $(TARGETPFX)mhitu.o: mhitu.c $(HACK_H) ../include/artifact.h $(TARGETPFX)minion.o: minion.c $(HACK_H) @@ -1193,7 +1193,7 @@ $(TARGETPFX)monmove.o: monmove.c $(HACK_H) ../include/artifact.h \ $(TARGETPFX)monst.o: monst.c $(CONFIG_H) ../include/align.h \ ../include/defsym.h ../include/monattk.h ../include/monflag.h \ ../include/monsters.h ../include/permonst.h ../include/sym.h \ - ../include/wintype.h + ../include/weight.h ../include/wintype.h $(TARGETPFX)mplayer.o: mplayer.c $(HACK_H) $(TARGETPFX)mthrowu.o: mthrowu.c $(HACK_H) $(TARGETPFX)muse.o: muse.c $(HACK_H) diff --git a/sys/vms/Makefile.src b/sys/vms/Makefile.src index 6635a5690..14b75a3da 100644 --- a/sys/vms/Makefile.src +++ b/sys/vms/Makefile.src @@ -393,7 +393,7 @@ $(HACK_H) : $(INC)hack.h $(CONFIG_H) $(INC)align.h \ $(INC)dungeon.h $(INC)sym.h $(INC)defsym.h $(INC)mkroom.h \ $(INC)objclass.h $(INC)youprop.h $(INC)prop.h \ $(INC)permonst.h $(INC)monattk.h \ - $(INC)monflag.h $(INC)mondata.h $(INC)nhconst.h $(INC)pm.h \ + $(INC)monflag.h $(INC)mondata.h $(INC)pm.h \ $(INC)wintype.h $(INC)context.h $(INC)decl.h $(INC)quest.h \ $(INC)spell.h $(INC)color.h $(INC)obj.h \ $(INC)you.h $(INC)attrib.h $(INC)monst.h \ @@ -401,7 +401,7 @@ $(HACK_H) : $(INC)hack.h $(CONFIG_H) $(INC)align.h \ $(INC)monsters.h $(INC)timeout.h $(INC)trap.h \ $(INC)flag.h $(INC)rm.h $(INC)vision.h \ $(INC)display.h $(INC)engrave.h $(INC)rect.h $(INC)region.h \ - $(INC)winprocs.h $(INC)wintty.h $(INC)sys.h + $(INC)weight.h $(INC)winprocs.h $(INC)wintty.h $(INC)sys.h $(TOUCH) $(HACK_H) # VMS-specific code vmsmain.obj : $(VMS)vmsmain.c $(HACK_H) $(INC)dlb.h diff --git a/sys/vms/Makefile_src.vms b/sys/vms/Makefile_src.vms index b5a4d793e..dd46aafad 100644 --- a/sys/vms/Makefile_src.vms +++ b/sys/vms/Makefile_src.vms @@ -750,7 +750,8 @@ $(TARGETPFX)mdlib.obj: mdlib.c $(CONFIG_H) $(INCL)permonst.h \ $(INCL)sndprocs.h $(INCL)seffects.h $(INCL)obj.h \ $(INCL)monst.h $(INCL)mextra.h $(INCL)you.h \ $(INCL)attrib.h $(INCL)prop.h $(INCL)skills.h \ - $(INCL)context.h $(INCL)flag.h $(INCL)dlb.h + $(INCL)context.h $(INCL)flag.h $(INCL)dlb.h \ + $(INCL)weight.h $(TARGETPFX)mhitm.obj: mhitm.c $(HACK_H) $(INCL)artifact.h $(TARGETPFX)mhitu.obj: mhitu.c $(HACK_H) $(INCL)artifact.h $(TARGETPFX)minion.obj: minion.c $(HACK_H) @@ -766,7 +767,7 @@ $(TARGETPFX)monmove.obj: monmove.c $(HACK_H) $(INCL)mfndpos.h \ $(TARGETPFX)monst.obj: monst.c $(CONFIG_H) $(INCL)permonst.h \ $(INCL)align.h $(INCL)monattk.h $(INCL)monflag.h \ $(INCL)monsters.h $(INCL)wintype.h $(INCL)sym.h \ - $(INCL)defsym.h $(INCL)color.h + $(INCL)defsym.h $(INCL)color.h $(INCL)weight.h $(TARGETPFX)mplayer.obj: mplayer.c $(HACK_H) $(TARGETPFX)mthrowu.obj: mthrowu.c $(HACK_H) $(TARGETPFX)muse.obj: muse.c $(HACK_H) diff --git a/sys/windows/Makefile.nmake b/sys/windows/Makefile.nmake index b25fbb208..1a9d0e8ee 100644 --- a/sys/windows/Makefile.nmake +++ b/sys/windows/Makefile.nmake @@ -1121,14 +1121,14 @@ HACK_H = $(CONFIG_H) $(INCL)align.h $(INCL)artilist.h \ $(INCL)hack.h $(INCL)lint.h $(INCL)mextra.h \ $(INCL)mkroom.h $(INCL)monattk.h $(INCL)mondata.h \ $(INCL)monflag.h $(INCL)monst.h $(INCL)monsters.h \ - $(INCL)nhconst.h $(INCL)nhlua.h $(INCL)obj.h \ - $(INCL)objclass.h $(INCL)objects.h $(INCL)permonst.h \ - $(INCL)prop.h $(INCL)quest.h $(INCL)rect.h \ - $(INCL)region.h $(INCL)rm.h $(INCL)seffects.h \ - $(INCL)selvar.h $(INCL)skills.h $(INCL)sndprocs.h \ - $(INCL)spell.h $(INCL)stairs.h $(INCL)sym.h \ - $(INCL)sys.h $(INCL)timeout.h $(INCL)trap.h \ - $(INCL)vision.h $(INCL)winprocs.h $(INCL)wintype.h \ + $(INCL)nhlua.h $(INCL)obj.h $(INCL)objclass.h \ + $(INCL)objects.h $(INCL)permonst.h $(INCL)prop.h \ + $(INCL)quest.h $(INCL)rect.h $(INCL)region.h \ + $(INCL)rm.h $(INCL)seffects.h $(INCL)selvar.h \ + $(INCL)skills.h $(INCL)sndprocs.h $(INCL)spell.h \ + $(INCL)stairs.h $(INCL)sym.h $(INCL)sys.h \ + $(INCL)timeout.h $(INCL)trap.h $(INCL)vision.h \ + $(INCL)\weight.h $(INCL)winprocs.h $(INCL)wintype.h \ $(INCL)you.h $(INCL)youprop.h TILE_H = $(WSHR)tile.h diff --git a/sys/windows/vs/NetHack/NetHack.vcxproj b/sys/windows/vs/NetHack/NetHack.vcxproj index b18e4a771..da501d2fb 100644 --- a/sys/windows/vs/NetHack/NetHack.vcxproj +++ b/sys/windows/vs/NetHack/NetHack.vcxproj @@ -279,6 +279,7 @@ + diff --git a/sys/windows/vs/NetHackW/NetHackW.vcxproj b/sys/windows/vs/NetHackW/NetHackW.vcxproj index c4a065c03..c5562205e 100644 --- a/sys/windows/vs/NetHackW/NetHackW.vcxproj +++ b/sys/windows/vs/NetHackW/NetHackW.vcxproj @@ -341,6 +341,7 @@ + diff --git a/sys/windows/vs/tilemap/tilemap.vcxproj b/sys/windows/vs/tilemap/tilemap.vcxproj index aa34626e5..fdbbc92e7 100644 --- a/sys/windows/vs/tilemap/tilemap.vcxproj +++ b/sys/windows/vs/tilemap/tilemap.vcxproj @@ -79,6 +79,7 @@ + From e70b92e20080750ac8a6c23a9718346ad74fbf76 Mon Sep 17 00:00:00 2001 From: nhmall Date: Wed, 19 Mar 2025 17:31:19 -0400 Subject: [PATCH 517/791] paste error in Makefile.nmake --- sys/windows/Makefile.nmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/windows/Makefile.nmake b/sys/windows/Makefile.nmake index 1a9d0e8ee..c7b54b098 100644 --- a/sys/windows/Makefile.nmake +++ b/sys/windows/Makefile.nmake @@ -1128,7 +1128,7 @@ HACK_H = $(CONFIG_H) $(INCL)align.h $(INCL)artilist.h \ $(INCL)skills.h $(INCL)sndprocs.h $(INCL)spell.h \ $(INCL)stairs.h $(INCL)sym.h $(INCL)sys.h \ $(INCL)timeout.h $(INCL)trap.h $(INCL)vision.h \ - $(INCL)\weight.h $(INCL)winprocs.h $(INCL)wintype.h \ + $(INCL)weight.h $(INCL)winprocs.h $(INCL)wintype.h \ $(INCL)you.h $(INCL)youprop.h TILE_H = $(WSHR)tile.h From b237337806565ecab14dfb8697b024f8151ac9ae Mon Sep 17 00:00:00 2001 From: PatR Date: Wed, 19 Mar 2025 14:33:13 -0700 Subject: [PATCH 518/791] streamline domove_core() Split handling for paranoid_confirm:Trap out of domove_core() into a separate routine. There should be no change in behavior. --- src/hack.c | 145 +++++++++++++++++++++++++++++------------------------ 1 file changed, 79 insertions(+), 66 deletions(-) diff --git a/src/hack.c b/src/hack.c index 908f9e5e9..878c93f1c 100644 --- a/src/hack.c +++ b/src/hack.c @@ -38,6 +38,7 @@ staticfn boolean impaired_movement(coordxy *, coordxy *) NONNULLPTRS; staticfn boolean avoid_moving_on_trap(coordxy, coordxy, boolean); staticfn boolean avoid_moving_on_liquid(coordxy, coordxy, boolean); staticfn boolean avoid_running_into_trap_or_liquid(coordxy, coordxy); +staticfn boolean avoid_trap_andor_region(coordxy, coordxy); staticfn boolean move_out_of_bounds(coordxy, coordxy); staticfn boolean carrying_too_much(void); staticfn boolean escape_from_sticky_mon(coordxy, coordxy); @@ -2481,6 +2482,79 @@ avoid_running_into_trap_or_liquid(coordxy x, coordxy y) return FALSE; } +/* if paranoid_confirm:Trap is enabled, check whether the next step forward + needs player confirmation due to visible region or discovered trap; + result: True => stop moving, False => proceed */ +staticfn boolean +avoid_trap_andor_region(coordxy x, coordxy y) +{ + char qbuf[QBUFSZ]; + NhRegion *newreg, *oldreg; + struct trap *trap = NULL; + + /* treat entering a visible gas cloud region like entering a trap; + there could be a known trap as well as a region at the target spot; + if so, ask about entring the region first; even though this could + lead to two consecutive confirmation prompts, the situation seems + to be too uncommon to warrant a separate case with combined + trap+region confirmation */ + if (ParanoidTrap && !Blind && !Stunned && !Confusion && !Hallucination + /* skip if player used 'm' prefix or is moving recklessly */ + && (!svc.context.nopick || svc.context.run) + /* check for region(s) */ + && (newreg = visible_region_at(x, y)) != 0 + && ((oldreg = visible_region_at(u.ux, u.uy)) == 0 + /* if moving from one region into another, only ask for + confirmation if the one potentially being entered inflicts + damage (poison gas) and the one being exited doesn't (vapor) */ + || (reg_damg(newreg) > 0 && reg_damg(oldreg) == 0)) + /* check whether attempted move will be viable */ + && test_move(u.ux, u.uy, u.dx, u.dy, TEST_MOVE) + /* we don't override confirmation for poison resistance since the + region also hinders hero's vision even if/when no damage is done */ + ) { + Snprintf(qbuf, sizeof qbuf, "%s into that %s cloud?", + u_locomotion("step"), + (reg_damg(newreg) > 0) ? "poison gas" : "vapor"); + if (!paranoid_query(ParanoidConfirm, upstart(qbuf))) { + nomul(0); + svc.context.move = 0; + return TRUE; + } + } + + /* maybe ask player for confirmation before walking into known trap */ + if (ParanoidTrap && !Stunned && !Confusion + /* skip if player used 'm' prefix or is moving recklessly */ + && (!svc.context.nopick || svc.context.run) + /* check for discovered trap */ + && (trap = t_at(x, y)) != 0 && trap->tseen + /* check whether attempted move will be viable */ + && test_move(u.ux, u.uy, u.dx, u.dy, TEST_MOVE) + /* override confirmation if the trap is harmless to the hero */ + && (immune_to_trap(&gy.youmonst, trap->ttyp) != TRAP_CLEARLY_IMMUNE + /* Hallucination: all traps still show as ^, but the + hero can't tell what they are, so treat as dangerous */ + || Hallucination)) { + int traptype = (Hallucination ? rnd(TRAPNUM - 1) : (int) trap->ttyp); + boolean into = into_vs_onto(traptype); + + Snprintf(qbuf, sizeof qbuf, "Really %s %s that %s?", + u_locomotion("step"), into ? "into" : "onto", + defsyms[trap_to_defsym(traptype)].explanation); + /* handled like paranoid_confirm:pray; when paranoid_confirm:trap + isn't set, don't ask at all but if it is set (checked above), + ask via y/n if parnoid_confirm:confirm isn't also set or via + yes/no if it is */ + if (!paranoid_query(ParanoidConfirm, qbuf)) { + nomul(0); + svc.context.move = 0; + return TRUE; + } + } + return FALSE; +} + /* trying to move out-of-bounds? */ staticfn boolean move_out_of_bounds(coordxy x, coordxy y) @@ -2612,9 +2686,7 @@ domove_core(void) { struct monst *mtmp; struct rm *tmpr; - NhRegion *newreg, *oldreg; coordxy x, y; - struct trap *trap = NULL; int glyph; coordxy chainx = 0, chainy = 0, ballx = 0, bally = 0; /* ball&chain new positions */ @@ -2721,74 +2793,15 @@ domove_core(void) if (u_rooted()) return; - /* treat entering a visible gas cloud region like entering a trap; - there could be a known trap as well as a region at the target spot; - if so, ask about entring the region first; even though this could - lead to two consecutive confirmation prompts, the situation seems - to be too uncommon to warrant a separate case with combined - trap+region confirmation */ - if (ParanoidTrap && !Blind && !Stunned && !Confusion && !Hallucination - /* skip if player used 'm' prefix or is moving recklessly */ - && (!svc.context.nopick || svc.context.run) - /* check for region(s) */ - && (newreg = visible_region_at(x, y)) != 0 - && ((oldreg = visible_region_at(u.ux, u.uy)) == 0 - /* if moving from one region into another, only ask for - confirmation if the one potentially being entered inflicts - damage (poison gas) and the one being exited doesn't - (vapor) */ - || (reg_damg(newreg) > 0 && reg_damg(oldreg) == 0)) - /* check whether attempted move will be viable */ - && test_move(u.ux, u.uy, u.dx, u.dy, TEST_MOVE) - /* we don't override confirmation for poison resistance since - the region also hinders hero's vision even if/when no damage - is done */ - ) { - char qbuf[QBUFSZ]; - - Snprintf(qbuf, sizeof qbuf, "%s into that %s cloud?", - u_locomotion("step"), - (reg_damg(newreg) > 0) ? "poison gas" : "vapor"); - if (!paranoid_query(ParanoidConfirm, upstart(qbuf))) { - nomul(0); - svc.context.move = 0; + /* handling for paranoid_confirm:Trap which doubles as + paranoid_confirm:Region */ + if (ParanoidTrap) { + if (avoid_trap_andor_region(x, y)) return; - } - } - /* maybe ask player for confirmation before walking into known trap */ - if (ParanoidTrap && !Stunned && !Confusion - /* skip if player used 'm' prefix or is moving recklessly */ - && (!svc.context.nopick || svc.context.run) - /* check for discovered trap */ - && (trap = t_at(x, y)) != 0 && trap->tseen - /* check whether attempted move will be viable */ - && test_move(u.ux, u.uy, u.dx, u.dy, TEST_MOVE) - /* override confirmation if the trap is harmless to the hero */ - && (immune_to_trap(&gy.youmonst, trap->ttyp) != TRAP_CLEARLY_IMMUNE - /* Hallucination: all traps still show as ^, but the - hero can't tell what they are, so treat as dangerous */ - || Hallucination)) { - char qbuf[QBUFSZ]; - int traptype = (Hallucination ? rnd(TRAPNUM - 1) - : (int) trap->ttyp); - boolean into = into_vs_onto(traptype); - - Snprintf(qbuf, sizeof qbuf, "Really %s %s that %s?", - u_locomotion("step"), into ? "into" : "onto", - defsyms[trap_to_defsym(traptype)].explanation); - /* handled like paranoid_confirm:pray; when paranoid_confirm:trap - isn't set, don't ask at all but if it is set (checked above), - ask via y/n if parnoid_confirm:confirm isn't also set or via - yes/no if it is */ - if (!paranoid_query(ParanoidConfirm, qbuf)) { - nomul(0); - svc.context.move = 0; - return; - } } if (u.utrap) { /* when u.utrap is True, displaceu is False */ - boolean moved = trapmove(x, y, trap); + boolean moved = trapmove(x, y, (struct trap *) NULL); if (!u.utrap) { disp.botl = TRUE; From 5cc94c74c8bf83f0c61ba3bc08a30805155feb51 Mon Sep 17 00:00:00 2001 From: nhw_cron Date: Wed, 19 Mar 2025 17:24:06 -0400 Subject: [PATCH 519/791] This is cron-daily v1-Apr-1-2024. 000files updated: Files --- Files | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Files b/Files index 49234e7a8..04f76ecb6 100644 --- a/Files +++ b/Files @@ -94,14 +94,14 @@ dlb.h dungeon.h engrave.h extern.h flag.h fnamesiz.h func_tab.h global.h hack.h hacklib.h integer.h isaac64.h lint.h mail.h mextra.h mfndpos.h micro.h mkroom.h monattk.h mondata.h -monflag.h monst.h monsters.h nhconst.h nhmd4.h -nhregex.h obj.h objclass.h objects.h optlist.h -patchlevel.h pcconf.h permonst.h prop.h quest.h -rect.h region.h rm.h seffects.h selvar.h -skills.h sndprocs.h sp_lev.h spell.h stairs.h -sym.h sys.h tcap.h tileset.h timeout.h -tradstdc.h trap.h unixconf.h vision.h vmsconf.h -warnings.h winami.h wincurs.h windconf.h winprocs.h +monflag.h monst.h monsters.h nhmd4.h nhregex.h +obj.h objclass.h objects.h optlist.h patchlevel.h +pcconf.h permonst.h prop.h quest.h rect.h +region.h rm.h seffects.h selvar.h skills.h +sndprocs.h sp_lev.h spell.h stairs.h sym.h +sys.h tcap.h tileset.h timeout.h tradstdc.h +trap.h unixconf.h vision.h vmsconf.h warnings.h +weight.h winami.h wincurs.h windconf.h winprocs.h wintype.h you.h youprop.h (file for tty versions) From 872a9778edb72b03d637ed4e4fb79a67a78abde9 Mon Sep 17 00:00:00 2001 From: nhmall Date: Wed, 19 Mar 2025 19:26:27 -0400 Subject: [PATCH 520/791] Xcode project update --- sys/unix/NetHack.xcodeproj/project.pbxproj | 54 ++++++++++++++-------- 1 file changed, 35 insertions(+), 19 deletions(-) diff --git a/sys/unix/NetHack.xcodeproj/project.pbxproj b/sys/unix/NetHack.xcodeproj/project.pbxproj index 55f36fd7f..644d86393 100644 --- a/sys/unix/NetHack.xcodeproj/project.pbxproj +++ b/sys/unix/NetHack.xcodeproj/project.pbxproj @@ -164,6 +164,7 @@ 5462D14823E7B19200969423 /* insight.c in Sources */ = {isa = PBXBuildFile; fileRef = 5462D14723E7B19200969423 /* insight.c */; }; 5493735A277AAE830031FE02 /* alloc.c in Sources */ = {isa = PBXBuildFile; fileRef = 31B8A36521A238040055BD01 /* alloc.c */; }; 54A3D3EC282C55A900143F8C /* utf8map.c in Sources */ = {isa = PBXBuildFile; fileRef = 54A3D3EB282C55A900143F8C /* utf8map.c */; }; + 54BD340D2D8B70350073C484 /* hacklib.c in Sources */ = {isa = PBXBuildFile; fileRef = 31B8A36421A238040055BD01 /* hacklib.c */; }; 54FB2B4B246310A600397C0E /* symbols.c in Sources */ = {isa = PBXBuildFile; fileRef = 54FB2B4A246310A600397C0E /* symbols.c */; }; 54FCE8292223261F00F393C8 /* isaac64.c in Sources */ = {isa = PBXBuildFile; fileRef = 54FCE8282223261F00F393C8 /* isaac64.c */; }; BAB57DB527C1C3E200FCF150 /* libnhlua.a in Frameworks */ = {isa = PBXBuildFile; fileRef = BAE8010A27B97760002B3786 /* libnhlua.a */; }; @@ -528,7 +529,6 @@ 544768B523995488004B9739 /* nhlua.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = nhlua.h; path = ../../include/nhlua.h; sourceTree = ""; }; 544768B923995BB7004B9739 /* liblua.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = liblua.a; path = ../../lib/lua/liblua.a; sourceTree = ""; }; 5462D14723E7B19200969423 /* insight.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = insight.c; path = ../../src/insight.c; sourceTree = ""; }; - 546A4E5A29AAB2DA00E02495 /* seffects.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = seffects.h; sourceTree = ""; }; 548FB9F9297F2B03000D04CF /* sndprocs.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = sndprocs.h; path = ../../include/sndprocs.h; sourceTree = ""; }; 548FB9FA297F2BBD000D04CF /* optlist.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = optlist.h; path = ../../include/optlist.h; sourceTree = ""; }; 548FB9FB297F2BBD000D04CF /* hacklib.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = hacklib.h; path = ../../include/hacklib.h; sourceTree = ""; }; @@ -540,6 +540,11 @@ 548FBA01297F2BBD000D04CF /* monsters.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = monsters.h; path = ../../include/monsters.h; sourceTree = ""; }; 54A3D3EB282C55A900143F8C /* utf8map.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = utf8map.c; path = ../../src/utf8map.c; sourceTree = ""; }; 54AEB885297EE7C4005F1B13 /* macsound.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = macsound.m; path = ../../sound/macsound/macsound.m; sourceTree = ""; }; + 54BD340E2D8B711E0073C484 /* nhregex.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = nhregex.h; path = /Users/mikeallison/Documents/devel/git/NHsource/include/nhregex.h; sourceTree = ""; }; + 54BD340F2D8B711E0073C484 /* seffects.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = seffects.h; path = /Users/mikeallison/Documents/devel/git/NHsource/include/seffects.h; sourceTree = ""; }; + 54BD34102D8B711E0073C484 /* selvar.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = selvar.h; path = /Users/mikeallison/Documents/devel/git/NHsource/include/selvar.h; sourceTree = ""; }; + 54BD34112D8B711E0073C484 /* stairs.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = stairs.h; path = /Users/mikeallison/Documents/devel/git/NHsource/include/stairs.h; sourceTree = ""; }; + 54BD34122D8B711E0073C484 /* weight.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = weight.h; path = /Users/mikeallison/Documents/devel/git/NHsource/include/weight.h; sourceTree = ""; }; 54FB2B4A246310A600397C0E /* symbols.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = symbols.c; path = ../../src/symbols.c; sourceTree = ""; }; 54FCE8282223261F00F393C8 /* isaac64.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = isaac64.c; path = ../../src/isaac64.c; sourceTree = ""; }; BAE8010A27B97760002B3786 /* libnhlua.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libnhlua.a; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -797,18 +802,6 @@ 3189579621A2046700FB2ABE /* include */ = { isa = PBXGroup; children = ( - 546A4E5A29AAB2DA00E02495 /* seffects.h */, - 548FB9FD297F2BBD000D04CF /* defsym.h */, - 548FB9FE297F2BBD000D04CF /* fnamesiz.h */, - 548FB9FB297F2BBD000D04CF /* hacklib.h */, - 548FBA01297F2BBD000D04CF /* monsters.h */, - 548FB9FF297F2BBD000D04CF /* objects.h */, - 548FB9FA297F2BBD000D04CF /* optlist.h */, - 548FBA00297F2BBD000D04CF /* tile.h */, - 548FB9FC297F2BBD000D04CF /* warnings.h */, - 548FB9F9297F2B03000D04CF /* sndprocs.h */, - 544768B523995488004B9739 /* nhlua.h */, - 544768B423995447004B9739 /* isaac64.h */, 3186A3B721A4B0FD0052BF02 /* align.h */, 3186A38821A4B0FB0052BF02 /* artifact.h */, 3186A3AB21A4B0FD0052BF02 /* artilist.h */, @@ -819,8 +812,10 @@ 3186A3C621A4B0FE0052BF02 /* config1.h */, 3186A37121A4B0FA0052BF02 /* context.h */, 3186A3C521A4B0FE0052BF02 /* coord.h */, + 3186A38A21A4B0FB0052BF02 /* cstd.h */, 3186A3B021A4B0FD0052BF02 /* date.h */, 3186A3D021A4B0FE0052BF02 /* decl.h */, + 548FB9FD297F2BBD000D04CF /* defsym.h */, 3186A3A021A4B0FD0052BF02 /* dgn_file.h */, 3186A3A921A4B0FD0052BF02 /* display.h */, 3186A38E21A4B0FC0052BF02 /* dlb.h */, @@ -828,10 +823,13 @@ 3186A3A221A4B0FD0052BF02 /* engrave.h */, 3186A37021A4B0FA0052BF02 /* extern.h */, 3186A3B521A4B0FD0052BF02 /* flag.h */, + 548FB9FE297F2BBD000D04CF /* fnamesiz.h */, 3186A37321A4B0FA0052BF02 /* func_tab.h */, 3186A3C121A4B0FD0052BF02 /* global.h */, 3186A3A521A4B0FD0052BF02 /* hack.h */, + 548FB9FB297F2BBD000D04CF /* hacklib.h */, 3186A37A21A4B0FA0052BF02 /* integer.h */, + 544768B423995447004B9739 /* isaac64.h */, 3186A3BC21A4B0FD0052BF02 /* lint.h */, 3186A3B821A4B0FD0052BF02 /* mail.h */, 3186A38521A4B0FB0052BF02 /* mextra.h */, @@ -842,10 +840,13 @@ 3186A3C821A4B0FE0052BF02 /* mondata.h */, 3186A38F21A4B0FC0052BF02 /* monflag.h */, 3186A3BB21A4B0FD0052BF02 /* monst.h */, - 3186A38421A4B0FB0052BF02 /* sym.h */, - 3186A39B21A4B0FD0052BF02 /* windconf.h */, + 548FBA01297F2BBD000D04CF /* monsters.h */, + 544768B523995488004B9739 /* nhlua.h */, + 54BD340E2D8B711E0073C484 /* nhregex.h */, 3186A39521A4B0FC0052BF02 /* obj.h */, 3186A3A821A4B0FD0052BF02 /* objclass.h */, + 548FB9FF297F2BBD000D04CF /* objects.h */, + 548FB9FA297F2BBD000D04CF /* optlist.h */, 3186A37521A4B0FA0052BF02 /* patchlevel.h */, 3186A38121A4B0FB0052BF02 /* pcconf.h */, 3186A38321A4B0FB0052BF02 /* permonst.h */, @@ -854,12 +855,17 @@ 3186A37C21A4B0FA0052BF02 /* rect.h */, 3186A37B21A4B0FA0052BF02 /* region.h */, 3186A39721A4B0FC0052BF02 /* rm.h */, + 54BD340F2D8B711E0073C484 /* seffects.h */, + 54BD34102D8B711E0073C484 /* selvar.h */, 3186A38221A4B0FB0052BF02 /* skills.h */, + 548FB9F9297F2B03000D04CF /* sndprocs.h */, 3186A3B621A4B0FD0052BF02 /* sp_lev.h */, 3186A3A321A4B0FD0052BF02 /* spell.h */, + 54BD34112D8B711E0073C484 /* stairs.h */, + 3186A38421A4B0FB0052BF02 /* sym.h */, 3186A3CB21A4B0FE0052BF02 /* sys.h */, - 3186A38A21A4B0FB0052BF02 /* cstd.h */, 3186A3C321A4B0FE0052BF02 /* tcap.h */, + 548FBA00297F2BBD000D04CF /* tile.h */, 3186A3A121A4B0FD0052BF02 /* tile2x11.h */, 3186A39421A4B0FC0052BF02 /* tileset.h */, 3186A3CA21A4B0FE0052BF02 /* timeout.h */, @@ -868,8 +874,11 @@ 3186A3AD21A4B0FD0052BF02 /* unixconf.h */, 3186A37E21A4B0FA0052BF02 /* vision.h */, 3186A3BE21A4B0FD0052BF02 /* vmsconf.h */, + 548FB9FC297F2BBD000D04CF /* warnings.h */, + 54BD34122D8B711E0073C484 /* weight.h */, 3186A3AA21A4B0FD0052BF02 /* winami.h */, 3186A37621A4B0FA0052BF02 /* wincurs.h */, + 3186A39B21A4B0FD0052BF02 /* windconf.h */, 3186A36F21A4B0FA0052BF02 /* winprocs.h */, 3186A39A21A4B0FD0052BF02 /* wintty.h */, 3186A3C021A4B0FD0052BF02 /* wintype.h */, @@ -1196,6 +1205,7 @@ outputFileListPaths = ( ); outputPaths = ( + "${NH_LIB_DIR}/libnhlua.a", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; @@ -1222,6 +1232,7 @@ }; 059660C22C80B0FD00398EDE /* Codesign dlb */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); @@ -1251,6 +1262,7 @@ outputFileListPaths = ( ); outputPaths = ( + "$(NH_UTIL_DIR}/recover", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; @@ -1362,7 +1374,7 @@ }; 317E7C5421A3804400F6E4E5 /* Build Guidebook */ = { isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; + buildActionMask = 8; files = ( ); inputFileListPaths = ( @@ -1379,7 +1391,7 @@ outputPaths = ( "$(NH_DOC_DIR)/Guidebook", ); - runOnlyForDeploymentPostprocessing = 0; + runOnlyForDeploymentPostprocessing = 1; shellPath = /bin/sh; shellScript = "cd \"${NH_DOC_DIR}\"\ncat Guidebook.mn | ${NH_UTIL_DIR}/makedefs --grep --input - --output - | tbl tmac.n - | nroff -c -Tascii | col -bx > Guidebook\n"; }; @@ -1874,7 +1886,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 059660BE2C80B00400398EDE /* hacklib.c in Sources */, + 54BD340D2D8B70350073C484 /* hacklib.c in Sources */, 31B8A45221A26A750055BD01 /* recover.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -2151,6 +2163,7 @@ INSTALL_PATH = "$(NH_INSTALL_DIR)"; MACOSX_DEPLOYMENT_TARGET = "$(RECOMMENDED_MACOSX_DEPLOYMENT_TARGET)"; OTHER_CFLAGS = ( + "-Wno-ambiguous-macro", "-DNOMAIL", "-DNOTPARMDECL", "-DDEFAULT_WINDOW_SYS=\\\"tty\\\"", @@ -2182,6 +2195,7 @@ INSTALL_PATH = "$(NH_INSTALL_DIR)"; MACOSX_DEPLOYMENT_TARGET = "$(RECOMMENDED_MACOSX_DEPLOYMENT_TARGET)"; OTHER_CFLAGS = ( + "-Wno-ambiguous-macro", "-DNOMAIL", "-DNOTPARMDECL", "-DDEFAULT_WINDOW_SYS=\\\"tty\\\"", @@ -2278,6 +2292,7 @@ CODE_SIGN_STYLE = Automatic; DEAD_CODE_STRIPPING = YES; DEVELOPMENT_TEAM = 6978C4Q2VB; + ENABLE_USER_SCRIPT_SANDBOXING = NO; EXECUTABLE_PREFIX = lib; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_NO_COMMON_BLOCKS = YES; @@ -2314,6 +2329,7 @@ CODE_SIGN_STYLE = Automatic; DEAD_CODE_STRIPPING = YES; DEVELOPMENT_TEAM = 6978C4Q2VB; + ENABLE_USER_SCRIPT_SANDBOXING = NO; EXECUTABLE_PREFIX = lib; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_NO_COMMON_BLOCKS = YES; From b55162a605a4ea842f341d1888aca2480ad17c00 Mon Sep 17 00:00:00 2001 From: nhmall Date: Wed, 19 Mar 2025 19:46:11 -0400 Subject: [PATCH 521/791] more file name change follow-up for weight.h --- include/weight.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/weight.h b/include/weight.h index 2a1113fb8..b89b4c56a 100644 --- a/include/weight.h +++ b/include/weight.h @@ -1,9 +1,9 @@ -/* NetHack 3.7 nhconst.h $NHDT-Date: 1725653014 2024/09/06 20:03:34 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.26 $ */ +/* NetHack 3.7 weight.h $NHDT-Date: 1742427965 2025/03/19 23:46:05 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.1 $ */ /* Copyright (c) Michael Allison, 2025. */ /* NetHack may be freely redistributed. See license for details. */ -#ifndef NHCONST_H -#define NHCONST_H +#ifndef WEIGHT_H +#define WEIGHT_H /* weight-related constants and thresholds */ enum weight_constants { @@ -29,6 +29,6 @@ enum weight_constants { WT_DRAGON = 4500, /* weight of dragon body */ }; -#endif /* NHCONST_H */ +#endif /* WEIGHT_H */ From d7f107eaf953754b7ba98a76f81cadac90d1db18 Mon Sep 17 00:00:00 2001 From: PatR Date: Wed, 19 Mar 2025 17:30:56 -0700 Subject: [PATCH 522/791] still more 'nethack --dumpweights' After updating the --dumpweights code in hack.c to insert "pair of" for gloves and boots and "set of" for dragon scales, I've switched it to use simple_typename() instead. Turns out that that routine also lacked handling for 'pair|set of'. And it was generating "coin of gold piece". Fix those. Roughly half of the gems are "" and the others " stone", so the --dumpweights output is different by more than just pair/set. --- src/hack.c | 16 +++------------- src/objnam.c | 15 +++++++++++---- 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/src/hack.c b/src/hack.c index 878c93f1c..af9d392c5 100644 --- a/src/hack.c +++ b/src/hack.c @@ -4349,25 +4349,15 @@ dump_weights(void) for (i = 0; i < ocount; ++i) { const char *oc_name = (i == SLIME_MOLD) ? "slime mold" : obj_descr[i].oc_name; - int wt = (int) objects[i].oc_weight, - ocls = objects[i].oc_class; + int wt = (int) objects[i].oc_weight; if (wt && oc_name) { weightlist[cnt].idx = i; weightlist[cnt].wt = wt; weightlist[cnt].wtyp = 2; weightlist[cnt].unique = (objects[i].oc_unique != 0); - Snprintf(nmbufbase, sizeof nmbufbase, "%s%s", - (ocls == POTION_CLASS) ? "potion of " - : (ocls == WAND_CLASS) ? "wand of " - : (ocls == SCROLL_CLASS) ? "scroll of " - : (ocls == RING_CLASS) ? "ring of " - : (ocls == SPBOOK_CLASS - && objects[i].oc_name_idx != SPE_BOOK_OF_THE_DEAD - && objects[i].oc_name_idx != SPE_NOVEL) - ? "spellbook of " - : "", - oc_name); + objects[i].oc_name_known = 1; + Strcpy(nmbufbase, simple_typename(i)); Snprintf(nmbuf, sizeof nmbuf, "%07u%s", wt, (weightlist[cnt].unique) ? the(nmbufbase) : an(nmbufbase)); diff --git a/src/objnam.c b/src/objnam.c index d3ce48ffb..334e383dd 100644 --- a/src/objnam.c +++ b/src/objnam.c @@ -220,8 +220,7 @@ obj_typename(int otyp) buf[0] = '\0'; /* redundant */ switch (ocl->oc_class) { case COIN_CLASS: - Strcpy(buf, "coin"); - break; + return strcpy(buf, actualn); /* "gold piece" */ case POTION_CLASS: Strcpy(buf, "potion"); break; @@ -252,9 +251,17 @@ obj_typename(int otyp) if (dn) Sprintf(eos(buf), " (%s)", dn); return buf; + case ARMOR_CLASS: + if (objects[otyp].oc_armcat == ARM_GLOVES + || objects[otyp].oc_armcat == ARM_BOOTS) + Strcpy(buf, "pair of "); + else if (otyp >= GRAY_DRAGON_SCALES && otyp <= YELLOW_DRAGON_SCALES) + Strcpy(buf, "set of "); + FALLTHROUGH; + /*FALLTHRU*/ default: if (nn) { - Strcpy(buf, actualn); + Strcat(buf, actualn); if (GemStone(otyp)) Strcat(buf, " stone"); if (un) /* 3: length of " (" + ")" which will enclose 'dn' */ @@ -262,7 +269,7 @@ obj_typename(int otyp) if (dn) Sprintf(eos(buf), " (%s)", dn); } else { - Strcpy(buf, dn ? dn : actualn); + Strcat(buf, dn ? dn : actualn); if (ocl->oc_class == GEM_CLASS) Strcat(buf, (ocl->oc_material == MINERAL) ? " stone" : " gem"); From f30780e42e3ec81123004704057b3eac8a5f9ce4 Mon Sep 17 00:00:00 2001 From: nhmall Date: Wed, 19 Mar 2025 21:16:46 -0400 Subject: [PATCH 523/791] clean up absolute paths --- sys/unix/NetHack.xcodeproj/project.pbxproj | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sys/unix/NetHack.xcodeproj/project.pbxproj b/sys/unix/NetHack.xcodeproj/project.pbxproj index 644d86393..3d9906363 100644 --- a/sys/unix/NetHack.xcodeproj/project.pbxproj +++ b/sys/unix/NetHack.xcodeproj/project.pbxproj @@ -540,11 +540,11 @@ 548FBA01297F2BBD000D04CF /* monsters.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = monsters.h; path = ../../include/monsters.h; sourceTree = ""; }; 54A3D3EB282C55A900143F8C /* utf8map.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = utf8map.c; path = ../../src/utf8map.c; sourceTree = ""; }; 54AEB885297EE7C4005F1B13 /* macsound.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = macsound.m; path = ../../sound/macsound/macsound.m; sourceTree = ""; }; - 54BD340E2D8B711E0073C484 /* nhregex.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = nhregex.h; path = /Users/mikeallison/Documents/devel/git/NHsource/include/nhregex.h; sourceTree = ""; }; - 54BD340F2D8B711E0073C484 /* seffects.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = seffects.h; path = /Users/mikeallison/Documents/devel/git/NHsource/include/seffects.h; sourceTree = ""; }; - 54BD34102D8B711E0073C484 /* selvar.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = selvar.h; path = /Users/mikeallison/Documents/devel/git/NHsource/include/selvar.h; sourceTree = ""; }; - 54BD34112D8B711E0073C484 /* stairs.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = stairs.h; path = /Users/mikeallison/Documents/devel/git/NHsource/include/stairs.h; sourceTree = ""; }; - 54BD34122D8B711E0073C484 /* weight.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = weight.h; path = /Users/mikeallison/Documents/devel/git/NHsource/include/weight.h; sourceTree = ""; }; + 54BD340E2D8B711E0073C484 /* nhregex.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = nhregex.h; path = ../../include/nhregex.h; sourceTree = ""; }; + 54BD340F2D8B711E0073C484 /* seffects.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = seffects.h; path = ../../include/seffects.h; sourceTree = ""; }; + 54BD34102D8B711E0073C484 /* selvar.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = selvar.h; path = ../../include/selvar.h; sourceTree = ""; }; + 54BD34112D8B711E0073C484 /* stairs.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = stairs.h; path = ../../include/stairs.h; sourceTree = ""; }; + 54BD34122D8B711E0073C484 /* weight.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = weight.h; path = ../../include/weight.h; sourceTree = ""; }; 54FB2B4A246310A600397C0E /* symbols.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = symbols.c; path = ../../src/symbols.c; sourceTree = ""; }; 54FCE8282223261F00F393C8 /* isaac64.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = isaac64.c; path = ../../src/isaac64.c; sourceTree = ""; }; BAE8010A27B97760002B3786 /* libnhlua.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libnhlua.a; sourceTree = BUILT_PRODUCTS_DIR; }; From 3ed63f9be42d3dd3e4989cafadd4074f9ad7a389 Mon Sep 17 00:00:00 2001 From: nhmall Date: Wed, 19 Mar 2025 21:20:39 -0400 Subject: [PATCH 524/791] more Xcode cleanup --- sys/unix/NetHack.xcodeproj/project.pbxproj | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sys/unix/NetHack.xcodeproj/project.pbxproj b/sys/unix/NetHack.xcodeproj/project.pbxproj index 3d9906363..762be72de 100644 --- a/sys/unix/NetHack.xcodeproj/project.pbxproj +++ b/sys/unix/NetHack.xcodeproj/project.pbxproj @@ -540,11 +540,11 @@ 548FBA01297F2BBD000D04CF /* monsters.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = monsters.h; path = ../../include/monsters.h; sourceTree = ""; }; 54A3D3EB282C55A900143F8C /* utf8map.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = utf8map.c; path = ../../src/utf8map.c; sourceTree = ""; }; 54AEB885297EE7C4005F1B13 /* macsound.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = macsound.m; path = ../../sound/macsound/macsound.m; sourceTree = ""; }; - 54BD340E2D8B711E0073C484 /* nhregex.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = nhregex.h; path = ../../include/nhregex.h; sourceTree = ""; }; - 54BD340F2D8B711E0073C484 /* seffects.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = seffects.h; path = ../../include/seffects.h; sourceTree = ""; }; - 54BD34102D8B711E0073C484 /* selvar.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = selvar.h; path = ../../include/selvar.h; sourceTree = ""; }; - 54BD34112D8B711E0073C484 /* stairs.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = stairs.h; path = ../../include/stairs.h; sourceTree = ""; }; - 54BD34122D8B711E0073C484 /* weight.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = weight.h; path = ../../include/weight.h; sourceTree = ""; }; + 54BD340E2D8B711E0073C484 /* nhregex.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = nhregex.h; path = ../../include/nhregex.h; sourceTree = ""; }; + 54BD340F2D8B711E0073C484 /* seffects.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = seffects.h; path = ../../include/seffects.h; sourceTree = ""; }; + 54BD34102D8B711E0073C484 /* selvar.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = selvar.h; path = ../../include/selvar.h; sourceTree = ""; }; + 54BD34112D8B711E0073C484 /* stairs.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = stairs.h; path = ../../include/stairs.h; sourceTree = ""; }; + 54BD34122D8B711E0073C484 /* weight.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = weight.h; path = ../../include/weight.h; sourceTree = ""; }; 54FB2B4A246310A600397C0E /* symbols.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = symbols.c; path = ../../src/symbols.c; sourceTree = ""; }; 54FCE8282223261F00F393C8 /* isaac64.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = isaac64.c; path = ../../src/isaac64.c; sourceTree = ""; }; BAE8010A27B97760002B3786 /* libnhlua.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libnhlua.a; sourceTree = BUILT_PRODUCTS_DIR; }; From 9e2a0f977ecf018dc61e19622e4c089aad0a92e8 Mon Sep 17 00:00:00 2001 From: nhmall Date: Thu, 20 Mar 2025 14:39:04 -0400 Subject: [PATCH 525/791] fixes entry update --- doc/fixes3-7-0.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index bce39a4d1..c98cd28e5 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -2781,6 +2781,7 @@ blessed scroll of destroy armor asks which armor to destroy archeologists' fedora is lucky telepathic hero can discern which particular monster just read a scroll add "make fetch-docs" to download pre-formatted documentation +monsters will use throw-and-return weapons such as an aklys Platform- and/or Interface-Specific New Features From 1df8fd8b3bc3c393bba83e7f8aed3589986ca3b2 Mon Sep 17 00:00:00 2001 From: PatR Date: Thu, 20 Mar 2025 16:09:15 -0700 Subject: [PATCH 526/791] cutting down closed doors Most things that can be dug or chopped can only have that done by one of the two types of digging/chopping tools: pick-axe or axe. Since closed door can be broken open via either type, mention the type of implement in the final "you break through the door" message by adding "with your ." --- src/dig.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/src/dig.c b/src/dig.c index fabafac7b..e8a89888f 100644 --- a/src/dig.c +++ b/src/dig.c @@ -438,6 +438,7 @@ dig(void) } if (svc.context.digging.effort > 100) { + char digbuf[BUFSZ]; const char *digtxt, *dmgtxt = (const char *) 0; struct obj *obj, *bobj; boolean shopedge = *in_rooms(dpx, dpy, SHOPBASE); @@ -504,7 +505,9 @@ dig(void) if (!(lev->doormask & D_TRAPPED)) lev->doormask = D_BROKEN; } else if (closed_door(dpx, dpy)) { - digtxt = "You break through the door."; + Sprintf(digbuf, "You break through the door with your %s.", + simpleonames(uwep)); + digtxt = digbuf; if (shopedge) { add_damage(dpx, dpy, SHOP_DOOR_COST); dmgtxt = "break"; @@ -523,18 +526,9 @@ dig(void) pay_for_damage(dmgtxt, FALSE); if (Is_earthlevel(&u.uz) && !rn2(3)) { - struct monst *mtmp; + int mndx = rn2(2) ? PM_EARTH_ELEMENTAL : PM_XORN; - switch (rn2(2)) { - case 0: - mtmp = makemon(&mons[PM_EARTH_ELEMENTAL], dpx, dpy, - MM_NOMSG); - break; - default: - mtmp = makemon(&mons[PM_XORN], dpx, dpy, MM_NOMSG); - break; - } - if (mtmp) + if (makemon(&mons[mndx], dpx, dpy, MM_NOMSG)) pline_The("debris from your digging comes to life!"); } if (IS_DOOR(lev->typ) && (lev->doormask & D_TRAPPED)) { From da197df75e5fb6c6d827246a8389c06e2d7d1aa7 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 22 Mar 2025 12:17:12 -0400 Subject: [PATCH 527/791] comment typo --- include/weight.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/weight.h b/include/weight.h index b89b4c56a..a404eb1af 100644 --- a/include/weight.h +++ b/include/weight.h @@ -25,7 +25,7 @@ enum weight_constants { MAX_CARR_CAP = 1000, /* max carrying capacity, so that * boulders can be heavier */ WT_HUMAN = 1450, /* weight of human body */ - WT_BABY_DRAGON = 1500, /* weight ob baby dragon body */ + WT_BABY_DRAGON = 1500, /* weight of baby dragon body */ WT_DRAGON = 4500, /* weight of dragon body */ }; From b32ce258e37affe4dcfe548a69476008ca7a58e7 Mon Sep 17 00:00:00 2001 From: copperwater Date: Sat, 29 Mar 2025 07:11:49 -0400 Subject: [PATCH 528/791] Fix: buffer overflow in gamelog with an extremely long wish string This was discovered when a game of xNetHack crashed with stack smashing detected during dumplog creation after an ascension. I traced the problem to a wish with a very long string the player had made much earlier in the game ("greased very blessed holy rustproof unlit historic thoroughly +5 very cloak of protection named it would be a shame if something happened to me wearing this cloak"), which is further recorded in an even longer form in the chronicle as 'wished for "X", got "Y"'. That string does get truncated, but since the gamelog strings are dynamically allocated, they can be longer than BUFSZ. When show_gamelog was subsequently called, it didn't use any bounds checking, which allowed its stack-allocated buffer to overflow. Changing the offending sprintf to snprintf and limiting it to the buffer size appears to fix this issue. It will truncate the string at BUFSZ-1 characters and therefore will be expressed in the dumplog as an incomplete string, but 1) that was happening anyway because the gamelog string already doesn't capture the entire "wished for X, got Y" message on such a wish, and 2) this should only ever happen for very long wishes. --- src/insight.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/insight.c b/src/insight.c index f4d0c945f..a1c44b6c9 100644 --- a/src/insight.c +++ b/src/insight.c @@ -2580,7 +2580,7 @@ show_gamelog(int final) continue; if (!eventcnt++) putstr(win, 0, " Turn"); - Sprintf(buf, "%5ld: %s", llmsg->turn, llmsg->text); + Snprintf(buf, sizeof buf, "%5ld: %s", llmsg->turn, llmsg->text); putstr(win, 0, buf); } /* since start of game is logged as a major event, 'eventcnt' should From eee5a1698bb9363eeb4e2c2e30c2edd563ca6b28 Mon Sep 17 00:00:00 2001 From: PatR Date: Sun, 30 Mar 2025 14:43:09 -0700 Subject: [PATCH 529/791] whitespace cleanup for themerms.lua I hope this doesn't break anything. There seemed to be one or two misplaced 'end' statements, but after some massaging I'm not sure about this anymore. There were lots of wide lines; those are easy. The Water-surrounded vault had very inconsistent indentation so was harder to untangle. --- dat/themerms.lua | 263 +++++++++++++++++++++++++++-------------------- 1 file changed, 149 insertions(+), 114 deletions(-) diff --git a/dat/themerms.lua b/dat/themerms.lua index 454059125..f42111dc7 100644 --- a/dat/themerms.lua +++ b/dat/themerms.lua @@ -1,4 +1,4 @@ --- NetHack themerms.lua $NHDT-Date: 1652196294 2022/05/10 15:24:54 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.16 $ +-- NetHack themerms.lua $NHDT-Date: 1743399789 2025/03/30 21:43:09 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.36 $ -- Copyright (c) 2020 by Pasi Kallinen -- NetHack may be freely redistributed. See license for details. -- @@ -81,8 +81,7 @@ themeroom_fills = { -- Trap room function(rm) local traps = { "arrow", "dart", "falling rock", "bear", - "land mine", "sleep gas", "rust", - "anti magic" }; + "land mine", "sleep gas", "rust", "anti magic" }; shuffle(traps); local locs = selection.room():percentage(30); local func = function(x,y) @@ -103,22 +102,28 @@ themeroom_fills = { des.feature("fountain"); end end - table.insert(postprocess, { handler = make_garden_walls, data = { sel = selection.room() } }); + table.insert(postprocess, { handler = make_garden_walls, + data = { sel = selection.room() } }); end }, -- Buried treasure function(rm) - des.object({ id = "chest", buried = true, contents = function(otmp) - local xobj = otmp:totable(); - -- keep track of the last buried treasure - if (xobj.NO_OBJ == nil) then - table.insert(postprocess, { handler = make_dig_engraving, data = { x = xobj.ox, y = xobj.oy }}); - end - for i = 1, d(3,4) do - des.object(); - end - end }); + des.object({ + id = "chest", buried = true, + contents = function(otmp) + local xobj = otmp:totable(); + -- keep track of the last buried treasure + if (xobj.NO_OBJ == nil) then + table.insert(postprocess, { handler = make_dig_engraving, + data = { x = xobj.ox, + y = xobj.oy } }); + end + for i = 1, d(3, 4) do + des.object(); + end + end + }); end, -- Buried zombies @@ -229,7 +234,9 @@ themeroom_fills = { if (pos.x > 0) then pos.x = pos.x + rm.region.x1 - 1; pos.y = pos.y + rm.region.y1; - table.insert(postprocess, { handler = make_a_trap, data = { type = "teleport", seen = true, coord = pos, teledest = 1 } }); + table.insert(postprocess, { handler = make_a_trap, + data = { type = "teleport", seen = true, + coord = pos, teledest = 1 } }); end end end, @@ -248,7 +255,8 @@ themerooms = { function() des.room({ type = "ordinary", w = 11,h = 9, filled = 1, contents = function() - des.room({ type = "ordinary", x = 4,y = 3, w = 3,h = 3, filled = 1, + des.room({ type = "ordinary", x = 4, y = 3, w = 3, h = 3, + filled = 1, contents = function() des.door({ state="random", wall="all" }); end @@ -272,7 +280,8 @@ themerooms = { -- Huge room, with another room inside (90%) function() - des.room({ type = "ordinary", w = nh.rn2(10)+11,h = nh.rn2(5)+8, filled = 1, + des.room({ type = "ordinary", w = nh.rn2(10) + 11, h = nh.rn2(5) + 8, + filled = 1, contents = function() if (percent(90)) then des.room({ type = "ordinary", filled = 1, @@ -360,15 +369,17 @@ themerooms = { des.room({ type = "themed", w = 5 + nh.rn2(3)*2, h = 5 + nh.rn2(3)*2, contents = function(rm) des.room({ type = "themed", - x = (rm.width - 1) / 2, y = (rm.height - 1) / 2, - w = 1, h = 1, joined = false, + x = (rm.width - 1) / 2, y = (rm.height - 1) / 2, + w = 1, h = 1, joined = false, contents = function() if (percent(50)) then local mons = { "M", "V", "L", "Z" }; shuffle(mons); - des.monster({ class = mons[1], x=0,y=0, waiting = 1 }); + des.monster({ class = mons[1], x=0, y=0, + waiting = 1 }); else - des.object({ id = "corpse", montype = "@", coord = {0,0} }); + des.object({ id = "corpse", montype = "@", + coord = {0,0} }); end if (percent(20)) then des.door({ state="secret", wall="all" }); @@ -388,7 +399,7 @@ themerooms = { local feature = { "C", "L", "I", "P", "T" }; shuffle(feature); des.terrain((rm.width - 1) / 2, (rm.height - 1) / 2, - feature[1]); + feature[1]); end }); end, @@ -459,13 +470,15 @@ xxx-----]], contents = function(m) filler_region(1,1); end }); |.........| |.........| -----------]], contents = function(m) -if (percent(30)) then - local terr = { "-", "P" }; - shuffle(terr); - des.replace_terrain({ region = {1,1, 9,9}, fromterrain = "L", toterrain = terr[1] }); -end -filler_region(1,1); -end }); + if (percent(30)) then + local terr = { "-", "P" }; + shuffle(terr); + des.replace_terrain({ region = {1,1, 9,9}, + fromterrain = "L", toterrain = terr[1] }); + end + filler_region(1,1); + end + }); end, -- Circular, small @@ -666,102 +679,116 @@ xx|.....|xx }|..|} }|..|} }----} -}}}}}}]], contents = function(m) des.region({ region={3,3,3,3}, type="themed", irregular=true, filled=0, joined=false }); - local nasty_undead = { "giant zombie", "ettin zombie", "vampire lord" }; - local chest_spots = { { 2, 2 }, { 3, 2 }, { 2, 3 }, { 3, 3 } }; +}}}}}}]], contents = function(m) des.region({ region = {3, 3, 3, 3}, + type = "themed", irregular = true, + filled = 0, joined = false }); + local nasty_undead = { "giant zombie", "ettin zombie", + "vampire lord" }; + local chest_spots = { { 2, 2 }, { 3, 2 }, { 2, 3 }, { 3, 3 } }; - shuffle(chest_spots) - -- Guarantee an escape item inside one of the chests, to prevent the hero - -- falling in from above and becoming permanently stuck - -- [cf. generate_way_out_method(sp_lev.c)]. - -- If the escape item is made of glass or crystal, make sure that the - -- chest isn't locked so that kicking it to gain access to its contents - -- won't be necessary; otherwise retain lock state from random creation. - -- "pick-axe", "dwarvish mattock" could be included in the list of escape - -- items but don't normally generate in containers. - local escape_items = { - "scroll of teleportation", "ring of teleportation", - "wand of teleportation", "wand of digging" - }; - local itm = obj.new(escape_items[math.random(#escape_items)]); - local itmcls = itm:class() - local box - if itmcls[ "material" ] == "glass" then - -- explicitly force chest to be unlocked - box = des.object({ id = "chest", coord = chest_spots[1], - olocked = "no" }); - else - -- accept random locked/unlocked state - box = des.object({ id = "chest", coord = chest_spots[1] }); - end; - box:addcontent(itm); + shuffle(chest_spots) + -- Guarantee an escape item inside one of the chests, to prevent the + -- hero falling in from above and becoming permanently stuck + -- [cf. generate_way_out_method(sp_lev.c)]. + -- If the escape item is made of glass or crystal, make sure that + -- the chest isn't locked so that kicking it to gain access to its + -- contents won't be necessary; otherwise retain lock state from + -- random creation. "pick-axe", "dwarvish mattock" could be included + -- in list of escape items but don't normally generate in containers. + local escape_items = { + "scroll of teleportation", "ring of teleportation", + "wand of teleportation", "wand of digging" + }; + local itm = obj.new( escape_items[math.random(#escape_items)] ); + local itmcls = itm:class() + local box + if itmcls[ "material" ] == "glass" then + -- explicitly force chest to be unlocked + box = des.object({ id = "chest", coord = chest_spots[1], + olocked = "no" }); + else + -- accept random locked/unlocked state + box = des.object({ id = "chest", coord = chest_spots[1] }); + end; + box:addcontent(itm); - for i = 2, #chest_spots do - des.object({ id = "chest", coord = chest_spots[i] }); - end + for i = 2, #chest_spots do + des.object({ id = "chest", coord = chest_spots[i] }); + end - shuffle(nasty_undead); - des.monster(nasty_undead[1], 2, 2); - des.exclusion({ type = "teleport", region = { 2,2, 3,3 } }); -end }); + shuffle(nasty_undead); + des.monster(nasty_undead[1], 2, 2); + des.exclusion({ type = "teleport", region = { 2,2, 3,3 } }); + end + }); -- des.map end, -- Twin businesses { - mindiff = 4; -- arbitrary + mindiff = 4; -- arbitrary; needs to be greater than 1 since no shops on 1 contents = function() -- Due to the way room connections work in mklev.c, we must guarantee -- that the "aisle" between the shops touches all four walls of the -- larger room. Thus it has an extra width and height. des.room({ type="themed", w=9, h=5, contents = function() - -- There are eight possible placements of the two shops, four of - -- which have the vertical aisle in the center. - southeast = function() return percent(50) and "south" or "east" end - northeast = function() return percent(50) and "north" or "east" end - northwest = function() return percent(50) and "north" or "west" end - southwest = function() return percent(50) and "south" or "west" end - placements = { - { lx = 1, ly = 1, rx = 4, ry = 1, lwall = "south", rwall = southeast() }, - { lx = 1, ly = 2, rx = 4, ry = 2, lwall = "north", rwall = northeast() }, - { lx = 1, ly = 1, rx = 5, ry = 1, lwall = southeast(), rwall = southwest() }, - { lx = 1, ly = 1, rx = 5, ry = 2, lwall = southeast(), rwall = northwest() }, - { lx = 1, ly = 2, rx = 5, ry = 1, lwall = northeast(), rwall = southwest() }, - { lx = 1, ly = 2, rx = 5, ry = 2, lwall = northeast(), rwall = northwest() }, - { lx = 2, ly = 1, rx = 5, ry = 1, lwall = southwest(), rwall = "south" }, - { lx = 2, ly = 2, rx = 5, ry = 2, lwall = northwest(), rwall = "north" } - } - ltype,rtype = "weapon shop","armor shop" - if percent(50) then - ltype,rtype = rtype,ltype + -- There are eight possible placements of the two shops, four of + -- which have the vertical aisle in the center. + southeast = function() return percent(50) and "south" or "east" end + northeast = function() return percent(50) and "north" or "east" end + northwest = function() return percent(50) and "north" or "west" end + southwest = function() return percent(50) and "south" or "west" end + placements = { + { lx = 1, ly = 1, rx = 4, ry = 1, + lwall = "south", rwall = southeast() }, + { lx = 1, ly = 2, rx = 4, ry = 2, + lwall = "north", rwall = northeast() }, + { lx = 1, ly = 1, rx = 5, ry = 1, + lwall = southeast(), rwall = southwest() }, + { lx = 1, ly = 1, rx = 5, ry = 2, + lwall = southeast(), rwall = northwest() }, + { lx = 1, ly = 2, rx = 5, ry = 1, + lwall = northeast(), rwall = southwest() }, + { lx = 1, ly = 2, rx = 5, ry = 2, + lwall = northeast(), rwall = northwest() }, + { lx = 2, ly = 1, rx = 5, ry = 1, + lwall = southwest(), rwall = "south" }, + { lx = 2, ly = 2, rx = 5, ry = 2, + lwall = northwest(), rwall = "north" } + } + ltype, rtype = "weapon shop", "armor shop" + if percent(50) then + ltype, rtype = rtype, ltype + end + shopdoorstate = function() + if percent(1) then + return "locked" + elseif percent(50) then + return "closed" + else + return "open" end - shopdoorstate = function() - if percent(1) then - return "locked" - elseif percent(50) then - return "closed" - else - return "open" - end - end - p = placements[d(#placements)] - des.room({ type=ltype, x=p["lx"], y=p["ly"], w=3, h=3, filled=1, joined=false, - contents = function() - des.door({ state=shopdoorstate(), wall=p["lwall"] }) - end - }); - des.room({ type=rtype, x=p["rx"], y=p["ry"], w=3, h=3, filled=1, joined=false, - contents = function() - des.door({ state=shopdoorstate(), wall=p["rwall"] }) - end - }); + end + p = placements[ d(#placements) ] + des.room({ type = ltype, x = p["lx"], y = p["ly"], w = 3, h = 3, + filled = 1, joined = false, + contents = function() + des.door({ state = shopdoorstate(), + wall = p["lwall"] }) + end + }); + des.room({ type = rtype, x = p["rx"], y = p["ry"], w = 3, h = 3, + filled = 1, joined = false, + contents = function() + des.door({ state = shopdoorstate(), + wall = p["rwall"] }) + end + }); end }); end }, - }; - function filler_region(x, y) local rmtyp = "ordinary"; local func = nil; @@ -769,7 +796,8 @@ function filler_region(x, y) rmtyp = "themed"; func = themeroom_fill; end - des.region({ region={x,y,x,y}, type=rmtyp, irregular=true, filled=1, contents = func }); + des.region({ region = {x,y,x,y}, type = rmtyp, irregular = true, filled = 1, + contents = func }); end function is_eligible(room, mkrm) @@ -799,14 +827,16 @@ function themerooms_generate() -- which may change on different levels because of level difficulty. if is_eligible(themerooms[i], nil) then local this_frequency; - if (type(themerooms[i]) == "table" and themerooms[i].frequency ~= nil) then + if (type(themerooms[i]) == "table" and themerooms[i].frequency ~= nil) + then this_frequency = themerooms[i].frequency; else this_frequency = 1; end total_frequency = total_frequency + this_frequency; -- avoid rn2(0) if a room has freq 0 - if this_frequency > 0 and nh.rn2(total_frequency) < this_frequency then + if this_frequency > 0 and nh.rn2(total_frequency) < this_frequency + then pick = i; end end @@ -837,14 +867,16 @@ function themeroom_fill(rm) -- which may change on different levels because of level difficulty. if is_eligible(themeroom_fills[i], rm) then local this_frequency; - if (type(themeroom_fills[i]) == "table" and themeroom_fills[i].frequency ~= nil) then + if (type(themeroom_fills[i]) == "table" + and themeroom_fills[i].frequency ~= nil) then this_frequency = themeroom_fills[i].frequency; else this_frequency = 1; end total_frequency = total_frequency + this_frequency; -- avoid rn2(0) if a room has freq 0 - if this_frequency > 0 and nh.rn2(total_frequency) < this_frequency then + if this_frequency > 0 and nh.rn2(total_frequency) < this_frequency + then pick = i; end end @@ -869,10 +901,12 @@ function make_dig_engraving(data) dig = " here"; else if (tx < 0 or tx > 0) then - dig = string.format(" %i %s", math.abs(tx), (tx > 0) and "east" or "west"); + dig = string.format(" %i %s", math.abs(tx), + (tx > 0) and "east" or "west"); end if (ty < 0 or ty > 0) then - dig = dig .. string.format(" %i %s", math.abs(ty), (ty > 0) and "south" or "north"); + dig = dig .. string.format(" %i %s", math.abs(ty), + (ty > 0) and "south" or "north"); end end des.engraving({ coord = pos, type = "burn", text = "Dig" .. dig }); @@ -890,7 +924,8 @@ function make_a_trap(data) local locs = selection.negate():filter_mapchar("."); repeat data.teledest = locs:rndcoord(1); - until (data.teledest.x ~= data.coord.x and data.teledest.y ~= data.coord.y); + until (data.teledest.x ~= data.coord.x + and data.teledest.y ~= data.coord.y); end des.trap(data); end From 0ecd573152ebf2c5377c3084c2ce043458830e48 Mon Sep 17 00:00:00 2001 From: PatR Date: Thu, 3 Apr 2025 15:26:05 -0700 Subject: [PATCH 530/791] escape_from_sticky_mon() Reorganized a 'switch' statement in order to eliminate a 'goto'. There should be no changed in behavior. --- src/hack.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/hack.c b/src/hack.c index af9d392c5..d7e6f6b1f 100644 --- a/src/hack.c +++ b/src/hack.c @@ -2636,14 +2636,6 @@ escape_from_sticky_mon(coordxy x, coordxy y) * guaranteed escape. */ switch (rn2(!u.ustuck->mcanmove ? 8 : 40)) { - case 0: - case 1: - case 2: - pull_free: - mtmp = u.ustuck; - set_ustuck((struct monst *) 0); - You("pull free from %s.", y_monnam(mtmp)); - break; case 3: if (!u.ustuck->mcanmove) { /* it's free to move on next turn */ @@ -2653,11 +2645,20 @@ escape_from_sticky_mon(coordxy x, coordxy y) FALLTHROUGH; /*FALLTHRU*/ default: - if (u.ustuck->mtame && !Conflict && !u.ustuck->mconf) - goto pull_free; - You("cannot escape from %s!", y_monnam(u.ustuck)); - nomul(0); - return TRUE; + if (Conflict || u.ustuck->mconf || !u.ustuck->mtame) { + You("cannot escape from %s!", y_monnam(u.ustuck)); + nomul(0); + return TRUE; + } + FALLTHROUGH; + /*FALLTHRU*/ + case 0: + case 1: + case 2: + mtmp = u.ustuck; + set_ustuck((struct monst *) 0); + You("pull free from %s.", y_monnam(mtmp)); + break; } } } From 4afb9254e1c6ef855e64372660ad57fd607ac8f5 Mon Sep 17 00:00:00 2001 From: PatR Date: Thu, 3 Apr 2025 20:07:31 -0700 Subject: [PATCH 531/791] fuzzer vs yn_function() This has been sitting around for a long time. It prevents at least one fuzzer exit. Before adding this, I did trigger one yn_function() 'impossible' while doing ordinary testing but wasn't able to reproduce that, so am still not sure what is going on. --- src/cmd.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 47 insertions(+), 5 deletions(-) diff --git a/src/cmd.c b/src/cmd.c index 1bcb1d4fd..8273cfade 100644 --- a/src/cmd.c +++ b/src/cmd.c @@ -3738,16 +3738,36 @@ getdir(const char *s) retry: program_state.input_state = getdirInp; - if (gi.in_doagain || *readchar_queue) + if (gi.in_doagain || *readchar_queue) { dirsym = readchar(); - else + } else { dirsym = yn_function((s && *s != '^') ? s : "In what direction?", (char *) 0, '\0', FALSE); + + /* for the fuzzer, usually force the result to be a valid direction, + but sometimes let it exercise the invalid direction code; we + don't try to enforce no-diagonal for hero in grid bug form since + things like '^' to look at adjacent trap shouldn't be bound by + that (caller is expected to handle situations where it matters) */ + if (iflags.debug_fuzzer && rn2(20)) { + switch (rn2(20)) { + case 0: + dirsym = gc.Cmd.spkeys[rn2(2) ? NHKF_GETDIR_SELF : NHKF_ESC]; + break; + case 1: + dirsym = gc.Cmd.dirchars[rn2(2) ? DIR_DOWN : DIR_UP]; + break; + default: + dirsym = gc.Cmd.dirchars[rn2(N_DIRS)]; + break; + } + } + } /* remove the prompt string so caller won't have to */ clear_nhwindow(WIN_MESSAGE); if (redraw_cmd(dirsym)) { /* ^R */ - docrt(); /* redraw */ + docrt_flags(docrtRefresh); /* redraw */ goto retry; } if (!gi.in_doagain) @@ -5240,6 +5260,28 @@ yn_function( res = cq.key; else cmdq_clear(CQ_CANNED); /* 'res' is ESC */ + addcmdq = FALSE; + + /* for the fuzzer, usually force a valid response, but sometimes let + it exercise windowport yn_function and invalid response handling */ + } else if (iflags.debug_fuzzer && resp && *resp && rn2(20)) { + int ln = (int) strlen(resp), ridx = rn2(ln); + + res = resp[ridx]; + /* if valid-responses includes ESC followed by unshown candidates + and we randomly picked the ESC, try again with only whatever is + before it; be careful to avoid rn2(0) */ + if (res == '\033') { + if (ln > 1) { + /* if ESC is at start (ridx==0), pick something after it */ + ridx = (ridx == 0) ? (1 + rn2(ln - 1)) : rn2(ridx); + res = resp[ridx]; + } else { + /* ESC is the only thing (ln==1); something is strange... */ + res = def; /* might be '\0' */ + } + } + } else { #ifdef SND_SPEECH if ((gp.pline_flags & PLINE_SPEECH) != 0) { @@ -5250,9 +5292,9 @@ yn_function( if (!yn_function_menu(query, resp, def, &res)) { res = (*windowprocs.win_yn_function)(query, resp, def); } - if (addcmdq) - cmdq_add_key(CQ_REPEAT, res); } + if (addcmdq) + cmdq_add_key(CQ_REPEAT, res); #ifdef DUMPLOG_CORE if (idx == gs.saved_pline_index) { From 500af49dd3e5b0244e5d0e48e81749b72f3d6dd6 Mon Sep 17 00:00:00 2001 From: PatR Date: Sat, 5 Apr 2025 09:44:02 -0700 Subject: [PATCH 532/791] fix issue #1407 - mon throw-and-return crash Issue reported by k21971: a gnome throwing a wielded aklys at the hero was killed when failing to catch its return. Bookkeeping for dead monsters got messed up, then a crash occurred. This fixes things. Instead of a comment stating that the thrower might be dead, kill it off. --- src/mthrowu.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mthrowu.c b/src/mthrowu.c index 4313ce8d7..092264c35 100644 --- a/src/mthrowu.c +++ b/src/mthrowu.c @@ -904,7 +904,8 @@ return_from_mtoss(struct monst *magr, struct obj *otmp, boolean tethered_weapon) if (otmp->oartifact) (void) artifact_hit((struct monst *) 0, magr, otmp, &dmg, 0); magr->mhp -= dmg; - /* magr could be a DEADMONSTER now */ + if (DEADMONSTER(magr)) + monkilled(magr, canspotmon(magr) ? "" : (char *) 0, AD_PHYS); } if (notcaught) { (void) snuff_candle(otmp); From afc34c9873c308df769b953c9714ad8183e04af0 Mon Sep 17 00:00:00 2001 From: PatR Date: Sat, 5 Apr 2025 09:50:38 -0700 Subject: [PATCH 533/791] mon throw-and-return cleanup Fix up a few comments in the monster throwing code. And change a couple 'if (!Blind)' checks to use 'if (canseemon(magr))' instead of that the player won't be told about a returning aklys hitting an invisible monster ("it") on the arm. --- src/mthrowu.c | 43 +++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/src/mthrowu.c b/src/mthrowu.c index 092264c35..259484698 100644 --- a/src/mthrowu.c +++ b/src/mthrowu.c @@ -313,7 +313,7 @@ monshoot(struct monst *mtmp, struct obj *otmp, struct obj *mwep) } /* an object launched by someone/thing other than player attacks a monster; - return 1 if the object has stopped moving (hit or its range used up) + return 1 if the object has stopped moving (hit or its range used up); can anger the monster, if this happened due to hero (eg. exploding bag of holding throwing the items) */ boolean @@ -323,7 +323,7 @@ ohitmon( int range, /* how much farther will object travel if it misses; * use -1 to signify to keep going even after hit, * unless it's gone (for rolling_boulder_traps) */ - boolean verbose)/* give messages even when you can't see what happened */ + boolean verbose) /* give messages even when you can't see what happened */ { int damage, tmp; boolean vis, ismimic, objgone; @@ -456,8 +456,8 @@ ohitmon( (nonliving(mtmp->data) || is_vampshifter(mtmp) || !canspotmon(mtmp)) ? "destroyed" : "killed"); /* don't blame hero for unknown rolling boulder trap */ - if (!svc.context.mon_moving && (otmp->otyp != BOULDER - || range >= 0 || otmp->otrapped)) + if (!svc.context.mon_moving + && (otmp->otyp != BOULDER || range >= 0 || otmp->otrapped)) xkilled(mtmp, XKILL_NOMSG); else mondied(mtmp); @@ -531,7 +531,7 @@ ucatchgem( (/* missile hits edge of screen */ \ !isok(gb.bhitpos.x + dx, gb.bhitpos.y + dy) \ /* missile hits the wall */ \ - || IS_OBSTRUCTED(levl[gb.bhitpos.x + dx][gb.bhitpos.y + dy].typ) \ + || IS_OBSTRUCTED(levl[gb.bhitpos.x + dx][gb.bhitpos.y + dy].typ) \ /* missile hit closed door */ \ || closed_door(gb.bhitpos.x + dx, gb.bhitpos.y + dy) \ /* missile might hit iron bars */ \ @@ -549,8 +549,8 @@ ucatchgem( void m_throw( struct monst *mon, /* launching monster */ - coordxy x, coordxy y, /* launch point */ - coordxy dx, coordxy dy, /* direction */ + coordxy x, coordxy y, /* launch point */ + coordxy dx, coordxy dy, /* direction */ int range, /* maximum distance */ struct obj *obj) /* missile (or stack providing it) */ { @@ -575,7 +575,7 @@ m_throw( * with 0 daggers? (This caused the infamous 2^32-1 orcish * dagger bug). * - * VENOM is not in minvent - it should already be OBJ_FREE. + * VENOM is not in minvent--it should already be OBJ_FREE. * The extract below does nothing. */ @@ -593,7 +593,7 @@ m_throw( /* global pointer for missile object in OBJ_FREE state */ gt.thrownobj = singleobj; - singleobj->owornmask = 0; /* threw one of multiple weapons in hand? */ + singleobj->owornmask = 0L; /* threw one of multiple weapons in hand? */ if (!canseemon(mon)) clear_dknown(singleobj); /* singleobj->dknown = 0; */ @@ -630,7 +630,7 @@ m_throw( } else { tmp_at(DISP_TETHER, obj_to_glyph(singleobj, rn2_on_display_rng)); /* - * Considerations for a tethered object based on in throwit()/bhit() : + * Considerations for a tethered object based on throwit()/bhit() : * - wall of water/lava will stop items, and triggers return. * - iron bars will stop items, and triggers return. * - pass harmlessly through shades. @@ -784,7 +784,8 @@ m_throw( || (gm.marcher && canseemon(gm.marcher)))) pline("%s misses.", The(mshot_xname(singleobj))); if (!tethered_weapon) { - (void) drop_throw(singleobj, 0, gb.bhitpos.x, gb.bhitpos.y); + (void) drop_throw(singleobj, 0, + gb.bhitpos.x, gb.bhitpos.y); } else { /*ready for return journey */ return_flightpath = TRUE; @@ -818,7 +819,10 @@ m_throw( #undef MT_FLIGHTCHECK staticfn void -return_from_mtoss(struct monst *magr, struct obj *otmp, boolean tethered_weapon) +return_from_mtoss( + struct monst *magr, + struct obj *otmp, + boolean tethered_weapon) { boolean impaired = (magr->mconf || magr->mstun || magr->mblinded), notcaught = FALSE, hits_thrower = FALSE; @@ -847,11 +851,12 @@ return_from_mtoss(struct monst *magr, struct obj *otmp, boolean tethered_weapon) x = magr->mx; y = magr->my; if (!impaired && rn2(100)) { + /* FIXME: this should be moved to struct g (gd these days) */ static long do_not_annoy = 0; - if (!do_not_annoy || (svm.moves - do_not_annoy) > 500) { + if (!do_not_annoy || (svm.moves - do_not_annoy) > 500L) { pline("%s to %s %s!", Tobjnam(otmp, "return"), - s_suffix(mon_nam(magr)), mbodypart(magr, HAND)); + s_suffix(mon_nam(magr)), mbodypart(magr, HAND)); do_not_annoy = svm.moves; } if (otmp) { @@ -868,7 +873,7 @@ return_from_mtoss(struct monst *magr, struct obj *otmp, boolean tethered_weapon) dmg = rn2(2); if (!dmg) { - if (!Blind) { + if (canseemon(magr)) { pline("%s back to %s, landing %s %s %s.", Tobjnam(otmp, "return"), mon_nam(magr), mlevitating ? "beneath" : "at", mhis(magr), @@ -878,12 +883,10 @@ return_from_mtoss(struct monst *magr, struct obj *otmp, boolean tethered_weapon) } } else { dmg += rnd(3); - if (!Blind) { + if (canseemon(magr)) { pline("%s back toward %s, hitting %s %s!", - Tobjnam(otmp, "fly"), - mon_nam(magr), - mhis(magr), - body_part(ARM)); + Tobjnam(otmp, "fly"), mon_nam(magr), + mhis(magr), body_part(ARM)); } else if (!Deaf) { You_hear("%s hit %s with a thud!", something, mon_nam(magr)); From 3aecc90b2da4a4093020ccca4a414a39c11cae5f Mon Sep 17 00:00:00 2001 From: PatR Date: Mon, 7 Apr 2025 14:11:58 -0700 Subject: [PATCH 534/791] commit 46b98bab5b951c16f3c6766f23acb22c3046608c Author: PatR Date: Mon Apr 7 13:58:28 2025 -0700 fix issue #1404 - re-tamed feral pet starves Issue reported by k21971: changes in 'struct edog' initialization resulted in re-taming of a feral former pet producing a tame monst that immediately dies of starvation. I didn't look at the earlier behavior, just forced hunger to be initialized separately from other edog fields. Fixes #1404 --- src/dog.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/src/dog.c b/src/dog.c index ce9abc706..d77ad17a9 100644 --- a/src/dog.c +++ b/src/dog.c @@ -44,6 +44,8 @@ free_edog(struct monst *mtmp) void initedog(struct monst *mtmp, boolean everything) { + struct edog *edogp = EDOG(mtmp); + long minhungry = svm.moves + 1000L; schar minimumtame = is_domestic(mtmp->data) ? 10 : 5; mtmp->mtame = max(minimumtame, mtmp->mtame); @@ -53,18 +55,22 @@ initedog(struct monst *mtmp, boolean everything) if (everything) { mtmp->mleashed = 0; mtmp->meating = 0; - EDOG(mtmp)->droptime = 0; - EDOG(mtmp)->dropdist = 10000; - EDOG(mtmp)->apport = ACURR(A_CHA); - EDOG(mtmp)->whistletime = 0; - EDOG(mtmp)->hungrytime = 1000 + svm.moves; - EDOG(mtmp)->ogoal.x = -1; /* force error if used before set */ - EDOG(mtmp)->ogoal.y = -1; - EDOG(mtmp)->abuse = 0; - EDOG(mtmp)->revivals = 0; - EDOG(mtmp)->mhpmax_penalty = 0; - EDOG(mtmp)->killed_by_u = 0; + edogp->droptime = 0; + edogp->dropdist = 10000; + edogp->apport = ACURR(A_CHA); + edogp->whistletime = 0; + /* edogp->hungrytime = 0L; // set below */ + edogp->ogoal.x = -1; /* force error if used before set */ + edogp->ogoal.y = -1; + edogp->abuse = 0; + edogp->revivals = 0; + edogp->mhpmax_penalty = 0; + edogp->killed_by_u = 0; } + /* always set for newly tamed pet or feral former pet; hungrytime might + already be higher when taming magic affects already tame monst */ + if (edogp->hungrytime < minhungry) + edogp->hungrytime = minhungry; /* livelog first pet, but only if you didn't start with one (the starting * pet will be initialized before in_moveloop is true) */ if (!u.uconduct.pets && program_state.in_moveloop) { From 2065d2d392f17f5242f6afb22625eff5830d75c6 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Wed, 9 Apr 2025 18:40:56 +0300 Subject: [PATCH 535/791] Avoid premapping outside Sokoban map to prevent showing stone glyphs If user has changed the stone glyph to something other than a space (or uses a tileset), Sokoban levels showed the unreachable stone outside the map area. Prevent marking those areas as seen, so the stone glyphs aren't shown. --- doc/fixes3-7-0.txt | 1 + src/detect.c | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index c98cd28e5..d2b0a4964 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -1506,6 +1506,7 @@ since introduction in 3.1.0, the definition for Mitre of Holiness has specified no 'defends' capability for it since carrying should encompass that if a tree and a boulder or statue were at the same location, applying an axe would break the boulder or statue rather than chop the tree +avoid premapping outside Sokoban map to prevent showing stone glyphs Fixes to 3.7.0-x General Problems Exposed Via git Repository diff --git a/src/detect.c b/src/detect.c index cb6dc2458..0d1de0c83 100644 --- a/src/detect.c +++ b/src/detect.c @@ -38,6 +38,7 @@ staticfn void foundone(coordxy, coordxy, int); staticfn void findone(coordxy, coordxy, genericptr_t); staticfn void openone(coordxy, coordxy, genericptr_t); staticfn int mfind0(struct monst *, boolean); +staticfn boolean skip_premap_detect(coordxy, coordxy); staticfn int reveal_terrain_getglyph(coordxy, coordxy, unsigned, int, unsigned); @@ -2117,6 +2118,16 @@ warnreveal(void) } } +/* skip premap detection of areas outside Sokoban map */ +staticfn boolean +skip_premap_detect(coordxy x, coordxy y) +{ + if ((levl[x][y].typ == STONE) + && (levl[x][y].wall_info & (W_NONDIGGABLE | W_NONPASSWALL)) != 0) + return TRUE; + return FALSE; +} + /* Pre-map (the sokoban) levels */ void premap_detect(void) @@ -2128,6 +2139,8 @@ premap_detect(void) /* Map the background and boulders */ for (x = 1; x < COLNO; x++) for (y = 0; y < ROWNO; y++) { + if (skip_premap_detect(x, y)) + continue; levl[x][y].seenv = SVALL; levl[x][y].waslit = TRUE; if (levl[x][y].typ == SDOOR) From 67d58202ad84dd04ccfd6079fc2665e87ef80fc3 Mon Sep 17 00:00:00 2001 From: disperse Date: Tue, 1 Apr 2025 15:52:45 -0400 Subject: [PATCH 536/791] Silver maces Added the silver mace to be the base weapon type of Demonbane. It is appropriate that an artifact weapon designed to slay Demons would be made of (or plated with) silver. This helps to offset the damage reduction when Demonbane was changed from a longsword to a mace and makes it more specialized against silver-haters. Set the probability to 2, equal to that of a silver spear. Increased the weight of the silver mace by 120% -- equal to the weight increase from a normal spear to a silver spear. (Assuming the weapon is silver plated rather than made entirely out of silver.) Increased the base cost to 60, a similar increase as spear to silver spear, to be an even number between silver spear and silver saber. Monsters will prefer silver maces over regular maces. Otherwise, identical in function to a normal mace. --- include/artilist.h | 2 +- include/objects.h | 4 ++++ src/weapon.c | 5 +++-- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/include/artilist.h b/include/artilist.h index df49ba865..f3ecf2e72 100644 --- a/include/artilist.h +++ b/include/artilist.h @@ -158,7 +158,7 @@ static NEARDATA struct artifact artilist[] = { PHYS(5, 0), NO_DFNS, NO_CARY, 0, A_NONE, NON_PM, NON_PM, 2, 5, 500L, NO_COLOR, DRAGONBANE), - A("Demonbane", MACE, (SPFX_RESTR | SPFX_DFLAG2), 0, M2_DEMON, + A("Demonbane", SILVER_MACE, (SPFX_RESTR | SPFX_DFLAG2), 0, M2_DEMON, PHYS(5, 0), NO_DFNS, NO_CARY, BANISH, A_LAWFUL, PM_CLERIC, NON_PM, 1, 3, 2500L, NO_COLOR, DEMONBANE), diff --git a/include/objects.h b/include/objects.h index 93866d1a5..e7783a2d2 100644 --- a/include/objects.h +++ b/include/objects.h @@ -352,6 +352,10 @@ WEAPON("mace", NoDes, 1, 0, 0, 40, 30, 5, 6, 6, 0, B, P_MACE, IRON, HI_METAL, MACE), /* +1 small */ +WEAPON("silver mace", NoDes, + 1, 0, 0, 2, 36, 60, 6, 6, 0, B, P_MACE, SILVER, HI_SILVER, + SILVER_MACE), + /* +1 small */ WEAPON("morning star", NoDes, 1, 0, 0, 12, 120, 10, 4, 6, 0, B, P_MORNING_STAR, IRON, HI_METAL, MORNING_STAR), diff --git a/src/weapon.c b/src/weapon.c index c2da65a58..1966f5fce 100644 --- a/src/weapon.c +++ b/src/weapon.c @@ -266,6 +266,7 @@ dmgval(struct obj *otmp, struct monst *mon) case IRON_CHAIN: case CROSSBOW_BOLT: case MACE: + case SILVER_MACE: case WAR_HAMMER: case FLAIL: case SPETUM: @@ -686,8 +687,8 @@ static const NEARDATA short hwep[] = { TSURUGI, RUNESWORD, DWARVISH_MATTOCK, TWO_HANDED_SWORD, BATTLE_AXE, KATANA, UNICORN_HORN, CRYSKNIFE, TRIDENT, LONG_SWORD, ELVEN_BROADSWORD, BROADSWORD, SCIMITAR, SILVER_SABER, MORNING_STAR, ELVEN_SHORT_SWORD, - DWARVISH_SHORT_SWORD, SHORT_SWORD, ORCISH_SHORT_SWORD, MACE, AXE, - DWARVISH_SPEAR, SILVER_SPEAR, ELVEN_SPEAR, SPEAR, ORCISH_SPEAR, FLAIL, + DWARVISH_SHORT_SWORD, SHORT_SWORD, ORCISH_SHORT_SWORD, SILVER_MACE, MACE, + AXE, DWARVISH_SPEAR, SILVER_SPEAR, ELVEN_SPEAR, SPEAR, ORCISH_SPEAR, FLAIL, BULLWHIP, QUARTERSTAFF, JAVELIN, AKLYS, CLUB, PICK_AXE, RUBBER_HOSE, WAR_HAMMER, SILVER_DAGGER, ELVEN_DAGGER, DAGGER, ORCISH_DAGGER, ATHAME, SCALPEL, KNIFE, WORM_TOOTH From b5768d676cb837dc72ad74b9d290af1f16b3c049 Mon Sep 17 00:00:00 2001 From: disperse Date: Wed, 2 Apr 2025 18:59:24 -0400 Subject: [PATCH 537/791] Added tile for silver mace Copied the mace tile and added more blue and white and softened the shadows on the head of the mace. --- win/share/objects.txt | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/win/share/objects.txt b/win/share/objects.txt index 1b3f3b556..fb9a5f149 100644 --- a/win/share/objects.txt +++ b/win/share/objects.txt @@ -1456,6 +1456,25 @@ Z = (195, 195, 195) ...A............ ................ } +# tile 73 (silver mace) +{ + ................ + ................ + ................ + .........BPB.... + ........B.N.BP.. + ........PN.N.P.. + ........B.N.BP.. + ........PB.BPP.. + .......KJQPPP... + ......KJA....... + .....KJA........ + ....KJA......... + ...KJA.......... + ..KJA........... + ...A............ + ................ +} # tile 74 (morning star) { ................ From c271f878f9cf471aa5ed425af9f6c062d09150b9 Mon Sep 17 00:00:00 2001 From: disperse Date: Wed, 2 Apr 2025 19:15:25 -0400 Subject: [PATCH 538/791] Fixed tile numbering in objects.txt --- win/share/objects.txt | 812 +++++++++++++++++++++--------------------- 1 file changed, 406 insertions(+), 406 deletions(-) diff --git a/win/share/objects.txt b/win/share/objects.txt index fb9a5f149..9c1a3e736 100644 --- a/win/share/objects.txt +++ b/win/share/objects.txt @@ -1456,7 +1456,7 @@ Z = (195, 195, 195) ...A............ ................ } -# tile 73 (silver mace) +# tile 74 (silver mace) { ................ ................ @@ -1475,7 +1475,7 @@ Z = (195, 195, 195) ...A............ ................ } -# tile 74 (morning star) +# tile 75 (morning star) { ................ ................ @@ -1494,7 +1494,7 @@ Z = (195, 195, 195) ......KA........ ................ } -# tile 75 (war hammer) +# tile 76 (war hammer) { ..........O..... .........PPOA... @@ -1513,7 +1513,7 @@ Z = (195, 195, 195) .JA............. ................ } -# tile 76 (club) +# tile 77 (club) { ................ ................ @@ -1532,7 +1532,7 @@ Z = (195, 195, 195) .JA............. ................ } -# tile 77 (rubber hose) +# tile 78 (rubber hose) { ................ ................ @@ -1551,7 +1551,7 @@ Z = (195, 195, 195) ....AAA......... ................ } -# tile 78 (staff / quarterstaff) +# tile 79 (staff / quarterstaff) { ................ .............JK. @@ -1570,7 +1570,7 @@ Z = (195, 195, 195) .JJAA........... ..A............. } -# tile 79 (thonged club / aklys) +# tile 80 (thonged club / aklys) { ................ ................ @@ -1589,7 +1589,7 @@ Z = (195, 195, 195) ......OA.OA..... .......OOA...... } -# tile 80 (flail) +# tile 81 (flail) { ................ ............KJ.. @@ -1608,7 +1608,7 @@ Z = (195, 195, 195) ..JA............ ................ } -# tile 81 (bullwhip) +# tile 82 (bullwhip) { ................ ................ @@ -1627,7 +1627,7 @@ Z = (195, 195, 195) ......AAA....... ................ } -# tile 82 (bow) +# tile 83 (bow) { ................ .....K.......... @@ -1646,7 +1646,7 @@ Z = (195, 195, 195) .....KAA........ ................ } -# tile 83 (runed bow / elven bow) +# tile 84 (runed bow / elven bow) { .....K.......... .....KP......... @@ -1665,7 +1665,7 @@ Z = (195, 195, 195) .....KPAAA...... .....KAA........ } -# tile 84 (crude bow / orcish bow) +# tile 85 (crude bow / orcish bow) { ................ ................ @@ -1684,7 +1684,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 85 (long bow / yumi) +# tile 86 (long bow / yumi) { .....L.......... .....LP......... @@ -1703,7 +1703,7 @@ Z = (195, 195, 195) .....LPAAA...... .....LAA........ } -# tile 86 (sling) +# tile 87 (sling) { ................ ................ @@ -1722,7 +1722,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 87 (crossbow) +# tile 88 (crossbow) { ................ ................ @@ -1741,7 +1741,7 @@ Z = (195, 195, 195) ........OA...... ................ } -# tile 88 (leather hat / elven leather helm) +# tile 89 (leather hat / elven leather helm) { ................ ................ @@ -1760,7 +1760,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 89 (iron skull cap / orcish helm) +# tile 90 (iron skull cap / orcish helm) { ................ ................ @@ -1779,7 +1779,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 90 (hard hat / dwarvish iron helm) +# tile 91 (hard hat / dwarvish iron helm) { ................ ................ @@ -1798,7 +1798,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 91 (fedora) +# tile 92 (fedora) { ................ ................ @@ -1817,7 +1817,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 92 (conical hat / cornuthaum) +# tile 93 (conical hat / cornuthaum) { ................ .......E........ @@ -1836,7 +1836,7 @@ Z = (195, 195, 195) ....EEEEEEE..... ................ } -# tile 93 (conical hat / dunce cap) +# tile 94 (conical hat / dunce cap) { ................ .......E........ @@ -1855,7 +1855,7 @@ Z = (195, 195, 195) ....EEEEEEE..... ................ } -# tile 94 (dented pot) +# tile 95 (dented pot) { ................ ................ @@ -1874,7 +1874,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 95 (crystal helmet / helm of brilliance) +# tile 96 (crystal helmet / helm of brilliance) { ................ ................ @@ -1893,7 +1893,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 96 (plumed helmet / helmet) +# tile 97 (plumed helmet / helmet) { .......DID...... ......DIBI...... @@ -1912,7 +1912,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 97 (etched helmet / helm of caution) +# tile 98 (etched helmet / helm of caution) { ................ ................ @@ -1931,7 +1931,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 98 (crested helmet / helm of opposite alignment) +# tile 99 (crested helmet / helm of opposite alignment) { ................ ................ @@ -1950,7 +1950,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 99 (visored helmet / helm of telepathy) +# tile 100 (visored helmet / helm of telepathy) { ................ ................ @@ -1969,7 +1969,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 100 (gray dragon scale mail) +# tile 101 (gray dragon scale mail) { ................ ................ @@ -1988,7 +1988,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 101 (gold dragon scale mail) +# tile 102 (gold dragon scale mail) { ................ ................ @@ -2007,7 +2007,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 102 (silver dragon scale mail) +# tile 103 (silver dragon scale mail) { ................ ................ @@ -2026,7 +2026,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 103 (shimmering dragon scale mail) +# tile 104 (shimmering dragon scale mail) { ................ ................ @@ -2045,7 +2045,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 104 (red dragon scale mail) +# tile 105 (red dragon scale mail) { ................ ................ @@ -2064,7 +2064,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 105 (white dragon scale mail) +# tile 106 (white dragon scale mail) { ................ ................ @@ -2083,7 +2083,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 106 (orange dragon scale mail) +# tile 107 (orange dragon scale mail) { ................ ................ @@ -2102,7 +2102,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 107 (black dragon scale mail) +# tile 108 (black dragon scale mail) { ................ ................ @@ -2121,7 +2121,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 108 (blue dragon scale mail) +# tile 109 (blue dragon scale mail) { ................ ................ @@ -2140,7 +2140,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 109 (green dragon scale mail) +# tile 110 (green dragon scale mail) { ................ ................ @@ -2159,7 +2159,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 110 (yellow dragon scale mail) +# tile 111 (yellow dragon scale mail) { ................ ................ @@ -2178,7 +2178,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 111 (gray dragon scales) +# tile 112 (gray dragon scales) { ................ ................ @@ -2197,7 +2197,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 112 (gold dragon scales) +# tile 113 (gold dragon scales) { ................ ................ @@ -2216,7 +2216,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 113 (silver dragon scales) +# tile 114 (silver dragon scales) { ................ ................ @@ -2235,7 +2235,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 114 (shimmering dragon scales) +# tile 115 (shimmering dragon scales) { ................ ................ @@ -2254,7 +2254,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 115 (red dragon scales) +# tile 116 (red dragon scales) { ................ ................ @@ -2273,7 +2273,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 116 (white dragon scales) +# tile 117 (white dragon scales) { ................ ................ @@ -2292,7 +2292,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 117 (orange dragon scales) +# tile 118 (orange dragon scales) { ................ ................ @@ -2311,7 +2311,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 118 (black dragon scales) +# tile 119 (black dragon scales) { ................ ................ @@ -2330,7 +2330,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 119 (blue dragon scales) +# tile 120 (blue dragon scales) { ................ ................ @@ -2349,7 +2349,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 120 (green dragon scales) +# tile 121 (green dragon scales) { ................ ................ @@ -2368,7 +2368,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 121 (yellow dragon scales) +# tile 122 (yellow dragon scales) { ................ ................ @@ -2387,7 +2387,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 122 (plate mail) +# tile 123 (plate mail) { ................ ................ @@ -2406,7 +2406,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 123 (crystal plate mail) +# tile 124 (crystal plate mail) { ................ ................ @@ -2425,7 +2425,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 124 (bronze plate mail) +# tile 125 (bronze plate mail) { ................ ................ @@ -2444,7 +2444,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 125 (splint mail) +# tile 126 (splint mail) { ................ ................ @@ -2463,7 +2463,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 126 (banded mail) +# tile 127 (banded mail) { ................ ................ @@ -2482,7 +2482,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 127 (dwarvish mithril-coat) +# tile 128 (dwarvish mithril-coat) { ................ ................ @@ -2501,7 +2501,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 128 (elven mithril-coat) +# tile 129 (elven mithril-coat) { ................ ...N.N.NO.O.O... @@ -2520,7 +2520,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 129 (chain mail) +# tile 130 (chain mail) { ................ ................ @@ -2539,7 +2539,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 130 (crude chain mail / orcish chain mail) +# tile 131 (crude chain mail / orcish chain mail) { ................ ................ @@ -2558,7 +2558,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 131 (scale mail) +# tile 132 (scale mail) { ................ ................ @@ -2577,7 +2577,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 132 (studded leather armor) +# tile 133 (studded leather armor) { ................ ................ @@ -2596,7 +2596,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 133 (ring mail) +# tile 134 (ring mail) { ................ ................ @@ -2615,7 +2615,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 134 (crude ring mail / orcish ring mail) +# tile 135 (crude ring mail / orcish ring mail) { ................ ................ @@ -2634,7 +2634,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 135 (leather armor) +# tile 136 (leather armor) { ................ ................ @@ -2653,7 +2653,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 136 (leather jacket) +# tile 137 (leather jacket) { ................ ................ @@ -2672,7 +2672,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 137 (Hawaiian shirt) +# tile 138 (Hawaiian shirt) { ................ ................ @@ -2691,7 +2691,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 138 (T-shirt) +# tile 139 (T-shirt) { ................ ................ @@ -2710,7 +2710,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 139 (mummy wrapping) +# tile 140 (mummy wrapping) { ................ ................ @@ -2729,7 +2729,7 @@ Z = (195, 195, 195) ..N.AAN.NA.OO... ................ } -# tile 140 (faded pall / elven cloak) +# tile 141 (faded pall / elven cloak) { ................ ................ @@ -2748,7 +2748,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 141 (coarse mantelet / orcish cloak) +# tile 142 (coarse mantelet / orcish cloak) { ................ ................ @@ -2767,7 +2767,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 142 (hooded cloak / dwarvish cloak) +# tile 143 (hooded cloak / dwarvish cloak) { ................ ................ @@ -2786,7 +2786,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 143 (slippery cloak / oilskin cloak) +# tile 144 (slippery cloak / oilskin cloak) { ................ ................ @@ -2805,7 +2805,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 144 (robe) +# tile 145 (robe) { ................ ......CCC....... @@ -2824,7 +2824,7 @@ Z = (195, 195, 195) ...ACCCCCCAAA... ....AAAAAAAA.... } -# tile 145 (apron / alchemy smock) +# tile 146 (apron / alchemy smock) { ................ ................ @@ -2843,7 +2843,7 @@ Z = (195, 195, 195) .....NNNNNAA.... ......AAAAA..... } -# tile 146 (leather cloak) +# tile 147 (leather cloak) { ................ ................ @@ -2862,7 +2862,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 147 (tattered cape / cloak of protection) +# tile 148 (tattered cape / cloak of protection) { ................ ................ @@ -2881,7 +2881,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 148 (opera cloak / cloak of invisibility) +# tile 149 (opera cloak / cloak of invisibility) { ................ ......NNN....... @@ -2900,7 +2900,7 @@ Z = (195, 195, 195) ..AANNNNNNAOOAA. ....AAAAAAAAAA.. } -# tile 149 (ornamental cope / cloak of magic resistance) +# tile 150 (ornamental cope / cloak of magic resistance) { ................ ................ @@ -2919,7 +2919,7 @@ Z = (195, 195, 195) ..AAAAAAAAAAAP.. ...PPPPPPPPPPP.. } -# tile 150 (piece of cloth / cloak of displacement) +# tile 151 (piece of cloth / cloak of displacement) { ................ ................ @@ -2938,7 +2938,7 @@ Z = (195, 195, 195) .....PPPPPAA.... .......PPAA..... } -# tile 151 (small shield) +# tile 152 (small shield) { ................ ................ @@ -2957,7 +2957,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 152 (blue and green shield / elven shield) +# tile 153 (blue and green shield / elven shield) { ................ ................ @@ -2976,7 +2976,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 153 (white-handed shield / Uruk-hai shield) +# tile 154 (white-handed shield / Uruk-hai shield) { ................ ...K.KKKJJJ.J... @@ -2995,7 +2995,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 154 (red-eyed shield / orcish shield) +# tile 155 (red-eyed shield / orcish shield) { ................ ................ @@ -3014,7 +3014,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 155 (large shield) +# tile 156 (large shield) { ................ ...N.NNNOOO.O... @@ -3033,7 +3033,7 @@ Z = (195, 195, 195) ........AA...... ................ } -# tile 156 (large round shield / dwarvish roundshield) +# tile 157 (large round shield / dwarvish roundshield) { ................ ................ @@ -3052,7 +3052,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 157 (polished silver shield / shield of reflection) +# tile 158 (polished silver shield / shield of reflection) { ................ ................ @@ -3071,7 +3071,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 158 (old gloves / leather gloves) +# tile 159 (old gloves / leather gloves) { ................ ................ @@ -3090,7 +3090,7 @@ Z = (195, 195, 195) .........AAA.... ................ } -# tile 159 (padded gloves / gauntlets of fumbling) +# tile 160 (padded gloves / gauntlets of fumbling) { ................ ................ @@ -3109,7 +3109,7 @@ Z = (195, 195, 195) .........AAA.... ................ } -# tile 160 (riding gloves / gauntlets of power) +# tile 161 (riding gloves / gauntlets of power) { ................ ................ @@ -3128,7 +3128,7 @@ Z = (195, 195, 195) .........AAA.... ................ } -# tile 161 (fencing gloves / gauntlets of dexterity) +# tile 162 (fencing gloves / gauntlets of dexterity) { ................ ................ @@ -3147,7 +3147,7 @@ Z = (195, 195, 195) .........AAA.... ................ } -# tile 162 (walking shoes / low boots) +# tile 163 (walking shoes / low boots) { ................ ................ @@ -3166,7 +3166,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 163 (hard shoes / iron shoes) +# tile 164 (hard shoes / iron shoes) { ................ ................ @@ -3185,7 +3185,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 164 (jackboots / high boots) +# tile 165 (jackboots / high boots) { .......CCKKKK... ......CKAAAAJJ.. @@ -3204,7 +3204,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 165 (combat boots / speed boots) +# tile 166 (combat boots / speed boots) { ................ ................ @@ -3223,7 +3223,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 166 (jungle boots / water walking boots) +# tile 167 (jungle boots / water walking boots) { ................ ................ @@ -3242,7 +3242,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 167 (hiking boots / jumping boots) +# tile 168 (hiking boots / jumping boots) { ................ ................ @@ -3261,7 +3261,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 168 (mud boots / elven boots) +# tile 169 (mud boots / elven boots) { ................ ................ @@ -3280,7 +3280,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 169 (buckled boots / kicking boots) +# tile 170 (buckled boots / kicking boots) { ................ ................ @@ -3299,7 +3299,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 170 (riding boots / fumble boots) +# tile 171 (riding boots / fumble boots) { ................ ................ @@ -3318,7 +3318,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 171 (snow boots / levitation boots) +# tile 172 (snow boots / levitation boots) { ................ ................ @@ -3337,7 +3337,7 @@ Z = (195, 195, 195) ...A.A.A.A.A.A.. ................ } -# tile 172 (wooden / adornment) +# tile 173 (wooden / adornment) { ................ ................ @@ -3356,7 +3356,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 173 (granite / gain strength) +# tile 174 (granite / gain strength) { ................ ................ @@ -3375,7 +3375,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 174 (opal / gain constitution) +# tile 175 (opal / gain constitution) { ................ ................ @@ -3394,7 +3394,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 175 (clay / increase accuracy) +# tile 176 (clay / increase accuracy) { ................ ................ @@ -3413,7 +3413,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 176 (coral / increase damage) +# tile 177 (coral / increase damage) { ................ ................ @@ -3432,7 +3432,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 177 (black onyx / protection) +# tile 178 (black onyx / protection) { ................ ................ @@ -3451,7 +3451,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 178 (moonstone / regeneration) +# tile 179 (moonstone / regeneration) { ................ ................ @@ -3470,7 +3470,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 179 (tiger eye / searching) +# tile 180 (tiger eye / searching) { ................ ................ @@ -3489,7 +3489,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 180 (jade / stealth) +# tile 181 (jade / stealth) { ................ ................ @@ -3508,7 +3508,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 181 (bronze / sustain ability) +# tile 182 (bronze / sustain ability) { ................ ................ @@ -3527,7 +3527,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 182 (agate / levitation) +# tile 183 (agate / levitation) { ................ ................ @@ -3546,7 +3546,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 183 (topaz / hunger) +# tile 184 (topaz / hunger) { ................ ................ @@ -3565,7 +3565,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 184 (sapphire / aggravate monster) +# tile 185 (sapphire / aggravate monster) { ................ ................ @@ -3584,7 +3584,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 185 (ruby / conflict) +# tile 186 (ruby / conflict) { ................ ................ @@ -3603,7 +3603,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 186 (diamond / warning) +# tile 187 (diamond / warning) { ................ ................ @@ -3622,7 +3622,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 187 (pearl / poison resistance) +# tile 188 (pearl / poison resistance) { ................ ................ @@ -3641,7 +3641,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 188 (iron / fire resistance) +# tile 189 (iron / fire resistance) { ................ ................ @@ -3660,7 +3660,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 189 (brass / cold resistance) +# tile 190 (brass / cold resistance) { ................ ................ @@ -3679,7 +3679,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 190 (copper / shock resistance) +# tile 191 (copper / shock resistance) { ................ ................ @@ -3698,7 +3698,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 191 (twisted / free action) +# tile 192 (twisted / free action) { ................ ................ @@ -3717,7 +3717,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 192 (steel / slow digestion) +# tile 193 (steel / slow digestion) { ................ ................ @@ -3736,7 +3736,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 193 (silver / teleportation) +# tile 194 (silver / teleportation) { ................ ................ @@ -3755,7 +3755,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 194 (gold / teleport control) +# tile 195 (gold / teleport control) { ................ ................ @@ -3774,7 +3774,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 195 (ivory / polymorph) +# tile 196 (ivory / polymorph) { ................ ................ @@ -3793,7 +3793,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 196 (emerald / polymorph control) +# tile 197 (emerald / polymorph control) { ................ ................ @@ -3812,7 +3812,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 197 (wire / invisibility) +# tile 198 (wire / invisibility) { ................ ................ @@ -3831,7 +3831,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 198 (engagement / see invisible) +# tile 199 (engagement / see invisible) { ................ ................ @@ -3850,7 +3850,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 199 (shiny / protection from shape changers) +# tile 200 (shiny / protection from shape changers) { ................ ................ @@ -3869,7 +3869,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 200 (circular / amulet of ESP) +# tile 201 (circular / amulet of ESP) { ................ ......LLLLLAA... @@ -3888,7 +3888,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 201 (spherical / amulet of life saving) +# tile 202 (spherical / amulet of life saving) { ................ ......LLLLLAA... @@ -3907,7 +3907,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 202 (oval / amulet of strangulation) +# tile 203 (oval / amulet of strangulation) { ................ ......LLLLLLAA.. @@ -3926,7 +3926,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 203 (triangular / amulet of restful sleep) +# tile 204 (triangular / amulet of restful sleep) { ................ ......LLLLLAA... @@ -3945,7 +3945,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 204 (pyramidal / amulet versus poison) +# tile 205 (pyramidal / amulet versus poison) { ................ ......LLLLLAA... @@ -3964,7 +3964,7 @@ Z = (195, 195, 195) ....KJJJJJJJJA.. .......AAAAAAA.. } -# tile 205 (square / amulet of change) +# tile 206 (square / amulet of change) { ................ ......LLLLLAA... @@ -3983,7 +3983,7 @@ Z = (195, 195, 195) .......AAAAA.... ................ } -# tile 206 (concave / amulet of unchanging) +# tile 207 (concave / amulet of unchanging) { ................ ......LLLLLAA... @@ -4002,7 +4002,7 @@ Z = (195, 195, 195) .......KCCAA.... ........AAA..... } -# tile 207 (hexagonal / amulet of reflection) +# tile 208 (hexagonal / amulet of reflection) { ................ ......LLLLLAA... @@ -4021,7 +4021,7 @@ Z = (195, 195, 195) ........AAA..... ................ } -# tile 208 (octagonal / amulet of magical breathing) +# tile 209 (octagonal / amulet of magical breathing) { ................ ......LLLLLAA... @@ -4040,7 +4040,7 @@ Z = (195, 195, 195) .......KKKAA.... ........AAA..... } -# tile 209 (perforated / amulet of guarding) +# tile 210 (perforated / amulet of guarding) { ................ ......LLLLLAA... @@ -4059,7 +4059,7 @@ Z = (195, 195, 195) .......KKKAA.... ........AAA..... } -# tile 210 (cubical / amulet of flying) +# tile 211 (cubical / amulet of flying) { ................ ......LLLLLAA... @@ -4078,7 +4078,7 @@ Z = (195, 195, 195) ......CKKKKA.... .......AAAAA.... } -# tile 211 (Amulet of Yendor / cheap plastic imitation of the Amulet of Yendor) +# tile 212 (Amulet of Yendor / cheap plastic imitation of the Amulet of Yendor) { ................ ......HHHHHAA... @@ -4097,7 +4097,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 212 (Amulet of Yendor / Amulet of Yendor) +# tile 213 (Amulet of Yendor / Amulet of Yendor) { ................ ......HHHHHAA... @@ -4116,7 +4116,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 213 (large box) +# tile 214 (large box) { ................ ................ @@ -4135,7 +4135,7 @@ Z = (195, 195, 195) CKKKKKKKKKKJAA.. .AAAAAAAAAAAA... } -# tile 214 (chest) +# tile 215 (chest) { ................ ................ @@ -4154,7 +4154,7 @@ Z = (195, 195, 195) CKKKKKKKKKKJAA.. .AAAAAAAAAAAA... } -# tile 215 (ice box) +# tile 216 (ice box) { ................ ................ @@ -4173,7 +4173,7 @@ Z = (195, 195, 195) NBBBBBBBBBBPAA.. .AAAAAAAAAAAA... } -# tile 216 (bag / sack) +# tile 217 (bag / sack) { ................ ................ @@ -4192,7 +4192,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 217 (bag / oilskin sack) +# tile 218 (bag / oilskin sack) { ................ ................ @@ -4211,7 +4211,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 218 (bag / bag of holding) +# tile 219 (bag / bag of holding) { ................ ................ @@ -4230,7 +4230,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 219 (bag / bag of tricks) +# tile 220 (bag / bag of tricks) { ................ ................ @@ -4249,7 +4249,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 220 (key / skeleton key) +# tile 221 (key / skeleton key) { ................ ................ @@ -4268,7 +4268,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 221 (lock pick) +# tile 222 (lock pick) { ................ ................ @@ -4287,7 +4287,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 222 (credit card) +# tile 223 (credit card) { ................ ................ @@ -4306,7 +4306,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 223 (candle / tallow candle) +# tile 224 (candle / tallow candle) { ................ ................ @@ -4325,7 +4325,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 224 (candle / wax candle) +# tile 225 (candle / wax candle) { ................ ................ @@ -4344,7 +4344,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 225 (brass lantern) +# tile 226 (brass lantern) { ................ ................ @@ -4363,7 +4363,7 @@ Z = (195, 195, 195) .....AAAAAAA.... ................ } -# tile 226 (lamp / oil lamp) +# tile 227 (lamp / oil lamp) { ................ ................ @@ -4382,7 +4382,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 227 (lamp / magic lamp) +# tile 228 (lamp / magic lamp) { ................ ................ @@ -4401,7 +4401,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 228 (expensive camera) +# tile 229 (expensive camera) { ................ ................ @@ -4420,7 +4420,7 @@ Z = (195, 195, 195) ...PPPPPPPPPPPP. ................ } -# tile 229 (looking glass / mirror) +# tile 230 (looking glass / mirror) { ................ ................ @@ -4439,7 +4439,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 230 (glass orb / crystal ball) +# tile 231 (glass orb / crystal ball) { ................ ................ @@ -4458,7 +4458,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 231 (lenses) +# tile 232 (lenses) { ................ ................ @@ -4477,7 +4477,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 232 (blindfold) +# tile 233 (blindfold) { ................ ................ @@ -4496,7 +4496,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 233 (towel) +# tile 234 (towel) { ................ ................ @@ -4515,7 +4515,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 234 (saddle) +# tile 235 (saddle) { ................ ................ @@ -4534,7 +4534,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 235 (leash) +# tile 236 (leash) { ................ ................ @@ -4553,7 +4553,7 @@ Z = (195, 195, 195) .....AAAA....... ................ } -# tile 236 (stethoscope) +# tile 237 (stethoscope) { ................ ................ @@ -4572,7 +4572,7 @@ Z = (195, 195, 195) ........AAA..... ................ } -# tile 237 (tinning kit) +# tile 238 (tinning kit) { ................ ................ @@ -4591,7 +4591,7 @@ Z = (195, 195, 195) ......AAA....... ................ } -# tile 238 (tin opener) +# tile 239 (tin opener) { ................ ................ @@ -4610,7 +4610,7 @@ Z = (195, 195, 195) ........AA...... ................ } -# tile 239 (can of grease) +# tile 240 (can of grease) { ................ ................ @@ -4629,7 +4629,7 @@ Z = (195, 195, 195) .......AAAA..... ................ } -# tile 240 (figurine) +# tile 241 (figurine) { ................ ................ @@ -4648,7 +4648,7 @@ Z = (195, 195, 195) .....JJJJJAA.... ................ } -# tile 241 (magic marker) +# tile 242 (magic marker) { ................ ................ @@ -4667,7 +4667,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 242 (land mine) +# tile 243 (land mine) { ................ ................ @@ -4686,7 +4686,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 243 (beartrap) +# tile 244 (beartrap) { ................ ................ @@ -4705,7 +4705,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 244 (whistle / tin whistle) +# tile 245 (whistle / tin whistle) { ................ ................ @@ -4724,7 +4724,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 245 (whistle / magic whistle) +# tile 246 (whistle / magic whistle) { ................ ................ @@ -4743,7 +4743,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 246 (flute / wooden flute) +# tile 247 (flute / wooden flute) { ................ ................ @@ -4762,7 +4762,7 @@ Z = (195, 195, 195) ..A............. ................ } -# tile 247 (flute / magic flute) +# tile 248 (flute / magic flute) { ................ ................ @@ -4781,7 +4781,7 @@ Z = (195, 195, 195) ..A............. ................ } -# tile 248 (horn / tooled horn) +# tile 249 (horn / tooled horn) { ................ ................ @@ -4800,7 +4800,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 249 (horn / frost horn) +# tile 250 (horn / frost horn) { ................ ................ @@ -4819,7 +4819,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 250 (horn / fire horn) +# tile 251 (horn / fire horn) { ................ ................ @@ -4838,7 +4838,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 251 (horn / horn of plenty) +# tile 252 (horn / horn of plenty) { ................ ................ @@ -4857,7 +4857,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 252 (harp / wooden harp) +# tile 253 (harp / wooden harp) { ................ ................ @@ -4876,7 +4876,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 253 (harp / magic harp) +# tile 254 (harp / magic harp) { ................ ................ @@ -4895,7 +4895,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 254 (bell) +# tile 255 (bell) { ................ .......KA....... @@ -4914,7 +4914,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 255 (bugle) +# tile 256 (bugle) { ................ ................ @@ -4933,7 +4933,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 256 (drum / leather drum) +# tile 257 (drum / leather drum) { ................ ................ @@ -4952,7 +4952,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 257 (drum / drum of earthquake) +# tile 258 (drum / drum of earthquake) { ................ ................ @@ -4971,7 +4971,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 258 (pick-axe) +# tile 259 (pick-axe) { ................ ................ @@ -4990,7 +4990,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 259 (grappling hook) +# tile 260 (grappling hook) { .............N.. ..............P. @@ -5009,7 +5009,7 @@ Z = (195, 195, 195) ..OOA..OOOA..... ....OOOAA....... } -# tile 260 (unicorn horn) +# tile 261 (unicorn horn) { ................ ................ @@ -5028,7 +5028,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 261 (candelabrum / Candelabrum of Invocation) +# tile 262 (candelabrum / Candelabrum of Invocation) { .......N........ .......D........ @@ -5047,7 +5047,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 262 (silver bell / Bell of Opening) +# tile 263 (silver bell / Bell of Opening) { ................ .......OA....... @@ -5066,7 +5066,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 263 (tripe ration) +# tile 264 (tripe ration) { ................ ................ @@ -5085,7 +5085,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 264 (corpse) +# tile 265 (corpse) { ................ .....D.DPLN..... @@ -5104,7 +5104,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 265 (egg) +# tile 266 (egg) { ................ ................ @@ -5123,7 +5123,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 266 (meatball) +# tile 267 (meatball) { ................ ................ @@ -5142,7 +5142,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 267 (meat stick) +# tile 268 (meat stick) { ................ ................ @@ -5161,7 +5161,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 268 (enormous meatball) +# tile 269 (enormous meatball) { ................ ................ @@ -5180,7 +5180,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 269 (meat ring) +# tile 270 (meat ring) { ................ ................ @@ -5199,7 +5199,7 @@ Z = (195, 195, 195) ......AAAAA..... ................ } -# tile 270 (glob of gray ooze) +# tile 271 (glob of gray ooze) { ................ ................ @@ -5218,7 +5218,7 @@ Z = (195, 195, 195) ...AAA.AAAAA.... ................ } -# tile 271 (glob of brown pudding) +# tile 272 (glob of brown pudding) { ................ ................ @@ -5237,7 +5237,7 @@ Z = (195, 195, 195) ...AAA.AAAAA.... ................ } -# tile 272 (glob of green slime) +# tile 273 (glob of green slime) { ................ ................ @@ -5256,7 +5256,7 @@ Z = (195, 195, 195) ...AAA.AAAAA.... ................ } -# tile 273 (glob of black pudding) +# tile 274 (glob of black pudding) { ................ ................ @@ -5275,7 +5275,7 @@ Z = (195, 195, 195) ...AAA.AAAAA.... ................ } -# tile 274 (kelp frond) +# tile 275 (kelp frond) { ....FA.......... ....FFA......... @@ -5294,7 +5294,7 @@ Z = (195, 195, 195) .....FFFFA...... ......FFFFA..... } -# tile 275 (eucalyptus leaf) +# tile 276 (eucalyptus leaf) { ................ ................ @@ -5313,7 +5313,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 276 (apple) +# tile 277 (apple) { ................ ................ @@ -5332,7 +5332,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 277 (orange) +# tile 278 (orange) { ................ ................ @@ -5351,7 +5351,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 278 (pear) +# tile 279 (pear) { ................ ................ @@ -5370,7 +5370,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 279 (melon) +# tile 280 (melon) { ................ ................ @@ -5389,7 +5389,7 @@ Z = (195, 195, 195) ......AAA....... ................ } -# tile 280 (banana) +# tile 281 (banana) { ................ ................ @@ -5408,7 +5408,7 @@ Z = (195, 195, 195) .....AAAAA...... ................ } -# tile 281 (carrot) +# tile 282 (carrot) { ................ ..........F..F.. @@ -5427,7 +5427,7 @@ Z = (195, 195, 195) ...A............ ................ } -# tile 282 (sprig of wolfsbane) +# tile 283 (sprig of wolfsbane) { ................ ................ @@ -5446,7 +5446,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 283 (clove of garlic) +# tile 284 (clove of garlic) { ................ ................ @@ -5465,7 +5465,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 284 (slime mold) +# tile 285 (slime mold) { ................ ................ @@ -5484,7 +5484,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 285 (lump of royal jelly) +# tile 286 (lump of royal jelly) { ................ ................ @@ -5503,7 +5503,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 286 (cream pie) +# tile 287 (cream pie) { ................ ................ @@ -5522,7 +5522,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 287 (candy bar) +# tile 288 (candy bar) { ................ ................ @@ -5541,7 +5541,7 @@ Z = (195, 195, 195) ....A........... ................ } -# tile 288 (fortune cookie) +# tile 289 (fortune cookie) { ................ ................ @@ -5560,7 +5560,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 289 (pancake) +# tile 290 (pancake) { ................ ................ @@ -5579,7 +5579,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 290 (lembas wafer) +# tile 291 (lembas wafer) { ................ ................ @@ -5598,7 +5598,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 291 (cram ration) +# tile 292 (cram ration) { ................ ...JKA.......... @@ -5617,7 +5617,7 @@ Z = (195, 195, 195) .....AAAAAA..... ................ } -# tile 292 (food ration) +# tile 293 (food ration) { ...JJA.......... ...BPA.......... @@ -5636,7 +5636,7 @@ Z = (195, 195, 195) ....KKKKKKKKKA.. .....AAAAAAAA... } -# tile 293 (K-ration) +# tile 294 (K-ration) { ................ ................ @@ -5655,7 +5655,7 @@ Z = (195, 195, 195) ....KKKKKKKKKA.. .....AAAAAAAA... } -# tile 294 (C-ration) +# tile 295 (C-ration) { ................ ................ @@ -5674,7 +5674,7 @@ Z = (195, 195, 195) ....KKKKKKKKKA.. .....AAAAAAAA... } -# tile 295 (tin) +# tile 296 (tin) { ................ ................ @@ -5693,7 +5693,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 296 (ruby / gain ability) +# tile 297 (ruby / gain ability) { ................ ................ @@ -5712,7 +5712,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 297 (pink / restore ability) +# tile 298 (pink / restore ability) { ................ ................ @@ -5731,7 +5731,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 298 (orange / confusion) +# tile 299 (orange / confusion) { ................ ................ @@ -5750,7 +5750,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 299 (yellow / blindness) +# tile 300 (yellow / blindness) { ................ ................ @@ -5769,7 +5769,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 300 (emerald / paralysis) +# tile 301 (emerald / paralysis) { ................ ................ @@ -5788,7 +5788,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 301 (dark green / speed) +# tile 302 (dark green / speed) { ................ ................ @@ -5807,7 +5807,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 302 (cyan / levitation) +# tile 303 (cyan / levitation) { ................ ................ @@ -5826,7 +5826,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 303 (sky blue / hallucination) +# tile 304 (sky blue / hallucination) { ................ ................ @@ -5845,7 +5845,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 304 (brilliant blue / invisibility) +# tile 305 (brilliant blue / invisibility) { ................ ................ @@ -5864,7 +5864,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 305 (magenta / see invisible) +# tile 306 (magenta / see invisible) { ................ ................ @@ -5883,7 +5883,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 306 (purple-red / healing) +# tile 307 (purple-red / healing) { ................ ................ @@ -5902,7 +5902,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 307 (puce / extra healing) +# tile 308 (puce / extra healing) { ................ ................ @@ -5921,7 +5921,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 308 (milky / gain level) +# tile 309 (milky / gain level) { ................ ................ @@ -5940,7 +5940,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 309 (swirly / enlightenment) +# tile 310 (swirly / enlightenment) { ................ ................ @@ -5959,7 +5959,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 310 (bubbly / monster detection) +# tile 311 (bubbly / monster detection) { ................ ................ @@ -5978,7 +5978,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 311 (smoky / object detection) +# tile 312 (smoky / object detection) { ................ ................ @@ -5997,7 +5997,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 312 (cloudy / gain energy) +# tile 313 (cloudy / gain energy) { ................ ................ @@ -6016,7 +6016,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 313 (effervescent / sleeping) +# tile 314 (effervescent / sleeping) { ................ ................ @@ -6035,7 +6035,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 314 (black / full healing) +# tile 315 (black / full healing) { ................ ................ @@ -6054,7 +6054,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 315 (golden / polymorph) +# tile 316 (golden / polymorph) { ................ ................ @@ -6073,7 +6073,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 316 (brown / booze) +# tile 317 (brown / booze) { ................ ................ @@ -6092,7 +6092,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 317 (fizzy / sickness) +# tile 318 (fizzy / sickness) { ................ ................ @@ -6111,7 +6111,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 318 (dark / fruit juice) +# tile 319 (dark / fruit juice) { ................ ................ @@ -6130,7 +6130,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 319 (white / acid) +# tile 320 (white / acid) { ................ ................ @@ -6149,7 +6149,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 320 (murky / oil) +# tile 321 (murky / oil) { ................ ................ @@ -6168,7 +6168,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 321 (clear / water) +# tile 322 (clear / water) { ................ ................ @@ -6187,7 +6187,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 322 (ZELGO MER / enchant armor) +# tile 323 (ZELGO MER / enchant armor) { ................ ................ @@ -6206,7 +6206,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 323 (JUYED AWK YACC / destroy armor) +# tile 324 (JUYED AWK YACC / destroy armor) { ................ ................ @@ -6225,7 +6225,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 324 (NR 9 / confuse monster) +# tile 325 (NR 9 / confuse monster) { ................ ................ @@ -6244,7 +6244,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 325 (XIXAXA XOXAXA XUXAXA / scare monster) +# tile 326 (XIXAXA XOXAXA XUXAXA / scare monster) { ................ ................ @@ -6263,7 +6263,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 326 (PRATYAVAYAH / remove curse) +# tile 327 (PRATYAVAYAH / remove curse) { ................ ................ @@ -6282,7 +6282,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 327 (DAIYEN FOOELS / enchant weapon) +# tile 328 (DAIYEN FOOELS / enchant weapon) { ................ ................ @@ -6301,7 +6301,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 328 (LEP GEX VEN ZEA / create monster) +# tile 329 (LEP GEX VEN ZEA / create monster) { ................ ................ @@ -6320,7 +6320,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 329 (PRIRUTSENIE / taming) +# tile 330 (PRIRUTSENIE / taming) { ................ ................ @@ -6339,7 +6339,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 330 (ELBIB YLOH / genocide) +# tile 331 (ELBIB YLOH / genocide) { ................ ................ @@ -6358,7 +6358,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 331 (VERR YED HORRE / light) +# tile 332 (VERR YED HORRE / light) { ................ ................ @@ -6377,7 +6377,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 332 (VENZAR BORGAVVE / teleportation) +# tile 333 (VENZAR BORGAVVE / teleportation) { ................ ................ @@ -6396,7 +6396,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 333 (THARR / gold detection) +# tile 334 (THARR / gold detection) { ................ ................ @@ -6415,7 +6415,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 334 (YUM YUM / food detection) +# tile 335 (YUM YUM / food detection) { ................ ................ @@ -6434,7 +6434,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 335 (KERNOD WEL / identify) +# tile 336 (KERNOD WEL / identify) { ................ ................ @@ -6453,7 +6453,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 336 (ELAM EBOW / magic mapping) +# tile 337 (ELAM EBOW / magic mapping) { ................ ................ @@ -6472,7 +6472,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 337 (DUAM XNAHT / amnesia) +# tile 338 (DUAM XNAHT / amnesia) { ................ ................ @@ -6491,7 +6491,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 338 (ANDOVA BEGARIN / fire) +# tile 339 (ANDOVA BEGARIN / fire) { ................ ................ @@ -6510,7 +6510,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 339 (KIRJE / earth) +# tile 340 (KIRJE / earth) { ................ ................ @@ -6529,7 +6529,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 340 (VE FORBRYDERNE / punishment) +# tile 341 (VE FORBRYDERNE / punishment) { ................ ................ @@ -6548,7 +6548,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 341 (HACKEM MUCHE / charging) +# tile 342 (HACKEM MUCHE / charging) { ................ ................ @@ -6567,7 +6567,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 342 (VELOX NEB / stinking cloud) +# tile 343 (VELOX NEB / stinking cloud) { ................ ................ @@ -6586,7 +6586,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 343 (FOOBIE BLETCH) +# tile 344 (FOOBIE BLETCH) { ................ ................ @@ -6605,7 +6605,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 344 (TEMOV) +# tile 345 (TEMOV) { ................ ................ @@ -6624,7 +6624,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 345 (GARVEN DEH) +# tile 346 (GARVEN DEH) { ................ ................ @@ -6643,7 +6643,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 346 (READ ME) +# tile 347 (READ ME) { ................ ................ @@ -6662,7 +6662,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 347 (ETAOIN SHRDLU) +# tile 348 (ETAOIN SHRDLU) { ................ ................ @@ -6681,7 +6681,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 348 (LOREM IPSUM) +# tile 349 (LOREM IPSUM) { ................ ................ @@ -6700,7 +6700,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 349 (FNORD) +# tile 350 (FNORD) { ................ ................ @@ -6719,7 +6719,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 350 (KO BATE) +# tile 351 (KO BATE) { ................ ................ @@ -6738,7 +6738,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 351 (ABRA KA DABRA) +# tile 352 (ABRA KA DABRA) { ................ ................ @@ -6757,7 +6757,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 352 (ASHPD SODALG) +# tile 353 (ASHPD SODALG) { ................ ................ @@ -6776,7 +6776,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 353 (ZLORFIK) +# tile 354 (ZLORFIK) { ................ ................ @@ -6795,7 +6795,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 354 (GNIK SISI VLE) +# tile 355 (GNIK SISI VLE) { ................ ................ @@ -6814,7 +6814,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 355 (HAPAX LEGOMENON) +# tile 356 (HAPAX LEGOMENON) { ................ ................ @@ -6833,7 +6833,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 356 (EIRIS SAZUN IDISI) +# tile 357 (EIRIS SAZUN IDISI) { ................ ................ @@ -6852,7 +6852,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 357 (PHOL ENDE WODAN) +# tile 358 (PHOL ENDE WODAN) { ................ ................ @@ -6871,7 +6871,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 358 (GHOTI) +# tile 359 (GHOTI) { ................ ................ @@ -6890,7 +6890,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 359 (MAPIRO MAHAMA DIROMAT) +# tile 360 (MAPIRO MAHAMA DIROMAT) { ................ ................ @@ -6909,7 +6909,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 360 (VAS CORP BET MANI) +# tile 361 (VAS CORP BET MANI) { ................ ................ @@ -6928,7 +6928,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 361 (XOR OTA) +# tile 362 (XOR OTA) { ................ ................ @@ -6947,7 +6947,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 362 (STRC PRST SKRZ KRK) +# tile 363 (STRC PRST SKRZ KRK) { ................ ................ @@ -6966,7 +6966,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 363 (stamped / mail) +# tile 364 (stamped / mail) { ................ ................ @@ -6985,7 +6985,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 364 (unlabeled / blank paper) +# tile 365 (unlabeled / blank paper) { ................ ................ @@ -7004,7 +7004,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 365 (parchment / dig) +# tile 366 (parchment / dig) { ................ ................ @@ -7023,7 +7023,7 @@ Z = (195, 195, 195) .......JJJAA.... ................ } -# tile 366 (vellum / magic missile) +# tile 367 (vellum / magic missile) { ................ ................ @@ -7042,7 +7042,7 @@ Z = (195, 195, 195) .......JJJAA.... ................ } -# tile 367 (ragged / fireball) +# tile 368 (ragged / fireball) { ................ ................ @@ -7061,7 +7061,7 @@ Z = (195, 195, 195) ......OOJJAA.... ................ } -# tile 368 (dog eared / cone of cold) +# tile 369 (dog eared / cone of cold) { ................ ................ @@ -7080,7 +7080,7 @@ Z = (195, 195, 195) .......JJJAA.... ................ } -# tile 369 (mottled / sleep) +# tile 370 (mottled / sleep) { ................ ................ @@ -7099,7 +7099,7 @@ Z = (195, 195, 195) .......JJJAA.... ................ } -# tile 370 (stained / finger of death) +# tile 371 (stained / finger of death) { ................ ................ @@ -7118,7 +7118,7 @@ Z = (195, 195, 195) .......JJJAA.... ................ } -# tile 371 (cloth / light) +# tile 372 (cloth / light) { ................ ................ @@ -7137,7 +7137,7 @@ Z = (195, 195, 195) .......PPPAA.... ................ } -# tile 372 (leathery / detect monsters) +# tile 373 (leathery / detect monsters) { ................ ................ @@ -7156,7 +7156,7 @@ Z = (195, 195, 195) .......JJJAA.... ................ } -# tile 373 (white / healing) +# tile 374 (white / healing) { ................ ................ @@ -7175,7 +7175,7 @@ Z = (195, 195, 195) .......PNNAA.... ................ } -# tile 374 (pink / knock) +# tile 375 (pink / knock) { ................ ................ @@ -7194,7 +7194,7 @@ Z = (195, 195, 195) .......IIIAA.... ................ } -# tile 375 (red / force bolt) +# tile 376 (red / force bolt) { ................ ................ @@ -7213,7 +7213,7 @@ Z = (195, 195, 195) .......DDDAA.... ................ } -# tile 376 (orange / confuse monster) +# tile 377 (orange / confuse monster) { ................ ................ @@ -7232,7 +7232,7 @@ Z = (195, 195, 195) .......CCCAA.... ................ } -# tile 377 (yellow / cure blindness) +# tile 378 (yellow / cure blindness) { ................ ................ @@ -7251,7 +7251,7 @@ Z = (195, 195, 195) .......HHHAA.... ................ } -# tile 378 (velvet / drain life) +# tile 379 (velvet / drain life) { ................ ................ @@ -7270,7 +7270,7 @@ Z = (195, 195, 195) .......EEEAA.... ................ } -# tile 379 (light green / slow monster) +# tile 380 (light green / slow monster) { ................ ................ @@ -7289,7 +7289,7 @@ Z = (195, 195, 195) .......GGGAA.... ................ } -# tile 380 (dark green / wizard lock) +# tile 381 (dark green / wizard lock) { ................ ................ @@ -7308,7 +7308,7 @@ Z = (195, 195, 195) .......FFFAA.... ................ } -# tile 381 (turquoise / create monster) +# tile 382 (turquoise / create monster) { ................ ................ @@ -7327,7 +7327,7 @@ Z = (195, 195, 195) .......FBBAA.... ................ } -# tile 382 (cyan / detect food) +# tile 383 (cyan / detect food) { ................ ................ @@ -7346,7 +7346,7 @@ Z = (195, 195, 195) .......BBBAA.... ................ } -# tile 383 (light blue / cause fear) +# tile 384 (light blue / cause fear) { ................ ................ @@ -7365,7 +7365,7 @@ Z = (195, 195, 195) .......BBBAA.... ................ } -# tile 384 (dark blue / clairvoyance) +# tile 385 (dark blue / clairvoyance) { ................ ................ @@ -7384,7 +7384,7 @@ Z = (195, 195, 195) .......EEEAA.... ................ } -# tile 385 (indigo / cure sickness) +# tile 386 (indigo / cure sickness) { ................ ................ @@ -7403,7 +7403,7 @@ Z = (195, 195, 195) .......EEEAA.... ................ } -# tile 386 (magenta / charm monster) +# tile 387 (magenta / charm monster) { ................ ................ @@ -7422,7 +7422,7 @@ Z = (195, 195, 195) .......IIIAA.... ................ } -# tile 387 (purple / haste self) +# tile 388 (purple / haste self) { ................ ................ @@ -7441,7 +7441,7 @@ Z = (195, 195, 195) .......IIIAA.... ................ } -# tile 388 (violet / detect unseen) +# tile 389 (violet / detect unseen) { ................ ................ @@ -7460,7 +7460,7 @@ Z = (195, 195, 195) .......IIIAA.... ................ } -# tile 389 (tan / levitation) +# tile 390 (tan / levitation) { ................ ................ @@ -7479,7 +7479,7 @@ Z = (195, 195, 195) .......KKKAA.... ................ } -# tile 390 (plaid / extra healing) +# tile 391 (plaid / extra healing) { ................ ................ @@ -7498,7 +7498,7 @@ Z = (195, 195, 195) .......EFDAA.... ................ } -# tile 391 (light brown / restore ability) +# tile 392 (light brown / restore ability) { ................ ................ @@ -7517,7 +7517,7 @@ Z = (195, 195, 195) .......JJJAA.... ................ } -# tile 392 (dark brown / invisibility) +# tile 393 (dark brown / invisibility) { ................ ................ @@ -7536,7 +7536,7 @@ Z = (195, 195, 195) .......JJJAA.... ................ } -# tile 393 (gray / detect treasure) +# tile 394 (gray / detect treasure) { ................ ................ @@ -7555,7 +7555,7 @@ Z = (195, 195, 195) .......PPPAA.... ................ } -# tile 394 (wrinkled / remove curse) +# tile 395 (wrinkled / remove curse) { ................ ................ @@ -7574,7 +7574,7 @@ Z = (195, 195, 195) ......JJKKAA.... ................ } -# tile 395 (dusty / magic mapping) +# tile 396 (dusty / magic mapping) { ................ ................ @@ -7593,7 +7593,7 @@ Z = (195, 195, 195) .KAKA..JJJAA.... ................ } -# tile 396 (bronze / identify) +# tile 397 (bronze / identify) { ................ ................ @@ -7612,7 +7612,7 @@ Z = (195, 195, 195) .......CCCAA.... ................ } -# tile 397 (copper / turn undead) +# tile 398 (copper / turn undead) { ................ ................ @@ -7631,7 +7631,7 @@ Z = (195, 195, 195) .......JCJAA.... ................ } -# tile 398 (silver / polymorph) +# tile 399 (silver / polymorph) { ................ ................ @@ -7650,7 +7650,7 @@ Z = (195, 195, 195) .......PPPAA.... ................ } -# tile 399 (gold / teleport away) +# tile 400 (gold / teleport away) { ................ ................ @@ -7669,7 +7669,7 @@ Z = (195, 195, 195) .......HHHAA.... ................ } -# tile 400 (glittering / create familiar) +# tile 401 (glittering / create familiar) { ................ ................ @@ -7688,7 +7688,7 @@ Z = (195, 195, 195) .......PPPAN.... .......N........ } -# tile 401 (shining / cancellation) +# tile 402 (shining / cancellation) { ....N........... .......N........ @@ -7707,7 +7707,7 @@ Z = (195, 195, 195) .......PPPAA.... ................ } -# tile 402 (dull / protection) +# tile 403 (dull / protection) { ................ ................ @@ -7726,7 +7726,7 @@ Z = (195, 195, 195) .......JJJAA.... ................ } -# tile 403 (thin / jumping) +# tile 404 (thin / jumping) { ................ ................ @@ -7745,7 +7745,7 @@ Z = (195, 195, 195) .......JJJAA.... ................ } -# tile 404 (thick / stone to flesh) +# tile 405 (thick / stone to flesh) { ................ ................ @@ -7764,7 +7764,7 @@ Z = (195, 195, 195) .......JJJAA.... ................ } -# tile 405 (checkered / chain lightning) +# tile 406 (checkered / chain lightning) { ................ ................ @@ -7783,7 +7783,7 @@ Z = (195, 195, 195) .......AAA...... ................ } -# tile 405 (plain / blank paper) +# tile 406 (plain / blank paper) { ................ ................ @@ -7802,7 +7802,7 @@ Z = (195, 195, 195) .......JJJAA.... ................ } -# tile 406 (paperback / novel) +# tile 407 (paperback / novel) { ................ ................ @@ -7821,7 +7821,7 @@ Z = (195, 195, 195) .......EEEAA.... ................ } -# tile 407 (papyrus / Book of the Dead) +# tile 408 (papyrus / Book of the Dead) { ................ ................ @@ -7840,7 +7840,7 @@ Z = (195, 195, 195) .......AAA...... ................ } -# tile 408 (glass / light) +# tile 409 (glass / light) { ................ ................ @@ -7859,7 +7859,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 409 (balsa / secret door detection) +# tile 410 (balsa / secret door detection) { ................ ................ @@ -7878,7 +7878,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 410 (crystal / enlightenment) +# tile 411 (crystal / enlightenment) { ................ ................ @@ -7897,7 +7897,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 411 (maple / create monster) +# tile 412 (maple / create monster) { ................ ................ @@ -7916,7 +7916,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 412 (pine / wishing) +# tile 413 (pine / wishing) { ................ ................ @@ -7935,7 +7935,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 413 (oak / nothing) +# tile 414 (oak / nothing) { ................ ................ @@ -7954,7 +7954,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 414 (ebony / striking) +# tile 415 (ebony / striking) { ................ ................ @@ -7973,7 +7973,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 415 (marble / make invisible) +# tile 416 (marble / make invisible) { ................ ................ @@ -7992,7 +7992,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 416 (tin / slow monster) +# tile 417 (tin / slow monster) { ................ ................ @@ -8011,7 +8011,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 417 (brass / speed monster) +# tile 418 (brass / speed monster) { ................ ................ @@ -8030,7 +8030,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 418 (copper / undead turning) +# tile 419 (copper / undead turning) { ................ ................ @@ -8049,7 +8049,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 419 (silver / polymorph) +# tile 420 (silver / polymorph) { ................ ................ @@ -8068,7 +8068,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 420 (platinum / cancellation) +# tile 421 (platinum / cancellation) { ................ ................ @@ -8087,7 +8087,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 421 (iridium / teleportation) +# tile 422 (iridium / teleportation) { ................ ................ @@ -8106,7 +8106,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 422 (zinc / opening) +# tile 423 (zinc / opening) { ................ ................ @@ -8125,7 +8125,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 423 (aluminum / locking) +# tile 424 (aluminum / locking) { ................ ................ @@ -8144,7 +8144,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 424 (uranium / probing) +# tile 425 (uranium / probing) { ................ ................ @@ -8163,7 +8163,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 425 (iron / digging) +# tile 426 (iron / digging) { ................ ................ @@ -8182,7 +8182,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 426 (steel / magic missile) +# tile 427 (steel / magic missile) { ................ ................ @@ -8201,7 +8201,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 427 (hexagonal / fire) +# tile 428 (hexagonal / fire) { ................ ................ @@ -8220,7 +8220,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 428 (short / cold) +# tile 429 (short / cold) { ................ ................ @@ -8239,7 +8239,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 429 (runed / sleep) +# tile 430 (runed / sleep) { ................ ................ @@ -8258,7 +8258,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 430 (long / death) +# tile 431 (long / death) { ................ .............NO. @@ -8277,7 +8277,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 431 (curved / lightning) +# tile 432 (curved / lightning) { ................ .......NO....... @@ -8296,7 +8296,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 432 (forked) +# tile 433 (forked) { ................ ................ @@ -8315,7 +8315,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 433 (spiked) +# tile 434 (spiked) { ................ ................ @@ -8334,7 +8334,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 434 (jeweled) +# tile 435 (jeweled) { ................ ................ @@ -8353,7 +8353,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 435 (gold piece) +# tile 436 (gold piece) { ................ ................ @@ -8372,7 +8372,7 @@ Z = (195, 195, 195) .........HA..... ...........HA... } -# tile 436 (white / dilithium crystal) +# tile 437 (white / dilithium crystal) { ................ ................ @@ -8391,7 +8391,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 437 (white / diamond) +# tile 438 (white / diamond) { ................ ................ @@ -8410,7 +8410,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 438 (red / ruby) +# tile 439 (red / ruby) { ................ ................ @@ -8429,7 +8429,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 439 (orange / jacinth) +# tile 440 (orange / jacinth) { ................ ................ @@ -8448,7 +8448,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 440 (blue / sapphire) +# tile 441 (blue / sapphire) { ................ ................ @@ -8467,7 +8467,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 441 (black / black opal) +# tile 442 (black / black opal) { ................ ................ @@ -8486,7 +8486,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 442 (green / emerald) +# tile 443 (green / emerald) { ................ ................ @@ -8505,7 +8505,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 443 (green / turquoise) +# tile 444 (green / turquoise) { ................ ................ @@ -8524,7 +8524,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 444 (yellow / citrine) +# tile 445 (yellow / citrine) { ................ ................ @@ -8543,7 +8543,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 445 (green / aquamarine) +# tile 446 (green / aquamarine) { ................ ................ @@ -8562,7 +8562,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 446 (yellowish brown / amber) +# tile 447 (yellowish brown / amber) { ................ ................ @@ -8581,7 +8581,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 447 (yellowish brown / topaz) +# tile 448 (yellowish brown / topaz) { ................ ................ @@ -8600,7 +8600,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 448 (black / jet) +# tile 449 (black / jet) { ................ ................ @@ -8619,7 +8619,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 449 (white / opal) +# tile 450 (white / opal) { ................ ................ @@ -8638,7 +8638,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 450 (yellow / chrysoberyl) +# tile 451 (yellow / chrysoberyl) { ................ ................ @@ -8657,7 +8657,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 451 (red / garnet) +# tile 452 (red / garnet) { ................ ................ @@ -8676,7 +8676,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 452 (violet / amethyst) +# tile 453 (violet / amethyst) { ................ ................ @@ -8695,7 +8695,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 453 (red / jasper) +# tile 454 (red / jasper) { ................ ................ @@ -8714,7 +8714,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 454 (violet / fluorite) +# tile 455 (violet / fluorite) { ................ ................ @@ -8733,7 +8733,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 455 (black / obsidian) +# tile 456 (black / obsidian) { ................ ................ @@ -8752,7 +8752,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 456 (orange / agate) +# tile 457 (orange / agate) { ................ ................ @@ -8771,7 +8771,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 457 (green / jade) +# tile 458 (green / jade) { ................ ................ @@ -8790,7 +8790,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 458 (white / worthless piece of white glass) +# tile 459 (white / worthless piece of white glass) { ................ ................ @@ -8809,7 +8809,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 459 (blue / worthless piece of blue glass) +# tile 460 (blue / worthless piece of blue glass) { ................ ................ @@ -8828,7 +8828,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 460 (red / worthless piece of red glass) +# tile 461 (red / worthless piece of red glass) { ................ ................ @@ -8847,7 +8847,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 461 (yellowish brown / worthless piece of yellowish brown glass) +# tile 462 (yellowish brown / worthless piece of yellowish brown glass) { ................ ................ @@ -8866,7 +8866,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 462 (orange / worthless piece of orange glass) +# tile 463 (orange / worthless piece of orange glass) { ................ ................ @@ -8885,7 +8885,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 463 (yellow / worthless piece of yellow glass) +# tile 464 (yellow / worthless piece of yellow glass) { ................ ................ @@ -8904,7 +8904,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 464 (black / worthless piece of black glass) +# tile 465 (black / worthless piece of black glass) { ................ ................ @@ -8923,7 +8923,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 465 (green / worthless piece of green glass) +# tile 466 (green / worthless piece of green glass) { ................ ................ @@ -8942,7 +8942,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 466 (violet / worthless piece of violet glass) +# tile 467 (violet / worthless piece of violet glass) { ................ ................ @@ -8961,7 +8961,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 467 (gray / luckstone) +# tile 468 (gray / luckstone) { ................ ................ @@ -8980,7 +8980,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 468 (gray / loadstone) +# tile 469 (gray / loadstone) { ................ ................ @@ -8999,7 +8999,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 469 (gray / touchstone) +# tile 470 (gray / touchstone) { ................ ................ @@ -9018,7 +9018,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 470 (gray / flint) +# tile 471 (gray / flint) { ................ ................ @@ -9037,7 +9037,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 471 (rock) +# tile 472 (rock) { ................ ................ @@ -9056,7 +9056,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 472 (boulder) +# tile 473 (boulder) { ................ ................ @@ -9075,7 +9075,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 473 (statue) +# tile 474 (statue) { ................ ........JJ...... @@ -9094,7 +9094,7 @@ Z = (195, 195, 195) .....JJJJJJAA... ................ } -# tile 474 (heavy iron ball) +# tile 475 (heavy iron ball) { ................ ................ @@ -9113,7 +9113,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 475 (iron chain) +# tile 476 (iron chain) { ................ ................ @@ -9132,7 +9132,7 @@ Z = (195, 195, 195) ...........PP.PA ............AA.. } -# tile 476 (splash of venom / splash of blinding venom) +# tile 477 (splash of venom / splash of blinding venom) { ................ ................ @@ -9151,7 +9151,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 477 (splash of venom / splash of acid venom) +# tile 478 (splash of venom / splash of acid venom) { ................ ................ From fa229439d4df0a2b23ac55191f2a7336862efa58 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Wed, 9 Apr 2025 21:00:34 +0300 Subject: [PATCH 539/791] Fixes entry for silver mace Fixes #1405 --- doc/fixes3-7-0.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index d2b0a4964..ea3e3b373 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -989,7 +989,7 @@ bigroom variant 3 may have some walls replaced with other terrain bigroom variant 4 may have two large squares of terrain in the middle bigroom variant 5 may have patches of ice or clouds some large monsters can knock back smaller monsters with a hit -change Demonbane to a mace, make it the first sac gift for priests, +change Demonbane to a silver mace, make it the first sac gift for priests, and give it an invoke ability to banish demons wielding Giantslayer prevents knockback from larger monsters; likewise for carried loadstone(s) @@ -2980,6 +2980,7 @@ split making pits on do_earthquake() into a separate function and eliminate some gotos on do_earthquake() (pr #1287 by argrath) update the WASM cross-compile to work with the current code (pr #1331 by guillaumebrunerie) +add silver maces (pr #1405 by disperse) Code Cleanup and Reorganization From 197e6af78c2ac1dfefdef4769a56eefeba72f886 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Wed, 9 Apr 2025 21:26:22 +0300 Subject: [PATCH 540/791] Increment EDITLEVEL for silver maces --- include/patchlevel.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/patchlevel.h b/include/patchlevel.h index ee05d8ac0..9b6140a6d 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 120 +#define EDITLEVEL 121 /* * Development status possibilities. From 7138af00ba16f97a79a5c251348142dde303c4ca Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Thu, 10 Apr 2025 23:38:44 +0300 Subject: [PATCH 541/791] Praying on an altar with pet statue on it can revive the pet --- doc/fixes3-7-0.txt | 2 +- src/pray.c | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index ea3e3b373..b7d83fd89 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -963,7 +963,7 @@ putting on water walking boots while underwater (maybe via magical breathing) and rising to surface wasn't causing the boots to become discovered flying pets wouldn't target underwater food but if they happened to fly over such food they could and would eat it -praying on an altar with pet corpse on it can revive the pet +praying on an altar with pet corpse or statue on it can revive the pet applying a cursed oil lamp can make your hands slippery valkyries start with a spear instead of a long sword grid bugs don't have hands diff --git a/src/pray.c b/src/pray.c index 066042af0..6250505ee 100644 --- a/src/pray.c +++ b/src/pray.c @@ -2178,14 +2178,19 @@ pray_revive(void) struct obj *otmp; for (otmp = svl.level.objects[u.ux][u.uy]; otmp; otmp = otmp->nexthere) - if (otmp->otyp == CORPSE && has_omonst(otmp) + if ((otmp->otyp == CORPSE || otmp->otyp == STATUE) + && has_omonst(otmp) && OMONST(otmp)->mtame && !OMONST(otmp)->isminion) break; if (!otmp) return FALSE; - return (revive(otmp, TRUE) != NULL); + if (otmp->otyp == CORPSE) + return (revive(otmp, TRUE) != NULL); + else { + return (animate_statue(otmp, u.ux, u.uy, ANIMATE_SPELL, NULL) != NULL); + } } /* #pray command */ From 5a910f3df71ed7ef378e533cd258729d49802255 Mon Sep 17 00:00:00 2001 From: PatR Date: Fri, 11 Apr 2025 15:19:06 -0700 Subject: [PATCH 542/791] Revert "whitespace cleanup for themerms.lua" This reverts commit eee5a1698bb9363eeb4e2c2e30c2edd563ca6b28. Easier to commit PR #1384. --- dat/themerms.lua | 263 ++++++++++++++++++++--------------------------- 1 file changed, 114 insertions(+), 149 deletions(-) diff --git a/dat/themerms.lua b/dat/themerms.lua index f42111dc7..454059125 100644 --- a/dat/themerms.lua +++ b/dat/themerms.lua @@ -1,4 +1,4 @@ --- NetHack themerms.lua $NHDT-Date: 1743399789 2025/03/30 21:43:09 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.36 $ +-- NetHack themerms.lua $NHDT-Date: 1652196294 2022/05/10 15:24:54 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.16 $ -- Copyright (c) 2020 by Pasi Kallinen -- NetHack may be freely redistributed. See license for details. -- @@ -81,7 +81,8 @@ themeroom_fills = { -- Trap room function(rm) local traps = { "arrow", "dart", "falling rock", "bear", - "land mine", "sleep gas", "rust", "anti magic" }; + "land mine", "sleep gas", "rust", + "anti magic" }; shuffle(traps); local locs = selection.room():percentage(30); local func = function(x,y) @@ -102,28 +103,22 @@ themeroom_fills = { des.feature("fountain"); end end - table.insert(postprocess, { handler = make_garden_walls, - data = { sel = selection.room() } }); + table.insert(postprocess, { handler = make_garden_walls, data = { sel = selection.room() } }); end }, -- Buried treasure function(rm) - des.object({ - id = "chest", buried = true, - contents = function(otmp) - local xobj = otmp:totable(); - -- keep track of the last buried treasure - if (xobj.NO_OBJ == nil) then - table.insert(postprocess, { handler = make_dig_engraving, - data = { x = xobj.ox, - y = xobj.oy } }); - end - for i = 1, d(3, 4) do - des.object(); - end - end - }); + des.object({ id = "chest", buried = true, contents = function(otmp) + local xobj = otmp:totable(); + -- keep track of the last buried treasure + if (xobj.NO_OBJ == nil) then + table.insert(postprocess, { handler = make_dig_engraving, data = { x = xobj.ox, y = xobj.oy }}); + end + for i = 1, d(3,4) do + des.object(); + end + end }); end, -- Buried zombies @@ -234,9 +229,7 @@ themeroom_fills = { if (pos.x > 0) then pos.x = pos.x + rm.region.x1 - 1; pos.y = pos.y + rm.region.y1; - table.insert(postprocess, { handler = make_a_trap, - data = { type = "teleport", seen = true, - coord = pos, teledest = 1 } }); + table.insert(postprocess, { handler = make_a_trap, data = { type = "teleport", seen = true, coord = pos, teledest = 1 } }); end end end, @@ -255,8 +248,7 @@ themerooms = { function() des.room({ type = "ordinary", w = 11,h = 9, filled = 1, contents = function() - des.room({ type = "ordinary", x = 4, y = 3, w = 3, h = 3, - filled = 1, + des.room({ type = "ordinary", x = 4,y = 3, w = 3,h = 3, filled = 1, contents = function() des.door({ state="random", wall="all" }); end @@ -280,8 +272,7 @@ themerooms = { -- Huge room, with another room inside (90%) function() - des.room({ type = "ordinary", w = nh.rn2(10) + 11, h = nh.rn2(5) + 8, - filled = 1, + des.room({ type = "ordinary", w = nh.rn2(10)+11,h = nh.rn2(5)+8, filled = 1, contents = function() if (percent(90)) then des.room({ type = "ordinary", filled = 1, @@ -369,17 +360,15 @@ themerooms = { des.room({ type = "themed", w = 5 + nh.rn2(3)*2, h = 5 + nh.rn2(3)*2, contents = function(rm) des.room({ type = "themed", - x = (rm.width - 1) / 2, y = (rm.height - 1) / 2, - w = 1, h = 1, joined = false, + x = (rm.width - 1) / 2, y = (rm.height - 1) / 2, + w = 1, h = 1, joined = false, contents = function() if (percent(50)) then local mons = { "M", "V", "L", "Z" }; shuffle(mons); - des.monster({ class = mons[1], x=0, y=0, - waiting = 1 }); + des.monster({ class = mons[1], x=0,y=0, waiting = 1 }); else - des.object({ id = "corpse", montype = "@", - coord = {0,0} }); + des.object({ id = "corpse", montype = "@", coord = {0,0} }); end if (percent(20)) then des.door({ state="secret", wall="all" }); @@ -399,7 +388,7 @@ themerooms = { local feature = { "C", "L", "I", "P", "T" }; shuffle(feature); des.terrain((rm.width - 1) / 2, (rm.height - 1) / 2, - feature[1]); + feature[1]); end }); end, @@ -470,15 +459,13 @@ xxx-----]], contents = function(m) filler_region(1,1); end }); |.........| |.........| -----------]], contents = function(m) - if (percent(30)) then - local terr = { "-", "P" }; - shuffle(terr); - des.replace_terrain({ region = {1,1, 9,9}, - fromterrain = "L", toterrain = terr[1] }); - end - filler_region(1,1); - end - }); +if (percent(30)) then + local terr = { "-", "P" }; + shuffle(terr); + des.replace_terrain({ region = {1,1, 9,9}, fromterrain = "L", toterrain = terr[1] }); +end +filler_region(1,1); +end }); end, -- Circular, small @@ -679,116 +666,102 @@ xx|.....|xx }|..|} }|..|} }----} -}}}}}}]], contents = function(m) des.region({ region = {3, 3, 3, 3}, - type = "themed", irregular = true, - filled = 0, joined = false }); - local nasty_undead = { "giant zombie", "ettin zombie", - "vampire lord" }; - local chest_spots = { { 2, 2 }, { 3, 2 }, { 2, 3 }, { 3, 3 } }; +}}}}}}]], contents = function(m) des.region({ region={3,3,3,3}, type="themed", irregular=true, filled=0, joined=false }); + local nasty_undead = { "giant zombie", "ettin zombie", "vampire lord" }; + local chest_spots = { { 2, 2 }, { 3, 2 }, { 2, 3 }, { 3, 3 } }; - shuffle(chest_spots) - -- Guarantee an escape item inside one of the chests, to prevent the - -- hero falling in from above and becoming permanently stuck - -- [cf. generate_way_out_method(sp_lev.c)]. - -- If the escape item is made of glass or crystal, make sure that - -- the chest isn't locked so that kicking it to gain access to its - -- contents won't be necessary; otherwise retain lock state from - -- random creation. "pick-axe", "dwarvish mattock" could be included - -- in list of escape items but don't normally generate in containers. - local escape_items = { - "scroll of teleportation", "ring of teleportation", - "wand of teleportation", "wand of digging" - }; - local itm = obj.new( escape_items[math.random(#escape_items)] ); - local itmcls = itm:class() - local box - if itmcls[ "material" ] == "glass" then - -- explicitly force chest to be unlocked - box = des.object({ id = "chest", coord = chest_spots[1], - olocked = "no" }); - else - -- accept random locked/unlocked state - box = des.object({ id = "chest", coord = chest_spots[1] }); - end; - box:addcontent(itm); + shuffle(chest_spots) + -- Guarantee an escape item inside one of the chests, to prevent the hero + -- falling in from above and becoming permanently stuck + -- [cf. generate_way_out_method(sp_lev.c)]. + -- If the escape item is made of glass or crystal, make sure that the + -- chest isn't locked so that kicking it to gain access to its contents + -- won't be necessary; otherwise retain lock state from random creation. + -- "pick-axe", "dwarvish mattock" could be included in the list of escape + -- items but don't normally generate in containers. + local escape_items = { + "scroll of teleportation", "ring of teleportation", + "wand of teleportation", "wand of digging" + }; + local itm = obj.new(escape_items[math.random(#escape_items)]); + local itmcls = itm:class() + local box + if itmcls[ "material" ] == "glass" then + -- explicitly force chest to be unlocked + box = des.object({ id = "chest", coord = chest_spots[1], + olocked = "no" }); + else + -- accept random locked/unlocked state + box = des.object({ id = "chest", coord = chest_spots[1] }); + end; + box:addcontent(itm); - for i = 2, #chest_spots do - des.object({ id = "chest", coord = chest_spots[i] }); - end + for i = 2, #chest_spots do + des.object({ id = "chest", coord = chest_spots[i] }); + end - shuffle(nasty_undead); - des.monster(nasty_undead[1], 2, 2); - des.exclusion({ type = "teleport", region = { 2,2, 3,3 } }); - end - }); -- des.map + shuffle(nasty_undead); + des.monster(nasty_undead[1], 2, 2); + des.exclusion({ type = "teleport", region = { 2,2, 3,3 } }); +end }); end, -- Twin businesses { - mindiff = 4; -- arbitrary; needs to be greater than 1 since no shops on 1 + mindiff = 4; -- arbitrary contents = function() -- Due to the way room connections work in mklev.c, we must guarantee -- that the "aisle" between the shops touches all four walls of the -- larger room. Thus it has an extra width and height. des.room({ type="themed", w=9, h=5, contents = function() - -- There are eight possible placements of the two shops, four of - -- which have the vertical aisle in the center. - southeast = function() return percent(50) and "south" or "east" end - northeast = function() return percent(50) and "north" or "east" end - northwest = function() return percent(50) and "north" or "west" end - southwest = function() return percent(50) and "south" or "west" end - placements = { - { lx = 1, ly = 1, rx = 4, ry = 1, - lwall = "south", rwall = southeast() }, - { lx = 1, ly = 2, rx = 4, ry = 2, - lwall = "north", rwall = northeast() }, - { lx = 1, ly = 1, rx = 5, ry = 1, - lwall = southeast(), rwall = southwest() }, - { lx = 1, ly = 1, rx = 5, ry = 2, - lwall = southeast(), rwall = northwest() }, - { lx = 1, ly = 2, rx = 5, ry = 1, - lwall = northeast(), rwall = southwest() }, - { lx = 1, ly = 2, rx = 5, ry = 2, - lwall = northeast(), rwall = northwest() }, - { lx = 2, ly = 1, rx = 5, ry = 1, - lwall = southwest(), rwall = "south" }, - { lx = 2, ly = 2, rx = 5, ry = 2, - lwall = northwest(), rwall = "north" } - } - ltype, rtype = "weapon shop", "armor shop" - if percent(50) then - ltype, rtype = rtype, ltype - end - shopdoorstate = function() - if percent(1) then - return "locked" - elseif percent(50) then - return "closed" - else - return "open" + -- There are eight possible placements of the two shops, four of + -- which have the vertical aisle in the center. + southeast = function() return percent(50) and "south" or "east" end + northeast = function() return percent(50) and "north" or "east" end + northwest = function() return percent(50) and "north" or "west" end + southwest = function() return percent(50) and "south" or "west" end + placements = { + { lx = 1, ly = 1, rx = 4, ry = 1, lwall = "south", rwall = southeast() }, + { lx = 1, ly = 2, rx = 4, ry = 2, lwall = "north", rwall = northeast() }, + { lx = 1, ly = 1, rx = 5, ry = 1, lwall = southeast(), rwall = southwest() }, + { lx = 1, ly = 1, rx = 5, ry = 2, lwall = southeast(), rwall = northwest() }, + { lx = 1, ly = 2, rx = 5, ry = 1, lwall = northeast(), rwall = southwest() }, + { lx = 1, ly = 2, rx = 5, ry = 2, lwall = northeast(), rwall = northwest() }, + { lx = 2, ly = 1, rx = 5, ry = 1, lwall = southwest(), rwall = "south" }, + { lx = 2, ly = 2, rx = 5, ry = 2, lwall = northwest(), rwall = "north" } + } + ltype,rtype = "weapon shop","armor shop" + if percent(50) then + ltype,rtype = rtype,ltype end - end - p = placements[ d(#placements) ] - des.room({ type = ltype, x = p["lx"], y = p["ly"], w = 3, h = 3, - filled = 1, joined = false, - contents = function() - des.door({ state = shopdoorstate(), - wall = p["lwall"] }) - end - }); - des.room({ type = rtype, x = p["rx"], y = p["ry"], w = 3, h = 3, - filled = 1, joined = false, - contents = function() - des.door({ state = shopdoorstate(), - wall = p["rwall"] }) - end - }); + shopdoorstate = function() + if percent(1) then + return "locked" + elseif percent(50) then + return "closed" + else + return "open" + end + end + p = placements[d(#placements)] + des.room({ type=ltype, x=p["lx"], y=p["ly"], w=3, h=3, filled=1, joined=false, + contents = function() + des.door({ state=shopdoorstate(), wall=p["lwall"] }) + end + }); + des.room({ type=rtype, x=p["rx"], y=p["ry"], w=3, h=3, filled=1, joined=false, + contents = function() + des.door({ state=shopdoorstate(), wall=p["rwall"] }) + end + }); end }); end }, + }; + function filler_region(x, y) local rmtyp = "ordinary"; local func = nil; @@ -796,8 +769,7 @@ function filler_region(x, y) rmtyp = "themed"; func = themeroom_fill; end - des.region({ region = {x,y,x,y}, type = rmtyp, irregular = true, filled = 1, - contents = func }); + des.region({ region={x,y,x,y}, type=rmtyp, irregular=true, filled=1, contents = func }); end function is_eligible(room, mkrm) @@ -827,16 +799,14 @@ function themerooms_generate() -- which may change on different levels because of level difficulty. if is_eligible(themerooms[i], nil) then local this_frequency; - if (type(themerooms[i]) == "table" and themerooms[i].frequency ~= nil) - then + if (type(themerooms[i]) == "table" and themerooms[i].frequency ~= nil) then this_frequency = themerooms[i].frequency; else this_frequency = 1; end total_frequency = total_frequency + this_frequency; -- avoid rn2(0) if a room has freq 0 - if this_frequency > 0 and nh.rn2(total_frequency) < this_frequency - then + if this_frequency > 0 and nh.rn2(total_frequency) < this_frequency then pick = i; end end @@ -867,16 +837,14 @@ function themeroom_fill(rm) -- which may change on different levels because of level difficulty. if is_eligible(themeroom_fills[i], rm) then local this_frequency; - if (type(themeroom_fills[i]) == "table" - and themeroom_fills[i].frequency ~= nil) then + if (type(themeroom_fills[i]) == "table" and themeroom_fills[i].frequency ~= nil) then this_frequency = themeroom_fills[i].frequency; else this_frequency = 1; end total_frequency = total_frequency + this_frequency; -- avoid rn2(0) if a room has freq 0 - if this_frequency > 0 and nh.rn2(total_frequency) < this_frequency - then + if this_frequency > 0 and nh.rn2(total_frequency) < this_frequency then pick = i; end end @@ -901,12 +869,10 @@ function make_dig_engraving(data) dig = " here"; else if (tx < 0 or tx > 0) then - dig = string.format(" %i %s", math.abs(tx), - (tx > 0) and "east" or "west"); + dig = string.format(" %i %s", math.abs(tx), (tx > 0) and "east" or "west"); end if (ty < 0 or ty > 0) then - dig = dig .. string.format(" %i %s", math.abs(ty), - (ty > 0) and "south" or "north"); + dig = dig .. string.format(" %i %s", math.abs(ty), (ty > 0) and "south" or "north"); end end des.engraving({ coord = pos, type = "burn", text = "Dig" .. dig }); @@ -924,8 +890,7 @@ function make_a_trap(data) local locs = selection.negate():filter_mapchar("."); repeat data.teledest = locs:rndcoord(1); - until (data.teledest.x ~= data.coord.x - and data.teledest.y ~= data.coord.y); + until (data.teledest.x ~= data.coord.x and data.teledest.y ~= data.coord.y); end des.trap(data); end From 47e6edc66388927b04194940eb61cb92fba1add1 Mon Sep 17 00:00:00 2001 From: copperwater Date: Sun, 23 Feb 2025 13:50:30 -0500 Subject: [PATCH 543/791] Enable generating specific themed rooms for debugging A common pain point I encounter when working on themed rooms is making specific rooms generate. The only ways to do this were mass commenting out the rooms not being tested, or hacking in different room frequency values (even more annoying when testing a fill, not a room, or testing pure-function rooms/fills that have no frequency). This change solves that problem by allowing a wizard-mode user to define THEMERM or THEMERMFILL environment variables to make specific rooms or fills generate. The first part of this change is converting all themed rooms and fills that were plain functions into tables, and converting their comment names into actual names in those tables. The names are not intended to be shown during gameplay, but instead serve as values that THEMERM or THEMERMFILL can be matched to to generate those rooms. It's no longer possible to have a function themeroom; this will raise an impossible. As far as I'm concerned, this is a good change because it allows some code simplification of themerooms_generate and makes it easier to add difficulty or eligibility parameters to rooms. The second part of this change is adding a new nh.debug_themerm function to make the environment variable values accessible to themerms.lua. I looked for an existing way to do this but didn't see one (nh.variable is the closest but appears to be for variables that get saved). The final part is inserting behavior into the actual themeroom generation code that changes how they generate when either a room or a fill is set. I don't think it's safe to generate every single room with the requested type or fill - that might lead to cases where the stairs or a magic portal cannot generate. So it creates ordinary rooms half of the time, which still results in plenty of themed rooms on levels. Another thing to note is that any themed room using filler_region will still only pick a fill 30% of the time. If one specifies both a fill and a room that uses filler_region, many of those rooms will appear without a themed fill. --- dat/themerms.lua | 1061 ++++++++++++++++++++++++++-------------------- src/nhlua.c | 26 ++ 2 files changed, 637 insertions(+), 450 deletions(-) diff --git a/dat/themerms.lua b/dat/themerms.lua index 454059125..b7e0f1f0a 100644 --- a/dat/themerms.lua +++ b/dat/themerms.lua @@ -2,12 +2,26 @@ -- Copyright (c) 2020 by Pasi Kallinen -- NetHack may be freely redistributed. See license for details. -- --- themerooms is an array of tables and/or functions. --- the tables define "frequency", "contents", "mindiff" and "maxdiff". --- frequency is optional; if omitted, 1 is assumed. --- mindiff and maxdiff are optional and independent; if omitted, the room is --- not constrained by level difficulty. --- a plain function has frequency of 1, and no difficulty constraints. +-- themerooms is an array of tables. +-- the tables define "name", "frequency", "contents", "mindiff" and "maxdiff". +-- * "name" is not shown in-game; it is so that developers can specify a certain +-- room to generate by using the THEMERM or THEMERMFILL environment variable. +-- While technically optional, it should be provided on all the rooms; if it +-- isn't, the room can't be directly specified. +-- * "frequency" is optional; if omitted, 1 is assumed. +-- * "contents" is a function describing what gets put into the room. +-- * "mindiff" and "maxdiff" are optional and independent; if omitted, the room +-- is not constrained by level difficulty. +-- +-- themeroom_fills is an array of tables with the exact same structure as +-- themerooms. It is used for contents of a room that are independent of its +-- shape, so that interestingly-shaped themerooms can be filled with a variety +-- of contents. +-- * The "contents" functions in themeroom_fills take the room they are filling as +-- an argument. +-- * Frequency of themeroom_fills is a separate pool from themerooms, and has no +-- effect on how likely it is that any given room will receive a themeroom_fill. +-- -- des.room({ type = "ordinary", filled = 1 }) -- - ordinary rooms can be converted to shops or any other special rooms. -- - filled = 1 means the room gets random room contents, even if it @@ -24,35 +38,38 @@ -- The lua state is persistent through the gameplay, but not across saves, -- so remember to reset any variables. - local postprocess = { }; themeroom_fills = { - -- Ice room - function(rm) - local ice = selection.room(); - des.terrain(ice, "I"); - if (percent(25)) then - local mintime = 1000 - (nh.level_difficulty() * 100); - local ice_melter = function(x,y) - nh.start_timer_at(x,y, "melt-ice", mintime + nh.rn2(1000)); - end; - ice:iterate(ice_melter); - end - end, - - -- Cloud room - function(rm) - local fog = selection.room(); - for i = 1, (fog:numpoints() / 4) do - des.monster({ id = "fog cloud", asleep = true }); - end - des.gas_cloud({ selection = fog }); - end, - - -- Boulder room { + name = "Ice room", + contents = function(rm) + local ice = selection.room(); + des.terrain(ice, "I"); + if (percent(25)) then + local mintime = 1000 - (nh.level_difficulty() * 100); + local ice_melter = function(x,y) + nh.start_timer_at(x,y, "melt-ice", mintime + nh.rn2(1000)); + end; + ice:iterate(ice_melter); + end + end, + }, + + { + name = "Cloud room", + contents = function(rm) + local fog = selection.room(); + for i = 1, (fog:numpoints() / 4) do + des.monster({ id = "fog cloud", asleep = true }); + end + des.gas_cloud({ selection = fog }); + end, + }, + + { + name = "Boulder room", mindiff = 4, contents = function(rm) local locs = selection.room():percentage(30); @@ -64,35 +81,39 @@ themeroom_fills = { end end; locs:iterate(func); - end + end, }, - -- Spider nest - function(rm) - local spooders = nh.level_difficulty() > 8; - local locs = selection.room():percentage(30); - local func = function(x,y) - des.trap({ type = "web", x = x, y = y, - spider_on_web = spooders and percent(80) }); - end - locs:iterate(func); - end, - - -- Trap room - function(rm) - local traps = { "arrow", "dart", "falling rock", "bear", - "land mine", "sleep gas", "rust", - "anti magic" }; - shuffle(traps); - local locs = selection.room():percentage(30); - local func = function(x,y) - des.trap(traps[1], x, y); - end - locs:iterate(func); - end, - - -- Garden { + name = "Spider nest", + contents = function(rm) + local spooders = nh.level_difficulty() > 8; + local locs = selection.room():percentage(30); + local func = function(x,y) + des.trap({ type = "web", x = x, y = y, + spider_on_web = spooders and percent(80) }); + end + locs:iterate(func); + end, + }, + + { + name = "Trap room", + contents = function(rm) + local traps = { "arrow", "dart", "falling rock", "bear", + "land mine", "sleep gas", "rust", + "anti magic" }; + shuffle(traps); + local locs = selection.room():percentage(30); + local func = function(x,y) + des.trap(traps[1], x, y); + end + locs:iterate(func); + end, + }, + + { + name = "Garden", eligible = function(rm) return rm.lit == true; end, contents = function(rm) local s = selection.room(); @@ -107,216 +128,242 @@ themeroom_fills = { end }, - -- Buried treasure - function(rm) - des.object({ id = "chest", buried = true, contents = function(otmp) - local xobj = otmp:totable(); - -- keep track of the last buried treasure - if (xobj.NO_OBJ == nil) then - table.insert(postprocess, { handler = make_dig_engraving, data = { x = xobj.ox, y = xobj.oy }}); - end - for i = 1, d(3,4) do - des.object(); - end - end }); - end, - - -- Buried zombies - function(rm) - local diff = nh.level_difficulty() - -- start with [1..4] for low difficulty - local zombifiable = { "kobold", "gnome", "orc", "dwarf" }; - if diff > 3 then -- medium difficulty - zombifiable[5], zombifiable[6] = "elf", "human"; - if diff > 6 then -- high difficulty (relatively speaking) - zombifiable[7], zombifiable[8] = "ettin", "giant"; - end - end - for i = 1, (rm.width * rm.height) / 2 do - shuffle(zombifiable); - local o = des.object({ id = "corpse", montype = zombifiable[1], - buried = true }); - o:stop_timer("rot-corpse"); - o:start_timer("zombify-mon", math.random(990, 1010)); - end - end, - - -- Massacre - function(rm) - local mon = { "apprentice", "warrior", "ninja", "thug", - "hunter", "acolyte", "abbot", "page", - "attendant", "neanderthal", "chieftain", - "student", "wizard", "valkyrie", "tourist", - "samurai", "rogue", "ranger", "priestess", - "priest", "monk", "knight", "healer", - "cavewoman", "caveman", "barbarian", - "archeologist" }; - local idx = math.random(#mon); - for i = 1, d(5,5) do - if (percent(10)) then idx = math.random(#mon); end - des.object({ id = "corpse", montype = mon[idx] }); - end - end, - - -- Statuary - function(rm) - for i = 1, d(5,5) do - des.object({ id = "statue" }); - end - for i = 1, d(3) do - des.trap("statue"); - end - end, - - -- Light source { + name = "Buried treasure", + contents = function(rm) + des.object({ id = "chest", buried = true, contents = function(otmp) + local xobj = otmp:totable(); + -- keep track of the last buried treasure + if (xobj.NO_OBJ == nil) then + table.insert(postprocess, { handler = make_dig_engraving, data = { x = xobj.ox, y = xobj.oy }}); + end + for i = 1, d(3,4) do + des.object(); + end + end }); + end, + }, + + { + name = "Buried zombies", + contents = function(rm) + local diff = nh.level_difficulty() + -- start with [1..4] for low difficulty + local zombifiable = { "kobold", "gnome", "orc", "dwarf" }; + if diff > 3 then -- medium difficulty + zombifiable[5], zombifiable[6] = "elf", "human"; + if diff > 6 then -- high difficulty (relatively speaking) + zombifiable[7], zombifiable[8] = "ettin", "giant"; + end + end + for i = 1, (rm.width * rm.height) / 2 do + shuffle(zombifiable); + local o = des.object({ id = "corpse", montype = zombifiable[1], + buried = true }); + o:stop_timer("rot-corpse"); + o:start_timer("zombify-mon", math.random(990, 1010)); + end + end, + }, + + { + name = "Massacre", + contents = function(rm) + local mon = { "apprentice", "warrior", "ninja", "thug", + "hunter", "acolyte", "abbot", "page", + "attendant", "neanderthal", "chieftain", + "student", "wizard", "valkyrie", "tourist", + "samurai", "rogue", "ranger", "priestess", + "priest", "monk", "knight", "healer", + "cavewoman", "caveman", "barbarian", + "archeologist" }; + local idx = math.random(#mon); + for i = 1, d(5,5) do + if (percent(10)) then idx = math.random(#mon); end + des.object({ id = "corpse", montype = mon[idx] }); + end + end, + }, + + { + name = "Statuary", + contents = function(rm) + for i = 1, d(5,5) do + des.object({ id = "statue" }); + end + for i = 1, d(3) do + des.trap("statue"); + end + end, + }, + + + { + name = "Light source", eligible = function(rm) return rm.lit == false; end, contents = function(rm) des.object({ id = "oil lamp", lit = true }); end }, - -- Temple of the gods - function(rm) - des.altar({ align = align[1] }); - des.altar({ align = align[2] }); - des.altar({ align = align[3] }); - end, + { + name = "Temple of the gods", + contents = function(rm) + des.altar({ align = align[1] }); + des.altar({ align = align[2] }); + des.altar({ align = align[3] }); + end, + }, - -- Ghost of an Adventurer - function(rm) - local loc = selection.room():rndcoord(0); - des.monster({ id = "ghost", asleep = true, waiting = true, coord = loc }); - if percent(65) then - des.object({ id = "dagger", coord = loc, buc = "not-blessed" }); - end - if percent(55) then - des.object({ class = ")", coord = loc, buc = "not-blessed" }); - end - if percent(45) then - des.object({ id = "bow", coord = loc, buc = "not-blessed" }); - des.object({ id = "arrow", coord = loc, buc = "not-blessed" }); - end - if percent(65) then - des.object({ class = "[", coord = loc, buc = "not-blessed" }); - end - if percent(20) then - des.object({ class = "=", coord = loc, buc = "not-blessed" }); - end - if percent(20) then - des.object({ class = "?", coord = loc, buc = "not-blessed" }); - end - end, - - -- Storeroom - function(rm) - local locs = selection.room():percentage(30); - local func = function(x,y) - if (percent(25)) then - des.object("chest"); - else - des.monster({ class = "m", appear_as = "obj:chest" }); + { + name = "Ghost of an Adventurer", + contents = function(rm) + local loc = selection.room():rndcoord(0); + des.monster({ id = "ghost", asleep = true, waiting = true, coord = loc }); + if percent(65) then + des.object({ id = "dagger", coord = loc, buc = "not-blessed" }); end - end; - locs:iterate(func); - end, - - -- Teleportation hub - function(rm) - local locs = selection.room():filter_mapchar("."); - for i = 1, 2 + nh.rn2(3) do - local pos = locs:rndcoord(1); - if (pos.x > 0) then - pos.x = pos.x + rm.region.x1 - 1; - pos.y = pos.y + rm.region.y1; - table.insert(postprocess, { handler = make_a_trap, data = { type = "teleport", seen = true, coord = pos, teledest = 1 } }); + if percent(55) then + des.object({ class = ")", coord = loc, buc = "not-blessed" }); end - end - end, + if percent(45) then + des.object({ id = "bow", coord = loc, buc = "not-blessed" }); + des.object({ id = "arrow", coord = loc, buc = "not-blessed" }); + end + if percent(65) then + des.object({ class = "[", coord = loc, buc = "not-blessed" }); + end + if percent(20) then + des.object({ class = "=", coord = loc, buc = "not-blessed" }); + end + if percent(20) then + des.object({ class = "?", coord = loc, buc = "not-blessed" }); + end + end, + }, + + { + name = "Storeroom", + contents = function(rm) + local locs = selection.room():percentage(30); + local func = function(x,y) + if (percent(25)) then + des.object("chest"); + else + des.monster({ class = "m", appear_as = "obj:chest" }); + end + end; + locs:iterate(func); + end, + }, + + { + name = "Teleportation hub", + contents = function(rm) + local locs = selection.room():filter_mapchar("."); + for i = 1, 2 + nh.rn2(3) do + local pos = locs:rndcoord(1); + if (pos.x > 0) then + pos.x = pos.x + rm.region.x1 - 1; + pos.y = pos.y + rm.region.y1; + table.insert(postprocess, { handler = make_a_trap, data = { type = "teleport", seen = true, coord = pos, teledest = 1 } }); + end + end + end, + }, }; themerooms = { { - -- the "default" room + name = "default", frequency = 1000, contents = function() des.room({ type = "ordinary", filled = 1 }); end }, - -- Fake Delphi - function() - des.room({ type = "ordinary", w = 11,h = 9, filled = 1, - contents = function() - des.room({ type = "ordinary", x = 4,y = 3, w = 3,h = 3, filled = 1, - contents = function() - des.door({ state="random", wall="all" }); - end - }); - end - }); - end, - - -- Room in a room - function() - des.room({ type = "ordinary", filled = 1, - contents = function() - des.room({ type = "ordinary", - contents = function() - des.door({ state="random", wall="all" }); - end - }); - end - }); - end, - - -- Huge room, with another room inside (90%) - function() - des.room({ type = "ordinary", w = nh.rn2(10)+11,h = nh.rn2(5)+8, filled = 1, - contents = function() - if (percent(90)) then - des.room({ type = "ordinary", filled = 1, - contents = function() - des.door({ state="random", wall="all" }); - if (percent(50)) then - des.door({ state="random", wall="all" }); - end - end - }); - end - end - }); - end, - - -- Nesting rooms - function() - des.room({ type = "ordinary", w = 9 + nh.rn2(4), h = 9 + nh.rn2(4), filled = 1, - contents = function(rm) - local wid = math.random(math.floor(rm.width / 2), rm.width - 2); - local hei = math.random(math.floor(rm.height / 2), rm.height - 2); - des.room({ type = "ordinary", w = wid,h = hei, filled = 1, - contents = function() - if (percent(90)) then - des.room({ type = "ordinary", filled = 1, - contents = function() - des.door({ state="random", wall="all" }); - if (percent(15)) then - des.door({ state="random", wall="all" }); - end - end - }); - end - des.door({ state="random", wall="all" }); - if (percent(15)) then - des.door({ state="random", wall="all" }); - end - end - }); - end - }); - end, + { + name = "Fake Delphi", + contents = function() + des.room({ type = "ordinary", w = 11,h = 9, filled = 1, + contents = function() + des.room({ type = "ordinary", x = 4,y = 3, w = 3,h = 3, filled = 1, + contents = function() + des.door({ state="random", wall="all" }); + end + }); + end + }); + end, + }, { + name = "Room in a room", + contents = function() + des.room({ type = "ordinary", filled = 1, + contents = function() + des.room({ type = "ordinary", + contents = function() + des.door({ state="random", wall="all" }); + end + }); + end + }); + end, + }, + + { + name = "Huge room with another room inside", + contents = function() + des.room({ type = "ordinary", w = nh.rn2(10)+11,h = nh.rn2(5)+8, filled = 1, + contents = function() + if (percent(90)) then + des.room({ type = "ordinary", filled = 1, + contents = function() + des.door({ state="random", wall="all" }); + if (percent(50)) then + des.door({ state="random", wall="all" }); + end + end + }); + end + end + }); + end, + }, + + { + name = "Nesting rooms", + contents = function() + des.room({ type = "ordinary", w = 9 + nh.rn2(4), h = 9 + nh.rn2(4), filled = 1, + contents = function(rm) + local wid = math.random(math.floor(rm.width / 2), rm.width - 2); + local hei = math.random(math.floor(rm.height / 2), rm.height - 2); + des.room({ type = "ordinary", w = wid,h = hei, filled = 1, + contents = function() + if (percent(90)) then + des.room({ type = "ordinary", filled = 1, + contents = function() + des.door({ state="random", wall="all" }); + if (percent(15)) then + des.door({ state="random", wall="all" }); + end + end + }); + end + des.door({ state="random", wall="all" }); + if (percent(15)) then + des.door({ state="random", wall="all" }); + end + end + }); + end + }); + end, + }, + + { + name = "Default room with themed fill", frequency = 6, contents = function() des.room({ type = "themed", contents = themeroom_fill }); @@ -324,6 +371,7 @@ themerooms = { }, { + name = "Unlit room with themed fill", frequency = 2, contents = function() des.room({ type = "themed", lit = 0, contents = themeroom_fill }); @@ -331,71 +379,79 @@ themerooms = { }, { + name = "Room with both normal contents and themed fill", frequency = 2, contents = function() des.room({ type = "themed", filled = 1, contents = themeroom_fill }); end }, - -- Pillars - function() - des.room({ type = "themed", w = 10, h = 10, - contents = function(rm) - local terr = { "-", "-", "-", "-", "L", "P", "T" }; - shuffle(terr); - for x = 0, (rm.width / 4) - 1 do - for y = 0, (rm.height / 4) - 1 do - des.terrain({ x = x * 4 + 2, y = y * 4 + 2, typ = terr[1], lit = -2 }); - des.terrain({ x = x * 4 + 3, y = y * 4 + 2, typ = terr[1], lit = -2 }); - des.terrain({ x = x * 4 + 2, y = y * 4 + 3, typ = terr[1], lit = -2 }); - des.terrain({ x = x * 4 + 3, y = y * 4 + 3, typ = terr[1], lit = -2 }); - end - end - end - }); - end, + { + name = 'Pillars', + contents = function() + des.room({ type = "themed", w = 10, h = 10, + contents = function(rm) + local terr = { "-", "-", "-", "-", "L", "P", "T" }; + shuffle(terr); + for x = 0, (rm.width / 4) - 1 do + for y = 0, (rm.height / 4) - 1 do + des.terrain({ x = x * 4 + 2, y = y * 4 + 2, typ = terr[1], lit = -2 }); + des.terrain({ x = x * 4 + 3, y = y * 4 + 2, typ = terr[1], lit = -2 }); + des.terrain({ x = x * 4 + 2, y = y * 4 + 3, typ = terr[1], lit = -2 }); + des.terrain({ x = x * 4 + 3, y = y * 4 + 3, typ = terr[1], lit = -2 }); + end + end + end + }); + end, + }, - -- Mausoleum - function() - des.room({ type = "themed", w = 5 + nh.rn2(3)*2, h = 5 + nh.rn2(3)*2, - contents = function(rm) - des.room({ type = "themed", - x = (rm.width - 1) / 2, y = (rm.height - 1) / 2, - w = 1, h = 1, joined = false, - contents = function() - if (percent(50)) then - local mons = { "M", "V", "L", "Z" }; - shuffle(mons); - des.monster({ class = mons[1], x=0,y=0, waiting = 1 }); - else - des.object({ id = "corpse", montype = "@", coord = {0,0} }); - end - if (percent(20)) then - des.door({ state="secret", wall="all" }); - end - end - }); - end - }); - end, + { + name = 'Mausoleum', + contents = function() + des.room({ type = "themed", w = 5 + nh.rn2(3)*2, h = 5 + nh.rn2(3)*2, + contents = function(rm) + des.room({ type = "themed", + x = (rm.width - 1) / 2, y = (rm.height - 1) / 2, + w = 1, h = 1, joined = false, + contents = function() + if (percent(50)) then + local mons = { "M", "V", "L", "Z" }; + shuffle(mons); + des.monster({ class = mons[1], x=0,y=0, waiting = 1 }); + else + des.object({ id = "corpse", montype = "@", coord = {0,0} }); + end + if (percent(20)) then + des.door({ state="secret", wall="all" }); + end + end + }); + end + }); + end, + }, - -- Random dungeon feature in the middle of an odd-sized room - function() - local wid = 3 + (nh.rn2(3) * 2); - local hei = 3 + (nh.rn2(3) * 2); - des.room({ type = "ordinary", filled = 1, w = wid, h = hei, - contents = function(rm) - local feature = { "C", "L", "I", "P", "T" }; - shuffle(feature); - des.terrain((rm.width - 1) / 2, (rm.height - 1) / 2, - feature[1]); - end - }); - end, + { + name = 'Random dungeon feature in the middle of an odd-sized room', + contents = function() + local wid = 3 + (nh.rn2(3) * 2); + local hei = 3 + (nh.rn2(3) * 2); + des.room({ type = "ordinary", filled = 1, w = wid, h = hei, + contents = function(rm) + local feature = { "C", "L", "I", "P", "T" }; + shuffle(feature); + des.terrain((rm.width - 1) / 2, (rm.height - 1) / 2, + feature[1]); + end + }); + end, + }, - -- L-shaped - function() - des.map({ map = [[ + { + name = 'L-shaped', + contents = function() + des.map({ map = [[ -----xxx |...|xxx |...|xxx @@ -404,11 +460,13 @@ themerooms = { |......| |......| --------]], contents = function(m) filler_region(1,1); end }); - end, + end, + }, - -- L-shaped, rot 1 - function() - des.map({ map = [[ + { + name = 'L-shaped, rot 1', + contents = function() + des.map({ map = [[ xxx----- xxx|...| xxx|...| @@ -417,11 +475,13 @@ xxx|...| |......| |......| --------]], contents = function(m) filler_region(5,1); end }); - end, + end, + }, - -- L-shaped, rot 2 - function() - des.map({ map = [[ + { + name = 'L-shaped, rot 2', + contents = function() + des.map({ map = [[ -------- |......| |......| @@ -430,11 +490,13 @@ xxx|...| xxx|...| xxx|...| xxx-----]], contents = function(m) filler_region(1,1); end }); - end, + end, + }, - -- L-shaped, rot 3 - function() - des.map({ map = [[ + { + name = 'L-shaped, rot 3', + contents = function() + des.map({ map = [[ -------- |......| |......| @@ -443,11 +505,13 @@ xxx-----]], contents = function(m) filler_region(1,1); end }); |...|xxx |...|xxx -----xxx]], contents = function(m) filler_region(1,1); end }); - end, + end, + }, - -- Blocked center - function() - des.map({ map = [[ + { + name = 'Blocked center', + contents = function() + des.map({ map = [[ ----------- |.........| |.........| @@ -459,18 +523,20 @@ xxx-----]], contents = function(m) filler_region(1,1); end }); |.........| |.........| -----------]], contents = function(m) -if (percent(30)) then - local terr = { "-", "P" }; - shuffle(terr); - des.replace_terrain({ region = {1,1, 9,9}, fromterrain = "L", toterrain = terr[1] }); -end -filler_region(1,1); -end }); - end, + if (percent(30)) then + local terr = { "-", "P" }; + shuffle(terr); + des.replace_terrain({ region = {1,1, 9,9}, fromterrain = "L", toterrain = terr[1] }); + end + filler_region(1,1); + end }); + end, + }, - -- Circular, small - function() - des.map({ map = [[ + { + name = 'Circular, small', + contents = function() + des.map({ map = [[ xx---xx x--.--x --...-- @@ -478,11 +544,13 @@ x--.--x --...-- x--.--x xx---xx]], contents = function(m) filler_region(3,3); end }); - end, + end, + }, - -- Circular, medium - function() - des.map({ map = [[ + { + name = 'Circular, medium', + contents = function() + des.map({ map = [[ xx-----xx x--...--x --.....-- @@ -492,11 +560,13 @@ x--...--x --.....-- x--...--x xx-----xx]], contents = function(m) filler_region(4,4); end }); - end, + end, + }, - -- Circular, big - function() - des.map({ map = [[ + { + name = 'Circular, big', + contents = function() + des.map({ map = [[ xxx-----xxx x---...---x x-.......-x @@ -508,11 +578,13 @@ x-.......-x x-.......-x x---...---x xxx-----xxx]], contents = function(m) filler_region(5,5); end }); - end, + end, + }, - -- T-shaped - function() - des.map({ map = [[ + { + name = 'T-shaped', + contents = function() + des.map({ map = [[ xxx-----xxx xxx|...|xxx xxx|...|xxx @@ -521,11 +593,13 @@ xxx|...|xxx |.........| |.........| -----------]], contents = function(m) filler_region(5,5); end }); - end, + end, + }, - -- T-shaped, rot 1 - function() - des.map({ map = [[ + { + name = 'T-shaped, rot 1', + contents = function() + des.map({ map = [[ -----xxx |...|xxx |...|xxx @@ -537,11 +611,13 @@ xxx|...|xxx |...|xxx |...|xxx -----xxx]], contents = function(m) filler_region(2,2); end }); - end, + end, + }, - -- T-shaped, rot 2 - function() - des.map({ map = [[ + { + name = 'T-shaped, rot 2', + contents = function() + des.map({ map = [[ ----------- |.........| |.........| @@ -550,11 +626,13 @@ xxx|...|xxx xxx|...|xxx xxx|...|xxx xxx-----xxx]], contents = function(m) filler_region(2,2); end }); - end, + end, + }, - -- T-shaped, rot 3 - function() - des.map({ map = [[ + { + name = 'T-shaped, rot 3', + contents = function() + des.map({ map = [[ xxx----- xxx|...| xxx|...| @@ -566,11 +644,13 @@ xxx|...| xxx|...| xxx|...| xxx-----]], contents = function(m) filler_region(5,5); end }); - end, + end, + }, - -- S-shaped - function() - des.map({ map = [[ + { + name = 'S-shaped', + contents = function() + des.map({ map = [[ -----xxx |...|xxx |...|xxx @@ -582,11 +662,13 @@ xxx-----]], contents = function(m) filler_region(5,5); end }); xxx|...| xxx|...| xxx-----]], contents = function(m) filler_region(2,2); end }); - end, + end, + }, - -- S-shaped, rot 1 - function() - des.map({ map = [[ + { + name = 'S-shaped, rot 1', + contents = function() + des.map({ map = [[ xxx-------- xxx|......| xxx|......| @@ -595,11 +677,13 @@ xxx|......| |......|xxx |......|xxx --------xxx]], contents = function(m) filler_region(5,5); end }); - end, + end, + }, - -- Z-shaped - function() - des.map({ map = [[ + { + name = 'Z-shaped', + contents = function() + des.map({ map = [[ xxx----- xxx|...| xxx|...| @@ -611,11 +695,13 @@ xxx|...| |...|xxx |...|xxx -----xxx]], contents = function(m) filler_region(5,5); end }); - end, + end, + }, - -- Z-shaped, rot 1 - function() - des.map({ map = [[ + { + name = 'Z-shaped, rot 1', + contents = function() + des.map({ map = [[ --------xxx |......|xxx |......|xxx @@ -624,11 +710,13 @@ xxx|...| xxx|......| xxx|......| xxx--------]], contents = function(m) filler_region(2,2); end }); - end, + end, + }, - -- Cross - function() - des.map({ map = [[ + { + name = 'Cross', + contents = function() + des.map({ map = [[ xxx-----xxx xxx|...|xxx xxx|...|xxx @@ -640,11 +728,13 @@ xxx|...|xxx xxx|...|xxx xxx|...|xxx xxx-----xxx]], contents = function(m) filler_region(6,6); end }); - end, + end, + }, - -- Four-leaf clover - function() - des.map({ map = [[ + { + name = 'Four-leaf clover', + contents = function() + des.map({ map = [[ -----x----- |...|x|...| |...---...| @@ -656,59 +746,63 @@ xx|.....|xx |...---...| |...|x|...| -----x-----]], contents = function(m) filler_region(6,6); end }); - end, + end, + }, - -- Water-surrounded vault - function() - des.map({ map = [[ + { + name = 'Water-surrounded vault', + contents = function() + des.map({ map = [[ }}}}}} }----} }|..|} }|..|} }----} }}}}}}]], contents = function(m) des.region({ region={3,3,3,3}, type="themed", irregular=true, filled=0, joined=false }); - local nasty_undead = { "giant zombie", "ettin zombie", "vampire lord" }; - local chest_spots = { { 2, 2 }, { 3, 2 }, { 2, 3 }, { 3, 3 } }; + local nasty_undead = { "giant zombie", "ettin zombie", "vampire lord" }; + local chest_spots = { { 2, 2 }, { 3, 2 }, { 2, 3 }, { 3, 3 } }; - shuffle(chest_spots) - -- Guarantee an escape item inside one of the chests, to prevent the hero - -- falling in from above and becoming permanently stuck - -- [cf. generate_way_out_method(sp_lev.c)]. - -- If the escape item is made of glass or crystal, make sure that the - -- chest isn't locked so that kicking it to gain access to its contents - -- won't be necessary; otherwise retain lock state from random creation. - -- "pick-axe", "dwarvish mattock" could be included in the list of escape - -- items but don't normally generate in containers. - local escape_items = { - "scroll of teleportation", "ring of teleportation", - "wand of teleportation", "wand of digging" - }; - local itm = obj.new(escape_items[math.random(#escape_items)]); - local itmcls = itm:class() - local box - if itmcls[ "material" ] == "glass" then - -- explicitly force chest to be unlocked - box = des.object({ id = "chest", coord = chest_spots[1], - olocked = "no" }); - else - -- accept random locked/unlocked state - box = des.object({ id = "chest", coord = chest_spots[1] }); - end; - box:addcontent(itm); + shuffle(chest_spots) + -- Guarantee an escape item inside one of the chests, to prevent the + -- hero falling in from above and becoming permanently stuck + -- [cf. generate_way_out_method(sp_lev.c)]. + -- If the escape item is made of glass or crystal, make sure that + -- the chest isn't locked so that kicking it to gain access to its + -- contents won't be necessary; otherwise retain lock state from + -- random creation. + -- "pick-axe", "dwarvish mattock" could be included in the list of + -- escape items but don't normally generate in containers. + local escape_items = { + "scroll of teleportation", "ring of teleportation", + "wand of teleportation", "wand of digging" + }; + local itm = obj.new(escape_items[math.random(#escape_items)]); + local itmcls = itm:class() + local box + if itmcls[ "material" ] == "glass" then + -- explicitly force chest to be unlocked + box = des.object({ id = "chest", coord = chest_spots[1], + olocked = "no" }); + else + -- accept random locked/unlocked state + box = des.object({ id = "chest", coord = chest_spots[1] }); + end; + box:addcontent(itm); - for i = 2, #chest_spots do - des.object({ id = "chest", coord = chest_spots[i] }); - end + for i = 2, #chest_spots do + des.object({ id = "chest", coord = chest_spots[i] }); + end - shuffle(nasty_undead); - des.monster(nasty_undead[1], 2, 2); - des.exclusion({ type = "teleport", region = { 2,2, 3,3 } }); -end }); - end, + shuffle(nasty_undead); + des.monster(nasty_undead[1], 2, 2); + des.exclusion({ type = "teleport", region = { 2,2, 3,3 } }); + end }); + end, + }, - -- Twin businesses { - mindiff = 4; -- arbitrary + name = 'Twin businesses', + mindiff = 4, -- arbitrary contents = function() -- Due to the way room connections work in mklev.c, we must guarantee -- that the "aisle" between the shops touches all four walls of the @@ -761,7 +855,14 @@ end }); }; +-- store these at global scope, they will be reinitialized in +-- pre_themerooms_generate +debug_rm_idx = nil +debug_fill_idx = nil +-- Given a point in a themed room, ensure that themed room is stocked with +-- regular room contents. +-- With 30% chance, also give it a random themed fill. function filler_region(x, y) local rmtyp = "ordinary"; local func = nil; @@ -775,31 +876,76 @@ end function is_eligible(room, mkrm) local t = type(room); local diff = nh.level_difficulty(); - if (t == "table") then - if (room.mindiff ~= nil and diff < room.mindiff) then - return false - elseif (room.maxdiff ~= nil and diff > room.maxdiff) then - return false - end - if (mkrm ~= nil and room.eligible ~= nil) then - return room.eligible(mkrm); - end - elseif (t == "function") then - -- functions currently have no constraints + if (room.mindiff ~= nil and diff < room.mindiff) then + return false + elseif (room.maxdiff ~= nil and diff > room.maxdiff) then + return false + end + if (mkrm ~= nil and room.eligible ~= nil) then + return room.eligible(mkrm); end return true end +-- given the name of a themed room or fill, return its index in that array +function lookup_by_name(name, checkfills) + if name == nil then + return nil + end + if checkfills then + for i = 1, #themeroom_fills do + if themeroom_fills[i].name == name then + return i + end + end + else + for i = 1, #themerooms do + if themerooms[i].name == name then + return i + end + end + end + return nil +end + -- called repeatedly until the core decides there are enough rooms function themerooms_generate() + if debug_rm_idx ~= nil then + -- room may not be suitable for stairs/portals, so create the "default" + -- room half of the time + -- (if the user specified BOTH a room and a fill, presumably they are + -- interested in what happens when that room gets that fill, so don't + -- bother generating default-with-fill rooms as happens below) + local actualrm = lookup_by_name("default", false); + if percent(50) then + if is_eligible(themerooms[debug_rm_idx]) then + actualrm = debug_rm_idx + else + pline("Warning: themeroom '"..themerooms[debug_rm_idx].name + .."' is ineligible") + end + end + themerooms[actualrm].contents(); + return + elseif debug_fill_idx ~= nil then + -- when a fill is requested but not a room, still create the "default" + -- room half of the time, and "default with themed fill" half of the time + -- (themeroom_fill will take care of guaranteeing the fill in it) + local actualrm = lookup_by_name(percent(50) and "Default room with themed fill" + or "default") + themerooms[actualrm].contents(); + return + end local pick = 1; local total_frequency = 0; for i = 1, #themerooms do - -- Reservoir sampling: select one room from the set of eligible rooms, - -- which may change on different levels because of level difficulty. - if is_eligible(themerooms[i], nil) then + if (type(themerooms[i]) ~= "table") then + nh.impossible('themed room '..i..' is not a table') + elseif is_eligible(themerooms[i], nil) then + -- Reservoir sampling: select one room from the set of eligible rooms, + -- which may change on different levels because of level difficulty. local this_frequency; - if (type(themerooms[i]) == "table" and themerooms[i].frequency ~= nil) then + if (themerooms[i].frequency ~= nil) then this_frequency = themerooms[i].frequency; else this_frequency = 1; @@ -811,17 +957,23 @@ function themerooms_generate() end end end - - local t = type(themerooms[pick]); - if (t == "table") then - themerooms[pick].contents(); - elseif (t == "function") then - themerooms[pick](); - end + themerooms[pick].contents(); end -- called before any rooms are generated function pre_themerooms_generate() + local debug_themerm = nh.debug_themerm(false) + local debug_fill = nh.debug_themerm(true) + debug_rm_idx = lookup_by_name(debug_themerm, false) + debug_fill_idx = lookup_by_name(debug_fill, true) + if debug_themerm ~= nil and debug_rm_idx == nil then + pline("Warning: themeroom '"..debug_themerm + .."' not found in themerooms", true) + end + if debug_fill ~= nil and debug_fill_idx == nil then + pline("Warning: themeroom fill '"..debug_fill + .."' not found in themeroom_fills", true) + end end -- called after all rooms have been generated @@ -830,32 +982,41 @@ function post_themerooms_generate() end function themeroom_fill(rm) + if debug_fill_idx ~= nil then + if is_eligible(themeroom_fills[debug_fill_idx], rm) then + themeroom_fills[debug_fill_idx].contents(rm); + else + -- ideally this would be a debugpline, not a full pline, and offer + -- some more context on whether it failed because of difficulty or + -- because of eligible function returning false; the warning doesn't + -- necessarily mean anything. + pline("Warning: fill '"..themeroom_fills[debug_fill_idx].name + .."' is not eligible in room that generated it") + end + return + end local pick = 1; local total_frequency = 0; for i = 1, #themeroom_fills do - -- Reservoir sampling: select one room from the set of eligible rooms, - -- which may change on different levels because of level difficulty. - if is_eligible(themeroom_fills[i], rm) then + if (type(themeroom_fills[i]) ~= "table") then + nh.impossible('themeroom fill '..i..' must be a table') + elseif is_eligible(themeroom_fills[i], rm) then + -- Reservoir sampling: select one room from the set of eligible rooms, + -- which may change on different levels because of level difficulty. local this_frequency; - if (type(themeroom_fills[i]) == "table" and themeroom_fills[i].frequency ~= nil) then + if (themeroom_fills[i].frequency ~= nil) then this_frequency = themeroom_fills[i].frequency; else this_frequency = 1; end total_frequency = total_frequency + this_frequency; - -- avoid rn2(0) if a room has freq 0 + -- avoid rn2(0) if a fill has freq 0 if this_frequency > 0 and nh.rn2(total_frequency) < this_frequency then pick = i; end end end - - local t = type(themeroom_fills[pick]); - if (t == "table") then - themeroom_fills[pick].contents(rm); - elseif (t == "function") then - themeroom_fills[pick](rm); - end + themeroom_fills[pick].contents(rm); end -- postprocess callback: create an engraving pointing at a location diff --git a/src/nhlua.c b/src/nhlua.c index 6342f949c..10c67494a 100644 --- a/src/nhlua.c +++ b/src/nhlua.c @@ -65,6 +65,7 @@ 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 int nhl_get_debug_themerm_name(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 *); @@ -975,6 +976,30 @@ nhl_is_genocided(lua_State *L) return 1; } +/* local debug_themerm = nh.debug_themerm(isfill) + * if isfill is false, returns value of env variable THEMERM + * if isfill is true, returns value of env variable THEMERMFILL + * return nil if not in wizard mode or the variable isn't set */ +staticfn int +nhl_get_debug_themerm_name(lua_State *L) +{ + int argc = lua_gettop(L); + if (argc == 1) { + char *dbg_themerm = (char *) 0; + boolean is_fill = lua_toboolean(L, 1); + lua_pop(L, 1); + if (wizard) + dbg_themerm = getenv(is_fill ? "THEMERMFILL" : "THEMERM"); + if (!dbg_themerm || strlen(dbg_themerm) == 0) { + lua_pushnil(L); + } else { + lua_pushstring(L, dbg_themerm); + } + } else { + nhl_error(L, "debug_themerm should have 1 boolean arg"); + } + return 1; +} RESTORE_WARNING_UNREACHABLE_CODE @@ -1754,6 +1779,7 @@ static const struct luaL_Reg nhl_functions[] = { { "random", nhl_random }, { "level_difficulty", nhl_level_difficulty }, { "is_genocided", nhl_is_genocided }, + { "debug_themerm", nhl_get_debug_themerm_name }, { "parse_config", nhl_parse_config }, { "get_config", nhl_get_config }, { "get_config_errors", l_get_config_errors }, From 3427c43df26c1588b4e85dcf5fc89e56251c6616 Mon Sep 17 00:00:00 2001 From: copperwater Date: Sun, 23 Feb 2025 16:29:40 -0500 Subject: [PATCH 544/791] Guard against no themed rooms or fills being eligible to generate The themed room code previously assumed that on any given level, at least one room or fill would resolve as OK to generate there. However, that's not a great assumption to make, and if it happened to be broken, the first themed room or fill would arbitrarily be executed, even though it wasn't eligible. Fix that by setting the initial pick to nil, and raising an impossible if it's still nil after trying to choose a random room. --- dat/themerms.lua | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/dat/themerms.lua b/dat/themerms.lua index b7e0f1f0a..64c1b316e 100644 --- a/dat/themerms.lua +++ b/dat/themerms.lua @@ -936,7 +936,7 @@ function themerooms_generate() themerooms[actualrm].contents(); return end - local pick = 1; + local pick = nil; local total_frequency = 0; for i = 1, #themerooms do if (type(themerooms[i]) ~= "table") then @@ -957,6 +957,10 @@ function themerooms_generate() end end end + if pick == nil then + nh.impossible('no eligible themed rooms?') + return + end themerooms[pick].contents(); end @@ -995,7 +999,7 @@ function themeroom_fill(rm) end return end - local pick = 1; + local pick = nil; local total_frequency = 0; for i = 1, #themeroom_fills do if (type(themeroom_fills[i]) ~= "table") then @@ -1016,6 +1020,10 @@ function themeroom_fill(rm) end end end + if pick == nil then + nh.impossible('no eligible themed room fills?') + return + end themeroom_fills[pick].contents(rm); end From 1fd27044b7dc90e1f3becf2f8a5eec1dfaac58c4 Mon Sep 17 00:00:00 2001 From: PatR Date: Fri, 11 Apr 2025 16:29:08 -0700 Subject: [PATCH 545/791] github PR #1384 - THEMERM and ThEMERMFILL Pull request from copperwater: reorganize the theme rooms data so that a room or a fill can be chosen by name, and when in wizard mode, consult environment variables THEMERM and THEMERMFILL during level creation to provide control over which theme rooms/room fills to generate. I reverted a commit that did a bunch of reformatting to themerms.lua because to caused substantial merge conflicts. I will redo at least part of it. Closes #1384 --- doc/fixes3-7-0.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index b7d83fd89..bc3d300a5 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -2549,6 +2549,8 @@ item-using monsters will zap wand of undead turning at corpse-wielding hero when the corpse is harmful boiling a pool or fountain now creates a temporary cloud of steam random themed rooms in the dungeons of doom +environment variables THEMERM and THEMERMFILL can be used in wizard mode to + provide some control over theme room generation extended achievement and conduct fields for xlogfile record amount of gold in hero's possession in xlogfile new objects: amulets of flying and guarding, helm of caution, From 48d1b8617e8c1aa6a7aa992a9c212f41fe0ab446 Mon Sep 17 00:00:00 2001 From: PatR Date: Fri, 11 Apr 2025 17:07:55 -0700 Subject: [PATCH 546/791] themerms.lua formatting Do some reformatting of dat/themerms.lua. I didn't try to reproduce the changes that were in the reverted commit, and didn't slow through to the end. --- dat/themerms.lua | 138 ++++++++++++++++++++++++++--------------------- 1 file changed, 76 insertions(+), 62 deletions(-) diff --git a/dat/themerms.lua b/dat/themerms.lua index 64c1b316e..c7ef49147 100644 --- a/dat/themerms.lua +++ b/dat/themerms.lua @@ -1,26 +1,27 @@ --- NetHack themerms.lua $NHDT-Date: 1652196294 2022/05/10 15:24:54 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.16 $ +-- NetHack themerms.lua $NHDT-Date: 1744445274 2025/04/12 00:07:54 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.40 $ -- Copyright (c) 2020 by Pasi Kallinen -- NetHack may be freely redistributed. See license for details. -- -- themerooms is an array of tables. -- the tables define "name", "frequency", "contents", "mindiff" and "maxdiff". --- * "name" is not shown in-game; it is so that developers can specify a certain --- room to generate by using the THEMERM or THEMERMFILL environment variable. --- While technically optional, it should be provided on all the rooms; if it --- isn't, the room can't be directly specified. +-- * "name" is not shown in-game; it is so that developers can specify a +-- certain room to generate by using the THEMERM or THEMERMFILL environment +-- variable. While technically optional, it should be provided on all the +-- rooms; if it isn't, the room can't be directly specified. -- * "frequency" is optional; if omitted, 1 is assumed. -- * "contents" is a function describing what gets put into the room. --- * "mindiff" and "maxdiff" are optional and independent; if omitted, the room --- is not constrained by level difficulty. +-- * "mindiff" and "maxdiff" are optional and independent; if omitted, the +-- room is not constrained by level difficulty. +-- * "eligible" is optional; if omitted, True is assumed. -- -- themeroom_fills is an array of tables with the exact same structure as -- themerooms. It is used for contents of a room that are independent of its -- shape, so that interestingly-shaped themerooms can be filled with a variety -- of contents. --- * The "contents" functions in themeroom_fills take the room they are filling as --- an argument. --- * Frequency of themeroom_fills is a separate pool from themerooms, and has no --- effect on how likely it is that any given room will receive a themeroom_fill. +-- * The "contents" functions in themeroom_fills take the room they are +-- filling as an argument. +-- * Frequency of themeroom_fills is a separate pool from themerooms, and has +-- no effect on how likely that any given room will receive a themeroom_fill. -- -- des.room({ type = "ordinary", filled = 1 }) -- - ordinary rooms can be converted to shops or any other special rooms. @@ -124,7 +125,8 @@ themeroom_fills = { des.feature("fountain"); end end - table.insert(postprocess, { handler = make_garden_walls, data = { sel = selection.room() } }); + table.insert(postprocess, { handler = make_garden_walls, + data = { sel = selection.room() } }); end }, @@ -135,7 +137,8 @@ themeroom_fills = { local xobj = otmp:totable(); -- keep track of the last buried treasure if (xobj.NO_OBJ == nil) then - table.insert(postprocess, { handler = make_dig_engraving, data = { x = xobj.ox, y = xobj.oy }}); + table.insert(postprocess, { handler = make_dig_engraving, + data = { x = xobj.ox, y = xobj.oy }}); end for i = 1, d(3,4) do des.object(); @@ -219,7 +222,8 @@ themeroom_fills = { name = "Ghost of an Adventurer", contents = function(rm) local loc = selection.room():rndcoord(0); - des.monster({ id = "ghost", asleep = true, waiting = true, coord = loc }); + des.monster({ id = "ghost", asleep = true, waiting = true, + coord = loc }); if percent(65) then des.object({ id = "dagger", coord = loc, buc = "not-blessed" }); end @@ -266,7 +270,9 @@ themeroom_fills = { if (pos.x > 0) then pos.x = pos.x + rm.region.x1 - 1; pos.y = pos.y + rm.region.y1; - table.insert(postprocess, { handler = make_a_trap, data = { type = "teleport", seen = true, coord = pos, teledest = 1 } }); + table.insert(postprocess, { handler = make_a_trap, + data = { type = "teleport", seen = true, + coord = pos, teledest = 1 } }); end end end, @@ -279,7 +285,7 @@ themerooms = { frequency = 1000, contents = function() des.room({ type = "ordinary", filled = 1 }); - end + end }, { @@ -287,10 +293,11 @@ themerooms = { contents = function() des.room({ type = "ordinary", w = 11,h = 9, filled = 1, contents = function() - des.room({ type = "ordinary", x = 4,y = 3, w = 3,h = 3, filled = 1, - contents = function() - des.door({ state="random", wall="all" }); - end + des.room({ type = "ordinary", x = 4,y = 3, w = 3,h = 3, + filled = 1, + contents = function() + des.door({ state="random", wall="all" }); + end }); end }); @@ -303,9 +310,9 @@ themerooms = { des.room({ type = "ordinary", filled = 1, contents = function() des.room({ type = "ordinary", - contents = function() - des.door({ state="random", wall="all" }); - end + contents = function() + des.door({ state="random", wall="all" }); + end }); end }); @@ -315,19 +322,20 @@ themerooms = { { name = "Huge room with another room inside", contents = function() - des.room({ type = "ordinary", w = nh.rn2(10)+11,h = nh.rn2(5)+8, filled = 1, - contents = function() - if (percent(90)) then - des.room({ type = "ordinary", filled = 1, - contents = function() - des.door({ state="random", wall="all" }); - if (percent(50)) then - des.door({ state="random", wall="all" }); - end - end - }); - end - end + des.room({ type = "ordinary", w = nh.rn2(10)+11,h = nh.rn2(5)+8, + filled = 1, + contents = function() + if (percent(90)) then + des.room({ type = "ordinary", filled = 1, + contents = function() + des.door({ state="random", wall="all" }); + if (percent(50)) then + des.door({ state="random", wall="all" }); + end + end + }); + end + end }); end, }, @@ -335,29 +343,31 @@ themerooms = { { name = "Nesting rooms", contents = function() - des.room({ type = "ordinary", w = 9 + nh.rn2(4), h = 9 + nh.rn2(4), filled = 1, - contents = function(rm) - local wid = math.random(math.floor(rm.width / 2), rm.width - 2); - local hei = math.random(math.floor(rm.height / 2), rm.height - 2); - des.room({ type = "ordinary", w = wid,h = hei, filled = 1, - contents = function() - if (percent(90)) then - des.room({ type = "ordinary", filled = 1, - contents = function() - des.door({ state="random", wall="all" }); - if (percent(15)) then - des.door({ state="random", wall="all" }); - end - end - }); - end - des.door({ state="random", wall="all" }); - if (percent(15)) then - des.door({ state="random", wall="all" }); - end - end - }); + des.room({ type = "ordinary", w = 9 + nh.rn2(4), h = 9 + nh.rn2(4), + filled = 1, + contents = function(rm) + local wid = math.random(math.floor(rm.width / 2), rm.width - 2); + local hei = math.random(math.floor(rm.height / 2), + rm.height - 2); + des.room({ type = "ordinary", w = wid,h = hei, filled = 1, + contents = function() + if (percent(90)) then + des.room({ type = "ordinary", filled = 1, + contents = function() + des.door({ state="random", wall="all" }); + if (percent(15)) then + des.door({ state="random", wall="all" }); + end + end + }); + end + des.door({ state="random", wall="all" }); + if (percent(15)) then + des.door({ state="random", wall="all" }); + end end + }); + end }); end, }, @@ -526,7 +536,9 @@ xxx-----]], contents = function(m) filler_region(1,1); end }); if (percent(30)) then local terr = { "-", "P" }; shuffle(terr); - des.replace_terrain({ region = {1,1, 9,9}, fromterrain = "L", toterrain = terr[1] }); + des.replace_terrain({ region = {1,1, 9,9}, + fromterrain = "L", + toterrain = terr[1] }); end filler_region(1,1); end }); @@ -758,13 +770,15 @@ xx|.....|xx }|..|} }|..|} }----} -}}}}}}]], contents = function(m) des.region({ region={3,3,3,3}, type="themed", irregular=true, filled=0, joined=false }); +}}}}}}]], contents = function(m) + des.region({ region={3,3,3,3}, type="themed", irregular=true, + filled=0, joined=false }); local nasty_undead = { "giant zombie", "ettin zombie", "vampire lord" }; local chest_spots = { { 2, 2 }, { 3, 2 }, { 2, 3 }, { 3, 3 } }; shuffle(chest_spots) - -- Guarantee an escape item inside one of the chests, to prevent the - -- hero falling in from above and becoming permanently stuck + -- Guarantee an escape item inside one of the chests, to prevent + -- the hero falling in from above and becoming permanently stuck -- [cf. generate_way_out_method(sp_lev.c)]. -- If the escape item is made of glass or crystal, make sure that -- the chest isn't locked so that kicking it to gain access to its From 8f7258dc35a92daaf530e9f5858c95ee114a0c99 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sat, 12 Apr 2025 19:23:20 +0300 Subject: [PATCH 547/791] Buff Grimtooth with poison Grimtooth is now permanently poisoned, protects the wielder from poison, and can be invoked to throw poison. Permapoison code comes from xNetHack by copperwater . --- doc/fixes3-7-0.txt | 1 + include/artifact.h | 1 + include/artilist.h | 7 +++-- include/extern.h | 1 + include/obj.h | 9 +++--- src/artifact.c | 22 +++++++++++++++ src/mkobj.c | 2 ++ src/objnam.c | 3 ++ src/potion.c | 7 +++-- src/uhitm.c | 70 +++++++++++++++++++++++++++++++++++----------- 10 files changed, 96 insertions(+), 27 deletions(-) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index bc3d300a5..0f54d8dde 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -1507,6 +1507,7 @@ since introduction in 3.1.0, the definition for Mitre of Holiness has specified if a tree and a boulder or statue were at the same location, applying an axe would break the boulder or statue rather than chop the tree avoid premapping outside Sokoban map to prevent showing stone glyphs +Grimtooth is permanently poisoned, protects from poison, and can fling poison Fixes to 3.7.0-x General Problems Exposed Via git Repository diff --git a/include/artifact.h b/include/artifact.h index 4199a7feb..efd0a4992 100644 --- a/include/artifact.h +++ b/include/artifact.h @@ -67,6 +67,7 @@ enum invoke_prop_types { ENLIGHTENING, CREATE_AMMO, BANISH, + FLING_POISON, BLINDING_RAY }; diff --git a/include/artilist.h b/include/artilist.h index f3ecf2e72..8d55c6789 100644 --- a/include/artilist.h +++ b/include/artilist.h @@ -43,6 +43,7 @@ static const char *const artifact_names[] = { #define FIRE(a,b) {0,AD_FIRE,a,b} #define ELEC(a,b) {0,AD_ELEC,a,b} /* electrical shock */ #define STUN(a,b) {0,AD_STUN,a,b} /* magical attack */ +#define POIS(a,b) {0,AD_DRST,a,b} /* poison */ /* clang-format on */ static NEARDATA struct artifact artilist[] = { @@ -120,9 +121,9 @@ static NEARDATA struct artifact artilist[] = { * (handled as special case in spec_dbon()). */ A("Grimtooth", ORCISH_DAGGER, (SPFX_RESTR | SPFX_WARN | SPFX_DFLAG2), - 0, M2_ELF, PHYS(2, 6), NO_DFNS, - NO_CARY, 0, A_CHAOTIC, NON_PM, PM_ORC, - 0, 5, 300L, CLR_RED, GRIMTOOTH), + 0, M2_ELF, PHYS(2, 6), POIS(0,0), + NO_CARY, FLING_POISON, A_CHAOTIC, NON_PM, PM_ORC, + 0, 5, 1200L, CLR_RED, GRIMTOOTH), /* * Orcrist and Sting have same alignment as elves. * diff --git a/include/extern.h b/include/extern.h index 2290f9711..f6bfe2e43 100644 --- a/include/extern.h +++ b/include/extern.h @@ -183,6 +183,7 @@ extern void mkot_trap_warn(void); extern boolean is_magic_key(struct monst *, struct obj *); extern struct obj *has_magic_key(struct monst *); extern boolean is_art(struct obj *, int); +extern boolean permapoisoned(struct obj *); /* ### attrib.c ### */ diff --git a/include/obj.h b/include/obj.h index 56a29a358..3b1524b17 100644 --- a/include/obj.h +++ b/include/obj.h @@ -254,10 +254,11 @@ struct obj { (otmp->oclass == WEAPON_CLASS \ && objects[otmp->otyp].oc_skill >= -P_SHURIKEN \ && objects[otmp->otyp].oc_skill <= -P_BOW) -#define is_poisonable(otmp) \ - (otmp->oclass == WEAPON_CLASS \ - && objects[otmp->otyp].oc_skill >= -P_SHURIKEN \ - && objects[otmp->otyp].oc_skill <= -P_BOW) +#define is_poisonable(otmp) \ + ((otmp->oclass == WEAPON_CLASS \ + && objects[otmp->otyp].oc_skill >= -P_SHURIKEN \ + && objects[otmp->otyp].oc_skill <= -P_BOW) \ + || permapoisoned(otmp)) #define uslinging() (uwep && objects[uwep->otyp].oc_skill == P_SLING) /* 'is_quest_artifact()' only applies to the current role's artifact */ #define any_quest_artifact(o) ((o)->oartifact >= ART_ORB_OF_DETECTION) diff --git a/src/artifact.c b/src/artifact.c index 2254b3976..3cb92fac5 100644 --- a/src/artifact.c +++ b/src/artifact.c @@ -283,6 +283,8 @@ mk_artifact( otmp = 0; } /* otherwise, otmp has not changed; just fallthrough to return it */ } + if (permapoisoned(otmp)) + otmp->opoisoned = 1; return otmp; } @@ -2009,6 +2011,19 @@ arti_invoke(struct obj *obj) } break; } + case FLING_POISON: + if (getdir((char *) 0)) { + int venom = rn2(2) ? BLINDING_VENOM : ACID_VENOM; + struct obj *otmp = mksobj(venom, TRUE, FALSE); + + otmp->spe = 1; /* the poison is yours */ + throwit(otmp, 0L, FALSE, (struct obj *) 0); + } else { + /* no direction picked */ + pline("%s", Never_mind); + obj->age = svm.moves; + } + break; case BLINDING_RAY: if (getdir((char *) 0)) { if (u.dx || u.dy) { @@ -2699,4 +2714,11 @@ get_artifact(struct obj *obj) } return &artilist[ART_NONARTIFACT]; } + +/* is object permanently poisoned? (currently only Grimtooth) */ +boolean +permapoisoned(struct obj *obj) +{ + return (obj && is_art(obj, ART_GRIMTOOTH)); +} /*artifact.c*/ diff --git a/src/mkobj.c b/src/mkobj.c index d76e65f1b..4713e9d29 100644 --- a/src/mkobj.c +++ b/src/mkobj.c @@ -1160,6 +1160,8 @@ mksobj_init(struct obj **obj, boolean artif) } mkobj_erosions(otmp); + if (permapoisoned(otmp)) + otmp->opoisoned = 1; } /* mksobj(): create a specific type of object; result is always non-Null */ diff --git a/src/objnam.c b/src/objnam.c index 334e383dd..0816a4fd2 100644 --- a/src/objnam.c +++ b/src/objnam.c @@ -5338,6 +5338,9 @@ readobjnam(char *bp, struct obj *no_wish) } } + if (permapoisoned(d.otmp)) + d.otmp->opoisoned = 1; + /* more wishing abuse: don't allow wishing for certain artifacts */ /* and make them pay; charge them for the wish anyway! */ if ((is_quest_artifact(d.otmp) diff --git a/src/potion.c b/src/potion.c index 86a0545a9..3ff57c360 100644 --- a/src/potion.c +++ b/src/potion.c @@ -2595,9 +2595,10 @@ potion_dip(struct obj *obj, struct obj *potion) obj->opoisoned = TRUE; poof(potion); return ECMD_TIME; - } else if (obj->opoisoned && (potion->otyp == POT_HEALING - || potion->otyp == POT_EXTRA_HEALING - || potion->otyp == POT_FULL_HEALING)) { + } else if (obj->opoisoned && !permapoisoned(obj) + && (potion->otyp == POT_HEALING + || potion->otyp == POT_EXTRA_HEALING + || potion->otyp == POT_FULL_HEALING)) { pline("A coating wears off %s.", the(xname(obj))); obj->opoisoned = 0; poof(potion); diff --git a/src/uhitm.c b/src/uhitm.c index e68f1a60f..581c6287e 100644 --- a/src/uhitm.c +++ b/src/uhitm.c @@ -13,6 +13,8 @@ staticfn boolean mhitm_mgc_atk_negated(struct monst *, struct monst *, staticfn boolean known_hitum(struct monst *, struct obj *, int *, int, int, struct attack *, int) NONNULLARG13; staticfn boolean theft_petrifies(struct obj *) NONNULLARG1; +staticfn void mhitm_really_poison(struct monst *, struct attack *, + struct monst *, struct mhitm_data *); staticfn void steal_it(struct monst *, struct attack *) NONNULLARG1; /* hitum_cleave() has contradictory information. There's a comment * beside the 1st arg 'target' stating non-null, but later on there @@ -1036,6 +1038,9 @@ hmon_hitmon_weapon_melee( if (obj->opoisoned && is_poisonable(obj)) hmd->ispoisoned = TRUE; } + /* permapoisoned is non-ammo/missile, limit the poison */ + if (permapoisoned(obj) && hmd->dieroll <= 5) + hmd->ispoisoned = TRUE; } staticfn void @@ -1484,7 +1489,7 @@ hmon_hitmon_poison( You_feel("like an evil coward for using a poisoned weapon."); adjalign(-1); } - if (!rn2(nopoison)) { + if (!permapoisoned(obj) && !rn2(nopoison)) { /* remove poison now in case obj ends up in a bones file */ obj->opoisoned = FALSE; /* defer "obj is no longer poisoned" until after hit message */ @@ -3026,6 +3031,29 @@ mhitm_ad_curs( } } +/* Helper for mhitm_ad_drst(), containing some code that is also called from + * mhitm_ad_phys (for poisoned weapons) and shouldn't be subject to magic + * cancellation or a 1/8 chance roll. + * In this specific case, the "mhitm" in the name ACTUALLY means just that - + * this should be called only for monster versus monster situations. */ +staticfn void +mhitm_really_poison(struct monst *magr, struct attack *mattk, + struct monst *mdef, struct mhitm_data *mhm) +{ + if (gv.vis && canspotmon(magr)) + pline("%s %s was poisoned!", s_suffix(Monnam(magr)), + mpoisons_subj(magr, mattk)); + if (resists_poison(mdef)) { + if (gv.vis && canspotmon(mdef) && canspotmon(magr)) + pline_The("poison doesn't seem to affect %s.", + mon_nam(mdef)); + } else { + mhm->damage += rn1(10, 6); + if (mhm->damage >= mdef->mhp && gv.vis && canspotmon(mdef)) + pline_The("poison was deadly..."); + } +} + void mhitm_ad_drst( struct monst *magr, struct attack *mattk, @@ -3067,22 +3095,7 @@ mhitm_ad_drst( } else { /* mhitm */ if (!negated && !rn2(8)) { - if (gv.vis && canspotmon(magr)) - pline("%s %s was poisoned!", s_suffix(Monnam(magr)), - mpoisons_subj(magr, mattk)); - if (resists_poison(mdef)) { - if (gv.vis && canspotmon(mdef) && canspotmon(magr)) - pline_The("poison doesn't seem to affect %s.", - mon_nam(mdef)); - } else { - if (rn2(10)) { - mhm->damage += rn1(10, 6); - } else { - if (gv.vis && canspotmon(mdef)) - pline_The("poison was deadly..."); - mhm->damage = mdef->mhp; - } - } + mhitm_really_poison(magr, mattk, mdef, mhm); } } } @@ -3957,6 +3970,7 @@ mhitm_ad_phys( if (mattk->aatyp == AT_WEAP && otmp) { struct obj *marmg; int tmp; + boolean was_poisoned = (otmp->opoisoned || permapoisoned(otmp)); if (otmp->otyp == CORPSE && touch_petrifies(&mons[otmp->corpsenm])) { @@ -4015,6 +4029,21 @@ mhitm_ad_phys( You("divide as %s hits you!", mon_nam(magr)); } rustm(&gy.youmonst, otmp); + if (was_poisoned && gm.mhitu_dieroll <= 5) { + char buf[BUFSZ]; + + /* similar to mhitm_really_poison, but we don't use the + * exact same values, nor do we want the same 1/8 chance of + * the poison taking (use 1/4, same as in the mhitm case). */ + Sprintf(buf, "%s %s", s_suffix(Monnam(magr)), + mpoisons_subj(magr, mattk)); + /* arbitrary, but most poison sources in the game are + * strength-based. With hpdamchance = 10, HP damage occurs + * 1/2 of the time and it will hit Str the rest of the time. + * (This is the same as poisoned ammo.) */ + poisoned(buf, A_STR, pmname(magr->data, Mgender(magr)), + 10, FALSE); + } } else if (mattk->aatyp != AT_TUCH || mhm->damage != 0 || magr != u.ustuck) { hitmsg(magr, mattk); @@ -4077,6 +4106,13 @@ mhitm_ad_phys( } if (mhm->damage) rustm(mdef, mwep); + if ((mwep->opoisoned || permapoisoned(mwep)) && !rn2(4)) { + /* 1/4 chance of weapon poison applying is the same as in + * uhitm and mhitu cases. But since we don't need to call + * any special functions or go through tangled hmon_hitmon + * code, we can just jump straight to the poisoning. */ + mhitm_really_poison(magr, mattk, mdef, mhm); + } } else if (pa == &mons[PM_PURPLE_WORM] && pd == &mons[PM_SHRIEKER]) { /* hack to enhance mm_aggression(); we don't want purple worm's bite attack to kill a shrieker because then it From ab8ab7b3447e53d0935ae525f589265ba5be3ad6 Mon Sep 17 00:00:00 2001 From: PatR Date: Sat, 12 Apr 2025 10:22:52 -0700 Subject: [PATCH 548/791] more THEMERM and THEMERMFILL Give a little more information if environment variable THEMERM or THEMERMFILL has an invalid value. --- dat/themerms.lua | 11 +++++++++-- src/nhlua.c | 2 +- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/dat/themerms.lua b/dat/themerms.lua index c7ef49147..7d5a73860 100644 --- a/dat/themerms.lua +++ b/dat/themerms.lua @@ -982,15 +982,22 @@ end function pre_themerooms_generate() local debug_themerm = nh.debug_themerm(false) local debug_fill = nh.debug_themerm(true) + local xtrainfo = "" debug_rm_idx = lookup_by_name(debug_themerm, false) debug_fill_idx = lookup_by_name(debug_fill, true) if debug_themerm ~= nil and debug_rm_idx == nil then + if lookup_by_name(debug_themerm, true) ~= nil then + xtrainfo = "; it is a fill type" + end pline("Warning: themeroom '"..debug_themerm - .."' not found in themerooms", true) + .."' not found in themerooms"..xtrainfo, true) end if debug_fill ~= nil and debug_fill_idx == nil then + if lookup_by_name(debug_fill, false) ~= nil then + xtrainfo = "; it is a room type" + end pline("Warning: themeroom fill '"..debug_fill - .."' not found in themeroom_fills", true) + .."' not found in themeroom_fills"..xtrainfo, true) end end diff --git a/src/nhlua.c b/src/nhlua.c index 10c67494a..b3dfd32ad 100644 --- a/src/nhlua.c +++ b/src/nhlua.c @@ -990,7 +990,7 @@ nhl_get_debug_themerm_name(lua_State *L) lua_pop(L, 1); if (wizard) dbg_themerm = getenv(is_fill ? "THEMERMFILL" : "THEMERM"); - if (!dbg_themerm || strlen(dbg_themerm) == 0) { + if (!dbg_themerm || !*dbg_themerm) { lua_pushnil(L); } else { lua_pushstring(L, dbg_themerm); From 6a74f46c25b2abfc71518e817009523d5a45d324 Mon Sep 17 00:00:00 2001 From: rbsec Date: Sat, 12 Apr 2025 13:43:41 +0100 Subject: [PATCH 549/791] Fix a couple of incorrect names in the Terry Pratchett tributes --- dat/tribute | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dat/tribute b/dat/tribute index e8b34a8ec..5438d48be 100644 --- a/dat/tribute +++ b/dat/tribute @@ -3665,7 +3665,7 @@ and needs to see in the dark. Strange but true. %e passage # p. 218 %passage 9 -"He's bound to have done /something/," Noddy repeated. +"He's bound to have done /something/," Nobby repeated. In this he was echoing the Patrician's view of crime and punishment. If there was a crime, there should be punishment. If the specific criminal @@ -6031,7 +6031,7 @@ was mostly unexplored, too.(1) %e passage # p. 219 (passage begins mid-sentence) %passage 12 -[...] Sam Vines had learned a lot from watching Lady Sybil. She didn't +[...] Sam Vimes had learned a lot from watching Lady Sybil. She didn't mean to act like that, but she'd been born to it, into a class which had always behaved this way: You went through the world as if there was /no possibility/ that anyone would stop you or question you, and most of From a05cca16ef75d17dcd2c10da84e40e7cec7f3c7f Mon Sep 17 00:00:00 2001 From: PatR Date: Sat, 12 Apr 2025 10:43:32 -0700 Subject: [PATCH 550/791] fixes entry for PR #1408, typos in tribute names Pull request from rbsec: a couple of character names had misspellings. Closes #1408 --- doc/fixes3-7-0.txt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index 0f54d8dde..c6d0a154f 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -121,7 +121,8 @@ tribute (Discworld snippets) typos, in book order rather than fix order: quote, passage #6 first footnote, insert omitted "be", passage #7 last paragraph, "to" -> "be" Men at Arms passage #1, italicize /for/, passage #2, insert omitted - word "had": 'it was /fate/ that _had_ let Edward' + word "had": 'it was /fate/ that _had_ let Edward', #9, fix name typo + "Noddy" -> "Nobby" Interesting Times passage #1, italicize several words Feet of Clay passage #1, second "does not need" -> "doesn't even need" Hogfather passage #7 missing initial double quote for "Oh, just ...", @@ -131,7 +132,8 @@ tribute (Discworld snippets) typos, in book order rather than fix order: missing opening single quote on second sentence of Lord Downey's line, passage #11 both in footnote: "genious" -> "genius", "was, oddly enough, was one [...]" -> "was, oddly enough, one [...]" - The Fifth Elephant #1, italicize /always/, #9, "dublet" -> "doublet" + The Fifth Elephant #1, italicize /always/, #9, "dublet" -> "doublet", + #12, fix name typo, "Vines" -> "Vimes" The Truth #1, italicize several words Thief of Time #2, "gold starts" -> "gold stars" A Hat Full of Sky passage #9 "though" -> "thought" From 9821caf984b5a407589f1f6c0cd9b72a7581ca4b Mon Sep 17 00:00:00 2001 From: Greg Chappell Date: Tue, 11 Mar 2025 15:22:09 -0700 Subject: [PATCH 551/791] Add "I have reached Mine's End" epitaph --- dat/epitaph.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/dat/epitaph.txt b/dat/epitaph.txt index a8fbb3266..3b2da1480 100644 --- a/dat/epitaph.txt +++ b/dat/epitaph.txt @@ -279,6 +279,7 @@ I died laughing I disbelieved in reincarnation in my last life, too. I hacked myself to death I have all the time in the world +I have reached Mine's End I knew I'd find a use for this gravestone! I know my mind. And it's around here someplace. I lied! I'll never be alright! From efee4553b60cf9b81797350e88dda44747db1a20 Mon Sep 17 00:00:00 2001 From: PatR Date: Sat, 12 Apr 2025 12:19:50 -0700 Subject: [PATCH 552/791] github PR #1394 - "Mine's End" epitaph Pull request from chappg: add "I have reached Mine's End" to the set of epitaphs. Blame the explantory comment on me. Closes #1394 --- dat/epitaph.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/dat/epitaph.txt b/dat/epitaph.txt index 3b2da1480..d559d1fb3 100644 --- a/dat/epitaph.txt +++ b/dat/epitaph.txt @@ -279,6 +279,7 @@ I died laughing I disbelieved in reincarnation in my last life, too. I hacked myself to death I have all the time in the world +#"reached Mine's End": not necessarily true; sounds like "reached my end" I have reached Mine's End I knew I'd find a use for this gravestone! I know my mind. And it's around here someplace. From e26a4960882e87c69add8cf3d4333eaa69c54051 Mon Sep 17 00:00:00 2001 From: PatR Date: Sat, 12 Apr 2025 17:21:40 -0700 Subject: [PATCH 553/791] fix issue #1309 - secret doors in Garden rooms Issue reported by elunna: when a room gets converted into a theme room with fill type Garden, its walls are changed to trees but any secret doors in those walls are still displayed as regular walls. This adds a new D_ARBOREAL flag for secret doors, used to force them to be displayed as a tree instead of a wall. Fixes #1309 --- dat/themerms.lua | 3 +++ include/rm.h | 3 +++ src/detect.c | 2 +- src/display.c | 12 +++++++++++- src/mkmaze.c | 12 ++++++++++-- 5 files changed, 28 insertions(+), 4 deletions(-) diff --git a/dat/themerms.lua b/dat/themerms.lua index 7d5a73860..6aff95286 100644 --- a/dat/themerms.lua +++ b/dat/themerms.lua @@ -1071,7 +1071,10 @@ end -- postprocess callback: turn room walls into trees function make_garden_walls(data) local sel = data.sel:grow(); + -- change walls to trees des.replace_terrain({ selection = sel, fromterrain="w", toterrain = "T" }); + -- update secret doors; attempting to change to AIR will set arboreal flag + des.replace_terrain({ selection = sel, fromterrain="S", toterrain = "A" }); end -- postprocess callback: make a trap diff --git a/include/rm.h b/include/rm.h index 001414a10..f0382870f 100644 --- a/include/rm.h +++ b/include/rm.h @@ -219,6 +219,9 @@ struct rm { #define D_LOCKED 0x08 #define D_TRAPPED 0x10 +/* secret doors aren't trapped or nonpasswall; overload D_TRAPPED and + W_NONPASSWALL for 'arboreal' secret doors (in garden theme room) */ +#define D_ARBOREAL D_TRAPPED #define D_SECRET 0x20 /* only used by sp_lev.c, NOT in rm-struct */ /* diff --git a/src/detect.c b/src/detect.c index 0d1de0c83..89476dc88 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1588,7 +1588,7 @@ do_vicinity_map( void cvt_sdoor_to_door(struct rm *lev) { - int newmask = lev->doormask & ~WM_MASK; + int newmask = lev->doormask & ~(WM_MASK | D_ARBOREAL); if (Is_rogue_level(&u.uz)) { /* rogue didn't have doors, only doorways */ diff --git a/src/display.c b/src/display.c index 71c77bb87..716bdf2b8 100644 --- a/src/display.c +++ b/src/display.c @@ -2289,6 +2289,13 @@ back_to_glyph(coordxy x, coordxy y) case CORR: idx = (ptr->waslit || flags.lit_corridor) ? S_litcorr : S_corr; break; + case SDOOR: + if ((ptr->doormask & D_ARBOREAL) != 0) { + idx = S_tree; + break; + } + FALLTHROUGH; + /*FALLTHRU*/ case HWALL: case VWALL: case TLCORNER: @@ -2300,7 +2307,6 @@ back_to_glyph(coordxy x, coordxy y) case TDWALL: case TLWALL: case TRWALL: - case SDOOR: idx = ptr->seenv ? wall_angle(ptr) : S_stone; break; case DOOR: @@ -3579,6 +3585,10 @@ wall_angle(struct rm *lev) break; case SDOOR: + if ((lev->doormask & D_ARBOREAL) != 0) { + idx = S_tree; + break; + } if (lev->horizontal) goto horiz; FALLTHROUGH; diff --git a/src/mkmaze.c b/src/mkmaze.c index df83d2136..903330cf3 100644 --- a/src/mkmaze.c +++ b/src/mkmaze.c @@ -76,8 +76,16 @@ boolean set_levltyp(coordxy x, coordxy y, schar newtyp) { if (isok(x, y) && newtyp >= STONE && newtyp < MAX_TYPE) { - if (CAN_OVERWRITE_TERRAIN(levl[x][y].typ)) { - schar oldtyp = levl[x][y].typ; + schar oldtyp = levl[x][y].typ; + + /* hack for secret doors in garden theme rooms */ + if (oldtyp == SDOOR && newtyp == AIR) { + /* levl[][].typ stays SDOOR rather than change to AIR */ + levl[x][y].doormask |= D_ARBOREAL; + return TRUE; + } + + if (CAN_OVERWRITE_TERRAIN(oldtyp)) { /* typ==ICE || (typ==DRAWBRIDGE_UP && drawbridgemask==DB_ICE) */ boolean was_ice = is_ice(x, y); From 652f8576c06ffd52427c962a63a5a730bacebade Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sun, 13 Apr 2025 12:48:21 +0300 Subject: [PATCH 554/791] Cursed magic whistle can teleport you to your pet --- doc/fixes3-7-0.txt | 1 + include/extern.h | 1 + src/apply.c | 2 ++ src/teleport.c | 22 ++++++++++++++++++++++ 4 files changed, 26 insertions(+) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index c6d0a154f..183fa644d 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -1510,6 +1510,7 @@ if a tree and a boulder or statue were at the same location, applying an axe would break the boulder or statue rather than chop the tree avoid premapping outside Sokoban map to prevent showing stone glyphs Grimtooth is permanently poisoned, protects from poison, and can fling poison +cursed magic whistle can teleport you to your pet Fixes to 3.7.0-x General Problems Exposed Via git Repository diff --git a/include/extern.h b/include/extern.h index f6bfe2e43..459b452c9 100644 --- a/include/extern.h +++ b/include/extern.h @@ -3124,6 +3124,7 @@ extern int collect_coords(coord *, coordxy, coordxy, int, unsigned, boolean (*)(coordxy, coordxy)) NONNULLARG1; extern boolean safe_teleds(int); extern boolean teleport_pet(struct monst *, boolean) NONNULLARG1; +extern void tele_to_rnd_pet(void); extern void tele(void); extern void scrolltele(struct obj *) NO_NNARGS; extern int dotelecmd(void); diff --git a/src/apply.c b/src/apply.c index 6bf45b266..3af75ce59 100644 --- a/src/apply.c +++ b/src/apply.c @@ -498,6 +498,8 @@ use_magic_whistle(struct obj *obj) You("produce a %shigh-%s.", Underwater ? "very " : "", Deaf ? "frequency vibration" : "pitched humming noise"); wake_nearby(TRUE); + if (!rn2(2)) + tele_to_rnd_pet(); } else { /* it's magic! it works underwater too (at a higher pitch) */ You(Deaf ? alt_whistle_str : whistle_str, diff --git a/src/teleport.c b/src/teleport.c index 3088c461c..3c3d6df3e 100644 --- a/src/teleport.c +++ b/src/teleport.c @@ -804,6 +804,28 @@ teleport_pet(struct monst *mtmp, boolean force_it) return TRUE; } +/* teleport to random pet, if valid location next to it */ +void +tele_to_rnd_pet(void) +{ + struct monst *mtmp, *pet = (struct monst *) 0; + int cnt = 0; + + for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) + if (!DEADMONSTER(mtmp) && mtmp->mtame && !mon_offmap(mtmp)) { + cnt++; + if (!rn2(cnt)) + pet = mtmp; + } + if (pet && !m_next2u(pet)) { + coordxy tx = pet->mx + rn2(3) - 1, + ty = pet->my + rn2(3) - 1; + + if (isok(tx, ty) && teleok(tx, ty, FALSE)) + teleds(tx, ty, TELEDS_TELEPORT); + } +} + /* teleport the hero via some method other than scroll of teleport */ void tele(void) From 85de51a69a5e4aa3ac0256ef3ab4aca07ef6e973 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sun, 13 Apr 2025 13:10:24 +0300 Subject: [PATCH 555/791] Add invocation effect to Fire and Frost Brand Casts fireball or cone of cold at expert level --- doc/fixes3-7-0.txt | 1 + include/artifact.h | 2 ++ include/artilist.h | 4 ++-- src/artifact.c | 12 ++++++++++++ 4 files changed, 17 insertions(+), 2 deletions(-) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index 183fa644d..eb54336a9 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -1511,6 +1511,7 @@ if a tree and a boulder or statue were at the same location, applying an axe avoid premapping outside Sokoban map to prevent showing stone glyphs Grimtooth is permanently poisoned, protects from poison, and can fling poison cursed magic whistle can teleport you to your pet +Fire and Frost Brand can be invoked for expert level fireball or cone of cold Fixes to 3.7.0-x General Problems Exposed Via git Repository diff --git a/include/artifact.h b/include/artifact.h index efd0a4992..9d66ad33f 100644 --- a/include/artifact.h +++ b/include/artifact.h @@ -68,6 +68,8 @@ enum invoke_prop_types { CREATE_AMMO, BANISH, FLING_POISON, + FIRESTORM, + SNOWSTORM, BLINDING_RAY }; diff --git a/include/artilist.h b/include/artilist.h index 8d55c6789..0adb26260 100644 --- a/include/artilist.h +++ b/include/artilist.h @@ -147,11 +147,11 @@ static NEARDATA struct artifact artilist[] = { 0, 7, 3500L, NO_COLOR, MAGICBANE), A("Frost Brand", LONG_SWORD, (SPFX_RESTR | SPFX_ATTK | SPFX_DEFN), 0, 0, - COLD(5, 0), COLD(0, 0), NO_CARY, 0, A_NONE, NON_PM, NON_PM, + COLD(5, 0), COLD(0, 0), NO_CARY, SNOWSTORM, A_NONE, NON_PM, NON_PM, 0, 9, 3000L, NO_COLOR, FROST_BRAND), A("Fire Brand", LONG_SWORD, (SPFX_RESTR | SPFX_ATTK | SPFX_DEFN), 0, 0, - FIRE(5, 0), FIRE(0, 0), NO_CARY, 0, A_NONE, NON_PM, NON_PM, + FIRE(5, 0), FIRE(0, 0), NO_CARY, FIRESTORM, A_NONE, NON_PM, NON_PM, 0, 5, 3000L, NO_COLOR, FIRE_BRAND), A("Dragonbane", BROADSWORD, diff --git a/src/artifact.c b/src/artifact.c index 3cb92fac5..7d9a082c6 100644 --- a/src/artifact.c +++ b/src/artifact.c @@ -2024,6 +2024,18 @@ arti_invoke(struct obj *obj) obj->age = svm.moves; } break; + case SNOWSTORM: + case FIRESTORM: + { + int storm = oart->inv_prop == SNOWSTORM ? SPE_CONE_OF_COLD : SPE_FIREBALL; + int skill = spell_skilltype(storm); + int expertise = P_SKILL(skill); + + P_SKILL(skill) = P_EXPERT; + (void) spelleffects(storm, FALSE, TRUE); + P_SKILL(skill) = expertise; + } + break; case BLINDING_RAY: if (getdir((char *) 0)) { if (u.dx || u.dy) { From eeb96c41512b7139ac3a9d8b2dfc3e3124575a03 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 13 Apr 2025 10:22:59 -0400 Subject: [PATCH 556/791] update tested versions of Visual Studio 2025-04-13 --- sys/windows/Makefile.nmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sys/windows/Makefile.nmake b/sys/windows/Makefile.nmake index c7b54b098..081586ab5 100644 --- a/sys/windows/Makefile.nmake +++ b/sys/windows/Makefile.nmake @@ -9,7 +9,7 @@ # # Visual Studio Compilers Tested: # - Microsoft Visual Studio 2019 Community Edition v 16.11.42 -# - Microsoft Visual Studio 2022 Community Edition v 17.13.3 +# - Microsoft Visual Studio 2022 Community Edition v 17.13.6 # #============================================================================== # This is used for building two distinct executables of NetHack: @@ -1177,7 +1177,7 @@ rc=Rc.exe # # Recently tested versions: TESTEDVS2019 = 14.29.30157.0 -TESTEDVS2022 = 14.43.34809.0 +TESTEDVS2022 = 14.43.34810.0 VS2019CUR = $(TESTEDVS2019:.=) VS2022CUR = $(TESTEDVS2022:.=) From a185c270bb0ac77a48fe35cb3cc0e0e4f474189e Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sun, 13 Apr 2025 17:32:14 +0300 Subject: [PATCH 557/791] Expose trap once-field to lua --- doc/lua.adoc | 1 + src/nhlua.c | 1 + 2 files changed, 2 insertions(+) diff --git a/doc/lua.adoc b/doc/lua.adoc index 58669e9ec..3b457b670 100644 --- a/doc/lua.adoc +++ b/doc/lua.adoc @@ -201,6 +201,7 @@ Returns a table with the following elements: | ttyp_name | text | name of trap type | tseen | boolean | trap seen by you? | madeby_u | boolean | trap made by you? +| once | boolean | trap is deleted once triggered | tnote | integer | note of a squeaky board trap | launchx, launchy, launch2x, launch2y | integer | coordinates of a boulder for a rolling boulder trap | conjoined | integer | encoded directions for a [spiked] pit. diff --git a/src/nhlua.c b/src/nhlua.c index b3dfd32ad..6bc523e7e 100644 --- a/src/nhlua.c +++ b/src/nhlua.c @@ -432,6 +432,7 @@ nhl_gettrap(lua_State *L) get_trapname_bytype(ttmp->ttyp)); nhl_add_table_entry_bool(L, "tseen", ttmp->tseen); nhl_add_table_entry_bool(L, "madeby_u", ttmp->madeby_u); + nhl_add_table_entry_bool(L, "once", ttmp->once); switch (ttmp->ttyp) { case SQKY_BOARD: nhl_add_table_entry_int(L, "tnote", ttmp->tnote); From a70db6dafbdd24d51dbb368ba4b084f2d06d5f63 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 13 Apr 2025 12:14:38 -0400 Subject: [PATCH 558/791] WIN_MAP==WIN_ERR on a code path to tty_wait_synch --- win/tty/wintty.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/win/tty/wintty.c b/win/tty/wintty.c index 46f32d353..dbebb57a7 100644 --- a/win/tty/wintty.c +++ b/win/tty/wintty.c @@ -3602,7 +3602,7 @@ tty_wait_synch(void) { HUPSKIP(); /* we just need to make sure all windows are synch'd */ - if (!ttyDisplay || ttyDisplay->rawprint) { + if (!ttyDisplay || ttyDisplay->rawprint || WIN_MAP == WIN_ERR) { getret(); if (ttyDisplay) ttyDisplay->rawprint = 0; From 932f5986897514ca142ba63fa1e9aeef169a3acc Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 13 Apr 2025 12:23:09 -0400 Subject: [PATCH 559/791] follow-up bit --- win/tty/wintty.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/win/tty/wintty.c b/win/tty/wintty.c index dbebb57a7..785dab116 100644 --- a/win/tty/wintty.c +++ b/win/tty/wintty.c @@ -3602,7 +3602,7 @@ tty_wait_synch(void) { HUPSKIP(); /* we just need to make sure all windows are synch'd */ - if (!ttyDisplay || ttyDisplay->rawprint || WIN_MAP == WIN_ERR) { + if (WIN_MAP == WIN_ERR || !ttyDisplay || ttyDisplay->rawprint) { getret(); if (ttyDisplay) ttyDisplay->rawprint = 0; From d6dd5c743c6520652a82937063f788d7be747014 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sun, 13 Apr 2025 20:13:54 +0300 Subject: [PATCH 560/791] Reinstate some of the mind flayer amnesia When I reworked amnesia to not forget levels or objects, I removed the forgetting from the mind flayer attacks. I intended to add something to replace it, but forgot ... --- src/uhitm.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/uhitm.c b/src/uhitm.c index 581c6287e..fecd46228 100644 --- a/src/uhitm.c +++ b/src/uhitm.c @@ -3197,7 +3197,14 @@ mhitm_ad_drin( } /* adjattrib gives dunce cap message when appropriate */ (void) adjattrib(A_INT, -rnd(2), FALSE); - + if (!rn2(5)) { + losespells(); + gs.skipdrin = TRUE; + } + if (!rn2(5)) { + drain_weapon_skill(rnd(2)); + gs.skipdrin = TRUE; + } } else { /* mhitm */ char buf[BUFSZ]; From af3e601ff7ea14cf7f896c17c3ec62f8a1f98b9f Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Tue, 15 Apr 2025 14:45:51 +0300 Subject: [PATCH 561/791] Remove melting ice timer when breaking digging wand --- src/apply.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/apply.c b/src/apply.c index 3af75ce59..a9142e75a 100644 --- a/src/apply.c +++ b/src/apply.c @@ -4015,6 +4015,8 @@ do_break_wand(struct obj *obj) if (*in_rooms(x, y, SHOPBASE)) shop_damage = TRUE; } + if (levl[x][y].typ == ICE) + spot_stop_timers(x, y, MELT_ICE_AWAY); /* * Let liquid flow into the newly created pits. * Adjust corresponding code in music.c for From a3e12550eafda69685fdf24c9cd07a9ceb1967bd Mon Sep 17 00:00:00 2001 From: nhmall Date: Tue, 15 Apr 2025 15:35:17 -0400 Subject: [PATCH 562/791] savefile changes - part 1 This is the first of several savefile-related changes to follow later. This one is groundwork for those later changes. Remove internal compression schemes (RLECOMP and ZEROCOMP) and discard the savefile_info struct that was primarily used to convey which internal compression schemes had been in use. Relocate some struct definitions into appropriate header files for use by code to come in later changes. Remove the two struct size-related fields from version_info and from the nmakedefs_s. Instead, include a series of bytes near the beginning of the savefile, representing the size of each struct or base data type that impacts the historical savefile content. Those are referred to as the "critical bytes". (Related note: the "you" struct required two bytes, low and high, due to its size). Compare those critical bytes in a savefile against the NetHack build that is reading the savefile. This allows mismatch detection early in the savefile-reading process, and a clean exit, rather than proceeding to read nonsensical values from the file. Include some feedback on what the first mismatch was when encountering one. For arrays stored in the savefile, use loop-logic in the core to write/read the array elements one at a time, rather than in a single blob. This will be required for changes to follow later. (impacts artiexist[], artidisco[], svd.dungeons[], svl.level_info[], svl.level.locations[][], msrooms[] field of mapseen, svb.bases[], svb.disco[] objects[], svm.mvitals[], svs.spl_book[], svd.doors[], go.oracle_loc[], utrack[], wgrowtime[]) This also adds data model to the long version information. This invalidates existing save and bones files due to the changes in the information at the start of the file. --- include/artifact.h | 18 +++ include/config.h | 32 ----- include/dungeon.h | 111 +++++++------- include/extern.h | 7 + include/global.h | 4 - include/integer.h | 5 + include/patchlevel.h | 2 +- include/wintype.h | 2 + src/artifact.c | 45 +++--- src/bones.c | 34 ++--- src/date.c | 4 - src/decl.c | 28 ---- src/dungeon.c | 109 +++++++++----- src/end.c | 8 +- src/engrave.c | 9 +- src/files.c | 17 +-- src/light.c | 12 +- src/mdlib.c | 78 +++++----- src/mkmaze.c | 6 +- src/mkroom.c | 18 ++- src/nhlua.c | 21 +-- src/o_init.c | 24 +++- src/region.c | 60 ++++---- src/restore.c | 334 ++++++++++++++++++++++--------------------- src/rumors.c | 40 ++++-- src/save.c | 283 +++++++++++++++++------------------- src/timeout.c | 30 ++-- src/track.c | 20 +-- src/version.c | 318 ++++++++++++++++++++++++++++++---------- src/worm.c | 18 ++- sys/share/pcmain.c | 5 +- util/makedefs.c | 12 -- 32 files changed, 962 insertions(+), 752 deletions(-) diff --git a/include/artifact.h b/include/artifact.h index 9d66ad33f..2db7270fb 100644 --- a/include/artifact.h +++ b/include/artifact.h @@ -5,6 +5,10 @@ #ifndef ARTIFACT_H #define ARTIFACT_H + +#include "permonst.h" +#include "prop.h" + /* clang-format off */ #define SPFX_NONE 0x00000000L /* no special effects, just a bonus */ @@ -73,5 +77,19 @@ enum invoke_prop_types { BLINDING_RAY }; +/* artifact tracking; gift and wish imply found; it also gets set for items + seen on the floor, in containers, and wielded or dropped by monsters */ +struct arti_info { + Bitfield(exists, 1); /* 1 if corresponding artifact has been created */ + Bitfield(found, 1); /* 1 if artifact is known by hero to exist */ + Bitfield(gift, 1); /* 1 iff artifact was created as a prayer reward */ + Bitfield(wish, 1); /* 1 iff artifact was created via wish */ + Bitfield(named, 1); /* 1 iff artifact was made by naming an item */ + Bitfield(viadip, 1); /* 1 iff dipped long sword became Excalibur */ + Bitfield(lvldef, 1); /* 1 iff created by special level definition */ + Bitfield(bones, 1); /* 1 iff came from bones file */ + Bitfield(rndm, 1); /* 1 iff randomly generated */ +}; + /* clang-format on */ #endif /* ARTIFACT_H */ diff --git a/include/config.h b/include/config.h index a7097b363..14bfdc2e8 100644 --- a/include/config.h +++ b/include/config.h @@ -397,38 +397,6 @@ /* # define ZLIB_COMP */ /* ZLIB for compression */ #endif -/* - * Internal Compression Options - * - * Internal compression options RLECOMP and ZEROCOMP alter the data - * that gets written to the save file by NetHack, in contrast - * to COMPRESS or ZLIB_COMP which compress the entire file after - * the NetHack data is written out. - * - * Defining RLECOMP builds in support for internal run-length - * compression of level structures. If RLECOMP support is included - * it can be toggled on/off at runtime via the config file option - * rlecomp. - * - * Defining ZEROCOMP builds in support for internal zero-comp - * compression of data. If ZEROCOMP support is included it can still - * be toggled on/off at runtime via the config file option zerocomp. - * - * RLECOMP and ZEROCOMP support can be included even if - * COMPRESS or ZLIB_COMP support is included. One reason for doing - * so would be to provide savefile read compatibility with a savefile - * where those options were in effect. With RLECOMP and/or ZEROCOMP - * defined, NetHack can read an rlecomp or zerocomp savefile in, yet - * re-save without them. - * - * Using any compression option will create smaller bones/level/save - * files at the cost of additional code and time. - */ - -/* # define INTERNAL_COMP */ /* defines both ZEROCOMP and RLECOMP */ -/* # define ZEROCOMP */ /* Support ZEROCOMP compression */ -/* # define RLECOMP */ /* Support RLECOMP compression */ - /* * Data librarian. Defining DLB places most of the support files into * a tar-like file, thus making a neater installation. See *conf.h diff --git a/include/dungeon.h b/include/dungeon.h index 288b15b58..d4a1dcf62 100644 --- a/include/dungeon.h +++ b/include/dungeon.h @@ -188,66 +188,71 @@ struct linfo { /* what the player knows about a single dungeon level */ /* initialized in mklev() */ +struct mapseen_feat { + /* feature knowledge that must be calculated from levl array */ + Bitfield(nfount, 2); + Bitfield(nsink, 2); + Bitfield(naltar, 2); + Bitfield(nthrone, 2); + + Bitfield(ngrave, 2); + Bitfield(ntree, 2); + Bitfield(water, 2); + Bitfield(lava, 2); + + Bitfield(ice, 2); + /* calculated from rooms array */ + Bitfield(nshop, 2); + Bitfield(ntemple, 2); + /* altar alignment; MSA_NONE if there is more than one and + they aren't all the same */ + Bitfield(msalign, 2); + + Bitfield(shoptype, 5); +}; +struct mapseen_flags { + Bitfield(notreachable, 1); /* can't get back to this level */ + Bitfield(forgot, 1); /* player has forgotten about this level */ + Bitfield(knownbones, 1); /* player aware of bones */ + Bitfield(oracle, 1); + Bitfield(sokosolved, 1); + Bitfield(bigroom, 1); + Bitfield(castle, 1); + Bitfield(castletune, 1); /* add tune hint to castle annotation */ + + Bitfield(valley, 1); + Bitfield(msanctum, 1); + Bitfield(ludios, 1); + Bitfield(roguelevel, 1); + /* quest annotations: quest_summons is for main dungeon level + with entry portal and is reset once quest has been finished; + questing is for quest home (level 1) */ + Bitfield(quest_summons, 1); /* heard summons from leader */ + Bitfield(questing, 1); /* quest leader has unlocked quest stairs */ + /* "gateway to sanctum" */ + Bitfield(vibrating_square, 1); /* found vibrating square 'trap'; + * flag cleared once the msanctum + * annotation has been added (on + * the next dungeon level; temple + * entered or high altar mapped) */ + Bitfield(spare1, 1); /* not used */ +}; + +struct mapseen_rooms { + Bitfield(seen, 1); + Bitfield(untended, 1); /* flag for shop without shk */ +}; + typedef struct mapseen { struct mapseen *next; /* next map in the chain */ branch *br; /* knows about branch via taking it in goto_level */ d_level lev; /* corresponding dungeon level */ - struct mapseen_feat { - /* feature knowledge that must be calculated from levl array */ - Bitfield(nfount, 2); - Bitfield(nsink, 2); - Bitfield(naltar, 2); - Bitfield(nthrone, 2); - - Bitfield(ngrave, 2); - Bitfield(ntree, 2); - Bitfield(water, 2); - Bitfield(lava, 2); - - Bitfield(ice, 2); - /* calculated from rooms array */ - Bitfield(nshop, 2); - Bitfield(ntemple, 2); - /* altar alignment; MSA_NONE if there is more than one and - they aren't all the same */ - Bitfield(msalign, 2); - - Bitfield(shoptype, 5); - } feat; - struct mapseen_flags { - Bitfield(notreachable, 1); /* can't get back to this level */ - Bitfield(forgot, 1); /* player has forgotten about this level */ - Bitfield(knownbones, 1); /* player aware of bones */ - Bitfield(oracle, 1); - Bitfield(sokosolved, 1); - Bitfield(bigroom, 1); - Bitfield(castle, 1); - Bitfield(castletune, 1); /* add tune hint to castle annotation */ - - Bitfield(valley, 1); - Bitfield(msanctum, 1); - Bitfield(ludios, 1); - Bitfield(roguelevel, 1); - /* quest annotations: quest_summons is for main dungeon level - with entry portal and is reset once quest has been finished; - questing is for quest home (level 1) */ - Bitfield(quest_summons, 1); /* heard summons from leader */ - Bitfield(questing, 1); /* quest leader has unlocked quest stairs */ - /* "gateway to sanctum" */ - Bitfield(vibrating_square, 1); /* found vibrating square 'trap'; - * flag cleared once the msanctum - * annotation has been added (on - * the next dungeon level; temple - * entered or high altar mapped) */ - Bitfield(spare1, 1); /* not used */ - } flags; + struct mapseen_feat feat; + struct mapseen_flags flags; /* custom naming */ char *custom; unsigned custom_lth; - struct mapseen_rooms { - Bitfield(seen, 1); - Bitfield(untended, 1); /* flag for shop without shk */ - } msrooms[(MAXNROFROOMS + 1) * 2]; /* same size as svr.rooms[] */ + struct mapseen_rooms msrooms[(MAXNROFROOMS + 1) * 2]; /* same size as svr.rooms[] */ /* dead heroes; might not have graves or ghosts */ struct cemetery *final_resting_place; /* same as level.bonesinfo */ } mapseen; diff --git a/include/extern.h b/include/extern.h index 459b452c9..585b2273b 100644 --- a/include/extern.h +++ b/include/extern.h @@ -67,6 +67,10 @@ * */ +#ifndef ARTIFACT_H +#include "artifact.h" +#endif + /* ### alloc.c ### */ #if 0 @@ -3495,6 +3499,9 @@ extern unsigned long get_current_feature_ver(void); extern const char *copyright_banner_line(int) NONNULL; extern void early_version_info(boolean); extern void dump_version_info(void); +extern void store_critical_bytes(NHFILE *) NONNULLARG1; +extern int compare_critical_bytes(NHFILE *); +extern int get_critical_size_count(void); /* ### video.c ### */ diff --git a/include/global.h b/include/global.h index 77740213b..db6faa52d 100644 --- a/include/global.h +++ b/include/global.h @@ -357,8 +357,6 @@ struct version_info { unsigned long incarnation; /* actual version number */ unsigned long feature_set; /* bitmask of config settings */ unsigned long entity_count; /* # of monsters and objects */ - unsigned long struct_sizes1; /* size of key structs */ - unsigned long struct_sizes2; /* size of more key structs */ }; struct savefile_info { @@ -391,8 +389,6 @@ struct nomakedefs_s { unsigned long version_features; unsigned long ignored_features; unsigned long version_sanity1; - unsigned long version_sanity2; - unsigned long version_sanity3; unsigned long build_time; }; extern struct nomakedefs_s nomakedefs; diff --git a/include/integer.h b/include/integer.h index 32a3b3266..d38ea80ca 100644 --- a/include/integer.h +++ b/include/integer.h @@ -101,6 +101,11 @@ typedef uint32_t uint32; typedef int64_t int64; typedef uint64_t uint64; +/* Also provide ushort, uint, ulong */ +typedef unsigned short ushort; +typedef unsigned int uint; +typedef unsigned long ulong; + /* for non-negative L, calculate L * 10 + D, avoiding signed overflow; yields -1 if overflow would have happened; assumes compiler will optimize the constants */ diff --git a/include/patchlevel.h b/include/patchlevel.h index 9b6140a6d..1fcec2047 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 121 +#define EDITLEVEL 122 /* * Development status possibilities. diff --git a/include/wintype.h b/include/wintype.h index 6bf49aabb..6b94bef64 100644 --- a/include/wintype.h +++ b/include/wintype.h @@ -32,6 +32,8 @@ typedef union any { const char *a_string; int (*a_nfunc)(void); unsigned long a_mask32; /* used by status highlighting */ + int64 a_int64; + uint64 a_uint64; /* add types as needed */ } anything; #define ANY_P union any /* avoid typedef in prototypes diff --git a/src/artifact.c b/src/artifact.c index 7d9a082c6..dfb436c3d 100644 --- a/src/artifact.c +++ b/src/artifact.c @@ -47,26 +47,15 @@ staticfn void dispose_of_orig_obj(struct obj *); of hit points that will fit in a 15 bit integer. */ #define FATAL_DAMAGE_MODIFIER 200 -/* artifact tracking; gift and wish imply found; it also gets set for items - seen on the floor, in containers, and wielded or dropped by monsters */ -struct arti_info { - Bitfield(exists, 1); /* 1 if corresponding artifact has been created */ - Bitfield(found, 1); /* 1 if artifact is known by hero to exist */ - Bitfield(gift, 1); /* 1 iff artifact was created as a prayer reward */ - Bitfield(wish, 1); /* 1 iff artifact was created via wish */ - Bitfield(named, 1); /* 1 iff artifact was made by naming an item */ - Bitfield(viadip, 1); /* 1 iff dipped long sword became Excalibur */ - Bitfield(lvldef, 1); /* 1 iff created by special level definition */ - Bitfield(bones, 1); /* 1 iff came from bones file */ - Bitfield(rndm, 1); /* 1 iff randomly generated */ -}; +/* arti_info struct definition moved to artifact.h */ + /* array of flags tracking which artifacts exist, indexed by ART_xx; ART_xx values are 1..N, element [0] isn't used; no terminator needed */ static struct arti_info artiexist[1 + NROFARTIFACTS]; /* discovery list; for N discovered artifacts, the first N entries are ART_xx values in discovery order, the remaining (NROFARTIFACTS-N) slots are 0 */ static xint16 artidisco[NROFARTIFACTS]; -/* note: artiexist[] and artidisco[] don't need to be in struct g; they +/* note: artiexist[] and artidisco[] don't need to be in struct ga; they * get explicitly initialized at game start so don't need to be part of * bulk re-init if game restart ever gets implemented. They are saved * and restored but that is done through this file so they can be local. @@ -111,18 +100,34 @@ init_artifacts(void) void save_artifacts(NHFILE *nhfp) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) artiexist, sizeof artiexist); - bwrite(nhfp->fd, (genericptr_t) artidisco, sizeof artidisco); + int i; + + for (i = 0; i < (NROFARTIFACTS + 1); ++i) { + if (nhfp->structlevel) + bwrite(nhfp->fd, (genericptr_t) &artiexist[i], + sizeof (struct arti_info)); + } + for (i = 0; i < (NROFARTIFACTS); ++i) { + if (nhfp->structlevel) + bwrite(nhfp->fd, (genericptr_t) &artidisco[i], + sizeof (xint16)); } } void restore_artifacts(NHFILE *nhfp) { - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) artiexist, sizeof artiexist); - mread(nhfp->fd, (genericptr_t) artidisco, sizeof artidisco); + int i; + + for (i = 0; i < (NROFARTIFACTS + 1); ++i) { + if (nhfp->structlevel) + mread(nhfp->fd, (genericptr_t) &artiexist[i], + sizeof (struct arti_info)); + } + for (i = 0; i < (NROFARTIFACTS); ++i) { + if (nhfp->structlevel) + mread(nhfp->fd, (genericptr_t) &artidisco[i], + sizeof (xint16)); } hack_artifacts(); /* redo non-saved special cases */ } diff --git a/src/bones.c b/src/bones.c index e0a809de9..f165e71ea 100644 --- a/src/bones.c +++ b/src/bones.c @@ -610,14 +610,14 @@ savebones(int how, time_t when, struct obj *corpse) nhfp->mode = WRITING; store_version(nhfp); - store_savefileinfo(nhfp); + + /* if a bones pool digit is in use, it precedes the bonesid + string and isn't recorded in the file */ if (nhfp->structlevel) { - /* if a bones pool digit is in use, it precedes the bonesid - string and isn't recorded in the file */ bwrite(nhfp->fd, (genericptr_t) &c, sizeof c); bwrite(nhfp->fd, (genericptr_t) bonesid, (unsigned) c); /* DD.nn */ - savefruitchn(nhfp); } + savefruitchn(nhfp); update_mlstmv(); /* update monsters for eventual restoration */ savelev(nhfp, ledger_no(&u.uz)); close_nhfile(nhfp); @@ -668,23 +668,25 @@ getbones(void) return 0; } } + /* if a bones pool digit is in use, it precedes the bonesid + string and wasn't recorded in the file */ if (nhfp->structlevel) { - /* if a bones pool digit is in use, it precedes the bonesid - string and wasn't recorded in the file */ mread(nhfp->fd, (genericptr_t) &c, sizeof c); /* length including terminating '\0' */ - if ((unsigned) c <= sizeof oldbonesid) { + } + if ((unsigned) c <= sizeof oldbonesid) { + if (nhfp->structlevel) { mread(nhfp->fd, (genericptr_t) oldbonesid, - (unsigned) c); /* DD.nn or Qrrr.n for role rrr */ - } else { - if (wizard) - debugpline2("Abandoning bones , %u > %u.", - (unsigned) c, (unsigned) sizeof oldbonesid); - close_nhfile(nhfp); - compress_bonesfile(); - /* ToDo: maybe unlink these problematic bones? */ - return 0; + (unsigned) c); /* DD.nn or Qrrr.n for role rrr */ } + } else { + if (wizard) + debugpline2("Abandoning bones , %u > %u.", (unsigned) c, + (unsigned) sizeof oldbonesid); + close_nhfile(nhfp); + compress_bonesfile(); + /* ToDo: maybe unlink these problematic bones? */ + return 0; } if (strcmp(bonesid, oldbonesid) != 0) { char errbuf[BUFSZ]; diff --git a/src/date.c b/src/date.c index f4b96fdb0..3ec4fbb3d 100644 --- a/src/date.c +++ b/src/date.c @@ -36,8 +36,6 @@ struct nomakedefs_s nomakedefs = { 0x00000000UL, 0x00000000UL, 0x00000000UL, - 0x00000000UL, - 0x00000000UL, 554476737UL, }; @@ -113,8 +111,6 @@ populate_nomakedefs(struct version_info *version) nomakedefs.version_features = version->feature_set; nomakedefs.ignored_features = md_ignored_features(); nomakedefs.version_sanity1 = version->entity_count; - nomakedefs.version_sanity2 = version->struct_sizes1; - nomakedefs.version_sanity3 = version->struct_sizes2; nomakedefs.version_string = dupstr(mdlib_version_string(tmpbuf2, ".")); nomakedefs.version_id = dupstr( version_id_string(tmpbuf2, sizeof tmpbuf2, nomakedefs.build_date)); diff --git a/src/decl.c b/src/decl.c index 617d62e86..3859f5a2f 100644 --- a/src/decl.c +++ b/src/decl.c @@ -51,29 +51,6 @@ const struct c_common_strings c_common_strings = { "mon", "you" } }; -static const struct savefile_info default_sfinfo = { -#ifdef NHSTDC - 0x00000000UL -#else - 0x00000000L -#endif -#if defined(COMPRESS) || defined(ZLIB_COMP) - | SFI1_EXTERNALCOMP -#endif -#if defined(ZEROCOMP) - | SFI1_ZEROCOMP -#endif -#if defined(RLECOMP) - | SFI1_RLECOMP -#endif - , -#ifdef NHSTDC - 0x00000000UL, 0x00000000UL -#else - 0x00000000L, 0x00000000L -#endif -}; - const char disclosure_options[] = "iavgco"; char emptystr[] = {0}; /* non-const */ @@ -117,7 +94,6 @@ const char *materialnm[] = { "mysterious", "liquid", "wax", "organic", "platinum", "mithril", "plastic", "glass", "gemstone", "stone" }; const char quitchars[] = " \r\n\033"; -NEARDATA struct savefile_info sfcap, sfrestinfo, sfsaveinfo; const int shield_static[SHIELD_COUNT] = { S_ss1, S_ss2, S_ss3, S_ss2, S_ss1, S_ss2, S_ss4, /* 7 per row */ S_ss1, S_ss2, S_ss3, S_ss2, S_ss1, S_ss2, S_ss4, @@ -1166,10 +1142,6 @@ decl_globals_init(void) MAGICCHECK(g_init_y); MAGICCHECK(g_init_z); - sfcap = default_sfinfo; - sfrestinfo = default_sfinfo; - sfsaveinfo = default_sfinfo; - gs.subrooms = &svr.rooms[MAXNROFROOMS + 1]; ZERO(flags); diff --git a/src/dungeon.c b/src/dungeon.c index 47f6e2c49..f05c926ab 100644 --- a/src/dungeon.c +++ b/src/dungeon.c @@ -147,15 +147,21 @@ save_dungeon( boolean perform_write, boolean free_data) { - int count; + int i, count; branch *curr, *next; mapseen *curr_ms, *next_ms; if (perform_write) { - if(nhfp->structlevel) { + if (nhfp->structlevel) { bwrite(nhfp->fd, (genericptr_t) &svn.n_dgns, sizeof svn.n_dgns); - bwrite(nhfp->fd, (genericptr_t) svd.dungeons, - sizeof(dungeon) * (unsigned) svn.n_dgns); + } + for (i = 0; i < svn.n_dgns; ++i) { + if (nhfp->structlevel) { + bwrite(nhfp->fd, (genericptr_t) &svd.dungeons[i], + sizeof (dungeon)); + } + } + if (nhfp->structlevel) { bwrite(nhfp->fd, (genericptr_t) &svd.dungeon_topology, sizeof svd.dungeon_topology); bwrite(nhfp->fd, (genericptr_t) svt.tune, sizeof tune); @@ -172,16 +178,23 @@ save_dungeon( count = maxledgerno(); if (nhfp->structlevel) { bwrite(nhfp->fd, (genericptr_t) &count, sizeof count); - bwrite(nhfp->fd, (genericptr_t) svl.level_info, - (unsigned) count * sizeof (struct linfo)); + } + for (i = 0; i < count; ++i) { + if (nhfp->structlevel) { + bwrite(nhfp->fd, (genericptr_t) &svl.level_info[i], + sizeof (struct linfo)); + } + } + if (nhfp->structlevel) { bwrite(nhfp->fd, (genericptr_t) &svi.inv_pos, sizeof svi.inv_pos); } for (count = 0, curr_ms = svm.mapseenchn; curr_ms; curr_ms = curr_ms->next) count++; - if (nhfp->structlevel) + if (nhfp->structlevel) { bwrite(nhfp->fd, (genericptr_t) &count, sizeof count); + } for (curr_ms = svm.mapseenchn; curr_ms; curr_ms = curr_ms->next) { save_mapseen(nhfp, curr_ms); @@ -216,21 +229,30 @@ restore_dungeon(NHFILE *nhfp) if (nhfp->structlevel) { mread(nhfp->fd, (genericptr_t) &svn.n_dgns, sizeof svn.n_dgns); - mread(nhfp->fd, (genericptr_t) svd.dungeons, - sizeof (dungeon) * (unsigned) svn.n_dgns); + } + for (i = 0; i < svn.n_dgns; ++i) { + if (nhfp->structlevel) { + mread(nhfp->fd, (genericptr_t) &svd.dungeons[i], sizeof(dungeon)); + } + } + if (nhfp->structlevel) { mread(nhfp->fd, (genericptr_t) &svd.dungeon_topology, sizeof svd.dungeon_topology); + } + if (nhfp->structlevel) { mread(nhfp->fd, (genericptr_t) svt.tune, sizeof tune); } last = svb.branches = (branch *) 0; - if (nhfp->structlevel) + if (nhfp->structlevel) { mread(nhfp->fd, (genericptr_t) &count, sizeof count); + } for (i = 0; i < count; i++) { curr = (branch *) alloc(sizeof *curr); - if (nhfp->structlevel) + if (nhfp->structlevel) { mread(nhfp->fd, (genericptr_t) curr, sizeof *curr); + } curr->next = (branch *) 0; if (last) last->next = curr; @@ -245,10 +267,12 @@ restore_dungeon(NHFILE *nhfp) if (count >= MAXLINFO) panic("level information count larger (%d) than allocated size", count); - if (nhfp->structlevel) - mread(nhfp->fd, (genericptr_t) svl.level_info, - (unsigned) count * sizeof (struct linfo)); - + for (i = 0; i < count; ++i) { + if (nhfp->structlevel) { + mread(nhfp->fd, (genericptr_t) &svl.level_info[i], + sizeof (struct linfo)); + } + } if (nhfp->structlevel) { mread(nhfp->fd, (genericptr_t) &svi.inv_pos, sizeof svi.inv_pos); mread(nhfp->fd, (genericptr_t) &count, sizeof count); @@ -2566,17 +2590,19 @@ save_exclusions(NHFILE *nhfp) for (nez = 0, ez = sve.exclusion_zones; ez; ez = ez->next, ++nez) ; - if (nhfp->structlevel) - bwrite(nhfp->fd, (genericptr_t) &nez, sizeof nez); + if (perform_bwrite(nhfp)) { + if (nhfp->structlevel) + bwrite(nhfp->fd, (genericptr_t) &nez, sizeof nez); - for (ez = sve.exclusion_zones; ez; ez = ez->next) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &ez->zonetype, - sizeof ez->zonetype); - bwrite(nhfp->fd, (genericptr_t) &ez->lx, sizeof ez->lx); - bwrite(nhfp->fd, (genericptr_t) &ez->ly, sizeof ez->ly); - bwrite(nhfp->fd, (genericptr_t) &ez->hx, sizeof ez->hx); - bwrite(nhfp->fd, (genericptr_t) &ez->hy, sizeof ez->hy); + for (ez = sve.exclusion_zones; ez; ez = ez->next) { + if (nhfp->structlevel) { + bwrite(nhfp->fd, (genericptr_t) &ez->zonetype, + sizeof ez->zonetype); + bwrite(nhfp->fd, (genericptr_t) &ez->lx, sizeof ez->lx); + bwrite(nhfp->fd, (genericptr_t) &ez->ly, sizeof ez->ly); + bwrite(nhfp->fd, (genericptr_t) &ez->hx, sizeof ez->hx); + bwrite(nhfp->fd, (genericptr_t) &ez->hy, sizeof ez->hy); + } } } } @@ -2587,8 +2613,9 @@ load_exclusions(NHFILE *nhfp) struct exclusion_zone *ez; int nez = 0; - if (nhfp->structlevel) + if (nhfp->structlevel) { mread(nhfp->fd, (genericptr_t) &nez, sizeof nez); + } while (nez-- > 0) { ez = (struct exclusion_zone *) alloc(sizeof *ez); @@ -2668,15 +2695,14 @@ staticfn void save_mapseen(NHFILE *nhfp, mapseen *mptr) { branch *curr; - int brindx; + int i, brindx; for (brindx = 0, curr = svb.branches; curr; curr = curr->next, ++brindx) if (curr == mptr->br) break; - if (nhfp->structlevel) - bwrite(nhfp->fd, (genericptr_t) &brindx, sizeof brindx); if (nhfp->structlevel) { + bwrite(nhfp->fd, (genericptr_t) &brindx, sizeof brindx); bwrite(nhfp->fd, (genericptr_t) &mptr->lev, sizeof mptr->lev); bwrite(nhfp->fd, (genericptr_t) &mptr->feat, sizeof mptr->feat); bwrite(nhfp->fd, (genericptr_t) &mptr->flags, sizeof mptr->flags); @@ -2686,11 +2712,15 @@ save_mapseen(NHFILE *nhfp, mapseen *mptr) if (mptr->custom_lth) { if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) mptr->custom, mptr->custom_lth); + bwrite(nhfp->fd, (genericptr_t) mptr->custom, + mptr->custom_lth); } } - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &mptr->msrooms, sizeof mptr->msrooms); + for (i = 0; i < ((MAXNROFROOMS + 1) * 2); ++i) { + if (nhfp->structlevel) { + bwrite(nhfp->fd, (genericptr_t) &mptr->msrooms[i], + sizeof (struct mapseen_rooms)); + } } savecemetery(nhfp, &mptr->final_resting_place); } @@ -2698,14 +2728,15 @@ save_mapseen(NHFILE *nhfp, mapseen *mptr) staticfn mapseen * load_mapseen(NHFILE *nhfp) { - int branchnum = 0, brindx; + int i, branchnum = 0, brindx; mapseen *load; branch *curr; load = (mapseen *) alloc(sizeof *load); - if (nhfp->structlevel) + if (nhfp->structlevel) { mread(nhfp->fd, (genericptr_t) &branchnum, sizeof branchnum); + } for (brindx = 0, curr = svb.branches; curr; curr = curr->next, ++brindx) if (brindx == branchnum) break; @@ -2723,14 +2754,18 @@ load_mapseen(NHFILE *nhfp) /* length doesn't include terminator (which isn't saved & restored) */ load->custom = (char *) alloc(load->custom_lth + 1); if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) load->custom, load->custom_lth); + mread(nhfp->fd, (genericptr_t) load->custom, + load->custom_lth); } load->custom[load->custom_lth] = '\0'; } else { load->custom = 0; } - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &load->msrooms, sizeof load->msrooms); + for (i = 0; i < ((MAXNROFROOMS + 1) * 2); ++i) { + if (nhfp->structlevel) { + mread(nhfp->fd, (genericptr_t) &load->msrooms[i], + sizeof (struct mapseen_rooms)); + } } restcemetery(nhfp, &load->final_resting_place); return load; diff --git a/src/end.c b/src/end.c index 90ea4a3ea..35dfc1803 100644 --- a/src/end.c +++ b/src/end.c @@ -1755,8 +1755,9 @@ save_killers(NHFILE *nhfp) if (perform_bwrite(nhfp)) { for (kptr = &svk.killer; kptr; kptr = kptr->next) { - if (nhfp->structlevel) + if (nhfp->structlevel) { bwrite(nhfp->fd, (genericptr_t) kptr, sizeof (struct kinfo)); + } } } if (release_data(nhfp)) { @@ -1774,8 +1775,9 @@ restore_killers(NHFILE *nhfp) struct kinfo *kptr; for (kptr = &svk.killer; kptr != (struct kinfo *) 0; kptr = kptr->next) { - if (nhfp->structlevel) - mread(nhfp->fd, (genericptr_t) kptr, sizeof(struct kinfo)); + if (nhfp->structlevel) { + mread(nhfp->fd, (genericptr_t) kptr, sizeof (struct kinfo)); + } if (kptr->next) { kptr->next = (struct kinfo *) alloc(sizeof (struct kinfo)); } diff --git a/src/engrave.c b/src/engrave.c index 9db32403d..2a300cfac 100644 --- a/src/engrave.c +++ b/src/engrave.c @@ -1532,9 +1532,10 @@ save_engravings(NHFILE *nhfp) dealloc_engr(ep); } if (perform_bwrite(nhfp)) { - if (nhfp->structlevel) + if (nhfp->structlevel) { bwrite(nhfp->fd, (genericptr_t) &no_more_engr, sizeof no_more_engr); + } } if (release_data(nhfp)) head_engr = 0; @@ -1548,9 +1549,9 @@ rest_engravings(NHFILE *nhfp) head_engr = 0; while (1) { - if (nhfp->structlevel) - mread(nhfp->fd, (genericptr_t) <h, sizeof (unsigned)); - + if (nhfp->structlevel) { + mread(nhfp->fd, (genericptr_t) <h, sizeof(unsigned)); + } if (lth == 0) return; ep = newengr(lth); diff --git a/src/files.c b/src/files.c index f40385d4b..5489b0f41 100644 --- a/src/files.c +++ b/src/files.c @@ -4258,7 +4258,6 @@ recover_savefile(void) struct version_info version_data; int processed[256]; char savename[SAVESIZE], errbuf[BUFSZ], indicator; - struct savefile_info sfi; char tmpplbuf[PL_NSIZ_PLUS]; const char *savewrite_failure = (const char *) 0; @@ -4269,7 +4268,6 @@ recover_savefile(void) * pid of creating process (ignored here) * level number for current level of save file * name of save file nethack would have created - * savefile info * player name * and game state */ @@ -4304,7 +4302,6 @@ recover_savefile(void) != sizeof filecmc) || (read(gnhfp->fd, (genericptr_t) &version_data, sizeof version_data) != sizeof version_data) - || (read(gnhfp->fd, (genericptr_t) &sfi, sizeof sfi) != sizeof sfi) || (read(gnhfp->fd, (genericptr_t) &pltmpsiz, sizeof pltmpsiz) != sizeof pltmpsiz) || (pltmpsiz > PL_NSIZ_PLUS) || (read(gnhfp->fd, (genericptr_t) &tmpplbuf, pltmpsiz) @@ -4317,8 +4314,8 @@ recover_savefile(void) /* save file should contain: * format indicator and cmc * version info - * savefile info - * player name + * plnametmp = player name size (int, 2 bytes) + * player name (PL_NSIZ_PLUS) * current level (including pets) * (non-level-based) game state * other levels @@ -4347,17 +4344,7 @@ recover_savefile(void) return FALSE; } - /* - * Our savefile output format might _not_ be structlevel. - * We have to check and use the correct output routine here. - */ - /*store_formatindicator(snhfp); */ store_version(snhfp); - - if (snhfp->structlevel) { - if (write(snhfp->fd, (genericptr_t) &sfi, sizeof sfi) != sizeof sfi) - savewrite_failure = "savefileinfo"; - } if (savewrite_failure) goto cleanup; diff --git a/src/light.c b/src/light.c index e89c316ca..f783855eb 100644 --- a/src/light.c +++ b/src/light.c @@ -482,13 +482,15 @@ restore_light_sources(NHFILE *nhfp) light_source *ls; /* restore elements */ - if (nhfp->structlevel) + if (nhfp->structlevel) { mread(nhfp->fd, (genericptr_t) &count, sizeof count); + } while (count-- > 0) { ls = (light_source *) alloc(sizeof(light_source)); - if (nhfp->structlevel) + if (nhfp->structlevel) { mread(nhfp->fd, (genericptr_t) ls, sizeof(light_source)); + } ls->next = gl.light_base; gl.light_base = ls; } @@ -639,8 +641,9 @@ write_ls(NHFILE *nhfp, light_source *ls) if (ls->type == LS_OBJECT || ls->type == LS_MONSTER) { if (ls->flags & LSF_NEEDS_FIXUP) { - if (nhfp->structlevel) + if (nhfp->structlevel) { bwrite(nhfp->fd, (genericptr_t) ls, sizeof(light_source)); + } } else { /* replace object pointer with id for write, then put back */ arg_save = ls->id; @@ -692,8 +695,9 @@ write_ls(NHFILE *nhfp, light_source *ls) /* TODO: cleanup this ls, or skip writing it */ } ls->flags |= LSF_NEEDS_FIXUP; - if (nhfp->structlevel) + if (nhfp->structlevel) { bwrite(nhfp->fd, (genericptr_t) ls, sizeof(light_source)); + } ls->id = arg_save; ls->flags &= ~LSF_NEEDS_FIXUP; ls->flags &= ~LSF_IS_PROBLEMATIC; diff --git a/src/mdlib.c b/src/mdlib.c index 9e7700cc8..dc69e8a28 100644 --- a/src/mdlib.c +++ b/src/mdlib.c @@ -87,6 +87,7 @@ staticfn void build_options(void); staticfn int count_and_validate_winopts(void); staticfn void opt_out_words(char *, int *) NONNULLPTRS; staticfn void build_savebones_compat_string(void); +staticfn const char *datamodel(void); static int idxopttext, done_runtime_opt_init_once = 0; #define MAXOPT 60 /* 3.7: currently 40 lines get inserted into opttext[] */ @@ -228,30 +229,49 @@ static struct soundlib_information soundlib_opts[] = { }; #endif /* !MAKEDEFS_C */ -/* - * Use this to explicitly mask out features during version checks. - * - * ZEROCOMP, RLECOMP, and ZLIB_COMP describe compression features - * that the port/platform which wrote the savefile was capable of - * dealing with. Don't reject a savefile just because the port - * reading the savefile doesn't match on all/some of them. - * The actual compression features used to produce the savefile are - * recorded in the savefile_info structure immediately following the - * version_info, and that is what needs to be checked against the - * feature set of the port that is reading the savefile back in. - * That check is done in src/restore.c now. - * - */ unsigned long md_ignored_features(void) { return (0UL | (1UL << 19) /* SCORE_ON_BOTL */ - | (1UL << 27) /* ZEROCOMP */ - | (1UL << 28) /* RLECOMP */ ); } +#define MAX_D 5 +struct datamodel_information { + int sz[MAX_D]; + const char *datamodel; +}; + +static struct datamodel_information dm[] = { + { { (int) sizeof(short), (int) sizeof(int), (int) sizeof(long), + (int) sizeof(long long), (int) sizeof(genericptr_t) }, + "" }, + { { 2, 4, 4, 8, 4 }, "ILP32LL64" }, /* Windows, Unix x86 */ + { { 2, 4, 4, 8, 8 }, "IL32LLP64" }, /* Windows x64 */ + { { 2, 4, 8, 8, 8 }, "I32LP64" }, /* Unix 64-bit */ + { { 2, 8, 8, 8, 8 }, "ILP64" }, /* HAL, SPARC64 */ +}; + +staticfn const char * +datamodel(void) +{ + int i, j, matchcount; + static const char *unknown = "Unknown"; + + for (i = 1; i < SIZE(dm); ++i) { + matchcount = 0; + for (j = 0; j < MAX_D; ++j) { + if (dm[0].sz[j] == dm[i].sz[j]) + ++matchcount; + } + if (matchcount == MAX_D) + return dm[i].datamodel; + } + return unknown; +} +#undef MAX_D + staticfn void make_version(void) { @@ -285,15 +305,6 @@ make_version(void) #endif #ifdef SCORE_ON_BOTL | (1L << 19) -#endif -/* data format (27..31) - * External compression methods such as COMPRESS and ZLIB_COMP - * do not affect the contents and are thus excluded from here */ -#ifdef ZEROCOMP - | (1L << 27) -#endif -#ifdef RLECOMP - | (1L << 28) #endif ); /* @@ -307,15 +318,6 @@ make_version(void) version.entity_count = (version.entity_count << 12) | (unsigned long) i; i = NUMMONS; version.entity_count = (version.entity_count << 12) | (unsigned long) i; - /* - * Value used for compiler (word size/field alignment/padding) check. - */ - version.struct_sizes1 = - (((unsigned long) sizeof(struct context_info) << 24) - | ((unsigned long) sizeof(struct obj) << 17) - | ((unsigned long) sizeof(struct monst) << 10) - | ((unsigned long) sizeof(struct you))); - version.struct_sizes2 = (((unsigned long) sizeof(struct flag) << 10)); /* free bits in here */ return; } @@ -611,12 +613,6 @@ static const char *const build_opts[] = { #ifdef VISION_TABLES "vision tables", #endif -#ifdef ZEROCOMP - "zero-compressed save files", -#endif -#ifdef RLECOMP - "run-length compression of map in save files", -#endif #ifdef SYSCF "system configuration at run-time", #endif @@ -728,6 +724,8 @@ build_options(void) STOREOPTTEXT(optbuf); optbuf[0] = '\0'; length = COLNO + 1; /* force 1st item onto new line */ + Strcat(strcpy(buf, datamodel()), " data model,"); + opt_out_words(buf, &length); for (i = 0; i < SIZE(build_opts); i++) { #if !defined(MAKEDEFS_C) && defined(FOR_RUNTIME) #ifdef WIN32 diff --git a/src/mkmaze.c b/src/mkmaze.c index 903330cf3..799c2b6b8 100644 --- a/src/mkmaze.c +++ b/src/mkmaze.c @@ -1732,8 +1732,9 @@ save_waterlevel(NHFILE *nhfp) bwrite(nhfp->fd, (genericptr_t) &svy.ymax, sizeof(int)); } for (b = svb.bbubbles; b; b = b->next) { - if (nhfp->structlevel) + if (nhfp->structlevel) { bwrite(nhfp->fd, (genericptr_t) b, sizeof(struct bubble)); + } } } if (release_data(nhfp)) @@ -1759,8 +1760,9 @@ restore_waterlevel(NHFILE *nhfp) for (i = 0; i < n; i++) { btmp = b; b = (struct bubble *) alloc((unsigned) sizeof *b); - if (nhfp->structlevel) + if (nhfp->structlevel) { mread(nhfp->fd, (genericptr_t) b, (unsigned) sizeof *b); + } if (btmp) { btmp->next = b; b->prev = btmp; diff --git a/src/mkroom.c b/src/mkroom.c index c9aecb15a..d96eca758 100644 --- a/src/mkroom.c +++ b/src/mkroom.c @@ -845,8 +845,9 @@ save_room(NHFILE *nhfp, struct mkroom *r) * of writing the whole structure. That is I should not write * the gs.subrooms pointers, but who cares ? */ - if (nhfp->structlevel) + if (nhfp->structlevel) { bwrite(nhfp->fd, (genericptr_t) r, sizeof (struct mkroom)); + } for (i = 0; i < r->nsubrooms; i++) { save_room(nhfp, r->sbrooms[i]); } @@ -861,8 +862,9 @@ save_rooms(NHFILE *nhfp) short i; /* First, write the number of rooms */ - if (nhfp->structlevel) - bwrite(nhfp->fd, (genericptr_t) &svn.nroom, sizeof(svn.nroom)); + if (nhfp->structlevel) { + bwrite(nhfp->fd, (genericptr_t) &svn.nroom, sizeof svn.nroom); + } for (i = 0; i < svn.nroom; i++) save_room(nhfp, &svr.rooms[i]); } @@ -872,8 +874,9 @@ rest_room(NHFILE *nhfp, struct mkroom *r) { short i; - if (nhfp->structlevel) - mread(nhfp->fd, (genericptr_t) r, sizeof(struct mkroom)); + if (nhfp->structlevel) { + mread(nhfp->fd, (genericptr_t) r, sizeof (struct mkroom)); + } for (i = 0; i < r->nsubrooms; i++) { r->sbrooms[i] = &gs.subrooms[gn.nsubroom]; @@ -891,8 +894,9 @@ rest_rooms(NHFILE *nhfp) { short i; - if (nhfp->structlevel) - mread(nhfp->fd, (genericptr_t) &svn.nroom, sizeof(svn.nroom)); + if (nhfp->structlevel) { + mread(nhfp->fd, (genericptr_t) &svn.nroom, sizeof svn.nroom); + } gn.nsubroom = 0; for (i = 0; i < svn.nroom; i++) { diff --git a/src/nhlua.c b/src/nhlua.c index 6bc523e7e..ed9b3d877 100644 --- a/src/nhlua.c +++ b/src/nhlua.c @@ -1274,9 +1274,11 @@ save_luadata(NHFILE *nhfp) if (!lua_data) lua_data = dupstr(emptystr); lua_data_len = Strlen(lua_data) + 1; /* +1: include the terminator */ - bwrite(nhfp->fd, (genericptr_t) &lua_data_len, - (unsigned) sizeof lua_data_len); - bwrite(nhfp->fd, (genericptr_t) lua_data, lua_data_len); + if (nhfp->structlevel) { + bwrite(nhfp->fd, (genericptr_t) &lua_data_len, + (unsigned) sizeof lua_data_len); + bwrite(nhfp->fd, (genericptr_t) lua_data, lua_data_len); + } free(lua_data); } @@ -1284,13 +1286,16 @@ save_luadata(NHFILE *nhfp) void restore_luadata(NHFILE *nhfp) { - unsigned lua_data_len; + unsigned lua_data_len = 0; char *lua_data; - - mread(nhfp->fd, (genericptr_t) &lua_data_len, - (unsigned) sizeof lua_data_len); + if (nhfp->structlevel) { + mread(nhfp->fd, (genericptr_t) &lua_data_len, + (unsigned) sizeof lua_data_len); + } lua_data = (char *) alloc(lua_data_len); - mread(nhfp->fd, (genericptr_t) lua_data, lua_data_len); + if (nhfp->structlevel) { + mread(nhfp->fd, (genericptr_t) lua_data, lua_data_len); + } if (!gl.luacore) l_nhcore_init(); luaL_loadstring(gl.luacore, lua_data); diff --git a/src/o_init.c b/src/o_init.c index 1538c298d..bebc4f866 100644 --- a/src/o_init.c +++ b/src/o_init.c @@ -376,11 +376,21 @@ savenames(NHFILE *nhfp) unsigned int len; if (perform_bwrite(nhfp)) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) svb.bases, sizeof svb.bases); - bwrite(nhfp->fd, (genericptr_t) svd.disco, sizeof svd.disco); - bwrite(nhfp->fd, (genericptr_t) objects, - sizeof(struct objclass) * NUM_OBJECTS); + for (i = 0; i < (MAXOCLASSES + 2); ++i) { + if (nhfp->structlevel) { + bwrite(nhfp->fd, (genericptr_t) &svb.bases[i], sizeof (int)); + } + } + for (i = 0; i < NUM_OBJECTS; ++i) { + if (nhfp->structlevel) { + bwrite(nhfp->fd, (genericptr_t) &svd.disco[i], sizeof (short)); + } + } + for (i = 0; i < NUM_OBJECTS; ++i) { + if (nhfp->structlevel) { + bwrite(nhfp->fd, (genericptr_t) &objects[i], + sizeof (struct objclass)); + } } } /* as long as we use only one version of Hack we @@ -392,7 +402,7 @@ savenames(NHFILE *nhfp) len = Strlen(objects[i].oc_uname) + 1; if (nhfp->structlevel) { bwrite(nhfp->fd, (genericptr_t) &len, sizeof len); - bwrite(nhfp->fd, (genericptr_t) objects[i].oc_uname, len); + bwrite(nhfp->fd, (genericptr_t) &objects[i].oc_uname[0], len); } } if (release_data(nhfp)) { @@ -421,7 +431,7 @@ restnames(NHFILE *nhfp) } objects[i].oc_uname = (char *) alloc(len); if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) objects[i].oc_uname, len); + mread(nhfp->fd, (genericptr_t) &objects[i].oc_uname[0], len); } } } diff --git a/src/region.c b/src/region.c index 60001f866..b38ba0d7c 100644 --- a/src/region.c +++ b/src/region.c @@ -754,25 +754,29 @@ save_regions(NHFILE *nhfp) bwrite(nhfp->fd, (genericptr_t) &r->nrects, sizeof (short)); } for (j = 0; j < r->nrects; j++) { - if (nhfp->structlevel) + if (nhfp->structlevel) { bwrite(nhfp->fd, (genericptr_t) &r->rects[j], sizeof (NhRect)); + } } - if (nhfp->structlevel) + if (nhfp->structlevel) { bwrite(nhfp->fd, (genericptr_t) &r->attach_2_u, sizeof (boolean)); - if (nhfp->structlevel) bwrite(nhfp->fd, (genericptr_t) &r->attach_2_m, sizeof (unsigned)); + } n = !r->enter_msg ? 0U : (unsigned) strlen(r->enter_msg); - if (nhfp->structlevel) + if (nhfp->structlevel) { bwrite(nhfp->fd, (genericptr_t) &n, sizeof n); + } if (n > 0) { - if (nhfp->structlevel) + if (nhfp->structlevel) { bwrite(nhfp->fd, (genericptr_t) r->enter_msg, n); + } } n = !r->leave_msg ? 0U : (unsigned) strlen(r->leave_msg); - if (nhfp->structlevel) + if (nhfp->structlevel) { bwrite(nhfp->fd, (genericptr_t) &n, sizeof n); + } if (n > 0) { if (nhfp->structlevel) { bwrite(nhfp->fd, (genericptr_t) r->leave_msg, n); @@ -791,9 +795,10 @@ save_regions(NHFILE *nhfp) bwrite(nhfp->fd, (genericptr_t) &r->n_monst, sizeof (short)); } for (j = 0; j < r->n_monst; j++) { - if (nhfp->structlevel) + if (nhfp->structlevel) { bwrite(nhfp->fd, (genericptr_t) &r->monsters[j], sizeof (unsigned)); + } } if (nhfp->structlevel) { bwrite(nhfp->fd, (genericptr_t) &r->visible, sizeof (boolean)); @@ -818,15 +823,17 @@ rest_regions(NHFILE *nhfp) boolean ghostly = (nhfp->ftype == NHF_BONESFILE); clear_regions(); /* Just for security */ - if (nhfp->structlevel) - mread(nhfp->fd, (genericptr_t) &tmstamp, sizeof (tmstamp)); + if (nhfp->structlevel) { + mread(nhfp->fd, (genericptr_t) &tmstamp, sizeof(tmstamp)); + } if (ghostly) tmstamp = 0; else tmstamp = (svm.moves - tmstamp); - if (nhfp->structlevel) + if (nhfp->structlevel) { mread(nhfp->fd, (genericptr_t) &svn.n_regions, sizeof svn.n_regions); + } gm.max_regions = svn.n_regions; if (svn.n_regions > 0) @@ -842,40 +849,43 @@ rest_regions(NHFILE *nhfp) else r->rects = (NhRect *) 0; for (j = 0; j < r->nrects; j++) { - if (nhfp->structlevel) - mread(nhfp->fd, (genericptr_t) &r->rects[j], sizeof (NhRect)); + if (nhfp->structlevel) { + mread(nhfp->fd, (genericptr_t) &r->rects[j], sizeof(NhRect)); + } } if (nhfp->structlevel) { mread(nhfp->fd, (genericptr_t) &r->attach_2_u, sizeof (boolean)); mread(nhfp->fd, (genericptr_t) &r->attach_2_m, sizeof (unsigned)); - } - - if (nhfp->structlevel) mread(nhfp->fd, (genericptr_t) &n, sizeof n); + } if (n > 0) { msg_buf = (char *) alloc(n + 1); if (nhfp->structlevel) { mread(nhfp->fd, (genericptr_t) msg_buf, n); } msg_buf[n] = '\0'; - } else + } else { msg_buf = (char *) 0; + } r->enter_msg = (const char *) msg_buf; - if (nhfp->structlevel) + if (nhfp->structlevel) { mread(nhfp->fd, (genericptr_t) &n, sizeof n); + } if (n > 0) { msg_buf = (char *) alloc(n + 1); if (nhfp->structlevel) { mread(nhfp->fd, (genericptr_t) msg_buf, n); } msg_buf[n] = '\0'; - } else - msg_buf = (char *) 0; + } else { + msg_buf = (char *) 0; + } r->leave_msg = (const char *) msg_buf; - if (nhfp->structlevel) - mread(nhfp->fd, (genericptr_t) &r->ttl, sizeof (long)); + if (nhfp->structlevel) { + mread(nhfp->fd, (genericptr_t) &r->ttl, sizeof(long)); + } /* check for expired region */ if (r->ttl >= 0L) r->ttl = (r->ttl > tmstamp) ? r->ttl - tmstamp : 0L; @@ -893,17 +903,19 @@ rest_regions(NHFILE *nhfp) clear_hero_inside(r); clear_heros_fault(r); } - if (nhfp->structlevel) + if (nhfp->structlevel) { mread(nhfp->fd, (genericptr_t) &r->n_monst, sizeof (short)); + } if (r->n_monst > 0) r->monsters = (unsigned *) alloc(r->n_monst * sizeof (unsigned)); else r->monsters = (unsigned *) 0; r->max_monst = r->n_monst; for (j = 0; j < r->n_monst; j++) { - if (nhfp->structlevel) + if (nhfp->structlevel) { mread(nhfp->fd, (genericptr_t) &r->monsters[j], - sizeof (unsigned)); + sizeof(unsigned)); + } } if (nhfp->structlevel) { mread(nhfp->fd, (genericptr_t) &r->visible, sizeof (boolean)); diff --git a/src/restore.c b/src/restore.c index c15cce775..05292b5d9 100644 --- a/src/restore.c +++ b/src/restore.c @@ -11,12 +11,6 @@ extern int dotcnt; /* shared with save */ extern int dotrow; /* shared with save */ #endif -#ifdef ZEROCOMP -staticfn void zerocomp_minit(void); -staticfn void zerocomp_mread(int, genericptr_t, unsigned int); -staticfn int zerocomp_mgetc(void); -#endif - staticfn void find_lev_obj(void); staticfn void restlevchn(NHFILE *); staticfn void restdamage(NHFILE *); @@ -26,16 +20,19 @@ staticfn void restmon(NHFILE *, struct monst *); staticfn struct monst *restmonchn(NHFILE *); staticfn struct fruit *loadfruitchn(NHFILE *); staticfn void freefruitchn(struct fruit *); +staticfn void rest_levl(NHFILE *); +staticfn void rest_stairs(NHFILE *); staticfn void ghostfruit(struct obj *); staticfn boolean restgamestate(NHFILE *); staticfn void restlevelstate(void); staticfn int restlevelfile(xint8); staticfn void rest_bubbles(NHFILE *); staticfn void restore_gamelog(NHFILE *); -staticfn void restore_msghistory(NHFILE *); staticfn void reset_oattached_mids(boolean); -staticfn void rest_levl(NHFILE *, boolean); -staticfn void rest_stairs(NHFILE *); +staticfn boolean restgamestate(NHFILE *); +staticfn void rest_bubbles(NHFILE *); +staticfn void restore_gamelog(NHFILE *); +staticfn void restore_msghistory(NHFILE *); /* * Save a mapping of IDs from ghost levels to the current level. This @@ -132,13 +129,14 @@ restlevchn(NHFILE *nhfp) s_level *tmplev, *x; svs.sp_levchn = (s_level *) 0; - if (nhfp->structlevel) + if (nhfp->structlevel) { Mread(nhfp->fd, &cnt, sizeof cnt); - + } for (; cnt > 0; cnt--) { tmplev = (s_level *) alloc(sizeof(s_level)); - if (nhfp->structlevel) + if (nhfp->structlevel) { Mread(nhfp->fd, tmplev, sizeof *tmplev); + } if (!svs.sp_levchn) svs.sp_levchn = tmplev; @@ -159,16 +157,18 @@ restdamage(NHFILE *nhfp) struct damage *tmp_dam; boolean ghostly = (nhfp->ftype == NHF_BONESFILE); - if (nhfp->structlevel) + if (nhfp->structlevel) { Mread(nhfp->fd, &dmgcount, sizeof dmgcount); + } counter = (int) dmgcount; if (!counter) return; do { tmp_dam = (struct damage *) alloc(sizeof *tmp_dam); - if (nhfp->structlevel) + if (nhfp->structlevel) { Mread(nhfp->fd, tmp_dam, sizeof *tmp_dam); + } if (ghostly) tmp_dam->when += (svm.moves - go.omoves); @@ -184,8 +184,9 @@ restobj(NHFILE *nhfp, struct obj *otmp) { int buflen = 0; - if (nhfp->structlevel) + if (nhfp->structlevel) { Mread(nhfp->fd, otmp, sizeof *otmp); + } otmp->lua_ref_cnt = 0; /* next object pointers are invalid; otmp->cobj needs to be left @@ -196,18 +197,20 @@ restobj(NHFILE *nhfp, struct obj *otmp) otmp->oextra = newoextra(); /* oname - object's name */ - if (nhfp->structlevel) + if (nhfp->structlevel) { Mread(nhfp->fd, &buflen, sizeof buflen); - + } if (buflen > 0) { /* includes terminating '\0' */ new_oname(otmp, buflen); - if (nhfp->structlevel) + if (nhfp->structlevel) { Mread(nhfp->fd, ONAME(otmp), buflen); + } } /* omonst - corpse or statue might retain full monster details */ - if (nhfp->structlevel) + if (nhfp->structlevel) { Mread(nhfp->fd, &buflen, sizeof buflen); + } if (buflen > 0) { newomonst(otmp); /* this is actually a monst struct, so we @@ -216,21 +219,24 @@ restobj(NHFILE *nhfp, struct obj *otmp) } /* omailcmd - feedback mechanism for scroll of mail */ - if (nhfp->structlevel) + if (nhfp->structlevel) { Mread(nhfp->fd, &buflen, sizeof buflen); + } if (buflen > 0) { char *omailcmd = (char *) alloc(buflen); - if (nhfp->structlevel) + if (nhfp->structlevel) { Mread(nhfp->fd, omailcmd, buflen); + } new_omailcmd(otmp, omailcmd); free((genericptr_t) omailcmd); } /* omid - monster id number, connecting corpse to ghost */ newomid(otmp); /* superfluous; we're already allocated otmp->oextra */ - if (nhfp->structlevel) + if (nhfp->structlevel) { Mread(nhfp->fd, &OMID(otmp), sizeof OMID(otmp)); + } } } @@ -243,9 +249,9 @@ restobjchn(NHFILE *nhfp, boolean frozen) boolean ghostly = (nhfp->ftype == NHF_BONESFILE); while (1) { - if (nhfp->structlevel) + if (nhfp->structlevel) { Mread(nhfp->fd, &buflen, sizeof buflen); - + } if (buflen == -1) break; @@ -306,10 +312,11 @@ restobjchn(NHFILE *nhfp, boolean frozen) staticfn void restmon(NHFILE *nhfp, struct monst *mtmp) { - int buflen = 0; + int buflen = 0, mc = 0; - if (nhfp->structlevel) + if (nhfp->structlevel) { Mread(nhfp->fd, mtmp, sizeof *mtmp); + } /* next monster pointer is invalid */ mtmp->nmon = (struct monst *) 0; @@ -318,71 +325,85 @@ restmon(NHFILE *nhfp, struct monst *mtmp) mtmp->mextra = newmextra(); /* mgivenname - monster's name */ - if (nhfp->structlevel) + if (nhfp->structlevel) { Mread(nhfp->fd, &buflen, sizeof buflen); + } if (buflen > 0) { /* includes terminating '\0' */ new_mgivenname(mtmp, buflen); - if (nhfp->structlevel) + if (nhfp->structlevel) { Mread(nhfp->fd, MGIVENNAME(mtmp), buflen); + } } /* egd - vault guard */ - if (nhfp->structlevel) + if (nhfp->structlevel) { Mread(nhfp->fd, &buflen, sizeof buflen); - + } if (buflen > 0) { newegd(mtmp); - if (nhfp->structlevel) - Mread(nhfp->fd, EGD(mtmp), sizeof (struct egd)); + if (nhfp->structlevel) { + Mread(nhfp->fd, EGD(mtmp), sizeof(struct egd)); + } } /* epri - temple priest */ - if (nhfp->structlevel) + if (nhfp->structlevel) { Mread(nhfp->fd, &buflen, sizeof buflen); + } if (buflen > 0) { newepri(mtmp); - if (nhfp->structlevel) - Mread(nhfp->fd, EPRI(mtmp), sizeof (struct epri)); + if (nhfp->structlevel) { + Mread(nhfp->fd, EPRI(mtmp), sizeof(struct epri)); + } } /* eshk - shopkeeper */ - if (nhfp->structlevel) + if (nhfp->structlevel) { Mread(nhfp->fd, &buflen, sizeof buflen); + } if (buflen > 0) { neweshk(mtmp); - if (nhfp->structlevel) - Mread(nhfp->fd, ESHK(mtmp), sizeof (struct eshk)); + if (nhfp->structlevel) { + Mread(nhfp->fd, ESHK(mtmp), sizeof(struct eshk)); + } } /* emin - minion */ - if (nhfp->structlevel) + if (nhfp->structlevel) { Mread(nhfp->fd, &buflen, sizeof buflen); + } if (buflen > 0) { newemin(mtmp); - if (nhfp->structlevel) - Mread(nhfp->fd, EMIN(mtmp), sizeof (struct emin)); + if (nhfp->structlevel) { + Mread(nhfp->fd, EMIN(mtmp), sizeof(struct emin)); + } } /* edog - pet */ - if (nhfp->structlevel) + if (nhfp->structlevel) { Mread(nhfp->fd, &buflen, sizeof buflen); + } if (buflen > 0) { newedog(mtmp); - if (nhfp->structlevel) - Mread(nhfp->fd, EDOG(mtmp), sizeof (struct edog)); + if (nhfp->structlevel) { + Mread(nhfp->fd, EDOG(mtmp), sizeof(struct edog)); + } /* sanity check to prevent rn2(0) */ if (EDOG(mtmp)->apport <= 0) { EDOG(mtmp)->apport = 1; } } /* ebones */ - if (nhfp->structlevel) + if (nhfp->structlevel) { Mread(nhfp->fd, &buflen, sizeof buflen); + } if (buflen > 0) { newebones(mtmp); - if (nhfp->structlevel) - Mread(nhfp->fd, EBONES(mtmp), - sizeof (struct ebones)); + if (nhfp->structlevel) { + Mread(nhfp->fd, EBONES(mtmp), sizeof(struct ebones)); + } } /* mcorpsenm - obj->corpsenm for mimic posing as corpse or statue (inline int rather than pointer to something) */ - if (nhfp->structlevel) - Mread(nhfp->fd, &MCORPSENM(mtmp), sizeof MCORPSENM(mtmp)); + if (nhfp->structlevel) { + Mread(nhfp->fd, &mc, sizeof mc); + } + MCORPSENM(mtmp) = mc; } /* mextra */ } @@ -395,8 +416,9 @@ restmonchn(NHFILE *nhfp) boolean ghostly = (nhfp->ftype == NHF_BONESFILE); while (1) { - if (nhfp->structlevel) + if (nhfp->structlevel) { Mread(nhfp->fd, &buflen, sizeof buflen); + } if (buflen == -1) break; @@ -472,8 +494,9 @@ loadfruitchn(NHFILE *nhfp) flist = 0; for (;;) { fnext = newfruit(); - if (nhfp->structlevel) + if (nhfp->structlevel) { Mread(nhfp->fd, fnext, sizeof *fnext); + } if (fnext->fid != 0) { fnext->nextf = flist; flist = fnext; @@ -520,6 +543,7 @@ ghostfruit(struct obj *otmp) staticfn boolean restgamestate(NHFILE *nhfp) { + int i; struct flag newgameflags; struct context_info newgamecontext; /* all 0, but has some pointers */ struct obj *otmp; @@ -528,8 +552,9 @@ restgamestate(NHFILE *nhfp) unsigned long uid = 0; boolean defer_perm_invent, restoring_special; - if (nhfp->structlevel) + if (nhfp->structlevel) { Mread(nhfp->fd, &uid, sizeof uid); + } if (SYSOPT_CHECK_SAVE_UID && uid != (unsigned long) getuid()) { /* strange ... */ @@ -541,8 +566,9 @@ restgamestate(NHFILE *nhfp) } newgamecontext = svc.context; /* copy statically init'd context */ - if (nhfp->structlevel) + if (nhfp->structlevel) { Mread(nhfp->fd, &svc.context, sizeof svc.context); + } svc.context.warntype.species = (ismnum(svc.context.warntype.speciesidx)) ? &mons[svc.context.warntype.speciesidx] : (struct permonst *) 0; @@ -554,8 +580,9 @@ restgamestate(NHFILE *nhfp) file option values instead of keeping old save file option values if partial restore fails and we resort to starting a new game */ newgameflags = flags; - if (nhfp->structlevel) + if (nhfp->structlevel) { Mread(nhfp->fd, &flags, sizeof flags); + } /* avoid keeping permanent inventory window up to date during restore (setworn() calls update_inventory); attempting to include the cost @@ -583,8 +610,9 @@ restgamestate(NHFILE *nhfp) #ifdef AMII_GRAPHICS amii_setpens(amii_numcolors); /* use colors from save file */ #endif - if (nhfp->structlevel) + if (nhfp->structlevel) { Mread(nhfp->fd, &u, sizeof u); + } gy.youmonst.cham = u.mcham; if (restoring_special && iflags.explore_error_flag) { @@ -594,15 +622,17 @@ restgamestate(NHFILE *nhfp) u.uhp = 0; } - if (nhfp->structlevel) + if (nhfp->structlevel) { Mread(nhfp->fd, timebuf, 14); + } timebuf[14] = '\0'; ubirthday = time_from_yyyymmddhhmmss(timebuf); - if (nhfp->structlevel) + if (nhfp->structlevel) { Mread(nhfp->fd, &urealtime.realtime, sizeof urealtime.realtime); - - if (nhfp->structlevel) + } + if (nhfp->structlevel) { Mread(nhfp->fd, timebuf, 14); + } timebuf[14] = '\0'; urealtime.start_timing = time_from_yyyymmddhhmmss(timebuf); @@ -653,10 +683,11 @@ restgamestate(NHFILE *nhfp) gm.migrating_objs = restobjchn(nhfp, FALSE); gm.migrating_mons = restmonchn(nhfp); - if (nhfp->structlevel) { - Mread(nhfp->fd, &svm.mvitals[0], sizeof svm.mvitals); + for (i = 0; i < NUMMONS; ++i) { + if (nhfp->structlevel) { + Mread(nhfp->fd, &svm.mvitals[i], sizeof (struct mvitals)); + } } - /* * There are some things after this that can have unintended display * side-effects too early in the game. @@ -683,10 +714,17 @@ restgamestate(NHFILE *nhfp) restlevchn(nhfp); if (nhfp->structlevel) { Mread(nhfp->fd, &svm.moves, sizeof svm.moves); - /* hero_seq isn't saved and restored because it can be recalculated */ - gh.hero_seq = svm.moves << 3; /* normally handled in moveloop() */ + } + /* hero_seq isn't saved and restored because it can be recalculated */ + gh.hero_seq = svm.moves << 3; /* normally handled in moveloop() */ + if (nhfp->structlevel) { Mread(nhfp->fd, &svq.quest_status, sizeof svq.quest_status); - Mread(nhfp->fd, svs.spl_book, (MAXSPELL + 1) * sizeof (struct spell)); + } + for (i = 0; i < (MAXSPELL + 1); ++i) { + if (nhfp->structlevel) { + Mread(nhfp->fd, &svs.spl_book[i], + sizeof (struct spell)); + } } restore_artifacts(nhfp); restore_oracles(nhfp); @@ -819,9 +857,9 @@ dorecover(NHFILE *nhfp) while (1) { if (nhfp->structlevel) { Mread(nhfp->fd, <mp, sizeof ltmp); - if (restoreinfo.mread_flags == -1) - break; } + if (restoreinfo.mread_flags == -1) + break; getlev(nhfp, 0, ltmp); #ifdef MICRO curs(WIN_MAP, 1 + dotcnt++, dotrow); @@ -839,6 +877,7 @@ dorecover(NHFILE *nhfp) return rtmp; /* dorecover called recursively */ } restoreinfo.mread_flags = 0; + rewind_nhfile(nhfp); /* return to beginning of file */ (void) validate(nhfp, (char *) 0, FALSE); get_plname_from_file(nhfp, svp.plname, TRUE); @@ -939,14 +978,16 @@ restcemetery(NHFILE *nhfp, struct cemetery **cemeteryaddr) struct cemetery *bonesinfo, **bonesaddr; int cflag = 0; - if (nhfp->structlevel) + if (nhfp->structlevel) { Mread(nhfp->fd, &cflag, sizeof cflag); + } if (cflag == 0) { bonesaddr = cemeteryaddr; do { bonesinfo = (struct cemetery *) alloc(sizeof *bonesinfo); - if (nhfp->structlevel) + if (nhfp->structlevel) { Mread(nhfp->fd, bonesinfo, sizeof *bonesinfo); + } *bonesaddr = bonesinfo; bonesaddr = &(*bonesaddr)->next; } while (*bonesaddr); @@ -957,46 +998,16 @@ restcemetery(NHFILE *nhfp, struct cemetery **cemeteryaddr) /*ARGSUSED*/ staticfn void -rest_levl( - NHFILE *nhfp, -#ifdef RLECOMP - boolean rlecomp -#else - boolean rlecomp UNUSED -#endif -) +rest_levl(NHFILE *nhfp) { -#ifdef RLECOMP - short i, j; - uchar len; - struct rm r; + int c, r; - if (rlecomp) { - (void) memset((genericptr_t) &r, 0, sizeof(r)); - i = 0; - j = 0; - len = 0; - while (i < ROWNO) { - while (j < COLNO) { - if (len > 0) { - levl[j][i] = r; - len -= 1; - j += 1; - } else { - if (nhfp->structlevel) { - Mread(nhfp->fd, &len, sizeof len); - Mread(nhfp->fd, &r, sizeof r); - } - } + for (c = 0; c < COLNO; ++c) { + for (r = 0; r < ROWNO; ++r) { + if (nhfp->structlevel) { + Mread(nhfp->fd, &levl[c][r], sizeof (struct rm)); } - j = 0; - i += 1; } - return; - } -#endif /* RLECOMP */ - if (nhfp->structlevel) { - Mread(nhfp->fd, levl, sizeof levl); } } @@ -1015,12 +1026,14 @@ getlev(NHFILE *nhfp, int pid, xint8 lev) { struct trap *trap; struct monst *mtmp; - long elapsed; branch *br; + int x, y; + long elapsed = 0L; int hpid = 0; xint8 dlvl = 0; - int x, y; + int i, c, r; boolean ghostly = (nhfp->ftype == NHF_BONESFILE); + coord *tmpc = 0; #ifdef TOS short tlev; #endif @@ -1041,18 +1054,13 @@ getlev(NHFILE *nhfp, int pid, xint8 lev) go.oldfruit = loadfruitchn(nhfp); /* First some sanity checks */ - if (nhfp->structlevel) + if (nhfp->structlevel) { Mread(nhfp->fd, &hpid, sizeof hpid); + } -/* CHECK: This may prevent restoration */ -#ifdef TOS - if (nhfp->structlevel) - Mread(nhfp->fd, &tlev, sizeof tlev); - dlvl = tlev & 0x00ff; -#else - if (nhfp->structlevel) + if (nhfp->structlevel) { Mread(nhfp->fd, &dlvl, sizeof dlvl); -#endif + } if ((pid && pid != hpid) || (lev && dlvl != lev)) { char trickbuf[BUFSZ]; @@ -1066,48 +1074,58 @@ getlev(NHFILE *nhfp, int pid, xint8 lev) trickery(trickbuf); } restcemetery(nhfp, &svl.level.bonesinfo); - rest_levl(nhfp, - (boolean) ((sfrestinfo.sfi1 & SFI1_RLECOMP) == SFI1_RLECOMP)); - if (nhfp->structlevel) { - Mread(nhfp->fd, svl.lastseentyp, sizeof svl.lastseentyp); - Mread(nhfp->fd, &go.omoves, sizeof go.omoves); - } + rest_levl(nhfp); + for (c = 0; c < COLNO; ++c) + for (r = 0; r < ROWNO; ++r) { + if (nhfp->structlevel) { + Mread(nhfp->fd, &svl.lastseentyp[c][r], sizeof (schar)); + } + } + Mread(nhfp->fd, &go.omoves, sizeof go.omoves); elapsed = svm.moves - go.omoves; + rest_stairs(nhfp); if (nhfp->structlevel) { - rest_stairs(nhfp); Mread(nhfp->fd, &svu.updest, sizeof svu.updest); Mread(nhfp->fd, &svd.dndest, sizeof svd.dndest); Mread(nhfp->fd, &svl.level.flags, sizeof svl.level.flags); - if (svd.doors) { - free(svd.doors); - svd.doors = 0; - } + } + if (svd.doors) { + free(svd.doors); + svd.doors = 0; + } + if (nhfp->structlevel) { Mread(nhfp->fd, &svd.doors_alloc, sizeof svd.doors_alloc); - if (svd.doors_alloc) { /* avoid pointless alloc(0) */ - svd.doors = (coord *) alloc(svd.doors_alloc * sizeof (coord)); - Mread(nhfp->fd, svd.doors, svd.doors_alloc * sizeof (coord)); + } + if (svd.doors_alloc) { /* avoid pointless alloc(0) */ + svd.doors = (coord *) alloc(svd.doors_alloc * sizeof(coord)); + tmpc = svd.doors; + for (i = 0; i < svd.doors_alloc; ++i) { + if (nhfp->structlevel) { + Mread(nhfp->fd, tmpc, sizeof (coord)); + } + tmpc++; } } rest_rooms(nhfp); /* No joke :-) */ - if (svn.nroom) + if (svn.nroom) { gd.doorindex = svr.rooms[svn.nroom - 1].fdoor + svr.rooms[svn.nroom - 1].doorct; - else + } else { gd.doorindex = 0; + } restore_timers(nhfp, RANGE_LEVEL, elapsed); restore_light_sources(nhfp); fmon = restmonchn(nhfp); - - /* rest_worm(fd); */ /* restore worm information */ rest_worm(nhfp); /* restore worm information */ gf.ftrap = 0; for (;;) { trap = newtrap(); - if (nhfp->structlevel) + if (nhfp->structlevel) { Mread(nhfp->fd, trap, sizeof *trap); + } if (trap->tx != 0) { if (program_state.restoring != REST_GSTATE && trap->dst.dnum == u.uz.dnum) { @@ -1298,8 +1316,9 @@ rest_bubbles(NHFILE *nhfp) clouds are present is recorded during save so that we don't have to know what level is being restored */ bbubbly = 0; - if (nhfp->structlevel) + if (nhfp->structlevel) { Mread(nhfp->fd, &bbubbly, sizeof bbubbly); + } if (bbubbly) restore_waterlevel(nhfp); @@ -1310,21 +1329,24 @@ restore_gamelog(NHFILE *nhfp) { int slen = 0; char msg[BUFSZ*2]; - struct gamelog_line tmp; + struct gamelog_line tmp = { 0 }; while (1) { - if (nhfp->structlevel) + if (nhfp->structlevel) { Mread(nhfp->fd, &slen, sizeof slen); + } if (slen == -1) break; if (slen > ((BUFSZ*2) - 1)) panic("restore_gamelog: msg too big (%d)", slen); if (nhfp->structlevel) { Mread(nhfp->fd, msg, slen); - Mread(nhfp->fd, &tmp, sizeof tmp); - msg[slen] = '\0'; - gamelog_add(tmp.flags, tmp.turn, msg); } + msg[slen] = '\0'; + if (nhfp->structlevel) { + Mread(nhfp->fd, &tmp, sizeof tmp); + } + gamelog_add(tmp.flags, tmp.turn, msg); } } @@ -1335,14 +1357,16 @@ restore_msghistory(NHFILE *nhfp) char msg[BUFSZ]; while (1) { - if (nhfp->structlevel) + if (nhfp->structlevel) { Mread(nhfp->fd, &msgsize, sizeof msgsize); + } if (msgsize == -1) break; if (msgsize > BUFSZ - 1) panic("restore_msghistory: msg too big (%d)", msgsize); - if (nhfp->structlevel) + if (nhfp->structlevel) { Mread(nhfp->fd, msg, msgsize); + } msg[msgsize] = '\0'; putmsghistory(msg, TRUE); ++msgcount; @@ -1531,10 +1555,8 @@ restore_menu( int validate(NHFILE *nhfp, const char *name, boolean without_waitsynch_perfile) { - readLenType rlen = 0; - struct savefile_info sfi; unsigned long utdflags = 0L; - boolean verbose = name ? TRUE : FALSE, reslt = FALSE; + boolean reslt = FALSE; if (nhfp->structlevel) utdflags |= UTD_CHECKSIZES; @@ -1543,24 +1565,6 @@ validate(NHFILE *nhfp, const char *name, boolean without_waitsynch_perfile) if (!(reslt = uptodate(nhfp, name, utdflags))) return 1; - if ((nhfp->mode & WRITING) == 0) { - if (nhfp->structlevel) - rlen = (readLenType) read(nhfp->fd, (genericptr_t) &sfi, - sizeof sfi); - } else { - if (nhfp->structlevel) - rlen = (readLenType) read(nhfp->fd, (genericptr_t) &sfi, - sizeof sfi); - minit(); /* ZEROCOMP */ - if (rlen == 0) { - if (verbose) { - pline("File \"%s\" is empty during save file feature check?", - name); - wait_synch(); - } - return -1; - } - } return 0; } diff --git a/src/rumors.c b/src/rumors.c index 31fb19a82..d1d709516 100644 --- a/src/rumors.c +++ b/src/rumors.c @@ -596,21 +596,29 @@ init_oracles(dlb *fp) void save_oracles(NHFILE *nhfp) { + int i; + if (perform_bwrite(nhfp)) { - if (nhfp->structlevel) - bwrite(nhfp->fd, (genericptr_t) &svo.oracle_cnt, - sizeof svo.oracle_cnt); - if (svo.oracle_cnt) { + if (nhfp->structlevel) { + bwrite(nhfp->fd, (genericptr_t) &svo.oracle_cnt, + sizeof svo.oracle_cnt); + } + if (svo.oracle_cnt) { + for (i = 0; (unsigned) i < svo.oracle_cnt; ++i) { if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) go.oracle_loc, - svo.oracle_cnt * sizeof (long)); + bwrite(nhfp->fd, (genericptr_t) &go.oracle_loc[i], + sizeof (unsigned long)); } } + } } if (release_data(nhfp)) { if (svo.oracle_cnt) { + svo.oracle_cnt = 0, go.oracle_flg = 0; + } + if (go.oracle_loc) { free((genericptr_t) go.oracle_loc); - go.oracle_loc = 0, svo.oracle_cnt = 0, go.oracle_flg = 0; + go.oracle_loc = 0; } } } @@ -618,14 +626,20 @@ save_oracles(NHFILE *nhfp) void restore_oracles(NHFILE *nhfp) { - if (nhfp->structlevel) - mread(nhfp->fd, (genericptr_t) &svo.oracle_cnt, sizeof svo.oracle_cnt); + int i; + if (nhfp->structlevel) { + mread(nhfp->fd, (genericptr_t) &svo.oracle_cnt, + sizeof svo.oracle_cnt); + } if (svo.oracle_cnt) { - go.oracle_loc = (unsigned long *) alloc(svo.oracle_cnt * sizeof(long)); - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) go.oracle_loc, - svo.oracle_cnt * sizeof (long)); + go.oracle_loc = + (unsigned long *) alloc(svo.oracle_cnt * sizeof (unsigned long)); + for (i = 0; (unsigned) i < svo.oracle_cnt; ++i) { + if (nhfp->structlevel) { + mread(nhfp->fd, (genericptr_t) &go.oracle_loc[i], + sizeof (unsigned long)); + } } go.oracle_flg = 1; /* no need to call init_oracles() */ } diff --git a/src/save.c b/src/save.c index ad5f52773..bc8c55124 100644 --- a/src/save.c +++ b/src/save.c @@ -17,7 +17,7 @@ int dotcnt, dotrow; /* also used in restore */ #endif staticfn void savelevchn(NHFILE *); -staticfn void savelevl(NHFILE *, boolean); +staticfn void savelevl(NHFILE *); staticfn void savedamage(NHFILE *); staticfn void save_bubbles(NHFILE *, xint8); staticfn void save_stairs(NHFILE *); @@ -158,7 +158,6 @@ dosave0(void) #endif nhfp->mode = WRITING | FREEING; store_version(nhfp); - store_savefileinfo(nhfp); if (nhfp && nhfp->fplog) (void) fprintf(nhfp->fplog, "# post-validation\n"); store_plname_in_file(nhfp); @@ -216,8 +215,9 @@ dosave0(void) minit(); /* ZEROCOMP */ getlev(onhfp, svh.hackpid, ltmp); close_nhfile(onhfp); - if (nhfp->structlevel) + if (nhfp->structlevel) { bwrite(nhfp->fd, (genericptr_t) <mp, sizeof ltmp); /* lvl no. */ + } savelev(nhfp, ltmp); /* actual level*/ delete_levelfile(ltmp); } @@ -249,8 +249,8 @@ save_gamelog(NHFILE *nhfp) while (tmp) { tmp2 = tmp->next; if (perform_bwrite(nhfp)) { + slen = Strlen(tmp->text); if (nhfp->structlevel) { - slen = Strlen(tmp->text); bwrite(nhfp->fd, (genericptr_t) &slen, sizeof slen); bwrite(nhfp->fd, (genericptr_t) tmp->text, slen); bwrite(nhfp->fd, (genericptr_t) tmp, @@ -264,8 +264,8 @@ save_gamelog(NHFILE *nhfp) tmp = tmp2; } if (perform_bwrite(nhfp)) { + slen = -1; if (nhfp->structlevel) { - slen = -1; bwrite(nhfp->fd, (genericptr_t) &slen, sizeof slen); } } @@ -276,6 +276,7 @@ save_gamelog(NHFILE *nhfp) staticfn void savegamestate(NHFILE *nhfp) { + int i; unsigned long uid; program_state.saving++; /* caller should/did already set this... */ @@ -314,8 +315,12 @@ savegamestate(NHFILE *nhfp) savemonchn(nhfp, gm.migrating_mons); if (release_data(nhfp)) gm.migrating_mons = (struct monst *) 0; - if (nhfp->structlevel) - bwrite(nhfp->fd, (genericptr_t) svm.mvitals, sizeof svm.mvitals); + for (i = 0; i < NUMMONS; ++i) { + if (nhfp->structlevel) { + bwrite(nhfp->fd, (genericptr_t) &svm.mvitals[i], + sizeof (struct mvitals)); + } + } save_dungeon(nhfp, (boolean) !!perform_bwrite(nhfp), (boolean) !!release_data(nhfp)); savelevchn(nhfp); @@ -323,8 +328,12 @@ savegamestate(NHFILE *nhfp) bwrite(nhfp->fd, (genericptr_t) &svm.moves, sizeof svm.moves); bwrite(nhfp->fd, (genericptr_t) &svq.quest_status, sizeof svq.quest_status); - bwrite(nhfp->fd, (genericptr_t) svs.spl_book, - sizeof (struct spell) * (MAXSPELL + 1)); + } + for (i = 0; i < (MAXSPELL + 1); ++i) { + if (nhfp->structlevel) { + bwrite(nhfp->fd, (genericptr_t) &svs.spl_book[i], + sizeof(struct spell)); + } } save_artifacts(nhfp); save_oracles(nhfp); @@ -391,8 +400,9 @@ savestateinlock(void) return; } - if (nhfp->structlevel) + if (nhfp->structlevel) { (void) read(nhfp->fd, (genericptr_t) &hpid, sizeof hpid); + } if (svh.hackpid != hpid) { Sprintf(whynot, "Level #0 pid (%d) doesn't match ours (%d)!", hpid, svh.hackpid); @@ -421,12 +431,12 @@ savestateinlock(void) if (flags.ins_chkpt) { int currlev = ledger_no(&u.uz); - if (nhfp->structlevel) + if (nhfp->structlevel) { (void) write(nhfp->fd, (genericptr_t) &currlev, sizeof currlev); + } save_savefile_name(nhfp); store_version(nhfp); - store_savefileinfo(nhfp); store_plname_in_file(nhfp); /* if ball and/or chain aren't on floor or in invent, keep a copy @@ -472,6 +482,8 @@ savelev_core(NHFILE *nhfp, xint8 lev) #ifdef TOS short tlev; #endif + int i, c, r; + coord *tmpc; program_state.saving++; /* even if current mode is FREEING */ @@ -505,17 +517,10 @@ savelev_core(NHFILE *nhfp, xint8 lev) if (lev >= 0 && lev <= maxledgerno()) svl.level_info[lev].flags |= VISITED; - if (nhfp->structlevel) + if (nhfp->structlevel) { bwrite(nhfp->fd, (genericptr_t) &svh.hackpid, sizeof svh.hackpid); -#ifdef TOS - tlev = lev; - tlev &= 0x00ff; - if (nhfp->structlevel) - bwrite(nhfp->fd, (genericptr_t) &tlev, sizeof tlev); -#else - if (nhfp->structlevel) bwrite(nhfp->fd, (genericptr_t) &lev, sizeof lev); -#endif + } } /* bones info comes before level data; the intent is for an external @@ -528,23 +533,35 @@ savelev_core(NHFILE *nhfp, xint8 lev) if (nhfp->mode == FREEING) /* see above */ goto skip_lots; - savelevl(nhfp, ((sfsaveinfo.sfi1 & SFI1_RLECOMP) == SFI1_RLECOMP)); + savelevl(nhfp); + for (c = 0; c < COLNO; ++c) + for (r = 0; r < ROWNO; ++r) { + bwrite(nhfp->fd, (genericptr_t) &svl.lastseentyp[c][r], + sizeof(schar)); + } if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) svl.lastseentyp, - sizeof svl.lastseentyp); bwrite(nhfp->fd, (genericptr_t) &svm.moves, sizeof svm.moves); save_stairs(nhfp); - bwrite(nhfp->fd, (genericptr_t) &svu.updest, sizeof (dest_area)); - bwrite(nhfp->fd, (genericptr_t) &svd.dndest, sizeof (dest_area)); + bwrite(nhfp->fd, (genericptr_t) &svu.updest, sizeof(dest_area)); + bwrite(nhfp->fd, (genericptr_t) &svd.dndest, sizeof(dest_area)); bwrite(nhfp->fd, (genericptr_t) &svl.level.flags, sizeof svl.level.flags); + } + if (nhfp->structlevel) { bwrite(nhfp->fd, (genericptr_t) &svd.doors_alloc, sizeof svd.doors_alloc); - /* don't rely on underlying write() behavior to write - * nothing if count arg is 0, just skip it */ - if (svd.doors_alloc) - bwrite(nhfp->fd, (genericptr_t) svd.doors, - svd.doors_alloc * sizeof (coord)); + } + /* don't rely on underlying write() behavior to write + * nothing if count arg is 0, just skip it */ + if (svd.doors_alloc) { + tmpc = svd.doors; + for (i = 0; i < svd.doors_alloc; ++i) { + if (nhfp->structlevel) { + bwrite(nhfp->fd, (genericptr_t) tmpc, + sizeof (coord)); + } + tmpc++; + } } save_rooms(nhfp); /* no dynamic memory to reclaim */ @@ -582,61 +599,17 @@ savelev_core(NHFILE *nhfp, xint8 lev) } staticfn void -savelevl(NHFILE *nhfp, boolean rlecomp) +savelevl(NHFILE *nhfp) { -#ifdef RLECOMP - struct rm *prm, *rgrm; int x, y; - uchar match; - - if (rlecomp) { - /* perform run-length encoding of rm structs */ - - rgrm = &levl[0][0]; /* start matching at first rm */ - match = 0; + for (x = 0; x < COLNO; x++) { for (y = 0; y < ROWNO; y++) { - for (x = 0; x < COLNO; x++) { - prm = &levl[x][y]; - if (prm->glyph == rgrm->glyph && prm->typ == rgrm->typ - && prm->seenv == rgrm->seenv - && prm->horizontal == rgrm->horizontal - && prm->flags == rgrm->flags && prm->lit == rgrm->lit - && prm->waslit == rgrm->waslit - && prm->roomno == rgrm->roomno && prm->edge == rgrm->edge - && prm->candig == rgrm->candig) { - match++; - if (match > 254) { - match = 254; /* undo this match */ - goto writeout; - } - } else { - /* run has been broken, write out run-length encoding */ - writeout: - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &match, sizeof match); - bwrite(nhfp->fd, (genericptr_t) rgrm, sizeof *rgrm); - } - /* start encoding again. we have at least 1 rm - in the next run, viz. this one. */ - match = 1; - rgrm = prm; - } - } - } - if (match > 0) { if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &match, sizeof (uchar)); - bwrite(nhfp->fd, (genericptr_t) rgrm, sizeof (struct rm)); + bwrite(nhfp->fd, (genericptr_t) &levl[x][y], + sizeof(struct rm)); } } - return; - } -#else /* !RLECOMP */ - nhUse(rlecomp); -#endif /* ?RLECOMP */ - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) levl, sizeof levl); } return; } @@ -656,8 +629,9 @@ save_bubbles(NHFILE *nhfp, xint8 lev) bbubbly = 0; if (lev == ledger_no(&water_level) || lev == ledger_no(&air_level)) bbubbly = lev; /* non-zero */ - if (nhfp->structlevel) + if (nhfp->structlevel) { bwrite(nhfp->fd, (genericptr_t) &bbubbly, sizeof bbubbly); + } if (bbubbly) save_waterlevel(nhfp); /* save air bubbles or clouds */ @@ -672,15 +646,17 @@ savecemetery(NHFILE *nhfp, struct cemetery **cemeteryaddr) flag = *cemeteryaddr ? 0 : -1; if (perform_bwrite(nhfp)) { - if (nhfp->structlevel) + if (nhfp->structlevel) { bwrite(nhfp->fd, (genericptr_t) &flag, sizeof flag); + } } nextbones = *cemeteryaddr; while ((thisbones = nextbones) != 0) { nextbones = thisbones->next; if (perform_bwrite(nhfp)) { - if (nhfp->structlevel) + if (nhfp->structlevel) { bwrite(nhfp->fd, (genericptr_t) thisbones, sizeof *thisbones); + } } if (release_data(nhfp)) free((genericptr_t) thisbones); @@ -699,13 +675,15 @@ savedamage(NHFILE *nhfp) for (tmp_dam = damageptr; tmp_dam; tmp_dam = tmp_dam->next) xl++; if (perform_bwrite(nhfp)) { - if (nhfp->structlevel) + if (nhfp->structlevel) { bwrite(nhfp->fd, (genericptr_t) &xl, sizeof xl); + } } while (damageptr) { if (perform_bwrite(nhfp)) { - if (nhfp->structlevel) + if (nhfp->structlevel) { bwrite(nhfp->fd, (genericptr_t) damageptr, sizeof *damageptr); + } } tmp_dam = damageptr; damageptr = damageptr->next; @@ -793,33 +771,38 @@ saveobj(NHFILE *nhfp, struct obj *otmp) } if (otmp->oextra) { buflen = ONAME(otmp) ? (int) strlen(ONAME(otmp)) + 1 : 0; - if (nhfp->structlevel) + if (nhfp->structlevel) { bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof buflen); - + } if (buflen > 0) { - if (nhfp->structlevel) + if (nhfp->structlevel) { bwrite(nhfp->fd, (genericptr_t) ONAME(otmp), buflen); + } } /* defer to savemon() for this one */ if (OMONST(otmp)) { savemon(nhfp, OMONST(otmp)); } else { - if (nhfp->structlevel) + if (nhfp->structlevel) { bwrite(nhfp->fd, (genericptr_t) &zerobuf, sizeof zerobuf); + } } /* extra info about scroll of mail */ buflen = OMAILCMD(otmp) ? (int) strlen(OMAILCMD(otmp)) + 1 : 0; - if (nhfp->structlevel) + if (nhfp->structlevel) { bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof buflen); + } if (buflen > 0) { - if (nhfp->structlevel) - bwrite(nhfp->fd, (genericptr_t) OMAILCMD(otmp), buflen); + if (nhfp->structlevel) { + bwrite(nhfp->fd, (genericptr_t) OMAILCMD(otmp), buflen); + } } /* omid used to be indirect via a pointer in oextra but has become part of oextra itself; 0 means not applicable and gets saved/restored whenever any other oextra components do */ - if (nhfp->structlevel) + if (nhfp->structlevel) { bwrite(nhfp->fd, (genericptr_t) &OMID(otmp), sizeof OMID(otmp)); + } } } @@ -878,8 +861,9 @@ saveobjchn(NHFILE *nhfp, struct obj **obj_p) otmp = otmp2; } if (perform_bwrite(nhfp)) { - if (nhfp->structlevel) - bwrite(nhfp->fd, (genericptr_t) &minusone, sizeof (int)); + if (nhfp->structlevel) { + bwrite(nhfp->fd, (genericptr_t) &minusone, sizeof(int)); + } } if (release_data(nhfp)) { if (is_invent) @@ -902,59 +886,74 @@ savemon(NHFILE *nhfp, struct monst *mtmp) } if (mtmp->mextra) { buflen = MGIVENNAME(mtmp) ? (int) strlen(MGIVENNAME(mtmp)) + 1 : 0; - if (nhfp->structlevel) + if (nhfp->structlevel) { bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof buflen); + } if (buflen > 0) { - if (nhfp->structlevel) + if (nhfp->structlevel) { bwrite(nhfp->fd, (genericptr_t) MGIVENNAME(mtmp), buflen); + } } buflen = EGD(mtmp) ? (int) sizeof (struct egd) : 0; - if (nhfp->structlevel) + if (nhfp->structlevel) { bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof buflen); + } if (buflen > 0) { - if (nhfp->structlevel) + if (nhfp->structlevel) { bwrite(nhfp->fd, (genericptr_t) EGD(mtmp), buflen); + } } buflen = EPRI(mtmp) ? (int) sizeof (struct epri) : 0; - if (nhfp->structlevel) + if (nhfp->structlevel) { bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof buflen); + } if (buflen > 0) { - if (nhfp->structlevel) + if (nhfp->structlevel) { bwrite(nhfp->fd, (genericptr_t) EPRI(mtmp), buflen); + } } buflen = ESHK(mtmp) ? (int) sizeof (struct eshk) : 0; - if (nhfp->structlevel) - bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof (int)); + if (nhfp->structlevel) { + bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof(int)); + } if (buflen > 0) { - if (nhfp->structlevel) + if (nhfp->structlevel) { bwrite(nhfp->fd, (genericptr_t) ESHK(mtmp), buflen); + } } buflen = EMIN(mtmp) ? (int) sizeof (struct emin) : 0; - if (nhfp->structlevel) - bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof (int)); + if (nhfp->structlevel) { + bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof(int)); + } if (buflen > 0) { - if (nhfp->structlevel) + if (nhfp->structlevel) { bwrite(nhfp->fd, (genericptr_t) EMIN(mtmp), buflen); + } } buflen = EDOG(mtmp) ? (int) sizeof (struct edog) : 0; - if (nhfp->structlevel) - bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof (int)); + if (nhfp->structlevel) { + bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof(int)); + } if (buflen > 0) { - if (nhfp->structlevel) + if (nhfp->structlevel) { bwrite(nhfp->fd, (genericptr_t) EDOG(mtmp), buflen); + } } buflen = EBONES(mtmp) ? (int) sizeof (struct ebones) : 0; - if (nhfp->structlevel) - bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof (int)); + if (nhfp->structlevel) { + bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof(int)); + } if (buflen > 0) { - if (nhfp->structlevel) + if (nhfp->structlevel) { bwrite(nhfp->fd, (genericptr_t) EBONES(mtmp), buflen); + } } /* mcorpsenm is inline int rather than pointer to something, so doesn't need to be preceded by a length field */ - if (nhfp->structlevel) - bwrite(nhfp->fd, (genericptr_t) &MCORPSENM(mtmp), - sizeof MCORPSENM(mtmp)); + buflen = (int) MCORPSENM(mtmp); + if (nhfp->structlevel) { + bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof (int)); + } } } @@ -989,8 +988,9 @@ savemonchn(NHFILE *nhfp, struct monst *mtmp) mtmp = mtmp2; } if (perform_bwrite(nhfp)) { - if (nhfp->structlevel) - bwrite(nhfp->fd, (genericptr_t) &minusone, sizeof (int)); + if (nhfp->structlevel) { + bwrite(nhfp->fd, (genericptr_t) &minusone, sizeof(int)); + } } } @@ -1008,8 +1008,9 @@ savetrapchn(NHFILE *nhfp, struct trap *trap) if (use_relative) trap->dst.dlevel -= u.uz.dlevel; /* make it relative */ if (perform_bwrite(nhfp)) { - if (nhfp->structlevel) + if (nhfp->structlevel) { bwrite(nhfp->fd, (genericptr_t) trap, sizeof *trap); + } } if (use_relative) trap->dst.dlevel += u.uz.dlevel; /* reset back to absolute */ @@ -1018,8 +1019,9 @@ savetrapchn(NHFILE *nhfp, struct trap *trap) trap = trap2; } if (perform_bwrite(nhfp)) { - if (nhfp->structlevel) + if (nhfp->structlevel) { bwrite(nhfp->fd, (genericptr_t) &zerotrap, sizeof zerotrap); + } } } @@ -1038,16 +1040,18 @@ savefruitchn(NHFILE *nhfp) while (f1) { f2 = f1->nextf; if (f1->fid >= 0 && perform_bwrite(nhfp)) { - if (nhfp->structlevel) + if (nhfp->structlevel) { bwrite(nhfp->fd, (genericptr_t) f1, sizeof *f1); + } } if (release_data(nhfp)) dealloc_fruit(f1); f1 = f2; } if (perform_bwrite(nhfp)) { - if (nhfp->structlevel) + if (nhfp->structlevel) { bwrite(nhfp->fd, (genericptr_t) &zerofruit, sizeof zerofruit); + } } if (release_data(nhfp)) gf.ffruit = 0; @@ -1062,14 +1066,16 @@ savelevchn(NHFILE *nhfp) for (tmplev = svs.sp_levchn; tmplev; tmplev = tmplev->next) cnt++; if (perform_bwrite(nhfp)) { - if (nhfp->structlevel) + if (nhfp->structlevel) { bwrite(nhfp->fd, (genericptr_t) &cnt, sizeof cnt); + } } for (tmplev = svs.sp_levchn; tmplev; tmplev = tmplev2) { tmplev2 = tmplev->next; if (perform_bwrite(nhfp)) { - if (nhfp->structlevel) + if (nhfp->structlevel) { bwrite(nhfp->fd, (genericptr_t) tmplev, sizeof *tmplev); + } } if (release_data(nhfp)) free((genericptr_t) tmplev); @@ -1124,7 +1130,7 @@ save_msghistory(NHFILE *nhfp) /* ask window port for each message in sequence */ while ((msg = getmsghistory(init)) != 0) { init = FALSE; - msglen = Strlen(msg); + msglen = (int) Strlen(msg); if (msglen < 1) continue; /* sanity: truncate if necessary (shouldn't happen); @@ -1137,37 +1143,14 @@ save_msghistory(NHFILE *nhfp) } ++msgcount; } - if (nhfp->structlevel) - bwrite(nhfp->fd, (genericptr_t) &minusone, sizeof (int)); + if (nhfp->structlevel) { + bwrite(nhfp->fd, (genericptr_t) &minusone, sizeof(int)); + } } debugpline1("Stored %d messages into savefile.", msgcount); /* note: we don't attempt to handle release_data() here */ } -void -store_savefileinfo(NHFILE *nhfp) -{ - /* sfcap (decl.c) describes the savefile feature capabilities - * that are supported by this port/platform build. - * - * sfsaveinfo (decl.c) describes the savefile info that actually - * gets written into the savefile, and is used to determine the - * save file being written. - * - * sfrestinfo (decl.c) describes the savefile info that is - * being used to read the information from an existing savefile. - */ - - if (nhfp->structlevel) { - bufoff(nhfp->fd); - /* bwrite() before bufon() uses plain write() */ - bwrite(nhfp->fd, (genericptr_t) &sfsaveinfo, - (unsigned) sizeof sfsaveinfo); - bufon(nhfp->fd); - } - return; -} - /* also called by prscore(); this probably belongs in dungeon.c... */ void free_dungeons(void) diff --git a/src/timeout.c b/src/timeout.c index 81f62d531..34e95806a 100644 --- a/src/timeout.c +++ b/src/timeout.c @@ -2496,22 +2496,25 @@ write_timer(NHFILE *nhfp, timer_element *timer) case TIMER_GLOBAL: case TIMER_LEVEL: /* assume no pointers in arg */ - if (nhfp->structlevel) + if (nhfp->structlevel) { bwrite(nhfp->fd, (genericptr_t) timer, sizeof(timer_element)); + } break; case TIMER_OBJECT: if (timer->needs_fixup) { - if (nhfp->structlevel) + if (nhfp->structlevel) { bwrite(nhfp->fd, (genericptr_t) timer, sizeof(timer_element)); + } } else { /* replace object pointer with id */ arg_save.a_obj = timer->arg.a_obj; timer->arg = cg.zeroany; timer->arg.a_uint = (arg_save.a_obj)->o_id; timer->needs_fixup = 1; - if (nhfp->structlevel) + if (nhfp->structlevel) { bwrite(nhfp->fd, (genericptr_t) timer, sizeof(timer_element)); + } timer->arg.a_obj = arg_save.a_obj; timer->needs_fixup = 0; } @@ -2519,16 +2522,18 @@ write_timer(NHFILE *nhfp, timer_element *timer) case TIMER_MONSTER: if (timer->needs_fixup) { - if (nhfp->structlevel) + if (nhfp->structlevel) { bwrite(nhfp->fd, (genericptr_t) timer, sizeof(timer_element)); + } } else { /* replace monster pointer with id */ arg_save.a_monst = timer->arg.a_monst; timer->arg = cg.zeroany; timer->arg.a_uint = (arg_save.a_monst)->m_id; timer->needs_fixup = 1; - if (nhfp->structlevel) + if (nhfp->structlevel) { bwrite(nhfp->fd, (genericptr_t) timer, sizeof(timer_element)); + } timer->arg.a_monst = arg_save.a_monst; timer->needs_fixup = 0; } @@ -2662,13 +2667,15 @@ save_timers(NHFILE *nhfp, int range) if (perform_bwrite(nhfp)) { if (range == RANGE_GLOBAL) { - if (nhfp->structlevel) + if (nhfp->structlevel) { bwrite(nhfp->fd, (genericptr_t) &svt.timer_id, sizeof svt.timer_id); + } } count = maybe_write_timer(nhfp, range, FALSE); - if (nhfp->structlevel) + if (nhfp->structlevel) { bwrite(nhfp->fd, (genericptr_t) &count, sizeof count); + } (void) maybe_write_timer(nhfp, range, TRUE); } @@ -2703,19 +2710,22 @@ restore_timers(NHFILE *nhfp, int range, long adjust) boolean ghostly = (nhfp->ftype == NHF_BONESFILE); /* from a ghost level */ if (range == RANGE_GLOBAL) { - if (nhfp->structlevel) + if (nhfp->structlevel) { mread(nhfp->fd, (genericptr_t) &svt.timer_id, sizeof svt.timer_id); + } } /* restore elements */ - if (nhfp->structlevel) + if (nhfp->structlevel) { mread(nhfp->fd, (genericptr_t) &count, sizeof count); + } while (count-- > 0) { curr = (timer_element *) alloc(sizeof(timer_element)); - if (nhfp->structlevel) + if (nhfp->structlevel) { mread(nhfp->fd, (genericptr_t) curr, sizeof(timer_element)); + } if (ghostly) curr->timeout += adjust; insert_timer(curr); diff --git a/src/track.c b/src/track.c index e9c4923f8..60a0d382b 100644 --- a/src/track.c +++ b/src/track.c @@ -70,12 +70,14 @@ void save_track(NHFILE *nhfp) { if (perform_bwrite(nhfp)) { - if (nhfp->structlevel) { - int i; + int i; + if (nhfp->structlevel) { bwrite(nhfp->fd, (genericptr_t) &utcnt, sizeof utcnt); bwrite(nhfp->fd, (genericptr_t) &utpnt, sizeof utpnt); - for (i = 0; i < utcnt; i++) { + } + for (i = 0; i < utcnt; i++) { + if (nhfp->structlevel) { bwrite(nhfp->fd, (genericptr_t) &utrack[i].x, sizeof utrack[i].x); bwrite(nhfp->fd, (genericptr_t) &utrack[i].y, @@ -91,14 +93,16 @@ save_track(NHFILE *nhfp) void rest_track(NHFILE *nhfp) { - if (nhfp->structlevel) { - int i; + int i; + if (nhfp->structlevel) { mread(nhfp->fd, (genericptr_t) &utcnt, sizeof utcnt); mread(nhfp->fd, (genericptr_t) &utpnt, sizeof utpnt); - if (utcnt > UTSZ || utpnt > UTSZ) - panic("rest_track: impossible pt counts"); - for (i = 0; i < utcnt; i++) { + } + if (utcnt > UTSZ || utpnt > UTSZ) + panic("rest_track: impossible pt counts"); + for (i = 0; i < utcnt; i++) { + if (nhfp->structlevel) { mread(nhfp->fd, (genericptr_t) &utrack[i].x, sizeof utrack[i].x); mread(nhfp->fd, (genericptr_t) &utrack[i].y, sizeof utrack[i].y); } diff --git a/src/version.c b/src/version.c index e6b675ed3..83f119859 100644 --- a/src/version.c +++ b/src/version.c @@ -275,14 +275,14 @@ early_version_info(boolean pastebuf) char buf1[BUFSZ], buf2[BUFSZ]; char *buf, *tmp; - Snprintf(buf1, sizeof(buf1), "test"); + Snprintf(buf1, sizeof buf1, "test"); /* this is early enough that we have to do our own line-splitting */ getversionstring(buf1, sizeof buf1); tmp = strstri(buf1, " ("); /* split at start of version info */ if (tmp) { /* retain one buffer so that it all goes into the paste buffer */ *tmp++ = '\0'; - Snprintf(buf2, sizeof(buf2), "%s\n%s", buf1, tmp); + Snprintf(buf2, sizeof (buf2),"%s\n%s", buf1, tmp); buf = buf2; } else { buf = buf1; @@ -389,10 +389,6 @@ check_version( != (nomakedefs.version_features & ~nomakedefs.ignored_features) || ((utdflags & UTD_SKIP_SANITY1) == 0 && version_data->entity_count != nomakedefs.version_sanity1) - || ((utdflags & UTD_CHECKSIZES) != 0 - && version_data->struct_sizes1 != nomakedefs.version_sanity2) - || ((utdflags & UTD_CHECKSIZES) != 0 - && version_data->struct_sizes2 != nomakedefs.version_sanity3) ) { if (complain) { pline("Configuration incompatibility for file \"%s\".", filename); @@ -403,69 +399,11 @@ check_version( return TRUE; } -/* this used to be based on file date and somewhat OS-dependent, - but now examines the initial part of the file's contents */ -boolean -uptodate(NHFILE *nhfp, const char *name, unsigned long utdflags) -{ - ssize_t rlen = 0; - int cmc = 0, filecmc = 0; - struct version_info vers_info; - boolean verbose = name ? TRUE : FALSE; - char indicator; - - if (nhfp->structlevel) { - rlen = read(nhfp->fd, (genericptr_t) &indicator, sizeof indicator); - if (rlen != sizeof indicator) - return FALSE; - rlen = read(nhfp->fd, (genericptr_t) &filecmc, sizeof filecmc); - if (rlen == 0) - return FALSE; - } - if (cmc != filecmc) - return FALSE; - - rlen = read(nhfp->fd, (genericptr_t) &vers_info, sizeof vers_info); - minit(); /* ZEROCOMP */ - if (rlen == 0) { - if (verbose) { - pline("File \"%s\" is empty?", name); - if ((utdflags & UTD_WITHOUT_WAITSYNCH_PERFILE) == 0) - wait_synch(); - } - return FALSE; - } - - if (!check_version(&vers_info, name, verbose, utdflags)) { - if (verbose) { - if ((utdflags & UTD_WITHOUT_WAITSYNCH_PERFILE) == 0) - wait_synch(); - } - return FALSE; - } - return TRUE; -} - -void -store_formatindicator(NHFILE *nhfp) -{ - char indicate = 'u'; - int cmc = 0; - - if (nhfp->mode & WRITING) { - if (nhfp->structlevel) { - indicate = 'h'; /* historical */ - bwrite(nhfp->fd, (genericptr_t) &indicate, sizeof indicate); - bwrite(nhfp->fd, (genericptr_t) &cmc, sizeof cmc); - } - } -} - void store_version(NHFILE *nhfp) { struct version_info version_data = { - 0UL, 0UL, 0UL, 0UL, 0UL + 0UL, 0UL, 0UL, }; /* actual version number */ @@ -474,19 +412,19 @@ store_version(NHFILE *nhfp) version_data.feature_set = nomakedefs.version_features; /* # of monsters and objects */ version_data.entity_count = nomakedefs.version_sanity1; - /* size of key structs */ - version_data.struct_sizes1 = nomakedefs.version_sanity2; - /* size of more key structs */ - version_data.struct_sizes2 = nomakedefs.version_sanity3; - if (nhfp->structlevel) { + /* bwrite() before bufon() uses plain write() */ + if (nhfp->structlevel) bufoff(nhfp->fd); - /* bwrite() before bufon() uses plain write() */ - store_formatindicator(nhfp); + + store_critical_bytes(nhfp); + if (nhfp->structlevel) { bwrite(nhfp->fd, (genericptr_t) &version_data, (unsigned) (sizeof version_data)); - bufon(nhfp->fd); } + + if (nhfp->structlevel) + bufon(nhfp->fd); return; } @@ -566,16 +504,242 @@ dump_version_info(void) if (strlen(hname) > 33) hname = eos(nhStr(hname)) - 33; /* discard const for eos() */ runtime_info_init(); - Snprintf(buf, sizeof buf, "%-12.33s %08lx %08lx %08lx %08lx %08lx", + Snprintf(buf, sizeof buf, "%-12.33s %08lx %08lx %08lx", hname, nomakedefs.version_number, (nomakedefs.version_features & ~nomakedefs.ignored_features), - nomakedefs.version_sanity1, - nomakedefs.version_sanity2, - nomakedefs.version_sanity3); + nomakedefs.version_sanity1); raw_print(buf); release_runtime_info(); return; } +struct critical_sizes_with_names { + uchar ucsize; + const char *nm; +}; + +struct critical_sizes_with_names critical_sizes[] = { + { 0, "unused" }, + /* simple types, that don't have subfields */ + { (uchar) sizeof(short), "short" }, + { (uchar) sizeof(int), "int" }, + { (uchar) sizeof(long), "long" }, + { (uchar) sizeof(long long), "long long" }, + { (uchar) sizeof(genericptr_t), "genericptr_t" }, + { (uchar) sizeof(aligntyp), "aligntyp" }, + { (uchar) sizeof(boolean), "boolean" }, + { (uchar) sizeof(coordxy), "coordxy" }, + { (uchar) sizeof(int16), "int16" }, + { (uchar) sizeof(int32), "int32" }, + { (uchar) sizeof(int64), "int64" }, + { (uchar) sizeof(schar), "schar" }, + { (uchar) sizeof(size_t), "size_t" }, + { (uchar) sizeof(uchar), "uchar" }, + { (uchar) sizeof(uint16), "uint16" }, + { (uchar) sizeof(uint32), "uint32" }, + { (uchar) sizeof(uint64), "uint64" }, + { (uchar) sizeof(ulong), "ulong" }, + { (uchar) sizeof(unsigned), "unsigned" }, + { (uchar) sizeof(ushort), "ushort" }, + { (uchar) sizeof(xint16), "xint16" }, + { (uchar) sizeof(xint8), "xint8" }, + /* complex - they break down into one or more simple types */ + { (uchar) sizeof(struct arti_info), "struct arti_info" }, + { (uchar) sizeof(struct nhrect), "struct nhrect" }, + { (uchar) sizeof(struct branch), "struct branch" }, + { (uchar) sizeof(struct bubble), "struct bubble" }, + { (uchar) sizeof(struct cemetery), "struct cemetery" }, + { (uchar) sizeof(struct context_info), "struct context_info" }, + { (uchar) sizeof(struct nhcoord), "struct nhcoord" }, + { (uchar) sizeof(struct damage), "struct damage" }, + { (uchar) sizeof(struct dest_area), "struct dest_area" }, + { (uchar) sizeof(struct dgn_topology), "struct dgn_topology" }, + { (uchar) sizeof(struct dungeon), "struct dungeon" }, + { (uchar) sizeof(struct d_level), "struct d_level" }, + { (uchar) sizeof(struct ebones), "struct ebones" }, + { (uchar) sizeof(struct edog), "struct edog" }, + { (uchar) sizeof(struct egd), "struct egd" }, + { (uchar) sizeof(struct emin), "struct emin" }, + { (uchar) sizeof(struct engr), "struct engr" }, + { (uchar) sizeof(struct epri), "struct epri" }, + { (uchar) sizeof(struct eshk), "struct eshk" }, + { (uchar) sizeof(struct fe), "struct fe" }, + { (uchar) sizeof(struct flag), "struct flag" }, + { (uchar) sizeof(struct fruit), "struct fruit" }, + { (uchar) sizeof(struct gamelog_line), "struct gamelog_line" }, + { (uchar) sizeof(struct kinfo), "struct kinfo" }, + { (uchar) sizeof(struct levelflags), "struct levelflags" }, + { (uchar) sizeof(struct ls_t), "struct ls_t" }, + { (uchar) sizeof(struct linfo), "struct linfo" }, + { (uchar) sizeof(struct mapseen_feat), "struct mapseen_feat" }, + { (uchar) sizeof(struct mapseen_flags), "struct mapseen_flags" }, + { (uchar) sizeof(struct mapseen_rooms), "struct mapseen_rooms" }, + { (uchar) sizeof(struct mextra), "struct mextra" }, + { (uchar) sizeof(struct mkroom), "struct mkroom" }, + { (uchar) sizeof(struct monst), "struct monst" }, + { (uchar) sizeof(struct mvitals), "struct mvitals" }, + { (uchar) sizeof(struct obj), "struct obj" }, + { (uchar) sizeof(struct objclass), "struct objclass" }, + { (uchar) sizeof(struct q_score), "struct q_score" }, + { (uchar) sizeof(struct rm), "struct rm" }, + { (uchar) sizeof(struct spell), "struct spell" }, + { (uchar) sizeof(struct stairway), "struct stairway" }, + { (uchar) sizeof(struct s_level), "struct s_level" }, + { (uchar) sizeof(struct trap), "struct trap" }, + { (uchar) sizeof(struct version_info), "struct version_info" }, + { (uchar) sizeof(anything), "anything" }, + /* struct you requires 2 bytes */ + { (uchar) ((sizeof(struct you) & 0x00FF)), "you_LO" }, + { (uchar) ((sizeof(struct you) & 0xFF00) >> 8), "you_HI" }, +#ifdef SF_INCLUDE_SUBSTRUCTS + /* + * the ones below are substructures of the ones + * above, so there is no need to check these directly. + */ + { (uchar) sizeof(struct attribs), "struct attribs" }, + { (uchar) sizeof(struct dig_info), "struct dig_info" }, + { (uchar) sizeof(struct tin_info), "struct tin_info" }, + { (uchar) sizeof(struct book_info), "struct book_info" }, + { (uchar) sizeof(struct takeoff_info), "struct takeoff_info" }, + { (uchar) sizeof(struct victual_info), "struct victual_info" }, + { (uchar) sizeof(struct engrave_info), "struct engrave_info" }, + { (uchar) sizeof(struct warntype_info), "struct warntype_info" }, + { (uchar) sizeof(struct polearm_info), "struct polearm_info" }, + { (uchar) sizeof(struct obj_split), "struct obj_split" }, + { (uchar) sizeof(struct tribute_info), "struct tribute_info" }, + { (uchar) sizeof(struct novel_tracking), "struct novel_tracking" }, + { (uchar) sizeof(struct achievement_tracking), + "struct achievement_tracking" }, + { (uchar) sizeof(struct d_flags), "struct d_flags" }, + { (uchar) sizeof(struct mapseen), "struct mapseen" }, + { (uchar) sizeof(struct fakecorridor), "struct fakecorridor" }, + { (uchar) sizeof(struct bill_x), "struct bill_x" }, + { (uchar) sizeof(union vptrs), "union vptrs" }, + { (uchar) sizeof(struct oextra), "struct oextra" }, + { (uchar) sizeof(struct prop), "struct prop" }, + { (uchar) sizeof(struct skills), "struct skills" }, + { (uchar) sizeof(union vlaunchinfo), "union vlaunchinfo" }, + { (uchar) sizeof(struct u_have), "struct u_have" }, + { (uchar) sizeof(struct u_event), "struct u_event" }, + { (uchar) sizeof(struct u_realtime), "struct u_realtime" }, + { (uchar) sizeof(struct u_conduct), "struct u_conduct" }, + { (uchar) sizeof(struct u_roleplay), "struct u_roleplay" }, +#endif /* SF_INCLUDE_SUBSTRUCTS */ + /* 10 for future expansion without changing array size */ + { 0, "" }, + { 0, "" }, + { 0, "" }, + { 0, "" }, + { 0, "" }, + { 0, "" }, + { 0, "" }, + { 0, "" }, + { 0, "" }, + { 0, "" }, +}; + +uchar cscbuf[SIZE(critical_sizes)]; + +int +get_critical_size_count(void) +{ + return SIZE(critical_sizes); +} + +void +store_critical_bytes(NHFILE *nhfp) +{ + int i, cnt; + char indicate = 'u', csc_count = (char) SIZE(critical_sizes); + /* int cmc = 0; */ + + if (nhfp->mode & WRITING) { + indicate = (nhfp->structlevel) ? 'h' + : (nhfp->fnidx == ascii) ? 'a' + : 'l'; + if (nhfp->structlevel) { + bwrite(nhfp->fd, (genericptr_t) &indicate, + (unsigned) sizeof indicate); + } + if (nhfp->structlevel) { + bwrite(nhfp->fd, (genericptr_t) &csc_count, + (unsigned) sizeof csc_count); + } + cnt = (int) csc_count; + for (i = 0; i < cnt; ++i) { + if (nhfp->structlevel) { + bwrite(nhfp->fd, (genericptr_t) &critical_sizes[i].ucsize, + (unsigned) sizeof (uchar)); + } + } + } +} + +/* this used to be based on file date and somewhat OS-dependent, + but now examines the initial part of the file's contents */ +boolean +uptodate(NHFILE *nhfp, const char *name, unsigned long utdflags) +{ + struct version_info vers_info; + char indicator; + boolean verbose = name ? TRUE : FALSE; + int ccbresult = 0; + /* int you_size = (int) sizeof (struct you); */ + + if (nhfp->structlevel) { + mread(nhfp->fd, (genericptr_t) &indicator, sizeof indicator); + } + if ((ccbresult = compare_critical_bytes(nhfp)) != 0) { + if (ccbresult > 0) { + raw_printf("compare of critical bytes failed at %d (%s).", + critical_sizes[ccbresult].ucsize, + critical_sizes[ccbresult].nm); + } + return FALSE; + } + + if (nhfp->structlevel) { + mread(nhfp->fd, (genericptr_t) &vers_info, sizeof vers_info); + } + if (!check_version(&vers_info, name, verbose, utdflags)) { + if (verbose) { + if ((utdflags & UTD_WITHOUT_WAITSYNCH_PERFILE) == 0) + wait_synch(); + } + return FALSE; + } + return TRUE; +} + +int +compare_critical_bytes(NHFILE *nhfp) +{ + char active_csc_count = (char) SIZE(critical_sizes), + file_csc_count = 0; + int i, cnt = (int) active_csc_count; + + if (nhfp->structlevel) { + mread(nhfp->fd, (genericptr_t) &file_csc_count, + sizeof file_csc_count); + } + if (file_csc_count > cnt) { + raw_printf("critical byte counts do not match" + ", file:%d, critical_sizes:%d.", + file_csc_count, SIZE(critical_sizes)); + return -1; + } + for (i = 0; i < (int) file_csc_count; ++i) { + if (nhfp->structlevel) { + mread(nhfp->fd, (genericptr_t) &cscbuf[i], + sizeof (uchar)); + } + } + for (i = 1; i < cnt; ++i) { + if (cscbuf[i] != critical_sizes[i].ucsize) + return i; + } + return 0; /* everything matched */ +} + /*version.c*/ diff --git a/src/worm.c b/src/worm.c index 4b28790cd..c760bc3a3 100644 --- a/src/worm.c +++ b/src/worm.c @@ -532,8 +532,9 @@ save_worm(NHFILE *nhfp) for (count = 0, curr = wtails[i]; curr; curr = curr->nseg) count++; /* Save number of segments */ - if (nhfp->structlevel) + if (nhfp->structlevel) { bwrite(nhfp->fd, (genericptr_t) &count, sizeof count); + } /* Save segment locations of the monster. */ if (count) { for (curr = wtails[i]; curr; curr = curr->nseg) { @@ -546,8 +547,10 @@ save_worm(NHFILE *nhfp) } } } - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) wgrowtime, sizeof wgrowtime); + for (i = 0; i < MAX_NUM_WORMS; ++i) { + if (nhfp->structlevel) { + bwrite(nhfp->fd, (genericptr_t) &wgrowtime[i], sizeof (long)); + } } } @@ -581,8 +584,9 @@ rest_worm(NHFILE *nhfp) struct wseg *curr, *temp; for (i = 1; i < MAX_NUM_WORMS; i++) { - if (nhfp->structlevel) + if (nhfp->structlevel) { mread(nhfp->fd, (genericptr_t) &count, sizeof count); + } /* Get the segments. */ for (curr = (struct wseg *) 0, j = 0; j < count; j++) { @@ -600,8 +604,10 @@ rest_worm(NHFILE *nhfp) } wheads[i] = curr; } - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) wgrowtime, sizeof wgrowtime); + for (i = 0; i < MAX_NUM_WORMS; ++i) { + if (nhfp->structlevel) { + mread(nhfp->fd, (genericptr_t) &wgrowtime[i], sizeof (long)); + } } } diff --git a/sys/share/pcmain.c b/sys/share/pcmain.c index 5d60053cd..cad2bc69a 100644 --- a/sys/share/pcmain.c +++ b/sys/share/pcmain.c @@ -429,8 +429,9 @@ _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);*/ raw_print("Cannot create lock file"); } else { svh.hackpid = 1; - if (nhfp->structlevel) - write(nhfp->fd, (genericptr_t) &svh.hackpid, sizeof(svh.hackpid)); + if (nhfp->structlevel) { + write(nhfp->fd, (genericptr_t) &svh.hackpid, sizeof svh.hackpid); + } close_nhfile(nhfp); } diff --git a/util/makedefs.c b/util/makedefs.c index 1af34cb2e..bc86614bd 100644 --- a/util/makedefs.c +++ b/util/makedefs.c @@ -1869,18 +1869,6 @@ do_date(void) } Fprintf(ofp, "#define VERSION_SANITY1 0x%08lx%s\n", version.entity_count, ul_sfx); -#ifndef __EMSCRIPTEN__ - Fprintf(ofp, "#define VERSION_SANITY2 0x%08lx%s\n", version.struct_sizes1, - ul_sfx); - Fprintf(ofp, "#define VERSION_SANITY3 0x%08lx%s\n", version.struct_sizes2, - ul_sfx); -#else /* __EMSCRIPTEN__ */ - Fprintf(ofp, "#define VERSION_SANITY2 0x%08llx%s\n", version.struct_sizes1, - ul_sfx); - Fprintf(ofp, "#define VERSION_SANITY3 0x%08llx%s\n", version.struct_sizes2, - ul_sfx); -#endif /* !__EMSCRIPTEN__ */ - Fprintf(ofp, "\n"); Fprintf(ofp, "#define VERSION_STRING \"%s\"\n", mdlib_version_string(buf, ".")); From 502b60d210994d89f23e65dae80e05ff49f17559 Mon Sep 17 00:00:00 2001 From: nhmall Date: Tue, 15 Apr 2025 15:49:36 -0400 Subject: [PATCH 563/791] follow-up bit oextra should have been included in the critical bytes --- include/patchlevel.h | 2 +- src/version.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/patchlevel.h b/include/patchlevel.h index 1fcec2047..905dff4fe 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 122 +#define EDITLEVEL 123 /* * Development status possibilities. diff --git a/src/version.c b/src/version.c index 83f119859..72ea79348 100644 --- a/src/version.c +++ b/src/version.c @@ -581,6 +581,7 @@ struct critical_sizes_with_names critical_sizes[] = { { (uchar) sizeof(struct mvitals), "struct mvitals" }, { (uchar) sizeof(struct obj), "struct obj" }, { (uchar) sizeof(struct objclass), "struct objclass" }, + { (uchar) sizeof(struct oextra), "struct oextra" }, { (uchar) sizeof(struct q_score), "struct q_score" }, { (uchar) sizeof(struct rm), "struct rm" }, { (uchar) sizeof(struct spell), "struct spell" }, @@ -616,7 +617,6 @@ struct critical_sizes_with_names critical_sizes[] = { { (uchar) sizeof(struct fakecorridor), "struct fakecorridor" }, { (uchar) sizeof(struct bill_x), "struct bill_x" }, { (uchar) sizeof(union vptrs), "union vptrs" }, - { (uchar) sizeof(struct oextra), "struct oextra" }, { (uchar) sizeof(struct prop), "struct prop" }, { (uchar) sizeof(struct skills), "struct skills" }, { (uchar) sizeof(union vlaunchinfo), "union vlaunchinfo" }, From 44af2a96a55d33a5f1575edbe22dbf8cf5543f35 Mon Sep 17 00:00:00 2001 From: nhmall Date: Tue, 15 Apr 2025 18:02:44 -0400 Subject: [PATCH 564/791] recover utility updates --- src/version.c | 6 +++++ sys/unix/Makefile.utl | 7 ++++- util/recover.c | 62 +++++++++++++++++++++++-------------------- 3 files changed, 45 insertions(+), 30 deletions(-) diff --git a/src/version.c b/src/version.c index 72ea79348..f1303744d 100644 --- a/src/version.c +++ b/src/version.c @@ -3,9 +3,12 @@ /*-Copyright (c) Michael Allison, 2018. */ /* NetHack may be freely redistributed. See license for details. */ + #include "hack.h" #include "dlb.h" +#ifndef MINIMAL_FOR_RECOVER + #ifndef OPTIONS_AT_RUNTIME #define OPTIONS_AT_RUNTIME #endif @@ -513,6 +516,7 @@ dump_version_info(void) release_runtime_info(); return; } +#endif /* MINIMAL_FOR_RECOVER */ struct critical_sizes_with_names { uchar ucsize; @@ -647,6 +651,7 @@ get_critical_size_count(void) return SIZE(critical_sizes); } +#ifndef MINIMAL_FOR_RECOVER void store_critical_bytes(NHFILE *nhfp) { @@ -741,5 +746,6 @@ compare_critical_bytes(NHFILE *nhfp) } return 0; /* everything matched */ } +#endif /* MINIMAL_FOR_RECOVER */ /*version.c*/ diff --git a/sys/unix/Makefile.utl b/sys/unix/Makefile.utl index 770213255..1936257b0 100644 --- a/sys/unix/Makefile.utl +++ b/sys/unix/Makefile.utl @@ -200,7 +200,7 @@ HACKLIBOBJ = $(OBJDIR)/hacklib.o panic.o MAKEOBJS = makedefs.o $(OMONOBJ) $(ODATE) $(OALLOC) # object files for recovery utility -RECOVOBJS = recover.o +RECOVOBJS = recover.o recover-version.o # object files for the data librarian DLBOBJS = dlb_main.o $(OBJDIR)/dlb.o $(OALLOC) @@ -284,6 +284,11 @@ recover: $(RECOVOBJS) $(HACKLIB) recover.o: recover.c $(CONFIG_H) $(CC) $(CFLAGS) $(CSTD) -c recover.c -o $@ +recover-version.o: ../src/version.c $(HACK_H) + $(CC) $(CFLAGS) $(CSTD) -DMINIMAL_FOR_RECOVER -c ../src/version.c -o $@ + +recover-sfstruct.o: ../src/sfstruct.c $(HACK_H) + $(CC) $(CFLAGS) $(CSTD) -DMINIMAL_FOR_RECOVER -c ../src/sfstruct.c -o $@ # dependencies for dlb # diff --git a/util/recover.c b/util/recover.c index 8c701c799..85aceb4ce 100644 --- a/util/recover.c +++ b/util/recover.c @@ -34,7 +34,9 @@ int restore_savefile(char *); void set_levelfile_name(int); int open_levelfile(int); int create_savefile(void); -static void store_formatindicator(int); + +extern int get_critical_size_count(void); +extern uchar cscbuf[]; #ifndef WIN_CE #define Fprintf (void) fprintf @@ -201,17 +203,15 @@ int restore_savefile(char *basename) { int gfd, lfd, sfd; - int res = 0, lev, savelev, hpid, pltmpsiz, filecmc; + int res = 0, lev, savelev, hpid, pltmpsiz; xint8 levc; struct version_info version_data; - struct savefile_info sfi; - char plbuf[PL_NSIZ], indicator; + char plbuf[PL_NSIZ], indicator, cscsize; /* level 0 file contains: * pid of creating process (ignored here) * level number for current level of save file * name of save file nethack would have created - * savefile info * player name * and game state */ @@ -252,11 +252,12 @@ restore_savefile(char *basename) != sizeof savename) || (read(gfd, (genericptr_t) &indicator, sizeof indicator) != sizeof indicator) - || (read(gfd, (genericptr_t) &filecmc, sizeof filecmc) - != sizeof filecmc) + || (read(gfd, (genericptr_t) &cscsize, sizeof cscsize) + != sizeof cscsize) + || (read(gfd, (genericptr_t) &cscbuf, cscsize) + != cscsize) || (read(gfd, (genericptr_t) &version_data, sizeof version_data) != sizeof version_data) - || (read(gfd, (genericptr_t) &sfi, sizeof sfi) != sizeof sfi) || (read(gfd, (genericptr_t) &pltmpsiz, sizeof pltmpsiz) != sizeof pltmpsiz) || (pltmpsiz > PL_NSIZ) || (read(gfd, (genericptr_t) plbuf, pltmpsiz) != pltmpsiz)) { @@ -289,20 +290,35 @@ restore_savefile(char *basename) return -1; } - store_formatindicator(sfd); - if (write(sfd, (genericptr_t) &version_data, sizeof version_data) - != sizeof version_data) { - Fprintf(stderr, "Error writing %s; recovery failed.\n", savename); + if (write(sfd, (genericptr_t) &indicator, sizeof indicator) + != sizeof indicator) { + Fprintf(stderr, "Error writing %s %s; recovery failed.\n", + savename, "indicator"); Close(gfd); Close(sfd); Close(lfd); return -1; } - - if (write(sfd, (genericptr_t) &sfi, sizeof sfi) != sizeof sfi) { - Fprintf(stderr, - "Error writing %s; recovery failed (savefile_info).\n", - savename); + if (write(sfd, (genericptr_t) &cscsize, sizeof cscsize) != sizeof cscsize) { + Fprintf(stderr, "Error writing %s %s; recovery failed.\n", + savename, "cscsize"); + Close(gfd); + Close(sfd); + Close(lfd); + return -1; + } + if (write(sfd, (genericptr_t) &cscbuf, cscsize) != cscsize) { + Fprintf(stderr, "Error writing %s %s; recovery failed.\n", + savename, "critical bytes"); + Close(gfd); + Close(sfd); + Close(lfd); + return -1; + } + if (write(sfd, (genericptr_t) &version_data, sizeof version_data) + != sizeof version_data) { + Fprintf(stderr, "Error writing %s %s; recovery failed.\n", + savename, "version_data"); Close(gfd); Close(sfd); Close(lfd); @@ -399,18 +415,6 @@ restore_savefile(char *basename) return res; } -static void -store_formatindicator(int fd) -{ - char indicate = 'h'; /* historical */ - int cmc = 0; - - (void) write(fd, (genericptr_t) &indicate, sizeof indicate); - (void) write(fd, (genericptr_t) &cmc, sizeof cmc); -} - - - #ifdef EXEPATH #ifdef __DJGPP__ #define PATH_SEPARATOR '/' From 46d4639d661f692c4e00a69178531bb8d15791c5 Mon Sep 17 00:00:00 2001 From: nhmall Date: Tue, 15 Apr 2025 18:56:34 -0400 Subject: [PATCH 565/791] visual studio build fix (for recover) --- src/files.c | 8 ++++---- sys/windows/vs/recover/recover.vcxproj | 5 ++++- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/files.c b/src/files.c index 5489b0f41..8e7d214a9 100644 --- a/src/files.c +++ b/src/files.c @@ -4253,13 +4253,14 @@ boolean recover_savefile(void) { NHFILE *gnhfp, *lnhfp, *snhfp; - int lev, savelev, hpid, pltmpsiz, filecmc; + int lev, savelev, hpid, pltmpsiz; xint8 levc; struct version_info version_data; int processed[256]; char savename[SAVESIZE], errbuf[BUFSZ], indicator; char tmpplbuf[PL_NSIZ_PLUS]; const char *savewrite_failure = (const char *) 0; + int ccbresult = 0; for (lev = 0; lev < 256; lev++) processed[lev] = 0; @@ -4298,8 +4299,7 @@ recover_savefile(void) != sizeof savename) || (read(gnhfp->fd, (genericptr_t) &indicator, sizeof indicator) != sizeof indicator) - || (read(gnhfp->fd, (genericptr_t) &filecmc, sizeof filecmc) - != sizeof filecmc) + || ((ccbresult = compare_critical_bytes(gnhfp)) != 0) || (read(gnhfp->fd, (genericptr_t) &version_data, sizeof version_data) != sizeof version_data) || (read(gnhfp->fd, (genericptr_t) &pltmpsiz, sizeof pltmpsiz) @@ -4312,7 +4312,7 @@ recover_savefile(void) } /* save file should contain: - * format indicator and cmc + * format indicator and critical_bytes * version info * plnametmp = player name size (int, 2 bytes) * player name (PL_NSIZ_PLUS) diff --git a/sys/windows/vs/recover/recover.vcxproj b/sys/windows/vs/recover/recover.vcxproj index 66fd134d0..b8e080962 100644 --- a/sys/windows/vs/recover/recover.vcxproj +++ b/sys/windows/vs/recover/recover.vcxproj @@ -30,6 +30,9 @@ + + WIN32CON;DLB;MSWIN_GRAPHICS;HAS_STDINT_H;MINIMAL_FOR_RECOVER;%(PreprocessorDefinitions) + @@ -50,4 +53,4 @@ - + \ No newline at end of file From 5560bdb27cb899a8ef60a0004b5ca0e999ab69ee Mon Sep 17 00:00:00 2001 From: nhmall Date: Tue, 15 Apr 2025 19:53:50 -0400 Subject: [PATCH 566/791] msdos recover --- sys/unix/hints/include/cross-post.370 | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/sys/unix/hints/include/cross-post.370 b/sys/unix/hints/include/cross-post.370 index 93f01f9dc..3e9a9cd39 100644 --- a/sys/unix/hints/include/cross-post.370 +++ b/sys/unix/hints/include/cross-post.370 @@ -246,14 +246,16 @@ ifdef MAKEFILE_UTL $(TARGETPFX)recover.o: recover.c $(CONFIG_H) $(TARGET_CC) $(TARGET_CFLAGS) $(CSTD) -c recover.c -o $@ ifdef CROSS_TO_MSDOS -$(TARGETPFX)recover.exe : $(TARGETPFX)recover.o $(TARGETPFX)hacklib.a +$(TARGETPFX)recover.exe : $(TARGETPFX)recover.o $(TARGETPFX)rversion.o $(TARGETPFX)hacklib.a $(TARGET_LINK) $(TARGET_LFLAGS) \ - $(TARGETPFX)recover.o $(TARGETPFX)hacklib.a -o $@ + $(TARGETPFX)recover.o $(TARGETPFX)rversion.o $(TARGETPFX)hacklib.a -o $@ else -$(TARGETPFX)recover : $(TARGETPFX)recover.o $(TARGETPFX)hacklib.a +$(TARGETPFX)recover : $(TARGETPFX)recover.o $(TARGETPFX)rversion.o $(TARGETPFX)hacklib.a $(TARGET_LINK) $(TARGET_LFLAGS) \ - $(TARGETPFX)recover.o $(TARGETPFX)hacklib.a -o $@ + $(TARGETPFX)recover.o $(TARGETPFX)rversion.o $(TARGETPFX)hacklib.a -o $@ endif +$(TARGETPFX)rversion.o: ../src/version.c $(HACK_H) + $(TARGET_CC) $(TARGET_CFLAGS) -DMINIMAL_FOR_RECOVER $(CSTD) -c ../src/version.c -o $@ endif # MAKEFILE_UTL endif # CROSS From 28d2ff516c0dac9af0ef42a245363feef3860549 Mon Sep 17 00:00:00 2001 From: nhmall Date: Tue, 15 Apr 2025 19:58:25 -0400 Subject: [PATCH 567/791] sys/windows/GNUmakefile recover --- sys/windows/GNUmakefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sys/windows/GNUmakefile b/sys/windows/GNUmakefile index 29085431c..b7611b61a 100644 --- a/sys/windows/GNUmakefile +++ b/sys/windows/GNUmakefile @@ -523,7 +523,7 @@ CLEAN_FILE += $(MTARGETS) $(MOBJS) # Recover #========================================== OR = $(OBJ) -ROBJS = $(OR)/recover.o +ROBJS = $(OR)/recover.o $(OR)/rversion.o RTARGETS = $(GAMEDIR)/recover.txt $(GAMEDIR)/recover.exe recover: $(RTARGETS) @@ -536,6 +536,8 @@ $(GAMEDIR)/recover.exe: $(ROBJS) $(HLHACKLIB) | $(GAMEDIR) $(OR)/recover.o: $(U)recover.c | $(OR) $(cc) $(CFLAGSU) $< -o$@ +$(OR)/rversion.o: $(SRC)version.c | $(OR) + $(cc) $(CFLAGSU) $< -o$@ # $(OR): # @mkdir -p $@ From 6cf9415b72d66ace817c46bfc8558feafcbb8c93 Mon Sep 17 00:00:00 2001 From: nhmall Date: Tue, 15 Apr 2025 20:01:02 -0400 Subject: [PATCH 568/791] add define to GNUmakefile build --- sys/windows/GNUmakefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/windows/GNUmakefile b/sys/windows/GNUmakefile index b7611b61a..b7860caff 100644 --- a/sys/windows/GNUmakefile +++ b/sys/windows/GNUmakefile @@ -537,7 +537,7 @@ $(GAMEDIR)/recover.exe: $(ROBJS) $(HLHACKLIB) | $(GAMEDIR) $(OR)/recover.o: $(U)recover.c | $(OR) $(cc) $(CFLAGSU) $< -o$@ $(OR)/rversion.o: $(SRC)version.c | $(OR) - $(cc) $(CFLAGSU) $< -o$@ + $(cc) $(CFLAGSU) -DMINIMAL_FOR_RECOVER $< -o$@ # $(OR): # @mkdir -p $@ From dcb0fc76543e14607da50fe33569364298a0f76f Mon Sep 17 00:00:00 2001 From: nhmall Date: Tue, 15 Apr 2025 20:03:28 -0400 Subject: [PATCH 569/791] remove unused target from Makefile.utl --- sys/unix/Makefile.utl | 3 --- 1 file changed, 3 deletions(-) diff --git a/sys/unix/Makefile.utl b/sys/unix/Makefile.utl index 1936257b0..c63caea3b 100644 --- a/sys/unix/Makefile.utl +++ b/sys/unix/Makefile.utl @@ -287,9 +287,6 @@ recover.o: recover.c $(CONFIG_H) recover-version.o: ../src/version.c $(HACK_H) $(CC) $(CFLAGS) $(CSTD) -DMINIMAL_FOR_RECOVER -c ../src/version.c -o $@ -recover-sfstruct.o: ../src/sfstruct.c $(HACK_H) - $(CC) $(CFLAGS) $(CSTD) -DMINIMAL_FOR_RECOVER -c ../src/sfstruct.c -o $@ - # dependencies for dlb # dlb: $(DLBOBJS) $(HACKLIB) From c2a2d5e344ba8a2fc96908c2c4b9df02f2b246b4 Mon Sep 17 00:00:00 2001 From: nhmall Date: Tue, 15 Apr 2025 21:02:16 -0400 Subject: [PATCH 570/791] fix some issues with recover unrelated to today's changes --- util/recover.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/util/recover.c b/util/recover.c index 85aceb4ce..07481cbc5 100644 --- a/util/recover.c +++ b/util/recover.c @@ -206,7 +206,7 @@ restore_savefile(char *basename) int res = 0, lev, savelev, hpid, pltmpsiz; xint8 levc; struct version_info version_data; - char plbuf[PL_NSIZ], indicator, cscsize; + char plbuf[PL_NSIZ_PLUS], indicator, cscsize; /* level 0 file contains: * pid of creating process (ignored here) @@ -259,7 +259,7 @@ restore_savefile(char *basename) || (read(gfd, (genericptr_t) &version_data, sizeof version_data) != sizeof version_data) || (read(gfd, (genericptr_t) &pltmpsiz, sizeof pltmpsiz) - != sizeof pltmpsiz) || (pltmpsiz > PL_NSIZ) + != sizeof pltmpsiz) || (pltmpsiz > PL_NSIZ_PLUS) || (read(gfd, (genericptr_t) plbuf, pltmpsiz) != pltmpsiz)) { Fprintf(stderr, "Error reading %s -- can't recover.\n", lock); Close(gfd); From 8c23cfe4e4b20e351cfa06bc0454649045648f0b Mon Sep 17 00:00:00 2001 From: nhmall Date: Tue, 15 Apr 2025 21:03:59 -0400 Subject: [PATCH 571/791] some cleanup --- src/save.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/save.c b/src/save.c index bc8c55124..87d4c18c6 100644 --- a/src/save.c +++ b/src/save.c @@ -32,14 +32,6 @@ staticfn void savegamestate(NHFILE *); staticfn void savelev_core(NHFILE *, xint8); staticfn void save_msghistory(NHFILE *); -#ifdef ZEROCOMP -staticfn void zerocomp_bufon(int); -staticfn void zerocomp_bufoff(int); -staticfn void zerocomp_bflush(int); -staticfn void zerocomp_bwrite(int, genericptr_t, unsigned int); -staticfn void zerocomp_bputc(int); -#endif - #if defined(HANGUPHANDLING) #define HUP if (!program_state.done_hup) #else From 799e252c214e0e3fbb7d64ea5e5c7f54db5439ec Mon Sep 17 00:00:00 2001 From: nhmall Date: Tue, 15 Apr 2025 21:08:03 -0400 Subject: [PATCH 572/791] GNUmakefile requires slashes between macro and file --- sys/windows/GNUmakefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/windows/GNUmakefile b/sys/windows/GNUmakefile index b7860caff..e16bdb31e 100644 --- a/sys/windows/GNUmakefile +++ b/sys/windows/GNUmakefile @@ -536,7 +536,7 @@ $(GAMEDIR)/recover.exe: $(ROBJS) $(HLHACKLIB) | $(GAMEDIR) $(OR)/recover.o: $(U)recover.c | $(OR) $(cc) $(CFLAGSU) $< -o$@ -$(OR)/rversion.o: $(SRC)version.c | $(OR) +$(OR)/rversion.o: $(SRC)/version.c | $(OR) $(cc) $(CFLAGSU) -DMINIMAL_FOR_RECOVER $< -o$@ # $(OR): From 01e031e639e1e01e69f3f81b78437e765300c3d1 Mon Sep 17 00:00:00 2001 From: nhmall Date: Wed, 16 Apr 2025 10:10:34 -0400 Subject: [PATCH 573/791] visual studio recover project update --- sys/windows/vs/recover/recover.vcxproj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sys/windows/vs/recover/recover.vcxproj b/sys/windows/vs/recover/recover.vcxproj index b8e080962..d03553015 100644 --- a/sys/windows/vs/recover/recover.vcxproj +++ b/sys/windows/vs/recover/recover.vcxproj @@ -19,7 +19,7 @@ $(IncDir);$(SysWindDir);$(LuaDir);%(AdditionalIncludeDirectories) - WIN32CON;DLB;MSWIN_GRAPHICS;HAS_STDINT_H;%(PreprocessorDefinitions) + WIN32CON;DLB;MSWIN_GRAPHICS;HAS_STDINT_H;MINIMAL_FOR_RECOVER;%(PreprocessorDefinitions) stdclatest /w45262 %(AdditionalOptions) @@ -30,7 +30,7 @@ - + WIN32CON;DLB;MSWIN_GRAPHICS;HAS_STDINT_H;MINIMAL_FOR_RECOVER;%(PreprocessorDefinitions) @@ -53,4 +53,4 @@ - \ No newline at end of file + From 86bfb3e2f974fae81fa6ef205ed5039ea3a193e6 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Wed, 16 Apr 2025 18:08:33 +0300 Subject: [PATCH 574/791] Avoid map accessibility notices when map isn't updated --- src/display.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/display.c b/src/display.c index 716bdf2b8..c14165c3d 100644 --- a/src/display.c +++ b/src/display.c @@ -1998,8 +1998,9 @@ show_glyph(coordxy x, coordxy y, int glyph) oldglyph = gg.gbuf[y][x].glyphinfo.glyph; if (a11y.glyph_updates && !a11y.mon_notices_blocked - && !program_state.in_docrt - && !program_state.in_getlev + && !program_state.in_docrt && !program_state.gameover + && !program_state.in_getlev && !program_state.stopprint + && !_suppress_map_output() && (oldglyph != glyph || gg.gbuf[y][x].gnew)) { int c = glyph_to_cmap(glyph); From e024cbc57a6836050478fcc7e6ee554786aff38d Mon Sep 17 00:00:00 2001 From: nhmall Date: Wed, 16 Apr 2025 12:45:32 -0400 Subject: [PATCH 575/791] go.omoves to svo.omoves since it is read from savefile --- include/decl.h | 3 ++- src/decl.c | 6 +++--- src/restore.c | 8 ++++---- src/save.c | 1 + 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/include/decl.h b/include/decl.h index c95d6d5b1..b201816f3 100644 --- a/include/decl.h +++ b/include/decl.h @@ -732,7 +732,6 @@ struct instance_globals_o { /* restore.c */ struct fruit *oldfruit; - long omoves; /* rumors.c */ int oracle_flg; /* -1=>don't use, 0=>need init, 1=>init done */ @@ -1170,6 +1169,8 @@ struct instance_globals_saved_n { struct instance_globals_saved_o { /* rumors.c */ unsigned oracle_cnt; /* oracles are handled differently from rumors... */ + /* other */ + long omoves; /* level timestamp */ }; struct instance_globals_saved_p { diff --git a/src/decl.c b/src/decl.c index 3859f5a2f..e4dc3c6e8 100644 --- a/src/decl.c +++ b/src/decl.c @@ -117,7 +117,6 @@ const char ynNaqchars[] = "yn#aq"; const char rightleftchars[] = "rl"; const char hidespinchars[] = "hsq"; NEARDATA long yn_number = 0L; - #ifdef PANICTRACE const char *ARGV0; #endif @@ -601,7 +600,6 @@ static const struct instance_globals_o g_init_o = { 0, /* oldcap */ /* restore.c */ UNDEFINED_PTR, /* oldfruit */ - 0L, /* omoves */ /* rumors.c */ 0, /* oracle_flag */ UNDEFINED_PTR, /* oracle_loc */ @@ -931,7 +929,9 @@ static const struct instance_globals_saved_n init_svn = { static const struct instance_globals_saved_o init_svo = { /* rumors.c */ - 0U /* oracle_cnt */ + 0U, /* oracle_cnt */ + /* other */ + 0L /* omoves */ }; static const struct instance_globals_saved_p init_svp = { diff --git a/src/restore.c b/src/restore.c index 05292b5d9..dc89bd33d 100644 --- a/src/restore.c +++ b/src/restore.c @@ -171,7 +171,7 @@ restdamage(NHFILE *nhfp) } if (ghostly) - tmp_dam->when += (svm.moves - go.omoves); + tmp_dam->when += (svm.moves - svo.omoves); tmp_dam->next = svl.level.damagelist; svl.level.damagelist = tmp_dam; @@ -276,7 +276,7 @@ restobjchn(NHFILE *nhfp, boolean frozen) * immediately after old player died. */ if (ghostly && !frozen && !age_is_relative(otmp)) - otmp->age = svm.moves - go.omoves + otmp->age; + otmp->age = svm.moves - svo.omoves + otmp->age; /* get contents of a container or statue */ if (Has_contents(otmp)) { @@ -1081,8 +1081,8 @@ getlev(NHFILE *nhfp, int pid, xint8 lev) Mread(nhfp->fd, &svl.lastseentyp[c][r], sizeof (schar)); } } - Mread(nhfp->fd, &go.omoves, sizeof go.omoves); - elapsed = svm.moves - go.omoves; + Mread(nhfp->fd, &svo.omoves, sizeof svo.omoves); + elapsed = svm.moves - svo.omoves; rest_stairs(nhfp); if (nhfp->structlevel) { diff --git a/src/save.c b/src/save.c index 87d4c18c6..3ba551ea9 100644 --- a/src/save.c +++ b/src/save.c @@ -316,6 +316,7 @@ savegamestate(NHFILE *nhfp) save_dungeon(nhfp, (boolean) !!perform_bwrite(nhfp), (boolean) !!release_data(nhfp)); savelevchn(nhfp); + /* svm.moves below will actually be read back into svo.omoves on restore */ if (nhfp->structlevel) { bwrite(nhfp->fd, (genericptr_t) &svm.moves, sizeof svm.moves); bwrite(nhfp->fd, (genericptr_t) &svq.quest_status, From 15fa0758f2db2528b8b1541dd09d6ecaaa223f3b Mon Sep 17 00:00:00 2001 From: nhmall Date: Wed, 16 Apr 2025 13:39:32 -0400 Subject: [PATCH 576/791] put added comment in the correct place --- src/save.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/save.c b/src/save.c index 3ba551ea9..974f25995 100644 --- a/src/save.c +++ b/src/save.c @@ -316,7 +316,6 @@ savegamestate(NHFILE *nhfp) save_dungeon(nhfp, (boolean) !!perform_bwrite(nhfp), (boolean) !!release_data(nhfp)); savelevchn(nhfp); - /* svm.moves below will actually be read back into svo.omoves on restore */ if (nhfp->structlevel) { bwrite(nhfp->fd, (genericptr_t) &svm.moves, sizeof svm.moves); bwrite(nhfp->fd, (genericptr_t) &svq.quest_status, @@ -532,9 +531,12 @@ savelev_core(NHFILE *nhfp, xint8 lev) bwrite(nhfp->fd, (genericptr_t) &svl.lastseentyp[c][r], sizeof(schar)); } + /* svm.moves below will actually be read back into svo.omoves on restore */ if (nhfp->structlevel) { bwrite(nhfp->fd, (genericptr_t) &svm.moves, sizeof svm.moves); - save_stairs(nhfp); + } + save_stairs(nhfp); + if (nhfp->structlevel) { bwrite(nhfp->fd, (genericptr_t) &svu.updest, sizeof(dest_area)); bwrite(nhfp->fd, (genericptr_t) &svd.dndest, sizeof(dest_area)); bwrite(nhfp->fd, (genericptr_t) &svl.level.flags, From a7412dc83508b70f085e3852dd4442a560481f9f Mon Sep 17 00:00:00 2001 From: PatR Date: Wed, 16 Apr 2025 12:46:28 -0700 Subject: [PATCH 577/791] add '--debug:fuzzer' command line option Provide a way to bypass a debugger when initiating fuzzing. nethack -D --debug:fuzzer # run fuzzer in wizard mode nethack --debug:fuzzer # run it in normal mode nethack [-D] -@ --debug:fuzzer # skip role/race/&c selection --- include/flag.h | 10 +++++++--- src/allmain.c | 11 ++++++++++- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/include/flag.h b/include/flag.h index 01ad42fb0..d9d2ddf9a 100644 --- a/include/flag.h +++ b/include/flag.h @@ -1,4 +1,4 @@ -/* NetHack 3.7 flag.h $NHDT-Date: 1715979826 2024/05/17 21:03:46 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.246 $ */ +/* NetHack 3.7 flag.h $NHDT-Date: 1744860497 2025/04/16 19:28:17 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.251 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2006. */ /* NetHack may be freely redistributed. See license for details. */ @@ -237,9 +237,11 @@ enum debug_fuzzer_states { * and probably warrant a structure of their own elsewhere some day. */ struct instance_flags { - boolean query_menu; /* use a menu for yes/no queries */ - boolean showdamage; boolean defer_plname; /* X11 hack: askname() might not set svp.plname */ + boolean fuzzerpending; /* fuzzing requested on command line but not active + * yet (to allow interactive initialization prior + * to input becoming taken over); + * True => enable fuzzer when entering moveloop */ boolean herecmd_menu; /* use menu when mouseclick on yourself */ boolean invis_goldsym; /* gold symbol is ' '? */ boolean in_lua; /* executing a lua script */ @@ -247,8 +249,10 @@ struct instance_flags { boolean nofollowers; /* level change ignores pets (for tutorial) */ boolean partly_eaten_hack; /* extra flag for xname() used when it's called * indirectly so we can't use xname_flags() */ + boolean query_menu; /* use a menu for yes/no queries */ boolean remember_getpos; /* save getpos() positioning in do-again queue */ boolean sad_feeling; /* unseen pet is dying */ + boolean showdamage; /* extra message reporting damage hero has taken */ xint8 debug_fuzzer; /* fuzz testing */ int at_midnight; /* only valid during end of game disclosure */ int at_night; /* also only valid during end of game disclosure */ diff --git a/src/allmain.c b/src/allmain.c index 237ec2c06..5620e1eac 100644 --- a/src/allmain.c +++ b/src/allmain.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 allmain.c $NHDT-Date: 1742207239 2025/03/17 02:27:19 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.275 $ */ +/* NetHack 3.7 allmain.c $NHDT-Date: 1744860497 2025/04/16 19:28:17 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.276 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -99,6 +99,12 @@ moveloop_preamble(boolean resuming) u.uz0.dlevel = u.uz.dlevel; svc.context.move = 0; + /* finish processing "--debug:fuzzer" from the command line */ + if (iflags.fuzzerpending) { + iflags.debug_fuzzer = fuzzer_impossible_panic; + iflags.fuzzerpending = FALSE; + } + program_state.in_moveloop = 1; /* for perm_invent preset at startup, display persistent inventory after invent is fully populated and the in_moveloop flag has been set */ @@ -1078,6 +1084,7 @@ argcheck(int argc, char *argv[], enum earlyarg e_arg) * immediateflips - WIN32: turn off display performance * optimization so that display output * can be debugged without buffering. + * fuzzer - enable fuzzer without debugger intervention. */ staticfn void debug_fields(const char *opts) @@ -1122,6 +1129,8 @@ debug_fields(const char *opts) if (match_optname(opts, "immediateflips", 14, FALSE)) iflags.debug.immediateflips = negated ? FALSE : TRUE; #endif + if (match_optname(opts, "fuzzer", 4, FALSE)) + iflags.fuzzerpending = TRUE; return; } From f887ba7704c45ae471a321b4a0a709dc1f8a7b39 Mon Sep 17 00:00:00 2001 From: PatR Date: Wed, 16 Apr 2025 13:14:42 -0700 Subject: [PATCH 578/791] build fix for MONITOR_HEAP Compile of alloc.c failed when MONITOR_HEAP is defined. --- src/alloc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/alloc.c b/src/alloc.c index 72faa160b..158d03a55 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -221,7 +221,7 @@ nhdupstr(const char *string, const char *file, int line) /* we've got some info about the caller, so use it instead of __func__ */ unsigned len = FITSuint_(strlen(string), file, line); - if (FITSuint(len + 1, file, line) < len) + if (FITSuint_(len + 1, file, line) < len) panic("nhdupstr: string length overflow, line %d of %s", line, file); From d4008772ac05a6b36f4262481105ea75e9d20159 Mon Sep 17 00:00:00 2001 From: PatR Date: Wed, 16 Apr 2025 13:17:36 -0700 Subject: [PATCH 579/791] build fix for SCORE_ON_BOTL Warning about missing parantheses when mixing '+' and '?:'. It didn't cause 'make' to quit but resulted in incorrect score-in-progress values eing generated. --- src/botl.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/botl.c b/src/botl.c index 7cd0f3a0d..f3ad98aa5 100644 --- a/src/botl.c +++ b/src/botl.c @@ -422,7 +422,7 @@ max_rank_sz(void) long botl_score(void) { - long deepest = deepest_lev_reached(FALSE); + long deepest = (long) deepest_lev_reached(FALSE); long umoney, depthbonus; /* hidden_gold(False): only gold in containers whose contents are known */ @@ -430,10 +430,10 @@ botl_score(void) /* don't include initial gold; don't impose penalty if it's all gone */ if ((umoney -= u.umoney0) < 0L) umoney = 0L; - depthbonus = 50 * (deepest - 1) - + (deepest > 30) ? 10000 - : (deepest > 20) ? 1000 * (deepest - 20) - : 0; + depthbonus = (50L * (deepest - 1L)) + + ((deepest > 30L) ? 10000L + : (deepest > 20L) ? (1000L * (deepest - 20L)) + : 0L); /* neither umoney nor depthbonus can grow unusually big (gold due to weight); u.urexp might */ return nowrap_add(u.urexp, umoney + depthbonus); From 830e18f52e5183b94dc20ce0a6aa6e26ee73196c Mon Sep 17 00:00:00 2001 From: nhmall Date: Wed, 16 Apr 2025 16:56:17 -0400 Subject: [PATCH 580/791] some cleanup of stale bits --- include/extern.h | 1 - include/global.h | 25 ------------------------- src/do.c | 1 - src/save.c | 1 - src/sfstruct.c | 6 ------ 5 files changed, 34 deletions(-) diff --git a/include/extern.h b/include/extern.h index 585b2273b..ecb1ee654 100644 --- a/include/extern.h +++ b/include/extern.h @@ -2664,7 +2664,6 @@ extern void get_plname_from_file(NHFILE *, char *, boolean) NONNULLARG12; #ifdef SELECTSAVED extern int restore_menu(winid); #endif -extern void minit(void); extern boolean lookup_id_mapping(unsigned, unsigned *) NONNULLARG2; extern int validate(NHFILE *, const char *, boolean) NONNULLARG1; /* extern void reset_restpref(void); */ diff --git a/include/global.h b/include/global.h index db6faa52d..a38c7722b 100644 --- a/include/global.h +++ b/include/global.h @@ -115,16 +115,6 @@ typedef uchar nhsym; #endif #endif -#if 0 -/* comment out to test effects of each #define -- these will probably - * disappear eventually - */ -#ifdef INTERNAL_COMP -#define RLECOMP /* run-length compression of levl array - JLee */ -#define ZEROCOMP /* zero-run compression of everything - Olaf Seibert */ -#endif -#endif - /* #define SPECIALIZATION */ /* do "specialized" version of new topology */ #ifdef BITFIELDS @@ -359,21 +349,6 @@ struct version_info { unsigned long entity_count; /* # of monsters and objects */ }; -struct savefile_info { - unsigned long sfi1; /* compression etc. */ - unsigned long sfi2; /* miscellaneous */ - unsigned long sfi3; /* thirdparty */ -}; -#ifdef NHSTDC -#define SFI1_EXTERNALCOMP (1UL) -#define SFI1_RLECOMP (1UL << 1) -#define SFI1_ZEROCOMP (1UL << 2) -#else -#define SFI1_EXTERNALCOMP (1L) -#define SFI1_RLECOMP (1L << 1) -#define SFI1_ZEROCOMP (1L << 2) -#endif - /* This is used to store some build-info data that used to be present in makedefs-generated header file date.h */ diff --git a/src/do.c b/src/do.c index 2d1d7d57b..ae26e7158 100644 --- a/src/do.c +++ b/src/do.c @@ -1708,7 +1708,6 @@ goto_level( } reseed_random(rn2); reseed_random(rn2_on_display_rng); - minit(); /* ZEROCOMP */ getlev(nhfp, svh.hackpid, new_ledger); close_nhfile(nhfp); oinit(); /* reassign level dependent obj probabilities */ diff --git a/src/save.c b/src/save.c index 974f25995..f7aab28b8 100644 --- a/src/save.c +++ b/src/save.c @@ -204,7 +204,6 @@ dosave0(void) HUP done(TRICKED); goto done; } - minit(); /* ZEROCOMP */ getlev(onhfp, svh.hackpid, ltmp); close_nhfile(onhfp); if (nhfp->structlevel) { diff --git a/src/sfstruct.c b/src/sfstruct.c index ae0b2c5fd..f4a09163f 100644 --- a/src/sfstruct.c +++ b/src/sfstruct.c @@ -206,12 +206,6 @@ bwrite(int fd, const genericptr_t loc, unsigned num) /* ===================================================== */ -void -minit(void) -{ - return; -} - void mread(int fd, genericptr_t buf, unsigned len) { From 16fc4aacb14a8237bbed5d2bbd20020494e02b3a Mon Sep 17 00:00:00 2001 From: nhmall Date: Wed, 16 Apr 2025 17:00:21 -0400 Subject: [PATCH 581/791] another stale ZEROCOMP bit --- include/extern.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/include/extern.h b/include/extern.h index ecb1ee654..d680ac6b3 100644 --- a/include/extern.h +++ b/include/extern.h @@ -2816,9 +2816,6 @@ extern void bwrite(int, const genericptr_t, unsigned) NONNULLARG2; extern void mread(int, genericptr_t, unsigned) NONNULLARG2; extern void minit(void); extern void bclose(int); -#if defined(ZEROCOMP) -extern void zerocomp_bclose(int); -#endif /* ### shk.c ### */ From c88b2883292e1dc2e574d7079f8da033a88573bd Mon Sep 17 00:00:00 2001 From: nhmall Date: Wed, 16 Apr 2025 17:04:45 -0400 Subject: [PATCH 582/791] yet another stale ZEROCOMP bit --- include/extern.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/extern.h b/include/extern.h index d680ac6b3..5a4dffa45 100644 --- a/include/extern.h +++ b/include/extern.h @@ -2814,7 +2814,6 @@ extern void bufoff(int); extern void bflush(int); extern void bwrite(int, const genericptr_t, unsigned) NONNULLARG2; extern void mread(int, genericptr_t, unsigned) NONNULLARG2; -extern void minit(void); extern void bclose(int); /* ### shk.c ### */ From 178bd3a988d28e6ca9ffd872d2ab8585e02260e3 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Thu, 17 Apr 2025 17:28:07 +0300 Subject: [PATCH 583/791] Wielding Trollsbane grants hungerless regeneration --- doc/fixes3-7-0.txt | 1 + include/artilist.h | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index eb54336a9..32b735014 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -1512,6 +1512,7 @@ avoid premapping outside Sokoban map to prevent showing stone glyphs Grimtooth is permanently poisoned, protects from poison, and can fling poison cursed magic whistle can teleport you to your pet Fire and Frost Brand can be invoked for expert level fireball or cone of cold +wielding Trollsbane grants hungerless regeneration Fixes to 3.7.0-x General Problems Exposed Via git Repository diff --git a/include/artilist.h b/include/artilist.h index 0adb26260..b5dce04f8 100644 --- a/include/artilist.h +++ b/include/artilist.h @@ -179,8 +179,8 @@ static NEARDATA struct artifact artilist[] = { PHYS(5, 0), NO_DFNS, NO_CARY, 0, A_NONE, NON_PM, NON_PM, 2, 1, 200L, NO_COLOR, OGRESMASHER), - A("Trollsbane", MORNING_STAR, (SPFX_RESTR | SPFX_DCLAS), 0, S_TROLL, - PHYS(5, 0), NO_DFNS, NO_CARY, 0, A_NONE, NON_PM, NON_PM, + A("Trollsbane", MORNING_STAR, (SPFX_RESTR | SPFX_DCLAS | SPFX_REGEN), 0, + S_TROLL, PHYS(5, 0), NO_DFNS, NO_CARY, 0, A_NONE, NON_PM, NON_PM, 2, 1, 200L, NO_COLOR, TROLLSBANE), /* From f1ba320cb3ce34327ac10a8070a29faac0ee98e1 Mon Sep 17 00:00:00 2001 From: PatR Date: Thu, 17 Apr 2025 10:06:46 -0700 Subject: [PATCH 584/791] memory tracking fix 'heaputil' is producing a lot of complaints. This fixes one of them, about freeing memory that was never allocated. In this case, it's when removing an overview annotation for a level. The annotation is using dupstr_n() and not being recorded due to dupstr_n() being placed after MONITOR_HEAP undefines the macro that overrides alloc(). There's only one use of dupstr_n(), and its length checking isn't needed there, so just switch to dupstr() and comment out the implementation of dupstr_n(). I left the prototype in extern.h; that's harmless. If dupstr_n() needs to be resurrected, a second MONITOR_HEAP-aware version should be implemented, with corresponding macro to choose which one to use. --- src/alloc.c | 4 +++- src/dungeon.c | 17 ++++++++--------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/alloc.c b/src/alloc.c index 158d03a55..05dfb502f 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -246,6 +246,8 @@ dupstr(const char *string) return strcpy((char *) alloc(len + 1), string); } +#if 0 /* suppress this; if included, it will need a MONITOR_HEAP edition */ + /* similar for reasonable size strings, but return length of input as well */ char * dupstr_n(const char *string, unsigned int *lenout) @@ -257,7 +259,7 @@ dupstr_n(const char *string, unsigned int *lenout) *lenout = (unsigned int) len; return strcpy((char *) alloc(len + 1), string); } - +#endif /* cast to int or panic on overflow; use via macro */ int diff --git a/src/dungeon.c b/src/dungeon.c index f05c926ab..aac8266a8 100644 --- a/src/dungeon.c +++ b/src/dungeon.c @@ -2554,7 +2554,9 @@ query_annotation(d_level *lev) /* add new annotation, unless it's all spaces (which will be an empty string after mungspaces() above) */ if (*nbuf && strcmp(nbuf, " ")) { - mptr->custom = dupstr_n(nbuf,&mptr->custom_lth); + mptr->custom = dupstr(nbuf); + /* _lth field does not include trailing '\0' in the count */ + mptr->custom_lth = (unsigned) strlen(mptr->custom); } } @@ -2668,27 +2670,24 @@ rm_mapseen(int ledger_num) if (svd.dungeons[mptr->lev.dnum].ledger_start + mptr->lev.dlevel == ledger_num) break; - if (!mptr) return; if (mptr->custom) - free((genericptr_t) mptr->custom); + free((genericptr_t) mptr->custom), mptr->custom = (char *) NULL; - bp = mptr->final_resting_place; - while (bp) { + bpnext = mptr->final_resting_place; + while ((bp = bpnext) != NULL) { bpnext = bp->next; - free(bp); - bp = bpnext; + free((genericptr_t) bp); } if (mprev) { mprev->next = mptr->next; - free(mptr); } else { svm.mapseenchn = mptr->next; - free(mptr); } + free(mptr); } staticfn void From f307f05afdb75ce745fec9c1eaf0d63ec73e3c09 Mon Sep 17 00:00:00 2001 From: PatR Date: Thu, 17 Apr 2025 10:10:52 -0700 Subject: [PATCH 585/791] another MONITOR_HEAP 'unsigned long' isn't big enough to hold a pointer in my configuration, and the old "only micros are sure to support %p format" is long out of date. Just assume that everyone has %p these days, and provide a hook to avoid it for anyone who doesn't. (Opt-out instead of opt-in.) --- include/tradstdc.h | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/include/tradstdc.h b/include/tradstdc.h index f2ebeb74e..adcfa0619 100644 --- a/include/tradstdc.h +++ b/include/tradstdc.h @@ -1,4 +1,4 @@ -/* NetHack 3.7 tradstdc.h $NHDT-Date: 1685522034 2023/05/31 08:33:54 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.54 $ */ +/* NetHack 3.7 tradstdc.h $NHDT-Date: 1744938651 2025/04/17 17:10:51 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.67 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2006. */ /* NetHack may be freely redistributed. See license for details. */ @@ -178,14 +178,10 @@ typedef const char *vA; typedef genericptr genericptr_t; /* (void *) or (char *) */ #endif -#if defined(MICRO) || defined(WIN32) +#ifndef NO_PTR_FMT /* We actually want to know which systems have an ANSI run-time library * to know which support the %p format for printing pointers. - * Due to the presence of things like gcc, NHSTDC is not a good test. - * So we assume microcomputers have all converted to ANSI and bigger - * computers which may have older libraries give reasonable results with - * casting pointers to unsigned long int (fmt_ptr() in alloc.c). - */ + * Since we require C99 or later, assume the library supports it. */ #define HAS_PTR_FMT #endif From b03e1ee3cb4b3c827d589d7818fe844e2ca3998c Mon Sep 17 00:00:00 2001 From: PatR Date: Thu, 17 Apr 2025 10:17:28 -0700 Subject: [PATCH 586/791] purging deleted objects I don't think that this fixed any of the 'heaputil' complaints, but it makes deleted object handling more consistent with dead monster clearup. --- src/save.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/save.c b/src/save.c index f7aab28b8..8a67865f2 100644 --- a/src/save.c +++ b/src/save.c @@ -505,6 +505,9 @@ savelev_core(NHFILE *nhfp, xint8 lev) create statue trap then immediately level teleport) */ if (iflags.purge_monsters) dmonsfree(); + /* clear objs_deleted list too */ + if (go.objs_deleted) + dobjsfree(); /* really free deleted objects */ if (lev >= 0 && lev <= maxledgerno()) svl.level_info[lev].flags |= VISITED; @@ -1197,6 +1200,7 @@ freedynamicdata(void) /* move-specific data */ dmonsfree(); /* release dead monsters */ + dobjsfree(); /* really free deleted objects */ alloc_itermonarr(0U); /* a request of 0 releases existing allocation */ /* level-specific data */ @@ -1209,8 +1213,6 @@ freedynamicdata(void) free_light_sources(RANGE_GLOBAL); freeobjchn(gi.invent); freeobjchn(gm.migrating_objs); - if (go.objs_deleted) - dobjsfree(); /* really free deleted objects */ freemonchn(gm.migrating_mons); freemonchn(gm.mydogs); /* ascension or dungeon escape */ /* freelevchn(); -- [folded into free_dungeons()] */ From a6ffebf3207422ee74bb08e6ad49fa954685bcab Mon Sep 17 00:00:00 2001 From: PatR Date: Thu, 17 Apr 2025 11:40:07 -0700 Subject: [PATCH 587/791] another MONITOR_HEAP bit 'heaputil' complains about free(NULL) because that wasn't handled consistently back in the pre-standard days. Avoid using that. --- src/mklev.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mklev.c b/src/mklev.c index add7d733d..d0b30967a 100644 --- a/src/mklev.c +++ b/src/mklev.c @@ -1184,8 +1184,8 @@ themerooms_post_level_generate(void) iflags.in_lua = gi.in_mk_themerooms = FALSE; wallification(1, 0, COLNO - 1, ROWNO - 1); - free(gc.coder); - gc.coder = NULL; + if (gc.coder) + free(gc.coder), gc.coder = NULL; lua_gc(themes, LUA_GCCOLLECT); } From 1dfbfa12e68117c279dd393b2e266a3fe9b540a5 Mon Sep 17 00:00:00 2001 From: PatR Date: Thu, 17 Apr 2025 11:57:02 -0700 Subject: [PATCH 588/791] undo earlier change to freedyanmicdata() Freeing objects early brought back an old issue with unfreed memory. --- src/save.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/save.c b/src/save.c index 8a67865f2..e861a2f4f 100644 --- a/src/save.c +++ b/src/save.c @@ -1200,7 +1200,7 @@ freedynamicdata(void) /* move-specific data */ dmonsfree(); /* release dead monsters */ - dobjsfree(); /* really free deleted objects */ + /* dobjsfree(); // handled below */ alloc_itermonarr(0U); /* a request of 0 releases existing allocation */ /* level-specific data */ @@ -1229,6 +1229,9 @@ freedynamicdata(void) cmdq_clear(CQ_REPEAT); free_tutorial(); /* (only needed if quitting while in tutorial) */ + /* per-turn data, but might get added to when freeing other stuff */ + dobjsfree(); /* really free deleted objects */ + /* some pointers in iflags */ if (iflags.wc_font_map) free((genericptr_t) iflags.wc_font_map), iflags.wc_font_map = 0; From 8b7cbbdb0f274dd9e0e756cddaf352214fa1d885 Mon Sep 17 00:00:00 2001 From: PatR Date: Thu, 17 Apr 2025 13:49:45 -0700 Subject: [PATCH 589/791] yn_function() band-aid If the yn_function() delivers its impossible about returning a result that isn't considered to be viable, put the prompt into paniclog. The updated comment contains my guess about what it going wrong, and I'm fairly sure it is correct. But I don't know how to fix it unless we change ^A to just repeat the last command without attempting to also repeat whatever followed. At the moment, users will occasionally get strange outcome from ^A. --- src/cmd.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/cmd.c b/src/cmd.c index 8273cfade..84fac12f5 100644 --- a/src/cmd.c +++ b/src/cmd.c @@ -5307,15 +5307,28 @@ yn_function( } #endif /* should not happen but cq.key has been observed to not obey 'resp'; - do this after dumplog has recorded the potentially bad value */ + it is most likely caused by saving a keystroke that was just used + to answer a context-sensitive prompt, then using the do-again + command with context that has changed */ if (resp && res && !strchr(resp, res)) { /* this probably needs refinement since caller is expecting something within 'resp' and ESC won't be (it could be present, but as a flag for unshown possibilities rather than as acceptable input) */ int altres = def ? def : '\033'; - impossible("yn_function() returned '%s'; using '%s' instead", - visctrl(res), visctrl(altres)); + if (!gi.in_doagain || wizard) { +/*TEMP*/ xint8 fuzzing = iflags.debug_fuzzer; + char dbg_buf[BUFSZ]; + + Snprintf(dbg_buf, sizeof dbg_buf, "%s [%s] (%s)", + query, resp ? resp : "", def ? visctrl(def) : ""); + paniclog("yn debug", dbg_buf); +/*TEMP*/ /* don't let this known problem kill the fuzzer */ +/*TEMP*/ iflags.debug_fuzzer = fuzzer_impossible_continue; + impossible("yn_function() returned '%s'; using '%s' instead", + visctrl(res), visctrl(altres)); +/*TEMP*/ iflags.debug_fuzzer = fuzzing; + } res = altres; } /* in case we're called via getdir() which sets input_state */ From 07b59e783e72d684b263821e7060f5eafa43873e Mon Sep 17 00:00:00 2001 From: PatR Date: Thu, 17 Apr 2025 16:59:49 -0700 Subject: [PATCH 590/791] object deletion during save operations Not sure why my earlier attempt was unsuccessful. This one isn't as comprehensive but is simpler and better yet, works as intended. When saving a level or exiting the program, objects can be deleted directly rather than having to pass though the objs_deleted list. --- include/hack.h | 1 + src/mkobj.c | 13 +++++++++---- src/save.c | 2 ++ 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/include/hack.h b/include/hack.h index a7db0e819..b21fd98dc 100644 --- a/include/hack.h +++ b/include/hack.h @@ -794,6 +794,7 @@ struct sinfo { int exiting; /* an exit handler is executing */ int saving; /* creating a save file */ int restoring; /* reloading a save file */ + int freeingdata; /* in saveobjchn(), mode FREEING */ int in_getlev; /* in getlev() */ int in_moveloop; /* normal gameplay in progress */ int in_impossible; /* reporting a warning */ diff --git a/src/mkobj.c b/src/mkobj.c index 4713e9d29..7af30c4ce 100644 --- a/src/mkobj.c +++ b/src/mkobj.c @@ -2739,10 +2739,15 @@ dealloc_obj(struct obj *obj) obj->where = OBJ_LUAFREE; return; } - /* mark object as deleted, put it into queue to be freed */ - obj->where = OBJ_DELETED; - obj->nobj = go.objs_deleted; - go.objs_deleted = obj; + if (!program_state.freeingdata) { + /* mark object as deleted, put it into queue to be freed */ + obj->where = OBJ_DELETED; + obj->nobj = go.objs_deleted; + go.objs_deleted = obj; + } else { + /* when saving, there's no need to stage deletions on objs_deleted */ + dealloc_obj_real(obj); + } } /* actually deallocate the object */ diff --git a/src/save.c b/src/save.c index e861a2f4f..69b9de6cb 100644 --- a/src/save.c +++ b/src/save.c @@ -853,7 +853,9 @@ saveobjchn(NHFILE *nhfp, struct obj **obj_p) setworn((struct obj *) 0, otmp->owornmask & (W_BALL | W_CHAIN)); otmp->owornmask = 0L; /* no longer care */ + program_state.freeingdata++; dealloc_obj(otmp); + program_state.freeingdata--; } otmp = otmp2; } From 7c40819202a237992fca6908264b2b5034db5bd7 Mon Sep 17 00:00:00 2001 From: PatR Date: Thu, 17 Apr 2025 17:00:39 -0700 Subject: [PATCH 591/791] free CRASHREPORT option data Plug a straightforward memory leak. --- src/options.c | 17 +++++++++-------- src/sys.c | 7 +++++++ 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/options.c b/src/options.c index 468f8be00..22963b343 100644 --- a/src/options.c +++ b/src/options.c @@ -1238,11 +1238,11 @@ optfn_crash_email( return optn_ok; } if (req == do_set) { - if ((op = string_for_opt(opts, FALSE)) - != empty_optstr) { - gc.crash_email = dupstr(op); - } else + if ((op = string_for_opt(opts, FALSE)) == empty_optstr) return optn_err; + if (gc.crash_email) + free((genericptr_t) gc.crash_email); + gc.crash_email = dupstr(op); return optn_ok; } if (req == get_val || req == get_cnf_val) { @@ -1264,11 +1264,11 @@ optfn_crash_name( return optn_ok; } if (req == do_set) { - if ((op = string_for_opt(opts, FALSE)) - != empty_optstr) { - gc.crash_name = dupstr(op); - } else + if ((op = string_for_opt(opts, FALSE)) == empty_optstr) return optn_err; + if (gc.crash_name) + free((genericptr_t) gc.crash_name); + gc.crash_name = dupstr(op); return optn_ok; } if (req == get_val || req == get_cnf_val) { @@ -1311,6 +1311,7 @@ optfn_crash_urlmax( } return optn_ok; } + #endif /* CRASHREPORT */ #ifdef CURSES_GRAPHICS diff --git a/src/sys.c b/src/sys.c index 41710bfbb..9cdead0ba 100644 --- a/src/sys.c +++ b/src/sys.c @@ -143,6 +143,13 @@ sysopt_release(void) if (sysopt.greppath) free((genericptr_t) sysopt.greppath), sysopt.greppath = (char *) 0; +#ifdef CRASHREPORT + if (gc.crash_email) + free((genericptr_t) gc.crash_email), gc.crash_email = (char *) NULL; + if (gc.crash_name) + free((genericptr_t) gc.crash_name), gc.crash_name = (char *) NULL; +#endif + /* this one's last because it might be used in panic feedback, although none of the preceding ones are likely to trigger a controlled panic */ if (sysopt.fmtd_wizard_list) From 050846ada9bc62a694c6ed80d40b17f74b342629 Mon Sep 17 00:00:00 2001 From: PatR Date: Thu, 17 Apr 2025 17:04:20 -0700 Subject: [PATCH 592/791] lua memory allocated vs MONITOR_HEAP I hope this is temporary. nhrealloc() intends to deal with realloc(NULL, size) but something isn't working correctly. The code in alloc.c looks right so the problem might be in heaputil. However, the code there looks ok too. --- src/nhlua.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/nhlua.c b/src/nhlua.c index ed9b3d877..bff707637 100644 --- a/src/nhlua.c +++ b/src/nhlua.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 nhlua.c $NHDT-Date: 1711034373 2024/03/21 15:19:33 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.141 $ */ +/* NetHack 3.7 nhlua.c $NHDT-Date: 1744963460 2025/04/18 00:04:20 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.153 $ */ /* Copyright (c) 2018 by Pasi Kallinen */ /* NetHack may be freely redistributed. See license for details. */ @@ -2875,7 +2875,10 @@ nhl_alloc(void *ud, void *ptr, size_t osize UNUSED, size_t nsize) return NULL; } - return re_alloc(ptr, nsize); + /* realloc(NULL, size) is legitimate but confuses MONITOR_HEAP */ + if (!ptr) + return alloc((unsigned) nsize); + return re_alloc(ptr, (unsigned) nsize); } DISABLE_WARNING_UNREACHABLE_CODE From f12108c5c5e7f8d7e9692b7247dd90b609c951c0 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Fri, 18 Apr 2025 11:40:48 +0300 Subject: [PATCH 593/791] Fix memory leak when setting autocompletions --- src/cmd.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/cmd.c b/src/cmd.c index 84fac12f5..92eef584c 100644 --- a/src/cmd.c +++ b/src/cmd.c @@ -2328,6 +2328,8 @@ handler_change_autocompletions(void) parseautocomplete(buf, FALSE); } } + if (n > 0) + free((genericptr_t) picks); } destroy_nhwindow(win); From 3d5b7f1f519326911d65c89d5d66b2372b407d36 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Fri, 18 Apr 2025 14:40:10 +0300 Subject: [PATCH 594/791] Killing quest leader angers the guardians --- src/mon.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/mon.c b/src/mon.c index b1ad1b3b2..89d2949a5 100644 --- a/src/mon.c +++ b/src/mon.c @@ -20,6 +20,7 @@ staticfn void set_mon_min_mhpmax(struct monst *, int); staticfn void lifesaved_monster(struct monst *); staticfn boolean vamprises(struct monst *); staticfn void logdeadmon(struct monst *, int); +staticfn void anger_quest_guardians(struct monst *); staticfn boolean ok_to_obliterate(struct monst *); staticfn void qst_guardians_respond(void); staticfn void peacefuls_respond(struct monst *); @@ -2999,6 +3000,14 @@ logdeadmon(struct monst *mtmp, int mndx) } } +/* anger all the quest guards on the level */ +staticfn void +anger_quest_guardians(struct monst *mtmp) +{ + if (mtmp->data == &mons[gu.urole.guardnum]) + setmangry(mtmp, TRUE); +} + /* monster 'mtmp' has died; maybe life-save, otherwise unshapeshift and update vanquished stats and update map */ void @@ -3600,6 +3609,8 @@ xkilled( change_luck(-20); pline("That was %sa bad idea...", u.uevent.qcompleted ? "probably " : ""); + if (!svc.context.mon_moving) + iter_mons(anger_quest_guardians); } else if (mdat->msound == MS_NEMESIS) { /* Real good! */ if (!svq.quest_status.killed_leader) adjalign((int) (ALIGNLIM / 4)); From 96a750d99e9efe7226cff7878f30c9ef18192e5f Mon Sep 17 00:00:00 2001 From: PatR Date: Fri, 18 Apr 2025 20:29:27 -0700 Subject: [PATCH 595/791] undo commit 050846ada9 - lua memory allocator Commit 050846ada9bc62a694c6ed80d40b17f74b342629 checked for re_alloc(NULL,n) and returned alloc(n) for that case. After testing MONITOR_HEAP and heaputil, the original code worked as intended. I'm not sure what was going wrong yesterday. Switch back to the previous code. I could have used 'git revert' but haven't. --- src/nhlua.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/nhlua.c b/src/nhlua.c index bff707637..080cf1552 100644 --- a/src/nhlua.c +++ b/src/nhlua.c @@ -2875,9 +2875,6 @@ nhl_alloc(void *ud, void *ptr, size_t osize UNUSED, size_t nsize) return NULL; } - /* realloc(NULL, size) is legitimate but confuses MONITOR_HEAP */ - if (!ptr) - return alloc((unsigned) nsize); return re_alloc(ptr, (unsigned) nsize); } From 4b7e330f3a263f38db39cf7e7546493626d65a2d Mon Sep 17 00:00:00 2001 From: PatR Date: Sat, 19 Apr 2025 11:23:29 -0700 Subject: [PATCH 596/791] secret doors in Garden filled rooms, take two A comment in rm.h claimed that secret doors can't be trapped so I used door flag D_TRAPPED to handle secret doors that should be shown as trees instead of walls. But the comment was inaccurate and secret doors can be trapped. Such trapped secret doors in ordinary rooms ended up being shown as trees too. Switch from using D_ARBOREAL in levl[][].doormask to new levl[][].arboreal_sdoor which overloads levl[][].candig. Also, wizard mode wishing for secret doors needed updating to allow creating trapped ones (at wall or door locations). This ought to update EDITLEVEL but I think existing save files can live with secret door display issues. Untrapped secret doors in garden-fill rooms will end up becoming trapped. Replaces the fix for github issue #1309 --- include/rm.h | 16 +++++++++------- src/detect.c | 7 ++++--- src/display.c | 6 +++--- src/mkmaze.c | 4 ++-- src/objnam.c | 9 ++++----- 5 files changed, 22 insertions(+), 20 deletions(-) diff --git a/include/rm.h b/include/rm.h index f0382870f..e22f48054 100644 --- a/include/rm.h +++ b/include/rm.h @@ -1,4 +1,4 @@ -/* NetHack 3.7 rm.h $NHDT-Date: 1684058570 2023/05/14 10:02:50 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.107 $ */ +/* NetHack 3.7 rm.h $NHDT-Date: 1745114235 2025/04/19 17:57:15 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.120 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Pasi Kallinen, 2017. */ /* NetHack may be freely redistributed. See license for details. */ @@ -164,10 +164,11 @@ struct rm { * | bit5 | bit4 | bit3 | bit2 | bit1 | * | 0x10 | 0x8 | 0x4 | 0x2 | 0x1 | * +-------------+-------------+------------+------------+------------+ + * wall |W_NONPASSWALL|W_NONDIGGABLE| W_MASK | W_MASK | W_MASK | * door |D_TRAPPED | D_LOCKED | D_CLOSED | D_ISOPEN | D_BROKEN | * |D_WARNED | | | | | + * sdoor |D_TRAPPED | D_LOCKED | W_MASK | W_MASK | W_MASK | * drawbr. |DB_FLOOR | DB_ICE | DB_LAVA | DB_DIR | DB_DIR | - * wall |W_NONPASSWALL|W_NONDIGGABLE| W_MASK | W_MASK | W_MASK | * sink | | | S_LRING | S_LDWASHER | S_LPUDDING | * tree | | | | TREE_SWARM | TREE_LOOTED| * throne | | | | | T_LOOTED | @@ -191,8 +192,8 @@ struct rm { * it isn't set to D_LOCKED (see cvt_sdoor_to_door() in detect.c). * * D_LOCKED conflicts with W_NONDIGGABLE but the latter is not - * expected to be used on door locations. D_TRAPPED conflicts - * with W_NONPASSWALL but secret doors aren't trapped. + * expected to be used on door locations. + * D_TRAPPED conflicts with W_NONPASSWALL. * D_SECRET would not fit within struct rm's 5-bit 'flags' field. */ @@ -205,6 +206,10 @@ struct rm { #define icedpool flags /* used for ice (in case it melts) */ #define emptygrave flags /* no corpse in grave */ +/* candig is used for floor trap locations so is available for overload + on walls, doors, secret doors, and furniture */ +#define arboreal_sdoor candig + /* * The 5 possible states of doors. * For historical reasons they are numbered as mask bits rather than 0..4. @@ -219,9 +224,6 @@ struct rm { #define D_LOCKED 0x08 #define D_TRAPPED 0x10 -/* secret doors aren't trapped or nonpasswall; overload D_TRAPPED and - W_NONPASSWALL for 'arboreal' secret doors (in garden theme room) */ -#define D_ARBOREAL D_TRAPPED #define D_SECRET 0x20 /* only used by sp_lev.c, NOT in rm-struct */ /* diff --git a/src/detect.c b/src/detect.c index 89476dc88..61e5dd3d6 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 detect.c $NHDT-Date: 1721684299 2024/07/22 21:38:19 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.180 $ */ +/* NetHack 3.7 detect.c $NHDT-Date: 1745114235 2025/04/19 17:57:15 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.190 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2018. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1584,11 +1584,11 @@ do_vicinity_map( docrt(); } -/* convert a secret door into a normal door */ +/* convert a secret door into a normal door; it might be trapped */ void cvt_sdoor_to_door(struct rm *lev) { - int newmask = lev->doormask & ~(WM_MASK | D_ARBOREAL); + int newmask = lev->doormask & ~WM_MASK; if (Is_rogue_level(&u.uz)) { /* rogue didn't have doors, only doorways */ @@ -1600,6 +1600,7 @@ cvt_sdoor_to_door(struct rm *lev) } lev->typ = DOOR; lev->doormask = newmask; + lev->arboreal_sdoor = 0; /* clears 'candig' */ } /* update the map for something which has just been found by wand of secret diff --git a/src/display.c b/src/display.c index c14165c3d..ba1841cca 100644 --- a/src/display.c +++ b/src/display.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 display.c $NHDT-Date: 1723834773 2024/08/16 18:59:33 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.244 $ */ +/* NetHack 3.7 display.c $NHDT-Date: 1745114235 2025/04/19 17:57:15 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.260 $ */ /* Copyright (c) Dean Luick, with acknowledgements to Kevin Darcy */ /* and Dave Cohrs, 1990. */ /* NetHack may be freely redistributed. See license for details. */ @@ -2291,7 +2291,7 @@ back_to_glyph(coordxy x, coordxy y) idx = (ptr->waslit || flags.lit_corridor) ? S_litcorr : S_corr; break; case SDOOR: - if ((ptr->doormask & D_ARBOREAL) != 0) { + if (ptr->arboreal_sdoor) { idx = S_tree; break; } @@ -3586,7 +3586,7 @@ wall_angle(struct rm *lev) break; case SDOOR: - if ((lev->doormask & D_ARBOREAL) != 0) { + if (lev->arboreal_sdoor) { idx = S_tree; break; } diff --git a/src/mkmaze.c b/src/mkmaze.c index 799c2b6b8..debc686cd 100644 --- a/src/mkmaze.c +++ b/src/mkmaze.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 mkmaze.c $NHDT-Date: 1737387068 2025/01/20 07:31:08 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.176 $ */ +/* NetHack 3.7 mkmaze.c $NHDT-Date: 1745114235 2025/04/19 17:57:15 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.179 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Pasi Kallinen, 2018. */ /* NetHack may be freely redistributed. See license for details. */ @@ -81,7 +81,7 @@ set_levltyp(coordxy x, coordxy y, schar newtyp) /* hack for secret doors in garden theme rooms */ if (oldtyp == SDOOR && newtyp == AIR) { /* levl[][].typ stays SDOOR rather than change to AIR */ - levl[x][y].doormask |= D_ARBOREAL; + levl[x][y].arboreal_sdoor = 1; return TRUE; } diff --git a/src/objnam.c b/src/objnam.c index 0816a4fd2..32091dfcc 100644 --- a/src/objnam.c +++ b/src/objnam.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 objnam.c $NHDT-Date: 1737528848 2025/01/21 22:54:08 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.444 $ */ +/* NetHack 3.7 objnam.c $NHDT-Date: 1745114235 2025/04/19 17:57:15 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.453 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2011. */ /* NetHack may be freely redistributed. See license for details. */ @@ -3770,10 +3770,9 @@ wizterrainwish(struct _readobjnam_data *d) lev->wall_info |= (old_wall_info & WM_MASK); /* set up trapped flag; open door states aren't eligible */ if (d->trapped == 2 /* 2: wish includes explicit "untrapped" */ - || secret /* secret doors can't be trapped due to their use - * of both doormask and wall_info; those both - * overlay rm->flags and partially conflict */ - || (lev->doormask & (D_LOCKED | D_CLOSED)) == 0) + || ((lev->doormask & (D_LOCKED | D_CLOSED)) == 0 + /* D_CLOSED is implicit for secret doors */ + && !secret)) d->trapped = 0; if (d->trapped) lev->doormask |= D_TRAPPED; From d32c8c63bdfd26913ab0d4ac076d926bde42e7ce Mon Sep 17 00:00:00 2001 From: PatR Date: Sat, 19 Apr 2025 17:53:22 -0700 Subject: [PATCH 597/791] Mention reading scrolls while blind in Guidebook --- doc/Guidebook.mn | 16 ++++++++++++---- doc/Guidebook.tex | 18 ++++++++++++++---- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/doc/Guidebook.mn b/doc/Guidebook.mn index 574bed82b..c55a6f058 100644 --- a/doc/Guidebook.mn +++ b/doc/Guidebook.mn @@ -1,4 +1,4 @@ -.\" $NHDT-Branch: master $:$NHDT-Revision: 1.596 $ $NHDT-Date: 1735103892 2024/12/25 00:18:12 $ +.\" $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.598 $ $NHDT-Date: 1745139202 2025/04/20 00:53:22 $ .\" .\" This is an excerpt from the 'roff' man page from the 'groff' package. .\"+-- @@ -47,7 +47,7 @@ .ds f0 \*(vr .ds f1 \" empty .\"DO NOT REMOVE NH_DATESUB .ds f2 Date(%B %-d, %Y) -.ds f2 December 25, 2024 +.ds f2 April 20, 2025 . .\" A note on some special characters: .\" \(lq = left double quote @@ -2920,8 +2920,16 @@ magic spells on them). .pg One of the most useful of these is the \fIscroll of identify\fP, which can be used to determine what another object is, whether it is cursed or -blessed, and how many uses it has left. Some objects of subtle -enchantment are difficult to identify without these. +blessed, and how many uses it has left. +Some objects of subtle enchantment are difficult to identify without these. +.pg +A scroll whose label is known can be read even when the hero is blind. +If a scroll has been discovered, it will be listed in inventory by type +rather than by label, but the label is known in that situtaion even though +it isn't shown. +.pg +Many scrolls produce a different effect from usual if they are blessed or +cursed, or read while the hero is confused. .pg A mail daemon may run up and deliver mail to you as a \fIscroll of mail\fP (on versions compiled with this feature). diff --git a/doc/Guidebook.tex b/doc/Guidebook.tex index b6769704c..9cced113b 100644 --- a/doc/Guidebook.tex +++ b/doc/Guidebook.tex @@ -1,5 +1,5 @@ \documentstyle[titlepage,longtable]{article} -% NetHack 3.7 Guidebook.tex $NHDT-Date: 1711040379 2024/03/21 16:59:39 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.562 $ */ +% NetHack 3.7 Guidebook.tex $NHDT-Date: 1745139202 2025/04/20 00:53:22 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.579 $ */ %+% we're still limping along in LaTeX 2.09 compatibility mode %-%\documentclass{article} %-%\usepackage{hyperref} % before longtable @@ -48,7 +48,7 @@ \author{Original version - Eric S. Raymond\\ (Edited and expanded for 3.7.0 by Mike Stephenson and others)} %DO NOT REMOVE NH_DATESUB \date{Date(%B %-d, %Y)} -\date{November 16, 2024} +\date{April 20, 2025} \maketitle @@ -3158,8 +3158,18 @@ magic spells on them). One of the most useful of these is the % {\it scroll of identify}, which can be used to determine what another object is, whether it is cursed or -blessed, and how many uses it has left. Some objects of subtle -enchantment are difficult to identify without these. +blessed, and how many uses it has left. +Some objects of subtle enchantment are difficult to identify without these. + +%.pg +A scroll whose label is known can be read even when the hero is blind. +If a scroll has been discovered, it will be listed in inventory by type +rather than by label, but the label is known in that situtaion even though +it isn't shown. + +%.pg +Many scrolls produce a different effect from usual if they are blessed or +cursed, or read while the hero is confused. %.pg A mail daemon may run up and deliver mail to you as a % From 8f38267775ae27a923a071d309c95eff171c15ad Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 20 Apr 2025 13:11:09 -0400 Subject: [PATCH 598/791] use documented SIG_RET_TYPE for Linux with gcc --- include/hack.h | 13 ++++++------- include/windconf.h | 4 ++++ sys/unix/hints/linux.370 | 11 +++++++++++ sys/unix/hints/macOS.370 | 13 +++++++++++++ 4 files changed, 34 insertions(+), 7 deletions(-) diff --git a/include/hack.h b/include/hack.h index b21fd98dc..c97aff6af 100644 --- a/include/hack.h +++ b/include/hack.h @@ -1512,17 +1512,16 @@ typedef uint32_t mmflags_nht; /* makemon MM_ flags */ #define getlogin() ((char *) 0) #endif /* MICRO */ -/* The function argument to qsort() requires a particular - * calling convention under WINCE which is not the default - * in that environment. - */ -#if defined(WIN_CE) -#define QSORTCALLBACK __cdecl -#else +/* These may have been defined to platform-specific values in *conf.h + * or on the compiler command line from a hints file or Makefile */ + +#ifndef QSORTCALLBACK #define QSORTCALLBACK #endif +#ifndef SIG_RET_TYPE #define SIG_RET_TYPE void (*)(int) +#endif #define DEVTEAM_EMAIL "devteam@nethack.org" #define DEVTEAM_URL "https://www.nethack.org/" diff --git a/include/windconf.h b/include/windconf.h index c3b6d4e05..bd30f8a6b 100644 --- a/include/windconf.h +++ b/include/windconf.h @@ -274,6 +274,10 @@ extern boolean file_newer(const char *, const char *); /* #include "system.h" */ #endif +#if defined(WIN_CE) +#define QSORTCALLBACK __cdecl +#endif + /* Override the default version of nhassert. The default version is unable * to generate a string form of the expression due to the need to be * compatible with compilers which do not support macro stringization (i.e. diff --git a/sys/unix/hints/linux.370 b/sys/unix/hints/linux.370 index e3dec785b..1644cc826 100755 --- a/sys/unix/hints/linux.370 +++ b/sys/unix/hints/linux.370 @@ -165,17 +165,28 @@ endif #WANT_WIN_CURSES #-INCLUDE multisnd1-pre.370 # +ifeq "$(CCISCLANG)" "1" +# clang-specific starts +# clang-specific ends +else +# gcc-specific starts +LIBCFLAGS+=-DSIG_RET_TYPE=__sighandler_t +# gcc-specific ends +endif + # WINCFLAGS set from multiw-2.370 # SNDCFLAGS set from multisnd-pre.370 CFLAGS+= $(WINCFLAGS) CFLAGS+= $(SNDCFLAGS) CFLAGS+= $(NHCFLAGS) +CFLAGS+= $(LIBCFLAGS) # WINCFLAGS set from multiw-2.370 # SNDCFLAGS set from multisnd-pre.370 CCXXFLAGS+= $(WINCFLAGS) CCXXFLAGS+= $(SNDCFLAGS) CCXXFLAGS+= $(NHCFLAGS) +CCXXFLAGS+= $(LIBCFLAGS) VARDATND = VARDATND0 = diff --git a/sys/unix/hints/macOS.370 b/sys/unix/hints/macOS.370 index 05042cafd..48b9e90df 100755 --- a/sys/unix/hints/macOS.370 +++ b/sys/unix/hints/macOS.370 @@ -219,17 +219,30 @@ endif #-INCLUDE multisnd1-pre.370 # +# although not currently doing anything for macOS, this is +# kept in for consistency with layout of linux.370 +ifeq "$(CCISCLANG)" "1" +# clang-specific starts +# clang-specific ends +else +# gcc-specific starts +# LIBCFLAGS+= +# gcc-specific ends +endif + # WINCFLAGS set from multiw-2.370 # SNDCFLAGS set from multisnd-pre.370 CFLAGS+= $(PKGCFLAGS) $(WINCFLAGS) CFLAGS+= $(SNDCFLAGS) CFLAGS+= $(NHCFLAGS) +CFLAGS+= $(LIBCFLAGS) # WINCFLAGS set from multiw-2.370 # SNDCFLAGS set from multisnd-pre.370 CCXXFLAGS+= $(WINCFLAGS) CCXXFLAGS+= $(SNDCFLAGS) CCXXFLAGS+= $(NHCFLAGS) +CCXXFLAGS+= $(LIBCFLAGS) VARDATND = VARDATND0 = From 079566cad9e7a089316e61d41a3f214bd2779e4c Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sun, 20 Apr 2025 20:19:01 +0300 Subject: [PATCH 599/791] Fix memory leak in lua selection iterate Iterating over a large set of locations in a selection caused a memory leak. Lua couldn't do garbage collection in the middle of the iterator function, so it eventually ran out of space, and just quietly dropped stuff. --- src/nhlsel.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/nhlsel.c b/src/nhlsel.c index f700a9ea3..306820cf9 100644 --- a/src/nhlsel.c +++ b/src/nhlsel.c @@ -925,7 +925,7 @@ l_selection_iterate(lua_State *L) if (argc == 2 && lua_type(L, 2) == LUA_TFUNCTION) { sel = l_selection_check(L, 1); selection_getbounds(sel, &rect); - for (y = rect.ly; y <= rect.hy; y++) + for (y = rect.ly; y <= rect.hy; y++) { for (x = max(1,rect.lx); x <= rect.hx; x++) if (selection_getpoint(x, y, sel)) { coordxy tmpx = x, tmpy = y; @@ -939,6 +939,8 @@ l_selection_iterate(lua_State *L) goto out; } } + lua_gc(L, LUA_GCCOLLECT, 0); + } } else { nhl_error(L, "wrong parameters"); /*NOTREACHED*/ From e21a5c6ac37095c1d4062c8488ee976b55e2d086 Mon Sep 17 00:00:00 2001 From: PatR Date: Sun, 20 Apr 2025 14:19:40 -0700 Subject: [PATCH 600/791] curses band-aid heaputil reported an attempt to free a null pointer at line 1314 of cursdial.c (in menu_display_page()). curses_break_str() can return Null but its callers aren't prepared for that. Make it return an empty string that can be passed to free() instead. --- win/curses/cursmisc.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/win/curses/cursmisc.c b/win/curses/cursmisc.c index 42dd6250b..ce02ca435 100644 --- a/win/curses/cursmisc.c +++ b/win/curses/cursmisc.c @@ -343,7 +343,12 @@ curses_break_str(const char *str, int width, int line_num) } if (curline < line_num) { +#if 0 return NULL; +#else + /* callers aren't prepared to handle NULL return */ + Strcpy(curstr, ""); +#endif } retstr = curses_copy_of(curstr); From f9af1aa0cf545d89cbe06fe692cd50d7835d0c36 Mon Sep 17 00:00:00 2001 From: PatR Date: Sun, 20 Apr 2025 14:31:33 -0700 Subject: [PATCH 601/791] splitobj() panic feedback In case the splitobj() panic gets triggered again, provide some more info about why that has happened. --- src/mkobj.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/mkobj.c b/src/mkobj.c index 7af30c4ce..b6aef88b0 100644 --- a/src/mkobj.c +++ b/src/mkobj.c @@ -458,8 +458,11 @@ splitobj(struct obj *obj, long num) { struct obj *otmp; + /* can't split containers */ if (obj->cobj || num <= 0L || obj->quan <= num) - panic("splitobj"); /* can't split containers */ + panic("splitobj [cobj=%s num=%ld quan=%ld]", + obj->cobj ? "non-empty container" : "(null)", num, obj->quan); + otmp = newobj(); *otmp = *obj; /* copies whole structure */ otmp->oextra = (struct oextra *) 0; From 617b7588ccd9ff6e1a32b4fb356637def1f6c517 Mon Sep 17 00:00:00 2001 From: PatR Date: Sun, 20 Apr 2025 15:07:11 -0700 Subject: [PATCH 602/791] more obj panic feedback --- src/mkobj.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/mkobj.c b/src/mkobj.c index b6aef88b0..c6d65e9c0 100644 --- a/src/mkobj.c +++ b/src/mkobj.c @@ -2454,7 +2454,7 @@ remove_object(struct obj *otmp) coordxy y = otmp->oy; if (otmp->where != OBJ_FLOOR) - panic("remove_object: obj not on floor"); + panic("remove_object: obj where=%d, not on floor", otmp->where); extract_nexthere(otmp, &svl.level.objects[x][y]); extract_nobj(otmp, &fobj); if (otmp->otyp == BOULDER) @@ -2529,7 +2529,7 @@ obj_extract_self(struct obj *obj) extract_nobj(obj, &gb.billobjs); break; default: - panic("obj_extract_self"); + panic("obj_extract_self, where=%d", obj->where); break; } } @@ -2593,7 +2593,7 @@ add_to_minv(struct monst *mon, struct obj *obj) struct obj *otmp; if (obj->where != OBJ_FREE) - panic("add_to_minv: obj not free"); + panic("add_to_minv: obj where=%d, not free", obj->where); /* merge if possible */ for (otmp = mon->minvent; otmp; otmp = otmp->nobj) @@ -2621,7 +2621,7 @@ add_to_container(struct obj *container, struct obj *obj) struct obj *otmp; if (obj->where != OBJ_FREE) - panic("add_to_container: obj not free"); + panic("add_to_container: obj where=%d, not free", obj->where); if (container->where != OBJ_INVENT && container->where != OBJ_MINVENT) obj_no_longer_held(obj); @@ -2641,7 +2641,7 @@ void add_to_migration(struct obj *obj) { if (obj->where != OBJ_FREE) - panic("add_to_migration: obj not free"); + panic("add_to_migration: obj where=%d, not free", obj->where); if (obj->unpaid) /* caller should have changed unpaid item to stolen */ impossible("unpaid object migrating to another level? [%s]", @@ -2663,7 +2663,7 @@ void add_to_buried(struct obj *obj) { if (obj->where != OBJ_FREE) - panic("add_to_buried: obj not free"); + panic("add_to_buried: obj where=%d, not free", obj->where); obj->where = OBJ_BURIED; obj->nobj = svl.level.buriedobjlist; @@ -2776,12 +2776,12 @@ dobjsfree(void) struct obj *otmp; while (go.objs_deleted) { - otmp = go.objs_deleted->nobj; - if (go.objs_deleted->where != OBJ_DELETED) - panic("dobjsfree: obj where is not OBJ_DELETED"); - obj_extract_self(go.objs_deleted); - dealloc_obj_real(go.objs_deleted); - go.objs_deleted = otmp; + otmp = go.objs_deleted; + go.objs_deleted = otmp->nobj; + if (otmp->where != OBJ_DELETED) + panic("dobjsfree: obj where=%d, not OBJ_DELETED", otmp->where); + obj_extract_self(otmp); + dealloc_obj_real(otmp); } } From 9f04269ec4e937c298c8b1990d2cca8025860094 Mon Sep 17 00:00:00 2001 From: PatR Date: Sun, 20 Apr 2025 17:18:49 -0700 Subject: [PATCH 603/791] couple of formatting bits --- src/dothrow.c | 6 ++++-- src/mklev.c | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/dothrow.c b/src/dothrow.c index fbc507c3c..df019f6e4 100644 --- a/src/dothrow.c +++ b/src/dothrow.c @@ -1458,7 +1458,8 @@ throwit_return(boolean clear_thrownobj) } staticfn void -swallowit(struct obj *obj){ +swallowit(struct obj *obj) +{ if (obj != uball) { (void) mpickobj(u.ustuck, obj); /* clears 'gt.thrownobj' */ throwit_return(FALSE); @@ -1468,7 +1469,8 @@ swallowit(struct obj *obj){ /* throw an object, NB: obj may be consumed in the process */ void -throwit(struct obj *obj, +throwit( + struct obj *obj, long wep_mask, /* used to re-equip returning boomerang */ boolean twoweap, /* used to restore twoweapon mode if * wielded weapon returns */ diff --git a/src/mklev.c b/src/mklev.c index d0b30967a..bab79e46d 100644 --- a/src/mklev.c +++ b/src/mklev.c @@ -773,9 +773,9 @@ makeniche(int trap_type) dosdoor(xx, yy, aroom, SDOOR); } else { rm->typ = CORR; - if (rn2(7)) + if (rn2(7)) { dosdoor(xx, yy, aroom, rn2(5) ? SDOOR : DOOR); - else { + } else { /* inaccessible niches occasionally have iron bars */ if (!rn2(5) && IS_WALL(levl[xx][yy].typ)) { (void) set_levltyp(xx, yy, IRONBARS); From ec5fe78b64f03a3c9828f967f044002be4f4ef83 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 20 Apr 2025 21:07:38 -0400 Subject: [PATCH 604/791] apparently gcc-9 wonn't work on latest Linux in CI --- azure-pipelines.yml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index cdec5d7d5..a54d8662f 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -1,8 +1,8 @@ strategy: matrix: - linux_latest_gcc9_minimal: + linux_latest_gcc14_minimal: imageName: 'ubuntu-latest' - toolchainName: gcc9 + toolchainName: gcc14 buildTargetName: minimal linux_noble_clang_all: imageName: 'ubuntu-24.04' @@ -70,6 +70,11 @@ steps: echo "##vso[task.setvariable variable=CC]gcc-13" echo "##vso[task.setvariable variable=CXX]g++-13" fi + if [ "$(toolchain)" == "gcc14" ] + then + echo "##vso[task.setvariable variable=CC]gcc-14" + echo "##vso[task.setvariable variable=CXX]g++-14" + fi if [ "$(toolchain)" == "clang" ] then echo "##vso[task.setvariable variable=CC]clang" From 1c679779f454d9d90961bd0c448ebfdcdfb52fd5 Mon Sep 17 00:00:00 2001 From: PatR Date: Sun, 20 Apr 2025 19:36:56 -0700 Subject: [PATCH 605/791] final disclosure of inventory vs force_invmenu It seems surpristing that no one has noticed this since the code that is responsible has been present for six months. Inventory list at end of game included bogus "? - (list likely candidates)". --- doc/fixes3-7-0.txt | 2 ++ src/end.c | 1 + 2 files changed, 3 insertions(+) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index 32b735014..0787fcea3 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -2110,6 +2110,8 @@ when attacking a displacer beast, using the 'F' forcefight prefix prevented it successfully disarming a chest trap was clearing the chest's 'tknown' bit instead of setting it; likewise when failing to disarm triggered and used up the trap +when game ended with 'force_invmenu' On, final disclosure of inventory would + contain spurious menu entry "? - (list likely candidates)" Fixes to 3.7.0-x Platform and/or Interface Problems Exposed Via git Repository diff --git a/src/end.c b/src/end.c index 35dfc1803..57b189d12 100644 --- a/src/end.c +++ b/src/end.c @@ -630,6 +630,7 @@ disclose(int how, boolean taken) if (c == 'y') { /* caller has already ID'd everything; we pass 'want_reply=True' to force display_pickinv() to avoid using WIN_INVENT */ + iflags.force_invmenu = FALSE; (void) display_inventory((char *) 0, TRUE); container_contents(gi.invent, TRUE, TRUE, FALSE); } From 3c70918c529ec14a71ee17f17b66efa1fa3682bf Mon Sep 17 00:00:00 2001 From: PatR Date: Mon, 21 Apr 2025 07:16:04 -0700 Subject: [PATCH 606/791] disclosure of geno'd and/or extinct species If there is at least one genocided or extinct type of monster, final disclosure asks if you want to see the list. It was using "ynaq" for the choice of answer, where 'a' is used to prompt for sort order rather than "all". Change it to only include the 'a' choice if there are more than 1 of either category or 1 each of both categories (since they're listed interspersed with each other, sorting is relevant for the one-of-each situation). --- src/insight.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/insight.c b/src/insight.c index a1c44b6c9..9f0f71059 100644 --- a/src/insight.c +++ b/src/insight.c @@ -3046,12 +3046,14 @@ list_genocided(char defquery, boolean ask) ngone = num_gone(mvflags, mindx); /* genocided or extinct species list */ - if (ngenocided != 0 || nextinct != 0) { + if (ngone > 0) { Sprintf(buf, "Do you want a list of %sspecies%s%s?", (nextinct && !ngenocided) ? "extinct " : "", (ngenocided) ? " genocided" : "", (nextinct && ngenocided) ? " and extinct" : ""); - c = ask ? yn_function(buf, ynaqchars, defquery, TRUE) : defquery; + c = ask ? yn_function(buf, (ngone > 1) ? "ynaq" : "ynq\033a", + defquery, TRUE) + : defquery; if (c == 'q') done_stopprint++; if (c == 'y' || c == 'a') { From f65335614481465f0b544be67e8e65da8b7e570f Mon Sep 17 00:00:00 2001 From: PatR Date: Thu, 24 Apr 2025 11:11:55 -0700 Subject: [PATCH 607/791] monst.h comments End of line comments split across lines should start with '*' on the continuation lines. Otherwise clang-format, if we ever run it again, will mangle them by shifting the start of the comment from the end of its line to be a new block comment on the next line. [There are lots of these which ought to be fixed; I just happended to be looking at monst.h.] --- include/monst.h | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/include/monst.h b/include/monst.h index 0c52e239b..15114c600 100644 --- a/include/monst.h +++ b/include/monst.h @@ -99,12 +99,12 @@ struct monst { short mnum; /* permanent monster index number */ short cham; /* if shapeshifter, orig mons[] idx goes here */ short movement; /* movement points (derived from permonst definition - and added effects */ + * and added effects */ uchar m_lev; /* adjusted difficulty level of monster */ aligntyp malign; /* alignment of this monster, relative to the - player (positive = good to kill) */ + * player (positive = good to kill) */ coordxy mx, my; - coordxy mux, muy; /* where the monster thinks you are */ + coordxy mux, muy; /* where the monster thinks you are */ #define MTSZ 4 /* mtrack[0..2] is used to keep extra data when migrating the monster */ coord mtrack[MTSZ]; /* monster track */ @@ -112,11 +112,11 @@ struct monst { unsigned mappearance; /* for undetected mimics and the wiz */ uchar m_ap_type; /* what mappearance is describing, m_ap_types */ - schar mtame; /* level of tameness, implies peaceful */ + schar mtame; /* level of tameness, implies peaceful */ unsigned short mintrinsics; /* low 8 correspond to mresists */ unsigned short mextrinsics; /* low 8 correspond to mresists */ unsigned long seen_resistance; /* M_SEEN_x; saw you resist an effect */ - int mspec_used; /* monster's special ability attack timeout */ + int mspec_used; /* monster's special ability attack timeout */ Bitfield(female, 1); /* is female */ Bitfield(minvis, 1); /* currently invisible */ @@ -156,14 +156,13 @@ struct monst { Bitfield(ispriest, 1); /* is an aligned priest or high priest */ Bitfield(iswiz, 1); /* is the Wizard of Yendor */ +#define MAX_NUM_WORMS 32 /* should be 2^(wormno bitfield size) */ Bitfield(wormno, 5); /* at most 31 worms on any level */ Bitfield(mtemplit, 1); /* temporarily seen; only valid during bhit() */ Bitfield(meverseen, 1); /* mon has been seen at some point */ Bitfield(mspotted, 1); /* mon is currently seen by hero */ -#define MAX_NUM_WORMS 32 /* should be 2^(wormno bitfield size) */ - unsigned long mstrategy; /* for monsters with mflag3: current strategy */ #ifdef NHSTDC #define STRAT_APPEARMSG 0x80000000UL From 81e72dd0ccd2786ac058c03b37500b09b6ce03c6 Mon Sep 17 00:00:00 2001 From: PatR Date: Thu, 24 Apr 2025 11:19:20 -0700 Subject: [PATCH 608/791] notice_all_mons() Process monsters more consistently. --- src/hack.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/hack.c b/src/hack.c index d7e6f6b1f..7c30870c7 100644 --- a/src/hack.c +++ b/src/hack.c @@ -1728,22 +1728,25 @@ notice_all_mons(boolean reset) struct monst **arr = NULL; int j, i = 0, cnt = 0; - for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) + for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { + if (DEADMONSTER(mtmp)) + continue; if (canspotmon(mtmp)) cnt++; else if (reset) mtmp->mspotted = FALSE; - + } if (!cnt) return; - arr = (struct monst **) alloc(cnt * sizeof(struct monst *)); - + arr = (struct monst **) alloc(cnt * sizeof (struct monst *)); for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { + if (DEADMONSTER(mtmp)) + continue; if (!canspotmon(mtmp)) mtmp->mspotted = FALSE; - else if (!DEADMONSTER(mtmp) && i < cnt) + else if (i < cnt) arr[i++] = mtmp; } From c6906a78a47e2f4bec49efb13e7c049a5e704f71 Mon Sep 17 00:00:00 2001 From: PatR Date: Thu, 24 Apr 2025 11:34:35 -0700 Subject: [PATCH 609/791] fuzzer vs do-again Try to exercise ^A more when running the fuzzer. Also ^P, although that is tty-centric. I couldn't notice any difference in behavior so this doesn't seem to be very useful. --- src/cmd.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/cmd.c b/src/cmd.c index 92eef584c..8b912dc40 100644 --- a/src/cmd.c +++ b/src/cmd.c @@ -3284,12 +3284,20 @@ accept_menu_prefix(const struct ext_func_tab *ec) return (ec && ((ec->flags & CMD_M_PREFIX) != 0)); } +/* choose a random character, biased towards movement commands, primarily + for debug-fuzzer testing */ char randomkey(void) { static unsigned i = 0; + static char last_c = '\0'; char c; + /* give ^A and ^P a high probability of being repeated */ + if ((last_c == C('a') || last_c == C('p')) + && program_state.input_state == commandInp && rn2(5)) + return last_c; + switch (rn2(16)) { default: c = '\033'; @@ -3337,6 +3345,8 @@ randomkey(void) break; } + if (program_state.input_state == commandInp) + last_c = c; return c; } From 92255708f327b4c3e94d6cb21ad50370d8a84fe4 Mon Sep 17 00:00:00 2001 From: PatR Date: Thu, 24 Apr 2025 12:47:00 -0700 Subject: [PATCH 610/791] stone-to-flesh vs mimics Handle a FIXME in zap.c: stone-to-flesh spell hitting a mimic that is disguised as a stone object or stone furniture should bring it out of hiding. --- include/extern.h | 4 +++- include/hack.h | 4 ++++ src/mkobj.c | 36 ++++++++++++++++++++++++++++ src/uhitm.c | 15 ++++++++---- src/zap.c | 61 ++++++++++++++++++++++++++++-------------------- 5 files changed, 89 insertions(+), 31 deletions(-) diff --git a/include/extern.h b/include/extern.h index 5a4dffa45..5886eb0c0 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1624,6 +1624,8 @@ extern void costly_alteration(struct obj *, int) NONNULLARG1; extern void clear_dknown(struct obj *); extern void unknow_object(struct obj *); extern struct obj *mksobj(int, boolean, boolean) NONNULL; +extern boolean stone_object_type(unsigned); +extern boolean stone_furniture_type(unsigned); extern int bcsign(struct obj *) NONNULLARG1; extern int weight(struct obj *) NONNULLARG1; extern struct obj *mkgold(long, coordxy, coordxy); @@ -3385,7 +3387,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 that_is_a_mimic(struct monst *, unsigned) 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/include/hack.h b/include/hack.h index c97aff6af..bf50ff3d9 100644 --- a/include/hack.h +++ b/include/hack.h @@ -1155,6 +1155,10 @@ typedef uint32_t mmflags_nht; /* makemon MM_ flags */ #define MHID_ALTMON 4 /* if mimicking a monster, include that */ #define MHID_REGION 8 /* include region when mon is in one */ +/* flags for that_is_a_mimic() */ +#define MIM_REVEAL 1 /* seemimic() */ +#define MIM_OMIT_WAIT 2 /* strip beginning from "Wait! That is a " */ + /* flags for make_corpse() and mkcorpstat(); 0..7 are recorded in obj->spe */ #define CORPSTAT_NONE 0x00 #define CORPSTAT_GENDER 0x03 /* 0x01 | 0x02 */ diff --git a/src/mkobj.c b/src/mkobj.c index c6d65e9c0..bece8cd44 100644 --- a/src/mkobj.c +++ b/src/mkobj.c @@ -1251,6 +1251,42 @@ mksobj(int otyp, boolean init, boolean artif) return otmp; } +/* potential mimic shapes that should be undone by stone-to-flesh; + not used for objects that will be transformed when hit by stone-to-flesh */ +boolean +stone_object_type(unsigned mappearance) +{ + int otyp = (int) mappearance; + + /* we exclude wands, rings, and gems even though some qualify as stone; + there aren't any weapons or armor classified as made out of stone */ + return (otyp == BOULDER || otyp == STATUE || otyp == FIGURINE); +} + +/* possible mimic shapes that are affected by stone-to-flesh; + mappearance for furniture is a display symbol rather than a terrain type */ +boolean +stone_furniture_type(unsigned mappearance) +{ + int sym = (int) mappearance; + + switch (sym) { + case S_upstair: + case S_dnstair: + case S_brupstair: + case S_brdnstair: + case S_altar: + case S_throne: + case S_sink: /* stone sink is iffy; metal might be more appropriate */ + return TRUE; + default: + if (sym >= S_vwall && sym <= S_trwall) + return TRUE; + break; + } + return FALSE; +} + /* * Several areas of the code made direct reassignments * to obj->corpsenm. Because some special handling is diff --git a/src/uhitm.c b/src/uhitm.c index fecd46228..ced52abc5 100644 --- a/src/uhitm.c +++ b/src/uhitm.c @@ -6103,11 +6103,13 @@ DISABLE_WARNING_FORMAT_NONLITERAL void that_is_a_mimic( struct monst *mtmp, /* a hidden mimic (nonnull) */ - boolean reveal_it) /* True: remove its disguise */ + unsigned mimic_flags) /* 0, MIM_REVEAL, MIM_OMIT_WAIT, REVEAL+OMIT */ { static char generic[] = "a monster"; char fmtbuf[BUFSZ]; const char *what = NULL; + boolean reveal_it = (mimic_flags & MIM_REVEAL) != 0, + omit_wait = (mimic_flags & MIM_OMIT_WAIT) != 0; Strcpy(fmtbuf, "Wait! That's %s!"); if (Blind) { @@ -6116,7 +6118,7 @@ that_is_a_mimic( else if (M_AP_TYPE(mtmp) == M_AP_MONSTER) what = a_monnam(mtmp); /* differs from what was sensed */ } else { - coordxy x = u.ux + u.dx, y = u.uy + u.dy; + coordxy x = mtmp->mx, y = mtmp->my; int glyph = glyph_at(x, y); if (glyph_is_cmap(glyph)) { @@ -6167,8 +6169,11 @@ that_is_a_mimic( what = a_monnam(mtmp); } - if (what) - pline(fmtbuf, what); + if (what) { + int i = (omit_wait && !strncmp(fmtbuf, "Wait! ", 7)) ? 7 : 0; + + pline(&fmtbuf[i], what); + } if (reveal_it) seemimic(mtmp); } @@ -6179,7 +6184,7 @@ RESTORE_WARNING_FORMAT_NONLITERAL void stumble_onto_mimic(struct monst *mtmp) { - that_is_a_mimic(mtmp, TRUE); + that_is_a_mimic(mtmp, MIM_REVEAL); if (!u.ustuck && !mtmp->mflee && dmgtype(mtmp->data, AD_STCK) /* must be adjacent; attack via polearm could be from farther away */ diff --git a/src/zap.c b/src/zap.c index 7118ca4da..e1d199035 100644 --- a/src/zap.c +++ b/src/zap.c @@ -365,7 +365,7 @@ bhitm(struct monst *mtmp, struct obj *otmp) case WAN_LOCKING: case SPE_WIZARD_LOCK: if (disguised_mimic && box_or_door(mtmp)) - that_is_a_mimic(mtmp, TRUE); /*seemimic()*/ + that_is_a_mimic(mtmp, MIM_REVEAL); /*seemimic()*/ wake = closeholdingtrap(mtmp, &learn_it); break; case WAN_PROBING: @@ -377,7 +377,7 @@ bhitm(struct monst *mtmp, struct obj *otmp) case WAN_OPENING: case SPE_KNOCK: if (disguised_mimic && box_or_door(mtmp)) - that_is_a_mimic(mtmp, TRUE); /*seemimic()*/ + that_is_a_mimic(mtmp, MIM_REVEAL); /*seemimic()*/ wake = FALSE; /* don't want immediate counterattack */ if (mtmp == u.ustuck) { /* zapping either holder/holdee or self [zapyourself()] will @@ -483,21 +483,35 @@ bhitm(struct monst *mtmp, struct obj *otmp) learn_it = TRUE; break; case SPE_STONE_TO_FLESH: - /* FIXME: mimics disguished as stone furniture or stone object - should be taken out of concealment. */ - if (monsndx(mtmp->data) == PM_STONE_GOLEM) { - char *name = Monnam(mtmp); + if (mtmp->data->mlet == S_GOLEM) { + const char *mesg; + char *name = Monnam(mtmp); /* before possible polymorph */ - /* turn into flesh golem */ - if (newcham(mtmp, &mons[PM_FLESH_GOLEM], NO_NC_FLAGS)) { - if (canseemon(mtmp)) - pline("%s turns to flesh!", name); - } else { - if (canseemon(mtmp)) - pline("%s looks rather fleshy for a moment.", name); + /* turn stone golem into flesh golem */ + if (monsndx(mtmp->data) == PM_STONE_GOLEM + && newcham(mtmp, &mons[PM_FLESH_GOLEM], NO_NC_FLAGS)) + mesg = "turns to flesh!"; + else if (monsndx(mtmp->data) == PM_FLESH_GOLEM) + mesg = "seems fleshier..."; + else + mesg = "looks rather fleshy for a moment."; + + if (canseemon(mtmp)) + pline("%s %s", name, mesg); + } else if (mtmp->data->mlet == S_MIMIC + && ((M_AP_TYPE(mtmp) == M_AP_FURNITURE + && stone_furniture_type(mtmp->mappearance)) + || (M_AP_TYPE(mtmp) == M_AP_OBJECT + && stone_object_type(mtmp->mappearance)))) { + /* note: if that_is_a_mimic() doesn't get called to reveal the + mimic, wakeup() below will call seemimic() */ + if (cansee(mtmp->mx, mtmp->my)) { + set_msg_xy(mtmp->mx, mtmp->my); + that_is_a_mimic(mtmp, MIM_REVEAL | MIM_OMIT_WAIT); } - } else + } else { wake = FALSE; + } break; case SPE_DRAIN_LIFE: if (disguised_mimic) @@ -530,22 +544,19 @@ bhitm(struct monst *mtmp, struct obj *otmp) impossible("What an interesting effect (%d)", otyp); break; } - if (wake) { - if (!DEADMONSTER(mtmp)) { - wakeup(mtmp, helpful_gesture ? FALSE : TRUE); - m_respond(mtmp); - if (mtmp->isshk && !*u.ushops) - hot_pursuit(mtmp); - } else if (M_AP_TYPE(mtmp)) - seemimic(mtmp); /* might unblock if mimicking a boulder/door */ + if (wake && !DEADMONSTER(mtmp)) { + /* seemimic() is done by wakeup() and might unblock vision */ + wakeup(mtmp, helpful_gesture ? FALSE : TRUE); + m_respond(mtmp); + if (mtmp->isshk && !*u.ushops) + hot_pursuit(mtmp); } /* note: gb.bhitpos won't be set if swallowed, but that's okay since * reveal_invis will be false. We can't use mtmp->mx, my since it * might be an invisible worm hit on the tail. */ - if (reveal_invis) { - if (!DEADMONSTER(mtmp) && cansee(gb.bhitpos.x, gb.bhitpos.y) - && !canspotmon(mtmp)) + if (reveal_invis && !DEADMONSTER(mtmp)) { + if (cansee(gb.bhitpos.x, gb.bhitpos.y) && !canspotmon(mtmp)) map_invisible(gb.bhitpos.x, gb.bhitpos.y); } /* if effect was observable then discover the wand type provided From 2c6172a10dd712d4fcd9e68126687ed1af2d5e46 Mon Sep 17 00:00:00 2001 From: nhmall Date: Thu, 24 Apr 2025 22:45:49 -0400 Subject: [PATCH 611/791] follow-up bit to savefile changes - part 1 o_init.c restnames got missed --- src/o_init.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/o_init.c b/src/o_init.c index bebc4f866..42fbf73a1 100644 --- a/src/o_init.c +++ b/src/o_init.c @@ -418,11 +418,21 @@ restnames(NHFILE *nhfp) int i; unsigned int len = 0; - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) svb.bases, sizeof svb.bases); - mread(nhfp->fd, (genericptr_t) svd.disco, sizeof svd.disco); - mread(nhfp->fd, (genericptr_t) objects, - NUM_OBJECTS * sizeof (struct objclass)); + for (i = 0; i < (MAXOCLASSES + 2); ++i) { + if (nhfp->structlevel) { + mread(nhfp->fd, (genericptr_t) &svb.bases[i], sizeof(int)); + } + } + for (i = 0; i < NUM_OBJECTS; ++i) { + if (nhfp->structlevel) { + mread(nhfp->fd, (genericptr_t) &svd.disco[i], sizeof(short)); + } + } + for (i = 0; i < NUM_OBJECTS; ++i) { + if (nhfp->structlevel) { + mread(nhfp->fd, (genericptr_t) &objects[i], + sizeof(struct objclass)); + } } for (i = 0; i < NUM_OBJECTS; i++) { if (objects[i].oc_uname) { From 31e03f1c68b25ce2d68016421a9822539af9335e Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sat, 26 Apr 2025 20:38:46 +0300 Subject: [PATCH 612/791] Fix vision on plane of air We can't just unconditionally unblock vision when the cloud moves, as there could be a temporary poison cloud at that location. --- src/mkmaze.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mkmaze.c b/src/mkmaze.c index debc686cd..8e09bbf79 100644 --- a/src/mkmaze.c +++ b/src/mkmaze.c @@ -1644,7 +1644,7 @@ movebubbles(void) for (x = 1; x <= (COLNO - 1); x++) for (y = 0; y <= (ROWNO - 1); y++) { levl[x][y] = air_pos; - unblock_point(x, y); + recalc_block_point(x, y); /* all air or all cloud around the perimeter of the Air level tends to look strange; break up the pattern */ xedge = (boolean) (x < gbxmin || x > gbxmax); From 9e1e032ea81df4ca72637b8d6f1c523667480ce2 Mon Sep 17 00:00:00 2001 From: Kestrel Date: Thu, 3 Apr 2025 19:49:39 -0500 Subject: [PATCH 613/791] use_menu_glyphs --- dat/opthelp | 1 + doc/config.nh | 3 +++ include/flag.h | 1 + include/optlist.h | 3 +++ include/wintty.h | 1 + win/curses/cursdial.c | 9 ++------- win/tty/wintty.c | 12 ++++++++++-- 7 files changed, 21 insertions(+), 9 deletions(-) diff --git a/dat/opthelp b/dat/opthelp index 55c9b0028..330dd963a 100644 --- a/dat/opthelp +++ b/dat/opthelp @@ -80,6 +80,7 @@ travel enables travelling via mouse click if supported; [True] attempting to move the hero; does not affect travel via '_' use_darkgray use bold black instead of blue for black glyphs. [True] use_inverse display detected monsters in highlighted manner [False] +use_menu_glyphs show object glyphs in menu items (tty, curses) [True] verbose print more commentary during the game [True] whatis_menu show menu when getting a map location [False] whatis_moveskip skip same glyphs when getting a map location [False] diff --git a/doc/config.nh b/doc/config.nh index e1903861b..232ac2ba9 100644 --- a/doc/config.nh +++ b/doc/config.nh @@ -181,6 +181,9 @@ # acts as an accelerator key to select items of that class. #OPTIONS=menu_objsyms +# Show object glyphs in menus if supported by the windowport (tty, curses) +#OPTIONS=use_menu_glyphs + # Do not clear the screen before drawing menus, and align menus to right #OPTIONS=menu_overlay diff --git a/include/flag.h b/include/flag.h index d9d2ddf9a..798d923c9 100644 --- a/include/flag.h +++ b/include/flag.h @@ -334,6 +334,7 @@ struct instance_flags { boolean tux_penalty; /* True iff hero is a monk and wearing a suit */ boolean use_background_glyph; /* use background glyph when appropriate */ boolean use_menu_color; /* use color in menus; only if wc_color */ + boolean use_menu_glyphs; /* use object glyphs in menus, if the port supports it */ #ifdef STATUS_HILITES long hilite_delta; /* number of moves to leave a temp hilite lit */ long unhilite_deadline; /* time when oldest temp hilite should be unlit */ diff --git a/include/optlist.h b/include/optlist.h index 0a2234ed2..9d2db23c1 100644 --- a/include/optlist.h +++ b/include/optlist.h @@ -789,6 +789,9 @@ static int optfn_##a(int, int, boolean, char *, char *); NHOPTB(use_inverse, Advanced, 0, opt_out, set_in_game, On, Yes, No, No, NoAlias, &iflags.wc_inverse, Term_False, "display detected monsters in inverse") + NHOPTB(use_menu_glyphs, Advanced, 0, opt_out, set_in_game, + On, Yes, No, No, NoAlias, &iflags.use_menu_glyphs, + Term_False, "show object glyphs in menu items") NHOPTB(use_truecolor, Advanced, 0, opt_in, set_in_config, Off, Yes, No, No, "use_truecolour", &iflags.use_truecolor, Term_False, diff --git a/include/wintty.h b/include/wintty.h index c98db6958..c0c5d842e 100644 --- a/include/wintty.h +++ b/include/wintty.h @@ -34,6 +34,7 @@ typedef struct tty_mi { anything identifier; /* user identifier */ long count; /* user count */ char *str; /* description string (including accelerator) */ + glyph_info glyphinfo; /* glyph */ int attr; /* string attribute */ int color; /* string color */ boolean selected; /* TRUE if selected by user */ diff --git a/win/curses/cursdial.c b/win/curses/cursdial.c index dc34805b7..93157cd37 100644 --- a/win/curses/cursdial.c +++ b/win/curses/cursdial.c @@ -1060,11 +1060,9 @@ menu_win_size(nhmenu *menu) } else { /* Add space for accelerator (selector letter) */ curentrywidth += 4; -#if 0 /* FIXME: menu glyphs */ if (menu_item_ptr->glyphinfo.glyph != NO_GLYPH && iflags.use_menu_glyphs) curentrywidth += 2; -#endif } if (curentrywidth > maxentrywidth) { maxentrywidth = curentrywidth; @@ -1283,19 +1281,16 @@ menu_display_page( entry_cols -= 4; start_col += 4; } -#if 0 - /* FIXME: menuglyphs not implemented yet */ if (menu_item_ptr->glyphinfo.glyph != NO_GLYPH && iflags.use_menu_glyphs) { - color = (int) menu_item_ptr->glyphinfo.color; + color = menu_item_ptr->glyphinfo.gm.sym.color; curses_toggle_color_attr(win, color, NONE, ON); - mvwaddch(win, menu_item_ptr->line_num + 1, start_col, curletter); + mvwaddch(win, menu_item_ptr->line_num + 1, start_col, menu_item_ptr->glyphinfo.ttychar); curses_toggle_color_attr(win, color, NONE, OFF); mvwaddch(win, menu_item_ptr->line_num + 1, start_col + 1, ' '); entry_cols -= 2; start_col += 2; } -#endif color = menu_item_ptr->color; if (color == NO_COLOR) color = NONE; diff --git a/win/tty/wintty.c b/win/tty/wintty.c index 785dab116..7806785aa 100644 --- a/win/tty/wintty.c +++ b/win/tty/wintty.c @@ -1461,6 +1461,13 @@ process_menu_window(winid window, struct WinDesc *cw) (void) putchar('+'); /* all selected */ else (void) putchar('#'); /* count selected */ + } else if (iflags.use_menu_glyphs && n == 2 + && curr->identifier.a_void != 0 + && curr->glyphinfo.glyph != NO_GLYPH) { + /* tty_print_glyph could be used, but is overkill and requires referencing the cursor location */ + toggle_menu_attr(TRUE, curr->glyphinfo.gm.sym.color, ATR_NONE); + (void) putchar(curr->glyphinfo.ttychar); + toggle_menu_attr(FALSE, curr->glyphinfo.gm.sym.color, ATR_NONE); } else (void) putchar(*cp); } /* for *cp */ @@ -2537,8 +2544,8 @@ tty_start_menu(winid window, unsigned long mbehavior) void tty_add_menu( winid window, /* window to use, must be of type NHW_MENU */ - const glyph_info *glyphinfo UNUSED, /* glyph info with glyph to - * display with item */ + const glyph_info *glyphinfo, /* glyph info with glyph to + * display with item */ const anything *identifier, /* what to return if selected */ char ch, /* selector letter (0 = pick our own) */ char gch, /* group accelerator (0 = no group) */ @@ -2595,6 +2602,7 @@ tty_add_menu( item->attr = attr; item->color = clr; item->str = dupstr(newstr); + item->glyphinfo = *glyphinfo; item->next = cw->mlist; cw->mlist = item; From ee6538b3980c46e4a3735d6c8f28266c546c98c4 Mon Sep 17 00:00:00 2001 From: Kestrel Date: Fri, 11 Apr 2025 07:04:00 -0500 Subject: [PATCH 614/791] Update Guidebook.mn with use_menu_glyphs. --- doc/Guidebook.mn | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/Guidebook.mn b/doc/Guidebook.mn index c55a6f058..fb2f21156 100644 --- a/doc/Guidebook.mn +++ b/doc/Guidebook.mn @@ -4988,6 +4988,9 @@ to be \fIFalse\fP. Use bold black instead of blue for black glyphs (TTY only). .lp use_inverse If NetHack can, it should display inverse when the game specifies it. +.lp use_menu_glyphs +If NetHack can, it should display glyphs next to objects in the +inventory. .lp vary_msgcount If NetHack can, it should display this number of messages at a time in the message window. From 61f2af9ca9a17a240b3e3b8b13f300d9489621d0 Mon Sep 17 00:00:00 2001 From: Kestrel Date: Sun, 13 Apr 2025 07:53:04 -0500 Subject: [PATCH 615/791] Update Guidebook.tex with use_menu_glyphs. --- doc/Guidebook.tex | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/Guidebook.tex b/doc/Guidebook.tex index 9cced113b..c4fe56af3 100644 --- a/doc/Guidebook.tex +++ b/doc/Guidebook.tex @@ -5513,6 +5513,10 @@ Use bold black instead of blue for black glyphs (TTY only). \item[\ib{use\verb+_+inverse}] If {\it NetHack\/} can, it should display inverse when the game specifies it. %.lp +\item[\ib{use\verb+_+inverse}] +If {\it NetHack\/} can, it should display glyphs next to objects in the +inventory. +%.lp \item[\ib{vary\verb+_+msgcount}] If {\it NetHack\/} can, it should display this number of messages at a time in the message window. From 91f0c0852b2d72ffe22b3ed2dd229a1e0364ff40 Mon Sep 17 00:00:00 2001 From: Kestrel Date: Tue, 15 Apr 2025 11:44:16 -0500 Subject: [PATCH 616/791] Correct Guidebook.tex typo. --- doc/Guidebook.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/Guidebook.tex b/doc/Guidebook.tex index c4fe56af3..14cea949b 100644 --- a/doc/Guidebook.tex +++ b/doc/Guidebook.tex @@ -5513,7 +5513,7 @@ Use bold black instead of blue for black glyphs (TTY only). \item[\ib{use\verb+_+inverse}] If {\it NetHack\/} can, it should display inverse when the game specifies it. %.lp -\item[\ib{use\verb+_+inverse}] +\item[\ib{use\verb+_+menu\verb+_+glyphs}] If {\it NetHack\/} can, it should display glyphs next to objects in the inventory. %.lp From ba4f90eefbe2e60f2e10442243c0818a91e0dd56 Mon Sep 17 00:00:00 2001 From: PatR Date: Sat, 26 Apr 2025 12:50:48 -0700 Subject: [PATCH 617/791] PR #1406 = use_menu_glyphs for curses and tty Pull request from NullCGT: add 'use_menu_glyphs' option to be able show the object class symbol in menus of objects. tty: |a ? scroll of identify (instead of 'a - scroll of identify'), curses: | a) ? scroll of identify (instead of ' a) scroll of identify'). This commit fixes a bit of formatting in wintty.c. Closes #1406 --- win/tty/wintty.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/win/tty/wintty.c b/win/tty/wintty.c index 7806785aa..d042e6c9d 100644 --- a/win/tty/wintty.c +++ b/win/tty/wintty.c @@ -1461,15 +1461,19 @@ process_menu_window(winid window, struct WinDesc *cw) (void) putchar('+'); /* all selected */ else (void) putchar('#'); /* count selected */ - } else if (iflags.use_menu_glyphs && n == 2 - && curr->identifier.a_void != 0 - && curr->glyphinfo.glyph != NO_GLYPH) { - /* tty_print_glyph could be used, but is overkill and requires referencing the cursor location */ - toggle_menu_attr(TRUE, curr->glyphinfo.gm.sym.color, ATR_NONE); + } else if (iflags.use_menu_glyphs && n == 2 + && curr->identifier.a_void != 0 + && curr->glyphinfo.glyph != NO_GLYPH) { + int gcolor = curr->glyphinfo.gm.sym.color; + + /* tty_print_glyph could be used, but is overkill + and requires referencing the cursor location */ + toggle_menu_attr(TRUE, gcolor, ATR_NONE); (void) putchar(curr->glyphinfo.ttychar); - toggle_menu_attr(FALSE, curr->glyphinfo.gm.sym.color, ATR_NONE); - } else + toggle_menu_attr(FALSE, gcolor, ATR_NONE); + } else { (void) putchar(*cp); + } } /* for *cp */ if (n > attr_n && (color != NO_COLOR || attr != ATR_NONE)) toggle_menu_attr(FALSE, color, attr); From a587ccaa266782973296db54b9355cafa8d820ef Mon Sep 17 00:00:00 2001 From: PatR Date: Mon, 28 Apr 2025 18:12:02 -0700 Subject: [PATCH 618/791] merge new use_menu_glyphs option with menu_objsyms The two options are very similar but probably mutually exclusive except when using look-here and look-into-container (both via ':') with the default setting for 'sortloot', or with inventory when 'sortpack' has been toggled off. This removes 'use_menu_glyphs' and changes 'menu_objsyms' from a boolean to a compound taking six possible values: | 0: no object symbols in menus, | 1: append object class symbol to object header lines (same as old |menu_objsyms boolean), | 2: include object symbol in menu entry lines for objects (same as |recently added use_menu_glyphs), | 3: both 1 and 2, | 4: display as #2 but only if the menu lacks class header lines, | 5: if header lines are present, display as #1; if headers are not |present, then display as #4 (which will implicitly be #2). Default is #4. Effectively replaces the options portion of pull request #1406 and retains the functionality, but not as default for normal menus. Guidebook.tex is only partially updated. Someone else will need to finish that. --- dat/opthelp | 12 +++- doc/Guidebook.mn | 37 ++++++++-- doc/Guidebook.tex | 36 +++++++++- include/flag.h | 14 ++-- include/optlist.h | 9 +-- src/options.c | 155 ++++++++++++++++++++++++++++++++++++++++++ win/curses/cursdial.c | 22 +++++- win/tty/wintty.c | 29 +++++--- 8 files changed, 281 insertions(+), 33 deletions(-) diff --git a/dat/opthelp b/dat/opthelp index 330dd963a..16106b16c 100644 --- a/dat/opthelp +++ b/dat/opthelp @@ -40,7 +40,6 @@ mail enable the mail daemon [True] mention_decor give feedback when walking across stairs, altars, [False] fountains, and such even when not obscured by objects mention_walls give feedback when walking against a wall [False] -menu_objsyms show object symbols in menus if it is selectable [False] menu_overlay overlay menus on the screen and align to right [True] menucolors enable MENUCOLOR pattern matching to highlight [False] lines in object menus like inventory; might highlight with @@ -80,7 +79,6 @@ travel enables travelling via mouse click if supported; [True] attempting to move the hero; does not affect travel via '_' use_darkgray use bold black instead of blue for black glyphs. [True] use_inverse display detected monsters in highlighted manner [False] -use_menu_glyphs show object glyphs in menu items (tty, curses) [True] verbose print more commentary during the game [True] whatis_menu show menu when getting a map location [False] whatis_moveskip skip same glyphs when getting a map location [False] @@ -191,6 +189,16 @@ menustyle user interface for selection of multiple objects: [Full] only the first letter ('T','C','F','P') matters (With Traditional, many actions allow pseudo-class 'm' to request a menu for choosing items: one-shot Combination.) +menu_objsyms whether to include object class symbols in menus: [5] + 0 - none -- don't add object symbols to menus; + 1 - headers -- append object class symbol to menu header lines; + 2 - entries -- show object glyphs (same as class symbol + for ASCII interfaces) on each menu entry line; + 3 - both -- 1 and 2 combined; + 4 - conditional -- as 2 but only if no headers are present; + 5 - one-or-other -- 1 and 4 combined; + choices 0 and 1 should work with any interface; 2 through 5 + are supported by tty and curses msg_window behavior of ^P message recall for tty interface: [s] single -- one message at a time full -- full window with all saved top line messages diff --git a/doc/Guidebook.mn b/doc/Guidebook.mn index fb2f21156..7d3530359 100644 --- a/doc/Guidebook.mn +++ b/doc/Guidebook.mn @@ -4169,8 +4169,38 @@ Default \(oq|\(cq. Key to go to the next menu page. Default \(oq>\(cq. .lp menu_objsyms -Show object symbols in menu headings in menus where -the object symbols act as menu accelerators (default off). +." [originally menu_objsyms was a boolean] +." Show object symbols in menu headings in menus where +." the object symbols act as menu accelerators (default off). +Inventory and other object menus are normally separated by object class +(weapons, armor, and so forth), with a menu header line at the beginning +of each group. +You can have menus add the display symbol for the class of objects for +each header line. +You can also add the display symbol for the individual item in each menu +entry. +For a tiles map, that would be a small rendition of an object's tile. +For a text map, it is the same character as is used for the object's +class, which would be most useful when there are no headers separating +objects among classes. +Possible values are +.PS "5\ -\ One-or-other" +.PL "0\ -\ None" +no symbols for either header lines or menu entries; +.PL "1\ -\ Headers" +show symbols on header lines but not entries; +.PL "2\ -\ Entries" +show symbols on menu entry lines but not headers; +.PL "3\ -\ Both" +show symbols on headers and entries; +.PL "4\ -\ Conditional" +only show symbols for entries if there are no headers; +.PL "5\ -\ One-or-other" +show symbols on headers, or on entries if no headers. +.PE +Supported by tty and curses. +When setting the value, it can be specified by digit or keyword. +The default value is \f(CRConditional\fP (4). .lp menu_overlay Do not clear the screen before drawing menus, and align menus to the right edge of the screen. Only for the tty port. @@ -4988,9 +5018,6 @@ to be \fIFalse\fP. Use bold black instead of blue for black glyphs (TTY only). .lp use_inverse If NetHack can, it should display inverse when the game specifies it. -.lp use_menu_glyphs -If NetHack can, it should display glyphs next to objects in the -inventory. .lp vary_msgcount If NetHack can, it should display this number of messages at a time in the message window. diff --git a/doc/Guidebook.tex b/doc/Guidebook.tex index 14cea949b..6d7f1d38c 100644 --- a/doc/Guidebook.tex +++ b/doc/Guidebook.tex @@ -4576,8 +4576,40 @@ Key to go to the next menu page. Implemented by the Amiga, Gem and tty ports. Default `\verb+>+'. \item[\ib{menu\verb+_+objsyms}] -Show object symbols in menu headings in menus where -the object symbols act as menu accelerators (default off). +% [originally menu_objsyms was a boolean] +% Show object symbols in menu headings in menus where +% the object symbols act as menu accelerators (default off). +Inventory and other object menus are normally separated by object class +(weapons, armor, and so forth), with a menu header line at the beginning +of each group. +You can have menus add the display symbol for the class of objects for +each header line. +You can also add the display symbol for the individual item in each menu +entry. +For a tiles map, that would be a small rendition of an object's tile. +For a text map, it is the same character as is used for the object's +class, which would be most useful when there are no headers separating +objects among classes. +% FIXME! -- three column table may be simpler than mashing first two together +% Possible values are +% .PS "5\ -\ One-or-other" +% .PL "0\ -\ None" +% no symbols for either header lines or menu entries; +% .PL "1\ -\ Headers" +% show symbols on header lines but not entries; +% .PL "2\ -\ Entries" +% show symbols on menu entry lines but not headers; +% .PL "3\ -\ Both" +% show symbols on headers and entries; +% .PL "4\ -\ Conditional" +% only show symbols for entries if there are no headers; +% .PL "5\ -\ One-or-other" +% show symbols on headers, or on entries if no headers. +% .PE + +Supported by tty and curses. +When setting the value, it can be specified by digit or keyword. +The default value is {\tt Conditional} (4). \item[\ib{menu\verb+_+overlay}] Do not clear the screen before drawing menus, and align menus to the right edge of the screen. Only for the tty port. diff --git a/include/flag.h b/include/flag.h index 798d923c9..d586f3c5f 100644 --- a/include/flag.h +++ b/include/flag.h @@ -264,6 +264,8 @@ struct instance_flags { int getloc_filter; /* GFILTER_foo */ int in_lava_effects; /* hack for Boots_off() */ int last_msg; /* indicator of last message player saw */ + int menuobjsyms; /* value of 'menu_objsyms' option; + * ought to be in flags rather than iflags */ int override_ID; /* true to force full identification of objects */ int parse_config_file_src; /* hack for parse_config_line() */ int purge_monsters; /* # of dead monsters still on fmon list */ @@ -300,13 +302,13 @@ struct instance_flags { */ unsigned msg_history; /* hint: # of top lines to save */ int getpos_coords; /* show coordinates when getting cursor position */ - int menuinvertmode; /* 0 = invert toggles every item; - 1 = invert skips 'all items' item */ + int menuinvertmode; /* 0 = invert toggles every item; + * 1 = invert skips 'all items' item */ color_attr menu_headings; /* CLR_ and ATR_ for menu headings */ uint32_t colorcount; /* store how many colors terminal is capable of */ boolean use_truecolor; /* force use of truecolor */ #ifdef ALTMETA - boolean altmeta; /* Alt-c sends ESC c rather than M-c */ + boolean altmeta; /* Alt+c sends ESC c rather than M-c */ #endif boolean autodescribe; /* autodescribe mode in getpos() */ boolean cbreak; /* in cbreak mode, rogue format */ @@ -315,7 +317,8 @@ struct instance_flags { boolean echo; /* 1 to echo characters */ boolean force_invmenu; /* always menu when handling inventory */ boolean hilite_pile; /* mark piles of objects with a hilite */ - boolean menu_head_objsym; /* Show obj symbol in menu headings */ + boolean menu_head_objsym; /* Show obj symbol in menu headings; controlled + * by 'menuobjsyms' */ boolean menu_overlay; /* Draw menus over the map */ boolean menu_requested; /* Flag for overloaded use of 'm' prefix * on some non-move commands */ @@ -334,7 +337,8 @@ struct instance_flags { boolean tux_penalty; /* True iff hero is a monk and wearing a suit */ boolean use_background_glyph; /* use background glyph when appropriate */ boolean use_menu_color; /* use color in menus; only if wc_color */ - boolean use_menu_glyphs; /* use object glyphs in menus, if the port supports it */ + boolean use_menu_glyphs; /* use object glyphs in menus, if the port + * supports it; controlled by 'menuobjsyms' */ #ifdef STATUS_HILITES long hilite_delta; /* number of moves to leave a temp hilite lit */ long unhilite_deadline; /* time when oldest temp hilite should be unlit */ diff --git a/include/optlist.h b/include/optlist.h index 9d2db23c1..b0bc715f3 100644 --- a/include/optlist.h +++ b/include/optlist.h @@ -442,9 +442,9 @@ static int optfn_##a(int, int, boolean, char *, char *); No, Yes, No, No, NoAlias, "jump to the last page in a menu") NHOPTC(menu_next_page, Advanced, 4, opt_in, set_in_config, No, Yes, No, No, NoAlias, "go to the next menu page") - NHOPTB(menu_objsyms, Advanced, 0, opt_in, set_in_game, - Off, Yes, No, No, NoAlias, &iflags.menu_head_objsym, - Term_False, "show object symbols in menus") + NHOPTC(menu_objsyms, Advanced, 12, opt_in, set_in_game, + Yes, Yes, No, Yes, "use_menu_glyphs", + "show object symbols in menus") #ifdef TTY_GRAPHICS NHOPTB(menu_overlay, Advanced, 0, opt_in, set_in_game, On, Yes, No, No, NoAlias, &iflags.menu_overlay, Term_False, @@ -789,9 +789,6 @@ static int optfn_##a(int, int, boolean, char *, char *); NHOPTB(use_inverse, Advanced, 0, opt_out, set_in_game, On, Yes, No, No, NoAlias, &iflags.wc_inverse, Term_False, "display detected monsters in inverse") - NHOPTB(use_menu_glyphs, Advanced, 0, opt_out, set_in_game, - On, Yes, No, No, NoAlias, &iflags.use_menu_glyphs, - Term_False, "show object glyphs in menu items") NHOPTB(use_truecolor, Advanced, 0, opt_in, set_in_config, Off, Yes, No, No, "use_truecolour", &iflags.use_truecolor, Term_False, diff --git a/src/options.c b/src/options.c index 22963b343..704351790 100644 --- a/src/options.c +++ b/src/options.c @@ -257,6 +257,46 @@ static NEARDATA const char *perminv_modes[][3] = { /*8*/ { "in-use", "inuse-only", "subset: items currently in use" }, }; +struct objsymopt { + int num; + const char *nam; + const char *descr; +}; + +/* + * menuobjsyms: + * Inventory display for the various values of menuobjsyms. + * 4' and 5' represent !sortpack which lacks headers; they + * produce the same result. + * + * 0: 1: + * Weapons Weapons (')') + * a - 15 darts a - 15 darts + * Armor Armor ('[') + * b - Hawaiian shirt b - Hawaiian shirt + * 2: 3: + * Weapons Weapons (')') + * a ) 15 darts a ) 15 darts + * Armor Armor ('[') + * b [ Hawaiian shirt b [ Hawaiian shirt + * 4: 5: + * Weapons Weapons (')') + * a - 15 darts a - 15 darts + * Armor Armor ('[') + * b - Hawaiian shirt b - Hawaiian shirt + * 4': 5': + * a ) 15 darts a ) 15 darts + * b [ Hawaiian shirt b [ Hawaiian shirt + */ +static const struct objsymopt objsymvals[] = { + { 0, "none", "don't show object symbols in menus" }, + { 1, "headers", "show object symbols in menu header lines" }, + { 2, "entries", "show object symbols in individual menu entries" }, + { 3, "both", "show object symbols in headers and menu entries" }, + { 4, "conditional", "show objsyms in entries if no headers are shown" }, + { 5, "one-or-other", "show objsyms in header, in entries if no header" }, +}; + /* * Default menu manipulation command accelerators. These may _not_ be: * @@ -323,6 +363,7 @@ staticfn void rejectoption(const char *); staticfn char *string_for_opt(char *, boolean); staticfn char *string_for_env_opt(const char *, char *, boolean); staticfn void bad_negation(const char *, boolean); +staticfn void set_menuobjsyms_flags(int); staticfn int change_inv_order(char *); staticfn boolean warning_opts(char *, const char *); staticfn int feature_alert_opts(char *, const char *); @@ -368,6 +409,7 @@ staticfn int handler_align_misc(int); staticfn int handler_autounlock(int); staticfn int handler_disclose(void); staticfn int handler_menu_headings(void); +staticfn int handler_menu_objsyms(void); staticfn int handler_menustyle(void); staticfn int handler_msg_window(void); staticfn int handler_number_pad(void); @@ -2187,6 +2229,71 @@ optfn_menu_headings( return optn_ok; } +staticfn int +optfn_menu_objsyms( + int optidx, int req, + boolean negated, + char *opts, char *op) +{ + if (req == do_init) { + /* set iflags.menu_objsyms to 4, "conditional"; also sets + iflags.menu_head_objsym to False and + iflags.use_menu_glyphs True */ + set_menuobjsyms_flags(4); + return optn_ok; + } + if (req == do_set) { + unsigned k, l; + int i, osyms; + + if (negated) { + /* allow '!menu_objsyms' (and '!use_menu_glyphs') as + 'menu_objsyms:none' (0) */ + osyms = 0; + } else if (op == empty_optstr) { + /* treat boolean 'menu_objsyms' as 'menu_objsyms:headers' (1) + accept obsolete boolean 'use_menu_glyphs' as a synonym + for 'menu_objsyms:entries' (2) */ + osyms = !strncmp(opts, "use_menu_glyphs", 15) ? 2 : 1; + } else if (digit(*op)) { + i = atoi(op); + if (i >= SIZE(objsymvals)) { + config_error_add("Illegal %s parameter '%s'", + allopt[optidx].name, op); + return optn_err; + } + osyms = i; + } else { + /* stilted "one-or-other" is used to compress the menu width */ + static const char alt5[] = "one-or-the-other"; + unsigned l5 = (unsigned) (sizeof alt5 - sizeof ""); + + osyms = 0; + k = (unsigned) strlen(op); + for (i = 0; i < SIZE(objsymvals); ++i) { + l = (unsigned) strlen(objsymvals[i].nam); + if (k >= 4) + l = k; + if (!strncmpi(objsymvals[i].nam, op, l) + || (i == 5 && !strncmpi(alt5, op, l5))) { + osyms = i; + break; + } + } + } + set_menuobjsyms_flags(osyms); + return optn_ok; + } + if (req == get_val || req == get_cnf_val) { + Sprintf(opts, "%s", objsymvals[iflags.menuobjsyms].nam); + return optn_ok; + } + if (req == do_handler) { + return handler_menu_objsyms(); + } + return optn_ok; +} + staticfn int optfn_menuinvertmode( int optidx, int req, @@ -5671,6 +5778,43 @@ handler_menu_headings(void) return optn_ok; } +staticfn int +handler_menu_objsyms(void) +{ + winid tmpwin; + anything any; + char buf[BUFSZ]; + menu_item *picklist = (menu_item *) 0; + const char sep = iflags.menu_tab_sep ? '\t' : ' '; + int i, j, n, clr = NO_COLOR; + + tmpwin = create_nhwindow(NHW_MENU); + start_menu(tmpwin, MENU_BEHAVE_STANDARD); + any = cg.zeroany; + for (i = 0; i < SIZE(objsymvals); ++i) { + Snprintf(buf, sizeof buf, "%-12.12s%c%.60s", + objsymvals[i].nam, sep, objsymvals[i].descr); + any.a_int = i + 1; + j = objsymvals[i].num; + add_menu(tmpwin, &nul_glyphinfo, &any, '0' + i, *buf, + ATR_NONE, clr, buf, + (j == iflags.menuobjsyms) ? MENU_ITEMFLAGS_SELECTED + : MENU_ITEMFLAGS_NONE); + } + end_menu(tmpwin, "Set object symbols in menus to what?"); + n = select_menu(tmpwin, PICK_ONE, &picklist); + if (n > 0) { + i = picklist[0].item.a_int - 1; + /* if there are two picks, use the one that wasn't pre-selected */ + if (n > 1 && i == iflags.menuobjsyms) + i = picklist[1].item.a_int - 1; + set_menuobjsyms_flags(i); + free((genericptr_t) picklist); + } + destroy_nhwindow(tmpwin); + return optn_ok; +} + staticfn int handler_msg_window(void) { @@ -7033,6 +7177,7 @@ initoptions_init(void) flags.pile_limit = PILE_LIMIT_DFLT; /* 5 */ flags.runmode = RUN_LEAP; iflags.msg_history = 20; + /* msg_window has conflicting defaults for multi-interface binary */ #ifdef TTY_GRAPHICS iflags.prevmsg_window = 's'; @@ -7310,6 +7455,16 @@ initoptions_finish(void) ******************************************* */ +/* iflags.menuobjsyms also controls iflags.menu_head_objsym, and + iflags.use_menu_glyphs; they affect execution but are no longer options */ +staticfn void +set_menuobjsyms_flags(int newobjsyms) +{ + iflags.menuobjsyms = newobjsyms; + iflags.menu_head_objsym = ((newobjsyms & 1) != 0) ? TRUE : FALSE; + iflags.use_menu_glyphs = ((newobjsyms & (2 | 4)) != 0) ? TRUE : FALSE; +} + /* * Change the inventory order, using the given string as the new order. * Missing characters in the new order are filled in at the end from diff --git a/win/curses/cursdial.c b/win/curses/cursdial.c index 93157cd37..85803a5a8 100644 --- a/win/curses/cursdial.c +++ b/win/curses/cursdial.c @@ -60,6 +60,7 @@ typedef struct nhm { unsigned long mbehavior; /* menu flags */ boolean reuse_accels; /* Non-unique accelerators per page */ boolean bottom_heavy; /* display multi-page menu starting at end */ + boolean show_obj_syms; /* handle iflags.menuobjsyms */ struct nhm *prev_menu; /* Pointer to previous menu */ struct nhm *next_menu; /* Pointer to next menu */ } nhmenu; @@ -552,6 +553,7 @@ curses_create_nhmenu(winid wid, unsigned long mbehavior) new_menu->mbehavior = mbehavior; new_menu->reuse_accels = FALSE; new_menu->bottom_heavy = FALSE; + new_menu->show_obj_syms = FALSE; return; } @@ -565,6 +567,7 @@ curses_create_nhmenu(winid wid, unsigned long mbehavior) new_menu->mbehavior = mbehavior; new_menu->reuse_accels = FALSE; new_menu->bottom_heavy = FALSE; + new_menu->show_obj_syms = FALSE; new_menu->next_menu = NULL; if (nhmenus == NULL) { /* no menus in memory yet */ @@ -1029,6 +1032,18 @@ menu_win_size(nhmenu *menu) int maxentrywidth = 0; int maxheaderwidth = menu->prompt ? (int) strlen(menu->prompt) : 0; nhmenu_item *menu_item_ptr, *last_item_ptr = NULL; + boolean only_if_no_headers = (iflags.menuobjsyms & 4) != 0; + + /* check entire menu rather than one page at a time */ + menu->show_obj_syms = iflags.use_menu_glyphs; + if (only_if_no_headers) { + for (menu_item_ptr = menu->entries; menu_item_ptr != NULL; + menu_item_ptr = menu_item_ptr->next_item) + if (menu_item_ptr->identifier.a_void == 0) { + menu->show_obj_syms = FALSE; + break; + } + } #if 0 /* maxwidth is set below, so the value calculated here isn't used */ if (program_state.gameover) { @@ -1061,7 +1076,7 @@ menu_win_size(nhmenu *menu) /* Add space for accelerator (selector letter) */ curentrywidth += 4; if (menu_item_ptr->glyphinfo.glyph != NO_GLYPH - && iflags.use_menu_glyphs) + && menu->show_obj_syms) curentrywidth += 2; } if (curentrywidth > maxentrywidth) { @@ -1282,10 +1297,11 @@ menu_display_page( start_col += 4; } if (menu_item_ptr->glyphinfo.glyph != NO_GLYPH - && iflags.use_menu_glyphs) { + && menu->show_obj_syms) { color = menu_item_ptr->glyphinfo.gm.sym.color; curses_toggle_color_attr(win, color, NONE, ON); - mvwaddch(win, menu_item_ptr->line_num + 1, start_col, menu_item_ptr->glyphinfo.ttychar); + mvwaddch(win, menu_item_ptr->line_num + 1, start_col, + menu_item_ptr->glyphinfo.ttychar); curses_toggle_color_attr(win, color, NONE, OFF); mvwaddch(win, menu_item_ptr->line_num + 1, start_col + 1, ' '); entry_cols -= 2; diff --git a/win/tty/wintty.c b/win/tty/wintty.c index d042e6c9d..4c7a107dc 100644 --- a/win/tty/wintty.c +++ b/win/tty/wintty.c @@ -1330,7 +1330,8 @@ process_menu_window(winid window, struct WinDesc *cw) tty_menu_item *page_start, *page_end, *curr; long count; int n, attr_n, curr_page, page_lines, resp_len, previous_page_lines; - boolean finished, counting, reset_count; + boolean finished, counting, reset_count, show_obj_syms, + only_if_no_headers = (iflags.menuobjsyms & 4) != 0; char *cp, *rp, resp[QBUFSZ], gacc[QBUFSZ], *msave, *morestr, really_morc; #define MENU_EXPLICIT_CHOICE 0x7f /* pseudo menu manipulation char */ @@ -1378,6 +1379,15 @@ process_menu_window(winid window, struct WinDesc *cw) } resp_len = 0; /* lint suppression */ + show_obj_syms = iflags.use_menu_glyphs; + if (only_if_no_headers) { + for (curr = cw->mlist; curr; curr = curr->next) + if (curr->identifier.a_void == 0) { + show_obj_syms = FALSE; + break; + } + } + /* loop until finished */ while (!finished) { HUPSKIP(); @@ -1432,7 +1442,7 @@ process_menu_window(winid window, struct WinDesc *cw) if (curr->str[0] && curr->str[1] == ' ' && curr->str[2] && strchr("-+#", curr->str[2]) && curr->str[3] == ' ') - /* [0]=letter, [1]==space, [2]=[-+#], [3]=space */ + /* [0]=letter, [1]=space, [2]=[-+#], [3]=space */ attr_n = 4; /* [4:N]=entry description */ /* @@ -1454,15 +1464,14 @@ process_menu_window(winid window, struct WinDesc *cw) if (n == attr_n && (color != NO_COLOR || attr != ATR_NONE)) toggle_menu_attr(TRUE, color, attr); - if (n == 2 - && curr->identifier.a_void != 0 + if (n == 2 && curr->identifier.a_void != 0 && curr->selected) { - if (curr->count == -1L) - (void) putchar('+'); /* all selected */ - else - (void) putchar('#'); /* count selected */ - } else if (iflags.use_menu_glyphs && n == 2 - && curr->identifier.a_void != 0 + char c = (curr->count == -1L) ? '*' : '#'; + + /* all selected: '*' vs count selected: '#' */ + (void) putchar(c); + } else if (n == 2 && curr->identifier.a_void != 0 + && show_obj_syms && curr->glyphinfo.glyph != NO_GLYPH) { int gcolor = curr->glyphinfo.gm.sym.color; From d8ff80978e805660236ad720370cfb3fbd340206 Mon Sep 17 00:00:00 2001 From: PatR Date: Tue, 29 Apr 2025 11:05:03 -0700 Subject: [PATCH 619/791] remove vestige of 'use_menu_glyphs' --- doc/config.nh | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/doc/config.nh b/doc/config.nh index 232ac2ba9..695534110 100644 --- a/doc/config.nh +++ b/doc/config.nh @@ -1,7 +1,10 @@ -# NetHack 3.7 config.nh $NHDT-Date: 1596498144 2020/08/03 23:42:24 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.4 $ +# NetHack 3.7 config.nh $NHDT-Date: 1745978702 2025/04/29 18:05:02 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.10 $ # Copyright (c) 2016 by Pasi Kallinen # NetHack may be freely redistributed. See license for details. -# Sample config file for NetHack 3.7.0 +# +# Sample run-time configuration file for NetHack 3.7.0 +# usually named ".nethackrc" (note leading dot; location +# depends upon the type of system nethack is running on). # # A '#' at the beginning of a line means the rest of the line is a comment. # @@ -177,12 +180,17 @@ # Default is 'inverse' #OPTIONS=menu_headings:inverse -# Show object symbols in menus in the item class lines where that object symbol -# acts as an accelerator key to select items of that class. -#OPTIONS=menu_objsyms - -# Show object glyphs in menus if supported by the windowport (tty, curses) -#OPTIONS=use_menu_glyphs +# Control of displaying object symbols in menus for picking objects: +# show symbols in individual menu entries only if there are no class separators +#OPTIONS=menu_objsyms:4 +# show symbols on object class separator lines and also in individual entries +#OPTIONS=menu_objsyms:3 +# show symbols in individual entries but not on class separators +#OPTIONS=menu_objsyms:2 +# show object symbols on class separators but not in individual entries +#OPTIONS=menu_objsyms:1 +# don't show symbols on class separators or in individual menu entries +#OPTIONS=menu_objsyms:0 # Do not clear the screen before drawing menus, and align menus to right #OPTIONS=menu_overlay From a1e3943e1f6f8337b66589d32aecd50688fc20b2 Mon Sep 17 00:00:00 2001 From: PatR Date: Thu, 1 May 2025 15:43:57 -0700 Subject: [PATCH 620/791] fix #K4327 - inaccurate Guidebook for role/race/&c The Guidebook states that the default values for 'role', 'race', 'gender', and 'alignment' are "random" but that's wrong. Omitting those options results in interactive prompting. --- doc/Guidebook.mn | 19 ++++++++++++++----- doc/Guidebook.tex | 21 ++++++++++++++++----- 2 files changed, 30 insertions(+), 10 deletions(-) diff --git a/doc/Guidebook.mn b/doc/Guidebook.mn index 7d3530359..e852ff559 100644 --- a/doc/Guidebook.mn +++ b/doc/Guidebook.mn @@ -47,7 +47,7 @@ .ds f0 \*(vr .ds f1 \" empty .\"DO NOT REMOVE NH_DATESUB .ds f2 Date(%B %-d, %Y) -.ds f2 April 20, 2025 +.ds f2 May 1, 2025 . .\" A note on some special characters: .\" \(lq = left double quote @@ -3788,7 +3788,8 @@ See .op role for a description of how to use negation to exclude choices. .lp "" -Default is random. +If \f(CRalign\fP is not specified, there is no default value; +player will be prompted unless role and/or race forces a choice for alignment. Cannot be set with the \(oq\f(CRO\fP\(cq command. Persistent. .lp autodescribe @@ -4014,7 +4015,8 @@ See .op role for a description of how to use negation to exclude choices. .lp "" -Default is random. +If \f(CRgender\fP is not specified, there is no default value; +player will be prompted unless role and/or race forces a choice for gender. Cannot be set with the \(oq\f(CRO\fP\(cq command. Persistent. .lp "goldX " @@ -4284,6 +4286,11 @@ the role (that is, by suffixing one of If .op "\-@" is used for the role, then a random one will be automatically chosen. +.lp "" +On some systems, the default is the player's user name; +on others, there is no default and the player will be prompted. +The former can made to behave like the latter by specifying a generic name +such as ``player''. Cannot be set with the \(oq\f(CRO\fP\(cq command. .lp "news " Read the NetHack news file, if present (default on). @@ -4544,7 +4551,8 @@ See .op role for a description of how to use negation to exclude choices. .lp "" -Default is random. +If \f(CRrace\fP is not specified, there is no default value; +player will be prompted unless role forces a choice for race. Cannot be set with the \(oq\f(CRO\fP\(cq command. Persistent. .lp rest_on_space @@ -4580,7 +4588,8 @@ option if they're all negations. .\" Only one positive value is allowed, and if present, it overrides any .\" negations. .lp "" -Default is \f(CRrandom\fP. +If \f(CRrole\fP is not specified, there is no default value; +player will be prompted. Cannot be set with the \(oq\f(CRO\fP\(cq command. Persistent. .lp roguesymset diff --git a/doc/Guidebook.tex b/doc/Guidebook.tex index 6d7f1d38c..f590cefa3 100644 --- a/doc/Guidebook.tex +++ b/doc/Guidebook.tex @@ -48,7 +48,7 @@ \author{Original version - Eric S. Raymond\\ (Edited and expanded for 3.7.0 by Mike Stephenson and others)} %DO NOT REMOVE NH_DATESUB \date{Date(%B %-d, %Y)} -\date{April 20, 2025} +\date{May 1, 2025} \maketitle @@ -4145,7 +4145,8 @@ See {\it role\/} for a description of how to use negation to exclude choices. %.lp "" \\ -Default is random. +If {\tt align} is not specified, there is no default value; +player will be prompted unless role and/or race forces a choice for alignment. Cannot be set with the `{\tt O}' command. Persistent. %.lp \item[\ib{autodescribe}] @@ -4400,7 +4401,8 @@ See {\it role\/} for a description of how to use negation to exclude choices. %.lp "" \\ -Default is random. +If {\tt gender} is not specified, there is no default value; +player will be prompted unless role and/or race forces a choice for gender. Cannot be set with the `{\tt O}' command. Persistent. %.lp \item[\ib{goldX}] @@ -4708,6 +4710,12 @@ the role (that is, by suffixing one of ``{\tt -A -B -C -H -K -M -P -Ra -Ro -S -T -V -W}''). If ``{\tt -@}'' is used for the role, then a random one will be automatically chosen. +%.lp +\\ +On some systems, the default is the player's user name; +on others, there is no default and the player will be prompted. +The former can made to behave like the latter by specifying a generic name +such as ``player''. Cannot be set with the `{\tt O}' command. %.lp \item[\ib{news}] @@ -4990,7 +4998,9 @@ See {\it role\/} for a description of how to use negation to exclude choices. %.lp "" \\ -Default is random. +If {\tt race} is not specified, there is no default value; +player will be prompted unless role forces a choice for race. +unless role forces a choice for race. Cannot be set with the `{\tt O}' command. Persistent. %.lp \item[\ib{rest\verb+_+on\verb+_+space}] @@ -5025,7 +5035,8 @@ option if they're all negations. %.\" negations. %.lp "" \\ -Default is random. +If {\tt role} is not specified, there is no default value; +player will be prompted. Cannot be set with the `{\tt O}' command. Persistent. %.lp \item[\ib{roguesymset}] From d88f0cfeeee52cca3934580ffd824bc44a792ed7 Mon Sep 17 00:00:00 2001 From: Alex Smith Date: Mon, 5 May 2025 01:22:29 +0100 Subject: [PATCH 621/791] Change level difficulty formula for the ring of aggravate monster +15 wasn't very impactful in the late game and late mid-game, but was much too lethal in the early game (wearing the ring for a while near the start of the game would make the game unwinnable as very out-of-depth monsters spawned, and they would still be there even after removing the ring and usually capable of one-shotting an early-game character). This commit changes it to a doubling of level difficulty rather than a flat increase: that makes it more relevant in the late-game where a +25 or +50 might potentially have an impact, and more survivable in the early game (although it still spawns monsters that are difficult for the point in the game, there is now a chance that you might survive long enough to be able to take the ring off and clear off all the out-of-depth monsters that spawned). --- src/dungeon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dungeon.c b/src/dungeon.c index aac8266a8..9a43ed7ac 100644 --- a/src/dungeon.c +++ b/src/dungeon.c @@ -2073,7 +2073,7 @@ level_difficulty(void) } /* ring of aggravate monster */ if (EAggravate_monster) - res += 15; + res = res > 25 ? 50 : res * 2; return res; } From af6c53ac7cd01df904f5a53c1a3a00ac48f18aea Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sat, 10 May 2025 18:42:38 +0300 Subject: [PATCH 622/791] m_respond code reorg and splitting --- src/mon.c | 68 +++++++++++++++++++++++++++++++-------------------- src/monmove.c | 13 ++-------- 2 files changed, 44 insertions(+), 37 deletions(-) diff --git a/src/mon.c b/src/mon.c index 89d2949a5..049d21d14 100644 --- a/src/mon.c +++ b/src/mon.c @@ -22,6 +22,8 @@ staticfn boolean vamprises(struct monst *); staticfn void logdeadmon(struct monst *, int); staticfn void anger_quest_guardians(struct monst *); staticfn boolean ok_to_obliterate(struct monst *); +staticfn void m_respond_shrieker(struct monst *); +staticfn void m_respond_medusa(struct monst *); staticfn void qst_guardians_respond(void); staticfn void peacefuls_respond(struct monst *); staticfn void wake_nearto_core(coordxy, coordxy, int, boolean); @@ -4013,36 +4015,50 @@ mnearto( return res; } -/* monster responds to player action; not the same as a passive attack; - assumes reason for response has been tested, and response _must_ be made */ +/* shrieker special action: shriek, maybe summon monster, aggravate */ +staticfn void +m_respond_shrieker(struct monst *mtmp) +{ + if (!Deaf) { + pline("%s shrieks.", Monnam(mtmp)); + stop_occupation(); + } + if (!rn2(10)) { /* 1/10 chance per shriek to create a monster */ + /* new monster has a 1/13 chance to be a purple worm, random + otherwise; baby purple worm if adult is too difficult */ + (void) makemon(rn2(13) ? (struct permonst *) 0 + : &mons[montoostrong(PM_PURPLE_WORM, + monmax_difficulty_lev()) + ? PM_BABY_PURPLE_WORM : PM_PURPLE_WORM], + 0, 0, NO_MM_FLAGS); + } + aggravate(); +} + +/* medusa special action: gaze at hero */ +staticfn void +m_respond_medusa(struct monst *mtmp) +{ + int i; + + for (i = 0; i < NATTK; i++) + if (mtmp->data->mattk[i].aatyp == AT_GAZE) { + (void) gazemu(mtmp, &mtmp->data->mattk[i]); + break; + } +} + +/* monster responds to player action; not the same as a passive attack */ void m_respond(struct monst *mtmp) { - if (mtmp->data->msound == MS_SHRIEK) { - if (!Deaf) { - pline("%s shrieks.", Monnam(mtmp)); - stop_occupation(); - } - if (!rn2(10)) { /* 1/10 chance per shriek to create a monster */ - /* new monster has a 1/13 chance to be a purple worm, random - otherwise; baby purple worm if adult is too difficult */ - (void) makemon(rn2(13) ? (struct permonst *) 0 - : &mons[montoostrong(PM_PURPLE_WORM, - monmax_difficulty_lev()) - ? PM_BABY_PURPLE_WORM : PM_PURPLE_WORM], - 0, 0, NO_MM_FLAGS); - } + if (mtmp->data->msound == MS_SHRIEK && !um_dist(mtmp->mx, mtmp->my, 1)) + m_respond_shrieker(mtmp); + if (mtmp->data == &mons[PM_MEDUSA] && couldsee(mtmp->mx, mtmp->my)) + m_respond_medusa(mtmp); + /* Erinyes will inform surrounding monsters of your crimes */ + if (mtmp->data == &mons[PM_ERINYS] && !mtmp->mpeaceful && m_canseeu(mtmp)) aggravate(); - } - if (mtmp->data == &mons[PM_MEDUSA]) { - int i; - - for (i = 0; i < NATTK; i++) - if (mtmp->data->mattk[i].aatyp == AT_GAZE) { - (void) gazemu(mtmp, &mtmp->data->mattk[i]); - break; - } - } } /* how quest guardians respond when you attack the quest leader */ diff --git a/src/monmove.c b/src/monmove.c index b8c58cc8b..8bf665099 100644 --- a/src/monmove.c +++ b/src/monmove.c @@ -738,17 +738,8 @@ dochug(struct monst *mtmp) return 0; } - /* Erinyes will inform surrounding monsters of your crimes */ - if (mdat == &mons[PM_ERINYS] && !mtmp->mpeaceful && m_canseeu(mtmp)) - aggravate(); - - /* Shriekers and Medusa have irregular abilities which must be - checked every turn. These abilities do not cost a turn when - used. */ - if (mdat->msound == MS_SHRIEK && !um_dist(mtmp->mx, mtmp->my, 1)) - m_respond(mtmp); - if (mdat == &mons[PM_MEDUSA] && couldsee(mtmp->mx, mtmp->my)) - m_respond(mtmp); + /* some monsters have special abilities */ + m_respond(mtmp); if (DEADMONSTER(mtmp)) return 1; /* m_respond gaze can kill medusa */ From 6d374f9306213c65441e8b5f8598f1294d4d720d Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sun, 11 May 2025 20:28:20 +0300 Subject: [PATCH 623/791] No knockback with flimsy or non-blunt weapon Weapons that can do knockback are lucern hammer, bec de corbin, dwarvish mattock, (silver) mace, morning star, war hammer, club, quarterstaff, aklys, flail, pick-axe, and grappling hook. --- include/obj.h | 3 +++ src/uhitm.c | 8 +++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/include/obj.h b/include/obj.h index 3b1524b17..782f545bf 100644 --- a/include/obj.h +++ b/include/obj.h @@ -246,6 +246,9 @@ struct obj { ((o)->oclass == TOOL_CLASS && objects[(o)->otyp].oc_skill != P_NONE) /* towel is not a weptool: spe isn't an enchantment, cursed towel doesn't weld to hand, and twoweapon won't work with one */ +#define is_blunt_weapon(o) \ + (((o)->oclass == WEAPON_CLASS || is_weptool(o)) \ + && ((objects[(o)->otyp].oc_dir & WHACK) != 0)) #define is_wet_towel(o) ((o)->otyp == TOWEL && (o)->spe > 0) #define bimanual(otmp) \ ((otmp->oclass == WEAPON_CLASS || otmp->oclass == TOOL_CLASS) \ diff --git a/src/uhitm.c b/src/uhitm.c index ced52abc5..d03a267dc 100644 --- a/src/uhitm.c +++ b/src/uhitm.c @@ -5189,6 +5189,8 @@ mhitm_knockback( boolean u_agr = (magr == &gy.youmonst); boolean u_def = (mdef == &gy.youmonst); boolean was_u = FALSE, dismount = FALSE; + struct obj *wep = weapon_used ? (u_agr ? uwep : MON_WEP(magr)) + : (struct obj *)0; /* 1/6 chance of attack knocking back a monster */ if (rn2(6)) @@ -5236,12 +5238,16 @@ mhitm_knockback( if (!(magr->data->msize > (mdef->data->msize + 1))) return FALSE; + /* no knockback with a flimsy or non-blunt weapon */ + if (wep && (is_flimsy(wep) || !is_blunt_weapon(wep))) + return FALSE; + /* only certain attacks qualify for knockback */ if (!((mattk->adtyp == AD_PHYS) && (mattk->aatyp == AT_CLAW || mattk->aatyp == AT_KICK || mattk->aatyp == AT_BUTT - || (mattk->aatyp == AT_WEAP && !weapon_used)))) + || mattk->aatyp == AT_WEAP))) return FALSE; /* needs a solid physical hit */ From bd98dda8c19edbf589746a576999cb98b8035281 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sun, 11 May 2025 21:23:38 +0300 Subject: [PATCH 624/791] Unpolyed hero can knockback too Noticed a strange oversight in knockback: Hero hitting a monster did not cause knockback, unless polymorphed into a monster. Add knockback chance if we're using a weapon, not twoweaponing, and dealing some damage. --- src/uhitm.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/uhitm.c b/src/uhitm.c index d03a267dc..6fe983a51 100644 --- a/src/uhitm.c +++ b/src/uhitm.c @@ -1724,6 +1724,7 @@ hmon_hitmon( int dieroll) { struct _hitmon_data hmd; + boolean maybe_knockback = FALSE; hmd.dmg = 0; hmd.thrown = thrown; @@ -1790,6 +1791,9 @@ hmon_hitmon( hmon_hitmon_jousting(&hmd, mon, obj); } else if (hmd.unarmed && hmd.dmg > 1 && !thrown && !obj && !Upolyd) { hmon_hitmon_stagger(&hmd, mon, obj); + } else if (!hmd.unarmed && hmd.dmg > 1 && !thrown && !Upolyd + && !u.twoweap && uwep) { + maybe_knockback = TRUE; } if (!hmd.already_killed) { @@ -1869,9 +1873,17 @@ hmon_hitmon( Your("%s %s no longer poisoned.", hmd.saved_oname, vtense(hmd.saved_oname, "are")); - if (!hmd.destroyed) - wakeup(mon, TRUE); + if (!hmd.destroyed) { + int hitflags = M_ATTK_HIT; + wakeup(mon, TRUE); + if (maybe_knockback + && mhitm_knockback(&gy.youmonst, mon, gy.youmonst.data->mattk, + &hitflags, TRUE)) { + if ((hitflags & M_ATTK_DEF_DIED) != 0) + hmd.destroyed = TRUE; + } + } return hmd.destroyed ? FALSE : TRUE; } From c90cc53ab3cc1b1a101d7b4948fd13dd3faecb90 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Mon, 12 May 2025 10:24:06 +0300 Subject: [PATCH 625/791] Ogresmasher gives a higher chance of knockback --- doc/fixes3-7-0.txt | 1 + src/uhitm.c | 7 +++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index 0787fcea3..3a183935f 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -1513,6 +1513,7 @@ Grimtooth is permanently poisoned, protects from poison, and can fling poison cursed magic whistle can teleport you to your pet Fire and Frost Brand can be invoked for expert level fireball or cone of cold wielding Trollsbane grants hungerless regeneration +hitting with Ogresmasher gives a higher chance of knockback Fixes to 3.7.0-x General Problems Exposed Via git Repository diff --git a/src/uhitm.c b/src/uhitm.c index 6fe983a51..56a4079ce 100644 --- a/src/uhitm.c +++ b/src/uhitm.c @@ -5198,14 +5198,17 @@ mhitm_knockback( const char *knockedhow; coordxy dx, dy, defx, defy; int knockdistance = rn2(3) ? 1 : 2; /* 67%: 1 step, 33%: 2 steps */ + int chance = 6; /* 1/6 chance of attack knocking back a monster */ boolean u_agr = (magr == &gy.youmonst); boolean u_def = (mdef == &gy.youmonst); boolean was_u = FALSE, dismount = FALSE; struct obj *wep = weapon_used ? (u_agr ? uwep : MON_WEP(magr)) : (struct obj *)0; - /* 1/6 chance of attack knocking back a monster */ - if (rn2(6)) + if (wep && is_art(wep, ART_OGRESMASHER)) + chance = 2; + + if (rn2(chance)) return FALSE; /* decide where the first step will place the target; not accurate From 8ac31b24f64fdbcf4ee0e4f7b5a06977e66fc6de Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 12 May 2025 08:45:26 -0400 Subject: [PATCH 626/791] libnh build The macOS.370 has not yet been tested, but it is patterned after the linux.370 changes. --- sys/unix/hints/linux.370 | 9 +++++---- sys/unix/hints/macOS.370 | 9 +++++---- win/shim/winshim.c | 10 +++++----- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/sys/unix/hints/linux.370 b/sys/unix/hints/linux.370 index 1644cc826..2c4e460e8 100755 --- a/sys/unix/hints/linux.370 +++ b/sys/unix/hints/linux.370 @@ -440,13 +440,14 @@ endif endif ifdef WANT_LIBNH -$(TARGETPFX)libnh.a: $(HOBJ) $(LIBNHSYSOBJ) ../lib/lua/liblua.a - $(AR) rcs $@ $(HOBJ) $(LIBNHSYSOBJ) ../lib/lua/liblua.a +$(TARGETPFX)libnh.a: $(HOBJ) $(LIBNHSYSOBJ) ../lib/lua/liblua-$(LUA_VERSION).a + $(AR) rcs $@ $(HOBJ) $(LIBNHSYSOBJ) ../lib/lua/liblua-$(LUA_VERSION).a @echo "$@ built." $(TARGETPFX)libnhmain.o : ../sys/libnh/libnhmain.c $(HACK_H) $(CC) $(CFLAGS) -c -o$@ $< -$(TARGETPFX)winshim.o : ../win/shim/winshim.c $(HACK_H) - $(CC) $(CFLAGS) -c -o$@ $< +#dependency tool added this to Makefile.src +#$(TARGETPFX)winshim.o : ../win/shim/winshim.c $(HACK_H) +# $(CC) $(CFLAGS) -c -o$@ $< endif # WANT_LIBNH # diff --git a/sys/unix/hints/macOS.370 b/sys/unix/hints/macOS.370 index 48b9e90df..ad522bb2f 100755 --- a/sys/unix/hints/macOS.370 +++ b/sys/unix/hints/macOS.370 @@ -545,13 +545,14 @@ endif endif ifdef WANT_LIBNH -$(TARGETPFX)libnh.a: $(HOBJ) $(LIBNHSYSOBJ) ../lib/lua/liblua.a - $(AR) rcs $@ $(HOBJ) $(LIBNHSYSOBJ) ../lib/lua/liblua.a +$(TARGETPFX)libnh.a: $(HOBJ) $(LIBNHSYSOBJ) ../lib/lua/liblua-$(LUA_VERSION).a + $(AR) rcs $@ $(HOBJ) $(LIBNHSYSOBJ) ../lib/lua/liblua-$(LUA_VERSION).a @echo "$@ built." $(TARGETPFX)libnhmain.o : ../sys/libnh/libnhmain.c $(HACK_H) $(CC) $(CFLAGS) -c -o$@ $< -$(TARGETPFX)winshim.o : ../win/shim/winshim.c $(HACK_H) - $(CC) $(CFLAGS) -c -o$@ $< +# dependency tool added this to Makefile.src +#$(TARGETPFX)winshim.o : ../win/shim/winshim.c $(HACK_H) +# $(CC) $(CFLAGS) -c -o$@ $< endif # WANT_LIBNH ifdef MAKEFILE_DOC diff --git a/win/shim/winshim.c b/win/shim/winshim.c index 81bc7411d..ae4caed12 100644 --- a/win/shim/winshim.c +++ b/win/shim/winshim.c @@ -171,7 +171,6 @@ VDECLCB(shim_status_update, (int fldidx, genericptr_t ptr, int chg, int percent, int color, unsigned long *colormasks), "vipiiip", A2P fldidx, P2V ptr, A2P chg, A2P percent, A2P color, P2V colormasks) - #ifdef __EMSCRIPTEN__ /* XXX: calling display_inventory() from shim_update_inventory() causes reentrancy that breaks emscripten Asyncify */ /* this should be fine since according to windows.doc, the only purpose of shim_update_inventory() is to call display_inventory() */ @@ -192,15 +191,16 @@ win_request_info * shim_ctrl_nhwindow( winid window UNUSED, int request UNUSED, - win_request_info *wri UNUSED) { + win_request_info *wri) { return (win_request_info *) 0; } #else /* !__EMSCRIPTEN__ */ -VDECLCB(shim_update_inventory,(int a1 UNUSED) -DECLB(win_request_info *, shim_ctrl_nhwindow, +VDECLCB(shim_player_selection, (void), "v") +VDECLCB(shim_update_inventory,(int a1 UNUSED), "vi", A2P a1) +DECLCB(win_request_info *, shim_ctrl_nhwindow, (winid window, int request, win_request_info *wri), "viip", - A2P window UNUSED, A2P request UNUSED, P2V wri UNUSED) + A2P window, A2P request, P2V wri) #endif /* Interface definition used in windows.c */ From 035cd4377f28e8f8cc742f0a610324e36abe585d Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Mon, 12 May 2025 20:23:43 +0300 Subject: [PATCH 627/791] Snickersnee can hit at a distance once per turn for free Once per turn, Snickersnee can be used to hit at a distance, similar to a polearm, without taking any time. Breaks saves. --- doc/fixes3-7-0.txt | 1 + include/context.h | 1 + include/obj.h | 4 +++- include/patchlevel.h | 2 +- include/seffects.h | 1 + src/apply.c | 31 ++++++++++++++++++++++++++++++- src/wield.c | 2 +- 7 files changed, 38 insertions(+), 4 deletions(-) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index 3a183935f..7aff12fb6 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -1514,6 +1514,7 @@ cursed magic whistle can teleport you to your pet Fire and Frost Brand can be invoked for expert level fireball or cone of cold wielding Trollsbane grants hungerless regeneration hitting with Ogresmasher gives a higher chance of knockback +Snickersnee can hit at a distance once per turn for free Fixes to 3.7.0-x General Problems Exposed Via git Repository diff --git a/include/context.h b/include/context.h index ab9baf3bb..d98ada70e 100644 --- a/include/context.h +++ b/include/context.h @@ -148,6 +148,7 @@ struct context_info { int warnlevel; /* threshold (digit) to warn about unseen mons */ long next_attrib_check; /* next attribute check */ long seer_turn; /* when random clairvoyance will next kick in */ + long snickersnee_turn; /* Snickersnee last used to distance attack */ long stethoscope_seq; /* when a stethoscope was last used; first use * during a move takes no time, second uses move */ boolean travel; /* find way automatically to u.tx,u.ty */ diff --git a/include/obj.h b/include/obj.h index 782f545bf..e23c5f457 100644 --- a/include/obj.h +++ b/include/obj.h @@ -222,10 +222,12 @@ struct obj { (otmp->oclass == WEAPON_CLASS \ && objects[otmp->otyp].oc_skill >= P_SHORT_SWORD \ && objects[otmp->otyp].oc_skill <= P_SABER) +/* Snickersnee is not a polearm, but can hit from distance */ #define is_pole(otmp) \ ((otmp->oclass == WEAPON_CLASS || otmp->oclass == TOOL_CLASS) \ && (objects[otmp->otyp].oc_skill == P_POLEARMS \ - || objects[otmp->otyp].oc_skill == P_LANCE)) + || objects[otmp->otyp].oc_skill == P_LANCE \ + || is_art(otmp, ART_SNICKERSNEE))) #define is_spear(otmp) \ (otmp->oclass == WEAPON_CLASS && objects[otmp->otyp].oc_skill == P_SPEAR) #define is_launcher(otmp) \ diff --git a/include/patchlevel.h b/include/patchlevel.h index 905dff4fe..bfb185ef1 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 123 +#define EDITLEVEL 124 /* * Development status possibilities. diff --git a/include/seffects.h b/include/seffects.h index 91a9153a9..0774209b0 100644 --- a/include/seffects.h +++ b/include/seffects.h @@ -197,6 +197,7 @@ seffect(stone_breaking), seffect(stone_crumbling), seffect(swoosh), + seffect(sword_blade_rings), seffect(thud), seffect(thump), seffect(thunderclap), diff --git a/src/apply.c b/src/apply.c index a9142e75a..61219a716 100644 --- a/src/apply.c +++ b/src/apply.c @@ -33,6 +33,7 @@ staticfn int use_stone(struct obj *); staticfn int set_trap(void); /* occupation callback */ staticfn void display_polearm_positions(boolean); staticfn void calc_pole_range(int *, int *); +staticfn boolean snickersnee_used_dist_attk(struct obj *); staticfn int use_cream_pie(struct obj *); staticfn int jelly_ok(struct obj *); staticfn int use_royal_jelly(struct obj **); @@ -3403,6 +3404,16 @@ could_pole_mon(void) return FALSE; } +/* was Snickersnee used to attack at distance this turn already? */ +staticfn boolean +snickersnee_used_dist_attk(struct obj *obj) +{ + if (obj && obj == uwep && u_wield_art(ART_SNICKERSNEE) + && svc.context.snickersnee_turn == svm.moves) + return TRUE; + return FALSE; +} + /* Distance attacks by pole-weapons */ int use_pole(struct obj *obj, boolean autohit) @@ -3412,6 +3423,7 @@ use_pole(struct obj *obj, boolean autohit) coord cc; struct monst *mtmp; struct monst *hitm = svc.context.polearm.hitmon; + boolean freehit = FALSE; /* Are you allowed to use the pole? */ if (u.uswallow) { @@ -3480,8 +3492,25 @@ use_pole(struct obj *obj, boolean autohit) if (overexertion()) return ECMD_TIME; /* burn nutrition; maybe pass out */ svc.context.polearm.hitmon = mtmp; + + if (snickersnee_used_dist_attk(obj)) { + pline_The("blade doesn't reach there!"); + return ECMD_FAIL; + } + check_caitiff(mtmp); gn.notonhead = (gb.bhitpos.x != mtmp->mx || gb.bhitpos.y != mtmp->my); + + /* Snickersnee allows one free hit from a distance per turn */ + if (obj == uwep && u_wield_art(ART_SNICKERSNEE)) { + freehit = (svm.moves != svc.context.snickersnee_turn); + svc.context.snickersnee_turn = svm.moves; + if (freehit && !Deaf) { + Soundeffect(se_sword_blade_rings, 100); + pline("Shkinng!"); /* /sha-kin!/ */ + } + } + (void) thitmonst(mtmp, uwep); } else if (glyph_is_statue(glyph) /* might be hallucinatory */ && sobj_at(STATUE, gb.bhitpos.x, gb.bhitpos.y)) { @@ -3523,7 +3552,7 @@ use_pole(struct obj *obj, boolean autohit) } } u_wipe_engr(2); /* same as for melee or throwing */ - return ECMD_TIME; + return freehit ? ECMD_OK : ECMD_TIME; } #undef glyph_is_poleable diff --git a/src/wield.c b/src/wield.c index 9aaea38fc..53b0aa94f 100644 --- a/src/wield.c +++ b/src/wield.c @@ -123,7 +123,7 @@ setuwep(struct obj *obj) if (obj) { gu.unweapon = (obj->oclass == WEAPON_CLASS) ? is_launcher(obj) || is_ammo(obj) || is_missile(obj) - || (is_pole(obj) && !u.usteed) + || (is_pole(obj) && !u.usteed && !is_art(obj, ART_SNICKERSNEE)) : !is_weptool(obj) && !is_wet_towel(obj); } else gu.unweapon = TRUE; /* for "bare hands" message */ From 6f1bf6ec69693a14acb72ba3d0a7641bbda79691 Mon Sep 17 00:00:00 2001 From: nhmall Date: Tue, 13 May 2025 19:49:38 -0400 Subject: [PATCH 628/791] update tested versions of Visual Studio 2025-05-13 --- sys/windows/Makefile.nmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sys/windows/Makefile.nmake b/sys/windows/Makefile.nmake index 081586ab5..e19d067d7 100644 --- a/sys/windows/Makefile.nmake +++ b/sys/windows/Makefile.nmake @@ -9,7 +9,7 @@ # # Visual Studio Compilers Tested: # - Microsoft Visual Studio 2019 Community Edition v 16.11.42 -# - Microsoft Visual Studio 2022 Community Edition v 17.13.6 +# - Microsoft Visual Studio 2022 Community Edition v 17.14.0 # #============================================================================== # This is used for building two distinct executables of NetHack: @@ -1177,7 +1177,7 @@ rc=Rc.exe # # Recently tested versions: TESTEDVS2019 = 14.29.30157.0 -TESTEDVS2022 = 14.43.34810.0 +TESTEDVS2022 = 14.44.35207.1 VS2019CUR = $(TESTEDVS2019:.=) VS2022CUR = $(TESTEDVS2022:.=) From 1a0ef41406a5ee506e30306b8f6575b66c975c37 Mon Sep 17 00:00:00 2001 From: nhmall Date: Tue, 13 May 2025 20:02:13 -0400 Subject: [PATCH 629/791] fix a warning invent.c .\invent.c(3668): warning C5287: operands are different enum types 'inv_modes' and 'inv_mode_bits'; use an explicit cast to silence this warning .\invent.c(3669): warning C5287: operands are different enum types 'inv_modes' and 'inv_mode_bits'; use an explicit cast to silence this warning --- src/invent.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/invent.c b/src/invent.c index aa1e0de67..ef5a78dea 100644 --- a/src/invent.c +++ b/src/invent.c @@ -3665,8 +3665,8 @@ display_pickinv( win = WIN_INVEN; menu_behavior = MENU_BEHAVE_PERMINV; prepare_perminvent(win); - show_gold = ((wri_info.fromcore.invmode & InvShowGold) != 0); - inuse_only = ((wri_info.fromcore.invmode & InvInUse) != 0); + show_gold = ((wri_info.fromcore.invmode & (enum inv_modes) InvShowGold) != 0); + inuse_only = ((wri_info.fromcore.invmode & (enum inv_modes) InvInUse) != 0); doing_perm_invent = TRUE; } /* From 68ef0b49c1d18366d16eba8fdc3d562553528f4c Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Wed, 14 May 2025 18:30:55 +0300 Subject: [PATCH 630/791] Split arti_invoke code into smaller functions --- src/artifact.c | 633 +++++++++++++++++++++++++++---------------------- 1 file changed, 347 insertions(+), 286 deletions(-) diff --git a/src/artifact.c b/src/artifact.c index dfb436c3d..cd0c37bdd 100644 --- a/src/artifact.c +++ b/src/artifact.c @@ -27,6 +27,17 @@ staticfn int spec_applies(const struct artifact *, struct monst *) NONNULLARG12; staticfn int invoke_ok(struct obj *); staticfn void nothing_special(struct obj *) NONNULLARG1; +staticfn int invoke_taming(struct obj *) NONNULLARG1; +staticfn int invoke_healing(struct obj *) NONNULLARG1; +staticfn int invoke_energy_boost(struct obj *) NONNULLARG1; +staticfn int invoke_untrap(struct obj *) NONNULLARG1; +staticfn int invoke_charge_obj(struct obj *) NONNULLARG1; +staticfn int invoke_create_portal(struct obj *) NONNULLARG1; +staticfn int invoke_create_ammo(struct obj *) NONNULLARG1; +staticfn int invoke_banish(struct obj *) NONNULLARG1; +staticfn int invoke_fling_poison(struct obj *) NONNULLARG1; +staticfn int invoke_storm_spell(struct obj *) NONNULLARG1; +staticfn int invoke_blinding_ray(struct obj *) NONNULLARG1; staticfn int arti_invoke(struct obj *); staticfn boolean Mb_hit(struct monst * magr, struct monst *mdef, struct obj *, int *, int, boolean, char *); @@ -1750,10 +1761,331 @@ nothing_special(struct obj *obj) You_feel("a surge of power, but nothing seems to happen."); } +staticfn int +invoke_taming(struct obj *obj UNUSED) +{ + struct obj pseudo; + + pseudo = cg.zeroobj; /* neither cursed nor blessed, zero oextra too */ + pseudo.otyp = SCR_TAMING; + (void) seffects(&pseudo); + return ECMD_TIME; +} + +staticfn int +invoke_healing(struct obj *obj) +{ + int healamt = (u.uhpmax + 1 - u.uhp) / 2; + long creamed = (long) u.ucreamed; + + if (Upolyd) + healamt = (u.mhmax + 1 - u.mh) / 2; + if (healamt || Sick || Slimed || Blinded > creamed) + You_feel("better."); + if (healamt || Sick || Slimed || BlindedTimeout > creamed) + You_feel("%sbetter.", + (!healamt && !Sick && !Slimed + /* when healing temporary blindness (aside from + goop covering face), might still be blind + due to PermaBlind or eyeless polymorph; + vary the message in that situation */ + && (HBlinded & ~TIMEOUT) != 0L) ? "slightly " : ""); + else { + nothing_special(obj); + return ECMD_TIME; + } + if (healamt > 0) { + if (Upolyd) + u.mh += healamt; + else + u.uhp += healamt; + } + if (Sick) + make_sick(0L, (char *) 0, FALSE, SICK_ALL); + if (Slimed) + make_slimed(0L, (char *) 0); + if (BlindedTimeout > creamed) + make_blinded(creamed, FALSE); + disp.botl = TRUE; + return ECMD_TIME; +} + +staticfn int +invoke_energy_boost(struct obj *obj) +{ + int epboost = (u.uenmax + 1 - u.uen) / 2; + + if (epboost > 120) + epboost = 120; /* arbitrary */ + else if (epboost < 12) + epboost = u.uenmax - u.uen; + if (epboost) { + u.uen += epboost; + disp.botl = TRUE; + You_feel("re-energized."); + } else { + nothing_special(obj); + return ECMD_TIME; + } + return ECMD_TIME; +} + +staticfn int +invoke_untrap(struct obj *obj) +{ + if (!untrap(TRUE, 0, 0, (struct obj *) 0)) { + obj->age = 0; /* don't charge for changing their mind */ + return ECMD_CANCEL; + } + return ECMD_TIME; +} + +staticfn int +invoke_charge_obj(struct obj *obj) +{ + const struct artifact *oart = get_artifact(obj); + struct obj *otmp = getobj("charge", charge_ok, + GETOBJ_PROMPT | GETOBJ_ALLOWCNT); + boolean b_effect; + + if (!otmp) { + obj->age = 0; + return ECMD_CANCEL; + } + b_effect = (obj->blessed && (oart->role == Role_switch + || oart->role == NON_PM)); + recharge(otmp, b_effect ? 1 : obj->cursed ? -1 : 0); + update_inventory(); + return ECMD_TIME; +} + +staticfn int +invoke_create_portal(struct obj *obj) +{ + int i, num_ok_dungeons, last_ok_dungeon = 0; + d_level newlev; + winid tmpwin = create_nhwindow(NHW_MENU); + anything any; + int clr = NO_COLOR; + + any = cg.zeroany; /* set all bits to zero */ + start_menu(tmpwin, MENU_BEHAVE_STANDARD); + /* use index+1 (can't use 0) as identifier */ + for (i = num_ok_dungeons = 0; i < svn.n_dgns; i++) { + if (!svd.dungeons[i].dunlev_ureached) + continue; + if (i == tutorial_dnum) /* can't portal into tutorial */ + continue; + any.a_int = i + 1; + add_menu(tmpwin, &nul_glyphinfo, &any, 0, 0, + ATR_NONE, clr, + svd.dungeons[i].dname, MENU_ITEMFLAGS_NONE); + num_ok_dungeons++; + last_ok_dungeon = i; + } + end_menu(tmpwin, "Open a portal to which dungeon?"); + if (num_ok_dungeons > 1) { + /* more than one entry; display menu for choices */ + menu_item *selected; + int n; + + n = select_menu(tmpwin, PICK_ONE, &selected); + if (n <= 0) { + destroy_nhwindow(tmpwin); + nothing_special(obj); + return ECMD_TIME; + } + i = selected[0].item.a_int - 1; + free((genericptr_t) selected); + } else + i = last_ok_dungeon; /* also first & only OK dungeon */ + destroy_nhwindow(tmpwin); + + /* + * i is now index into dungeon structure for the new dungeon. + * Find the closest level in the given dungeon, open + * a use-once portal to that dungeon and go there. + * The closest level is either the entry or dunlev_ureached. + */ + newlev.dnum = i; + if (svd.dungeons[i].depth_start >= depth(&u.uz)) + newlev.dlevel = svd.dungeons[i].entry_lev; + else + newlev.dlevel = svd.dungeons[i].dunlev_ureached; + + if (u.uhave.amulet || In_endgame(&u.uz) || In_endgame(&newlev) + || newlev.dnum == u.uz.dnum || !next_to_u()) { + You_feel("very disoriented for a moment."); + } else { + if (!Blind) + You("are surrounded by a shimmering sphere!"); + else + You_feel("weightless for a moment."); + goto_level(&newlev, FALSE, FALSE, FALSE); + } + return ECMD_TIME; +} + +staticfn int +invoke_create_ammo(struct obj *obj) +{ + struct obj *otmp = mksobj(ARROW, TRUE, FALSE); + + if (!otmp) { + nothing_special(obj); + return ECMD_TIME; + } + otmp->blessed = obj->blessed; + otmp->cursed = obj->cursed; + otmp->bknown = obj->bknown; + otmp->oeroded = otmp->oeroded2 = 0; + if (obj->blessed) { + if (otmp->spe < 0) + otmp->spe = 0; + otmp->quan += rnd(10); + } else if (obj->cursed) { + if (otmp->spe > 0) + otmp->spe = 0; + } else + otmp->quan += rnd(5); + otmp->owt = weight(otmp); + otmp = hold_another_object(otmp, "Suddenly %s out.", + aobjnam(otmp, "fall"), (char *) 0); + nhUse(otmp); + return ECMD_TIME; +} + +staticfn int +invoke_banish(struct obj *obj UNUSED) +{ + int nvanished = 0, nstayed = 0; + struct monst *mtmp, *mtmp2; + d_level dest; + + find_hell(&dest); + + for (mtmp = fmon; mtmp; mtmp = mtmp2) { + int chance = 1; + + mtmp2 = mtmp->nmon; + if (DEADMONSTER(mtmp) || !isok(mtmp->mx, mtmp->my)) + continue; + if (!is_demon(mtmp->data) && mtmp->data->mlet != S_IMP) + continue; + if (!couldsee(mtmp->mx, mtmp->my)) + continue; + if (mtmp->data->msound == MS_NEMESIS) + continue; + + if (In_quest(&u.uz) && !svq.quest_status.killed_nemesis) + chance += 10; + if (is_dprince(mtmp->data)) + chance += 2; + if (is_dlord(mtmp->data)) + chance++; + + mtmp->msleeping = mtmp->mtame = mtmp->mpeaceful = 0; + if (chance <= 1 || !rn2(chance)) { + if (!Inhell) { + nvanished++; + /* banish to a random level in Gehennom */ + dest.dlevel = rn2(dunlevs_in_dungeon(&dest)); + migrate_mon(mtmp, ledger_no(&dest), MIGR_RANDOM); + } else { + u_teleport_mon(mtmp, FALSE); + } + } else { + nstayed++; + } + } + + if (nvanished) { + char subject[] = "demons"; + + if (nvanished == 1) + *(eos(subject) - 1) = '\0'; /* remove 's' */ + pline("%s %s %s in a cloud of brimstone!", + nstayed ? ((nvanished > nstayed) + ? "Most of the" + : "Some of the") + : "The", + subject, vtense(subject, "disappear")); + } + return ECMD_TIME; +} + +staticfn int +invoke_fling_poison(struct obj *obj) +{ + if (getdir((char *) 0)) { + int venom = rn2(2) ? BLINDING_VENOM : ACID_VENOM; + struct obj *otmp = mksobj(venom, TRUE, FALSE); + + otmp->spe = 1; /* the poison is yours */ + throwit(otmp, 0L, FALSE, (struct obj *) 0); + } else { + /* no direction picked */ + pline("%s", Never_mind); + obj->age = svm.moves; + return ECMD_CANCEL; + } + return ECMD_TIME; +} + +staticfn int +invoke_storm_spell(struct obj *obj) +{ + const struct artifact *oart = get_artifact(obj); + int storm = oart->inv_prop == SNOWSTORM ? SPE_CONE_OF_COLD : SPE_FIREBALL; + int skill = spell_skilltype(storm); + int expertise = P_SKILL(skill); + + P_SKILL(skill) = P_EXPERT; + (void) spelleffects(storm, FALSE, TRUE); + P_SKILL(skill) = expertise; + return ECMD_TIME; +} + +staticfn int +invoke_blinding_ray(struct obj *obj) +{ + if (getdir((char *) 0)) { + if (u.dx || u.dy) { + do_blinding_ray(obj); + } else if (u.dz) { + /* up or down => light this map spot; litroom() uses + radius 0 for Sunsword, except on Rogue level where + whole room gets lit and corridor spots remain unlit */ + litroom(TRUE, obj); + pline("%s", ((!Blind && levl[u.ux][u.uy].lit + && !levl[u.ux][u.uy].waslit) + ? "It is lit here now." + : nothing_seems_to_happen)); + } else { /* zapyourself() */ + boolean vulnerable = (u.umonnum == PM_GREMLIN); + int damg = obj->blessed ? 15 : !obj->cursed ? 10 : 5; + + if (vulnerable) /* could be fatal if Unchanging */ + (void) lightdamage(obj, TRUE, 2 * damg); + + if (!flashburn((long) (damg + rnd(damg)), FALSE) + && !vulnerable) + pline("%s", nothing_seems_to_happen); + } + } else { + /* no direction picked */ + pline("%s", Never_mind); + obj->age = svm.moves; + return ECMD_CANCEL; + } + return ECMD_TIME; +} + staticfn int arti_invoke(struct obj *obj) { const struct artifact *oart; + int res = ECMD_OK; if (!obj) { impossible("arti_invoke without obj"); @@ -1781,300 +2113,29 @@ arti_invoke(struct obj *obj) obj->age = svm.moves + rnz(100); switch (oart->inv_prop) { - case TAMING: { - struct obj pseudo; - - pseudo = - cg.zeroobj; /* neither cursed nor blessed, zero oextra too */ - pseudo.otyp = SCR_TAMING; - (void) seffects(&pseudo); - break; - } - case HEALING: { - int healamt = (u.uhpmax + 1 - u.uhp) / 2; - long creamed = (long) u.ucreamed; - - if (Upolyd) - healamt = (u.mhmax + 1 - u.mh) / 2; - if (healamt || Sick || Slimed || Blinded > creamed) - You_feel("better."); - if (healamt || Sick || Slimed || BlindedTimeout > creamed) - You_feel("%sbetter.", - (!healamt && !Sick && !Slimed - /* when healing temporary blindness (aside from - goop covering face), might still be blind - due to PermaBlind or eyeless polymorph; - vary the message in that situation */ - && (HBlinded & ~TIMEOUT) != 0L) ? "slightly " : ""); - else { - nothing_special(obj); - return ECMD_TIME; - } - if (healamt > 0) { - if (Upolyd) - u.mh += healamt; - else - u.uhp += healamt; - } - if (Sick) - make_sick(0L, (char *) 0, FALSE, SICK_ALL); - if (Slimed) - make_slimed(0L, (char *) 0); - if (BlindedTimeout > creamed) - make_blinded(creamed, FALSE); - disp.botl = TRUE; - break; - } - case ENERGY_BOOST: { - int epboost = (u.uenmax + 1 - u.uen) / 2; - - if (epboost > 120) - epboost = 120; /* arbitrary */ - else if (epboost < 12) - epboost = u.uenmax - u.uen; - if (epboost) { - u.uen += epboost; - disp.botl = TRUE; - You_feel("re-energized."); - } else { - nothing_special(obj); - return ECMD_TIME; - } - break; - } - case UNTRAP: { - if (!untrap(TRUE, 0, 0, (struct obj *) 0)) { - obj->age = 0; /* don't charge for changing their mind */ - return ECMD_OK; - } - break; - } - case CHARGE_OBJ: { - struct obj *otmp = getobj("charge", charge_ok, - GETOBJ_PROMPT | GETOBJ_ALLOWCNT); - boolean b_effect; - - if (!otmp) { - obj->age = 0; - return ECMD_CANCEL; - } - b_effect = (obj->blessed && (oart->role == Role_switch - || oart->role == NON_PM)); - recharge(otmp, b_effect ? 1 : obj->cursed ? -1 : 0); - update_inventory(); - break; - } - case LEV_TELE: - level_tele(); - break; - case CREATE_PORTAL: { - int i, num_ok_dungeons, last_ok_dungeon = 0; - d_level newlev; - winid tmpwin = create_nhwindow(NHW_MENU); - anything any; - int clr = NO_COLOR; - - any = cg.zeroany; /* set all bits to zero */ - start_menu(tmpwin, MENU_BEHAVE_STANDARD); - /* use index+1 (can't use 0) as identifier */ - for (i = num_ok_dungeons = 0; i < svn.n_dgns; i++) { - if (!svd.dungeons[i].dunlev_ureached) - continue; - if (i == tutorial_dnum) /* can't portal into tutorial */ - continue; - any.a_int = i + 1; - add_menu(tmpwin, &nul_glyphinfo, &any, 0, 0, - ATR_NONE, clr, - svd.dungeons[i].dname, MENU_ITEMFLAGS_NONE); - num_ok_dungeons++; - last_ok_dungeon = i; - } - end_menu(tmpwin, "Open a portal to which dungeon?"); - if (num_ok_dungeons > 1) { - /* more than one entry; display menu for choices */ - menu_item *selected; - int n; - - n = select_menu(tmpwin, PICK_ONE, &selected); - if (n <= 0) { - destroy_nhwindow(tmpwin); - nothing_special(obj); - return ECMD_TIME; - } - i = selected[0].item.a_int - 1; - free((genericptr_t) selected); - } else - i = last_ok_dungeon; /* also first & only OK dungeon */ - destroy_nhwindow(tmpwin); - - /* - * i is now index into dungeon structure for the new dungeon. - * Find the closest level in the given dungeon, open - * a use-once portal to that dungeon and go there. - * The closest level is either the entry or dunlev_ureached. - */ - newlev.dnum = i; - if (svd.dungeons[i].depth_start >= depth(&u.uz)) - newlev.dlevel = svd.dungeons[i].entry_lev; - else - newlev.dlevel = svd.dungeons[i].dunlev_ureached; - - if (u.uhave.amulet || In_endgame(&u.uz) || In_endgame(&newlev) - || newlev.dnum == u.uz.dnum || !next_to_u()) { - You_feel("very disoriented for a moment."); - } else { - if (!Blind) - You("are surrounded by a shimmering sphere!"); - else - You_feel("weightless for a moment."); - goto_level(&newlev, FALSE, FALSE, FALSE); - } - break; - } + case TAMING: res = invoke_taming(obj); break; + case HEALING: res = invoke_healing(obj); break; + case ENERGY_BOOST: res = invoke_energy_boost(obj); break; + case UNTRAP: res = invoke_untrap(obj); break; + case CHARGE_OBJ: res = invoke_charge_obj(obj); break; + case LEV_TELE: level_tele(); res = ECMD_TIME; break; + case CREATE_PORTAL: res = invoke_create_portal(obj); break; case ENLIGHTENING: enlightenment(MAGICENLIGHTENMENT, ENL_GAMEINPROGRESS); + res = ECMD_TIME; break; - case CREATE_AMMO: { - struct obj *otmp = mksobj(ARROW, TRUE, FALSE); - - if (!otmp) { - nothing_special(obj); - return ECMD_TIME; - } - otmp->blessed = obj->blessed; - otmp->cursed = obj->cursed; - otmp->bknown = obj->bknown; - otmp->oeroded = otmp->oeroded2 = 0; - if (obj->blessed) { - if (otmp->spe < 0) - otmp->spe = 0; - otmp->quan += rnd(10); - } else if (obj->cursed) { - if (otmp->spe > 0) - otmp->spe = 0; - } else - otmp->quan += rnd(5); - otmp->owt = weight(otmp); - otmp = hold_another_object(otmp, "Suddenly %s out.", - aobjnam(otmp, "fall"), (char *) 0); - nhUse(otmp); - break; - } - case BANISH: { - int nvanished = 0, nstayed = 0; - struct monst *mtmp, *mtmp2; - d_level dest; - - find_hell(&dest); - - for (mtmp = fmon; mtmp; mtmp = mtmp2) { - int chance = 1; - - mtmp2 = mtmp->nmon; - if (DEADMONSTER(mtmp) || !isok(mtmp->mx, mtmp->my)) - continue; - if (!is_demon(mtmp->data) && mtmp->data->mlet != S_IMP) - continue; - if (!couldsee(mtmp->mx, mtmp->my)) - continue; - if (mtmp->data->msound == MS_NEMESIS) - continue; - - if (In_quest(&u.uz) && !svq.quest_status.killed_nemesis) - chance += 10; - if (is_dprince(mtmp->data)) - chance += 2; - if (is_dlord(mtmp->data)) - chance++; - - mtmp->msleeping = mtmp->mtame = mtmp->mpeaceful = 0; - if (chance <= 1 || !rn2(chance)) { - if (!Inhell) { - nvanished++; - /* banish to a random level in Gehennom */ - dest.dlevel = rn2(dunlevs_in_dungeon(&dest)); - migrate_mon(mtmp, ledger_no(&dest), MIGR_RANDOM); - } else { - u_teleport_mon(mtmp, FALSE); - } - } else { - nstayed++; - } - } - - if (nvanished) { - char subject[] = "demons"; - - if (nvanished == 1) - *(eos(subject) - 1) = '\0'; /* remove 's' */ - pline("%s %s %s in a cloud of brimstone!", - nstayed ? ((nvanished > nstayed) - ? "Most of the" - : "Some of the") - : "The", - subject, vtense(subject, "disappear")); - } - break; - } - case FLING_POISON: - if (getdir((char *) 0)) { - int venom = rn2(2) ? BLINDING_VENOM : ACID_VENOM; - struct obj *otmp = mksobj(venom, TRUE, FALSE); - - otmp->spe = 1; /* the poison is yours */ - throwit(otmp, 0L, FALSE, (struct obj *) 0); - } else { - /* no direction picked */ - pline("%s", Never_mind); - obj->age = svm.moves; - } - break; + case CREATE_AMMO: res = invoke_create_ammo(obj); break; + case BANISH: res = invoke_banish(obj); break; + case FLING_POISON: res = invoke_fling_poison(obj); break; case SNOWSTORM: - case FIRESTORM: - { - int storm = oart->inv_prop == SNOWSTORM ? SPE_CONE_OF_COLD : SPE_FIREBALL; - int skill = spell_skilltype(storm); - int expertise = P_SKILL(skill); - - P_SKILL(skill) = P_EXPERT; - (void) spelleffects(storm, FALSE, TRUE); - P_SKILL(skill) = expertise; - } - break; - case BLINDING_RAY: - if (getdir((char *) 0)) { - if (u.dx || u.dy) { - do_blinding_ray(obj); - } else if (u.dz) { - /* up or down => light this map spot; litroom() uses - radius 0 for Sunsword, except on Rogue level where - whole room gets lit and corridor spots remain unlit */ - litroom(TRUE, obj); - pline("%s", ((!Blind && levl[u.ux][u.uy].lit - && !levl[u.ux][u.uy].waslit) - ? "It is lit here now." - : nothing_seems_to_happen)); - } else { /* zapyourself() */ - boolean vulnerable = (u.umonnum == PM_GREMLIN); - int damg = obj->blessed ? 15 : !obj->cursed ? 10 : 5; - - if (vulnerable) /* could be fatal if Unchanging */ - (void) lightdamage(obj, TRUE, 2 * damg); - - if (!flashburn((long) (damg + rnd(damg)), FALSE) - && !vulnerable) - pline("%s", nothing_seems_to_happen); - } - } else { - /* no direction picked */ - pline("%s", Never_mind); - obj->age = svm.moves; - } - break; + /*FALLTHRU*/ + case FIRESTORM: res = invoke_storm_spell(obj); break; + case BLINDING_RAY: res = invoke_blinding_ray(obj); break; default: impossible("Unknown invoke power %d.", oart->inv_prop); break; } + return res; } else { long eprop = (u.uprops[oart->inv_prop].extrinsic ^= W_ARTI), iprop = u.uprops[oart->inv_prop].intrinsic; From ab4f70b4482539e40dcfe7e5a9cf5f87c7e481d6 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Tue, 20 May 2025 19:59:25 +0300 Subject: [PATCH 631/791] Monsters were bashing with Snickersnee Side effect of allowing Snickersnee to attack like a polearm, monsters were bashing with it in melee. --- src/mhitm.c | 2 +- src/mhitu.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mhitm.c b/src/mhitm.c index 1380148ed..8892c0f59 100644 --- a/src/mhitm.c +++ b/src/mhitm.c @@ -1273,7 +1273,7 @@ mswingsm( struct obj *otemp) /* attacker's weapon */ { if (flags.verbose && !Blind && mon_visible(magr)) { - boolean bash = (is_pole(otemp) + boolean bash = (is_pole(otemp) && !is_art(otemp, ART_SNICKERSNEE) && (dist2(magr->mx, magr->my, mdef->mx, mdef->my) <= 2)); diff --git a/src/mhitu.c b/src/mhitu.c index 363c19cd4..ed0b6e098 100644 --- a/src/mhitu.c +++ b/src/mhitu.c @@ -872,6 +872,7 @@ mattacku(struct monst *mtmp) mon_currwep = MON_WEP(mtmp); if (mon_currwep) { boolean bash = (is_pole(mon_currwep) + && !is_art(mon_currwep, ART_SNICKERSNEE) && m_next2u(mtmp)); hittmp = hitval(mon_currwep, &gy.youmonst); From a4b971c7445d9810fd4a64a4d1cb0b724bdd151e Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Tue, 20 May 2025 20:06:28 +0300 Subject: [PATCH 632/791] Allow monsters to use Snickersnee like a polearm --- src/weapon.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/weapon.c b/src/weapon.c index 1966f5fce..59fa7c30d 100644 --- a/src/weapon.c +++ b/src/weapon.c @@ -558,6 +558,11 @@ select_rwep(struct monst *mtmp) mweponly = (mwelded(mwep) && mtmp->weapon_check == NO_WEAPON_WANTED); if (dist2(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy) <= 13 && couldsee(mtmp->mx, mtmp->my)) { + if (is_art(mwep, ART_SNICKERSNEE)) { + gp.propellor = mwep; + return mwep; + } + for (i = 0; i < SIZE(pwep); i++) { /* Only strong monsters can wield big (esp. long) weapons. * Big weapon is basically the same as bimanual. From 78a4fd2fb818987e3a9d9725e5b870868a9fc1b8 Mon Sep 17 00:00:00 2001 From: nhmall Date: Wed, 21 May 2025 23:58:01 -0400 Subject: [PATCH 633/791] split config file processing into its own src file --- include/decl.h | 2 +- include/extern.h | 37 +- src/cfgfiles.c | 1859 ++++++++++++++++++++ src/files.c | 1848 +------------------ src/options.c | 12 +- sys/msdos/Makefile.GCC | 50 +- sys/unix/Makefile.src | 3 +- sys/unix/NetHack.xcodeproj/project.pbxproj | 4 + sys/vms/Makefile.src | 11 +- sys/vms/Makefile_src.vms | 1 + sys/windows/GNUmakefile | 2 +- sys/windows/Makefile.nmake | 114 +- sys/windows/vs/NetHack/NetHack.vcxproj | 1 + sys/windows/vs/NetHackW/NetHackW.vcxproj | 1 + 14 files changed, 1993 insertions(+), 1952 deletions(-) create mode 100644 src/cfgfiles.c diff --git a/include/decl.h b/include/decl.h index b201816f3..db9042445 100644 --- a/include/decl.h +++ b/include/decl.h @@ -258,7 +258,7 @@ struct instance_globals_c { /* symbols.c */ int currentgraphics; - /* files.c */ + /* files.c, cfgfiles.c */ char *cmdline_rcfile; /* set in unixmain.c, used in options.c */ char *config_section_chosen; char *config_section_current; diff --git a/include/extern.h b/include/extern.h index 5886eb0c0..d4f1e549d 100644 --- a/include/extern.h +++ b/include/extern.h @@ -310,6 +310,28 @@ extern boolean friday_13th(void); extern int night(void); extern int midnight(void); +/* ### cfgfiles.c ### */ + +#if !defined(CROSSCOMPILE) || defined(CROSSCOMPILE_TARGET) +extern int l_get_config_errors(lua_State *) NONNULLARG1; +#endif +extern int do_write_config_file(void); +extern boolean parse_config_line(char *) NONNULLARG1; +#ifdef USER_SOUNDS +extern boolean can_read_file(const char *) NONNULLARG1; +#endif +extern void config_error_init(boolean, const char *, boolean); +extern void config_erradd(const char *); +extern int config_error_done(void); +/* arg1 of read_config_file can be NULL to pass through + * to fopen_config_file() to mean 'use the default config file name' */ +extern boolean read_config_file(const char *, int); +extern boolean parse_conf_str(const char *str, boolean (*proc)(char *)); +extern boolean parse_conf_file(FILE *fp, boolean (*proc)(char *arg)); +extern void set_configfile_name(const char *); +extern char *get_configfile(void); +extern const char *get_default_configfile(void); + /* ### coloratt.c ### */ extern char *color_attr_to_str(color_attr *); @@ -1009,9 +1031,6 @@ extern void makerogueghost(void); /* ### files.c ### */ extern const char *nh_basename(const char *, boolean) NONNULLARG1; -#if !defined(CROSSCOMPILE) || defined(CROSSCOMPILE_TARGET) -extern int l_get_config_errors(lua_State *) NONNULLARG1; -#endif extern char *fname_encode(const char *, char, char *, char *, int) NONNULLPTRS; extern char *fname_decode(char, char *, char *, int) NONNULLPTRS; @@ -1051,20 +1070,8 @@ extern void nh_compress(const char *); extern void nh_uncompress(const char *); extern boolean lock_file(const char *, int, int) NONNULLARG1; extern void unlock_file(const char *) NONNULLARG1; -extern int do_write_config_file(void); -extern boolean parse_config_line(char *) NONNULLARG1; -#ifdef USER_SOUNDS -extern boolean can_read_file(const char *) NONNULLARG1; -#endif -extern void config_error_init(boolean, const char *, boolean); -extern void config_erradd(const char *); -extern int config_error_done(void); -/* arg1 of read_config_file can be NULL to pass through - * to fopen_config_file() to mean 'use the default config file name' */ -extern boolean read_config_file(const char *, int); extern void check_recordfile(const char *); extern void read_wizkit(void); -extern boolean parse_conf_str(const char *str, boolean (*proc)(char *)); extern int read_sym_file(int); extern void paniclog(const char *, const char *) NONNULLPTRS; extern void testinglog(const char *, const char *, const char *); diff --git a/src/cfgfiles.c b/src/cfgfiles.c new file mode 100644 index 000000000..bf48bf9f6 --- /dev/null +++ b/src/cfgfiles.c @@ -0,0 +1,1859 @@ +/* NetHack 3.7 cfgfiles.c $NHDT-Date: 1740532826 2025/02/25 17:20:26 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.417 $ */ +/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ +/*-Copyright (c) Derek S. Ray, 2015. */ +/* NetHack may be freely redistributed. See license for details. */ + +#define NEED_VARARGS + +#include "hack.h" +#include "dlb.h" +#include + +#ifdef USER_SOUNDS +extern char *sounddir; /* defined in sounds.c */ +#endif + +staticfn FILE *fopen_config_file(const char *, int); +staticfn int get_uchars(char *, uchar *, boolean, int, const char *); +#ifdef NOCWD_ASSUMPTIONS +staticfn void adjust_prefix(char *, int); +#endif +staticfn char *choose_random_part(char *, char); +staticfn boolean config_error_nextline(const char *); +staticfn void free_config_sections(void); +staticfn char *is_config_section(char *); +staticfn boolean handle_config_section(char *); +boolean parse_config_line(char *); +staticfn char *find_optparam(const char *); +staticfn boolean cnf_line_OPTIONS(char *); +staticfn boolean cnf_line_AUTOPICKUP_EXCEPTION(char *); +staticfn boolean cnf_line_BINDINGS(char *); +staticfn boolean cnf_line_AUTOCOMPLETE(char *); +staticfn boolean cnf_line_MSGTYPE(char *); +staticfn boolean cnf_line_HACKDIR(char *); +staticfn boolean cnf_line_LEVELDIR(char *); +staticfn boolean cnf_line_SAVEDIR(char *); +staticfn boolean cnf_line_BONESDIR(char *); +staticfn boolean cnf_line_DATADIR(char *); +staticfn boolean cnf_line_SCOREDIR(char *); +staticfn boolean cnf_line_LOCKDIR(char *); +staticfn boolean cnf_line_CONFIGDIR(char *); +staticfn boolean cnf_line_TROUBLEDIR(char *); +staticfn boolean cnf_line_NAME(char *); +staticfn boolean cnf_line_ROLE(char *); +staticfn boolean cnf_line_dogname(char *); +staticfn boolean cnf_line_catname(char *); +#ifdef SYSCF +staticfn boolean cnf_line_WIZARDS(char *); +staticfn boolean cnf_line_SHELLERS(char *); +staticfn boolean cnf_line_MSGHANDLER(char *); +staticfn boolean cnf_line_EXPLORERS(char *); +staticfn boolean cnf_line_DEBUGFILES(char *); +staticfn boolean cnf_line_DUMPLOGFILE(char *); +staticfn boolean cnf_line_GENERICUSERS(char *); +staticfn boolean cnf_line_BONES_POOLS(char *); +staticfn boolean cnf_line_SUPPORT(char *); +staticfn boolean cnf_line_RECOVER(char *); +staticfn boolean cnf_line_CHECK_SAVE_UID(char *); +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_PERSMAX(char *); +staticfn boolean cnf_line_PERS_IS_UID(char *); +staticfn boolean cnf_line_ENTRYMAX(char *); +staticfn boolean cnf_line_POINTSMIN(char *); +staticfn boolean cnf_line_MAX_STATUENAME_RANK(char *); +staticfn boolean cnf_line_LIVELOG(char *); +staticfn boolean cnf_line_PANICTRACE_LIBC(char *); +staticfn boolean cnf_line_PANICTRACE_GDB(char *); +staticfn boolean cnf_line_GDBPATH(char *); +staticfn boolean cnf_line_GREPPATH(char *); +staticfn boolean cnf_line_CRASHREPORTURL(char *); +staticfn boolean cnf_line_SAVEFORMAT(char *); +staticfn boolean cnf_line_BONESFORMAT(char *); +staticfn boolean cnf_line_ACCESSIBILITY(char *); +staticfn boolean cnf_line_PORTABLE_DEVICE_PATHS(char *); +staticfn void parseformat(int *, char *); +#endif /* SYSCF */ +staticfn boolean cnf_line_BOULDER(char *); +staticfn boolean cnf_line_MENUCOLOR(char *); +staticfn boolean cnf_line_HILITE_STATUS(char *); +staticfn boolean cnf_line_WARNINGS(char *); +staticfn boolean cnf_line_ROGUESYMBOLS(char *); +staticfn boolean cnf_line_SYMBOLS(char *); +staticfn boolean cnf_line_WIZKIT(char *); +#ifdef USER_SOUNDS +staticfn boolean cnf_line_SOUNDDIR(char *); +staticfn boolean cnf_line_SOUND(char *); +#endif +staticfn boolean cnf_line_QT_TILEWIDTH(char *); +staticfn boolean cnf_line_QT_TILEHEIGHT(char *); +staticfn boolean cnf_line_QT_FONTSIZE(char *); +staticfn boolean cnf_line_QT_COMPACT(char *); +struct _cnf_parser_state; /* defined below (far below...) */ +staticfn void cnf_parser_init(struct _cnf_parser_state *parser); +staticfn void cnf_parser_done(struct _cnf_parser_state *parser); +staticfn void parse_conf_buf(struct _cnf_parser_state *parser, + boolean (*proc)(char *arg)); +/* next one is in extern.h; why here too? */ +boolean parse_conf_str(const char *str, boolean (*proc)(char *arg)); + +/* ---------- BEGIN CONFIG FILE HANDLING ----------- */ + +/* used for messaging. Also used in options.c */ +static const char *default_configfile = +#ifdef UNIX + ".nethackrc"; +#else +#if defined(MAC) || defined(__BEOS__) + "NetHack Defaults"; +#else +#if defined(MSDOS) || defined(WIN32) + CONFIG_FILE; +#else + "NetHack.cnf"; +#endif +#endif +#endif +static char configfile[BUFSZ]; + +char * +get_configfile(void) +{ + return configfile; +} + +const char * +get_default_configfile(void) +{ + return default_configfile; +} + +#ifdef MSDOS +/* conflict with speed-dial under windows + * for XXX.cnf file so support of NetHack.cnf + * is for backward compatibility only. + * Preferred name (and first tried) is now defaults.nh but + * the game will try the old name if there + * is no defaults.nh. + */ +const char *backward_compat_configfile = "nethack.cnf"; +#endif + +/* #saveoptions - save config options into file */ +int +do_write_config_file(void) +{ + FILE *fp; + char tmp[BUFSZ]; + + if (!configfile[0]) { + pline("Strange, could not figure out config file name."); + return ECMD_OK; + } + if (flags.suppress_alert < FEATURE_NOTICE_VER(3,7,0)) { + pline("Warning: saveoptions is highly experimental!"); + wait_synch(); + pline("Some settings are not saved!"); + wait_synch(); + pline("All manual customization and comments are removed" + " from the file!"); + wait_synch(); + } +#define overwrite_prompt "Overwrite config file %.*s?" + Sprintf(tmp, overwrite_prompt, + (int) (BUFSZ - sizeof overwrite_prompt - 2), configfile); +#undef overwrite_prompt + if (!paranoid_query(TRUE, tmp)) + return ECMD_OK; + + fp = fopen(configfile, "w"); + if (fp) { + size_t len, wrote; + strbuf_t buf; + + strbuf_init(&buf); + all_options_strbuf(&buf); + len = strlen(buf.str); + wrote = fwrite(buf.str, 1, len, fp); + fclose(fp); + strbuf_empty(&buf); + if (wrote != len) + pline("An error occurred, wrote only partial data (%zu/%zu).", + wrote, len); + } + return ECMD_OK; +} + +/* remember the name of the file we're accessing; + if may be used in option reject messages */ +void +set_configfile_name(const char *fname) +{ + (void) strncpy(configfile, fname, sizeof configfile - 1); + configfile[sizeof configfile - 1] = '\0'; +} + +staticfn FILE * +fopen_config_file(const char *filename, int src) +{ + FILE *fp; +#if defined(UNIX) || defined(VMS) + char tmp_config[BUFSZ]; + char *envp; +#endif + + if (src == set_in_sysconf) { + /* SYSCF_FILE; if we can't open it, caller will bail */ + if (filename && *filename) { + set_configfile_name(fqname(filename, SYSCONFPREFIX, 0)); + fp = fopen(configfile, "r"); + } else + fp = (FILE *) 0; + return fp; + } + /* If src != set_in_sysconf, "filename" is an environment variable, so it + * should hang around. If set, it is expected to be a full path name + * (if relevant) + */ + if (filename && *filename) { + set_configfile_name(filename); +#ifdef UNIX + if (access(configfile, 4) == -1) { /* 4 is R_OK on newer systems */ + /* nasty sneaky attempt to read file through + * NetHack's setuid permissions -- this is the only + * place a file name may be wholly under the player's + * control (but SYSCF_FILE is not under the player's + * control so it's OK). + */ + raw_printf("Access to %s denied (%d).", configfile, errno); + wait_synch(); + /* fall through to standard names */ + } else +#endif + if ((fp = fopen(configfile, "r")) != (FILE *) 0) { + return fp; +#if defined(UNIX) || defined(VMS) + } else { + /* access() above probably caught most problems for UNIX */ + raw_printf("Couldn't open requested config file %s (%d).", + configfile, errno); + wait_synch(); +#endif + } + } + /* fall through to standard names */ + +#if defined(MICRO) || defined(MAC) || defined(__BEOS__) || defined(WIN32) + set_configfile_name(fqname(default_configfile, CONFIGPREFIX, 0)); + if ((fp = fopen(configfile, "r")) != (FILE *) 0) { + return fp; + } else if (strcmp(default_configfile, configfile)) { + set_configfile_name(default_configfile); + if ((fp = fopen(configfile, "r")) != (FILE *) 0) + return fp; + } +#ifdef MSDOS + set_configfile_name(fqname(backward_compat_configfile, CONFIGPREFIX, 0)); + if ((fp = fopen(configfile, "r")) != (FILE *) 0) { + return fp; + } else if (strcmp(backward_compat_configfile, configfile)) { + set_configfile_name(backward_compat_configfile); + if ((fp = fopen(configfile, "r")) != (FILE *) 0) + return fp; + } +#endif +#else +/* constructed full path names don't need fqname() */ +#ifdef VMS + /* no punctuation, so might be a logical name */ + set_configfile_name("nethackini"); + if ((fp = fopen(configfile, "r")) != (FILE *) 0) + return fp; + set_configfile_name("sys$login:nethack.ini"); + if ((fp = fopen(configfile, "r")) != (FILE *) 0) + return fp; + + envp = nh_getenv("HOME"); + if (!envp || !*envp) + Strcpy(tmp_config, "NetHack.cnf"); + else + Sprintf(tmp_config, "%s%s%s", envp, + !strchr(":]>/", envp[strlen(envp) - 1]) ? "/" : "", + "NetHack.cnf"); + set_configfile_name(tmp_config); + if ((fp = fopen(configfile, "r")) != (FILE *) 0) + return fp; +#else /* should be only UNIX left */ + envp = nh_getenv("HOME"); + if (!envp) + Strcpy(tmp_config, ".nethackrc"); + else + Sprintf(tmp_config, "%s/%s", envp, ".nethackrc"); + + set_configfile_name(tmp_config); + if ((fp = fopen(configfile, "r")) != (FILE *) 0) + return fp; +#if defined(__APPLE__) /* UNIX+__APPLE__ => OSX || MacOS */ + /* try an alternative */ + if (envp) { + /* keep 'tmp_config' intact here; if alternates fail, use it to + restore configfile[] to its preferred setting (".nethackrc") */ + char alt_config[sizeof tmp_config]; + + /* OSX-style configuration settings */ + Snprintf(alt_config, sizeof alt_config, "%s/%s", envp, + "Library/Preferences/NetHack Defaults"); + set_configfile_name(alt_config); + if ((fp = fopen(configfile, "r")) != (FILE *) 0) + return fp; + /* may be easier for user to edit if filename has '.txt' suffix */ + Snprintf(alt_config, sizeof alt_config, "%s/%s", envp, + "Library/Preferences/NetHack Defaults.txt"); + set_configfile_name(alt_config); + if ((fp = fopen(configfile, "r")) != (FILE *) 0) + return fp; + /* couldn't open either of the alternate names; for use in + messages, put 'configfile' back to the normal value rather than + leaving it set to last alternate; retry open() to reset 'errno' */ + set_configfile_name(tmp_config); + if ((fp = fopen(configfile, "r")) != (FILE *) 0) + return fp; + } +#endif /*__APPLE__*/ + if (errno != ENOENT) { + const char *details; + + /* e.g., problems when setuid NetHack can't search home + directory restricted to user */ +#if defined(NHSTDC) && !defined(NOTSTDC) + if ((details = strerror(errno)) == 0) +#endif + details = ""; + raw_printf("Couldn't open default config file %s %s(%d).", + configfile, details, errno); + wait_synch(); + } +#endif /* !VMS => Unix */ +#endif /* !(MICRO || MAC || __BEOS__ || WIN32) */ + return (FILE *) 0; +} + +/* + * Retrieve a list of integers from buf into a uchar array. + * + * NOTE: zeros are inserted unless modlist is TRUE, in which case the list + * location is unchanged. Callers must handle zeros if modlist is FALSE. + */ +staticfn int +get_uchars(char *bufp, /* current pointer */ + uchar *list, /* return list */ + boolean modlist, /* TRUE: list is being modified in place */ + int size, /* return list size */ + const char *name) /* name of option for error message */ +{ + unsigned int num = 0; + int count = 0; + boolean havenum = FALSE; + + while (1) { + switch (*bufp) { + case ' ': + case '\0': + case '\t': + case '\n': + if (havenum) { + /* if modifying in place, don't insert zeros */ + if (num || !modlist) + list[count] = num; + count++; + num = 0; + havenum = FALSE; + } + if (count == size || !*bufp) + return count; + bufp++; + break; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + havenum = TRUE; + num = num * 10 + (*bufp - '0'); + bufp++; + break; + + case '\\': + goto gi_error; + break; + + default: + gi_error: + raw_printf("Syntax error in %s", name); + wait_synch(); + return count; + } + } + /*NOTREACHED*/ +} + +#ifdef NOCWD_ASSUMPTIONS +staticfn void +adjust_prefix(char *bufp, int prefixid) +{ + char *ptr; + + if (!bufp) + return; +#ifdef WIN32 + if (fqn_prefix_locked[prefixid]) + return; +#endif + /* Backward compatibility, ignore trailing ;n */ + if ((ptr = strchr(bufp, ';')) != 0) + *ptr = '\0'; + if (strlen(bufp) > 0) { + gf.fqn_prefix[prefixid] = (char *) alloc(strlen(bufp) + 2); + Strcpy(gf.fqn_prefix[prefixid], bufp); + append_slash(gf.fqn_prefix[prefixid]); + } +} +#endif + +/* Choose at random one of the sep separated parts from str. Mangles str. */ +staticfn char * +choose_random_part(char *str, char sep) +{ + int nsep = 1; + int csep; + int len = 0; + char *begin = str; + + if (!str) + return (char *) 0; + + while (*str) { + if (*str == sep) + nsep++; + str++; + } + csep = rn2(nsep); + str = begin; + while ((csep > 0) && *str) { + str++; + if (*str == sep) + csep--; + } + if (*str) { + if (*str == sep) + str++; + begin = str; + while (*str && *str != sep) { + str++; + len++; + } + *str = '\0'; + if (len) + return begin; + } + return (char *) 0; +} + +staticfn void +free_config_sections(void) +{ + if (gc.config_section_chosen) { + free(gc.config_section_chosen); + gc.config_section_chosen = NULL; + } + if (gc.config_section_current) { + free(gc.config_section_current); + gc.config_section_current = NULL; + } +} + +/* check for " [ anything-except-bracket-or-empty ] # arbitrary-comment" + with spaces optional; returns pointer to "anything-except..." (with + trailing " ] #..." stripped) if ok, otherwise Null */ +staticfn char * +is_config_section( + char *str) /* trailing spaces are stripped, ']' too iff result is good */ +{ + char *a, *c, *z; + + /* remove any spaces at start and end; won't significantly interfere + with echoing the string in a config error message, if warranted */ + a = trimspaces(str); + /* first character should be open square bracket; set pointer past it */ + if (*a++ != '[') + return (char *) 0; + /* last character should be close bracket, ignoring any comment */ + z = strchr(a, ']'); + if (!z) + return (char *) 0; + /* comment, if present, can be preceded by spaces */ + for (c = z + 1; *c == ' '; ++c) + continue; + if (*c && *c != '#') + return (char *) 0; + /* we now know that result is good; there won't be a config error + message so we can modify the input string */ + *z = '\0'; + /* 'a' points past '[' and the string ends where ']' was; remove any + spaces between '[' and choice-start and between choice-end and ']' */ + return trimspaces(a); +} + +staticfn boolean +handle_config_section(char *buf) +{ + char *sect = is_config_section(buf); + + if (sect) { + if (gc.config_section_current) + free(gc.config_section_current), gc.config_section_current = 0; + /* is_config_section() removed brackets from 'sect' */ + if (!gc.config_section_chosen) { + config_error_add("Section \"[%s]\" without CHOOSE", sect); + return TRUE; + } + if (*sect) { /* got a section name */ + gc.config_section_current = dupstr(sect); + debugpline1("set config section: '%s'", + gc.config_section_current); + } else { /* empty section name => end of sections */ + free_config_sections(); + debugpline0("unset config section"); + } + return TRUE; + } + + if (gc.config_section_current) { + if (!gc.config_section_chosen) + return TRUE; + if (strcmp(gc.config_section_current, gc.config_section_chosen)) + return TRUE; + } + return FALSE; +} + +#define match_varname(INP, NAM, LEN) match_optname(INP, NAM, LEN, TRUE) + +/* find the '=' or ':' */ +staticfn char * +find_optparam(const char *buf) +{ + char *bufp, *altp; + + bufp = strchr(buf, '='); + altp = strchr(buf, ':'); + if (!bufp || (altp && altp < bufp)) + bufp = altp; + + return bufp; +} + +staticfn boolean +cnf_line_OPTIONS(char *origbuf) +{ + char *bufp = find_optparam(origbuf); + + ++bufp; /* skip '='; parseoptions() handles spaces */ + return parseoptions(bufp, TRUE, TRUE); +} + +staticfn boolean +cnf_line_AUTOPICKUP_EXCEPTION(char *bufp) +{ + add_autopickup_exception(bufp); + return TRUE; +} + +staticfn boolean +cnf_line_BINDINGS(char *bufp) +{ + return parsebindings(bufp); +} + +staticfn boolean +cnf_line_AUTOCOMPLETE(char *bufp) +{ + parseautocomplete(bufp, TRUE); + return TRUE; +} + +staticfn boolean +cnf_line_MSGTYPE(char *bufp) +{ + return msgtype_parse_add(bufp); +} + +staticfn boolean +cnf_line_HACKDIR(char *bufp) +{ +#ifdef NOCWD_ASSUMPTIONS + adjust_prefix(bufp, HACKPREFIX); +#else /*NOCWD_ASSUMPTIONS*/ +#ifdef MICRO + (void) strncpy(gh.hackdir, bufp, PATHLEN - 1); +#else /* MICRO */ + nhUse(bufp); +#endif /* MICRO */ +#endif /*NOCWD_ASSUMPTIONS*/ + return TRUE; +} + +staticfn boolean +cnf_line_LEVELDIR(char *bufp) +{ +#ifdef NOCWD_ASSUMPTIONS + adjust_prefix(bufp, LEVELPREFIX); +#else /*NOCWD_ASSUMPTIONS*/ +#ifdef MICRO + if (strlen(bufp) >= PATHLEN) + bufp[PATHLEN - 1] = '\0'; + Strcpy(g.permbones, bufp); + if (!ramdisk_specified || !*levels) + Strcpy(levels, bufp); + gr.ramdisk = (strcmp(g.permbones, levels) != 0); +#else /* MICRO */ + nhUse(bufp); +#endif /* MICRO */ +#endif /*NOCWD_ASSUMPTIONS*/ + return TRUE; +} + +staticfn boolean +cnf_line_SAVEDIR(char *bufp) +{ +#ifdef NOCWD_ASSUMPTIONS + adjust_prefix(bufp, SAVEPREFIX); +#else /*NOCWD_ASSUMPTIONS*/ +#ifdef MICRO + char *ptr; + + if ((ptr = strchr(bufp, ';')) != 0) { + *ptr = '\0'; + } + + (void) strncpy(gs.SAVEP, bufp, SAVESIZE - 1); + append_slash(gs.SAVEP); +#else /* MICRO */ + nhUse(bufp); +#endif /* MICRO */ +#endif /*NOCWD_ASSUMPTIONS*/ + return TRUE; +} + +staticfn boolean +cnf_line_BONESDIR(char *bufp) +{ +#ifdef NOCWD_ASSUMPTIONS + adjust_prefix(bufp, BONESPREFIX); +#else + nhUse(bufp); +#endif + return TRUE; +} + +staticfn boolean +cnf_line_DATADIR(char *bufp) +{ +#ifdef NOCWD_ASSUMPTIONS + adjust_prefix(bufp, DATAPREFIX); +#else + nhUse(bufp); +#endif + return TRUE; +} + +staticfn boolean +cnf_line_SCOREDIR(char *bufp) +{ +#ifdef NOCWD_ASSUMPTIONS + adjust_prefix(bufp, SCOREPREFIX); +#else + nhUse(bufp); +#endif + return TRUE; +} + +staticfn boolean +cnf_line_LOCKDIR(char *bufp) +{ +#ifdef NOCWD_ASSUMPTIONS + adjust_prefix(bufp, LOCKPREFIX); +#else + nhUse(bufp); +#endif + return TRUE; +} + +staticfn boolean +cnf_line_CONFIGDIR(char *bufp) +{ +#ifdef NOCWD_ASSUMPTIONS + adjust_prefix(bufp, CONFIGPREFIX); +#else + nhUse(bufp); +#endif + return TRUE; +} + +staticfn boolean +cnf_line_TROUBLEDIR(char *bufp) +{ +#ifdef NOCWD_ASSUMPTIONS + adjust_prefix(bufp, TROUBLEPREFIX); +#else + nhUse(bufp); +#endif + return TRUE; +} + +staticfn boolean +cnf_line_NAME(char *bufp) +{ + (void) strncpy(svp.plname, bufp, PL_NSIZ - 1); + return TRUE; +} + +staticfn boolean +cnf_line_ROLE(char *bufp) +{ + int len; + + if ((len = str2role(bufp)) >= 0) + flags.initrole = len; + return TRUE; +} + +staticfn boolean +cnf_line_dogname(char *bufp) +{ + (void) strncpy(gd.dogname, bufp, PL_PSIZ - 1); + return TRUE; +} + +staticfn boolean +cnf_line_catname(char *bufp) +{ + (void) strncpy(gc.catname, bufp, PL_PSIZ - 1); + return TRUE; +} + +#ifdef SYSCF + +staticfn boolean +cnf_line_WIZARDS(char *bufp) +{ + if (sysopt.wizards) + free((genericptr_t) sysopt.wizards); + sysopt.wizards = dupstr(bufp); + if (strlen(sysopt.wizards) && strcmp(sysopt.wizards, "*")) { + /* pre-format WIZARDS list now; it's displayed during a panic + and since that panic might be due to running out of memory, + we don't want to risk attempting to allocate any memory then */ + if (sysopt.fmtd_wizard_list) + free((genericptr_t) sysopt.fmtd_wizard_list); + sysopt.fmtd_wizard_list = build_english_list(sysopt.wizards); + } + return TRUE; +} + +staticfn boolean +cnf_line_SHELLERS(char *bufp) +{ + if (sysopt.shellers) + free((genericptr_t) sysopt.shellers); + sysopt.shellers = dupstr(bufp); + return TRUE; +} + +staticfn boolean +cnf_line_MSGHANDLER(char *bufp) +{ + if (sysopt.msghandler) + free((genericptr_t) sysopt.msghandler); + sysopt.msghandler = dupstr(bufp); + return TRUE; +} + +staticfn boolean +cnf_line_EXPLORERS(char *bufp) +{ + if (sysopt.explorers) + free((genericptr_t) sysopt.explorers); + sysopt.explorers = dupstr(bufp); + return TRUE; +} + +staticfn boolean +cnf_line_DEBUGFILES(char *bufp) +{ + /* might already have a vaule from getenv("DEBUGFILES"); + if so, ignore this value from SYSCF */ + if (!sysopt.env_dbgfl) { + if (sysopt.debugfiles) + free((genericptr_t) sysopt.debugfiles); + sysopt.debugfiles = dupstr(bufp); + } + return TRUE; +} + +staticfn boolean +cnf_line_DUMPLOGFILE(char *bufp) +{ +#ifdef DUMPLOG + if (sysopt.dumplogfile) + free((genericptr_t) sysopt.dumplogfile); + sysopt.dumplogfile = dupstr(bufp); +#else + nhUse(bufp); +#endif /*DUMPLOG*/ + return TRUE; +} + +staticfn boolean +cnf_line_GENERICUSERS(char *bufp) +{ + if (sysopt.genericusers) + free((genericptr_t) sysopt.genericusers); + sysopt.genericusers = dupstr(bufp); + return TRUE; +} + +staticfn boolean +cnf_line_BONES_POOLS(char *bufp) +{ + /* max value of 10 guarantees (N % bones.pools) will be one digit + so we don't lose control of the length of bones file names */ + int n = atoi(bufp); + + sysopt.bones_pools = (n <= 0) ? 0 : min(n, 10); + /* note: right now bones_pools==0 is the same as bones_pools==1, + but we could change that and make bones_pools==0 become an + indicator to suppress bones usage altogether */ + return TRUE; +} + +staticfn boolean +cnf_line_SUPPORT(char *bufp) +{ + if (sysopt.support) + free((genericptr_t) sysopt.support); + sysopt.support = dupstr(bufp); + return TRUE; +} + +staticfn boolean +cnf_line_RECOVER(char *bufp) +{ + if (sysopt.recover) + free((genericptr_t) sysopt.recover); + sysopt.recover = dupstr(bufp); + return TRUE; +} + +staticfn boolean +cnf_line_CHECK_SAVE_UID(char *bufp) +{ + int n = atoi(bufp); + + sysopt.check_save_uid = n; + return TRUE; +} + +staticfn boolean +cnf_line_CHECK_PLNAME(char *bufp) +{ + int n = atoi(bufp); + + sysopt.check_plname = n; + return TRUE; +} + +staticfn boolean +cnf_line_SEDUCE(char *bufp) +{ + int n = !!atoi(bufp); /* XXX this could be tighter */ +#ifdef SYSCF + int src = iflags.parse_config_file_src; + boolean in_sysconf = (src == set_in_sysconf); +#else + boolean in_sysconf = FALSE; +#endif + + /* allow anyone to disable it but can only enable it in sysconf + or as a no-op for the user when sysconf hasn't disabled it */ + if (!in_sysconf && !sysopt.seduce && n != 0) { + config_error_add("Illegal value in SEDUCE"); + n = 0; + } + sysopt.seduce = n; + sysopt_seduce_set(sysopt.seduce); + return TRUE; +} + +staticfn boolean +cnf_line_HIDEUSAGE(char *bufp) +{ + int n = !!atoi(bufp); + + sysopt.hideusage = n; + return TRUE; +} + +staticfn boolean +cnf_line_MAXPLAYERS(char *bufp) +{ + int n = atoi(bufp); + + /* XXX to get more than 25, need to rewrite all lock code */ + if (n < 0 || n > 25) { + config_error_add("Illegal value in MAXPLAYERS (maximum is 25)"); + n = 5; + } + sysopt.maxplayers = n; + return TRUE; +} + +staticfn boolean +cnf_line_PERSMAX(char *bufp) +{ + int n = atoi(bufp); + + if (n < 1) { + config_error_add("Illegal value in PERSMAX (minimum is 1)"); + n = 0; + } + sysopt.persmax = n; + return TRUE; +} + +staticfn boolean +cnf_line_PERS_IS_UID(char *bufp) +{ + int n = atoi(bufp); + + if (n != 0 && n != 1) { + config_error_add("Illegal value in PERS_IS_UID (must be 0 or 1)"); + n = 0; + } + sysopt.pers_is_uid = n; + return TRUE; +} + +staticfn boolean +cnf_line_ENTRYMAX(char *bufp) +{ + int n = atoi(bufp); + + if (n < 10) { + config_error_add("Illegal value in ENTRYMAX (minimum is 10)"); + n = 10; + } + sysopt.entrymax = n; + return TRUE; +} + +staticfn boolean +cnf_line_POINTSMIN(char *bufp) +{ + int n = atoi(bufp); + + if (n < 1) { + config_error_add("Illegal value in POINTSMIN (minimum is 1)"); + n = 100; + } + sysopt.pointsmin = n; + return TRUE; +} + +staticfn boolean +cnf_line_MAX_STATUENAME_RANK(char *bufp) +{ + int n = atoi(bufp); + + if (n < 1) { + config_error_add("Illegal value in MAX_STATUENAME_RANK" + " (minimum is 1)"); + n = 10; + } + sysopt.tt_oname_maxrank = n; + return TRUE; +} + +staticfn boolean +cnf_line_LIVELOG(char *bufp) +{ + /* using 0 for base accepts "dddd" as decimal provided that first 'd' + isn't '0', "0xhhhh" as hexadecimal, and "0oooo" as octal; ignores + any trailing junk, including '8' or '9' for leading '0' octal */ + long L = strtol(bufp, NULL, 0); + + if (L < 0L || L > 0xffffL) { + config_error_add("Illegal value for LIVELOG" + " (must be between 0 and 0xFFFF)."); + return 0; + } + sysopt.livelog = L; + return TRUE; +} + +staticfn boolean +cnf_line_PANICTRACE_LIBC(char *bufp) +{ + int n = atoi(bufp); + +#if defined(PANICTRACE) && defined(PANICTRACE_LIBC) + if (n < 0 || n > 2) { + config_error_add("Illegal value in PANICTRACE_LIBC (not 0,1,2)"); + n = 0; + } +#endif + sysopt.panictrace_libc = n; + return TRUE; +} + +staticfn boolean +cnf_line_PANICTRACE_GDB(char *bufp) +{ + int n = atoi(bufp); + +#if defined(PANICTRACE) + if (n < 0 || n > 2) { + config_error_add("Illegal value in PANICTRACE_GDB (not 0,1,2)"); + n = 0; + } +#endif + sysopt.panictrace_gdb = n; + return TRUE; +} + +staticfn boolean +cnf_line_GDBPATH(char *bufp) +{ +#if defined(PANICTRACE) && !defined(VMS) + if (!file_exists(bufp)) { + config_error_add("File specified in GDBPATH does not exist"); + return FALSE; + } +#endif + if (sysopt.gdbpath) + free((genericptr_t) sysopt.gdbpath); + sysopt.gdbpath = dupstr(bufp); + return TRUE; +} + +staticfn boolean +cnf_line_GREPPATH(char *bufp) +{ +#if defined(PANICTRACE) && !defined(VMS) + if (!file_exists(bufp)) { + config_error_add("File specified in GREPPATH does not exist"); + return FALSE; + } +#endif + if (sysopt.greppath) + free((genericptr_t) sysopt.greppath); + sysopt.greppath = dupstr(bufp); + return TRUE; +} + +staticfn boolean +cnf_line_CRASHREPORTURL(char *bufp) +{ + if (sysopt.crashreporturl) + free((genericptr_t) sysopt.crashreporturl); + sysopt.crashreporturl = dupstr(bufp); + return TRUE; +} + +staticfn boolean +cnf_line_SAVEFORMAT(char *bufp) +{ + parseformat(sysopt.saveformat, bufp); + return TRUE; +} + +staticfn boolean +cnf_line_BONESFORMAT(char *bufp) +{ + parseformat(sysopt.bonesformat, bufp); + return TRUE; +} + +staticfn boolean +cnf_line_ACCESSIBILITY(char *bufp) +{ + int n = atoi(bufp); + + if (n < 0 || n > 1) { + config_error_add("Illegal value in ACCESSIBILITY (not 0,1)"); + n = 0; + } + sysopt.accessibility = n; + return TRUE; +} + +staticfn boolean +cnf_line_PORTABLE_DEVICE_PATHS(char *bufp) +{ +#ifdef WIN32 + int n = atoi(bufp); + + if (n < 0 || n > 1) { + config_error_add("Illegal value in PORTABLE_DEVICE_PATHS" + " (not 0 or 1)"); + n = 0; + } + sysopt.portable_device_paths = n; +#else /* Windows-only directive encountered by non-Windows config */ + nhUse(bufp); + config_error_add("PORTABLE_DEVICE_PATHS is not supported"); +#endif + return TRUE; +} + +#endif /* SYSCF */ + +staticfn boolean +cnf_line_BOULDER(char *bufp) +{ + (void) get_uchars(bufp, &go.ov_primary_syms[SYM_BOULDER + SYM_OFF_X], + TRUE, 1, "BOULDER"); + return TRUE; +} + +staticfn boolean +cnf_line_MENUCOLOR(char *bufp) +{ + return add_menu_coloring(bufp); +} + +staticfn boolean +cnf_line_HILITE_STATUS(char *bufp) +{ +#ifdef STATUS_HILITES + return parse_status_hl1(bufp, TRUE); +#else + nhUse(bufp); + return TRUE; +#endif +} + +staticfn boolean +cnf_line_WARNINGS(char *bufp) +{ + uchar translate[MAXPCHARS]; + + (void) get_uchars(bufp, translate, FALSE, WARNCOUNT, "WARNINGS"); + assign_warnings(translate); + return TRUE; +} + +staticfn boolean +cnf_line_ROGUESYMBOLS(char *bufp) +{ + if (parsesymbols(bufp, ROGUESET)) { + switch_symbols(TRUE); + return TRUE; + } + config_error_add("Error in ROGUESYMBOLS definition '%s'", bufp); + return FALSE; +} + +staticfn boolean +cnf_line_SYMBOLS(char *bufp) +{ + if (parsesymbols(bufp, PRIMARYSET)) { + switch_symbols(TRUE); + return TRUE; + } + config_error_add("Error in SYMBOLS definition '%s'", bufp); + return FALSE; +} + +staticfn boolean +cnf_line_WIZKIT(char *bufp) +{ + (void) strncpy(gw.wizkit, bufp, WIZKIT_MAX - 1); + return TRUE; +} + +#ifdef USER_SOUNDS +staticfn boolean +cnf_line_SOUNDDIR(char *bufp) +{ + if (sounddir) + free((genericptr_t) sounddir); + sounddir = dupstr(bufp); + return TRUE; +} + +staticfn boolean +cnf_line_SOUND(char *bufp) +{ + add_sound_mapping(bufp); + return TRUE; +} +#endif /*USER_SOUNDS*/ + +staticfn boolean +cnf_line_QT_TILEWIDTH(char *bufp) +{ +#ifdef QT_GRAPHICS + extern char *qt_tilewidth; + + if (qt_tilewidth == NULL) + qt_tilewidth = dupstr(bufp); +#else + nhUse(bufp); +#endif + return TRUE; +} + +staticfn boolean +cnf_line_QT_TILEHEIGHT(char *bufp) +{ +#ifdef QT_GRAPHICS + extern char *qt_tileheight; + + if (qt_tileheight == NULL) + qt_tileheight = dupstr(bufp); +#else + nhUse(bufp); +#endif + return TRUE; +} + +staticfn boolean +cnf_line_QT_FONTSIZE(char *bufp) +{ +#ifdef QT_GRAPHICS + extern char *qt_fontsize; + + if (qt_fontsize == NULL) + qt_fontsize = dupstr(bufp); +#else + nhUse(bufp); +#endif + return TRUE; +} + +staticfn boolean +cnf_line_QT_COMPACT(char *bufp) +{ +#ifdef QT_GRAPHICS + extern int qt_compact_mode; + + qt_compact_mode = atoi(bufp); +#else + nhUse(bufp); +#endif + return TRUE; +} + +typedef boolean (*config_line_stmt_func)(char *); + +/* normal */ +#define CNFL_N(n, l) { #n, l, FALSE, FALSE, cnf_line_##n } +/* normal, alias */ +#define CNFL_NA(n, l, f) { #n, l, FALSE, FALSE, cnf_line_##f } +/* sysconf only */ +#define CNFL_S(n, l) { #n, l, TRUE, FALSE, cnf_line_##n } + +static const struct match_config_line_stmt { + const char *name; + int len; + boolean syscnf_only; + boolean origbuf; + config_line_stmt_func fn; +} config_line_stmt[] = { + /* OPTIONS handled separately */ + { "OPTIONS", 4, FALSE, TRUE, cnf_line_OPTIONS }, + CNFL_N(AUTOPICKUP_EXCEPTION, 5), + CNFL_N(BINDINGS, 4), + CNFL_N(AUTOCOMPLETE, 5), + CNFL_N(MSGTYPE, 7), + CNFL_N(HACKDIR, 4), + CNFL_N(LEVELDIR, 4), + CNFL_NA(LEVELS, 4, LEVELDIR), + CNFL_N(SAVEDIR, 4), + CNFL_N(BONESDIR, 5), + CNFL_N(DATADIR, 4), + CNFL_N(SCOREDIR, 4), + CNFL_N(LOCKDIR, 4), + CNFL_N(CONFIGDIR, 4), + CNFL_N(TROUBLEDIR, 4), + CNFL_N(NAME, 4), + CNFL_N(ROLE, 4), + CNFL_NA(CHARACTER, 4, ROLE), + CNFL_N(dogname, 3), + CNFL_N(catname, 3), +#ifdef SYSCF + CNFL_S(WIZARDS, 7), + CNFL_S(SHELLERS, 8), + CNFL_S(MSGHANDLER, 9), + CNFL_S(EXPLORERS, 7), + CNFL_S(DEBUGFILES, 5), + CNFL_S(DUMPLOGFILE, 7), + CNFL_S(GENERICUSERS, 12), + CNFL_S(BONES_POOLS, 10), + CNFL_S(SUPPORT, 7), + CNFL_S(RECOVER, 7), + CNFL_S(CHECK_SAVE_UID, 14), + CNFL_S(CHECK_PLNAME, 12), + CNFL_S(SEDUCE, 6), + CNFL_S(HIDEUSAGE, 9), + CNFL_S(MAXPLAYERS, 10), + CNFL_S(PERSMAX, 7), + CNFL_S(PERS_IS_UID, 11), + CNFL_S(ENTRYMAX, 8), + CNFL_S(POINTSMIN, 9), + CNFL_S(MAX_STATUENAME_RANK, 10), + CNFL_S(LIVELOG, 7), + CNFL_S(PANICTRACE_LIBC, 15), + CNFL_S(PANICTRACE_GDB, 14), + CNFL_S(CRASHREPORTURL, 13), + CNFL_S(GDBPATH, 7), + CNFL_S(GREPPATH, 7), + CNFL_S(SAVEFORMAT, 10), + CNFL_S(BONESFORMAT, 11), + CNFL_S(ACCESSIBILITY, 13), + CNFL_S(PORTABLE_DEVICE_PATHS, 8), +#endif /*SYSCF*/ + CNFL_N(BOULDER, 3), + CNFL_N(MENUCOLOR, 9), + CNFL_N(HILITE_STATUS, 6), + CNFL_N(WARNINGS, 5), + CNFL_N(ROGUESYMBOLS, 4), + CNFL_N(SYMBOLS, 4), + CNFL_N(WIZKIT, 6), +#ifdef USER_SOUNDS + CNFL_N(SOUNDDIR, 8), + CNFL_N(SOUND, 5), +#endif /*USER_SOUNDS*/ + CNFL_N(QT_TILEWIDTH, 12), + CNFL_N(QT_TILEHEIGHT, 13), + CNFL_N(QT_FONTSIZE, 11), + CNFL_N(QT_COMPACT, 10) +}; + +#undef CNFL_N +#undef CNFL_NA +#undef CNFL_S + +boolean +parse_config_line(char *origbuf) +{ +#if defined(MICRO) && !defined(NOCWD_ASSUMPTIONS) + static boolean ramdisk_specified = FALSE; +#endif +#ifdef SYSCF + int src = iflags.parse_config_file_src; + boolean in_sysconf = (src == set_in_sysconf); +#endif + char *bufp, buf[4 * BUFSZ]; + int i; + + while (*origbuf == ' ' || *origbuf == '\t') /* skip leading whitespace */ + ++origbuf; /* (caller probably already did this) */ + (void) strncpy(buf, origbuf, sizeof buf - 1); + buf[sizeof buf - 1] = '\0'; /* strncpy not guaranteed to NUL terminate */ + /* convert any tab to space, condense consecutive spaces into one, + remove leading and trailing spaces (exception: if there is nothing + but spaces, one of them will be kept even though it leads/trails) */ + mungspaces(buf); + + /* find the '=' or ':' */ + bufp = find_optparam(buf); + if (!bufp) { + config_error_add("Not a config statement, missing '='"); + return FALSE; + } + /* skip past '=', then space between it and value, if any */ + ++bufp; + if (*bufp == ' ') + ++bufp; + + for (i = 0; i < SIZE(config_line_stmt); i++) { +#ifdef SYSCF + if (config_line_stmt[i].syscnf_only && !in_sysconf) + continue; +#endif + if (match_varname(buf, config_line_stmt[i].name, + config_line_stmt[i].len)) { + char *parm = config_line_stmt[i].origbuf ? origbuf : bufp; + + return config_line_stmt[i].fn(parm); + } + } + + config_error_add("Unknown config statement"); + return FALSE; +} + +#ifdef USER_SOUNDS +boolean +can_read_file(const char *filename) +{ + return (boolean) (access(filename, 4) == 0); +} +#endif /* USER_SOUNDS */ + +struct _config_error_errmsg { + int line_num; + char *errormsg; + struct _config_error_errmsg *next; +}; + +struct _config_error_frame { + int line_num; + int num_errors; + boolean origline_shown; + boolean fromfile; + boolean secure; + char origline[4 * BUFSZ]; + char source[BUFSZ]; + struct _config_error_frame *next; +}; + +static struct _config_error_frame *config_error_data = 0; +static struct _config_error_errmsg *config_error_msg = 0; + +void +config_error_init(boolean from_file, const char *sourcename, boolean secure) +{ + struct _config_error_frame *tmp = (struct _config_error_frame *) + alloc(sizeof *tmp); + + tmp->line_num = 0; + tmp->num_errors = 0; + tmp->origline_shown = FALSE; + tmp->fromfile = from_file; + tmp->secure = secure; + tmp->origline[0] = '\0'; + if (sourcename && sourcename[0]) { + (void) strncpy(tmp->source, sourcename, sizeof (tmp->source) - 1); + tmp->source[sizeof (tmp->source) - 1] = '\0'; + } else + tmp->source[0] = '\0'; + + tmp->next = config_error_data; + config_error_data = tmp; + program_state.config_error_ready = TRUE; +} + +staticfn boolean +config_error_nextline(const char *line) +{ + struct _config_error_frame *ced = config_error_data; + + if (!ced) + return FALSE; + + if (ced->num_errors && ced->secure) + return FALSE; + + ced->line_num++; + ced->origline_shown = FALSE; + if (line && line[0]) { + (void) strncpy(ced->origline, line, sizeof (ced->origline) - 1); + ced->origline[sizeof (ced->origline) - 1] = '\0'; + } else + ced->origline[0] = '\0'; + + return TRUE; +} + +int +l_get_config_errors(lua_State *L) +{ + struct _config_error_errmsg *dat = config_error_msg; + struct _config_error_errmsg *tmp; + int idx = 1; + + lua_newtable(L); + + while (dat) { + lua_pushinteger(L, idx++); + lua_newtable(L); + nhl_add_table_entry_int(L, "line", dat->line_num); + nhl_add_table_entry_str(L, "error", dat->errormsg); + lua_settable(L, -3); + tmp = dat->next; + free(dat->errormsg); + dat->errormsg = (char *) 0; + free(dat); + dat = tmp; + } + config_error_msg = (struct _config_error_errmsg *) 0; + + return 1; +} + +/* varargs 'config_error_add()' moved to pline.c */ +void +config_erradd(const char *buf) +{ + char lineno[QBUFSZ]; + const char *punct; + + if (!buf || !*buf) + buf = "Unknown error"; + + /* if buf[] doesn't end in a period, exclamation point, or question mark, + we'll include a period (in the message, not appended to buf[]) */ + punct = c_eos((char *) buf) - 1; /* eos(buf)-1 is valid */ + punct = strchr(".!?", *punct) ? "" : "."; + + if (!program_state.config_error_ready) { + /* either very early, where pline() will use raw_print(), or + player gave bad value when prompted by interactive 'O' command */ + pline("%s%s%s", !iflags.window_inited ? "config_error_add: " : "", + buf, punct); + wait_synch(); + return; + } + + if (iflags.in_lua) { + struct _config_error_errmsg *dat + = (struct _config_error_errmsg *) alloc(sizeof *dat); + + dat->next = config_error_msg; + dat->line_num = config_error_data->line_num; + dat->errormsg = dupstr(buf); + config_error_msg = dat; + return; + } + + config_error_data->num_errors++; + if (!config_error_data->origline_shown && !config_error_data->secure) { + pline("\n%s", config_error_data->origline); + config_error_data->origline_shown = TRUE; + } + if (config_error_data->line_num > 0 && !config_error_data->secure) { + Sprintf(lineno, "Line %d: ", config_error_data->line_num); + } else + lineno[0] = '\0'; + + pline("%s %s%s%s", config_error_data->secure ? "Error:" : " *", + lineno, buf, punct); +} + +int +config_error_done(void) +{ + int n; + struct _config_error_frame *tmp = config_error_data; + + if (!config_error_data) + return 0; + n = config_error_data->num_errors; +#ifndef USER_SOUNDS + if (gn.no_sound_notified > 0) { + /* no USER_SOUNDS; config_error_add() was called once for first + SOUND or SOUNDDIR entry seen, then skipped for any others; + include those skipped ones in the total error count */ + n += (gn.no_sound_notified - 1); + gn.no_sound_notified = 0; + } +#endif + if (n) { + boolean cmdline = !strcmp(config_error_data->source, "command line"); + + pline("\n%d error%s %s %s.\n", n, plur(n), cmdline ? "on" : "in", + *config_error_data->source ? config_error_data->source + : configfile); + wait_synch(); + } + config_error_data = tmp->next; + free(tmp); + program_state.config_error_ready = (config_error_data != 0); + return n; +} + +boolean +read_config_file(const char *filename, int src) +{ + FILE *fp; + boolean rv = TRUE; + + if (!(fp = fopen_config_file(filename, src))) + return FALSE; + + /* begin detection of duplicate configfile options */ + reset_duplicate_opt_detection(); + free_config_sections(); + iflags.parse_config_file_src = src; + + rv = parse_conf_file(fp, parse_config_line); + (void) fclose(fp); + + free_config_sections(); + /* turn off detection of duplicate configfile options */ + reset_duplicate_opt_detection(); + return rv; +} + +struct _cnf_parser_state { + char *inbuf; + unsigned inbufsz; + int rv; + char *ep; + char *buf; + boolean skip, morelines; + boolean cont; + boolean pbreak; +}; + +/* Initialize config parser data */ +staticfn void +cnf_parser_init(struct _cnf_parser_state *parser) +{ + parser->rv = TRUE; /* assume successful parse */ + parser->ep = parser->buf = (char *) 0; + parser->skip = FALSE; + parser->morelines = FALSE; + parser->inbufsz = 4 * BUFSZ; + parser->inbuf = (char *) alloc(parser->inbufsz); + parser->cont = FALSE; + parser->pbreak = FALSE; + memset(parser->inbuf, 0, parser->inbufsz); +} + +/* caller has finished with 'parser' (except for 'rv' so leave that intact) */ +staticfn void +cnf_parser_done(struct _cnf_parser_state *parser) +{ + parser->ep = 0; /* points into parser->inbuf, so becoming stale */ + if (parser->inbuf) + free(parser->inbuf), parser->inbuf = 0; + if (parser->buf) + free(parser->buf), parser->buf = 0; +} + +/* + * Parse config buffer, handling comments, empty lines, config sections, + * CHOOSE, and line continuation, calling proc for every valid line. + * + * Continued lines are merged together with one space in between. + */ +staticfn void +parse_conf_buf(struct _cnf_parser_state *p, boolean (*proc)(char *arg)) +{ + p->cont = FALSE; + p->pbreak = FALSE; + p->ep = strchr(p->inbuf, '\n'); + if (p->skip) { /* in case previous line was too long */ + if (p->ep) + p->skip = FALSE; /* found newline; next line is normal */ + } else { + if (!p->ep) { /* newline missing */ + if (strlen(p->inbuf) < (p->inbufsz - 2)) { + /* likely the last line of file is just + missing a newline; process it anyway */ + p->ep = eos(p->inbuf); + } else { + config_error_add("Line too long, skipping"); + p->skip = TRUE; /* discard next fgets */ + } + } else { + *p->ep = '\0'; /* remove newline */ + } + if (p->ep) { + char *tmpbuf = (char *) 0; + int len; + boolean ignoreline = FALSE; + boolean oldline = FALSE; + + /* line continuation (trailing '\') */ + p->morelines = (--p->ep >= p->inbuf && *p->ep == '\\'); + if (p->morelines) + *p->ep = '\0'; + + /* trim off spaces at end of line */ + while (p->ep >= p->inbuf + && (*p->ep == ' ' || *p->ep == '\t' || *p->ep == '\r')) + *p->ep-- = '\0'; + + if (!config_error_nextline(p->inbuf)) { + p->rv = FALSE; + if (p->buf) + free(p->buf), p->buf = (char *) 0; + p->pbreak = TRUE; + return; + } + + p->ep = p->inbuf; + while (*p->ep == ' ' || *p->ep == '\t') + ++p->ep; + + /* ignore empty lines and full-line comment lines */ + if (!*p->ep || *p->ep == '#') + ignoreline = TRUE; + + if (p->buf) + oldline = TRUE; + + /* merge now read line with previous ones, if necessary */ + if (!ignoreline) { + len = (int) strlen(p->ep) + 1; /* +1: final '\0' */ + if (p->buf) + len += (int) strlen(p->buf) + 1; /* +1: space */ + tmpbuf = (char *) alloc(len); + *tmpbuf = '\0'; + if (p->buf) { + Strcat(strcpy(tmpbuf, p->buf), " "); + free(p->buf), p->buf = 0; + } + p->buf = strcat(tmpbuf, p->ep); + if (strlen(p->buf) >= p->inbufsz) + p->buf[p->inbufsz - 1] = '\0'; + } + + if (p->morelines || (ignoreline && !oldline)) + return; + + if (handle_config_section(p->buf)) { + free(p->buf), p->buf = (char *) 0; + return; + } + + /* from here onwards, we'll handle buf only */ + + if (match_varname(p->buf, "CHOOSE", 6)) { + char *section; + char *bufp = find_optparam(p->buf); + + if (!bufp) { + config_error_add("Format is CHOOSE=section1" + ",section2,..."); + p->rv = FALSE; + free(p->buf), p->buf = (char *) 0; + return; + } + bufp++; + if (gc.config_section_chosen) + free(gc.config_section_chosen), + gc.config_section_chosen = 0; + section = choose_random_part(bufp, ','); + if (section) { + gc.config_section_chosen = dupstr(section); + } else { + config_error_add("No config section to choose"); + p->rv = FALSE; + } + free(p->buf), p->buf = (char *) 0; + return; + } + + if (!(*proc)(p->buf)) + p->rv = FALSE; + + free(p->buf), p->buf = (char *) 0; + } + } +} + +boolean +parse_conf_str(const char *str, boolean (*proc)(char *arg)) +{ + size_t len; + struct _cnf_parser_state parser; + + cnf_parser_init(&parser); + free_config_sections(); + config_error_init(FALSE, "parse_conf_str", FALSE); + while (str && *str) { + len = 0; + while (*str && len < (parser.inbufsz-1)) { + parser.inbuf[len] = *str; + len++; + str++; + if (parser.inbuf[len-1] == '\n') + break; + } + parser.inbuf[len] = '\0'; + parse_conf_buf(&parser, proc); + if (parser.pbreak) + break; + } + cnf_parser_done(&parser); + + free_config_sections(); + config_error_done(); + return parser.rv; +} + +/* parse_conf_file + * + * Read from file fp, calling parse_conf_buf for each line. + */ +boolean +parse_conf_file(FILE *fp, boolean (*proc)(char *arg)) +{ + struct _cnf_parser_state parser; + + cnf_parser_init(&parser); + free_config_sections(); + + while (fgets(parser.inbuf, parser.inbufsz, fp)) { + parse_conf_buf(&parser, proc); + if (parser.pbreak) + break; + } + cnf_parser_done(&parser); + + free_config_sections(); + return parser.rv; +} + +#ifdef SYSCF +staticfn void +parseformat(int *arr, char *str) +{ + const char *legal[] = { "historical", "lendian", "ascii" }; + int i, kwi = 0, words = 0; + char *p = str, *keywords[2]; + + while (*p) { + while (*p && isspace((uchar) *p)) { + *p = '\0'; + p++; + } + if (*p) { + words++; + if (kwi < 2) + keywords[kwi++] = p; + } + while (*p && !isspace((uchar) *p)) + p++; + } + if (!words) { + impossible("missing format list"); + return; + } + while (--kwi >= 0) + if (kwi < 2) { + for (i = 0; i < SIZE(legal); ++i) { + if (!strcmpi(keywords[kwi], legal[i])) + arr[kwi] = i + 1; + } + } +} +#endif /* SYSCF */ + +/* ---------- END CONFIG FILE HANDLING ----------- */ + +/*cfgfiles.c*/ diff --git a/src/files.c b/src/files.c index 8e7d214a9..cd8ea9815 100644 --- a/src/files.c +++ b/src/files.c @@ -114,10 +114,6 @@ extern char *translate_path_variables(const char *, char *); #define PRAGMA_UNUSED #endif -#ifdef USER_SOUNDS -extern char *sounddir; /* defined in sounds.c */ -#endif - staticfn NHFILE *new_nhfile(void); staticfn void free_nhfile(NHFILE *); #ifdef SELECTSAVED @@ -137,93 +133,7 @@ staticfn boolean make_compressed_name(const char *, char *); #ifndef USE_FCNTL staticfn char *make_lockname(const char *, char *); #endif -staticfn void set_configfile_name(const char *); -staticfn FILE *fopen_config_file(const char *, int); -staticfn int get_uchars(char *, uchar *, boolean, int, const char *); -#ifdef NOCWD_ASSUMPTIONS -staticfn void adjust_prefix(char *, int); -#endif -staticfn char *choose_random_part(char *, char); -staticfn boolean config_error_nextline(const char *); -staticfn void free_config_sections(void); -staticfn char *is_config_section(char *); -staticfn boolean handle_config_section(char *); -boolean parse_config_line(char *); -staticfn char *find_optparam(const char *); -staticfn boolean cnf_line_OPTIONS(char *); -staticfn boolean cnf_line_AUTOPICKUP_EXCEPTION(char *); -staticfn boolean cnf_line_BINDINGS(char *); -staticfn boolean cnf_line_AUTOCOMPLETE(char *); -staticfn boolean cnf_line_MSGTYPE(char *); -staticfn boolean cnf_line_HACKDIR(char *); -staticfn boolean cnf_line_LEVELDIR(char *); -staticfn boolean cnf_line_SAVEDIR(char *); -staticfn boolean cnf_line_BONESDIR(char *); -staticfn boolean cnf_line_DATADIR(char *); -staticfn boolean cnf_line_SCOREDIR(char *); -staticfn boolean cnf_line_LOCKDIR(char *); -staticfn boolean cnf_line_CONFIGDIR(char *); -staticfn boolean cnf_line_TROUBLEDIR(char *); -staticfn boolean cnf_line_NAME(char *); -staticfn boolean cnf_line_ROLE(char *); -staticfn boolean cnf_line_dogname(char *); -staticfn boolean cnf_line_catname(char *); -#ifdef SYSCF -staticfn boolean cnf_line_WIZARDS(char *); -staticfn boolean cnf_line_SHELLERS(char *); -staticfn boolean cnf_line_MSGHANDLER(char *); -staticfn boolean cnf_line_EXPLORERS(char *); -staticfn boolean cnf_line_DEBUGFILES(char *); -staticfn boolean cnf_line_DUMPLOGFILE(char *); -staticfn boolean cnf_line_GENERICUSERS(char *); -staticfn boolean cnf_line_BONES_POOLS(char *); -staticfn boolean cnf_line_SUPPORT(char *); -staticfn boolean cnf_line_RECOVER(char *); -staticfn boolean cnf_line_CHECK_SAVE_UID(char *); -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_PERSMAX(char *); -staticfn boolean cnf_line_PERS_IS_UID(char *); -staticfn boolean cnf_line_ENTRYMAX(char *); -staticfn boolean cnf_line_POINTSMIN(char *); -staticfn boolean cnf_line_MAX_STATUENAME_RANK(char *); -staticfn boolean cnf_line_LIVELOG(char *); -staticfn boolean cnf_line_PANICTRACE_LIBC(char *); -staticfn boolean cnf_line_PANICTRACE_GDB(char *); -staticfn boolean cnf_line_GDBPATH(char *); -staticfn boolean cnf_line_GREPPATH(char *); -staticfn boolean cnf_line_CRASHREPORTURL(char *); -staticfn boolean cnf_line_SAVEFORMAT(char *); -staticfn boolean cnf_line_BONESFORMAT(char *); -staticfn boolean cnf_line_ACCESSIBILITY(char *); -staticfn boolean cnf_line_PORTABLE_DEVICE_PATHS(char *); -staticfn void parseformat(int *, char *); -#endif /* SYSCF */ -staticfn boolean cnf_line_BOULDER(char *); -staticfn boolean cnf_line_MENUCOLOR(char *); -staticfn boolean cnf_line_HILITE_STATUS(char *); -staticfn boolean cnf_line_WARNINGS(char *); -staticfn boolean cnf_line_ROGUESYMBOLS(char *); -staticfn boolean cnf_line_SYMBOLS(char *); -staticfn boolean cnf_line_WIZKIT(char *); -#ifdef USER_SOUNDS -staticfn boolean cnf_line_SOUNDDIR(char *); -staticfn boolean cnf_line_SOUND(char *); -#endif -staticfn boolean cnf_line_QT_TILEWIDTH(char *); -staticfn boolean cnf_line_QT_TILEHEIGHT(char *); -staticfn boolean cnf_line_QT_FONTSIZE(char *); -staticfn boolean cnf_line_QT_COMPACT(char *); -struct _cnf_parser_state; /* defined below (far below...) */ -staticfn void cnf_parser_init(struct _cnf_parser_state *parser); -staticfn void cnf_parser_done(struct _cnf_parser_state *parser); -staticfn void parse_conf_buf(struct _cnf_parser_state *parser, - boolean (*proc)(char *arg)); -/* next one is in extern.h; why here too? */ -boolean parse_conf_str(const char *str, boolean (*proc)(char *arg)); -staticfn boolean parse_conf_file(FILE *fp, boolean (*proc)(char *arg)); + staticfn FILE *fopen_wizkit_file(void); staticfn void wizkit_addinv(struct obj *); boolean proc_wizkit_line(char *buf); @@ -2106,1752 +2016,6 @@ unlock_file(const char *filename) /* ---------- END FILE LOCKING HANDLING ----------- */ -/* ---------- BEGIN CONFIG FILE HANDLING ----------- */ - -static const char *default_configfile = -#ifdef UNIX - ".nethackrc"; -#else -#if defined(MAC) || defined(__BEOS__) - "NetHack Defaults"; -#else -#if defined(MSDOS) || defined(WIN32) - CONFIG_FILE; -#else - "NetHack.cnf"; -#endif -#endif -#endif - -/* used for messaging. Also used in options.c */ -char configfile[BUFSZ]; - -#ifdef MSDOS -/* conflict with speed-dial under windows - * for XXX.cnf file so support of NetHack.cnf - * is for backward compatibility only. - * Preferred name (and first tried) is now defaults.nh but - * the game will try the old name if there - * is no defaults.nh. - */ -const char *backward_compat_configfile = "nethack.cnf"; -#endif - -/* #saveoptions - save config options into file */ -int -do_write_config_file(void) -{ - FILE *fp; - char tmp[BUFSZ]; - - if (!configfile[0]) { - pline("Strange, could not figure out config file name."); - return ECMD_OK; - } - if (flags.suppress_alert < FEATURE_NOTICE_VER(3,7,0)) { - pline("Warning: saveoptions is highly experimental!"); - wait_synch(); - pline("Some settings are not saved!"); - wait_synch(); - pline("All manual customization and comments are removed" - " from the file!"); - wait_synch(); - } -#define overwrite_prompt "Overwrite config file %.*s?" - Sprintf(tmp, overwrite_prompt, - (int) (BUFSZ - sizeof overwrite_prompt - 2), configfile); -#undef overwrite_prompt - if (!paranoid_query(TRUE, tmp)) - return ECMD_OK; - - fp = fopen(configfile, "w"); - if (fp) { - size_t len, wrote; - strbuf_t buf; - - strbuf_init(&buf); - all_options_strbuf(&buf); - len = strlen(buf.str); - wrote = fwrite(buf.str, 1, len, fp); - fclose(fp); - strbuf_empty(&buf); - if (wrote != len) - pline("An error occurred, wrote only partial data (%zu/%zu).", - wrote, len); - } - return ECMD_OK; -} - -/* remember the name of the file we're accessing; - if may be used in option reject messages */ -staticfn void -set_configfile_name(const char *fname) -{ - (void) strncpy(configfile, fname, sizeof configfile - 1); - configfile[sizeof configfile - 1] = '\0'; -} - -staticfn FILE * -fopen_config_file(const char *filename, int src) -{ - FILE *fp; -#if defined(UNIX) || defined(VMS) - char tmp_config[BUFSZ]; - char *envp; -#endif - - if (src == set_in_sysconf) { - /* SYSCF_FILE; if we can't open it, caller will bail */ - if (filename && *filename) { - set_configfile_name(fqname(filename, SYSCONFPREFIX, 0)); - fp = fopen(configfile, "r"); - } else - fp = (FILE *) 0; - return fp; - } - /* If src != set_in_sysconf, "filename" is an environment variable, so it - * should hang around. If set, it is expected to be a full path name - * (if relevant) - */ - if (filename && *filename) { - set_configfile_name(filename); -#ifdef UNIX - if (access(configfile, 4) == -1) { /* 4 is R_OK on newer systems */ - /* nasty sneaky attempt to read file through - * NetHack's setuid permissions -- this is the only - * place a file name may be wholly under the player's - * control (but SYSCF_FILE is not under the player's - * control so it's OK). - */ - raw_printf("Access to %s denied (%d).", configfile, errno); - wait_synch(); - /* fall through to standard names */ - } else -#endif - if ((fp = fopen(configfile, "r")) != (FILE *) 0) { - return fp; -#if defined(UNIX) || defined(VMS) - } else { - /* access() above probably caught most problems for UNIX */ - raw_printf("Couldn't open requested config file %s (%d).", - configfile, errno); - wait_synch(); -#endif - } - } - /* fall through to standard names */ - -#if defined(MICRO) || defined(MAC) || defined(__BEOS__) || defined(WIN32) - set_configfile_name(fqname(default_configfile, CONFIGPREFIX, 0)); - if ((fp = fopen(configfile, "r")) != (FILE *) 0) { - return fp; - } else if (strcmp(default_configfile, configfile)) { - set_configfile_name(default_configfile); - if ((fp = fopen(configfile, "r")) != (FILE *) 0) - return fp; - } -#ifdef MSDOS - set_configfile_name(fqname(backward_compat_configfile, CONFIGPREFIX, 0)); - if ((fp = fopen(configfile, "r")) != (FILE *) 0) { - return fp; - } else if (strcmp(backward_compat_configfile, configfile)) { - set_configfile_name(backward_compat_configfile); - if ((fp = fopen(configfile, "r")) != (FILE *) 0) - return fp; - } -#endif -#else -/* constructed full path names don't need fqname() */ -#ifdef VMS - /* no punctuation, so might be a logical name */ - set_configfile_name("nethackini"); - if ((fp = fopen(configfile, "r")) != (FILE *) 0) - return fp; - set_configfile_name("sys$login:nethack.ini"); - if ((fp = fopen(configfile, "r")) != (FILE *) 0) - return fp; - - envp = nh_getenv("HOME"); - if (!envp || !*envp) - Strcpy(tmp_config, "NetHack.cnf"); - else - Sprintf(tmp_config, "%s%s%s", envp, - !strchr(":]>/", envp[strlen(envp) - 1]) ? "/" : "", - "NetHack.cnf"); - set_configfile_name(tmp_config); - if ((fp = fopen(configfile, "r")) != (FILE *) 0) - return fp; -#else /* should be only UNIX left */ - envp = nh_getenv("HOME"); - if (!envp) - Strcpy(tmp_config, ".nethackrc"); - else - Sprintf(tmp_config, "%s/%s", envp, ".nethackrc"); - - set_configfile_name(tmp_config); - if ((fp = fopen(configfile, "r")) != (FILE *) 0) - return fp; -#if defined(__APPLE__) /* UNIX+__APPLE__ => OSX || MacOS */ - /* try an alternative */ - if (envp) { - /* keep 'tmp_config' intact here; if alternates fail, use it to - restore configfile[] to its preferred setting (".nethackrc") */ - char alt_config[sizeof tmp_config]; - - /* OSX-style configuration settings */ - Snprintf(alt_config, sizeof alt_config, "%s/%s", envp, - "Library/Preferences/NetHack Defaults"); - set_configfile_name(alt_config); - if ((fp = fopen(configfile, "r")) != (FILE *) 0) - return fp; - /* may be easier for user to edit if filename has '.txt' suffix */ - Snprintf(alt_config, sizeof alt_config, "%s/%s", envp, - "Library/Preferences/NetHack Defaults.txt"); - set_configfile_name(alt_config); - if ((fp = fopen(configfile, "r")) != (FILE *) 0) - return fp; - /* couldn't open either of the alternate names; for use in - messages, put 'configfile' back to the normal value rather than - leaving it set to last alternate; retry open() to reset 'errno' */ - set_configfile_name(tmp_config); - if ((fp = fopen(configfile, "r")) != (FILE *) 0) - return fp; - } -#endif /*__APPLE__*/ - if (errno != ENOENT) { - const char *details; - - /* e.g., problems when setuid NetHack can't search home - directory restricted to user */ -#if defined(NHSTDC) && !defined(NOTSTDC) - if ((details = strerror(errno)) == 0) -#endif - details = ""; - raw_printf("Couldn't open default config file %s %s(%d).", - configfile, details, errno); - wait_synch(); - } -#endif /* !VMS => Unix */ -#endif /* !(MICRO || MAC || __BEOS__ || WIN32) */ - return (FILE *) 0; -} - -/* - * Retrieve a list of integers from buf into a uchar array. - * - * NOTE: zeros are inserted unless modlist is TRUE, in which case the list - * location is unchanged. Callers must handle zeros if modlist is FALSE. - */ -staticfn int -get_uchars(char *bufp, /* current pointer */ - uchar *list, /* return list */ - boolean modlist, /* TRUE: list is being modified in place */ - int size, /* return list size */ - const char *name) /* name of option for error message */ -{ - unsigned int num = 0; - int count = 0; - boolean havenum = FALSE; - - while (1) { - switch (*bufp) { - case ' ': - case '\0': - case '\t': - case '\n': - if (havenum) { - /* if modifying in place, don't insert zeros */ - if (num || !modlist) - list[count] = num; - count++; - num = 0; - havenum = FALSE; - } - if (count == size || !*bufp) - return count; - bufp++; - break; - - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - havenum = TRUE; - num = num * 10 + (*bufp - '0'); - bufp++; - break; - - case '\\': - goto gi_error; - break; - - default: - gi_error: - raw_printf("Syntax error in %s", name); - wait_synch(); - return count; - } - } - /*NOTREACHED*/ -} - -#ifdef NOCWD_ASSUMPTIONS -staticfn void -adjust_prefix(char *bufp, int prefixid) -{ - char *ptr; - - if (!bufp) - return; -#ifdef WIN32 - if (fqn_prefix_locked[prefixid]) - return; -#endif - /* Backward compatibility, ignore trailing ;n */ - if ((ptr = strchr(bufp, ';')) != 0) - *ptr = '\0'; - if (strlen(bufp) > 0) { - gf.fqn_prefix[prefixid] = (char *) alloc(strlen(bufp) + 2); - Strcpy(gf.fqn_prefix[prefixid], bufp); - append_slash(gf.fqn_prefix[prefixid]); - } -} -#endif - -/* Choose at random one of the sep separated parts from str. Mangles str. */ -staticfn char * -choose_random_part(char *str, char sep) -{ - int nsep = 1; - int csep; - int len = 0; - char *begin = str; - - if (!str) - return (char *) 0; - - while (*str) { - if (*str == sep) - nsep++; - str++; - } - csep = rn2(nsep); - str = begin; - while ((csep > 0) && *str) { - str++; - if (*str == sep) - csep--; - } - if (*str) { - if (*str == sep) - str++; - begin = str; - while (*str && *str != sep) { - str++; - len++; - } - *str = '\0'; - if (len) - return begin; - } - return (char *) 0; -} - -staticfn void -free_config_sections(void) -{ - if (gc.config_section_chosen) { - free(gc.config_section_chosen); - gc.config_section_chosen = NULL; - } - if (gc.config_section_current) { - free(gc.config_section_current); - gc.config_section_current = NULL; - } -} - -/* check for " [ anything-except-bracket-or-empty ] # arbitrary-comment" - with spaces optional; returns pointer to "anything-except..." (with - trailing " ] #..." stripped) if ok, otherwise Null */ -staticfn char * -is_config_section( - char *str) /* trailing spaces are stripped, ']' too iff result is good */ -{ - char *a, *c, *z; - - /* remove any spaces at start and end; won't significantly interfere - with echoing the string in a config error message, if warranted */ - a = trimspaces(str); - /* first character should be open square bracket; set pointer past it */ - if (*a++ != '[') - return (char *) 0; - /* last character should be close bracket, ignoring any comment */ - z = strchr(a, ']'); - if (!z) - return (char *) 0; - /* comment, if present, can be preceded by spaces */ - for (c = z + 1; *c == ' '; ++c) - continue; - if (*c && *c != '#') - return (char *) 0; - /* we now know that result is good; there won't be a config error - message so we can modify the input string */ - *z = '\0'; - /* 'a' points past '[' and the string ends where ']' was; remove any - spaces between '[' and choice-start and between choice-end and ']' */ - return trimspaces(a); -} - -staticfn boolean -handle_config_section(char *buf) -{ - char *sect = is_config_section(buf); - - if (sect) { - if (gc.config_section_current) - free(gc.config_section_current), gc.config_section_current = 0; - /* is_config_section() removed brackets from 'sect' */ - if (!gc.config_section_chosen) { - config_error_add("Section \"[%s]\" without CHOOSE", sect); - return TRUE; - } - if (*sect) { /* got a section name */ - gc.config_section_current = dupstr(sect); - debugpline1("set config section: '%s'", - gc.config_section_current); - } else { /* empty section name => end of sections */ - free_config_sections(); - debugpline0("unset config section"); - } - return TRUE; - } - - if (gc.config_section_current) { - if (!gc.config_section_chosen) - return TRUE; - if (strcmp(gc.config_section_current, gc.config_section_chosen)) - return TRUE; - } - return FALSE; -} - -#define match_varname(INP, NAM, LEN) match_optname(INP, NAM, LEN, TRUE) - -/* find the '=' or ':' */ -staticfn char * -find_optparam(const char *buf) -{ - char *bufp, *altp; - - bufp = strchr(buf, '='); - altp = strchr(buf, ':'); - if (!bufp || (altp && altp < bufp)) - bufp = altp; - - return bufp; -} - -staticfn boolean -cnf_line_OPTIONS(char *origbuf) -{ - char *bufp = find_optparam(origbuf); - - ++bufp; /* skip '='; parseoptions() handles spaces */ - return parseoptions(bufp, TRUE, TRUE); -} - -staticfn boolean -cnf_line_AUTOPICKUP_EXCEPTION(char *bufp) -{ - add_autopickup_exception(bufp); - return TRUE; -} - -staticfn boolean -cnf_line_BINDINGS(char *bufp) -{ - return parsebindings(bufp); -} - -staticfn boolean -cnf_line_AUTOCOMPLETE(char *bufp) -{ - parseautocomplete(bufp, TRUE); - return TRUE; -} - -staticfn boolean -cnf_line_MSGTYPE(char *bufp) -{ - return msgtype_parse_add(bufp); -} - -staticfn boolean -cnf_line_HACKDIR(char *bufp) -{ -#ifdef NOCWD_ASSUMPTIONS - adjust_prefix(bufp, HACKPREFIX); -#else /*NOCWD_ASSUMPTIONS*/ -#ifdef MICRO - (void) strncpy(gh.hackdir, bufp, PATHLEN - 1); -#else /* MICRO */ - nhUse(bufp); -#endif /* MICRO */ -#endif /*NOCWD_ASSUMPTIONS*/ - return TRUE; -} - -staticfn boolean -cnf_line_LEVELDIR(char *bufp) -{ -#ifdef NOCWD_ASSUMPTIONS - adjust_prefix(bufp, LEVELPREFIX); -#else /*NOCWD_ASSUMPTIONS*/ -#ifdef MICRO - if (strlen(bufp) >= PATHLEN) - bufp[PATHLEN - 1] = '\0'; - Strcpy(g.permbones, bufp); - if (!ramdisk_specified || !*levels) - Strcpy(levels, bufp); - gr.ramdisk = (strcmp(g.permbones, levels) != 0); -#else /* MICRO */ - nhUse(bufp); -#endif /* MICRO */ -#endif /*NOCWD_ASSUMPTIONS*/ - return TRUE; -} - -staticfn boolean -cnf_line_SAVEDIR(char *bufp) -{ -#ifdef NOCWD_ASSUMPTIONS - adjust_prefix(bufp, SAVEPREFIX); -#else /*NOCWD_ASSUMPTIONS*/ -#ifdef MICRO - char *ptr; - - if ((ptr = strchr(bufp, ';')) != 0) { - *ptr = '\0'; - } - - (void) strncpy(gs.SAVEP, bufp, SAVESIZE - 1); - append_slash(gs.SAVEP); -#else /* MICRO */ - nhUse(bufp); -#endif /* MICRO */ -#endif /*NOCWD_ASSUMPTIONS*/ - return TRUE; -} - -staticfn boolean -cnf_line_BONESDIR(char *bufp) -{ -#ifdef NOCWD_ASSUMPTIONS - adjust_prefix(bufp, BONESPREFIX); -#else - nhUse(bufp); -#endif - return TRUE; -} - -staticfn boolean -cnf_line_DATADIR(char *bufp) -{ -#ifdef NOCWD_ASSUMPTIONS - adjust_prefix(bufp, DATAPREFIX); -#else - nhUse(bufp); -#endif - return TRUE; -} - -staticfn boolean -cnf_line_SCOREDIR(char *bufp) -{ -#ifdef NOCWD_ASSUMPTIONS - adjust_prefix(bufp, SCOREPREFIX); -#else - nhUse(bufp); -#endif - return TRUE; -} - -staticfn boolean -cnf_line_LOCKDIR(char *bufp) -{ -#ifdef NOCWD_ASSUMPTIONS - adjust_prefix(bufp, LOCKPREFIX); -#else - nhUse(bufp); -#endif - return TRUE; -} - -staticfn boolean -cnf_line_CONFIGDIR(char *bufp) -{ -#ifdef NOCWD_ASSUMPTIONS - adjust_prefix(bufp, CONFIGPREFIX); -#else - nhUse(bufp); -#endif - return TRUE; -} - -staticfn boolean -cnf_line_TROUBLEDIR(char *bufp) -{ -#ifdef NOCWD_ASSUMPTIONS - adjust_prefix(bufp, TROUBLEPREFIX); -#else - nhUse(bufp); -#endif - return TRUE; -} - -staticfn boolean -cnf_line_NAME(char *bufp) -{ - (void) strncpy(svp.plname, bufp, PL_NSIZ - 1); - return TRUE; -} - -staticfn boolean -cnf_line_ROLE(char *bufp) -{ - int len; - - if ((len = str2role(bufp)) >= 0) - flags.initrole = len; - return TRUE; -} - -staticfn boolean -cnf_line_dogname(char *bufp) -{ - (void) strncpy(gd.dogname, bufp, PL_PSIZ - 1); - return TRUE; -} - -staticfn boolean -cnf_line_catname(char *bufp) -{ - (void) strncpy(gc.catname, bufp, PL_PSIZ - 1); - return TRUE; -} - -#ifdef SYSCF - -staticfn boolean -cnf_line_WIZARDS(char *bufp) -{ - if (sysopt.wizards) - free((genericptr_t) sysopt.wizards); - sysopt.wizards = dupstr(bufp); - if (strlen(sysopt.wizards) && strcmp(sysopt.wizards, "*")) { - /* pre-format WIZARDS list now; it's displayed during a panic - and since that panic might be due to running out of memory, - we don't want to risk attempting to allocate any memory then */ - if (sysopt.fmtd_wizard_list) - free((genericptr_t) sysopt.fmtd_wizard_list); - sysopt.fmtd_wizard_list = build_english_list(sysopt.wizards); - } - return TRUE; -} - -staticfn boolean -cnf_line_SHELLERS(char *bufp) -{ - if (sysopt.shellers) - free((genericptr_t) sysopt.shellers); - sysopt.shellers = dupstr(bufp); - return TRUE; -} - -staticfn boolean -cnf_line_MSGHANDLER(char *bufp) -{ - if (sysopt.msghandler) - free((genericptr_t) sysopt.msghandler); - sysopt.msghandler = dupstr(bufp); - return TRUE; -} - -staticfn boolean -cnf_line_EXPLORERS(char *bufp) -{ - if (sysopt.explorers) - free((genericptr_t) sysopt.explorers); - sysopt.explorers = dupstr(bufp); - return TRUE; -} - -staticfn boolean -cnf_line_DEBUGFILES(char *bufp) -{ - /* might already have a vaule from getenv("DEBUGFILES"); - if so, ignore this value from SYSCF */ - if (!sysopt.env_dbgfl) { - if (sysopt.debugfiles) - free((genericptr_t) sysopt.debugfiles); - sysopt.debugfiles = dupstr(bufp); - } - return TRUE; -} - -staticfn boolean -cnf_line_DUMPLOGFILE(char *bufp) -{ -#ifdef DUMPLOG - if (sysopt.dumplogfile) - free((genericptr_t) sysopt.dumplogfile); - sysopt.dumplogfile = dupstr(bufp); -#else - nhUse(bufp); -#endif /*DUMPLOG*/ - return TRUE; -} - -staticfn boolean -cnf_line_GENERICUSERS(char *bufp) -{ - if (sysopt.genericusers) - free((genericptr_t) sysopt.genericusers); - sysopt.genericusers = dupstr(bufp); - return TRUE; -} - -staticfn boolean -cnf_line_BONES_POOLS(char *bufp) -{ - /* max value of 10 guarantees (N % bones.pools) will be one digit - so we don't lose control of the length of bones file names */ - int n = atoi(bufp); - - sysopt.bones_pools = (n <= 0) ? 0 : min(n, 10); - /* note: right now bones_pools==0 is the same as bones_pools==1, - but we could change that and make bones_pools==0 become an - indicator to suppress bones usage altogether */ - return TRUE; -} - -staticfn boolean -cnf_line_SUPPORT(char *bufp) -{ - if (sysopt.support) - free((genericptr_t) sysopt.support); - sysopt.support = dupstr(bufp); - return TRUE; -} - -staticfn boolean -cnf_line_RECOVER(char *bufp) -{ - if (sysopt.recover) - free((genericptr_t) sysopt.recover); - sysopt.recover = dupstr(bufp); - return TRUE; -} - -staticfn boolean -cnf_line_CHECK_SAVE_UID(char *bufp) -{ - int n = atoi(bufp); - - sysopt.check_save_uid = n; - return TRUE; -} - -staticfn boolean -cnf_line_CHECK_PLNAME(char *bufp) -{ - int n = atoi(bufp); - - sysopt.check_plname = n; - return TRUE; -} - -staticfn boolean -cnf_line_SEDUCE(char *bufp) -{ - int n = !!atoi(bufp); /* XXX this could be tighter */ -#ifdef SYSCF - int src = iflags.parse_config_file_src; - boolean in_sysconf = (src == set_in_sysconf); -#else - boolean in_sysconf = FALSE; -#endif - - /* allow anyone to disable it but can only enable it in sysconf - or as a no-op for the user when sysconf hasn't disabled it */ - if (!in_sysconf && !sysopt.seduce && n != 0) { - config_error_add("Illegal value in SEDUCE"); - n = 0; - } - sysopt.seduce = n; - sysopt_seduce_set(sysopt.seduce); - return TRUE; -} - -staticfn boolean -cnf_line_HIDEUSAGE(char *bufp) -{ - int n = !!atoi(bufp); - - sysopt.hideusage = n; - return TRUE; -} - -staticfn boolean -cnf_line_MAXPLAYERS(char *bufp) -{ - int n = atoi(bufp); - - /* XXX to get more than 25, need to rewrite all lock code */ - if (n < 0 || n > 25) { - config_error_add("Illegal value in MAXPLAYERS (maximum is 25)"); - n = 5; - } - sysopt.maxplayers = n; - return TRUE; -} - -staticfn boolean -cnf_line_PERSMAX(char *bufp) -{ - int n = atoi(bufp); - - if (n < 1) { - config_error_add("Illegal value in PERSMAX (minimum is 1)"); - n = 0; - } - sysopt.persmax = n; - return TRUE; -} - -staticfn boolean -cnf_line_PERS_IS_UID(char *bufp) -{ - int n = atoi(bufp); - - if (n != 0 && n != 1) { - config_error_add("Illegal value in PERS_IS_UID (must be 0 or 1)"); - n = 0; - } - sysopt.pers_is_uid = n; - return TRUE; -} - -staticfn boolean -cnf_line_ENTRYMAX(char *bufp) -{ - int n = atoi(bufp); - - if (n < 10) { - config_error_add("Illegal value in ENTRYMAX (minimum is 10)"); - n = 10; - } - sysopt.entrymax = n; - return TRUE; -} - -staticfn boolean -cnf_line_POINTSMIN(char *bufp) -{ - int n = atoi(bufp); - - if (n < 1) { - config_error_add("Illegal value in POINTSMIN (minimum is 1)"); - n = 100; - } - sysopt.pointsmin = n; - return TRUE; -} - -staticfn boolean -cnf_line_MAX_STATUENAME_RANK(char *bufp) -{ - int n = atoi(bufp); - - if (n < 1) { - config_error_add("Illegal value in MAX_STATUENAME_RANK" - " (minimum is 1)"); - n = 10; - } - sysopt.tt_oname_maxrank = n; - return TRUE; -} - -staticfn boolean -cnf_line_LIVELOG(char *bufp) -{ - /* using 0 for base accepts "dddd" as decimal provided that first 'd' - isn't '0', "0xhhhh" as hexadecimal, and "0oooo" as octal; ignores - any trailing junk, including '8' or '9' for leading '0' octal */ - long L = strtol(bufp, NULL, 0); - - if (L < 0L || L > 0xffffL) { - config_error_add("Illegal value for LIVELOG" - " (must be between 0 and 0xFFFF)."); - return 0; - } - sysopt.livelog = L; - return TRUE; -} - -staticfn boolean -cnf_line_PANICTRACE_LIBC(char *bufp) -{ - int n = atoi(bufp); - -#if defined(PANICTRACE) && defined(PANICTRACE_LIBC) - if (n < 0 || n > 2) { - config_error_add("Illegal value in PANICTRACE_LIBC (not 0,1,2)"); - n = 0; - } -#endif - sysopt.panictrace_libc = n; - return TRUE; -} - -staticfn boolean -cnf_line_PANICTRACE_GDB(char *bufp) -{ - int n = atoi(bufp); - -#if defined(PANICTRACE) - if (n < 0 || n > 2) { - config_error_add("Illegal value in PANICTRACE_GDB (not 0,1,2)"); - n = 0; - } -#endif - sysopt.panictrace_gdb = n; - return TRUE; -} - -staticfn boolean -cnf_line_GDBPATH(char *bufp) -{ -#if defined(PANICTRACE) && !defined(VMS) - if (!file_exists(bufp)) { - config_error_add("File specified in GDBPATH does not exist"); - return FALSE; - } -#endif - if (sysopt.gdbpath) - free((genericptr_t) sysopt.gdbpath); - sysopt.gdbpath = dupstr(bufp); - return TRUE; -} - -staticfn boolean -cnf_line_GREPPATH(char *bufp) -{ -#if defined(PANICTRACE) && !defined(VMS) - if (!file_exists(bufp)) { - config_error_add("File specified in GREPPATH does not exist"); - return FALSE; - } -#endif - if (sysopt.greppath) - free((genericptr_t) sysopt.greppath); - sysopt.greppath = dupstr(bufp); - return TRUE; -} - -staticfn boolean -cnf_line_CRASHREPORTURL(char *bufp) -{ - if (sysopt.crashreporturl) - free((genericptr_t) sysopt.crashreporturl); - sysopt.crashreporturl = dupstr(bufp); - return TRUE; -} - -staticfn boolean -cnf_line_SAVEFORMAT(char *bufp) -{ - parseformat(sysopt.saveformat, bufp); - return TRUE; -} - -staticfn boolean -cnf_line_BONESFORMAT(char *bufp) -{ - parseformat(sysopt.bonesformat, bufp); - return TRUE; -} - -staticfn boolean -cnf_line_ACCESSIBILITY(char *bufp) -{ - int n = atoi(bufp); - - if (n < 0 || n > 1) { - config_error_add("Illegal value in ACCESSIBILITY (not 0,1)"); - n = 0; - } - sysopt.accessibility = n; - return TRUE; -} - -staticfn boolean -cnf_line_PORTABLE_DEVICE_PATHS(char *bufp) -{ -#ifdef WIN32 - int n = atoi(bufp); - - if (n < 0 || n > 1) { - config_error_add("Illegal value in PORTABLE_DEVICE_PATHS" - " (not 0 or 1)"); - n = 0; - } - sysopt.portable_device_paths = n; -#else /* Windows-only directive encountered by non-Windows config */ - nhUse(bufp); - config_error_add("PORTABLE_DEVICE_PATHS is not supported"); -#endif - return TRUE; -} - -#endif /* SYSCF */ - -staticfn boolean -cnf_line_BOULDER(char *bufp) -{ - (void) get_uchars(bufp, &go.ov_primary_syms[SYM_BOULDER + SYM_OFF_X], - TRUE, 1, "BOULDER"); - return TRUE; -} - -staticfn boolean -cnf_line_MENUCOLOR(char *bufp) -{ - return add_menu_coloring(bufp); -} - -staticfn boolean -cnf_line_HILITE_STATUS(char *bufp) -{ -#ifdef STATUS_HILITES - return parse_status_hl1(bufp, TRUE); -#else - nhUse(bufp); - return TRUE; -#endif -} - -staticfn boolean -cnf_line_WARNINGS(char *bufp) -{ - uchar translate[MAXPCHARS]; - - (void) get_uchars(bufp, translate, FALSE, WARNCOUNT, "WARNINGS"); - assign_warnings(translate); - return TRUE; -} - -staticfn boolean -cnf_line_ROGUESYMBOLS(char *bufp) -{ - if (parsesymbols(bufp, ROGUESET)) { - switch_symbols(TRUE); - return TRUE; - } - config_error_add("Error in ROGUESYMBOLS definition '%s'", bufp); - return FALSE; -} - -staticfn boolean -cnf_line_SYMBOLS(char *bufp) -{ - if (parsesymbols(bufp, PRIMARYSET)) { - switch_symbols(TRUE); - return TRUE; - } - config_error_add("Error in SYMBOLS definition '%s'", bufp); - return FALSE; -} - -staticfn boolean -cnf_line_WIZKIT(char *bufp) -{ - (void) strncpy(gw.wizkit, bufp, WIZKIT_MAX - 1); - return TRUE; -} - -#ifdef USER_SOUNDS -staticfn boolean -cnf_line_SOUNDDIR(char *bufp) -{ - if (sounddir) - free((genericptr_t) sounddir); - sounddir = dupstr(bufp); - return TRUE; -} - -staticfn boolean -cnf_line_SOUND(char *bufp) -{ - add_sound_mapping(bufp); - return TRUE; -} -#endif /*USER_SOUNDS*/ - -staticfn boolean -cnf_line_QT_TILEWIDTH(char *bufp) -{ -#ifdef QT_GRAPHICS - extern char *qt_tilewidth; - - if (qt_tilewidth == NULL) - qt_tilewidth = dupstr(bufp); -#else - nhUse(bufp); -#endif - return TRUE; -} - -staticfn boolean -cnf_line_QT_TILEHEIGHT(char *bufp) -{ -#ifdef QT_GRAPHICS - extern char *qt_tileheight; - - if (qt_tileheight == NULL) - qt_tileheight = dupstr(bufp); -#else - nhUse(bufp); -#endif - return TRUE; -} - -staticfn boolean -cnf_line_QT_FONTSIZE(char *bufp) -{ -#ifdef QT_GRAPHICS - extern char *qt_fontsize; - - if (qt_fontsize == NULL) - qt_fontsize = dupstr(bufp); -#else - nhUse(bufp); -#endif - return TRUE; -} - -staticfn boolean -cnf_line_QT_COMPACT(char *bufp) -{ -#ifdef QT_GRAPHICS - extern int qt_compact_mode; - - qt_compact_mode = atoi(bufp); -#else - nhUse(bufp); -#endif - return TRUE; -} - -typedef boolean (*config_line_stmt_func)(char *); - -/* normal */ -#define CNFL_N(n, l) { #n, l, FALSE, FALSE, cnf_line_##n } -/* normal, alias */ -#define CNFL_NA(n, l, f) { #n, l, FALSE, FALSE, cnf_line_##f } -/* sysconf only */ -#define CNFL_S(n, l) { #n, l, TRUE, FALSE, cnf_line_##n } - -static const struct match_config_line_stmt { - const char *name; - int len; - boolean syscnf_only; - boolean origbuf; - config_line_stmt_func fn; -} config_line_stmt[] = { - /* OPTIONS handled separately */ - { "OPTIONS", 4, FALSE, TRUE, cnf_line_OPTIONS }, - CNFL_N(AUTOPICKUP_EXCEPTION, 5), - CNFL_N(BINDINGS, 4), - CNFL_N(AUTOCOMPLETE, 5), - CNFL_N(MSGTYPE, 7), - CNFL_N(HACKDIR, 4), - CNFL_N(LEVELDIR, 4), - CNFL_NA(LEVELS, 4, LEVELDIR), - CNFL_N(SAVEDIR, 4), - CNFL_N(BONESDIR, 5), - CNFL_N(DATADIR, 4), - CNFL_N(SCOREDIR, 4), - CNFL_N(LOCKDIR, 4), - CNFL_N(CONFIGDIR, 4), - CNFL_N(TROUBLEDIR, 4), - CNFL_N(NAME, 4), - CNFL_N(ROLE, 4), - CNFL_NA(CHARACTER, 4, ROLE), - CNFL_N(dogname, 3), - CNFL_N(catname, 3), -#ifdef SYSCF - CNFL_S(WIZARDS, 7), - CNFL_S(SHELLERS, 8), - CNFL_S(MSGHANDLER, 9), - CNFL_S(EXPLORERS, 7), - CNFL_S(DEBUGFILES, 5), - CNFL_S(DUMPLOGFILE, 7), - CNFL_S(GENERICUSERS, 12), - CNFL_S(BONES_POOLS, 10), - CNFL_S(SUPPORT, 7), - CNFL_S(RECOVER, 7), - CNFL_S(CHECK_SAVE_UID, 14), - CNFL_S(CHECK_PLNAME, 12), - CNFL_S(SEDUCE, 6), - CNFL_S(HIDEUSAGE, 9), - CNFL_S(MAXPLAYERS, 10), - CNFL_S(PERSMAX, 7), - CNFL_S(PERS_IS_UID, 11), - CNFL_S(ENTRYMAX, 8), - CNFL_S(POINTSMIN, 9), - CNFL_S(MAX_STATUENAME_RANK, 10), - CNFL_S(LIVELOG, 7), - CNFL_S(PANICTRACE_LIBC, 15), - CNFL_S(PANICTRACE_GDB, 14), - CNFL_S(CRASHREPORTURL, 13), - CNFL_S(GDBPATH, 7), - CNFL_S(GREPPATH, 7), - CNFL_S(SAVEFORMAT, 10), - CNFL_S(BONESFORMAT, 11), - CNFL_S(ACCESSIBILITY, 13), - CNFL_S(PORTABLE_DEVICE_PATHS, 8), -#endif /*SYSCF*/ - CNFL_N(BOULDER, 3), - CNFL_N(MENUCOLOR, 9), - CNFL_N(HILITE_STATUS, 6), - CNFL_N(WARNINGS, 5), - CNFL_N(ROGUESYMBOLS, 4), - CNFL_N(SYMBOLS, 4), - CNFL_N(WIZKIT, 6), -#ifdef USER_SOUNDS - CNFL_N(SOUNDDIR, 8), - CNFL_N(SOUND, 5), -#endif /*USER_SOUNDS*/ - CNFL_N(QT_TILEWIDTH, 12), - CNFL_N(QT_TILEHEIGHT, 13), - CNFL_N(QT_FONTSIZE, 11), - CNFL_N(QT_COMPACT, 10) -}; - -#undef CNFL_N -#undef CNFL_NA -#undef CNFL_S - -boolean -parse_config_line(char *origbuf) -{ -#if defined(MICRO) && !defined(NOCWD_ASSUMPTIONS) - static boolean ramdisk_specified = FALSE; -#endif -#ifdef SYSCF - int src = iflags.parse_config_file_src; - boolean in_sysconf = (src == set_in_sysconf); -#endif - char *bufp, buf[4 * BUFSZ]; - int i; - - while (*origbuf == ' ' || *origbuf == '\t') /* skip leading whitespace */ - ++origbuf; /* (caller probably already did this) */ - (void) strncpy(buf, origbuf, sizeof buf - 1); - buf[sizeof buf - 1] = '\0'; /* strncpy not guaranteed to NUL terminate */ - /* convert any tab to space, condense consecutive spaces into one, - remove leading and trailing spaces (exception: if there is nothing - but spaces, one of them will be kept even though it leads/trails) */ - mungspaces(buf); - - /* find the '=' or ':' */ - bufp = find_optparam(buf); - if (!bufp) { - config_error_add("Not a config statement, missing '='"); - return FALSE; - } - /* skip past '=', then space between it and value, if any */ - ++bufp; - if (*bufp == ' ') - ++bufp; - - for (i = 0; i < SIZE(config_line_stmt); i++) { -#ifdef SYSCF - if (config_line_stmt[i].syscnf_only && !in_sysconf) - continue; -#endif - if (match_varname(buf, config_line_stmt[i].name, - config_line_stmt[i].len)) { - char *parm = config_line_stmt[i].origbuf ? origbuf : bufp; - - return config_line_stmt[i].fn(parm); - } - } - - config_error_add("Unknown config statement"); - return FALSE; -} - -#ifdef USER_SOUNDS -boolean -can_read_file(const char *filename) -{ - return (boolean) (access(filename, 4) == 0); -} -#endif /* USER_SOUNDS */ - -struct _config_error_errmsg { - int line_num; - char *errormsg; - struct _config_error_errmsg *next; -}; - -struct _config_error_frame { - int line_num; - int num_errors; - boolean origline_shown; - boolean fromfile; - boolean secure; - char origline[4 * BUFSZ]; - char source[BUFSZ]; - struct _config_error_frame *next; -}; - -static struct _config_error_frame *config_error_data = 0; -static struct _config_error_errmsg *config_error_msg = 0; - -void -config_error_init(boolean from_file, const char *sourcename, boolean secure) -{ - struct _config_error_frame *tmp = (struct _config_error_frame *) - alloc(sizeof *tmp); - - tmp->line_num = 0; - tmp->num_errors = 0; - tmp->origline_shown = FALSE; - tmp->fromfile = from_file; - tmp->secure = secure; - tmp->origline[0] = '\0'; - if (sourcename && sourcename[0]) { - (void) strncpy(tmp->source, sourcename, sizeof (tmp->source) - 1); - tmp->source[sizeof (tmp->source) - 1] = '\0'; - } else - tmp->source[0] = '\0'; - - tmp->next = config_error_data; - config_error_data = tmp; - program_state.config_error_ready = TRUE; -} - -staticfn boolean -config_error_nextline(const char *line) -{ - struct _config_error_frame *ced = config_error_data; - - if (!ced) - return FALSE; - - if (ced->num_errors && ced->secure) - return FALSE; - - ced->line_num++; - ced->origline_shown = FALSE; - if (line && line[0]) { - (void) strncpy(ced->origline, line, sizeof (ced->origline) - 1); - ced->origline[sizeof (ced->origline) - 1] = '\0'; - } else - ced->origline[0] = '\0'; - - return TRUE; -} - -int -l_get_config_errors(lua_State *L) -{ - struct _config_error_errmsg *dat = config_error_msg; - struct _config_error_errmsg *tmp; - int idx = 1; - - lua_newtable(L); - - while (dat) { - lua_pushinteger(L, idx++); - lua_newtable(L); - nhl_add_table_entry_int(L, "line", dat->line_num); - nhl_add_table_entry_str(L, "error", dat->errormsg); - lua_settable(L, -3); - tmp = dat->next; - free(dat->errormsg); - dat->errormsg = (char *) 0; - free(dat); - dat = tmp; - } - config_error_msg = (struct _config_error_errmsg *) 0; - - return 1; -} - -/* varargs 'config_error_add()' moved to pline.c */ -void -config_erradd(const char *buf) -{ - char lineno[QBUFSZ]; - const char *punct; - - if (!buf || !*buf) - buf = "Unknown error"; - - /* if buf[] doesn't end in a period, exclamation point, or question mark, - we'll include a period (in the message, not appended to buf[]) */ - punct = c_eos((char *) buf) - 1; /* eos(buf)-1 is valid */ - punct = strchr(".!?", *punct) ? "" : "."; - - if (!program_state.config_error_ready) { - /* either very early, where pline() will use raw_print(), or - player gave bad value when prompted by interactive 'O' command */ - pline("%s%s%s", !iflags.window_inited ? "config_error_add: " : "", - buf, punct); - wait_synch(); - return; - } - - if (iflags.in_lua) { - struct _config_error_errmsg *dat - = (struct _config_error_errmsg *) alloc(sizeof *dat); - - dat->next = config_error_msg; - dat->line_num = config_error_data->line_num; - dat->errormsg = dupstr(buf); - config_error_msg = dat; - return; - } - - config_error_data->num_errors++; - if (!config_error_data->origline_shown && !config_error_data->secure) { - pline("\n%s", config_error_data->origline); - config_error_data->origline_shown = TRUE; - } - if (config_error_data->line_num > 0 && !config_error_data->secure) { - Sprintf(lineno, "Line %d: ", config_error_data->line_num); - } else - lineno[0] = '\0'; - - pline("%s %s%s%s", config_error_data->secure ? "Error:" : " *", - lineno, buf, punct); -} - -int -config_error_done(void) -{ - int n; - struct _config_error_frame *tmp = config_error_data; - - if (!config_error_data) - return 0; - n = config_error_data->num_errors; -#ifndef USER_SOUNDS - if (gn.no_sound_notified > 0) { - /* no USER_SOUNDS; config_error_add() was called once for first - SOUND or SOUNDDIR entry seen, then skipped for any others; - include those skipped ones in the total error count */ - n += (gn.no_sound_notified - 1); - gn.no_sound_notified = 0; - } -#endif - if (n) { - boolean cmdline = !strcmp(config_error_data->source, "command line"); - - pline("\n%d error%s %s %s.\n", n, plur(n), cmdline ? "on" : "in", - *config_error_data->source ? config_error_data->source - : configfile); - wait_synch(); - } - config_error_data = tmp->next; - free(tmp); - program_state.config_error_ready = (config_error_data != 0); - return n; -} - -boolean -read_config_file(const char *filename, int src) -{ - FILE *fp; - boolean rv = TRUE; - - if (!(fp = fopen_config_file(filename, src))) - return FALSE; - - /* begin detection of duplicate configfile options */ - reset_duplicate_opt_detection(); - free_config_sections(); - iflags.parse_config_file_src = src; - - rv = parse_conf_file(fp, parse_config_line); - (void) fclose(fp); - - free_config_sections(); - /* turn off detection of duplicate configfile options */ - reset_duplicate_opt_detection(); - return rv; -} - -struct _cnf_parser_state { - char *inbuf; - unsigned inbufsz; - int rv; - char *ep; - char *buf; - boolean skip, morelines; - boolean cont; - boolean pbreak; -}; - -/* Initialize config parser data */ -staticfn void -cnf_parser_init(struct _cnf_parser_state *parser) -{ - parser->rv = TRUE; /* assume successful parse */ - parser->ep = parser->buf = (char *) 0; - parser->skip = FALSE; - parser->morelines = FALSE; - parser->inbufsz = 4 * BUFSZ; - parser->inbuf = (char *) alloc(parser->inbufsz); - parser->cont = FALSE; - parser->pbreak = FALSE; - memset(parser->inbuf, 0, parser->inbufsz); -} - -/* caller has finished with 'parser' (except for 'rv' so leave that intact) */ -staticfn void -cnf_parser_done(struct _cnf_parser_state *parser) -{ - parser->ep = 0; /* points into parser->inbuf, so becoming stale */ - if (parser->inbuf) - free(parser->inbuf), parser->inbuf = 0; - if (parser->buf) - free(parser->buf), parser->buf = 0; -} - -/* - * Parse config buffer, handling comments, empty lines, config sections, - * CHOOSE, and line continuation, calling proc for every valid line. - * - * Continued lines are merged together with one space in between. - */ -staticfn void -parse_conf_buf(struct _cnf_parser_state *p, boolean (*proc)(char *arg)) -{ - p->cont = FALSE; - p->pbreak = FALSE; - p->ep = strchr(p->inbuf, '\n'); - if (p->skip) { /* in case previous line was too long */ - if (p->ep) - p->skip = FALSE; /* found newline; next line is normal */ - } else { - if (!p->ep) { /* newline missing */ - if (strlen(p->inbuf) < (p->inbufsz - 2)) { - /* likely the last line of file is just - missing a newline; process it anyway */ - p->ep = eos(p->inbuf); - } else { - config_error_add("Line too long, skipping"); - p->skip = TRUE; /* discard next fgets */ - } - } else { - *p->ep = '\0'; /* remove newline */ - } - if (p->ep) { - char *tmpbuf = (char *) 0; - int len; - boolean ignoreline = FALSE; - boolean oldline = FALSE; - - /* line continuation (trailing '\') */ - p->morelines = (--p->ep >= p->inbuf && *p->ep == '\\'); - if (p->morelines) - *p->ep = '\0'; - - /* trim off spaces at end of line */ - while (p->ep >= p->inbuf - && (*p->ep == ' ' || *p->ep == '\t' || *p->ep == '\r')) - *p->ep-- = '\0'; - - if (!config_error_nextline(p->inbuf)) { - p->rv = FALSE; - if (p->buf) - free(p->buf), p->buf = (char *) 0; - p->pbreak = TRUE; - return; - } - - p->ep = p->inbuf; - while (*p->ep == ' ' || *p->ep == '\t') - ++p->ep; - - /* ignore empty lines and full-line comment lines */ - if (!*p->ep || *p->ep == '#') - ignoreline = TRUE; - - if (p->buf) - oldline = TRUE; - - /* merge now read line with previous ones, if necessary */ - if (!ignoreline) { - len = (int) strlen(p->ep) + 1; /* +1: final '\0' */ - if (p->buf) - len += (int) strlen(p->buf) + 1; /* +1: space */ - tmpbuf = (char *) alloc(len); - *tmpbuf = '\0'; - if (p->buf) { - Strcat(strcpy(tmpbuf, p->buf), " "); - free(p->buf), p->buf = 0; - } - p->buf = strcat(tmpbuf, p->ep); - if (strlen(p->buf) >= p->inbufsz) - p->buf[p->inbufsz - 1] = '\0'; - } - - if (p->morelines || (ignoreline && !oldline)) - return; - - if (handle_config_section(p->buf)) { - free(p->buf), p->buf = (char *) 0; - return; - } - - /* from here onwards, we'll handle buf only */ - - if (match_varname(p->buf, "CHOOSE", 6)) { - char *section; - char *bufp = find_optparam(p->buf); - - if (!bufp) { - config_error_add("Format is CHOOSE=section1" - ",section2,..."); - p->rv = FALSE; - free(p->buf), p->buf = (char *) 0; - return; - } - bufp++; - if (gc.config_section_chosen) - free(gc.config_section_chosen), - gc.config_section_chosen = 0; - section = choose_random_part(bufp, ','); - if (section) { - gc.config_section_chosen = dupstr(section); - } else { - config_error_add("No config section to choose"); - p->rv = FALSE; - } - free(p->buf), p->buf = (char *) 0; - return; - } - - if (!(*proc)(p->buf)) - p->rv = FALSE; - - free(p->buf), p->buf = (char *) 0; - } - } -} - -boolean -parse_conf_str(const char *str, boolean (*proc)(char *arg)) -{ - size_t len; - struct _cnf_parser_state parser; - - cnf_parser_init(&parser); - free_config_sections(); - config_error_init(FALSE, "parse_conf_str", FALSE); - while (str && *str) { - len = 0; - while (*str && len < (parser.inbufsz-1)) { - parser.inbuf[len] = *str; - len++; - str++; - if (parser.inbuf[len-1] == '\n') - break; - } - parser.inbuf[len] = '\0'; - parse_conf_buf(&parser, proc); - if (parser.pbreak) - break; - } - cnf_parser_done(&parser); - - free_config_sections(); - config_error_done(); - return parser.rv; -} - -/* parse_conf_file - * - * Read from file fp, calling parse_conf_buf for each line. - */ -staticfn boolean -parse_conf_file(FILE *fp, boolean (*proc)(char *arg)) -{ - struct _cnf_parser_state parser; - - cnf_parser_init(&parser); - free_config_sections(); - - while (fgets(parser.inbuf, parser.inbufsz, fp)) { - parse_conf_buf(&parser, proc); - if (parser.pbreak) - break; - } - cnf_parser_done(&parser); - - free_config_sections(); - return parser.rv; -} - -#ifdef SYSCF -staticfn void -parseformat(int *arr, char *str) -{ - const char *legal[] = { "historical", "lendian", "ascii" }; - int i, kwi = 0, words = 0; - char *p = str, *keywords[2]; - - while (*p) { - while (*p && isspace((uchar) *p)) { - *p = '\0'; - p++; - } - if (*p) { - words++; - if (kwi < 2) - keywords[kwi++] = p; - } - while (*p && !isspace((uchar) *p)) - p++; - } - if (!words) { - impossible("missing format list"); - return; - } - while (--kwi >= 0) - if (kwi < 2) { - for (i = 0; i < SIZE(legal); ++i) { - if (!strcmpi(keywords[kwi], legal[i])) - arr[kwi] = i + 1; - } - } -} -#endif /* SYSCF */ - -/* ---------- END CONFIG FILE HANDLING ----------- */ - /* ---------- BEGIN WIZKIT FILE HANDLING ----------- */ staticfn FILE * @@ -4621,7 +2785,7 @@ reveal_paths(int code) fqn = fqname(filep, SYSCONFPREFIX, 0); if (fqn) { set_configfile_name(fqn); - filep = configfile; + filep = get_configfile(); } raw_printf(" \"%s\"", filep); if (code == 1) { @@ -4765,7 +2929,7 @@ reveal_paths(int code) Strcat(buf, "/"); } endp = eos(buf); - copynchars(endp, default_configfile, + copynchars(endp, get_default_configfile(), (int) (sizeof buf - 1 - strlen(buf))); #if defined(__APPLE__) /* UNIX+__APPLE__ => MacOSX aka OSX aka macOS */ if (envp) { @@ -4783,7 +2947,7 @@ reveal_paths(int code) if (access(buf, 4) == -1) { /* second alternate failed too, so revert to the original default ("$HOME/.nethackrc") for message */ - copynchars(endp, default_configfile, + copynchars(endp, get_default_configfile(), (int) (sizeof buf - 1 - strlen(buf))); } } @@ -4794,9 +2958,9 @@ reveal_paths(int code) #else /* !UNIX */ fqn = (const char *) 0; #ifdef PREFIXES_IN_USE - fqn = fqname(default_configfile, CONFIGPREFIX, 2); + fqn = fqname(get_default_configfile(), CONFIGPREFIX, 2); #endif - raw_printf(" \"%s\"", fqn ? fqn : default_configfile); + raw_printf(" \"%s\"", fqn ? fqn : get_default_configfile()); #endif /* ?UNIX */ raw_print(""); diff --git a/src/options.c b/src/options.c index 704351790..82e1bafbb 100644 --- a/src/options.c +++ b/src/options.c @@ -111,7 +111,7 @@ static struct allopt_t allopt[SIZE(allopt_init)]; /* use rest of file */ -extern char configfile[]; /* for messages; files.c */ +/* extern char configfile[]; */ /* for messages; files.c */ extern const struct symparse loadsyms[]; #if defined(TOS) extern boolean colors_changed; /* in tos.c */ @@ -457,8 +457,8 @@ ask_do_tutorial(void) boolean norc; int n, pass = 0; - rc = nh_basename(configfile, TRUE); - norc = !strcmp(configfile, "/dev/null"); + rc = nh_basename(get_configfile(), TRUE); + norc = !strcmp(get_configfile(), "/dev/null"); Snprintf(buf, sizeof buf, "Put \"OPTIONS=!tutorial\" in %s to skip this query.", (rc && *rc && !norc) ? rc : "your configuration file"); @@ -6799,10 +6799,10 @@ staticfn void rejectoption(const char *optname) { #ifdef MICRO - pline("\"%s\" settable only from %s.", optname, configfile); + pline("\"%s\" settable only from %s.", optname, get_configfile()); #else pline("%s can be set only from NETHACKOPTIONS or %s.", optname, - configfile); + get_configfile()); #endif } @@ -9474,7 +9474,7 @@ option_help(void) datawin = create_nhwindow(NHW_TEXT); Snprintf(buf, sizeof buf, - "Set options as OPTIONS= in %s", configfile); + "Set options as OPTIONS= in %s", get_configfile()); opt_intro[CONFIG_SLOT] = (const char *) buf; for (i = 0; opt_intro[i]; i++) putstr(datawin, 0, opt_intro[i]); diff --git a/sys/msdos/Makefile.GCC b/sys/msdos/Makefile.GCC index 2828b60f3..069b2679a 100644 --- a/sys/msdos/Makefile.GCC +++ b/sys/msdos/Makefile.GCC @@ -272,31 +272,31 @@ DLBOBJ = $(O)dlb.o VOBJ01 = $(O)allmain.o $(O)alloc.o $(O)apply.o $(O)artifact.o $(O)attrib.o -VOBJ02 = $(O)ball.o $(O)bones.o $(O)botl.o $(O)calendar.o $(O)cmd.o -VOBJ03 = $(O)coloratt.o $(O)date.o $(O)dbridge.o $(O)decl.o $(O)detect.o -VOBJ04 = $(O)dig.o $(O)display.o $(O)do.o $(O)do_name.o $(O)do_wear.o -VOBJ05 = $(O)dog.o $(O)dogmove.o $(O)dokick.o $(O)dothrow.o $(O)drawing.o -VOBJ06 = $(O)dungeon.o $(O)eat.o $(O)end.o $(O)engrave.o $(O)exper.o -VOBJ07 = $(O)explode.o $(O)extralev.o $(O)files.o $(O)fountain.o $(O)getpos.o -VOBJ08 = $(O)glyphs.o $(O)getline.o $(O)hack.o $(O)hacklib.o $(O)insight.o -VOBJ09 = $(O)invent.o $(O)isaac64.o $(O)lock.o $(O)mail.o $(O)main.o -VOBJ10 = $(O)makemon.o $(O)mcastu.o $(O)mdlib.o $(O)mhitm.o $(O)mhitu.o -VOBJ11 = $(O)minion.o $(O)mkmap.o $(O)mklev.o $(O)mkmaze.o $(O)mkobj.o -VOBJ12 = $(O)mkroom.o $(O)mon.o $(O)mondata.o $(O)monmove.o $(O)monst.o -VOBJ13 = $(O)mplayer.o $(O)mthrowu.o $(O)muse.o $(O)music.o $(O)o_init.o -VOBJ14 = $(O)objects.o $(O)objnam.o $(O)options.o $(O)pickup.o $(O)pline.o -VOBJ15 = $(O)polyself.o $(O)potion.o $(O)quest.o $(O)questpgr.o $(O)pager.o -VOBJ16 = $(O)pray.o $(O)priest.o $(O)read.o $(O)rect.o $(O)region.o -VOBJ17 = $(O)report.o $(O)restore.o $(O)rip.o $(O)rnd.o $(O)role.o -VOBJ18 = $(O)rumors.o $(O)save.o $(O)selvar.o $(O)sfstruct.o $(O)shk.o -VOBJ19 = $(O)shknam.o $(O)sit.o $(O)sounds.o $(O)sp_lev.o $(O)spell.o -VOBJ20 = $(O)stairs.o $(O)steal.o $(O)steed.o $(O)symbols.o $(O)sys.o -VOBJ21 = $(O)teleport.o $(O)strutil.o $(O)termcap.o $(O)timeout.o $(O)topl.o -VOBJ22 = $(O)topten.o $(O)trap.o $(O)u_init.o $(O)uhitm.o $(O)utf8map.o -VOBJ23 = $(O)vault.o $(O)track.o $(O)vision.o $(O)weapon.o $(O)were.o -VOBJ24 = $(O)wield.o $(O)windows.o $(O)wintty.o $(O)wizard.o $(O)wizcmds.o -VOBJ25 = $(O)worm.o $(O)worn.o $(O)write.o $(O)zap.o $(O)light.o -VOBJ26 = $(O)dlb.o $(REGEX) +VOBJ02 = $(O)ball.o $(O)bones.o $(O)botl.o $(O)calendar.o $(O)cfgfiles.o +VOBJ03 = $(O)cmd.o $(O)coloratt.o $(O)date.o $(O)dbridge.o $(O)decl.o +VOBJ04 = $(O)detect.o $(O)dig.o $(O)display.o $(O)do.o $(O)do_name.o +VOBJ05 = $(O)do_wear.o $(O)dog.o $(O)dogmove.o $(O)dokick.o $(O)dothrow.o +VOBJ06 = $(O)drawing.o $(O)dungeon.o $(O)eat.o $(O)end.o $(O)engrave.o +VOBJ07 = $(O)exper.o $(O)explode.o $(O)extralev.o $(O)files.o $(O)fountain.o +VOBJ08 = $(O)getpos.o $(O)glyphs.o $(O)getline.o $(O)hack.o $(O)hacklib.o +VOBJ09 = $(O)insight.o $(O)invent.o $(O)isaac64.o $(O)lock.o $(O)mail.o +VOBJ10 = $(O)main.o $(O)makemon.o $(O)mcastu.o $(O)mdlib.o $(O)mhitm.o +VOBJ11 = $(O)mhitu.o $(O)minion.o $(O)mkmap.o $(O)mklev.o $(O)mkmaze.o +VOBJ12 = $(O)mkobj.o $(O)mkroom.o $(O)mon.o $(O)mondata.o $(O)monmove.o +VOBJ13 = $(O)monst.o $(O)mplayer.o $(O)mthrowu.o $(O)muse.o $(O)music.o +VOBJ14 = $(O)o_init.o $(O)objects.o $(O)objnam.o $(O)options.o $(O)pickup.o +VOBJ15 = $(O)pline.o $(O)polyself.o $(O)potion.o $(O)quest.o $(O)questpgr.o +VOBJ16 = $(O)pager.o $(O)pray.o $(O)priest.o $(O)read.o $(O)rect.o +VOBJ17 = $(O)region.o $(O)report.o $(O)restore.o $(O)rip.o $(O)rnd.o +VOBJ18 = $(O)role.o $(O)rumors.o $(O)save.o $(O)selvar.o $(O)sfstruct.o +VOBJ19 = $(O)shk.o $(O)shknam.o $(O)sit.o $(O)sounds.o $(O)sp_lev.o +VOBJ20 = $(O)spell.o $(O)stairs.o $(O)steal.o $(O)steed.o $(O)symbols.o +VOBJ21 = $(O)sys.o $(O)teleport.o $(O)strutil.o $(O)termcap.o $(O)timeout.o +VOBJ22 = $(O)topl.o $(O)topten.o $(O)trap.o $(O)u_init.o $(O)uhitm.o +VOBJ23 = $(O)utf8map.o $(O)vault.o $(O)track.o $(O)vision.o $(O)weapon.o +VOBJ24 = $(O)were.o $(O)wield.o $(O)windows.o $(O)wintty.o $(O)wizard.o +VOBJ25 = $(O)wizcmds.o $(O)worm.o $(O)worn.o $(O)write.o $(O)zap.o +VOBJ26 = $(O)light.o $(O)dlb.o $(REGEX) SOBJ = $(O)msdos.o $(O)pcsys.o $(O)tty.o $(O)unix.o \ $(O)video.o $(O)vidtxt.o $(O)pckeys.o diff --git a/sys/unix/Makefile.src b/sys/unix/Makefile.src index d8283a03f..d2e3c8e91 100644 --- a/sys/unix/Makefile.src +++ b/sys/unix/Makefile.src @@ -582,7 +582,7 @@ HOSTOBJ = $(FIRSTOBJ) alloc.o drawing.o HOBJ = $(TARGETPFX)allmain.o $(TARGETPFX)alloc.o \ $(TARGETPFX)apply.o $(TARGETPFX)artifact.o $(TARGETPFX)attrib.o \ $(TARGETPFX)ball.o $(TARGETPFX)bones.o $(TARGETPFX)botl.o \ - $(TARGETPFX)calendar.o $(TARGETPFX)cmd.o \ + $(TARGETPFX)calendar.o $(TARGETPFX)cfgfiles.o $(TARGETPFX)cmd.o \ $(TARGETPFX)coloratt.o $(TARGETPFX)dbridge.o $(TARGETPFX)decl.o \ $(TARGETPFX)detect.o $(TARGETPFX)dig.o $(TARGETPFX)display.o \ $(TARGETPFX)dlb.o $(TARGETPFX)do.o $(TARGETPFX)do_name.o \ @@ -1127,6 +1127,7 @@ $(TARGETPFX)ball.o: ball.c $(HACK_H) $(TARGETPFX)bones.o: bones.c $(HACK_H) $(TARGETPFX)botl.o: botl.c $(HACK_H) $(TARGETPFX)calendar.o: calendar.c $(HACK_H) +$(TARGETPFX)cfgfiles.o: cfgfiles.c $(HACK_H) $(TARGETPFX)cmd.o: cmd.c $(HACK_H) ../include/func_tab.h $(TARGETPFX)coloratt.o: coloratt.c $(HACK_H) $(TARGETPFX)dbridge.o: dbridge.c $(HACK_H) diff --git a/sys/unix/NetHack.xcodeproj/project.pbxproj b/sys/unix/NetHack.xcodeproj/project.pbxproj index 762be72de..f42f2a312 100644 --- a/sys/unix/NetHack.xcodeproj/project.pbxproj +++ b/sys/unix/NetHack.xcodeproj/project.pbxproj @@ -165,6 +165,7 @@ 5493735A277AAE830031FE02 /* alloc.c in Sources */ = {isa = PBXBuildFile; fileRef = 31B8A36521A238040055BD01 /* alloc.c */; }; 54A3D3EC282C55A900143F8C /* utf8map.c in Sources */ = {isa = PBXBuildFile; fileRef = 54A3D3EB282C55A900143F8C /* utf8map.c */; }; 54BD340D2D8B70350073C484 /* hacklib.c in Sources */ = {isa = PBXBuildFile; fileRef = 31B8A36421A238040055BD01 /* hacklib.c */; }; + 54EBA6D32DDED3F100CD20EC /* cfgfiles.c in Sources */ = {isa = PBXBuildFile; fileRef = 54EBA6D22DDED3F100CD20EC /* cfgfiles.c */; }; 54FB2B4B246310A600397C0E /* symbols.c in Sources */ = {isa = PBXBuildFile; fileRef = 54FB2B4A246310A600397C0E /* symbols.c */; }; 54FCE8292223261F00F393C8 /* isaac64.c in Sources */ = {isa = PBXBuildFile; fileRef = 54FCE8282223261F00F393C8 /* isaac64.c */; }; BAB57DB527C1C3E200FCF150 /* libnhlua.a in Frameworks */ = {isa = PBXBuildFile; fileRef = BAE8010A27B97760002B3786 /* libnhlua.a */; }; @@ -545,6 +546,7 @@ 54BD34102D8B711E0073C484 /* selvar.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = selvar.h; path = ../../include/selvar.h; sourceTree = ""; }; 54BD34112D8B711E0073C484 /* stairs.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = stairs.h; path = ../../include/stairs.h; sourceTree = ""; }; 54BD34122D8B711E0073C484 /* weight.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = weight.h; path = ../../include/weight.h; sourceTree = ""; }; + 54EBA6D22DDED3F100CD20EC /* cfgfiles.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = cfgfiles.c; path = /Users/mikeallison/Documents/git/NHsource/src/cfgfiles.c; sourceTree = ""; }; 54FB2B4A246310A600397C0E /* symbols.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = symbols.c; path = ../../src/symbols.c; sourceTree = ""; }; 54FCE8282223261F00F393C8 /* isaac64.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = isaac64.c; path = ../../src/isaac64.c; sourceTree = ""; }; BAE8010A27B97760002B3786 /* libnhlua.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libnhlua.a; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -657,6 +659,7 @@ 3189578C21A1FF8200FB2ABE /* src */ = { isa = PBXGroup; children = ( + 54EBA6D22DDED3F100CD20EC /* cfgfiles.c */, 056E43BB2C810EE800FD1F52 /* calendar.c */, 056E43BC2C810EE800FD1F52 /* coloratt.c */, 056E43BD2C810EE800FD1F52 /* getpos.c */, @@ -1790,6 +1793,7 @@ 31B8A3D121A238060055BD01 /* do.c in Sources */, 31B8A39021A238060055BD01 /* objnam.c in Sources */, 31B8A3B621A238060055BD01 /* bones.c in Sources */, + 54EBA6D32DDED3F100CD20EC /* cfgfiles.c in Sources */, 31B8A3C521A238060055BD01 /* timeout.c in Sources */, 31B8A3AD21A238060055BD01 /* uhitm.c in Sources */, 31B8A3B321A238060055BD01 /* track.c in Sources */, diff --git a/sys/vms/Makefile.src b/sys/vms/Makefile.src index 14b75a3da..f2efc62bb 100644 --- a/sys/vms/Makefile.src +++ b/sys/vms/Makefile.src @@ -147,8 +147,8 @@ HACK_H = $(SRC)hack.h-t # all .c that are part of the main NetHack program and are not operating- or # windowing-system specific HACKCSRC = allmain.c alloc.c apply.c artifact.c attrib.c ball.c bones.c \ - botl.c calendar.c cmd.c coloratt.c dbridge.c decl.c detect.c dig.c \ - display.c dlb.c do.c do_name.c do_wear.c dog.c dogmove.c dokick.c \ + botl.c calendar.c cfgfiles.c cmd.c coloratt.c dbridge.c decl.c detect.c \ + dig.c display.c dlb.c do.c do_name.c do_wear.c dog.c dogmove.c dokick.c \ dothrow.c drawing.c dungeon.c eat.c end.c engrave.c exper.c \ explode.c extralev.c files.c fountain.c getpos.c glyphs.c hack.c \ hacklib.c insight.c invent.c light.c lock.c \ @@ -191,9 +191,9 @@ FIRSTOBJ = vmsmisc.obj,vmsfiles.obj,monst.obj,objects.obj # split up long list so that we can write pieces of it into nethack.opt HOBJ1 = allmain.obj,alloc.obj,apply.obj,artifact.obj,attrib.obj, \ - ball.obj,bones.obj,botl.obj,calendar.obj,cmd.obj,coloratt.obj, \ - dbridge.obj,decl.obj,detect.obj,dig.obj,display.obj,dlb.obj, \ - do.obj,do_name.obj,do_wear.obj + ball.obj,bones.obj,botl.obj,calendar.obj,cfgfiles.obj,cmd.obj, \ + coloratt.obj,dbridge.obj,decl.obj,detect.obj,dig.obj,display.obj, \ + dlb.obj,do.obj,do_name.obj,do_wear.obj HOBJ2 = dog.obj,dogmove.obj,dokick.obj,dothrow.obj,drawing.obj, \ dungeon.obj,eat.obj,end.obj,engrave.obj,exper.obj,explode.obj, \ extralev.obj,files.obj,fountain.obj,getpos.obj,glyphs.obj,hack.obj, \ @@ -500,6 +500,7 @@ ball.obj : ball.c $(HACK_H) bones.obj : bones.c $(HACK_H) botl.obj : botl.c $(HACK_H) cmd.obj : cmd.c $(HACK_H) $(INC)func_tab.h +cfgfiles.obj : cfgfiles.c $(HACK_H) dbridge.obj : dbridge.c $(HACK_H) decl.obj : decl.c $(HACK_H) detect.obj : detect.c $(HACK_H) $(INC)artifact.h diff --git a/sys/vms/Makefile_src.vms b/sys/vms/Makefile_src.vms index dd46aafad..5123dfe4c 100644 --- a/sys/vms/Makefile_src.vms +++ b/sys/vms/Makefile_src.vms @@ -701,6 +701,7 @@ $(TARGETPFX)ball.obj: ball.c $(HACK_H) $(TARGETPFX)bones.obj: bones.c $(HACK_H) $(TARGETPFX)botl.obj: botl.c $(HACK_H) $(TARGETPFX)calendar.obj: calendar.c $(HACK_H) +$(TARGETPFX)cfgfiles.obj: cfgfiles.c $(HACK_H) $(TARGETPFX)cmd.obj: cmd.c $(HACK_H) $(INCL)func_tab.h $(TARGETPFX)coloratt.obj: coloratt.c $(HACK_H) $(TARGETPFX)dbridge.obj: dbridge.c $(HACK_H) diff --git a/sys/windows/GNUmakefile b/sys/windows/GNUmakefile index e16bdb31e..0698ae200 100644 --- a/sys/windows/GNUmakefile +++ b/sys/windows/GNUmakefile @@ -1000,7 +1000,7 @@ endif # HAVE_SOUNDLIB # nethackw #========================================== COREOBJS = $(addsuffix .o, allmain alloc apply artifact attrib ball bones botl \ - calendar cmd coloratt cppregex \ + calendar cfgfiles cmd coloratt cppregex \ dbridge decl detect dig display dlb do do_name do_wear \ dog dogmove dokick dothrow drawing dungeon \ eat end engrave exper explode extralev files fountain \ diff --git a/sys/windows/Makefile.nmake b/sys/windows/Makefile.nmake index e19d067d7..a0b8387e9 100644 --- a/sys/windows/Makefile.nmake +++ b/sys/windows/Makefile.nmake @@ -846,34 +846,34 @@ TTYOBJTTY = $(OTTY)topl.o $(OTTY)getline.o $(OTTY)wintty.o COREOBJTTY = \ $(OTTY)allmain.o $(OTTY)alloc.o $(OTTY)apply.o $(OTTY)artifact.o \ $(OTTY)attrib.o $(OTTY)ball.o $(OTTY)bones.o $(OTTY)botl.o \ - $(OTTY)calendar.o $(OTTY)cmd.o $(OTTY)coloratt.o $(OTTY)dbridge.o \ - $(OTTY)decl.o $(OTTY)detect.o $(OTTY)dig.o $(OTTY)display.o \ - $(OTTY)do.o $(OTTY)do_name.o $(OTTY)do_wear.o $(OTTY)dog.o \ - $(OTTY)dogmove.o $(OTTY)dokick.o $(OTTY)dothrow.o $(OTTY)drawing.o \ - $(OTTY)dungeon.o $(OTTY)eat.o $(OTTY)end.o $(OTTY)engrave.o \ - $(OTTY)exper.o $(OTTY)explode.o $(OTTY)extralev.o $(OTTY)files.o \ - $(OTTY)fountain.o $(OTTY)getpos.o $(OTTY)glyphs.o $(OTTY)hack.o \ - $(OTTY)insight.o $(OTTY)invent.o $(OTTY)isaac64.o $(OTTY)light.o \ - $(OTTY)lock.o $(OTTY)mail.o $(OTTY)makemon.o $(OTTY)mcastu.o \ - $(OTTY)mhitm.o $(OTTY)mhitu.o $(OTTY)minion.o $(OTTY)mklev.o \ - $(OTTY)mkmap.o $(OTTY)mkmaze.o $(OTTY)mkobj.o $(OTTY)mkroom.o \ - $(OTTY)mon.o $(OTTY)mondata.o $(OTTY)monmove.o $(OTTY)monst.o \ - $(OTTY)mplayer.o $(OTTY)mthrowu.o $(OTTY)muse.o $(OTTY)music.o \ - $(OTTY)o_init.o $(OTTY)objects.o $(OTTY)objnam.o $(OTTY)options.o \ - $(OTTY)pager.o $(OTTY)pickup.o $(OTTY)pline.o $(OTTY)polyself.o \ - $(OTTY)potion.o $(OTTY)pray.o $(OTTY)priest.o $(OTTY)quest.o \ - $(OTTY)questpgr.o $(OTTY)read.o $(OTTY)rect.o $(OTTY)region.o \ - $(OTTY)report.o $(OTTY)restore.o $(OTTY)rip.o $(OTTY)rnd.o \ - $(OTTY)role.o $(OTTY)rumors.o $(OTTY)save.o $(OTTY)selvar.o \ - $(OTTY)sfstruct.o $(OTTY)shk.o $(OTTY)shknam.o $(OTTY)sit.o \ - $(OTTY)sounds.o $(OTTY)sp_lev.o $(OTTY)spell.o $(OTTY)stairs.o \ - $(OTTY)steal.o $(OTTY)steed.o $(OTTY)strutil.o $(OTTY)symbols.o \ - $(OTTY)sys.o $(OTTY)teleport.o $(OTTY)timeout.o $(OTTY)topten.o \ - $(OTTY)track.o $(OTTY)trap.o $(OTTY)u_init.o $(OTTY)uhitm.o \ - $(OTTY)utf8map.o $(OTTY)vault.o $(OTTY)vision.o $(OTTY)weapon.o \ - $(OTTY)were.o $(OTTY)wield.o $(OTTY)windows.o $(OTTY)wizard.o \ - $(OTTY)wizcmds.o $(OTTY)worm.o $(OTTY)worn.o $(OTTY)write.o \ - $(OTTY)zap.o + $(OTTY)calendar.o $(OTTY)cfgfiles.o $(OTTY)cmd.o $(OTTY)coloratt.o \ + $(OTTY)dbridge.o $(OTTY)decl.o $(OTTY)detect.o $(OTTY)dig.o \ + $(OTTY)display.o $(OTTY)do.o $(OTTY)do_name.o $(OTTY)do_wear.o \ + $(OTTY)dog.o $(OTTY)dogmove.o $(OTTY)dokick.o $(OTTY)dothrow.o \ + $(OTTY)drawing.o $(OTTY)dungeon.o $(OTTY)eat.o $(OTTY)end.o \ + $(OTTY)engrave.o $(OTTY)exper.o $(OTTY)explode.o $(OTTY)extralev.o \ + $(OTTY)files.o $(OTTY)fountain.o $(OTTY)getpos.o $(OTTY)glyphs.o \ + $(OTTY)hack.o $(OTTY)insight.o $(OTTY)invent.o $(OTTY)isaac64.o \ + $(OTTY)light.o $(OTTY)lock.o $(OTTY)mail.o $(OTTY)makemon.o \ + $(OTTY)mcastu.o $(OTTY)mhitm.o $(OTTY)mhitu.o $(OTTY)minion.o \ + $(OTTY)mklev.o $(OTTY)mkmap.o $(OTTY)mkmaze.o $(OTTY)mkobj.o \ + $(OTTY)mkroom.o $(OTTY)mon.o $(OTTY)mondata.o $(OTTY)monmove.o \ + $(OTTY)monst.o $(OTTY)mplayer.o $(OTTY)mthrowu.o $(OTTY)muse.o \ + $(OTTY)music.o $(OTTY)o_init.o $(OTTY)objects.o $(OTTY)objnam.o \ + $(OTTY)options.o $(OTTY)pager.o $(OTTY)pickup.o $(OTTY)pline.o \ + $(OTTY)polyself.o $(OTTY)potion.o $(OTTY)pray.o $(OTTY)priest.o \ + $(OTTY)quest.o $(OTTY)questpgr.o $(OTTY)read.o $(OTTY)rect.o \ + $(OTTY)region.o $(OTTY)report.o $(OTTY)restore.o $(OTTY)rip.o \ + $(OTTY)rnd.o $(OTTY)role.o $(OTTY)rumors.o $(OTTY)save.o \ + $(OTTY)selvar.o $(OTTY)sfstruct.o $(OTTY)shk.o $(OTTY)shknam.o \ + $(OTTY)sit.o $(OTTY)sounds.o $(OTTY)sp_lev.o $(OTTY)spell.o \ + $(OTTY)stairs.o $(OTTY)steal.o $(OTTY)steed.o $(OTTY)strutil.o \ + $(OTTY)symbols.o $(OTTY)sys.o $(OTTY)teleport.o $(OTTY)timeout.o \ + $(OTTY)topten.o $(OTTY)track.o $(OTTY)trap.o $(OTTY)u_init.o \ + $(OTTY)uhitm.o $(OTTY)utf8map.o $(OTTY)vault.o $(OTTY)vision.o \ + $(OTTY)weapon.o $(OTTY)were.o $(OTTY)wield.o $(OTTY)windows.o \ + $(OTTY)wizard.o $(OTTY)wizcmds.o $(OTTY)worm.o $(OTTY)worn.o \ + $(OTTY)write.o $(OTTY)zap.o OBJSTTY = $(MDLIBTTY) $(COREOBJTTY) $(REGEXTTY) $(RANDOMTTY) @@ -909,34 +909,34 @@ GUIOBJ = $(OGUI)mhaskyn.o $(OGUI)mhdlg.o \ COREOBJGUI = \ $(OGUI)allmain.o $(OGUI)alloc.o $(OGUI)apply.o $(OGUI)artifact.o \ $(OGUI)attrib.o $(OGUI)ball.o $(OGUI)bones.o $(OGUI)botl.o \ - $(OGUI)calendar.o $(OGUI)cmd.o $(OGUI)coloratt.o $(OGUI)dbridge.o \ - $(OGUI)decl.o $(OGUI)detect.o $(OGUI)dig.o $(OGUI)display.o \ - $(OGUI)do.o $(OGUI)do_name.o $(OGUI)do_wear.o $(OGUI)dog.o \ - $(OGUI)dogmove.o $(OGUI)dokick.o $(OGUI)dothrow.o $(OGUI)drawing.o \ - $(OGUI)dungeon.o $(OGUI)eat.o $(OGUI)end.o $(OGUI)engrave.o \ - $(OGUI)exper.o $(OGUI)explode.o $(OGUI)extralev.o $(OGUI)files.o \ - $(OGUI)fountain.o $(OGUI)getpos.o $(OGUI)glyphs.o $(OGUI)hack.o \ - $(OGUI)insight.o $(OGUI)invent.o $(OGUI)isaac64.o $(OGUI)light.o \ - $(OGUI)lock.o $(OGUI)mail.o $(OGUI)makemon.o $(OGUI)mcastu.o \ - $(OGUI)mhitm.o $(OGUI)mhitu.o $(OGUI)minion.o $(OGUI)mklev.o \ - $(OGUI)mkmap.o $(OGUI)mkmaze.o $(OGUI)mkobj.o $(OGUI)mkroom.o \ - $(OGUI)mon.o $(OGUI)mondata.o $(OGUI)monmove.o $(OGUI)monst.o \ - $(OGUI)mplayer.o $(OGUI)mthrowu.o $(OGUI)muse.o $(OGUI)music.o \ - $(OGUI)o_init.o $(OGUI)objects.o $(OGUI)objnam.o $(OGUI)options.o \ - $(OGUI)pager.o $(OGUI)pickup.o $(OGUI)pline.o $(OGUI)polyself.o \ - $(OGUI)potion.o $(OGUI)pray.o $(OGUI)priest.o $(OGUI)quest.o \ - $(OGUI)questpgr.o $(OGUI)read.o $(OGUI)rect.o $(OGUI)region.o \ - $(OGUI)report.o $(OGUI)restore.o $(OGUI)rip.o $(OGUI)rnd.o \ - $(OGUI)role.o $(OGUI)rumors.o $(OGUI)save.o $(OGUI)selvar.o \ - $(OGUI)sfstruct.o $(OGUI)shk.o $(OGUI)shknam.o $(OGUI)sit.o \ - $(OGUI)sounds.o $(OGUI)sp_lev.o $(OGUI)spell.o $(OGUI)stairs.o \ - $(OGUI)steal.o $(OGUI)steed.o $(OGUI)strutil.o $(OGUI)symbols.o \ - $(OGUI)sys.o $(OGUI)teleport.o $(OGUI)timeout.o $(OGUI)topten.o \ - $(OGUI)track.o $(OGUI)trap.o $(OGUI)u_init.o $(OGUI)uhitm.o \ - $(OGUI)utf8map.o $(OGUI)vault.o $(OGUI)vision.o $(OGUI)weapon.o \ - $(OGUI)were.o $(OGUI)wield.o $(OGUI)windows.o $(OGUI)wizard.o \ - $(OGUI)wizcmds.o $(OGUI)worm.o $(OGUI)worn.o $(OGUI)write.o \ - $(OGUI)zap.o + $(OGUI)calendar.o $(OGUI)cfgfiles.o $(OGUI)cmd.o $(OGUI)coloratt.o \ + $(OGUI)dbridge.o $(OGUI)decl.o $(OGUI)detect.o $(OGUI)dig.o \ + $(OGUI)display.o $(OGUI)do.o $(OGUI)do_name.o $(OGUI)do_wear.o \ + $(OGUI)dog.o $(OGUI)dogmove.o $(OGUI)dokick.o $(OGUI)dothrow.o \ + $(OGUI)drawing.o $(OGUI)dungeon.o $(OGUI)eat.o $(OGUI)end.o \ + $(OGUI)engrave.o $(OGUI)exper.o $(OGUI)explode.o $(OGUI)extralev.o \ + $(OGUI)files.o $(OGUI)fountain.o $(OGUI)getpos.o $(OGUI)glyphs.o \ + $(OGUI)hack.o $(OGUI)insight.o $(OGUI)invent.o $(OGUI)isaac64.o \ + $(OGUI)light.o $(OGUI)lock.o $(OGUI)mail.o $(OGUI)makemon.o \ + $(OGUI)mcastu.o $(OGUI)mhitm.o $(OGUI)mhitu.o $(OGUI)minion.o \ + $(OGUI)mklev.o $(OGUI)mkmap.o $(OGUI)mkmaze.o $(OGUI)mkobj.o \ + $(OGUI)mkroom.o $(OGUI)mon.o $(OGUI)mondata.o $(OGUI)monmove.o \ + $(OGUI)monst.o $(OGUI)mplayer.o $(OGUI)mthrowu.o $(OGUI)muse.o \ + $(OGUI)music.o $(OGUI)o_init.o $(OGUI)objects.o $(OGUI)objnam.o \ + $(OGUI)options.o $(OGUI)pager.o $(OGUI)pickup.o $(OGUI)pline.o \ + $(OGUI)polyself.o $(OGUI)potion.o $(OGUI)pray.o $(OGUI)priest.o \ + $(OGUI)quest.o $(OGUI)questpgr.o $(OGUI)read.o $(OGUI)rect.o \ + $(OGUI)region.o $(OGUI)report.o $(OGUI)restore.o $(OGUI)rip.o \ + $(OGUI)rnd.o $(OGUI)role.o $(OGUI)rumors.o $(OGUI)save.o \ + $(OGUI)selvar.o $(OGUI)sfstruct.o $(OGUI)shk.o $(OGUI)shknam.o \ + $(OGUI)sit.o $(OGUI)sounds.o $(OGUI)sp_lev.o $(OGUI)spell.o \ + $(OGUI)stairs.o $(OGUI)steal.o $(OGUI)steed.o $(OGUI)strutil.o \ + $(OGUI)symbols.o $(OGUI)sys.o $(OGUI)teleport.o $(OGUI)timeout.o \ + $(OGUI)topten.o $(OGUI)track.o $(OGUI)trap.o $(OGUI)u_init.o \ + $(OGUI)uhitm.o $(OGUI)utf8map.o $(OGUI)vault.o $(OGUI)vision.o \ + $(OGUI)weapon.o $(OGUI)were.o $(OGUI)wield.o $(OGUI)windows.o \ + $(OGUI)wizard.o $(OGUI)wizcmds.o $(OGUI)worm.o $(OGUI)worn.o \ + $(OGUI)write.o $(OGUI)zap.o OBJSGUI = $(MDLIBGUI) $(COREOBJGUI) $(REGEXGUI) $(RANDOMGUI) @@ -2962,6 +2962,7 @@ $(OTTY)ball.o: ball.c $(HACK_H) $(OTTY)bones.o: bones.c $(HACK_H) $(OTTY)botl.o: botl.c $(HACK_H) $(OTTY)calendar.o: calendar.c $(HACK_H) +$(OTTY)cfgfiles.o: cfgfiles.c $(HACK_H) $(OTTY)cmd.o: cmd.c $(HACK_H) $(INCL)func_tab.h $(OTTY)coloratt.o: coloratt.c $(HACK_H) $(OTTY)dbridge.o: dbridge.c $(HACK_H) @@ -3338,6 +3339,7 @@ $(OGUI)ball.o: ball.c $(HACK_H) $(OGUI)bones.o: bones.c $(HACK_H) $(OGUI)botl.o: botl.c $(HACK_H) $(OGUI)calendar.o: calendar.c $(HACK_H) +$(OGUI)cfgfiles.o: cfgfiles.c $(HACK_H) $(OGUI)cmd.o: cmd.c $(HACK_H) $(INCL)func_tab.h $(OGUI)coloratt.o: coloratt.c $(HACK_H) $(OGUI)dbridge.o: dbridge.c $(HACK_H) diff --git a/sys/windows/vs/NetHack/NetHack.vcxproj b/sys/windows/vs/NetHack/NetHack.vcxproj index da501d2fb..9da54976c 100644 --- a/sys/windows/vs/NetHack/NetHack.vcxproj +++ b/sys/windows/vs/NetHack/NetHack.vcxproj @@ -82,6 +82,7 @@ + diff --git a/sys/windows/vs/NetHackW/NetHackW.vcxproj b/sys/windows/vs/NetHackW/NetHackW.vcxproj index c5562205e..6c0360d49 100644 --- a/sys/windows/vs/NetHackW/NetHackW.vcxproj +++ b/sys/windows/vs/NetHackW/NetHackW.vcxproj @@ -90,6 +90,7 @@ + From d019542669d64c621d9d35f4d4fd5ae92c605c94 Mon Sep 17 00:00:00 2001 From: nhw_cron Date: Thu, 22 May 2025 00:24:07 -0400 Subject: [PATCH 634/791] This is cron-daily v1-Apr-1-2024. 000files updated: Files --- Files | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/Files b/Files index 04f76ecb6..f76653997 100644 --- a/Files +++ b/Files @@ -292,26 +292,27 @@ windsound.c src: (files for all versions) allmain.c alloc.c apply.c artifact.c attrib.c ball.c -bones.c botl.c calendar.c cmd.c coloratt.c date.c -dbridge.c decl.c detect.c dig.c display.c dlb.c -do.c do_name.c do_wear.c dog.c dogmove.c dokick.c -dothrow.c drawing.c dungeon.c eat.c end.c engrave.c -exper.c explode.c extralev.c files.c fountain.c getpos.c -glyphs.c hack.c hacklib.c insight.c invent.c isaac64.c -light.c lock.c mail.c makemon.c mcastu.c mdlib.c -mhitm.c mhitu.c minion.c mklev.c mkmap.c mkmaze.c -mkobj.c mkroom.c mon.c mondata.c monmove.c monst.c -mplayer.c mthrowu.c muse.c music.c nhlobj.c nhlsel.c -nhlua.c nhmd4.c o_init.c objects.c objnam.c options.c -pager.c pickup.c pline.c polyself.c potion.c pray.c -priest.c quest.c questpgr.c read.c rect.c region.c -report.c restore.c rip.c rnd.c role.c rumors.c -save.c selvar.c sfstruct.c shk.c shknam.c sit.c -sounds.c sp_lev.c spell.c stairs.c steal.c steed.c -strutil.c symbols.c sys.c teleport.c timeout.c topten.c -track.c trap.c u_init.c uhitm.c utf8map.c vault.c -version.c vision.c weapon.c were.c wield.c windows.c -wizard.c wizcmds.c worm.c worn.c write.c zap.c +bones.c botl.c calendar.c cfgfiles.c cmd.c coloratt.c +date.c dbridge.c decl.c detect.c dig.c display.c +dlb.c do.c do_name.c do_wear.c dog.c dogmove.c +dokick.c dothrow.c drawing.c dungeon.c eat.c end.c +engrave.c exper.c explode.c extralev.c files.c fountain.c +getpos.c glyphs.c hack.c hacklib.c insight.c invent.c +isaac64.c light.c lock.c mail.c makemon.c mcastu.c +mdlib.c mhitm.c mhitu.c minion.c mklev.c mkmap.c +mkmaze.c mkobj.c mkroom.c mon.c mondata.c monmove.c +monst.c mplayer.c mthrowu.c muse.c music.c nhlobj.c +nhlsel.c nhlua.c nhmd4.c o_init.c objects.c objnam.c +options.c pager.c pickup.c pline.c polyself.c potion.c +pray.c priest.c quest.c questpgr.c read.c rect.c +region.c report.c restore.c rip.c rnd.c role.c +rumors.c save.c selvar.c sfstruct.c shk.c shknam.c +sit.c sounds.c sp_lev.c spell.c stairs.c steal.c +steed.c strutil.c symbols.c sys.c teleport.c timeout.c +topten.c track.c trap.c u_init.c uhitm.c utf8map.c +vault.c version.c vision.c weapon.c were.c wield.c +windows.c wizard.c wizcmds.c worm.c worn.c write.c +zap.c submodules: (files in top directory) From 0c765ce20738f2af15d5dcaaf62d055e5ebb56ce Mon Sep 17 00:00:00 2001 From: nhmall Date: Thu, 22 May 2025 10:04:54 -0400 Subject: [PATCH 635/791] move some Windows code: windmain.c -> windsys.c --- include/extern.h | 1 + sys/windows/Makefile.nmake | 2 +- sys/windows/windmain.c | 336 +----------------------------- sys/windows/windsys.c | 406 +++++++++++++++++++++++++++++++++++-- sys/windows/winos.h | 4 + 5 files changed, 395 insertions(+), 354 deletions(-) diff --git a/include/extern.h b/include/extern.h index d4f1e549d..63c6800fc 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1976,6 +1976,7 @@ extern int win32_cr_helper(char, struct CRctxt *, void *, int); extern int win32_cr_gettrace(int, char *, int); extern int *win32_cr_shellexecute(const char *); # endif +extern boolean contains_directory(const char *); #endif /* WIN32 */ #endif /* MICRO || WIN32 */ diff --git a/sys/windows/Makefile.nmake b/sys/windows/Makefile.nmake index a0b8387e9..14273dd61 100644 --- a/sys/windows/Makefile.nmake +++ b/sys/windows/Makefile.nmake @@ -1339,7 +1339,7 @@ guilflags = $(lflags) -subsystem:windows # basic subsystem specific libraries, less the C Run-Time baselibs = kernel32.lib $(optlibs) $(winsocklibs) advapi32.lib gdi32.lib \ - ole32.lib Shell32.lib dbghelp.lib + ole32.lib Shell32.lib UserEnv.lib dbghelp.lib winlibs = $(baselibs) user32.lib comdlg32.lib winspool.lib # for Windows applications that use the C Run-Time libraries diff --git a/sys/windows/windmain.c b/sys/windows/windmain.c index 45282b446..04b4668ac 100644 --- a/sys/windows/windmain.c +++ b/sys/windows/windmain.c @@ -19,9 +19,7 @@ #endif static void nhusage(void); -static char *get_executable_path(void); static void early_options(int argc, char **argv); -char *translate_path_variables(const char *, char *); char *exename(void); boolean fakeconsole(void); void freefakeconsole(void); @@ -98,17 +96,7 @@ static struct stat hbuf; extern char orgdir[]; -int get_known_folder_path(const KNOWNFOLDERID * folder_id, - char * path, size_t path_size); -void create_directory(const char * path); -int build_known_folder_path(const KNOWNFOLDERID * folder_id, - char * path, size_t path_size, boolean versioned); -void build_environment_path(const char * env_str, const char * folder, - char * path, size_t path_size); -boolean folder_file_exists(const char * folder, const char * file_name); -boolean test_portable_config(const char *executable_path, - char *portable_device_path, size_t portable_device_path_size); -void set_default_prefix_locations(const char *programPath); +extern void set_default_prefix_locations(const char *programPath); void copy_sysconf_content(void); void copy_config_content(void); void copy_hack_content(void); @@ -681,224 +669,6 @@ nhusage(void) #undef ADD_USAGE } -DISABLE_WARNING_UNREACHABLE_CODE - -int -get_known_folder_path(const KNOWNFOLDERID *folder_id, char *path, - size_t path_size) -{ - PWSTR wide_path; - if (FAILED(SHGetKnownFolderPath(folder_id, 0, NULL, &wide_path))) { - error("Unable to get known folder path"); - return FALSE; - } - - size_t converted; - errno_t err; - - err = wcstombs_s(&converted, path, path_size, wide_path, _TRUNCATE); - - CoTaskMemFree(wide_path); - - if (err == STRUNCATE || err == EILSEQ) { - // silently handle this problem - return FALSE; - } else if (err != 0) { - error( - "Failed folder (%lu) path string conversion, unexpected err = %d", - folder_id->Data1, err); - return FALSE; - } - - return TRUE; -} - -void -create_directory(const char *path) -{ - BOOL dres = CreateDirectoryA(path, NULL); - - if (!dres) { - DWORD dw = GetLastError(); - - if (dw != ERROR_ALREADY_EXISTS) - error("Unable to create directory '%s'", path); - } -} - -RESTORE_WARNING_UNREACHABLE_CODE - -int -build_known_folder_path(const KNOWNFOLDERID *folder_id, char *path, - size_t path_size, boolean versioned) -{ - if (!get_known_folder_path(folder_id, path, path_size)) - return FALSE; - - strcat(path, "\\NetHack\\"); - create_directory(path); - if (versioned) { - Sprintf(eos(path), "%d.%d\\", VERSION_MAJOR, VERSION_MINOR); - create_directory(path); - } - return TRUE; -} - -void -build_environment_path(const char *env_str, const char *folder, char *path, - size_t path_size) -{ - path[0] = '\0'; - - const char *root_path = nh_getenv(env_str); - - if (root_path == NULL) - return; - - strcpy_s(path, path_size, root_path); - - char *colon = strchr(path, ';'); - if (colon != NULL) - path[0] = '\0'; - - if (strlen(path) == 0) - return; - - append_slash(path); - - if (folder != NULL) { - strcat_s(path, path_size, folder); - strcat_s(path, path_size, "\\"); - } -} - -boolean -folder_file_exists(const char *folder, const char *file_name) -{ - char path[MAX_PATH]; - - if (folder[0] == '\0') - return FALSE; - - strcpy(path, folder); - strcat(path, file_name); - return file_exists(path); -} - -boolean -test_portable_config(const char *executable_path, char *portable_device_path, - size_t portable_device_path_size) -{ - int lth = 0; - const char *sysconf = "sysconf"; - char tmppath[MAX_PATH]; - boolean retval = FALSE, - save_initoptions_noterminate = iflags.initoptions_noterminate; - - if (portable_device_path - && folder_file_exists(executable_path, "sysconf")) { - /* - There is a sysconf file (not just sysconf.template) present in - the exe path, which is not the way NetHack is initially - distributed, so assume it means that the admin/installer wants to - override something, perhaps set up for a fully-portable - configuration that leaves no traces behind elsewhere on this - computer's hard drive - delve into that... - */ - - *portable_device_path = '\0'; - lth = sizeof tmppath - strlen(sysconf); - (void) strncpy(tmppath, executable_path, lth - 1); - tmppath[lth - 1] = '\0'; - (void) strcat(tmppath, sysconf); - - iflags.initoptions_noterminate = 1; - /* assure_syscf_file(); */ - config_error_init(TRUE, tmppath, FALSE); - /* ... and _must_ parse correctly. */ - if (read_config_file(tmppath, set_in_sysconf) - && sysopt.portable_device_paths) - retval = TRUE; - (void) config_error_done(); - iflags.initoptions_noterminate = save_initoptions_noterminate; - sysopt_release(); /* the real sysconf processing comes later */ - } - if (retval) { - lth = strlen(executable_path); - if (lth <= (int) portable_device_path_size - 1) - Strcpy(portable_device_path, executable_path); - else - retval = FALSE; - } - return retval; -} - -static char portable_device_path[MAX_PATH]; - -const char * -get_portable_device(void) -{ - return (const char *) portable_device_path; -} - -void -set_default_prefix_locations(const char *programPath UNUSED) -{ - static char executable_path[MAX_PATH]; - static char profile_path[MAX_PATH]; - static char versioned_profile_path[MAX_PATH]; - static char versioned_user_data_path[MAX_PATH]; - static char versioned_global_data_path[MAX_PATH]; - /* static char versioninfo[20] UNUSED; */ - - strcpy(executable_path, get_executable_path()); - append_slash(executable_path); - - if (test_portable_config(executable_path, portable_device_path, - sizeof portable_device_path)) { - gf.fqn_prefix[SYSCONFPREFIX] = executable_path; - gf.fqn_prefix[CONFIGPREFIX] = portable_device_path; - gf.fqn_prefix[HACKPREFIX] = portable_device_path; - gf.fqn_prefix[SAVEPREFIX] = portable_device_path; - gf.fqn_prefix[LEVELPREFIX] = portable_device_path; - gf.fqn_prefix[BONESPREFIX] = portable_device_path; - gf.fqn_prefix[SCOREPREFIX] = portable_device_path; - gf.fqn_prefix[LOCKPREFIX] = portable_device_path; - gf.fqn_prefix[TROUBLEPREFIX] = portable_device_path; - gf.fqn_prefix[DATAPREFIX] = executable_path; - } else { - if (!build_known_folder_path(&FOLDERID_Profile, profile_path, - sizeof(profile_path), FALSE)) - strcpy(profile_path, executable_path); - - if (!build_known_folder_path(&FOLDERID_Profile, - versioned_profile_path, - sizeof(profile_path), TRUE)) - strcpy(versioned_profile_path, executable_path); - - if (!build_known_folder_path(&FOLDERID_LocalAppData, - versioned_user_data_path, - sizeof(versioned_user_data_path), TRUE)) - strcpy(versioned_user_data_path, executable_path); - - if (!build_known_folder_path( - &FOLDERID_ProgramData, versioned_global_data_path, - sizeof(versioned_global_data_path), TRUE)) - strcpy(versioned_global_data_path, executable_path); - - gf.fqn_prefix[SYSCONFPREFIX] = versioned_global_data_path; - gf.fqn_prefix[CONFIGPREFIX] = profile_path; - gf.fqn_prefix[HACKPREFIX] = versioned_profile_path; - gf.fqn_prefix[SAVEPREFIX] = versioned_user_data_path; - gf.fqn_prefix[LEVELPREFIX] = versioned_user_data_path; - gf.fqn_prefix[BONESPREFIX] = versioned_global_data_path; - gf.fqn_prefix[SCOREPREFIX] = versioned_global_data_path; - gf.fqn_prefix[LOCKPREFIX] = versioned_global_data_path; - gf.fqn_prefix[TROUBLEPREFIX] = versioned_profile_path; - gf.fqn_prefix[DATAPREFIX] = executable_path; - } -} - /* copy file if destination does not exist */ void copy_file(const char *dst_folder, const char *dst_name, @@ -1080,7 +850,9 @@ authorize_explore_mode(void) return TRUE; /* no restrictions on explore mode */ } +#ifndef PATH_SEPARATOR #define PATH_SEPARATOR '\\' +#endif #if defined(WIN32) && !defined(WIN32CON) static char exenamebuf[PATHLEN]; @@ -1147,96 +919,6 @@ void freefakeconsole(void) } #endif -static boolean path_buffer_set = FALSE; -static char path_buffer[MAX_PATH]; - -char * -get_executable_path(void) -{ - -#ifdef UNICODE - { - TCHAR wbuf[BUFSZ]; - GetModuleFileName((HANDLE) 0, wbuf, BUFSZ); - WideCharToMultiByte(CP_ACP, 0, wbuf, -1, path_buffer, sizeof(path_buffer), NULL, NULL); - } -#else - DWORD length = GetModuleFileName((HANDLE) 0, path_buffer, MAX_PATH); - if (length == ERROR_INSUFFICIENT_BUFFER) error("Unable to get module name"); - path_buffer[length] = '\0'; -#endif - - char * seperator = strrchr(path_buffer, PATH_SEPARATOR); - if (seperator) - *seperator = '\0'; - - path_buffer_set = TRUE; - return path_buffer; -} - -char * -windows_exepath(void) -{ - char *p = (char *) 0; - - if (path_buffer_set) - p = path_buffer; - return p; -} - -char * -translate_path_variables(const char *str, char *buf) -{ - const char *src; - char evar[BUFSZ], *dest, *envp, *eptr = (char *) 0; - boolean in_evar; - size_t ccount, ecount, destcount, slen = str ? strlen(str) : 0; - - if (!slen || !buf) { - if (buf) - *buf = '\0'; - return buf; - } - - dest = buf; - src = str; - in_evar = FALSE; - destcount = ecount = 0; - for (ccount = 0; ccount < slen && destcount < (BUFSZ - 1) && - ecount < (BUFSZ - 1); ++ccount, ++src) { - if (*src == '%') { - if (in_evar) { - *eptr = '\0'; - envp = nh_getenv(evar); - if (envp) { - size_t elen = strlen(envp); - - if ((elen + destcount) < (size_t) (BUFSZ - 1)) { - Strcpy(dest, envp); - dest += elen; - destcount += elen; - } - } - } else { - eptr = evar; - ecount = 0; - } - in_evar = !in_evar; - continue; - } - if (in_evar) { - *eptr++ = *src; - ecount++; - } else { - *dest++ = *src; - destcount++; - } - } - *dest = '\0'; - return buf; -} - - /*ARGSUSED*/ void windows_raw_print(const char *str) @@ -1453,18 +1135,6 @@ gotlock: } #endif /* PC_LOCKING */ -boolean -file_exists(const char *path) -{ - struct stat sb; - - /* Just see if it's there */ - if (stat(path, &sb)) { - return FALSE; - } - return TRUE; -} - RESTORE_WARNING_UNREACHABLE_CODE /* diff --git a/sys/windows/windsys.c b/sys/windows/windsys.c index 24dd6ed60..ea425ce26 100644 --- a/sys/windows/windsys.c +++ b/sys/windows/windsys.c @@ -13,6 +13,7 @@ #include "win10.h" #include "winos.h" +#include #define NEED_VARARGS #include "hack.h" @@ -27,6 +28,7 @@ #ifdef WIN32 #include +#include /* * The following WIN32 API routines are used in this file. @@ -40,6 +42,8 @@ * */ +static char portable_device_path[MAX_PATH]; + /* runtime cursor display control switch */ boolean win32_cursorblink; @@ -68,7 +72,17 @@ unsigned long sys_random_seed(void); static int max_filename(void); #endif - +int get_known_folder_path(const KNOWNFOLDERID *folder_id, char *path, + size_t path_size); +void create_directory(const char *path); +int build_known_folder_path(const KNOWNFOLDERID *folder_id, char *path, + size_t path_size, boolean versioned); +void build_environment_path(const char *env_str, const char *folder, + char *path, size_t path_size); +boolean folder_file_exists(const char *folder, const char *file_name); +boolean test_portable_config(const char *executable_path, + char *portable_device_path, + size_t portable_device_path_size); /* The function pointer nt_kbhit contains a kbhit() equivalent * which varies depending on which window port is active. * For the tty port it is tty_kbhit() [from consoletty.c] @@ -491,6 +505,20 @@ get_port_id(char *buf) extern void free_winmain_stuff(void); #endif +/* return TRUE if s contains a directory, not just a filespec */ +boolean +contains_directory(const char *s) +{ + int i, slen = strlen(s); + const char *cp = s; + + for (i = 0; i < slen; ++i) { + if (*cp == '\\' || *cp == '/' || *cp == ':') + return TRUE; + } + return FALSE; +} + void nethack_exit(int code) { @@ -697,25 +725,6 @@ windows_early_options(const char *window_opt) return 0; } -/* - * Add a backslash to any name not ending in /, \ or : There must - * be room for the \ - */ -void -append_slash(char *name) -{ - char *ptr; - - if (!*name) - return; - ptr = name + (strlen(name) - 1); - if (*ptr != '\\' && *ptr != '/' && *ptr != ':') { - *++ptr = '\\'; - *++ptr = '\0'; - } - return; -} - #include /* Windows Crypto Next Gen (CNG) */ #ifndef STATUS_SUCCESS @@ -786,6 +795,363 @@ nt_assert_failed(const char *expression, const char *filepath, int line) expression, filename, line); } +boolean +get_user_home_folder(char *homebuf, size_t sz) +{ + static char szHomeDirBuf[MAX_PATH] = { 0 }; + // We need a process with query permission set + HANDLE hToken = 0; + DWORD result = + OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken); + DWORD BufSize = MAX_PATH; + + result = GetUserProfileDirectoryA(hToken, szHomeDirBuf, &BufSize); + // Close handle opened via OpenProcessToken + CloseHandle(hToken); + + return (result != 0); +} +static char *get_executable_path(void); + +static boolean path_buffer_set = FALSE; +static char path_buffer[MAX_PATH]; + +char * +get_executable_path(void) +{ +#ifdef UNICODE + { + TCHAR wbuf[BUFSZ]; + GetModuleFileName((HANDLE) 0, wbuf, BUFSZ); + WideCharToMultiByte(CP_ACP, 0, wbuf, -1, path_buffer, + sizeof(path_buffer), NULL, NULL); + } +#else + DWORD length = GetModuleFileName((HANDLE) 0, path_buffer, MAX_PATH); + if (length == ERROR_INSUFFICIENT_BUFFER) + error("Unable to get module name"); + path_buffer[length] = '\0'; +#endif + + char *seperator = strrchr(path_buffer, PATH_SEPARATOR); + if (seperator) + *seperator = '\0'; + + path_buffer_set = TRUE; + return path_buffer; +} + +char * +windows_exepath(void) +{ + char *p = (char *) 0; + + if (path_buffer_set) + p = path_buffer; + return p; +} + +char * +translate_path_variables(const char *str, char *buf) +{ + const char *src; + char evar[BUFSZ], *dest, *envp, *eptr = (char *) 0; + boolean in_evar; + size_t ccount, ecount, destcount, slen = str ? strlen(str) : 0; + + if (!slen || !buf) { + if (buf) + *buf = '\0'; + return buf; + } + + dest = buf; + src = str; + in_evar = FALSE; + destcount = ecount = 0; + for (ccount = 0; + ccount < slen && destcount < (BUFSZ - 1) && ecount < (BUFSZ - 1); + ++ccount, ++src) { + if (*src == '%') { + if (in_evar) { + *eptr = '\0'; + envp = nh_getenv(evar); + if (envp) { + size_t elen = strlen(envp); + + if ((elen + destcount) < (size_t) (BUFSZ - 1)) { + Strcpy(dest, envp); + dest += elen; + destcount += elen; + } + } + } else { + eptr = evar; + ecount = 0; + } + in_evar = !in_evar; + continue; + } + if (in_evar) { + *eptr++ = *src; + ecount++; + } else { + *dest++ = *src; + destcount++; + } + } + *dest = '\0'; + return buf; +} + +DISABLE_WARNING_UNREACHABLE_CODE + +int +get_known_folder_path(const KNOWNFOLDERID *folder_id, char *path, + size_t path_size) +{ + PWSTR wide_path; + if (FAILED(SHGetKnownFolderPath(folder_id, 0, NULL, &wide_path))) { + error("Unable to get known folder path"); + return FALSE; + } + + size_t converted; + errno_t err; + + err = wcstombs_s(&converted, path, path_size, wide_path, _TRUNCATE); + + CoTaskMemFree(wide_path); + + if (err == STRUNCATE || err == EILSEQ) { + // silently handle this problem + return FALSE; + } else if (err != 0) { + error( + "Failed folder (%lu) path string conversion, unexpected err = %d", + folder_id->Data1, err); + return FALSE; + } + + return TRUE; +} + +void +create_directory(const char *path) +{ + BOOL dres = CreateDirectoryA(path, NULL); + + if (!dres) { + DWORD dw = GetLastError(); + + if (dw != ERROR_ALREADY_EXISTS) + error("Unable to create directory '%s'", path); + } +} + +RESTORE_WARNING_UNREACHABLE_CODE + +int +build_known_folder_path(const KNOWNFOLDERID *folder_id, char *path, + size_t path_size, boolean versioned) +{ + if (!get_known_folder_path(folder_id, path, path_size)) + return FALSE; + + strcat(path, "\\NetHack\\"); + create_directory(path); + if (versioned) { + Sprintf(eos(path), "%d.%d\\", VERSION_MAJOR, VERSION_MINOR); + create_directory(path); + } + return TRUE; +} + +void +build_environment_path(const char *env_str, const char *folder, char *path, + size_t path_size) +{ + path[0] = '\0'; + + const char *root_path = nh_getenv(env_str); + + if (root_path == NULL) + return; + + strcpy_s(path, path_size, root_path); + + char *colon = strchr(path, ';'); + if (colon != NULL) + path[0] = '\0'; + + if (strlen(path) == 0) + return; + + append_slash(path); + + if (folder != NULL) { + strcat_s(path, path_size, folder); + strcat_s(path, path_size, "\\"); + } +} + +boolean +folder_file_exists(const char *folder, const char *file_name) +{ + char path[MAX_PATH]; + + if (folder[0] == '\0') + return FALSE; + + strcpy(path, folder); + strcat(path, file_name); + return file_exists(path); +} + +boolean +file_exists(const char *path) +{ + struct stat sb; + + /* Just see if it's there */ + if (stat(path, &sb)) { + return FALSE; + } + return TRUE; +} + +void +set_default_prefix_locations(const char *programPath UNUSED) +{ + static char executable_path[MAX_PATH]; + static char profile_path[MAX_PATH]; + static char versioned_profile_path[MAX_PATH]; + static char versioned_user_data_path[MAX_PATH]; + static char versioned_global_data_path[MAX_PATH]; + /* static char versioninfo[20] UNUSED; */ + + strcpy(executable_path, get_executable_path()); + append_slash(executable_path); + + if (test_portable_config(executable_path, portable_device_path, + sizeof portable_device_path)) { + gf.fqn_prefix[SYSCONFPREFIX] = executable_path; + gf.fqn_prefix[CONFIGPREFIX] = portable_device_path; + gf.fqn_prefix[HACKPREFIX] = portable_device_path; + gf.fqn_prefix[SAVEPREFIX] = portable_device_path; + gf.fqn_prefix[LEVELPREFIX] = portable_device_path; + gf.fqn_prefix[BONESPREFIX] = portable_device_path; + gf.fqn_prefix[SCOREPREFIX] = portable_device_path; + gf.fqn_prefix[LOCKPREFIX] = portable_device_path; + gf.fqn_prefix[TROUBLEPREFIX] = portable_device_path; + gf.fqn_prefix[DATAPREFIX] = executable_path; + } else { + if (!build_known_folder_path(&FOLDERID_Profile, profile_path, + sizeof(profile_path), FALSE)) + strcpy(profile_path, executable_path); + + if (!build_known_folder_path(&FOLDERID_Profile, + versioned_profile_path, + sizeof(profile_path), TRUE)) + strcpy(versioned_profile_path, executable_path); + + if (!build_known_folder_path(&FOLDERID_LocalAppData, + versioned_user_data_path, + sizeof(versioned_user_data_path), TRUE)) + strcpy(versioned_user_data_path, executable_path); + + if (!build_known_folder_path( + &FOLDERID_ProgramData, versioned_global_data_path, + sizeof(versioned_global_data_path), TRUE)) + strcpy(versioned_global_data_path, executable_path); + + gf.fqn_prefix[SYSCONFPREFIX] = versioned_global_data_path; + gf.fqn_prefix[CONFIGPREFIX] = profile_path; + gf.fqn_prefix[HACKPREFIX] = versioned_profile_path; + gf.fqn_prefix[SAVEPREFIX] = versioned_user_data_path; + gf.fqn_prefix[LEVELPREFIX] = versioned_user_data_path; + gf.fqn_prefix[BONESPREFIX] = versioned_global_data_path; + gf.fqn_prefix[SCOREPREFIX] = versioned_global_data_path; + gf.fqn_prefix[LOCKPREFIX] = versioned_global_data_path; + gf.fqn_prefix[TROUBLEPREFIX] = versioned_profile_path; + gf.fqn_prefix[DATAPREFIX] = executable_path; + } +} + +/* + * Add a backslash to any name not ending in /, \ or : There must + * be room for the \ + */ +void +append_slash(char *name) +{ + char *ptr; + + if (!*name) + return; + ptr = name + (strlen(name) - 1); + if (*ptr != '\\' && *ptr != '/' && *ptr != ':') { + *++ptr = '\\'; + *++ptr = '\0'; + } + return; +} + +void set_default_prefix_locations(const char *programPath); +boolean +test_portable_config(const char *executable_path, char *portable_device_path, + size_t portable_device_path_size) +{ + int lth = 0; + const char *sysconf = "sysconf"; + char tmppath[MAX_PATH]; + boolean retval = FALSE, + save_initoptions_noterminate = iflags.initoptions_noterminate; + + if (portable_device_path + && folder_file_exists(executable_path, "sysconf")) { + /* + There is a sysconf file (not just sysconf.template) present in + the exe path, which is not the way NetHack is initially + distributed, so assume it means that the admin/installer wants to + override something, perhaps set up for a fully-portable + configuration that leaves no traces behind elsewhere on this + computer's hard drive - delve into that... + */ + + *portable_device_path = '\0'; + lth = sizeof tmppath - strlen(sysconf); + (void) strncpy(tmppath, executable_path, lth - 1); + tmppath[lth - 1] = '\0'; + (void) strcat(tmppath, sysconf); + + iflags.initoptions_noterminate = 1; + /* assure_syscf_file(); */ + config_error_init(TRUE, tmppath, FALSE); + /* ... and _must_ parse correctly. */ + if (read_config_file(tmppath, set_in_sysconf) + && sysopt.portable_device_paths) + retval = TRUE; + (void) config_error_done(); + iflags.initoptions_noterminate = save_initoptions_noterminate; + sysopt_release(); /* the real sysconf processing comes later */ + } + if (retval) { + lth = strlen(executable_path); + if (lth <= (int) portable_device_path_size - 1) + Strcpy(portable_device_path, executable_path); + else + retval = FALSE; + } + return retval; +} + +const char * +get_portable_device(void) +{ + return (const char *) portable_device_path; +} + /* Windows helpers for CRASHREPORT etc */ #ifdef CRASHREPORT struct CRctxt { diff --git a/sys/windows/winos.h b/sys/windows/winos.h index 132b153e0..aed062035 100644 --- a/sys/windows/winos.h +++ b/sys/windows/winos.h @@ -7,6 +7,10 @@ #include "win32api.h" +#ifndef PATH_SEPARATOR +#define PATH_SEPARATOR '\\' +#endif + extern const WCHAR cp437[256]; WCHAR * From c5946c6a43414bb18049dac53315f5f648e0ac31 Mon Sep 17 00:00:00 2001 From: nhmall Date: Thu, 22 May 2025 10:07:29 -0400 Subject: [PATCH 636/791] Windows GNUmakefile library update --- sys/windows/GNUmakefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/windows/GNUmakefile b/sys/windows/GNUmakefile index 0698ae200..21c6e0d74 100644 --- a/sys/windows/GNUmakefile +++ b/sys/windows/GNUmakefile @@ -362,7 +362,7 @@ CONSOLEDEF = $(COMMONDEF) -D_CONSOLE # To build util targets CFLAGSU = $(CFLAGS) $(CONSOLEDEF) $(DLBFLG) -LIBS = -lcomctl32 -lgdi32 -lole32 -lshell32 -luuid -lwinmm -lbcrypt +LIBS = -lcomctl32 -lgdi32 -lole32 -lshell32 -luserenv -luuid -lwinmm -lbcrypt $(GAMEDIR): @mkdir -p $@ From 3c25b8312155b50997bba07059780bc9a52842b3 Mon Sep 17 00:00:00 2001 From: nhmall Date: Thu, 22 May 2025 10:13:44 -0400 Subject: [PATCH 637/791] visual studio project file updates --- sys/windows/vs/NetHack/NetHack.vcxproj | 2 +- sys/windows/vs/NetHackW/NetHackW.vcxproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sys/windows/vs/NetHack/NetHack.vcxproj b/sys/windows/vs/NetHack/NetHack.vcxproj index 9da54976c..7dfa0cf6b 100644 --- a/sys/windows/vs/NetHack/NetHack.vcxproj +++ b/sys/windows/vs/NetHack/NetHack.vcxproj @@ -57,7 +57,7 @@ /Gs /Oi- /w44774 /w45262 %(AdditionalOptions) - hacklib.lib;lualib.lib;kernel32.lib;dbghelp.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;winmm.lib;Winmm.lib;bcrypt.lib;%(AdditionalDependencies) + hacklib.lib;lualib.lib;kernel32.lib;dbghelp.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;winmm.lib;Winmm.lib;UserEnv.lib;bcrypt.lib;%(AdditionalDependencies) $(SndWavDir);%(AdditionalIncludeDirectories) diff --git a/sys/windows/vs/NetHackW/NetHackW.vcxproj b/sys/windows/vs/NetHackW/NetHackW.vcxproj index 6c0360d49..78a43906d 100644 --- a/sys/windows/vs/NetHackW/NetHackW.vcxproj +++ b/sys/windows/vs/NetHackW/NetHackW.vcxproj @@ -74,7 +74,7 @@ Windows - hacklib.lib;lualib.lib;dbghelp.lib;comctl32.lib;winmm.lib;bcrypt.lib;%(AdditionalDependencies) + hacklib.lib;lualib.lib;dbghelp.lib;comctl32.lib;winmm.lib;UserEnv.lib;bcrypt.lib;%(AdditionalDependencies) $(WinWin32Dir)NethackW.exe.manifest;%(AdditionalManifestFiles) From ec8fab9d7a5851777bb61167624502274dc6d4b3 Mon Sep 17 00:00:00 2001 From: nhmall Date: Thu, 22 May 2025 14:04:10 -0400 Subject: [PATCH 638/791] more config-file code relocations --- src/cfgfiles.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/files.c | 43 --------------------------- src/pline.c | 37 ----------------------- 3 files changed, 80 insertions(+), 80 deletions(-) diff --git a/src/cfgfiles.c b/src/cfgfiles.c index bf48bf9f6..3e1197a4e 100644 --- a/src/cfgfiles.c +++ b/src/cfgfiles.c @@ -9,10 +9,20 @@ #include "dlb.h" #include +#if (!defined(MAC) && !defined(O_WRONLY) && !defined(AZTEC_C)) \ + || defined(USE_FCNTL) +#include +#endif + +#define BIGBUFSZ (5 * BUFSZ) /* big enough to format a 4*BUFSZ string (from + * config file parsing) with modest decoration; + * result will then be truncated to BUFSZ-1 */ + #ifdef USER_SOUNDS extern char *sounddir; /* defined in sounds.c */ #endif +staticfn void vconfig_error_add(const char *, va_list); staticfn FILE *fopen_config_file(const char *, int); staticfn int get_uchars(char *, uchar *, boolean, int, const char *); #ifdef NOCWD_ASSUMPTIONS @@ -1819,6 +1829,36 @@ parse_conf_file(FILE *fp, boolean (*proc)(char *arg)) return parser.rv; } +DISABLE_WARNING_FORMAT_NONLITERAL + +void +config_error_add(const char *str, ...) +{ + va_list the_args; + + va_start(the_args, str); + vconfig_error_add(str, the_args); + va_end(the_args); +} + +staticfn void +vconfig_error_add(const char *str, va_list the_args) +{ /* start of vconf...() or of nested block in USE_OLDARG's conf...() */ + int vlen = 0; + char buf[BIGBUFSZ]; /* will be chopped down to BUFSZ-1 if longer */ + + vlen = vsnprintf(buf, sizeof buf, str, the_args); +#if (NH_DEVEL_STATUS != NH_STATUS_RELEASED) && defined(DEBUG) + if (vlen >= (int) sizeof buf) + panic("%s: truncation of buffer at %zu of %d bytes", + "config_error_add", sizeof buf, vlen); +#else + nhUse(vlen); +#endif + buf[BUFSZ - 1] = '\0'; + config_erradd(buf); +} + #ifdef SYSCF staticfn void parseformat(int *arr, char *str) @@ -1852,6 +1892,46 @@ parseformat(int *arr, char *str) } } } +#ifdef SYSCF_FILE +void +assure_syscf_file(void) +{ + int fd; + +#ifdef WIN32 + /* We are checking that the sysconf exists ... lock the path */ + fqn_prefix_locked[SYSCONFPREFIX] = TRUE; +#endif + /* + * All we really care about is the end result - can we read the file? + * So just check that directly. + * + * Not tested on most of the old platforms (which don't attempt + * to implement SYSCF). + * Some ports don't like open()'s optional third argument; + * VMS overrides open() usage with a macro which requires it. + */ +#ifndef VMS +#if defined(NOCWD_ASSUMPTIONS) && defined(WIN32) + fd = open(fqname(SYSCF_FILE, SYSCONFPREFIX, 0), O_RDONLY); +#else + fd = open(SYSCF_FILE, O_RDONLY); +#endif +#else + fd = open(SYSCF_FILE, O_RDONLY, 0); +#endif + if (fd >= 0) { + /* readable */ + close(fd); + return; + } + if (gd.deferred_showpaths) + do_deferred_showpaths(1); /* does not return */ + raw_printf("Unable to open SYSCF_FILE.\n"); + exit(EXIT_FAILURE); +} + +#endif /* SYSCF_FILE */ #endif /* SYSCF */ /* ---------- END CONFIG FILE HANDLING ----------- */ diff --git a/src/files.c b/src/files.c index cd8ea9815..90ab61076 100644 --- a/src/files.c +++ b/src/files.c @@ -2603,49 +2603,6 @@ recover_savefile(void) /* ---------- OTHER ----------- */ -#ifdef SYSCF -#ifdef SYSCF_FILE -void -assure_syscf_file(void) -{ - int fd; - -#ifdef WIN32 - /* We are checking that the sysconf exists ... lock the path */ - fqn_prefix_locked[SYSCONFPREFIX] = TRUE; -#endif - /* - * All we really care about is the end result - can we read the file? - * So just check that directly. - * - * Not tested on most of the old platforms (which don't attempt - * to implement SYSCF). - * Some ports don't like open()'s optional third argument; - * VMS overrides open() usage with a macro which requires it. - */ -#ifndef VMS -# if defined(NOCWD_ASSUMPTIONS) && defined(WIN32) - fd = open(fqname(SYSCF_FILE, SYSCONFPREFIX, 0), O_RDONLY); -# else - fd = open(SYSCF_FILE, O_RDONLY); -# endif -#else - fd = open(SYSCF_FILE, O_RDONLY, 0); -#endif - if (fd >= 0) { - /* readable */ - close(fd); - return; - } - if (gd.deferred_showpaths) - do_deferred_showpaths(1); /* does not return */ - raw_printf("Unable to open SYSCF_FILE.\n"); - exit(EXIT_FAILURE); -} - -#endif /* SYSCF_FILE */ -#endif /* SYSCF */ - ATTRNORETURN void do_deferred_showpaths(int code) { diff --git a/src/pline.c b/src/pline.c index 7a1bc1511..48f8fc89f 100644 --- a/src/pline.c +++ b/src/pline.c @@ -682,43 +682,6 @@ execplinehandler(const char *line) #endif } -/* - * varargs handling for files.c - */ -staticfn void vconfig_error_add(const char *, va_list); - -DISABLE_WARNING_FORMAT_NONLITERAL - -void -config_error_add(const char *str, ...) -{ - va_list the_args; - - va_start(the_args, str); - vconfig_error_add(str, the_args); - va_end(the_args); -} - -staticfn void -vconfig_error_add(const char *str, va_list the_args) -{ /* start of vconf...() or of nested block in USE_OLDARG's conf...() */ - int vlen = 0; - char buf[BIGBUFSZ]; /* will be chopped down to BUFSZ-1 if longer */ - - vlen = vsnprintf(buf, sizeof buf, str, the_args); -#if (NH_DEVEL_STATUS != NH_STATUS_RELEASED) && defined(DEBUG) - if (vlen >= (int) sizeof buf) - panic("%s: truncation of buffer at %zu of %d bytes", - "config_error_add", sizeof buf, vlen); -#else - nhUse(vlen); -#endif - buf[BUFSZ - 1] = '\0'; - config_erradd(buf); -} - -RESTORE_WARNING_FORMAT_NONLITERAL - /* nhassert_failed is called when an nhassert's condition is false */ void nhassert_failed(const char *expression, const char *filepath, int line) From 15ced6f1ff9b7b8f1ee38e519c28c8505c14601c Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Fri, 23 May 2025 17:21:24 +0300 Subject: [PATCH 639/791] Fix pet apport value Fuzzer encountered a case where a pet apport ended up being zero: the reviving tame troll already had edog structure, so it was not reset. --- src/dog.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/dog.c b/src/dog.c index d77ad17a9..d0d4e7f3c 100644 --- a/src/dog.c +++ b/src/dog.c @@ -66,6 +66,9 @@ initedog(struct monst *mtmp, boolean everything) edogp->revivals = 0; edogp->mhpmax_penalty = 0; edogp->killed_by_u = 0; + } else { + if (edogp->apport <= 0) + edogp->apport = 1; } /* always set for newly tamed pet or feral former pet; hungrytime might already be higher when taming magic affects already tame monst */ From f4a6da2e52046a07657388f71edba24ef047a8eb Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 25 May 2025 15:03:13 -0400 Subject: [PATCH 640/791] save/restore changes - part 2 This is the second of a series of changes related to save/restore. No EDITLEVEL bump has been included, because although the code is changed extensively by this, the content of the savefiles have not been changed. Push the use of the structlevel bwrite() and mread() function use out of the core and into sfstruct.c. This is groundwork for upcoming changes. In the core, replace the bwrite() and mread() calls with the use of type-specific savefile output (Sfo) and savefile input (Sfi) macros. The macros are defined in a new header file savefile.h, which also contains the prototypes for the sfo_* and sfi_* functions that the macros ultimately expand to. The functions themselves are in src/sfbase.c. On C99, each Sfo or Sfi macro expansion refers directly to the corresponding type-specific sfo_* or sfi_* function. If C23 or later is is use, the majority (all but 3 types) of the macros refer to a single _Generic output routine sfo(nhfp, dt, tag), and a single _Generic input routine sfi(nhfp, dt, tag), which handles the dispatch of the type-specific underlying functions. This was somewhat experimental, but turned out to be practical because the compiler would gripe if the type for a variable was not included in the _Generic when passed as an argument, so it could be fixed. This alters the savefile verication process by having a common set return values for the related functions such as uptodate(), check_version(), etc. The new return values return more information about savefile incompatibilities, beyond failure/sucess. The additional information will be useful for an upcoming addition. The expanded return values are: SF_UPTODATE (0) everything matched and looks good SF_OUTDATED (1) savefile is outdated SF_CRITICAL_BYTE_COUNT_MISMATCH (2) critical size count mismatch SF_DM_IL32LLP64_ON_ILP32LL64 (3) Windows x64 savefile on x86 SF_DM_I32LP64_ON_ILP32LL64 (4) Unix 64 savefile on x86 SF_DM_ILP32LL64_ON_I32LP64 (5) x86 savefile on Unix 64 SF_DM_ILP32LL64_ON_IL32LLP64 (6) x86 savefile on Windows x64 SF_DM_I32LP64_ON_IL32LLP64 (7) Unix 64 savefile on Windows x64 SF_DM_IL32LLP64_ON_I32LP64 (8) Windows x64 savefile on Unix 64 SF_DM_MISMATCH (9) some other mismatch The callers in the core have been adjusted to deal with the expanded return values. Other miscellaneous inclusions: - go.oracle_loc -> svo.oracle_loc. - add a bit (1UL << 30) to called SFCTOOL_BIT as groundwork for changes to follow. --- .gitignore | 1 + doc/Guidebook.mn | 14 - doc/Guidebook.tex | 16 - include/config.h | 2 +- include/decl.h | 6 +- include/extern.h | 9 +- include/global.h | 1 + include/hack.h | 59 ++- include/hacklib.h | 2 + include/savefile.h | 605 +++++++++++++++++++++++ include/sfprocs.h | 199 ++++++++ src/artifact.c | 31 +- src/bones.c | 41 +- src/cfgfiles.c | 6 +- src/decl.c | 4 +- src/dungeon.c | 175 +++---- src/end.c | 14 +- src/engrave.c | 51 +- src/files.c | 310 +++++++++--- src/hacklib.c | 49 ++ src/light.c | 24 +- src/mdlib.c | 37 +- src/mkmaze.c | 36 +- src/mkroom.c | 18 +- src/muse.c | 2 +- src/nhlua.c | 19 +- src/o_init.c | 47 +- src/options.c | 17 +- src/region.c | 175 +++---- src/restore.c | 388 ++++++--------- src/rumors.c | 37 +- src/save.c | 365 +++++--------- src/sfbase.c | 209 ++++++++ src/sfstruct.c | 398 ++++++++++++++- src/sys.c | 3 +- src/timeout.c | 47 +- src/track.c | 27 +- src/version.c | 192 ++++--- src/worm.c | 39 +- sys/share/pcmain.c | 5 +- sys/unix/Makefile.src | 25 +- sys/unix/Makefile.utl | 2 + sys/vms/Makefile.src | 21 +- sys/windows/Makefile.nmake | 67 ++- sys/windows/vs/NetHack/NetHack.vcxproj | 5 +- sys/windows/vs/NetHackW/NetHackW.vcxproj | 5 +- sys/windows/windmain.c | 3 + sys/windows/windsys.c | 14 - util/.gitignore | 1 + util/recover.c | 15 +- 50 files changed, 2551 insertions(+), 1287 deletions(-) create mode 100644 include/savefile.h create mode 100644 include/sfprocs.h create mode 100644 src/sfbase.c diff --git a/.gitignore b/.gitignore index f7849967c..f5a18b7e3 100644 --- a/.gitignore +++ b/.gitignore @@ -56,6 +56,7 @@ Makefile.gcc-orig *.lastcodeanalysissucceeded # VS 2017 caches data into the hidden directory .vs .vs +win/win32/vs/obj/* # Win32-specific ignores end .DS_Store # ms-dos diff --git a/doc/Guidebook.mn b/doc/Guidebook.mn index e852ff559..dae3b6713 100644 --- a/doc/Guidebook.mn +++ b/doc/Guidebook.mn @@ -6118,20 +6118,6 @@ the message as the only parameter. MAXPLAYERS\ =\ Limit the maximum number of games that can be running at the same time. .lp -SAVEFORMAT\ =\ A list of up to two save file formats separated by space. -The first format in the list will written as well as read. The second format -will be read only if no save file in the first format exists. -Valid choices are \(lqhistorical\(rq for binary writing of entire structs, -\(lqlendian\(rq for binary writing of each field in little-endian order, -\(lqascii\(rq for writing the save file content in ascii text. -.lp -BONESFORMAT\ =\ A list of up to two bones file formats separated by space. -The first format in the list will written as well as read. The second format -will be read only if no bones files in the first format exist. -Valid choices are \(lqhistorical\(rq for binary writing of entire structs, -\(lqlendian\(rq for binary writing of each field in little-endian order, -\(lqascii\(rq for writing the bones file content in ascii text. -.lp SUPPORT\ =\ A string explaining how to get local support (no default value). .lp RECOVER\ =\ A string explaining how to recover a game on this system diff --git a/doc/Guidebook.tex b/doc/Guidebook.tex index f590cefa3..a54d02b68 100644 --- a/doc/Guidebook.tex +++ b/doc/Guidebook.tex @@ -6768,22 +6768,6 @@ the message as the only parameter. \item[\ib{MAXPLAYERS}] Limit the maximum number of games that can be running at the same time. %.lp -\item[\ib{SAVEFORMAT}] -A list of up to two save file formats separated by space. -The first format in the list will written as well as read. The second format -will be read only if no save file in the first format exists. -Valid choices are ``{\tt historical}'' for binary writing of entire structs, -``{\tt lendian}'' for binary writing of each field in little-endian order, -``{\tt ascii}'' for writing the save file content in ascii text. -%.lp -\item[\ib{BONESFORMAT}] -A list of up to two bones file formats separated by space. -The first format in the list will written as well as read. The second -format will be read only if no bones files in the first format exist. -Valid choices are ``{\tt historical}'' for binary writing of entire structs, -``{\tt lendian}'' for binary writing of each field in little-endian order, -``{\tt ascii}'' for writing the bones file content in ascii text. -%.lp \item[\ib{SUPPORT}] A string explaining how to get local support (no default value). %.lp diff --git a/include/config.h b/include/config.h index 14bfdc2e8..f14273810 100644 --- a/include/config.h +++ b/include/config.h @@ -259,7 +259,7 @@ # ifdef CRASHREPORT # undef CRASHREPORT # endif -# ifdef MSDOS +# if defined(MSDOS) || defined(NOPANICTRACE) # undef PANICTRACE # endif #endif diff --git a/include/decl.h b/include/decl.h index db9042445..54cf2f390 100644 --- a/include/decl.h +++ b/include/decl.h @@ -296,6 +296,9 @@ struct instance_globals_c { short corpsenm_digested; /* monster type being digested, set by gulpum */ /* zap.c */ + /* new */ + boolean converted_savefile_loaded; + boolean havestate; }; @@ -735,7 +738,6 @@ struct instance_globals_o { /* rumors.c */ int oracle_flg; /* -1=>don't use, 0=>need init, 1=>init done */ - unsigned long *oracle_loc; /* uhitm.c */ boolean override_confirmation; /* Used to flag attacks caused by @@ -1169,6 +1171,8 @@ struct instance_globals_saved_n { struct instance_globals_saved_o { /* rumors.c */ unsigned oracle_cnt; /* oracles are handled differently from rumors... */ + unsigned long *oracle_loc; + /* other */ long omoves; /* level timestamp */ }; diff --git a/include/extern.h b/include/extern.h index 63c6800fc..42e47a3d4 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1969,6 +1969,7 @@ extern int dosuspend(void); extern void nt_regularize(char *); extern int(*nt_kbhit)(void); extern void Delay(int); +extern boolean contains_directory(const char *); # ifdef CRASHREPORT struct CRctxt; extern struct CRctxt *ctxp; @@ -1976,7 +1977,6 @@ extern int win32_cr_helper(char, struct CRctxt *, void *, int); extern int win32_cr_gettrace(int, char *, int); extern int *win32_cr_shellexecute(const char *); # endif -extern boolean contains_directory(const char *); #endif /* WIN32 */ #endif /* MICRO || WIN32 */ @@ -2675,7 +2675,6 @@ extern void get_plname_from_file(NHFILE *, char *, boolean) NONNULLARG12; extern int restore_menu(winid); #endif extern boolean lookup_id_mapping(unsigned, unsigned *) NONNULLARG2; -extern int validate(NHFILE *, const char *, boolean) NONNULLARG1; /* extern void reset_restpref(void); */ /* extern void set_restpref(const char *); */ /* extern void set_savepref(const char *); */ @@ -3496,8 +3495,7 @@ extern boolean comp_times(long); #endif extern boolean check_version(struct version_info *, const char *, boolean, unsigned long) NONNULLARG1; -extern boolean uptodate(NHFILE *, const char *, unsigned long) NONNULLARG1; -extern void store_formatindicator(NHFILE *) NONNULLARG1; +extern int uptodate(NHFILE *, const char *, unsigned long) NONNULLARG1; extern void store_version(NHFILE *) NONNULLARG1; extern unsigned long get_feature_notice_ver(char *) NO_NNARGS; extern unsigned long get_current_feature_ver(void); @@ -3505,8 +3503,9 @@ extern const char *copyright_banner_line(int) NONNULL; extern void early_version_info(boolean); extern void dump_version_info(void); extern void store_critical_bytes(NHFILE *) NONNULLARG1; -extern int compare_critical_bytes(NHFILE *); +extern int compare_critical_bytes(NHFILE *, int *, unsigned long) NONNULLARG1; extern int get_critical_size_count(void); +extern int validate(NHFILE *, const char *, boolean) NONNULLARG1; /* ### video.c ### */ diff --git a/include/global.h b/include/global.h index a38c7722b..727929d09 100644 --- a/include/global.h +++ b/include/global.h @@ -569,4 +569,5 @@ typedef enum NHL_pcall_action { NHLpa_impossible } NHL_pcall_action; +#define SFCTOOL_BIT (1UL << 30) /* needed for upcoming savefile handling */ #endif /* GLOBAL_H */ diff --git a/include/hack.h b/include/hack.h index bf50ff3d9..9960d223e 100644 --- a/include/hack.h +++ b/include/hack.h @@ -766,13 +766,6 @@ struct role_filter { }; #define NUM_RACES (5) -enum saveformats { - invalid = 0, - historical = 1, /* entire struct, binary, as-is */ - lendian = 2, /* each field, binary, little-endian */ - ascii = 3 /* each field, ascii text (just proof of concept) */ -}; - struct selectionvar { int wid, hei; boolean bounds_dirty; @@ -899,6 +892,19 @@ typedef struct { #define UTD_SKIP_SANITY1 0x04 #define UTD_SKIP_SAVEFILEINFO 0x08 #define UTD_WITHOUT_WAITSYNCH_PERFILE 0x10 +#define UTD_QUIETLY 0x20 + +/* Values for savefile status */ +#define SF_UPTODATE 0 +#define SF_OUTDATED 1 +#define SF_CRITICAL_BYTE_COUNT_MISMATCH 2 +#define SF_DM_IL32LLP64_ON_ILP32LL64 3 /* Wind x64 savefile on x86 */ +#define SF_DM_I32LP64_ON_ILP32LL64 4 /* Unix 64 savefile on x86 */ +#define SF_DM_ILP32LL64_ON_I32LP64 5 /* x86 savefile on Unix 64 */ +#define SF_DM_ILP32LL64_ON_IL32LLP64 6 /* x86 savefile on Wind x64 */ +#define SF_DM_I32LP64_ON_IL32LLP64 7 /* Unix 64 savefile on Wind x64 */ +#define SF_DM_IL32LLP64_ON_I32LP64 8 /* Wind x64 savefile on Unix 64 */ +#define SF_DM_MISMATCH 9 /* generic savefile byte mismatch */ #define ENTITIES 2 struct valuable_data { @@ -940,28 +946,43 @@ struct xlock_s { boolean magic_key; }; +#define MAX_BMASK 4 + /* NetHack ftypes */ #define NHF_LEVELFILE 1 #define NHF_SAVEFILE 2 #define NHF_BONESFILE 3 /* modes */ -#define READING 0x0 -#define COUNTING 0x1 -#define WRITING 0x2 -#define FREEING 0x4 -#define MAX_BMASK 4 +#define READING 0x0 +#define COUNTING 0x1 +#define WRITING 0x2 +#define FREEING 0x4 +#define CONVERTING 0x08 +#define UNCONVERTING 0x10 +#if 0 /* operations of the various saveXXXchn & co. routines */ #define perform_bwrite(nhfp) ((nhfp)->mode & (COUNTING | WRITING)) #define release_data(nhfp) ((nhfp)->mode & FREEING) +#endif + +/* operations of the various saveXXXchn & co. routines */ +#define update_file(nhfp) ((nhfp)->mode & (COUNTING | WRITING)) +#define release_data(nhfp) ((nhfp)->mode & FREEING) + +enum saveformats { + invalid = 0, + historical = 1, /* entire struct, binary, as-is */ + cnvascii = 2, /* each field, ascii text */ + NUM_SAVEFORMATS +}; /* Content types for fieldlevel files */ struct fieldlevel_content { boolean deflt; /* individual fields */ boolean binary; /* binary rather than text */ - boolean json; /* JSON */ }; -typedef struct { +struct nh_file { int fd; /* for traditional structlevel binary writes */ int mode; /* holds READING, WRITING, or FREEING modes */ int ftype; /* NHF_LEVELFILE, NHF_SAVEFILE, or NHF_BONESFILE */ @@ -978,7 +999,10 @@ typedef struct { FILE *fplog; /* file pointer logfile */ FILE *fpdebug; /* file pointer debug info */ struct fieldlevel_content style; -} NHFILE; + struct nh_file *nhfpconvert; +}; + +typedef struct nh_file NHFILE; /* Monster name articles */ #define ARTICLE_NONE 0 @@ -1534,8 +1558,13 @@ typedef uint32_t mmflags_nht; /* makemon MM_ flags */ #include "nhlua.h" #endif +#if !defined(RECOVER_C) + #include "extern.h" +#include "savefile.h" #include "decl.h" +#endif /* RECOVER_C */ + #endif /* HACK_H */ diff --git a/include/hacklib.h b/include/hacklib.h index 2912035a4..96b6bdf39 100644 --- a/include/hacklib.h +++ b/include/hacklib.h @@ -79,6 +79,8 @@ extern unsigned Strlen_(const char *, const char *, int) NONNULLPTRS; #endif extern int unicodeval_to_utf8str(int, uint8 *, size_t); extern boolean copy_bytes(int, int); +extern const char *datamodel(void); +extern const char *what_datamodel_is_this(int, int, int, int, int); #endif /* HACKLIB_H */ diff --git a/include/savefile.h b/include/savefile.h new file mode 100644 index 000000000..28cd24b23 --- /dev/null +++ b/include/savefile.h @@ -0,0 +1,605 @@ +/* NetHack 3.7 savefile.h $NHDT-Date: 1738638877 2025/02/03 19:14:37 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.1476 $ */ +/* Copyright (c) Michael Allison, 2025. */ +/* NetHack may be freely redistributed. See license for details. */ + +#ifndef SAVEFILE_H +#define SAVEFILE_H + +/* #define SAVEFILE_DEBUGGING */ + +extern void sf_init(void); +/* sfbase.c output functions */ +extern void sfo_aligntyp(NHFILE *, aligntyp *, const char *); +extern void sfo_any(NHFILE *, anything *, const char *); +extern void sfo_boolean(NHFILE *, boolean *, const char *); +extern void sfo_char(NHFILE *, char *, const char *, int); +extern void sfo_genericptr(NHFILE *, genericptr_t *, const char *); +extern void sfo_int16(NHFILE *, int16 *, const char *); +extern void sfo_int32(NHFILE *, int32 *, const char *); +extern void sfo_int64(NHFILE *, int64 *, const char *); +extern void sfo_uchar(NHFILE *, uchar *, const char *); +extern void sfo_uint16(NHFILE *, uint16 *, const char *); +extern void sfo_uint32(NHFILE *, uint32 *, const char *); +extern void sfo_uint64(NHFILE *, uint64 *, const char *); +extern void sfo_size_t(NHFILE *, size_t *, const char *); +extern void sfo_time_t(NHFILE *, time_t *, const char *); + +extern void sfo_arti_info(NHFILE *nhfp, + struct arti_info *d_arti_info, + const char *myname); +extern void sfo_dgn_topology(NHFILE *nhfp, + struct dgn_topology *d_dgn_topology, + const char *myname); +extern void sfo_dungeon(NHFILE *nhfp, struct dungeon *d_dungeon, + const char *myname); +extern void sfo_branch(NHFILE *nhfp, struct branch *d_branch, + const char *myname); +extern void sfo_linfo(NHFILE *nhfp, struct linfo *d_linfo, + const char *myname); +extern void sfo_nhcoord(NHFILE *nhfp, struct nhcoord *d_nhcoord, + const char *myname); +extern void sfo_d_level(NHFILE *nhfp, struct d_level *d_d_level, + const char *myname); +extern void sfo_mapseen_feat(NHFILE *nhfp, + struct mapseen_feat *d_mapseen_feat, + const char *myname); +extern void sfo_mapseen_flags(NHFILE *nhfp, + struct mapseen_flags *d_mapseen_flags, + const char *myname); +extern void sfo_mapseen_rooms(NHFILE *nhfp, + struct mapseen_rooms *d_mapseen_rooms, + const char *myname); +extern void sfo_kinfo(NHFILE *nhfp, + struct kinfo *d_kinfo, + const char *myname); +extern void sfo_engr(NHFILE *, struct engr *, const char *); +extern void sfo_ls_t(NHFILE *, struct ls_t *, const char *); +extern void sfo_bubble(NHFILE *, struct bubble *, const char *); +extern void sfo_mkroom(NHFILE *, struct mkroom *, const char *); +extern void sfo_objclass(NHFILE *, struct objclass *, const char *); +extern void sfo_nhrect(NHFILE *, struct nhrect *, const char *); +extern void sfo_fe(NHFILE *, struct fe *, const char *); +extern void sfo_version_info(NHFILE *, struct version_info *, + const char *); +extern void sfo_context_info(NHFILE *, struct context_info *, + const char *); +extern void sfo_flag(NHFILE *, struct flag *, const char *); +extern void sfo_you(NHFILE *, struct you *, const char *); +extern void sfo_mvitals(NHFILE *, struct mvitals *, const char *); +extern void sfo_q_score(NHFILE *, struct q_score *, const char *); +extern void sfo_spell(NHFILE *, struct spell *, const char *); +extern void sfo_dest_area(NHFILE *, struct dest_area *, const char *); +extern void sfo_levelflags(NHFILE *, struct levelflags *, const char *); +extern void sfo_rm(NHFILE *, struct rm *, const char *); +extern void sfo_cemetery(NHFILE *, struct cemetery *, const char *); +extern void sfo_damage(NHFILE *, struct damage *, const char *); +extern void sfo_stairway(NHFILE *, struct stairway *, const char *); +extern void sfo_obj(NHFILE *, struct obj *, const char *); +extern void sfo_monst(NHFILE *, struct monst *, const char *); +extern void sfo_ebones(NHFILE *, struct ebones *, const char *); +extern void sfo_edog(NHFILE *, struct edog *, const char *); +extern void sfo_egd(NHFILE *, struct egd *, const char *); +extern void sfo_emin(NHFILE *, struct emin *, const char *); +extern void sfo_engr(NHFILE *, struct engr *, const char *); +extern void sfo_epri(NHFILE *, struct epri *, const char *); +extern void sfo_eshk(NHFILE *, struct eshk *, const char *); +extern void sfo_trap(NHFILE *, struct trap *, const char *); +extern void sfo_gamelog_line(NHFILE *, struct gamelog_line *, const char *); +extern void sfo_fruit(NHFILE *, struct fruit *, const char *); +extern void sfo_s_level(NHFILE *, struct s_level *, const char *); +extern void sfo_xint8(NHFILE *, xint8 *, const char *); +extern void sfo_xint16(NHFILE *, xint16 *, const char *); +extern void sfo_schar(NHFILE *, schar *, const char *); +extern void sfo_short(NHFILE *, short *, const char *); +extern void sfo_ushort(NHFILE *, ushort *, const char *); +extern void sfo_int(NHFILE *, int *, const char *); +extern void sfo_unsigned(NHFILE *, unsigned *, const char *); +extern void sfo_long(NHFILE *, long *, const char *); +extern void sfo_ulong(NHFILE *, ulong *, const char *); +/* sfbase.c input functions */ +extern void sfi_addinfo(NHFILE *, const char *, const char *); +extern void sfi_aligntyp(NHFILE *, aligntyp *, const char *); +extern void sfi_any(NHFILE *, anything *, const char *); +extern void sfi_boolean(NHFILE *, boolean *, const char *); +extern void sfi_genericptr(NHFILE *, genericptr_t *, const char *); +extern void sfi_char(NHFILE *, char *, const char *, int); +extern void sfi_int16(NHFILE *, int16 *, const char *); +extern void sfi_int32(NHFILE *, int32 *, const char *); +extern void sfi_int64(NHFILE *, int64 *, const char *); +extern void sfi_uchar(NHFILE *, uchar *, const char *); +extern void sfi_uint16(NHFILE *, uint16 *, const char *); +extern void sfi_uint32(NHFILE *, uint32 *, const char *); +extern void sfi_uint64(NHFILE *, uint64 *, const char *); +extern void sfi_size_t(NHFILE *, size_t *, const char *); +extern void sfi_time_t(NHFILE *, time_t *, const char *); +extern void sfi_arti_info(NHFILE *nhfp, + struct arti_info *d_arti_info, + const char *myname); +extern void sfi_dungeon(NHFILE *nhfp, struct dungeon *d_dungeon, + const char *myname); +extern void sfi_dgn_topology(NHFILE *nhfp, + struct dgn_topology *d_dgn_topology, + const char *myname); +extern void sfi_branch(NHFILE *nhfp, struct branch *d_branch, + const char *myname); +extern void sfi_linfo(NHFILE *nhfp, struct linfo *d_linfo, + const char *myname); +extern void sfi_nhcoord(NHFILE *nhfp, struct nhcoord *d_nhcoord, + const char *myname); +extern void sfi_d_level(NHFILE *nhfp, struct d_level *d_d_level, + const char *myname); +extern void sfi_mapseen_feat(NHFILE *nhfp, + struct mapseen_feat *d_mapseen_feat, + const char *myname); +extern void sfi_mapseen_flags(NHFILE *nhfp, + struct mapseen_flags *d_mapseen_flags, + const char *myname); +extern void sfi_mapseen_rooms(NHFILE *nhfp, + struct mapseen_rooms *d_mapseen_rooms, + const char *myname); +extern void sfi_kinfo(NHFILE *nhfp, + struct kinfo *d_kinfo, + const char *myname); +extern void sfi_engr(NHFILE *, struct engr *, const char *); +extern void sfi_ls_t(NHFILE *, struct ls_t *, const char *); +extern void sfi_bubble(NHFILE *, struct bubble *, const char *); +extern void sfi_mkroom(NHFILE *, struct mkroom *, const char *); +extern void sfi_objclass(NHFILE *, struct objclass *, const char *); +extern void sfi_nhrect(NHFILE *, struct nhrect *, const char *); +extern void sfi_fe(NHFILE *, struct fe *, const char *); +extern void sfi_version_info(NHFILE *, struct version_info *, + const char *); +extern void sfi_context_info(NHFILE *, struct context_info *, + const char *); +extern void sfi_flag(NHFILE *, struct flag *, const char *); +extern void sfi_you(NHFILE *, struct you *, const char *); +extern void sfi_mvitals(NHFILE *, struct mvitals *, const char *); +extern void sfi_q_score(NHFILE *, struct q_score *, const char *); +extern void sfi_spell(NHFILE *, struct spell *, const char *); +extern void sfi_dest_area(NHFILE *, struct dest_area *, const char *); +extern void sfi_levelflags(NHFILE *, struct levelflags *, const char *); +extern void sfi_rm(NHFILE *, struct rm *, const char *); +extern void sfi_cemetery(NHFILE *, struct cemetery *, const char *); +extern void sfi_damage(NHFILE *, struct damage *, const char *); +extern void sfi_stairway(NHFILE *, struct stairway *, const char *); +extern void sfi_obj(NHFILE *, struct obj *, const char *); +extern void sfi_monst(NHFILE *, struct monst *, const char *); +extern void sfi_ebones(NHFILE *, struct ebones *, const char *); +extern void sfi_edog(NHFILE *, struct edog *, const char *); +extern void sfi_egd(NHFILE *, struct egd *, const char *); +extern void sfi_emin(NHFILE *, struct emin *, const char *); +extern void sfi_engr(NHFILE *, struct engr *, const char *); +extern void sfi_epri(NHFILE *, struct epri *, const char *); +extern void sfi_eshk(NHFILE *, struct eshk *, const char *); +extern void sfi_trap(NHFILE *, struct trap *, const char *); +extern void sfi_fruit(NHFILE *, struct fruit *, const char *); +extern void sfi_gamelog_line(NHFILE *, struct gamelog_line *, const char *); +extern void sfi_s_level(NHFILE *, struct s_level *, const char *); +extern void sfi_xint8(NHFILE *, xint8 *, const char *); +extern void sfi_xint16(NHFILE *, xint16 *, const char *); +extern void sfi_schar(NHFILE *, schar *, const char *); +extern void sfi_short(NHFILE *, short *, const char *); +extern void sfi_ushort(NHFILE *, ushort *, const char *); +extern void sfi_int(NHFILE *, int *, const char *); +extern void sfi_unsigned(NHFILE *, unsigned *, const char *); +extern void sfi_long(NHFILE *, long *, const char *); +extern void sfi_ulong(NHFILE *, ulong *, const char *); +#if NH_C < 202300L +#define Sfo_aligntyp(a,b,c) sfo_aligntyp(a, b, c) +#define Sfo_any(a,b,c) sfo_any(a, b, c) +#define Sfo_genericptr(a,b,c) sfo_genericptr(a, b, c) +#define Sfo_coordxy(a,b,c) sfo_int16(a, b, c) +#define Sfo_char(a,b,c,d) sfo_char(a, b, c, d) +#define Sfo_int16(a,b,c) sfo_int16(a, b, c) +#define Sfo_int32(a,b,c) sfo_int32(a, b, c) +#define Sfo_int64(a,b,c) sfo_int64(a, b, c) +#define Sfo_uchar(a,b,c) sfo_uchar(a, b, c) +#define Sfo_uint16(a,b,c) sfo_uint16(a, b, c) +#define Sfo_uint32(a,b,c) sfo_uint32(a, b, c) +#define Sfo_uint64(a,b,c) sfo_uint64(a, b, c) +#define Sfo_size_t(a,b,c) sfo_size_t(a, b, c) +#define Sfo_time_t(a,b,c) sfo_time_t(a, b, c) + +#define Sfo_arti_info(a,b,c) sfo_arti_info(a, b, c) +#define Sfo_dgn_topology(a,b,c) sfo_dgn_topology(a, b, c) +#define Sfo_dungeon(a,b,c) sfo_dungeon(a, b, c) +#define Sfo_branch(a,b,c) sfo_branch(a, b, c) +#define Sfo_linfo(a,b,c) sfo_linfo(a, b, c) +#define Sfo_nhcoord(a,b,c) sfo_nhcoord(a, b, c) +#define Sfo_d_level(a,b,c) sfo_d_level(a, b, c) +#define Sfo_mapseen_feat(a,b,c) sfo_mapseen_feat(a, b, c) +#define Sfo_mapseen_flags(a,b,c) sfo_mapseen_flags(a, b, c) +#define Sfo_mapseen_rooms(a,b,c) sfo_mapseen_rooms(a, b, c) +#define Sfo_kinfo(a,b,c) sfo_kinfo(a, b, c) +#define Sfo_engr(a,b,c) sfo_engr(a, b, c) +#define Sfo_ls_t(a,b,c) sfo_ls_t(a, b, c) +#define Sfo_bubble(a,b,c) sfo_bubble(a, b, c) +#define Sfo_mkroom(a,b,c) sfo_mkroom(a, b, c) +#define Sfo_objclass(a,b,c) sfo_objclass(a, b, c) +#define Sfo_nhrect(a,b,c) sfo_nhrect(a, b, c) +#define Sfo_fe(a,b,c) sfo_fe(a, b, c) +#define Sfo_version_info(a,b,c) sfo_version_info(a, b, c) +#define Sfo_context_info(a,b,c) sfo_context_info(a, b, c) +#define Sfo_flag(a,b,c) sfo_flag(a, b, c) +#define Sfo_you(a,b,c) sfo_you(a, b, c) +#define Sfo_mvitals(a,b,c) sfo_mvitals(a, b, c) +#define Sfo_q_score(a,b,c) sfo_q_score(a, b, c) +#define Sfo_spell(a,b,c) sfo_spell(a, b, c) +#define Sfo_dest_area(a,b,c) sfo_dest_area(a, b, c) +#define Sfo_levelflags(a,b,c) sfo_levelflags(a, b, c) +#define Sfo_rm(a,b,c) sfo_rm(a, b, c) +#define Sfo_cemetery(a,b,c) sfo_cemetery(a, b, c) +#define Sfo_damage(a,b,c) sfo_damage(a, b, c) +#define Sfo_stairway(a,b,c) sfo_stairway(a, b, c) +#define Sfo_obj(a,b,c) sfo_obj(a, b, c) +#define Sfo_monst(a,b,c) sfo_monst(a, b, c) +#define Sfo_ebones(a,b,c) sfo_ebones(a, b, c) +#define Sfo_edog(a,b,c) sfo_edog(a, b, c) +#define Sfo_egd(a,b,c) sfo_egd(a, b, c) +#define Sfo_emin(a,b,c) sfo_emin(a, b, c) +#define Sfo_engr(a,b,c) sfo_engr(a, b, c) +#define Sfo_epri(a,b,c) sfo_epri(a, b, c) +#define Sfo_eshk(a,b,c) sfo_eshk(a, b, c) +#define Sfo_trap(a,b,c) sfo_trap(a, b, c) +#define Sfo_gamelog_line(a,b,c) sfo_gamelog_line(a, b, c) +#define Sfo_fruit(a,b,c) sfo_fruit(a, b, c) +#define Sfo_s_level(a,b,c) sfo_s_level(a, b, c) +#define Sfo_schar(a,b,c) sfo_schar(a, b, c); +#define Sfo_short(a, b, c) sfo_short(a, b, c) +#define Sfo_ushort(a, b, c) sfo_ushort(a, b, c) +#define Sfo_int(a, b, c) sfo_int(a, b, c) +#define Sfo_unsigned(a, b, c) sfo_unsigned(a, b, c) +#define Sfo_long(a,b,c) sfo_long(a, b, c); +#define Sfo_ulong(a,b,c) sfo_ulong(a, b, c); +#define Sfo_boolean(a,b,c) sfo_boolean(a, b, c); +#define Sfo_xint8(a, b, c) sfo_xint8(a, b, c); +#define Sfo_xint16(a, b, c) sfo_xint16(a, b, c) +/* sfbase.c input functions */ +#define Sfi_addinfo(a,b,c) sfi_addinfo(a, b, c) +#define Sfi_aligntyp(a,b,c) sfi_aligntyp(a, b, c) +#define Sfi_any(a,b,c) sfi_any(a, b, c) +#define Sfi_genericptr(a,b,c) sfi_genericptr(a, b, c) +#define Sfi_coordxy(a,b,c) sfi_int16(a, b, c) +#define Sfi_char(a,b,c,d) sfi_char(a, b, c, d) +#define Sfi_int16(a,b,c) sfi_int16(a, b, c) +#define Sfi_int32(a,b,c) sfi_int32(a, b, c) +#define Sfi_int64(a,b,c) sfi_int64(a, b, c) +#define Sfi_uchar(a,b,c) sfi_uchar(a, b, c) +#define Sfi_uint16(a,b,c) sfi_uint16(a, b, c) +#define Sfi_uint32(a,b,c) sfi_uint32(a, b, c) +#define Sfi_uint64(a,b,c) sfi_uint64(a, b, c) +#define Sfi_size_t(a,b,c) sfi_size_t(a, b, c) +#define Sfi_time_t(a,b,c) sfi_time_t(a, b, c) +#define Sfi_arti_info(a,b,c) sfi_arti_info(a, b, c) +#define Sfi_dungeon(a,b,c) sfi_dungeon(a, b, c) +#define Sfi_dgn_topology(a,b,c) sfi_dgn_topology(a, b, c) +#define Sfi_branch(a,b,c) sfi_branch(a, b, c) +#define Sfi_linfo(a,b,c) sfi_linfo(a, b, c) +#define Sfi_nhcoord(a,b,c) sfi_nhcoord(a, b, c) +#define Sfi_d_level(a,b,c) sfi_d_level(a, b, c) +#define Sfi_mapseen_feat(a,b,c) sfi_mapseen_feat(a, b, c) +#define Sfi_mapseen_flags(a,b,c) sfi_mapseen_flags(a, b, c) +#define Sfi_mapseen_rooms(a,b,c) sfi_mapseen_rooms(a, b, c) +#define Sfi_kinfo(a,b,c) sfi_kinfo(a, b, c) +#define Sfi_engr(a,b,c) sfi_engr(a, b, c) +#define Sfi_ls_t(a,b,c) sfi_ls_t(a, b, c) +#define Sfi_bubble(a,b,c) sfi_bubble(a, b, c) +#define Sfi_mkroom(a,b,c) sfi_mkroom(a, b, c) +#define Sfi_objclass(a,b,c) sfi_objclass(a, b, c) +#define Sfi_nhrect(a,b,c) sfi_nhrect(a, b, c) +#define Sfi_fe(a,b,c) sfi_fe(a, b, c) +#define Sfi_version_info(a,b,c) sfi_version_info(a, b, c) +#define Sfi_context_info(a,b,c) sfi_context_info(a, b, c) +#define Sfi_flag(a,b,c) sfi_flag(a, b, c) +#define Sfi_you(a,b,c) sfi_you(a, b, c) +#define Sfi_mvitals(a,b,c) sfi_mvitals(a, b, c) +#define Sfi_q_score(a,b,c) sfi_q_score(a, b, c) +#define Sfi_spell(a,b,c) sfi_spell(a, b, c) +#define Sfi_dest_area(a,b,c) sfi_dest_area(a, b, c) +#define Sfi_levelflags(a,b,c) sfi_levelflags(a, b, c) +#define Sfi_rm(a,b,c) sfi_rm(a, b, c) +#define Sfi_cemetery(a,b,c) sfi_cemetery(a, b, c) +#define Sfi_damage(a,b,c) sfi_damage(a, b, c) +#define Sfi_stairway(a,b,c) sfi_stairway(a, b, c) +#define Sfi_obj(a,b,c) sfi_obj(a, b, c) +#define Sfi_monst(a,b,c) sfi_monst(a, b, c) +#define Sfi_ebones(a,b,c) sfi_ebones(a, b, c) +#define Sfi_edog(a,b,c) sfi_edog(a, b, c) +#define Sfi_egd(a,b,c) sfi_egd(a, b, c) +#define Sfi_emin(a,b,c) sfi_emin(a, b, c) +#define Sfi_engr(a,b,c) sfi_engr(a, b, c) +#define Sfi_epri(a,b,c) sfi_epri(a, b, c) +#define Sfi_eshk(a,b,c) sfi_eshk(a, b, c) +#define Sfi_trap(a,b,c) sfi_trap(a, b, c) +#define Sfi_fruit(a,b,c) sfi_fruit(a, b, c) +#define Sfi_gamelog_line(a,b,c) sfi_gamelog_line(a, b, c) +#define Sfi_s_level(a,b,c) sfi_s_level(a, b, c) +#define Sfi_schar(a,b,c) sfi_schar(a, b, c); +#define Sfi_short(a, b, c) sfi_short(a, b, c) +#define Sfi_ushort(a, b, c) sfi_ushort(a, b, c) +#define Sfi_int(a, b, c) sfi_int(a, b, c); +#define Sfi_unsigned(a, b, c) sfi_unsigned(a, b, c); +#define Sfi_long(a,b,c) sfi_long(a, b, c); +#define Sfi_ulong(a,b,c) sfi_ulong(a, b, c); +#define Sfi_boolean(a,b,c) sfi_boolean(a, b, c); +#define Sfi_xint8(a, b, c) sfi_xint8(a, b, c); +#define Sfi_xint16(a, b, c) sfi_xint16(a, b, c); +#else + +#define sfo(nhfp, dt, tag) \ + _Generic( (dt), \ + anything * : sfo_any, \ + int16_t * : sfo_int16, \ + int32_t * : sfo_int32, \ + int64_t * : sfo_int64, \ + uchar * : sfo_uchar, \ + uint16_t * : sfo_uint16, \ + uint32_t * : sfo_uint32, \ + uint64_t * : sfo_uint64, \ + long * : sfo_long, \ + unsigned long * : sfo_ulong, \ + xint8 * : sfo_xint8, \ + struct arti_info * : sfo_arti_info, \ + struct nhrect * : sfo_nhrect, \ + struct branch * : sfo_branch, \ + struct bubble * : sfo_bubble, \ + struct cemetery * : sfo_cemetery, \ + struct context_info * : sfo_context_info, \ + coord * : sfo_nhcoord, \ + struct damage * : sfo_damage, \ + struct dgn_topology * : sfo_dgn_topology, \ + dungeon * : sfo_dungeon, \ + d_level * : sfo_d_level, \ + struct levelflags * : sfo_levelflags, \ + light_source * : sfo_ls_t, \ + struct dest_area * : sfo_dest_area, \ + struct ebones * : sfo_ebones, \ + struct edog * : sfo_edog, \ + struct egd * : sfo_egd, \ + struct emin * : sfo_emin, \ + struct engr * : sfo_engr, \ + struct epri * : sfo_epri, \ + struct eshk * : sfo_eshk, \ + struct fe * : sfo_fe, \ + struct flag * : sfo_flag, \ + struct fruit * : sfo_fruit, \ + struct gamelog_line * : sfo_gamelog_line, \ + struct kinfo * : sfo_kinfo, \ + struct linfo * : sfo_linfo, \ + struct mapseen_feat * : sfo_mapseen_feat, \ + struct mapseen_flags *: sfo_mapseen_flags, \ + struct mapseen_rooms *: sfo_mapseen_rooms, \ + struct mkroom * : sfo_mkroom, \ + struct monst * : sfo_monst, \ + struct mvitals * : sfo_mvitals, \ + struct obj * : sfo_obj, \ + struct objclass * : sfo_objclass, \ + struct q_score * : sfo_q_score, \ + struct rm * : sfo_rm, \ + struct spell * : sfo_spell, \ + struct stairway * : sfo_stairway, \ + struct s_level * : sfo_s_level, \ + struct trap * : sfo_trap, \ + struct version_info * : sfo_version_info, \ + struct you * : sfo_you \ + ) (nhfp, dt, tag) + +/* struct container * : sfo_container, */ +/* struct mapseen * : sfo_mapseen, */ +/* struct mextra * : sfo_mextra, */ +/* struct oextra * : sfo_oextra, */ +/* struct permonst * : sfo_permonst, */ + +#define sfi(nhfp, dt, tag) \ + _Generic( (dt), \ + anything * : sfi_any, \ + int16_t * : sfi_int16, \ + int32_t * : sfi_int32, \ + int64_t * : sfi_int64, \ + uchar * : sfi_uchar, \ + uint16_t * : sfi_uint16, \ + uint32_t * : sfi_uint32, \ + uint64_t * : sfi_uint64, \ + long * : sfi_long, \ + unsigned long * : sfi_ulong, \ + xint8 * : sfi_xint8, \ + struct arti_info * : sfi_arti_info, \ + struct nhrect * : sfi_nhrect, \ + struct branch * : sfi_branch, \ + struct bubble * : sfi_bubble, \ + struct cemetery * : sfi_cemetery, \ + struct context_info * : sfi_context_info, \ + coord * : sfi_nhcoord, \ + struct damage * : sfi_damage, \ + struct dgn_topology * : sfi_dgn_topology, \ + dungeon * : sfi_dungeon, \ + d_level * : sfi_d_level, \ + struct levelflags * : sfi_levelflags, \ + light_source * : sfi_ls_t, \ + struct dest_area * : sfi_dest_area, \ + struct ebones * : sfi_ebones, \ + struct edog * : sfi_edog, \ + struct egd * : sfi_egd, \ + struct emin * : sfi_emin, \ + struct engr * : sfi_engr, \ + struct epri * : sfi_epri, \ + struct eshk * : sfi_eshk, \ + struct fe * : sfi_fe, \ + struct flag * : sfi_flag, \ + struct fruit * : sfi_fruit, \ + struct gamelog_line * : sfi_gamelog_line, \ + struct kinfo * : sfi_kinfo, \ + struct linfo * : sfi_linfo, \ + struct mapseen_feat * : sfi_mapseen_feat, \ + struct mapseen_flags *: sfi_mapseen_flags, \ + struct mapseen_rooms *: sfi_mapseen_rooms, \ + struct mkroom * : sfi_mkroom, \ + struct monst * : sfi_monst, \ + struct mvitals * : sfi_mvitals, \ + struct obj * : sfi_obj, \ + struct objclass * : sfi_objclass, \ + struct q_score * : sfi_q_score, \ + struct rm * : sfi_rm, \ + struct spell * : sfi_spell, \ + struct stairway * : sfi_stairway, \ + struct s_level * : sfi_s_level, \ + struct trap * : sfi_trap, \ + struct version_info * : sfi_version_info, \ + struct you * : sfi_you \ + ) (nhfp, dt, tag) + +/* char * : sfo_char, */ +/* char * : sfi_char, */ +/* struct container * : sfi_container, */ +/* struct mapseen * : sfi_mapseen, */ +/* struct mextra * : sfi_mextra, */ +/* struct oextra * : sfi_oextra, */ +/* struct permonst * : sfi_permonst, */ + +#define Sfo_any(a,b,c) sfo(a, b, c) +#define Sfo_aligntyp(a,b,c) sfo(a, b, c) +#define Sfo_genericptr(a,b,c) sfo(a, b, c) +#define Sfo_coordxy(a,b,c) sfo(a, b, c) +#define Sfo_int16(a,b,c) sfo(a, b, c) +#define Sfo_int32(a,b,c) sfo(a, b, c) +#define Sfo_int64(a,b,c) sfo(a, b, c) +#define Sfo_uchar(a,b,c) sfo(a, b, c) +#define Sfo_unsigned(a,b,c) sfo(a, b, c) +#define Sfo_uchar(a,b,c) sfo(a, b, c) +#define Sfo_uint16(a,b,c) sfo(a, b, c) +#define Sfo_uint32(a,b,c) sfo(a, b, c) +#define Sfo_uint64(a,b,c) sfo(a, b, c) +#define Sfo_size_t(a,b,c) sfo(a, b, c) +#define Sfo_time_t(a,b,c) sfo(a, b, c) + +#define Sfo_arti_info(a,b,c) sfo(a, b, c) +#define Sfo_dgn_topology(a,b,c) sfo(a, b, c) +#define Sfo_dungeon(a,b,c) sfo(a, b, c) +#define Sfo_branch(a,b,c) sfo(a, b, c) +#define Sfo_linfo(a,b,c) sfo(a, b, c) +#define Sfo_nhcoord(a,b,c) sfo(a, b, c) +#define Sfo_d_level(a,b,c) sfo(a, b, c) +#define Sfo_mapseen_feat(a,b,c) sfo(a, b, c) +#define Sfo_mapseen_flags(a,b,c) sfo(a, b, c) +#define Sfo_mapseen_rooms(a,b,c) sfo(a, b, c) +#define Sfo_kinfo(a,b,c) sfo(a, b, c) +#define Sfo_engr(a,b,c) sfo(a, b, c) +#define Sfo_ls_t(a,b,c) sfo(a, b, c) +#define Sfo_bubble(a,b,c) sfo(a, b, c) +#define Sfo_mkroom(a,b,c) sfo(a, b, c) +#define Sfo_objclass(a,b,c) sfo(a, b, c) +#define Sfo_nhrect(a,b,c) sfo(a, b, c) +#define Sfo_fe(a,b,c) sfo(a, b, c) +#define Sfo_version_info(a,b,c) sfo(a, b, c) +#define Sfo_context_info(a,b,c) sfo(a, b, c) +#define Sfo_flag(a,b,c) sfo(a, b, c) +#define Sfo_you(a,b,c) sfo(a, b, c) +#define Sfo_mvitals(a,b,c) sfo(a, b, c) +#define Sfo_q_score(a,b,c) sfo(a, b, c) +#define Sfo_spell(a,b,c) sfo(a, b, c) +#define Sfo_dest_area(a,b,c) sfo(a, b, c) +#define Sfo_levelflags(a,b,c) sfo(a, b, c) +#define Sfo_rm(a,b,c) sfo(a, b, c) +#define Sfo_cemetery(a,b,c) sfo(a, b, c) +#define Sfo_damage(a,b,c) sfo(a, b, c) +#define Sfo_stairway(a,b,c) sfo(a, b, c) +#define Sfo_obj(a,b,c) sfo(a, b, c) +#define Sfo_monst(a,b,c) sfo(a, b, c) +#define Sfo_ebones(a,b,c) sfo(a, b, c) +#define Sfo_edog(a,b,c) sfo(a, b, c) +#define Sfo_egd(a,b,c) sfo(a, b, c) +#define Sfo_emin(a,b,c) sfo(a, b, c) +#define Sfo_engr(a,b,c) sfo(a, b, c) +#define Sfo_epri(a,b,c) sfo(a, b, c) +#define Sfo_eshk(a,b,c) sfo(a, b, c) +#define Sfo_trap(a,b,c) sfo(a, b, c) +#define Sfo_gamelog_line(a,b,c) sfo(a, b, c) +#define Sfo_fruit(a,b,c) sfo(a, b, c) +#define Sfo_s_level(a,b,c) sfo(a, b, c) +#define Sfo_short(a, b, c) sfo(a, b, c) +#define Sfo_ushort(a, b, c) sfo(a, b, c) +#define Sfo_int(a, b, c) sfo(a, b, c) +#define Sfo_unsigned(a, b, c) sfo(a, b, c) +#define Sfo_long(a,b,c) sfo(a, b, c) +#define Sfo_ulong(a,b,c) sfo(a, b, c) +#define Sfo_xint8(a, b, c) sfo(a, b, c) +#define Sfo_xint16(a, b, c) sfo(a, b, c) +/* not in _Generic */ +#define Sfo_char(a,b,c,d) sfo_char(a, b, c, d) +#define Sfo_boolean(a,b,c) sfo_boolean(a, b, c) +#define Sfo_schar(a,b,c) sfo_schar(a, b, c) +/* sfbase.c input functions */ +#define Sfi_addinfo(a,b,c) sfi(a, b, c) +#define Sfi_aligntyp(a,b,c) sfi(a, b, c) +#define Sfi_any(a,b,c) sfi(a, b, c) +#define Sfi_genericptr(a,b,c) sfi(a, b, c) +#define Sfi_coordxy(a,b,c) sfi(a, b, c) +#define Sfi_int16(a,b,c) sfi(a, b, c) +#define Sfi_int32(a,b,c) sfi(a, b, c) +#define Sfi_int64(a,b,c) sfi(a, b, c) +#define Sfi_uchar(a,b,c) sfi(a, b, c) +#define Sfi_uint16(a,b,c) sfi(a, b, c) +#define Sfi_uint32(a,b,c) sfi(a, b, c) +#define Sfi_uint64(a,b,c) sfi(a, b, c) +#define Sfi_size_t(a,b,c) sfi(a, b, c) +#define Sfi_time_t(a,b,c) sfi(a, b, c) +#define Sfi_arti_info(a,b,c) sfi(a, b, c) +#define Sfi_dungeon(a,b,c) sfi(a, b, c) +#define Sfi_dgn_topology(a,b,c) sfi(a, b, c) +#define Sfi_branch(a,b,c) sfi(a, b, c) +#define Sfi_linfo(a,b,c) sfi(a, b, c) +#define Sfi_nhcoord(a,b,c) sfi(a, b, c) +#define Sfi_d_level(a,b,c) sfi(a, b, c) +#define Sfi_mapseen_feat(a,b,c) sfi(a, b, c) +#define Sfi_mapseen_flags(a,b,c) sfi(a, b, c) +#define Sfi_mapseen_rooms(a,b,c) sfi(a, b, c) +#define Sfi_kinfo(a,b,c) sfi(a, b, c) +#define Sfi_engr(a,b,c) sfi(a, b, c) +#define Sfi_ls_t(a,b,c) sfi(a, b, c) +#define Sfi_bubble(a,b,c) sfi(a, b, c) +#define Sfi_mkroom(a,b,c) sfi(a, b, c) +#define Sfi_objclass(a,b,c) sfi(a, b, c) +#define Sfi_nhrect(a,b,c) sfi(a, b, c) +#define Sfi_fe(a,b,c) sfi(a, b, c) +#define Sfi_version_info(a,b,c) sfi(a, b, c) +#define Sfi_context_info(a,b,c) sfi(a, b, c) +#define Sfi_flag(a,b,c) sfi(a, b, c) +#define Sfi_you(a,b,c) sfi(a, b, c) +#define Sfi_mvitals(a,b,c) sfi(a, b, c) +#define Sfi_q_score(a,b,c) sfi(a, b, c) +#define Sfi_spell(a,b,c) sfi(a, b, c) +#define Sfi_dest_area(a,b,c) sfi(a, b, c) +#define Sfi_levelflags(a,b,c) sfi(a, b, c) +#define Sfi_rm(a,b,c) sfi(a, b, c) +#define Sfi_cemetery(a,b,c) sfi(a, b, c) +#define Sfi_damage(a,b,c) sfi(a, b, c) +#define Sfi_stairway(a,b,c) sfi(a, b, c) +#define Sfi_obj(a,b,c) sfi(a, b, c) +#define Sfi_monst(a,b,c) sfi(a, b, c) +#define Sfi_ebones(a,b,c) sfi(a, b, c) +#define Sfi_edog(a,b,c) sfi(a, b, c) +#define Sfi_egd(a,b,c) sfi(a, b, c) +#define Sfi_emin(a,b,c) sfi(a, b, c) +#define Sfi_engr(a,b,c) sfi(a, b, c) +#define Sfi_epri(a,b,c) sfi(a, b, c) +#define Sfi_eshk(a,b,c) sfi(a, b, c) +#define Sfi_trap(a,b,c) sfi(a, b, c) +#define Sfi_fruit(a,b,c) sfi(a, b, c) +#define Sfi_gamelog_line(a,b,c) sfi(a, b, c) +#define Sfi_s_level(a,b,c) sfi(a, b, c) +#define Sfi_short(a, b, c) sfi(a, b, c) +#define Sfi_ushort(a, b, c) sfi(a, b, c) +#define Sfi_int(a,b,c) sfi(a, b, c) +#define Sfi_unsigned(a, b, c) sfi(a, b, c) +#define Sfi_long(a,b,c) sfi(a, b, c) +#define Sfi_ulong(a,b,c) sfi(a, b, c) +#define Sfi_xint8(a, b, c) sfi(a, b, c) +#define Sfi_xint16(a, b, c) sfi(a, b, c) +/* not in _Generic */ +#define Sfi_char(a,b,c,d) sfi_char(a, b, c, d) +#define Sfi_boolean(a,b,c) sfi_boolean(a, b, c) +#define Sfi_schar(a,b,c) sfi_schar(a, b, c) +#endif + +#endif /* SAVEFILE_H */ + diff --git a/include/sfprocs.h b/include/sfprocs.h new file mode 100644 index 000000000..661d1a40a --- /dev/null +++ b/include/sfprocs.h @@ -0,0 +1,199 @@ +/* NetHack 3.6 sfprocs.h Tue Nov 6 19:38:48 2018 */ +/* Copyright (c) NetHack Development Team 2025. */ +/* NetHack may be freely redistributed. See license for details. */ + +#ifndef SFPROCS_H +#define SFPROCS_H + +#define NHTYPE_SIMPLE 1 +#define NHTYPE_COMPLEX 2 + +#define SF_PROTO(dtyp) \ + extern void sfo_##dtyp(NHFILE *, dtyp *, const char *); \ + extern void sfi_##dtyp(NHFILE *, dtyp *, const char *); \ + extern void sfo_x_##dtyp(NHFILE *, dtyp *, const char *); \ + extern void sfi_x_##dtyp(NHFILE *, dtyp *, const char *) +#define SF_PROTO_C(keyw, dtyp) \ + extern void sfo_##dtyp(NHFILE *, keyw dtyp *, const char *); \ + extern void sfi_##dtyp(NHFILE *, keyw dtyp *, const char *); \ + extern void sfo_x_##dtyp(NHFILE *, keyw dtyp *, const char *); \ + extern void sfi_x_##dtyp(NHFILE *, keyw dtyp *, const char *) +#define SF_PROTO_X(xxx, dtyp) \ + extern void sfo_##dtyp(NHFILE *, xxx *, const char *, int bfsz); \ + extern void sfi_##dtyp(NHFILE *, xxx *, const char *, int bfsz); \ + extern void sfo_x_##dtyp(NHFILE *, xxx *, const char *, int bfsz); \ + extern void sfi_x_##dtyp(NHFILE *, xxx *, const char *, int bfsz) + +SF_PROTO_C(struct, arti_info); +SF_PROTO_C(struct, nhrect); +SF_PROTO_C(struct, branch); +SF_PROTO_C(struct, bubble); +SF_PROTO_C(struct, cemetery); +SF_PROTO_C(struct, context_info); +SF_PROTO_C(struct, nhcoord); +SF_PROTO_C(struct, damage); +SF_PROTO_C(struct, dest_area); +SF_PROTO_C(struct, dgn_topology); +SF_PROTO_C(struct, dungeon); +SF_PROTO_C(struct, d_level); +SF_PROTO_C(struct, ebones); +SF_PROTO_C(struct, edog); +SF_PROTO_C(struct, egd); +SF_PROTO_C(struct, emin); +SF_PROTO_C(struct, engr); +SF_PROTO_C(struct, epri); +SF_PROTO_C(struct, eshk); +SF_PROTO_C(struct, fe); +SF_PROTO_C(struct, flag); +SF_PROTO_C(struct, fruit); +SF_PROTO_C(struct, gamelog_line); +SF_PROTO_C(struct, kinfo); +SF_PROTO_C(struct, levelflags); +SF_PROTO_C(struct, ls_t); +SF_PROTO_C(struct, linfo); +SF_PROTO_C(struct, mapseen_feat); +SF_PROTO_C(struct, mapseen_flags); +SF_PROTO_C(struct, mapseen_rooms); +SF_PROTO_C(struct, mkroom); +SF_PROTO_C(struct, monst); +SF_PROTO_C(struct, mvitals); +SF_PROTO_C(struct, obj); +SF_PROTO_C(struct, objclass); +SF_PROTO_C(struct, q_score); +SF_PROTO_C(struct, rm); +SF_PROTO_C(struct, spell); +SF_PROTO_C(struct, stairway); +SF_PROTO_C(struct, s_level); +SF_PROTO_C(struct, trap); +SF_PROTO_C(struct, version_info); +SF_PROTO_C(struct, you); +SF_PROTO_C(union, any); +SF_PROTO(int16); +SF_PROTO(int32); +SF_PROTO(int64); +SF_PROTO(uchar); +SF_PROTO(uint16); +SF_PROTO(uint32); +SF_PROTO(uint64); +SF_PROTO(long); +SF_PROTO(ulong); +SF_PROTO(xint8); +SF_PROTO(boolean); +SF_PROTO(schar); +SF_PROTO(aligntyp); +SF_PROTO(genericptr); +SF_PROTO(size_t); +SF_PROTO(time_t); +SF_PROTO(int); +SF_PROTO(unsigned); +SF_PROTO(coordxy); +SF_PROTO(short); +SF_PROTO(xint16); +SF_PROTO(ushort); +SF_PROTO_X(uint8_t, bitfield); +SF_PROTO_X(char, char); + +#undef SF_PROTO +#undef SF_PROTO_C +#undef SF_PROTO_X + +#define SF_ENTRY(dtyp) \ + void (*sf_##dtyp)(NHFILE *, dtyp *, const char *) +#define SF_ENTRY_C(keyw, dtyp) \ + void (*sf_##dtyp)(NHFILE *, keyw dtyp *, const char *) +#define SF_ENTRY_X(xxx, dtyp) \ + void (*sf_##dtyp)(NHFILE *, xxx *, const char *, int bfsz) + +struct sf_procs { + SF_ENTRY_C(struct, arti_info); + SF_ENTRY_C(struct, nhrect); + SF_ENTRY_C(struct, branch); + SF_ENTRY_C(struct, bubble); + SF_ENTRY_C(struct, cemetery); + SF_ENTRY_C(struct, context_info); + SF_ENTRY_C(struct, nhcoord); + SF_ENTRY_C(struct, damage); + SF_ENTRY_C(struct, dest_area); + SF_ENTRY_C(struct, dgn_topology); + SF_ENTRY_C(struct, dungeon); + SF_ENTRY_C(struct, d_level); + SF_ENTRY_C(struct, ebones); + SF_ENTRY_C(struct, edog); + SF_ENTRY_C(struct, egd); + SF_ENTRY_C(struct, emin); + SF_ENTRY_C(struct, engr); + SF_ENTRY_C(struct, epri); + SF_ENTRY_C(struct, eshk); + SF_ENTRY_C(struct, fe); + SF_ENTRY_C(struct, flag); + SF_ENTRY_C(struct, fruit); + SF_ENTRY_C(struct, gamelog_line); + SF_ENTRY_C(struct, kinfo); + SF_ENTRY_C(struct, levelflags); + SF_ENTRY_C(struct, ls_t); + SF_ENTRY_C(struct, linfo); + SF_ENTRY_C(struct, mapseen_feat); + SF_ENTRY_C(struct, mapseen_flags); + SF_ENTRY_C(struct, mapseen_rooms); + SF_ENTRY_C(struct, mkroom); + SF_ENTRY_C(struct, monst); + SF_ENTRY_C(struct, mvitals); + SF_ENTRY_C(struct, obj); + SF_ENTRY_C(struct, objclass); + SF_ENTRY_C(struct, q_score); + SF_ENTRY_C(struct, rm); + SF_ENTRY_C(struct, spell); + SF_ENTRY_C(struct, stairway); + SF_ENTRY_C(struct, s_level); + SF_ENTRY_C(struct, trap); + SF_ENTRY_C(struct, version_info); + SF_ENTRY_C(struct, you); + SF_ENTRY_C(union, any); + + SF_ENTRY(aligntyp); + SF_ENTRY(boolean); + SF_ENTRY(coordxy); + SF_ENTRY(genericptr); + SF_ENTRY(int); + SF_ENTRY(int16); + SF_ENTRY(int32); + SF_ENTRY(int64); + SF_ENTRY(long); + SF_ENTRY(schar); + SF_ENTRY(short); + SF_ENTRY(size_t); + SF_ENTRY(time_t); + SF_ENTRY(uchar); + SF_ENTRY(uint16); + SF_ENTRY(uint32); + SF_ENTRY(uint64); + SF_ENTRY(ulong); + SF_ENTRY(unsigned); + SF_ENTRY(ushort); + SF_ENTRY(xint16); + SF_ENTRY(xint8); + SF_ENTRY_X(char, char); + SF_ENTRY_X(uint8_t, bitfield); +}; + +#undef SF_ENTRY +#undef SF_ENTRY_C +#undef SF_ENTRY_X + +struct sf_structlevel_procs { + const char *ext; + struct sf_procs fn; /* called for structlevel (historical) */ +}; +struct sf_fieldlevel_procs { + const char *ext; + struct sf_procs fn_x; /* called for fieldlevel */ +}; +extern struct sf_structlevel_procs sfoprocs[NUM_SAVEFORMATS], sfiprocs[NUM_SAVEFORMATS]; +extern struct sf_fieldlevel_procs sfoflprocs[NUM_SAVEFORMATS], sfiflprocs[NUM_SAVEFORMATS]; +extern struct sf_structlevel_procs historical_sfo_procs; +extern struct sf_structlevel_procs historical_sfi_procs; +extern struct sf_fieldlevel_procs cnv_sfo_procs; +extern struct sf_fieldlevel_procs cnv_sfi_procs; + +#endif /* SFPROCS_H */ + diff --git a/src/artifact.c b/src/artifact.c index cd0c37bdd..ddd254285 100644 --- a/src/artifact.c +++ b/src/artifact.c @@ -71,6 +71,7 @@ static xint16 artidisco[NROFARTIFACTS]; * bulk re-init if game restart ever gets implemented. They are saved * and restored but that is done through this file so they can be local. */ + static const struct arti_info zero_artiexist = {0}; /* all bits zero */ staticfn void hack_artifacts(void); @@ -113,16 +114,11 @@ save_artifacts(NHFILE *nhfp) { int i; - for (i = 0; i < (NROFARTIFACTS + 1); ++i) { - if (nhfp->structlevel) - bwrite(nhfp->fd, (genericptr_t) &artiexist[i], - sizeof (struct arti_info)); - } - for (i = 0; i < (NROFARTIFACTS); ++i) { - if (nhfp->structlevel) - bwrite(nhfp->fd, (genericptr_t) &artidisco[i], - sizeof (xint16)); - } + for (i = 0; i < (NROFARTIFACTS + 1); ++i) + Sfo_arti_info(nhfp, &artiexist[i], "artiexist"); + + for (i = 0; i < NROFARTIFACTS; ++i) + Sfo_xint16(nhfp, &artidisco[i], "artidisco"); } void @@ -130,16 +126,10 @@ restore_artifacts(NHFILE *nhfp) { int i; - for (i = 0; i < (NROFARTIFACTS + 1); ++i) { - if (nhfp->structlevel) - mread(nhfp->fd, (genericptr_t) &artiexist[i], - sizeof (struct arti_info)); - } - for (i = 0; i < (NROFARTIFACTS); ++i) { - if (nhfp->structlevel) - mread(nhfp->fd, (genericptr_t) &artidisco[i], - sizeof (xint16)); - } + for (i = 0; i < (NROFARTIFACTS + 1); ++i) + Sfi_arti_info(nhfp, &artiexist[i], "artiexist"); + for (i = 0; i < NROFARTIFACTS; ++i) + Sfi_short(nhfp, &artidisco[i], "artidisco"); hack_artifacts(); /* redo non-saved special cases */ } @@ -2799,4 +2789,5 @@ permapoisoned(struct obj *obj) { return (obj && is_art(obj, ART_GRIMTOOTH)); } + /*artifact.c*/ diff --git a/src/bones.c b/src/bones.c index f165e71ea..31185dd28 100644 --- a/src/bones.c +++ b/src/bones.c @@ -610,13 +610,10 @@ savebones(int how, time_t when, struct obj *corpse) nhfp->mode = WRITING; store_version(nhfp); - /* if a bones pool digit is in use, it precedes the bonesid - string and isn't recorded in the file */ - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &c, sizeof c); - bwrite(nhfp->fd, (genericptr_t) bonesid, (unsigned) c); /* DD.nn */ - } + string and isn't recorded in the file */ + Sfo_char(nhfp, &c, "bones_count", 1); + Sfo_char(nhfp, bonesid, "bonesid", (int) c); /* DD.nnn */ savefruitchn(nhfp); update_mlstmv(); /* update monsters for eventual restoration */ savelev(nhfp, ledger_no(&u.uz)); @@ -655,7 +652,7 @@ getbones(void) return 0; } - if (validate(nhfp, gb.bones, FALSE) != 0) { + if (validate(nhfp, gb.bones, FALSE) != SF_UPTODATE) { if (!wizard) pline("Discarding unusable bones; no need to panic..."); ok = FALSE; @@ -668,26 +665,18 @@ getbones(void) return 0; } } - /* if a bones pool digit is in use, it precedes the bonesid - string and wasn't recorded in the file */ - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &c, - sizeof c); /* length including terminating '\0' */ - } - if ((unsigned) c <= sizeof oldbonesid) { - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) oldbonesid, - (unsigned) c); /* DD.nn or Qrrr.n for role rrr */ + Sfi_char(nhfp, &c, "bones_count", 1); /* length incl. '\0' */ + if ((unsigned) c <= sizeof oldbonesid) { + Sfi_char(nhfp, oldbonesid, "bonesid", (int) c); + } else { + if (wizard) + debugpline2("Abandoning bones , %u > %u.", + (unsigned) c, (unsigned) sizeof oldbonesid); + close_nhfile(nhfp); + compress_bonesfile(); + /* ToDo: maybe unlink these problematic bones? */ + return 0; } - } else { - if (wizard) - debugpline2("Abandoning bones , %u > %u.", (unsigned) c, - (unsigned) sizeof oldbonesid); - close_nhfile(nhfp); - compress_bonesfile(); - /* ToDo: maybe unlink these problematic bones? */ - return 0; - } if (strcmp(bonesid, oldbonesid) != 0) { char errbuf[BUFSZ]; diff --git a/src/cfgfiles.c b/src/cfgfiles.c index 3e1197a4e..52f45a7a4 100644 --- a/src/cfgfiles.c +++ b/src/cfgfiles.c @@ -1133,7 +1133,6 @@ cnf_line_PORTABLE_DEVICE_PATHS(char *bufp) #endif return TRUE; } - #endif /* SYSCF */ staticfn boolean @@ -1863,9 +1862,9 @@ vconfig_error_add(const char *str, va_list the_args) staticfn void parseformat(int *arr, char *str) { - const char *legal[] = { "historical", "lendian", "ascii" }; + const char *legal[] = { "historical", "cnv" }; int i, kwi = 0, words = 0; - char *p = str, *keywords[2]; + char *p = str, *keywords[2] = { NULL }; while (*p) { while (*p && isspace((uchar) *p)) { @@ -1937,3 +1936,4 @@ assure_syscf_file(void) /* ---------- END CONFIG FILE HANDLING ----------- */ /*cfgfiles.c*/ + diff --git a/src/decl.c b/src/decl.c index e4dc3c6e8..3430cd3a5 100644 --- a/src/decl.c +++ b/src/decl.c @@ -282,6 +282,7 @@ static const struct instance_globals_c g_init_c = { UNDEFINED_PTR, /* coder */ /* uhitm.c */ NON_PM, /* corpsenm_digested */ + FALSE, /* converted_savefile_loaded */ TRUE, /* havestate*/ }; @@ -602,7 +603,6 @@ static const struct instance_globals_o g_init_o = { UNDEFINED_PTR, /* oldfruit */ /* rumors.c */ 0, /* oracle_flag */ - UNDEFINED_PTR, /* oracle_loc */ /* uhitm.c */ FALSE, /* override_confirmation */ /* zap.c */ @@ -930,6 +930,8 @@ static const struct instance_globals_saved_n init_svn = { static const struct instance_globals_saved_o init_svo = { /* rumors.c */ 0U, /* oracle_cnt */ + UNDEFINED_PTR, /* oracle_loc */ + /* other */ 0L /* omoves */ }; diff --git a/src/dungeon.c b/src/dungeon.c index 9a43ed7ac..cbc2abd8f 100644 --- a/src/dungeon.c +++ b/src/dungeon.c @@ -32,6 +32,8 @@ struct lchoice { char menuletter; }; +static mapseen *load_mapseen(NHFILE *); + #if 0 staticfn void Fread(genericptr_t, int, int, dlb *); #endif @@ -152,49 +154,31 @@ save_dungeon( mapseen *curr_ms, *next_ms; if (perform_write) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &svn.n_dgns, sizeof svn.n_dgns); - } + Sfo_int(nhfp, &svn.n_dgns, "dungeon_count"); for (i = 0; i < svn.n_dgns; ++i) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &svd.dungeons[i], - sizeof (dungeon)); - } - } - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &svd.dungeon_topology, - sizeof svd.dungeon_topology); - bwrite(nhfp->fd, (genericptr_t) svt.tune, sizeof tune); + Sfo_dungeon(nhfp, &svd.dungeons[i], "dungeon"); } + Sfo_dgn_topology(nhfp, &svd.dungeon_topology, "svd.dungeon_topology"); + Sfo_char(nhfp, svt.tune, "tune", (int) sizeof tune); for (count = 0, curr = svb.branches; curr; curr = curr->next) count++; - if (nhfp->structlevel) - bwrite(nhfp->fd, (genericptr_t) &count, sizeof count); + Sfo_int(nhfp, &count, "branch_count"); for (curr = svb.branches; curr; curr = curr->next) { - if (nhfp->structlevel) - bwrite(nhfp->fd, (genericptr_t) curr, sizeof *curr); + Sfo_branch(nhfp, curr, "branch"); } count = maxledgerno(); - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &count, sizeof count); - } + Sfo_int(nhfp, &count, "level_info_count"); for (i = 0; i < count; ++i) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &svl.level_info[i], - sizeof (struct linfo)); - } - } - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &svi.inv_pos, sizeof svi.inv_pos); + Sfo_linfo(nhfp, &svl.level_info[i], "svl.level_info"); } + Sfo_nhcoord(nhfp, &svi.inv_pos, "svi.inv_pos"); + for (count = 0, curr_ms = svm.mapseenchn; curr_ms; curr_ms = curr_ms->next) count++; - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &count, sizeof count); - } + Sfo_int(nhfp, &count, "mapseen_count"); for (curr_ms = svm.mapseenchn; curr_ms; curr_ms = curr_ms->next) { save_mapseen(nhfp, curr_ms); @@ -224,35 +208,24 @@ void restore_dungeon(NHFILE *nhfp) { branch *curr, *last; - int count = 0, i; + int count = 0; + int i; mapseen *curr_ms, *last_ms; - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &svn.n_dgns, sizeof svn.n_dgns); - } + Sfi_int(nhfp, &svn.n_dgns, "dungeon_count"); for (i = 0; i < svn.n_dgns; ++i) { - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &svd.dungeons[i], sizeof(dungeon)); - } - } - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &svd.dungeon_topology, - sizeof svd.dungeon_topology); - } - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) svt.tune, sizeof tune); + Sfi_dungeon(nhfp, &svd.dungeons[i], "dungeon"); } + Sfi_dgn_topology(nhfp, &svd.dungeon_topology, "svd.dungeon_topology"); + Sfi_char(nhfp, svt.tune, "tune", (int) sizeof tune); + last = svb.branches = (branch *) 0; - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &count, sizeof count); - } + Sfi_int(nhfp, &count, "branch_count"); for (i = 0; i < count; i++) { curr = (branch *) alloc(sizeof *curr); - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) curr, sizeof *curr); - } + Sfi_branch(nhfp, curr, "branch"); curr->next = (branch *) 0; if (last) last->next = curr; @@ -261,23 +234,19 @@ restore_dungeon(NHFILE *nhfp) last = curr; } - if (nhfp->structlevel) - mread(nhfp->fd, (genericptr_t) &count, sizeof count); + Sfi_int(nhfp, &count, "level_info_count"); if (count >= MAXLINFO) panic("level information count larger (%d) than allocated size", count); for (i = 0; i < count; ++i) { - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &svl.level_info[i], - sizeof (struct linfo)); - } - } - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &svi.inv_pos, sizeof svi.inv_pos); - mread(nhfp->fd, (genericptr_t) &count, sizeof count); + Sfi_linfo(nhfp, &svl.level_info[i], "svl.level_info"); } + Sfi_nhcoord(nhfp, &svi.inv_pos, "svi.inv_pos"); + + Sfi_int(nhfp, &count, "mapseen_count"); + last_ms = (mapseen *) 0; for (i = 0; i < count; i++) { curr_ms = load_mapseen(nhfp); @@ -2592,19 +2561,14 @@ save_exclusions(NHFILE *nhfp) for (nez = 0, ez = sve.exclusion_zones; ez; ez = ez->next, ++nez) ; - if (perform_bwrite(nhfp)) { - if (nhfp->structlevel) - bwrite(nhfp->fd, (genericptr_t) &nez, sizeof nez); - + if (update_file(nhfp)) { + Sfo_int(nhfp, &nez, "exclusion-count"); for (ez = sve.exclusion_zones; ez; ez = ez->next) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &ez->zonetype, - sizeof ez->zonetype); - bwrite(nhfp->fd, (genericptr_t) &ez->lx, sizeof ez->lx); - bwrite(nhfp->fd, (genericptr_t) &ez->ly, sizeof ez->ly); - bwrite(nhfp->fd, (genericptr_t) &ez->hx, sizeof ez->hx); - bwrite(nhfp->fd, (genericptr_t) &ez->hy, sizeof ez->hy); - } + Sfo_xint16(nhfp, &ez->zonetype, "exclusion-zonetype"); + Sfo_coordxy(nhfp, &ez->lx, "exclusion-lx"); + Sfo_coordxy(nhfp, &ez->ly, "exclusion-ly"); + Sfo_coordxy(nhfp, &ez->hx, "exclusion-hx"); + Sfo_coordxy(nhfp, &ez->hy, "exclusion-hy"); } } } @@ -2615,20 +2579,15 @@ load_exclusions(NHFILE *nhfp) struct exclusion_zone *ez; int nez = 0; - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &nez, sizeof nez); - } + Sfi_int(nhfp, &nez, "exclusion_count"); while (nez-- > 0) { ez = (struct exclusion_zone *) alloc(sizeof *ez); - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &ez->zonetype, - sizeof ez->zonetype); - mread(nhfp->fd, (genericptr_t) &ez->lx, sizeof ez->lx); - mread(nhfp->fd, (genericptr_t) &ez->ly, sizeof ez->ly); - mread(nhfp->fd, (genericptr_t) &ez->hx, sizeof ez->hx); - mread(nhfp->fd, (genericptr_t) &ez->hy, sizeof ez->hy); - } + Sfi_xint16(nhfp, &ez->zonetype, "exclusion-zonetype"); + Sfi_coordxy(nhfp, &ez->lx, "exclusion-lx"); + Sfi_coordxy(nhfp, &ez->ly, "exclusion-ly"); + Sfi_coordxy(nhfp, &ez->hx, "exclusion-hx"); + Sfi_coordxy(nhfp, &ez->hy, "exclusion-hy"); ez->next = sve.exclusion_zones; sve.exclusion_zones = ez; } @@ -2699,27 +2658,18 @@ save_mapseen(NHFILE *nhfp, mapseen *mptr) for (brindx = 0, curr = svb.branches; curr; curr = curr->next, ++brindx) if (curr == mptr->br) break; - - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &brindx, sizeof brindx); - bwrite(nhfp->fd, (genericptr_t) &mptr->lev, sizeof mptr->lev); - bwrite(nhfp->fd, (genericptr_t) &mptr->feat, sizeof mptr->feat); - bwrite(nhfp->fd, (genericptr_t) &mptr->flags, sizeof mptr->flags); - bwrite(nhfp->fd, (genericptr_t) &mptr->custom_lth, - sizeof mptr->custom_lth); - } + Sfo_int(nhfp, &brindx, "mapseen-branch_index"); + Sfo_d_level(nhfp, &mptr->lev, "mapseen-d_level"); + Sfo_mapseen_feat(nhfp, &mptr->feat, "mapseen-feat"); + Sfo_mapseen_flags(nhfp, &mptr->flags, "mapseen-flags"); + Sfo_unsigned(nhfp, &mptr->custom_lth, "mapseen-custom_lth"); if (mptr->custom_lth) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) mptr->custom, - mptr->custom_lth); - } + Sfo_char(nhfp, mptr->custom, "mapseen-custom", + (int) mptr->custom_lth); } for (i = 0; i < ((MAXNROFROOMS + 1) * 2); ++i) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &mptr->msrooms[i], - sizeof (struct mapseen_rooms)); - } + Sfo_mapseen_rooms(nhfp, &mptr->msrooms[i], "mapseen-msrooms"); } savecemetery(nhfp, &mptr->final_resting_place); } @@ -2733,38 +2683,28 @@ load_mapseen(NHFILE *nhfp) load = (mapseen *) alloc(sizeof *load); - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &branchnum, sizeof branchnum); - } + Sfi_int(nhfp, &branchnum, "mapseen-branch_index"); for (brindx = 0, curr = svb.branches; curr; curr = curr->next, ++brindx) if (brindx == branchnum) break; load->br = curr; - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &load->lev, sizeof load->lev); - mread(nhfp->fd, (genericptr_t) &load->feat, sizeof load->feat); - mread(nhfp->fd, (genericptr_t) &load->flags, sizeof load->flags); - mread(nhfp->fd, (genericptr_t) &load->custom_lth, - sizeof load->custom_lth); - } + Sfi_d_level(nhfp, &load->lev, "mapseen-d_level"); + Sfi_mapseen_feat(nhfp, &load->feat, "mapseen-feat"); + Sfi_mapseen_flags(nhfp, &load->flags, "mapseen-flags"); + Sfi_unsigned(nhfp, &load->custom_lth, "mapseen-custom_lth"); if (load->custom_lth) { /* length doesn't include terminator (which isn't saved & restored) */ load->custom = (char *) alloc(load->custom_lth + 1); - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) load->custom, - load->custom_lth); - } + Sfi_char(nhfp, load->custom, "mapseen-custom", + (int) load->custom_lth); load->custom[load->custom_lth] = '\0'; } else { load->custom = 0; } for (i = 0; i < ((MAXNROFROOMS + 1) * 2); ++i) { - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &load->msrooms[i], - sizeof (struct mapseen_rooms)); - } + Sfi_mapseen_rooms(nhfp, &load->msrooms[i], "mapseen-msrooms"); } restcemetery(nhfp, &load->final_resting_place); return load; @@ -3742,7 +3682,6 @@ print_mapseen( } } } - #undef OF_INTEREST #undef ADDNTOBUF #undef ADDTOBUF diff --git a/src/end.c b/src/end.c index 57b189d12..e17c17517 100644 --- a/src/end.c +++ b/src/end.c @@ -1754,11 +1754,9 @@ save_killers(NHFILE *nhfp) { struct kinfo *kptr; - if (perform_bwrite(nhfp)) { + if (update_file(nhfp)) { for (kptr = &svk.killer; kptr; kptr = kptr->next) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) kptr, sizeof (struct kinfo)); - } + Sfo_kinfo(nhfp, kptr, "kinfo"); } } if (release_data(nhfp)) { @@ -1776,9 +1774,7 @@ restore_killers(NHFILE *nhfp) struct kinfo *kptr; for (kptr = &svk.killer; kptr != (struct kinfo *) 0; kptr = kptr->next) { - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) kptr, sizeof (struct kinfo)); - } + Sfi_kinfo(nhfp, kptr, "kinfo"); if (kptr->next) { kptr->next = (struct kinfo *) alloc(sizeof (struct kinfo)); } @@ -1933,12 +1929,12 @@ NH_abort(char *why USED_FOR_CRASHREPORT) panictrace_setsignals(FALSE); #endif #endif /* PANICTRACE */ -#ifdef WIN32 +#if defined(WIN32) win32_abort(); #else abort(); #endif } -#undef USED_FOR_CRASHREPORT +#undef USED_FOR_CRASHREPORT /*end.c*/ diff --git a/src/engrave.c b/src/engrave.c index 2a300cfac..00602e0fc 100644 --- a/src/engrave.c +++ b/src/engrave.c @@ -1515,27 +1515,29 @@ void save_engravings(NHFILE *nhfp) { struct engr *ep, *ep2; - unsigned no_more_engr = 0; + unsigned no_more_engr = 0, engr_alloc; + unsigned szeach; for (ep = head_engr; ep; ep = ep2) { ep2 = ep->nxt_engr; if (ep->engr_alloc - && ep->engr_txt[actual_text][0] && perform_bwrite(nhfp)) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &(ep->engr_alloc), - sizeof ep->engr_alloc); - bwrite(nhfp->fd, (genericptr_t) ep, - sizeof (struct engr) + ep->engr_alloc); - } + && ep->engr_txt[actual_text][0] && update_file(nhfp)) { + engr_alloc = (unsigned) ep->engr_alloc; + szeach = ep->engr_szeach; + Sfo_unsigned(nhfp, &engr_alloc, "engraving-engr_alloc"); + Sfo_engr(nhfp, ep, "engraving"); + ep->engr_txt[actual_text] = (char *)(ep + 1); + ep->engr_txt[remembered_text] = ep->engr_txt[actual_text] + szeach; + ep->engr_txt[pristine_text] = ep->engr_txt[remembered_text] + szeach; + Sfo_char(nhfp, ep->engr_txt[actual_text], "engraving-actual_text", szeach); + Sfo_char(nhfp, ep->engr_txt[remembered_text], "engraving-remembered_text", szeach); + Sfo_char(nhfp, ep->engr_txt[pristine_text], "engraving-pristine_text", szeach); } if (release_data(nhfp)) dealloc_engr(ep); } - if (perform_bwrite(nhfp)) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &no_more_engr, - sizeof no_more_engr); - } + if (update_file(nhfp)) { + Sfo_unsigned(nhfp, &no_more_engr, "engraving-engr_alloc"); } if (release_data(nhfp)) head_engr = 0; @@ -1546,25 +1548,28 @@ rest_engravings(NHFILE *nhfp) { struct engr *ep; unsigned lth = 0; + unsigned szeach; head_engr = 0; while (1) { - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) <h, sizeof(unsigned)); - } + Sfi_unsigned(nhfp, <h, "engraving-engr_alloc"); if (lth == 0) return; ep = newengr(lth); - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) ep, sizeof (struct engr) + lth); - } + Sfi_engr(nhfp, ep, "engraving"); + szeach = ep->engr_szeach; ep->nxt_engr = head_engr; head_engr = ep; ep->engr_txt[actual_text] = (char *) (ep + 1); /* Andreas Bormann */ - ep->engr_txt[remembered_text] = ep->engr_txt[actual_text] - + ep->engr_szeach; - ep->engr_txt[pristine_text] = ep->engr_txt[remembered_text] - + ep->engr_szeach; + ep->engr_txt[remembered_text] = ep->engr_txt[actual_text] + szeach; + ep->engr_txt[pristine_text] = ep->engr_txt[remembered_text] + szeach; + Sfi_char(nhfp, ep->engr_txt[actual_text], + "engraving-actual_text", (int) szeach); + Sfi_char(nhfp, ep->engr_txt[remembered_text], + "engraving-remembered_text", (int) szeach); + Sfi_char(nhfp, ep->engr_txt[pristine_text], + "engraving-pristine_text", (int) szeach); + while (ep->engr_txt[actual_text][0] == ' ') ep->engr_txt[actual_text]++; while (ep->engr_txt[remembered_text][0] == ' ') diff --git a/src/files.c b/src/files.c index 90ab61076..238d03662 100644 --- a/src/files.c +++ b/src/files.c @@ -5,6 +5,10 @@ #define NEED_VARARGS +#if defined(WIN32) +#include "win32api.h" +#endif + #include "hack.h" #include "dlb.h" @@ -77,6 +81,9 @@ static char fqn_filename_buffer[FQN_NUMBUF][FQN_MAX_FILENAME]; #if defined(WIN32) #include +#include +#define F_OK 0 +#define access _access #endif #ifdef AMIGA @@ -96,11 +103,15 @@ extern void amii_set_text_font(char *, int); #endif #define Close close #ifndef WIN_CE +#ifdef DeleteFile +#undef DeleteFile +#endif #define DeleteFile unlink #endif #ifdef WIN32 -/*from windmain.c */ +/*from windsys.c */ extern char *translate_path_variables(const char *, char *); +extern boolean get_user_home_folder(char *, size_t); #endif #endif @@ -116,6 +127,7 @@ extern char *translate_path_variables(const char *, char *); staticfn NHFILE *new_nhfile(void); staticfn void free_nhfile(NHFILE *); + #ifdef SELECTSAVED staticfn int QSORTCALLBACK strcmp_wrap(const void *, const void *); #endif @@ -130,10 +142,17 @@ staticfn void docompress_file(const char *, boolean); #if defined(ZLIB_COMP) staticfn boolean make_compressed_name(const char *, char *); #endif + +staticfn NHFILE *problematic_savefile(int, const char *); +staticfn NHFILE *viable_nhfile(NHFILE *); +#ifdef SELECTSAVED +staticfn int QSORTCALLBACK strcmp_wrap(const void *, const void *); +#endif +staticfn char *set_bonesfile_name(char *, d_level *); +staticfn char *set_bonestemp_name(void); #ifndef USE_FCNTL staticfn char *make_lockname(const char *, char *); #endif - staticfn FILE *fopen_wizkit_file(void); staticfn void wizkit_addinv(struct obj *); boolean proc_wizkit_line(char *buf); @@ -407,7 +426,7 @@ zero_nhfile(NHFILE *nhfp) { nhfp->fd = -1; nhfp->mode = COUNTING; - nhfp->structlevel = FALSE; + nhfp->structlevel = TRUE; nhfp->fieldlevel = FALSE; nhfp->addinfo = FALSE; nhfp->bendian = IS_BIGENDIAN(); @@ -417,6 +436,9 @@ zero_nhfile(NHFILE *nhfp) nhfp->count = 0; nhfp->eof = FALSE; nhfp->fnidx = 0; + nhfp->style.deflt = FALSE; + nhfp->style.binary = TRUE; + nhfp->nhfpconvert = 0; } staticfn NHFILE * @@ -442,6 +464,12 @@ close_nhfile(NHFILE *nhfp) { if (nhfp->structlevel && nhfp->fd != -1) (void) nhclose(nhfp->fd), nhfp->fd = -1; + if (nhfp->fplog) + (void) fprintf(nhfp->fplog, "# closing\n"); + if (nhfp->fplog) + (void) fclose(nhfp->fplog); + if (nhfp->fpdebug) + (void) fclose(nhfp->fpdebug); zero_nhfile(nhfp); free_nhfile(nhfp); } @@ -449,13 +477,11 @@ close_nhfile(NHFILE *nhfp) void rewind_nhfile(NHFILE *nhfp) { - if (nhfp->structlevel) { #ifdef BSD - (void) lseek(nhfp->fd, 0L, 0); + (void) lseek(nhfp->fd, 0L, 0); #else - (void) lseek(nhfp->fd, (off_t) 0, 0); + (void) lseek(nhfp->fd, (off_t) 0, 0); #endif - } } staticfn NHFILE * @@ -465,10 +491,25 @@ viable_nhfile(NHFILE *nhfp) the pointer to the nethack file descriptor */ if (nhfp) { /* check for no open file at all, - * not a structlevel legacy file + * not a structlevel legacy file, + * nor a fieldlevel file. */ - if (nhfp->structlevel && nhfp->fd < 0) { + if (((nhfp->fd == -1) && !nhfp->fpdef) + || (nhfp->structlevel && nhfp->fd < 0) + || (nhfp->fieldlevel && !nhfp->fpdef)) { /* not viable, start the cleanup */ + if (nhfp->fieldlevel) { + if (nhfp->fpdef) { + (void) fclose(nhfp->fpdef); + nhfp->fpdef = (FILE *) 0; + } + if (nhfp->fplog) { + (void) fprintf(nhfp->fplog, "# closing, not viable\n"); + (void) fclose(nhfp->fplog); + } + if (nhfp->fpdebug) + (void) fclose(nhfp->fpdebug); + } zero_nhfile(nhfp); free_nhfile(nhfp); nhfp = (NHFILE *) 0; @@ -477,6 +518,20 @@ viable_nhfile(NHFILE *nhfp) return nhfp; } +int +nhclose(int fd) +{ + int retval = 0; + + if (fd >= 0) { + if (close_check(fd)) + bclose(fd); + else + retval = close(fd); + } + return retval; +} + /* ---------- BEGIN LEVEL FILE HANDLING ----------- */ /* Construct a file name for a level-type file, which is of the form @@ -520,6 +575,7 @@ create_levelfile(int lev, char errbuf[]) nhfp->addinfo = FALSE; nhfp->style.deflt = FALSE; nhfp->style.binary = TRUE; + nhfp->fnidx = historical; nhfp->fd = -1; nhfp->fpdef = (FILE *) 0; #if defined(MICRO) || defined(WIN32) @@ -542,6 +598,9 @@ create_levelfile(int lev, char errbuf[]) Sprintf(errbuf, "Cannot create file \"%s\" for level %d (errno %d).", gl.lock, lev, errno); +#if defined(MSDOS) + setmode(nhfp->fd, O_BINARY); +#endif } nhfp = viable_nhfile(nhfp); return nhfp; @@ -566,6 +625,7 @@ open_levelfile(int lev, char errbuf[]) nhfp->style.deflt = FALSE; nhfp->style.binary = TRUE; nhfp->ftype = NHF_LEVELFILE; + nhfp->fnidx = historical; nhfp->fd = -1; nhfp->fpdef = (FILE *) 0; } @@ -583,6 +643,9 @@ open_levelfile(int lev, char errbuf[]) Sprintf(errbuf, "Cannot open file \"%s\" for level %d (errno %d).", gl.lock, lev, errno); +#if defined(MSDOS) + setmode(nhfp->fd, O_BINARY); +#endif } nhfp = viable_nhfile(nhfp); return nhfp; @@ -631,20 +694,6 @@ strcmp_wrap(const void *p, const void *q) } #endif -int -nhclose(int fd) -{ - int retval = 0; - - if (fd >= 0) { - if (close_check(fd)) - bclose(fd); - else - retval = close(fd); - } - return retval; -} - /* ---------- END LEVEL FILE HANDLING ----------- */ /* ---------- BEGIN BONES FILE HANDLING ----------- */ @@ -731,10 +780,23 @@ create_bonesfile(d_level *lev, char **bonesid, char errbuf[]) nhfp = new_nhfile(); if (nhfp) { - nhfp->structlevel = TRUE; - nhfp->fieldlevel = FALSE; nhfp->ftype = NHF_BONESFILE; nhfp->mode = WRITING; + nhfp->structlevel = TRUE; + nhfp->fieldlevel = FALSE; + nhfp->addinfo = TRUE; + nhfp->style.deflt = TRUE; + nhfp->style.binary = TRUE; + nhfp->fnidx = historical; + nhfp->fd = -1; + nhfp->fpdef = fopen(file, nhfp->style.binary ? WRBMODE : WRTMODE); + if (nhfp->fpdef) { +#ifdef SAVEFILE_DEBUGGING + nhfp->fpdebug = fopen("create_bonesfile-debug.log", "a"); +#endif + } else { + failed = errno; + } if (nhfp->structlevel) { #if defined(MICRO) || defined(WIN32) /* Use O_TRUNC to force the file to be shortened if it already @@ -751,6 +813,9 @@ create_bonesfile(d_level *lev, char **bonesid, char errbuf[]) #endif if (nhfp->fd < 0) failed = errno; +#if defined(MSDOS) + setmode(nhfp->fd, O_BINARY); +#endif } if (failed && errbuf) /* failure explanation */ Sprintf(errbuf, "Cannot create bones \"%s\", id %s (errno %d).", @@ -814,11 +879,25 @@ open_bonesfile(d_level *lev, char **bonesid) nhfp->fieldlevel = FALSE; nhfp->ftype = NHF_BONESFILE; nhfp->mode = READING; + nhfp->addinfo = TRUE; + nhfp->style.deflt = TRUE; + nhfp->style.binary = (sysopt.bonesformat[0] != cnvascii); + nhfp->fnidx = sysopt.bonesformat[0]; + nhfp->fd = -1; + nhfp->fpdef = fopen(fq_bones, nhfp->style.binary ? RDBMODE : RDTMODE); + if (nhfp->fpdef) { +#ifdef SAVEFILE_DEBUGGING + nhfp->fpdebug = fopen("open_bonesfile-debug.log", "a"); +#endif + } if (nhfp->structlevel) { #ifdef MAC nhfp->fd = macopen(fq_bones, O_RDONLY | O_BINARY, BONE_TYPE); #else nhfp->fd = open(fq_bones, O_RDONLY | O_BINARY, 0); +#endif +#if defined(MSDOS) + setmode(nhfp->fd, O_BINARY); #endif } } @@ -829,8 +908,11 @@ open_bonesfile(d_level *lev, char **bonesid) int delete_bonesfile(d_level *lev) { + int reslt; + (void) set_bonesfile_name(gb.bones, lev); - return !(unlink(fqname(gb.bones, BONESPREFIX, 0)) < 0); + reslt = unlink(fqname(gb.bones, BONESPREFIX, 0)); + return !(reslt < 0); } /* assume we're compressing the recently read or created bonesfile, so the @@ -929,9 +1011,6 @@ set_savefile_name(boolean regularize_it) if (strlen(SAVE_EXTENSION) > (0) && !overflow) { if (strlen(gs.SAVEF) + strlen(SAVE_EXTENSION) < (SAVESIZE - 1)) { Strcat(gs.SAVEF, SAVE_EXTENSION); -#ifdef MSDOS - sfindicator = ""; -#endif } else overflow = 3; } @@ -960,8 +1039,7 @@ set_savefile_name(boolean regularize_it) void save_savefile_name(NHFILE *nhfp) { - if (nhfp->structlevel) - (void) write(nhfp->fd, (genericptr_t) gs.SAVEF, sizeof(gs.SAVEF)); + Sfo_char(nhfp, gs.SAVEF, "savefile_name", sizeof(gs.SAVEF)); } #endif @@ -999,12 +1077,9 @@ create_savefile(void) fq_save = fqname(gs.SAVEF, SAVEPREFIX, 0); nhfp = new_nhfile(); if (nhfp) { - nhfp->structlevel = TRUE; - nhfp->fieldlevel = FALSE; nhfp->ftype = NHF_SAVEFILE; nhfp->mode = WRITING; if (program_state.in_self_recover || do_historical) { - do_historical = TRUE; /* force it */ nhUse(do_historical); nhfp->structlevel = TRUE; nhfp->fieldlevel = FALSE; @@ -1014,19 +1089,24 @@ create_savefile(void) nhfp->fnidx = historical; nhfp->fd = -1; nhfp->fpdef = (FILE *) 0; - } - if (nhfp->structlevel) { +#ifdef SAVEFILE_DEBUGGING + nhfp->fplog = fopen("create-savefile.log", "w"); +#endif + } #if defined(MICRO) || defined(WIN32) nhfp->fd = open(fq_save, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC, FCMASK); #else #ifdef MAC - nhfp->fd = maccreat(fq_save, SAVE_TYPE); + nhfp->fd = maccreat(fq_save, SAVE_TYPE); #else - nhfp->fd = creat(fq_save, FCMASK); + nhfp->fd = creat(fq_save, FCMASK); #endif #endif /* MICRO || WIN32 */ - } +#if defined(MSDOS) || defined(WIN32) + if (nhfp->fd >= 0) + (void) setmode(nhfp->fd, O_BINARY); +#endif } #if defined(VMS) && !defined(SECURE) /* @@ -1054,8 +1134,6 @@ open_savefile(void) fq_save = fqname(gs.SAVEF, SAVEPREFIX, 0); nhfp = new_nhfile(); if (nhfp) { - nhfp->structlevel = TRUE; - nhfp->fieldlevel = FALSE; nhfp->ftype = NHF_SAVEFILE; nhfp->mode = READING; if (program_state.in_self_recover || do_historical) { @@ -1069,14 +1147,19 @@ open_savefile(void) nhfp->fnidx = historical; nhfp->fd = -1; nhfp->fpdef = (FILE *) 0; - } - if (nhfp->structlevel) { -#ifdef MAC - nhfp->fd = macopen(fq_save, O_RDONLY | O_BINARY, SAVE_TYPE); -#else - nhfp->fd = open(fq_save, O_RDONLY | O_BINARY, 0); +#ifdef SAVEFILE_DEBUGGING + nhfp->fplog = fopen("open-savefile.log", "w"); +#endif + } +#ifdef MAC + nhfp->fd = macopen(fq_save, O_RDONLY | O_BINARY, SAVE_TYPE); +#else + nhfp->fd = open(fq_save, O_RDONLY | O_BINARY, 0); +#endif +#if defined(MSDOS) || defined(WIN32) + if (nhfp->fd >= 0) + (void) setmode(nhfp->fd, O_BINARY); #endif - } } nhfp = viable_nhfile(nhfp); return nhfp; @@ -1086,7 +1169,9 @@ open_savefile(void) int delete_savefile(void) { - (void) unlink(fqname(gs.SAVEF, SAVEPREFIX, 0)); + const char *sfname = fqname(gs.SAVEF, SAVEPREFIX, 0); + + (void) unlink(sfname); return 0; /* for restore_saved_game() (ex-xxxmain.c) test */ } @@ -1096,16 +1181,16 @@ restore_saved_game(void) { const char *fq_save; NHFILE *nhfp = (NHFILE *) 0; + int sfstatus = 0; set_savefile_name(TRUE); fq_save = fqname(gs.SAVEF, SAVEPREFIX, 0); nh_uncompress(fq_save); if ((nhfp = open_savefile()) != 0) { - if (validate(nhfp, fq_save, FALSE) != 0) { + if ((sfstatus = validate(nhfp, fq_save, FALSE)) != SF_UPTODATE) { close_nhfile(nhfp); - nhfp = (NHFILE *) 0; - (void) delete_savefile(); + nhfp = problematic_savefile(sfstatus, fq_save); } } return nhfp; @@ -1165,6 +1250,7 @@ plname_from_file( NHFILE *nhfp; unsigned ln; char *result = 0; + int sfstatus = 0; Strcpy(gs.SAVEF, filename); #ifdef COMPRESS_EXTENSION @@ -1179,7 +1265,8 @@ plname_from_file( #endif nh_uncompress(gs.SAVEF); if ((nhfp = open_savefile()) != 0) { - if (validate(nhfp, filename, without_wait_synch_per_file) == 0) { + if ((sfstatus = validate(nhfp, filename, + without_wait_synch_per_file)) == SF_UPTODATE) { /* room for "name+role+race+gend+algn X" where the space before X is actually NUL and X is playmode: one of '-', 'X', or 'D' */ ln = (unsigned) PL_NSIZ_PLUS; @@ -1403,7 +1490,6 @@ docompress_file(const char *filename, boolean uncomp) #ifdef TTY_GRAPHICS boolean istty = WINDOWPORT(tty); #endif - #ifdef COMPRESS_EXTENSION xtra = COMPRESS_EXTENSION; #else @@ -1752,6 +1838,60 @@ docompress_file(const char *filename, boolean uncomp) /* ---------- END FILE COMPRESSION HANDLING ----------- */ + +/* ---------- BEGIN PROBLEMATIC SAVEFILE HANDLING ----------- */ + +static struct sfstatus_to_msg { + int sfstatus; + const char *msg; +} sf2msg[] = { + { SF_UPTODATE, "everything matches" }, + { SF_OUTDATED, "outdated savefile" }, + { SF_CRITICAL_BYTE_COUNT_MISMATCH, + "savefile critical byte-count mismatch" }, + { SF_DM_IL32LLP64_ON_ILP32LL64, "Windows x64 savefile on x86" }, + { SF_DM_I32LP64_ON_ILP32LL64, "Unix 64 savefile on x86" }, + { SF_DM_ILP32LL64_ON_I32LP64, "x86 savefile on Unix 64" }, + { SF_DM_ILP32LL64_ON_IL32LLP64, "x86 savefile on Windows x64" }, + { SF_DM_I32LP64_ON_IL32LLP64, "Unix 64 savefile on Windows x64" }, + { SF_DM_IL32LLP64_ON_I32LP64, "Windows x64 savefile on Unix 64" }, + { SF_DM_MISMATCH, "generic savefile mismatch" }, +}; + +staticfn NHFILE * +problematic_savefile(int sfstatus, const char *savefilenm) +{ + int i; + NHFILE *nhfp = (NHFILE *) 0; + + switch (sfstatus) { + case SF_UPTODATE: + break; + case SF_DM_IL32LLP64_ON_ILP32LL64: + case SF_DM_I32LP64_ON_ILP32LL64: + case SF_DM_ILP32LL64_ON_I32LP64: + case SF_DM_ILP32LL64_ON_IL32LLP64: + case SF_DM_I32LP64_ON_IL32LLP64: + case SF_DM_IL32LLP64_ON_I32LP64: + case SF_DM_MISMATCH: + case SF_OUTDATED: + case SF_CRITICAL_BYTE_COUNT_MISMATCH: + default: + for (i = 0; i < SIZE(sf2msg); ++i) { + if (sf2msg[i].sfstatus == sfstatus) { + raw_printf("\n%s is %s %s\n", + savefilenm, + (sfstatus == SF_OUTDATED) ? "an" : "a", + sf2msg[i].msg); + break; + } + } + } + return nhfp; +} + +/* ---------- END PROBLEMATIC SAVEFILE HANDLING ----------- */ + /* ---------- BEGIN FILE LOCKING HANDLING ----------- */ #if defined(NO_FILE_LINKS) || defined(USE_FCNTL) /* implies UNIX */ @@ -2413,18 +2553,22 @@ testinglog(const char *filenm, /* ad hoc file name */ #ifdef SELF_RECOVER /* ---------- BEGIN INTERNAL RECOVER ----------- */ + +extern uchar critical_sizes[], cscbuf[]; /* version.c */ + boolean recover_savefile(void) { NHFILE *gnhfp, *lnhfp, *snhfp; - int lev, savelev, hpid, pltmpsiz; + int lev, savelev, hpid, + pltmpsiz, cscount = get_critical_size_count(); xint8 levc; struct version_info version_data; int processed[256]; - char savename[SAVESIZE], errbuf[BUFSZ], indicator; + char savename[SAVESIZE], errbuf[BUFSZ], indicator, file_cscount; char tmpplbuf[PL_NSIZ_PLUS]; const char *savewrite_failure = (const char *) 0; - int ccbresult = 0; + off_t filesz = 0; for (lev = 0; lev < 256; lev++) processed[lev] = 0; @@ -2442,6 +2586,30 @@ recover_savefile(void) raw_printf("%s\n", errbuf); return FALSE; } + filesz = lseek(gnhfp->fd, 0L, SEEK_END); + (void) lseek(gnhfp->fd, 0L, SEEK_SET); + if ((size_t) filesz < (sizeof hpid + + sizeof lev + + sizeof savename + + sizeof indicator + + sizeof file_cscount + + sizeof version_data + sizeof pltmpsiz)) { + const char *fq_save; + + /* this indicates a .0 file that was created as part of + * recover that did not complete. There could be an intact + * savefile already there. Check for that and return TRUE + * if there is. */ + set_savefile_name(TRUE); + fq_save = fqname(gs.SAVEF, SAVEPREFIX, 0); + if (access(fq_save, F_OK) == 0) { + close_nhfile(gnhfp); + delete_levelfile(0); + return TRUE; + } else { + /* savefile doesn't exist, so fall through */ + } + } if (read(gnhfp->fd, (genericptr_t) &hpid, sizeof hpid) != sizeof hpid) { raw_printf("\n%s\n%s\n", "Checkpoint data incompletely written" @@ -2463,7 +2631,11 @@ recover_savefile(void) != sizeof savename) || (read(gnhfp->fd, (genericptr_t) &indicator, sizeof indicator) != sizeof indicator) - || ((ccbresult = compare_critical_bytes(gnhfp)) != 0) + || (read(gnhfp->fd, (genericptr_t) &file_cscount, sizeof file_cscount) + != sizeof file_cscount) + || (file_cscount <= cscount + && read(gnhfp->fd, (genericptr_t) &cscbuf, file_cscount) + != file_cscount) || (read(gnhfp->fd, (genericptr_t) &version_data, sizeof version_data) != sizeof version_data) || (read(gnhfp->fd, (genericptr_t) &pltmpsiz, sizeof pltmpsiz) @@ -2476,7 +2648,9 @@ recover_savefile(void) } /* save file should contain: - * format indicator and critical_bytes + * format indicator (1 byte) + * n = count of critical size list (1 byte) + * n bytes of critical sizes (n bytes) * version info * plnametmp = player name size (int, 2 bytes) * player name (PL_NSIZ_PLUS) @@ -2486,6 +2660,7 @@ recover_savefile(void) */ /* + * * Set a flag for the savefile routines to know the * circumstances and act accordingly: * program_state.in_self_recover @@ -2509,21 +2684,19 @@ recover_savefile(void) } store_version(snhfp); + if (savewrite_failure) goto cleanup; - if (snhfp->structlevel) { - if (write(snhfp->fd, (genericptr_t) &pltmpsiz, sizeof pltmpsiz) - != sizeof pltmpsiz) - savewrite_failure = "player name size"; - } + /* TODO: this is not a single byte, so a big-endian byte swap + * might be necessary here, if anyone is concerned about big-endian */ + Sfo_int(snhfp, &pltmpsiz, "plname-size"); + savewrite_failure = (const char *) 0; if (savewrite_failure) goto cleanup; - if (snhfp->structlevel) { - if (write(snhfp->fd, (genericptr_t) &tmpplbuf, pltmpsiz) != pltmpsiz) - savewrite_failure = "player name"; - } + Sfo_char(snhfp, tmpplbuf, "plname", pltmpsiz); + savewrite_failure = (const char *) 0; if (savewrite_failure) goto cleanup; @@ -3173,7 +3346,6 @@ Death_quote(char *buf, int bufsz) } /* ---------- END TRIBUTE ----------- */ - #ifdef LIVELOG #define LLOG_SEP "\t" /* livelog field separator, as a string literal */ #define LLOG_EOL "\n" /* end-of-line, for abstraction consistency */ diff --git a/src/hacklib.c b/src/hacklib.c index 1fb76c37a..fd8f20c91 100644 --- a/src/hacklib.c +++ b/src/hacklib.c @@ -953,5 +953,54 @@ copy_bytes(int ifd, int ofd) } while (nfrom == BUFSIZ); return TRUE; } +#define MAX_D 5 +struct datamodel_information { + int sz[MAX_D]; + const char *datamodel; +}; +static struct datamodel_information dm[] = { + { { (int) sizeof(short), (int) sizeof(int), (int) sizeof(long), + (int) sizeof(long long), (int) sizeof(genericptr_t) }, + "" }, + { { 2, 4, 4, 8, 4 }, "ILP32LL64" }, /* Windows, Unix x86 */ + { { 2, 4, 4, 8, 8 }, "IL32LLP64" }, /* Windows x64 */ + { { 2, 4, 8, 8, 8 }, "I32LP64" }, /* Unix 64-bit */ + { { 2, 8, 8, 8, 8 }, "ILP64" }, /* HAL, SPARC64 */ +}; + +const char * +datamodel(void) +{ + int i, j, matchcount; + static const char *unknown = "Unknown"; + + for (i = 1; i < SIZE(dm); ++i) { + matchcount = 0; + for (j = 0; j < MAX_D; ++j) { + if (dm[0].sz[j] == dm[i].sz[j]) + ++matchcount; + } + if (matchcount == MAX_D) + return dm[i].datamodel; + } + return unknown; +} + +const char * +what_datamodel_is_this(int szshort, int szint, int szlong, int szll, + int szptr) +{ + int i; + static const char *unknown = "Unknown"; + + for (i = 1; i < SIZE(dm); ++i) { + if (szshort == dm[i].sz[0] && szint == dm[i].sz[1] + && szlong == dm[i].sz[2] && szll == dm[i].sz[3] + && szptr == dm[i].sz[4]) + return dm[i].datamodel; + } + return unknown; +} +#undef MAX_D /*hacklib.c*/ diff --git a/src/light.c b/src/light.c index f783855eb..618ba5684 100644 --- a/src/light.c +++ b/src/light.c @@ -429,11 +429,9 @@ save_light_sources(NHFILE *nhfp, int range) discard_flashes(); gv.vision_full_recalc = 0; - if (perform_bwrite(nhfp)) { + if (update_file(nhfp)) { count = maybe_write_ls(nhfp, range, FALSE); - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &count, sizeof count); - } + Sfo_int(nhfp, &count, "lightsource-count"); actual = maybe_write_ls(nhfp, range, TRUE); if (actual != count) panic("counted %d light sources, wrote %d! [range=%d]", count, @@ -482,20 +480,17 @@ restore_light_sources(NHFILE *nhfp) light_source *ls; /* restore elements */ - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &count, sizeof count); - } + Sfi_int(nhfp, &count, "lightsource-count"); while (count-- > 0) { ls = (light_source *) alloc(sizeof(light_source)); - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) ls, sizeof(light_source)); - } + Sfi_ls_t(nhfp, ls, "lightsource"); ls->next = gl.light_base; gl.light_base = ls; } } + DISABLE_WARNING_FORMAT_NONLITERAL /* to support '#stats' wizard-mode command */ @@ -641,9 +636,7 @@ write_ls(NHFILE *nhfp, light_source *ls) if (ls->type == LS_OBJECT || ls->type == LS_MONSTER) { if (ls->flags & LSF_NEEDS_FIXUP) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) ls, sizeof(light_source)); - } + Sfo_ls_t(nhfp, ls, "lightsource"); } else { /* replace object pointer with id for write, then put back */ arg_save = ls->id; @@ -695,9 +688,7 @@ write_ls(NHFILE *nhfp, light_source *ls) /* TODO: cleanup this ls, or skip writing it */ } ls->flags |= LSF_NEEDS_FIXUP; - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) ls, sizeof(light_source)); - } + Sfo_ls_t(nhfp, ls, "lightsource"); ls->id = arg_save; ls->flags &= ~LSF_NEEDS_FIXUP; ls->flags &= ~LSF_IS_PROBLEMATIC; @@ -985,5 +976,4 @@ wiz_light_sources(void) #undef LSF_SHOW #undef LSF_NEEDS_FIXUP #undef mon_is_local - /*light.c*/ diff --git a/src/mdlib.c b/src/mdlib.c index dc69e8a28..95d4f1f2a 100644 --- a/src/mdlib.c +++ b/src/mdlib.c @@ -56,6 +56,7 @@ static boolean date_via_env = FALSE; extern unsigned long md_ignored_features(void); +extern const char *datamodel(void); char *version_id_string(char *, size_t, const char *) NONNULL NONNULLPTRS; char *bannerc_string(char *, size_t, const char *) NONNULL NONNULLPTRS; int case_insensitive_comp(const char *, const char *) NONNULLPTRS; @@ -87,7 +88,6 @@ staticfn void build_options(void); staticfn int count_and_validate_winopts(void); staticfn void opt_out_words(char *, int *) NONNULLPTRS; staticfn void build_savebones_compat_string(void); -staticfn const char *datamodel(void); static int idxopttext, done_runtime_opt_init_once = 0; #define MAXOPT 60 /* 3.7: currently 40 lines get inserted into opttext[] */ @@ -237,41 +237,6 @@ md_ignored_features(void) ); } -#define MAX_D 5 -struct datamodel_information { - int sz[MAX_D]; - const char *datamodel; -}; - -static struct datamodel_information dm[] = { - { { (int) sizeof(short), (int) sizeof(int), (int) sizeof(long), - (int) sizeof(long long), (int) sizeof(genericptr_t) }, - "" }, - { { 2, 4, 4, 8, 4 }, "ILP32LL64" }, /* Windows, Unix x86 */ - { { 2, 4, 4, 8, 8 }, "IL32LLP64" }, /* Windows x64 */ - { { 2, 4, 8, 8, 8 }, "I32LP64" }, /* Unix 64-bit */ - { { 2, 8, 8, 8, 8 }, "ILP64" }, /* HAL, SPARC64 */ -}; - -staticfn const char * -datamodel(void) -{ - int i, j, matchcount; - static const char *unknown = "Unknown"; - - for (i = 1; i < SIZE(dm); ++i) { - matchcount = 0; - for (j = 0; j < MAX_D; ++j) { - if (dm[0].sz[j] == dm[i].sz[j]) - ++matchcount; - } - if (matchcount == MAX_D) - return dm[i].datamodel; - } - return unknown; -} -#undef MAX_D - staticfn void make_version(void) { diff --git a/src/mkmaze.c b/src/mkmaze.c index 8e09bbf79..af12ba15e 100644 --- a/src/mkmaze.c +++ b/src/mkmaze.c @@ -1720,21 +1720,17 @@ save_waterlevel(NHFILE *nhfp) if (!svb.bbubbles) return; - if (perform_bwrite(nhfp)) { + if (update_file(nhfp)) { int n = 0; for (b = svb.bbubbles; b; b = b->next) ++n; - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &n, sizeof(int)); - bwrite(nhfp->fd, (genericptr_t) &svx.xmin, sizeof(int)); - bwrite(nhfp->fd, (genericptr_t) &svy.ymin, sizeof(int)); - bwrite(nhfp->fd, (genericptr_t) &svx.xmax, sizeof(int)); - bwrite(nhfp->fd, (genericptr_t) &svy.ymax, sizeof(int)); - } + Sfo_int(nhfp, &n, "waterlevel-bubble_count"); + Sfo_int(nhfp, &svx.xmin, "waterlevel-xmin"); + Sfo_int(nhfp, &svy.ymin, "waterlevel-ymin"); + Sfo_int(nhfp, &svx.xmax, "waterlevel-xmax"); + Sfo_int(nhfp, &svy.ymax, "waterlevel-ymax"); for (b = svb.bbubbles; b; b = b->next) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) b, sizeof(struct bubble)); - } + Sfo_bubble(nhfp, b, "waterlevel-bubble"); } } if (release_data(nhfp)) @@ -1748,21 +1744,15 @@ restore_waterlevel(NHFILE *nhfp) struct bubble *b = (struct bubble *) 0, *btmp; int i, n = 0; - svb.bbubbles = (struct bubble *) 0; - set_wportal(); - if (nhfp->structlevel) { - mread(nhfp->fd,(genericptr_t) &n, sizeof (int)); - mread(nhfp->fd,(genericptr_t) &svx.xmin, sizeof (int)); - mread(nhfp->fd,(genericptr_t) &svy.ymin, sizeof (int)); - mread(nhfp->fd,(genericptr_t) &svx.xmax, sizeof (int)); - mread(nhfp->fd,(genericptr_t) &svy.ymax, sizeof (int)); - } + Sfi_int(nhfp, &n, "waterlevel-bubble_count"); + Sfi_int(nhfp, &svx.xmin, "waterlevel-xmin"); + Sfi_int(nhfp, &svy.ymin, "waterlevel-ymin"); + Sfi_int(nhfp, &svx.xmax, "waterlevel-xmax"); + Sfi_int(nhfp, &svy.ymax, "waterlevel-ymax"); for (i = 0; i < n; i++) { btmp = b; b = (struct bubble *) alloc((unsigned) sizeof *b); - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) b, (unsigned) sizeof *b); - } + Sfi_bubble(nhfp, b, "waterlevel-bubble"); if (btmp) { btmp->next = b; b->prev = btmp; diff --git a/src/mkroom.c b/src/mkroom.c index d96eca758..21dd56912 100644 --- a/src/mkroom.c +++ b/src/mkroom.c @@ -25,8 +25,10 @@ staticfn void mktemple(void); staticfn coord *shrine_pos(int); staticfn struct permonst *morguemon(void); staticfn struct permonst *squadmon(void); + staticfn void save_room(NHFILE *, struct mkroom *); staticfn void rest_room(NHFILE *, struct mkroom *); + staticfn boolean invalid_shop_shape(struct mkroom *sroom); #define sq(x) ((x) * (x)) @@ -845,9 +847,7 @@ save_room(NHFILE *nhfp, struct mkroom *r) * of writing the whole structure. That is I should not write * the gs.subrooms pointers, but who cares ? */ - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) r, sizeof (struct mkroom)); - } + Sfo_mkroom(nhfp, r, "room-mkroom"); for (i = 0; i < r->nsubrooms; i++) { save_room(nhfp, r->sbrooms[i]); } @@ -862,9 +862,7 @@ save_rooms(NHFILE *nhfp) short i; /* First, write the number of rooms */ - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &svn.nroom, sizeof svn.nroom); - } + Sfo_int(nhfp, &svn.nroom, "room-nroom"); for (i = 0; i < svn.nroom; i++) save_room(nhfp, &svr.rooms[i]); } @@ -874,9 +872,7 @@ rest_room(NHFILE *nhfp, struct mkroom *r) { short i; - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) r, sizeof (struct mkroom)); - } + Sfi_mkroom(nhfp, r, "room-mkroom"); for (i = 0; i < r->nsubrooms; i++) { r->sbrooms[i] = &gs.subrooms[gn.nsubroom]; @@ -894,9 +890,7 @@ rest_rooms(NHFILE *nhfp) { short i; - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &svn.nroom, sizeof svn.nroom); - } + Sfi_int(nhfp, &svn.nroom, "room-nroom"); gn.nsubroom = 0; for (i = 0; i < svn.nroom; i++) { diff --git a/src/muse.c b/src/muse.c index b044af098..42243c832 100644 --- a/src/muse.c +++ b/src/muse.c @@ -3115,7 +3115,7 @@ muse_unslime( * Monsters don't start with oil and don't actively pick up oil * so this may never occur in a real game. (Possible though; * nymph can steal potions of oil; shapechanger could take on - * nymph form or vacuum up stuff as a g.cube and then eventually + * nymph form or vacuum up stuff as a gel.cube and then eventually * engage with a green slime.) */ diff --git a/src/nhlua.c b/src/nhlua.c index 080cf1552..0a77eb108 100644 --- a/src/nhlua.c +++ b/src/nhlua.c @@ -1264,6 +1264,8 @@ get_nh_lua_variables(void) RESTORE_WARNING_UNREACHABLE_CODE +/* char *lua_data; */ + /* save nh_lua_variables table to file */ void save_luadata(NHFILE *nhfp) @@ -1274,11 +1276,8 @@ save_luadata(NHFILE *nhfp) if (!lua_data) lua_data = dupstr(emptystr); lua_data_len = Strlen(lua_data) + 1; /* +1: include the terminator */ - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &lua_data_len, - (unsigned) sizeof lua_data_len); - bwrite(nhfp->fd, (genericptr_t) lua_data, lua_data_len); - } + Sfo_unsigned(nhfp, &lua_data_len, "luadata-lua_data_len"); + Sfo_char(nhfp, lua_data, "lua_data", lua_data_len); free(lua_data); } @@ -1288,14 +1287,10 @@ restore_luadata(NHFILE *nhfp) { unsigned lua_data_len = 0; char *lua_data; - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &lua_data_len, - (unsigned) sizeof lua_data_len); - } + + Sfi_unsigned(nhfp, &lua_data_len, "luadata-lua_data_len"); lua_data = (char *) alloc(lua_data_len); - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) lua_data, lua_data_len); - } + Sfi_char(nhfp, lua_data, "luadata", lua_data_len); if (!gl.luacore) l_nhcore_init(); luaL_loadstring(gl.luacore, lua_data); diff --git a/src/o_init.c b/src/o_init.c index 42fbf73a1..04730e3a2 100644 --- a/src/o_init.c +++ b/src/o_init.c @@ -375,22 +375,15 @@ savenames(NHFILE *nhfp) int i; unsigned int len; - if (perform_bwrite(nhfp)) { - for (i = 0; i < (MAXOCLASSES + 2); ++i) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &svb.bases[i], sizeof (int)); - } + if (update_file(nhfp)) { + for (i = 0; i < (MAXOCLASSES + 2); ++i) { + Sfo_int(nhfp, &svb.bases[i], "names-bases"); } for (i = 0; i < NUM_OBJECTS; ++i) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &svd.disco[i], sizeof (short)); - } + Sfo_short(nhfp, &svd.disco[i], "names-disco"); } for (i = 0; i < NUM_OBJECTS; ++i) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &objects[i], - sizeof (struct objclass)); - } + Sfo_objclass(nhfp, &objects[i], "names-objclass"); } } /* as long as we use only one version of Hack we @@ -398,12 +391,11 @@ savenames(NHFILE *nhfp) oc_uname for all objects */ for (i = 0; i < NUM_OBJECTS; i++) if (objects[i].oc_uname) { - if (perform_bwrite(nhfp)) { + if (update_file(nhfp)) { len = Strlen(objects[i].oc_uname) + 1; - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &len, sizeof len); - bwrite(nhfp->fd, (genericptr_t) &objects[i].oc_uname[0], len); - } + Sfo_unsigned(nhfp, &len, "names-len"); + Sfo_char(nhfp, objects[i].oc_uname, "names-oc_uname", + (int) len); } if (release_data(nhfp)) { free((genericptr_t) objects[i].oc_uname); @@ -419,30 +411,19 @@ restnames(NHFILE *nhfp) unsigned int len = 0; for (i = 0; i < (MAXOCLASSES + 2); ++i) { - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &svb.bases[i], sizeof(int)); - } + Sfi_int(nhfp, &svb.bases[i], "names-bases"); } for (i = 0; i < NUM_OBJECTS; ++i) { - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &svd.disco[i], sizeof(short)); - } + Sfi_short(nhfp, &svd.disco[i], "names-disco"); } for (i = 0; i < NUM_OBJECTS; ++i) { - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &objects[i], - sizeof(struct objclass)); - } + Sfi_objclass(nhfp, &objects[i], "names-objclass"); } for (i = 0; i < NUM_OBJECTS; i++) { if (objects[i].oc_uname) { - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &len, sizeof len); - } + Sfi_unsigned(nhfp, &len, "names-len"); objects[i].oc_uname = (char *) alloc(len); - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &objects[i].oc_uname[0], len); - } + Sfi_char(nhfp, objects[i].oc_uname, "names-oc_uname", (int) len); } } #ifdef TILES_IN_GLYPHMAP diff --git a/src/options.c b/src/options.c index 82e1bafbb..090300fe1 100644 --- a/src/options.c +++ b/src/options.c @@ -814,7 +814,7 @@ freeroleoptvals(void) void saveoptvals(NHFILE *nhfp) { - if (perform_bwrite(nhfp)) { + if (update_file(nhfp)) { char *val; unsigned len; int i, j; @@ -823,11 +823,9 @@ saveoptvals(NHFILE *nhfp) for (j = 0; j < num_opt_phases; ++j) { val = roleoptvals[i][j]; len = val ? Strlen(val) + 1 : 0; - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &len, sizeof len); - if (val) - bwrite(nhfp->fd, (genericptr_t) val, len); - } + Sfo_unsigned(nhfp, &len, "optvals-len"); + if (val) + Sfo_char(nhfp, val, "optvals-val", len); } } if (release_data(nhfp)) @@ -846,10 +844,10 @@ restoptvals(NHFILE *nhfp) for (i = 0; i < 4; ++i) for (j = 0; j < num_opt_phases; ++j) { /* len includes terminating '\0' for non-Null values */ - mread(nhfp->fd, (genericptr_t) &len, sizeof len); + Sfi_unsigned(nhfp, &len, "optvals-len"); if (len) { val = roleoptvals[i][j] = (char *) alloc(len); - mread(nhfp->fd, (genericptr_t) val, len); + Sfi_char(nhfp, val, "opvals-val", (int) len); } else { roleoptvals[i][j] = NULL; } @@ -7127,6 +7125,8 @@ initoptions_init(void) boolean have_branch = (nomakedefs.git_branch && *nomakedefs.git_branch); go.opt_phase = builtin_opt; /* Did I need to move this here? */ + /* initialize the function pointers for saving the game */ + sf_init(); memcpy(allopt, allopt_init, sizeof(allopt)); determine_ambiguities(); @@ -7777,6 +7777,7 @@ msgtype_free(void) tmp2 = tmp->next; free((genericptr_t) tmp->pattern); regex_free(tmp->regex); + tmp->regex = 0; free((genericptr_t) tmp); } gp.plinemsg_types = (struct plinemsg_type *) 0; diff --git a/src/region.c b/src/region.c index b38ba0d7c..b0aeb1127 100644 --- a/src/region.c +++ b/src/region.c @@ -12,6 +12,7 @@ #define NO_CALLBACK (-1) +void free_region(NhRegion *); boolean inside_gas_cloud(genericptr, genericptr); boolean expire_gas_cloud(genericptr, genericptr); boolean inside_rect(NhRect *, int, int); @@ -24,7 +25,6 @@ boolean mon_in_region(NhRegion *, struct monst *); #if 0 NhRegion *clone_region(NhRegion *); #endif -void free_region(NhRegion *); void add_region(NhRegion *); void remove_region(NhRegion *); @@ -739,72 +739,49 @@ save_regions(NHFILE *nhfp) int i, j; unsigned n; - if (!perform_bwrite(nhfp)) + if (!update_file(nhfp)) goto skip_lots; - if (nhfp->structlevel) { - /* timestamp */ - bwrite(nhfp->fd, (genericptr_t) &svm.moves, sizeof svm.moves); - bwrite(nhfp->fd, (genericptr_t) &svn.n_regions, sizeof svn.n_regions); - } + /* timestamp */ + Sfo_long(nhfp, &svm.moves, "region-tmstamp"); + Sfo_int(nhfp, &svn.n_regions, "region-region_count"); + for (i = 0; i < svn.n_regions; i++) { r = gr.regions[i]; - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &r->bounding_box, - sizeof (NhRect)); - bwrite(nhfp->fd, (genericptr_t) &r->nrects, sizeof (short)); - } + Sfo_nhrect(nhfp, &r->bounding_box, "region-bounding_box"); + Sfo_short(nhfp, &r->nrects, "region-nrects"); for (j = 0; j < r->nrects; j++) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &r->rects[j], - sizeof (NhRect)); - } + Sfo_nhrect(nhfp, &r->rects[j], "region-rect"); } - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &r->attach_2_u, sizeof (boolean)); - bwrite(nhfp->fd, (genericptr_t) &r->attach_2_m, sizeof (unsigned)); - } - + Sfo_boolean(nhfp, &r->attach_2_u, "region-attach_2_u"); + Sfo_unsigned(nhfp, &r->attach_2_m, "region-attach_2_m"); + n = 0; n = !r->enter_msg ? 0U : (unsigned) strlen(r->enter_msg); - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &n, sizeof n); - } + Sfo_unsigned(nhfp, &n, "region-enter_msg_length"); if (n > 0) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) r->enter_msg, n); - } + Sfo_char(nhfp, (char *) r->enter_msg, + "region-enter_msg", (int) n); } n = !r->leave_msg ? 0U : (unsigned) strlen(r->leave_msg); - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &n, sizeof n); - } + Sfo_unsigned(nhfp, &n, "region-leave_msg_length"); if (n > 0) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) r->leave_msg, n); - } - } - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &r->ttl, sizeof (long)); - bwrite(nhfp->fd, (genericptr_t) &r->expire_f, sizeof (short)); - bwrite(nhfp->fd, (genericptr_t) &r->can_enter_f, sizeof (short)); - bwrite(nhfp->fd, (genericptr_t) &r->enter_f, sizeof (short)); - bwrite(nhfp->fd, (genericptr_t) &r->can_leave_f, sizeof (short)); - bwrite(nhfp->fd, (genericptr_t) &r->leave_f, sizeof (short)); - bwrite(nhfp->fd, (genericptr_t) &r->inside_f, sizeof (short)); - bwrite(nhfp->fd, (genericptr_t) &r->player_flags, - sizeof (unsigned)); - bwrite(nhfp->fd, (genericptr_t) &r->n_monst, sizeof (short)); + Sfo_char(nhfp, (char *) r->leave_msg, "region-leave_msg", (int) n); } + Sfo_long(nhfp, &r->ttl, "region-ttl"); + Sfo_short(nhfp, &r->expire_f, "region-expire_f"); + Sfo_short(nhfp, &r->can_enter_f, "region-can_enter_f"); + Sfo_short(nhfp, &r->enter_f, "region-enter_f"); + Sfo_short(nhfp, &r->can_leave_f, "region-can_leave_f"); + Sfo_short(nhfp, &r->leave_f, "region-leave_f"); + Sfo_short(nhfp, &r->inside_f, "region-inside_f"); + Sfo_unsigned(nhfp, &r->player_flags, "region-player_flags"); + Sfo_short(nhfp, &r->n_monst, "region-monster_count"); + for (j = 0; j < r->n_monst; j++) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &r->monsters[j], - sizeof (unsigned)); - } - } - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &r->visible, sizeof (boolean)); - bwrite(nhfp->fd, (genericptr_t) &r->glyph, sizeof (int)); - bwrite(nhfp->fd, (genericptr_t) &r->arg, sizeof (anything)); + Sfo_unsigned(nhfp, &r->monsters[j], "region-monster"); } + Sfo_boolean(nhfp, &r->visible, "region-visible"); + Sfo_int(nhfp, &r->glyph, "region-glyph"); + Sfo_any(nhfp, &r->arg, "region-arg"); } skip_lots: @@ -823,105 +800,77 @@ rest_regions(NHFILE *nhfp) boolean ghostly = (nhfp->ftype == NHF_BONESFILE); clear_regions(); /* Just for security */ - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &tmstamp, sizeof(tmstamp)); - } + Sfi_long(nhfp, &tmstamp, "region-tmstamp"); if (ghostly) tmstamp = 0; else tmstamp = (svm.moves - tmstamp); - - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &svn.n_regions, sizeof svn.n_regions); - } - + Sfi_int(nhfp, &svn.n_regions, "region-region_count"); gm.max_regions = svn.n_regions; if (svn.n_regions > 0) gr.regions = (NhRegion **) alloc(svn.n_regions * sizeof (NhRegion *)); for (i = 0; i < svn.n_regions; i++) { r = gr.regions[i] = (NhRegion *) alloc(sizeof (NhRegion)); - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &r->bounding_box, sizeof (NhRect)); - mread(nhfp->fd, (genericptr_t) &r->nrects, sizeof (short)); - } + Sfi_nhrect(nhfp, &r->bounding_box, "region-bounding box"); + Sfi_short(nhfp, &r->nrects, "region-nrects"); if (r->nrects > 0) r->rects = (NhRect *) alloc(r->nrects * sizeof (NhRect)); else r->rects = (NhRect *) 0; for (j = 0; j < r->nrects; j++) { - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &r->rects[j], sizeof(NhRect)); - } - } - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &r->attach_2_u, sizeof (boolean)); - mread(nhfp->fd, (genericptr_t) &r->attach_2_m, sizeof (unsigned)); - mread(nhfp->fd, (genericptr_t) &n, sizeof n); + Sfi_nhrect(nhfp, &r->rects[j], "region-rect"); } + + Sfi_boolean(nhfp, &r->attach_2_u, "region-attach_2_u"); + Sfi_unsigned(nhfp, &r->attach_2_m, "region-attach_2_m"); + Sfi_unsigned(nhfp, &n, "region-enter_msg_length"); if (n > 0) { msg_buf = (char *) alloc(n + 1); - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) msg_buf, n); - } + Sfi_char(nhfp, msg_buf, "region-enter_msg", n); msg_buf[n] = '\0'; } else { msg_buf = (char *) 0; } r->enter_msg = (const char *) msg_buf; - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &n, sizeof n); - } - if (n > 0) { + Sfi_unsigned(nhfp, &n, "region-leave_msg_length"); + if (n > 0) { msg_buf = (char *) alloc(n + 1); - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) msg_buf, n); - } + Sfi_char(nhfp, msg_buf, "region-leave_msg", n); msg_buf[n] = '\0'; - } else { - msg_buf = (char *) 0; - } - r->leave_msg = (const char *) msg_buf; + r->leave_msg = (const char *) msg_buf; + } else { + msg_buf = (char *) 0; + } + r->leave_msg = (const char *) msg_buf; - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &r->ttl, sizeof(long)); - } + Sfi_long(nhfp, &r->ttl, "region-ttl"); /* check for expired region */ if (r->ttl >= 0L) r->ttl = (r->ttl > tmstamp) ? r->ttl - tmstamp : 0L; - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &r->expire_f, sizeof (short)); - mread(nhfp->fd, (genericptr_t) &r->can_enter_f, sizeof (short)); - mread(nhfp->fd, (genericptr_t) &r->enter_f, sizeof (short)); - mread(nhfp->fd, (genericptr_t) &r->can_leave_f, sizeof (short)); - mread(nhfp->fd, (genericptr_t) &r->leave_f, sizeof (short)); - mread(nhfp->fd, (genericptr_t) &r->inside_f, sizeof (short)); - mread(nhfp->fd, (genericptr_t) &r->player_flags, - sizeof (unsigned)); - } + Sfi_short(nhfp, &r->expire_f, "region-expire_f"); + Sfi_short(nhfp, &r->can_enter_f, "region-can_enter_f"); + Sfi_short(nhfp, &r->enter_f, "region-enter_f"); + Sfi_short(nhfp, &r->can_leave_f, "region-can_leave_f"); + Sfi_short(nhfp, &r->leave_f, "region-leave_f"); + Sfi_short(nhfp, &r->inside_f, "region-inside_f"); + Sfi_unsigned(nhfp, &r->player_flags, "region-player_flags"); if (ghostly) { /* settings pertained to old player */ clear_hero_inside(r); clear_heros_fault(r); } - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &r->n_monst, sizeof (short)); - } + Sfi_short(nhfp, &r->n_monst, "region-monster_count"); if (r->n_monst > 0) r->monsters = (unsigned *) alloc(r->n_monst * sizeof (unsigned)); else r->monsters = (unsigned *) 0; r->max_monst = r->n_monst; for (j = 0; j < r->n_monst; j++) { - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &r->monsters[j], - sizeof(unsigned)); - } - } - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &r->visible, sizeof (boolean)); - mread(nhfp->fd, (genericptr_t) &r->glyph, sizeof (int)); - mread(nhfp->fd, (genericptr_t) &r->arg, sizeof (anything)); + Sfi_unsigned(nhfp, &r->monsters[j], "region-monster"); } + Sfi_boolean(nhfp, &r->visible, "region-visible"); + Sfi_int(nhfp, &r->glyph, "region-glyph"); + Sfi_any(nhfp, &r->arg, "region-arg"); } /* remove expired regions, do not trigger the expire_f callback (yet!); also update monster lists if this data is coming from a bones file */ diff --git a/src/restore.c b/src/restore.c index dc89bd33d..77e4e2383 100644 --- a/src/restore.c +++ b/src/restore.c @@ -59,12 +59,8 @@ extern int amii_numcolors; #define Is_IceBox(o) ((o)->otyp == ICE_BOX ? TRUE : FALSE) -/* third arg passed to mread() should be 'unsigned' but most calls use - sizeof so are attempting to pass 'size_t'; mread()'s prototype results - in an implicit conversion; this macro does it explicitly */ -#define Mread(fd,adr,siz) mread((fd), (genericptr_t) (adr), (unsigned) (siz)) - /* Recalculate svl.level.objects[x][y], since this info was not saved. */ + staticfn void find_lev_obj(void) { @@ -129,14 +125,10 @@ restlevchn(NHFILE *nhfp) s_level *tmplev, *x; svs.sp_levchn = (s_level *) 0; - if (nhfp->structlevel) { - Mread(nhfp->fd, &cnt, sizeof cnt); - } + Sfi_int(nhfp, &cnt, "levchn-lev_count"); for (; cnt > 0; cnt--) { tmplev = (s_level *) alloc(sizeof(s_level)); - if (nhfp->structlevel) { - Mread(nhfp->fd, tmplev, sizeof *tmplev); - } + Sfi_s_level(nhfp, tmplev, "levchn-s_level"); if (!svs.sp_levchn) svs.sp_levchn = tmplev; @@ -157,19 +149,15 @@ restdamage(NHFILE *nhfp) struct damage *tmp_dam; boolean ghostly = (nhfp->ftype == NHF_BONESFILE); - if (nhfp->structlevel) { - Mread(nhfp->fd, &dmgcount, sizeof dmgcount); - } + Sfi_unsigned(nhfp, &dmgcount, "damage-damage_count"); counter = (int) dmgcount; if (!counter) return; do { tmp_dam = (struct damage *) alloc(sizeof *tmp_dam); - if (nhfp->structlevel) { - Mread(nhfp->fd, tmp_dam, sizeof *tmp_dam); - } + Sfi_damage(nhfp, tmp_dam, "damage"); if (ghostly) tmp_dam->when += (svm.moves - svo.omoves); @@ -183,11 +171,9 @@ staticfn void restobj(NHFILE *nhfp, struct obj *otmp) { int buflen = 0; + unsigned omid = 0; - if (nhfp->structlevel) { - Mread(nhfp->fd, otmp, sizeof *otmp); - } - + Sfi_obj(nhfp, otmp, "obj"); otmp->lua_ref_cnt = 0; /* next object pointers are invalid; otmp->cobj needs to be left as is--being non-null is key to restoring container contents */ @@ -197,20 +183,14 @@ restobj(NHFILE *nhfp, struct obj *otmp) otmp->oextra = newoextra(); /* oname - object's name */ - if (nhfp->structlevel) { - Mread(nhfp->fd, &buflen, sizeof buflen); - } + Sfi_int(nhfp, &buflen, "obj-oname_length"); if (buflen > 0) { /* includes terminating '\0' */ new_oname(otmp, buflen); - if (nhfp->structlevel) { - Mread(nhfp->fd, ONAME(otmp), buflen); - } + Sfi_char(nhfp, ONAME(otmp), "obj-oname", buflen); } /* omonst - corpse or statue might retain full monster details */ - if (nhfp->structlevel) { - Mread(nhfp->fd, &buflen, sizeof buflen); - } + Sfi_int(nhfp, &buflen, "obj-omonst_length"); if (buflen > 0) { newomonst(otmp); /* this is actually a monst struct, so we @@ -219,24 +199,19 @@ restobj(NHFILE *nhfp, struct obj *otmp) } /* omailcmd - feedback mechanism for scroll of mail */ - if (nhfp->structlevel) { - Mread(nhfp->fd, &buflen, sizeof buflen); - } + Sfi_int(nhfp, &buflen, "obj-omail_length"); if (buflen > 0) { char *omailcmd = (char *) alloc(buflen); - if (nhfp->structlevel) { - Mread(nhfp->fd, omailcmd, buflen); - } + Sfi_char(nhfp, omailcmd, "obj-omailcmd", buflen); new_omailcmd(otmp, omailcmd); free((genericptr_t) omailcmd); } /* omid - monster id number, connecting corpse to ghost */ newomid(otmp); /* superfluous; we're already allocated otmp->oextra */ - if (nhfp->structlevel) { - Mread(nhfp->fd, &OMID(otmp), sizeof OMID(otmp)); - } + Sfi_unsigned(nhfp, &omid, "obj-omid_length"); + OMID(otmp) = omid; } } @@ -249,9 +224,7 @@ restobjchn(NHFILE *nhfp, boolean frozen) boolean ghostly = (nhfp->ftype == NHF_BONESFILE); while (1) { - if (nhfp->structlevel) { - Mread(nhfp->fd, &buflen, sizeof buflen); - } + Sfi_int(nhfp, &buflen, "obj-obj_length"); if (buflen == -1) break; @@ -287,6 +260,7 @@ restobjchn(NHFILE *nhfp, boolean frozen) for (otmp3 = otmp->cobj; otmp3; otmp3 = otmp3->nobj) otmp3->ocontainer = otmp; } + if (otmp->bypass) otmp->bypass = 0; if (!ghostly) { @@ -304,7 +278,6 @@ restobjchn(NHFILE *nhfp, boolean frozen) impossible("Restobjchn: error reading objchn."); otmp2->nobj = 0; } - return first; } @@ -314,9 +287,7 @@ restmon(NHFILE *nhfp, struct monst *mtmp) { int buflen = 0, mc = 0; - if (nhfp->structlevel) { - Mread(nhfp->fd, mtmp, sizeof *mtmp); - } + Sfi_monst(nhfp, mtmp, "monst"); /* next monster pointer is invalid */ mtmp->nmon = (struct monst *) 0; @@ -325,84 +296,54 @@ restmon(NHFILE *nhfp, struct monst *mtmp) mtmp->mextra = newmextra(); /* mgivenname - monster's name */ - if (nhfp->structlevel) { - Mread(nhfp->fd, &buflen, sizeof buflen); - } + Sfi_int(nhfp, &buflen, "monst-mgivenname_length"); if (buflen > 0) { /* includes terminating '\0' */ new_mgivenname(mtmp, buflen); - if (nhfp->structlevel) { - Mread(nhfp->fd, MGIVENNAME(mtmp), buflen); - } + Sfi_char(nhfp, MGIVENNAME(mtmp), "monst-mgivenname", (int) buflen); } /* egd - vault guard */ - if (nhfp->structlevel) { - Mread(nhfp->fd, &buflen, sizeof buflen); - } + Sfi_int(nhfp, &buflen, "monst-egd_length"); if (buflen > 0) { newegd(mtmp); - if (nhfp->structlevel) { - Mread(nhfp->fd, EGD(mtmp), sizeof(struct egd)); - } + Sfi_egd(nhfp, EGD(mtmp), "monst-egd"); } /* epri - temple priest */ - if (nhfp->structlevel) { - Mread(nhfp->fd, &buflen, sizeof buflen); - } + Sfi_int(nhfp, &buflen, "monst-epri_length"); if (buflen > 0) { newepri(mtmp); - if (nhfp->structlevel) { - Mread(nhfp->fd, EPRI(mtmp), sizeof(struct epri)); - } + Sfi_epri(nhfp, EPRI(mtmp), "monst-epri"); } /* eshk - shopkeeper */ - if (nhfp->structlevel) { - Mread(nhfp->fd, &buflen, sizeof buflen); - } + Sfi_int(nhfp, &buflen, "monst-eshk_length"); if (buflen > 0) { neweshk(mtmp); - if (nhfp->structlevel) { - Mread(nhfp->fd, ESHK(mtmp), sizeof(struct eshk)); - } + Sfi_eshk(nhfp, ESHK(mtmp), "monst-eshk"); } /* emin - minion */ - if (nhfp->structlevel) { - Mread(nhfp->fd, &buflen, sizeof buflen); - } + Sfi_int(nhfp, &buflen, "monst-emin_length"); if (buflen > 0) { newemin(mtmp); - if (nhfp->structlevel) { - Mread(nhfp->fd, EMIN(mtmp), sizeof(struct emin)); - } + Sfi_emin(nhfp, EMIN(mtmp), "monst-emin"); } /* edog - pet */ - if (nhfp->structlevel) { - Mread(nhfp->fd, &buflen, sizeof buflen); - } + Sfi_int(nhfp, &buflen, "monst-edog_length"); if (buflen > 0) { newedog(mtmp); - if (nhfp->structlevel) { - Mread(nhfp->fd, EDOG(mtmp), sizeof(struct edog)); - } + Sfi_edog(nhfp, EDOG(mtmp), "monst-edog"); /* sanity check to prevent rn2(0) */ if (EDOG(mtmp)->apport <= 0) { EDOG(mtmp)->apport = 1; } } /* ebones */ - if (nhfp->structlevel) { - Mread(nhfp->fd, &buflen, sizeof buflen); - } + Sfi_int(nhfp, &buflen, "monst-ebones_length"); if (buflen > 0) { newebones(mtmp); - if (nhfp->structlevel) { - Mread(nhfp->fd, EBONES(mtmp), sizeof(struct ebones)); - } + Sfi_ebones(nhfp, EBONES(mtmp), "monst-ebones"); } /* mcorpsenm - obj->corpsenm for mimic posing as corpse or statue (inline int rather than pointer to something) */ - if (nhfp->structlevel) { - Mread(nhfp->fd, &mc, sizeof mc); - } + Sfi_int(nhfp, &mc, "monst-mcorpsenm"); MCORPSENM(mtmp) = mc; } /* mextra */ } @@ -416,9 +357,7 @@ restmonchn(NHFILE *nhfp) boolean ghostly = (nhfp->ftype == NHF_BONESFILE); while (1) { - if (nhfp->structlevel) { - Mread(nhfp->fd, &buflen, sizeof buflen); - } + Sfi_int(nhfp, &buflen, "monst-monst_length"); if (buflen == -1) break; @@ -494,9 +433,7 @@ loadfruitchn(NHFILE *nhfp) flist = 0; for (;;) { fnext = newfruit(); - if (nhfp->structlevel) { - Mread(nhfp->fd, fnext, sizeof *fnext); - } + Sfi_fruit(nhfp, fnext, "fruit"); if (fnext->fid != 0) { fnext->nextf = flist; flist = fnext; @@ -546,29 +483,29 @@ restgamestate(NHFILE *nhfp) int i; struct flag newgameflags; struct context_info newgamecontext; /* all 0, but has some pointers */ - struct obj *otmp; struct obj *bc_obj; char timebuf[15]; unsigned long uid = 0; boolean defer_perm_invent, restoring_special; + struct obj *otmp; - if (nhfp->structlevel) { - Mread(nhfp->fd, &uid, sizeof uid); - } - + Sfi_ulong(nhfp, &uid, "gamestate-uid"); if (SYSOPT_CHECK_SAVE_UID && uid != (unsigned long) getuid()) { /* strange ... */ - /* for wizard mode, issue a reminder; for others, treat it - as an attempt to cheat and refuse to restore this file */ - pline("Saved game was not yours."); - if (!wizard) + if (!gc.converted_savefile_loaded) + /* for wizard mode, issue a reminder; for others, treat it + as an attempt to cheat and refuse to restore this file */ + pline("Saved game was not yours."); + if (wizard || gc.converted_savefile_loaded) { + if (gc.converted_savefile_loaded) + gc.converted_savefile_loaded = FALSE; + } else { return FALSE; + } } newgamecontext = svc.context; /* copy statically init'd context */ - if (nhfp->structlevel) { - Mread(nhfp->fd, &svc.context, sizeof svc.context); - } + Sfi_context_info(nhfp, &svc.context, "gamestate-context"); svc.context.warntype.species = (ismnum(svc.context.warntype.speciesidx)) ? &mons[svc.context.warntype.speciesidx] : (struct permonst *) 0; @@ -580,9 +517,7 @@ restgamestate(NHFILE *nhfp) file option values instead of keeping old save file option values if partial restore fails and we resort to starting a new game */ newgameflags = flags; - if (nhfp->structlevel) { - Mread(nhfp->fd, &flags, sizeof flags); - } + Sfi_flag(nhfp, &flags, "gamestate-flags"); /* avoid keeping permanent inventory window up to date during restore (setworn() calls update_inventory); attempting to include the cost @@ -610,9 +545,8 @@ restgamestate(NHFILE *nhfp) #ifdef AMII_GRAPHICS amii_setpens(amii_numcolors); /* use colors from save file */ #endif - if (nhfp->structlevel) { - Mread(nhfp->fd, &u, sizeof u); - } + + Sfi_you(nhfp, &u, "gamestate-you"); gy.youmonst.cham = u.mcham; if (restoring_special && iflags.explore_error_flag) { @@ -622,17 +556,11 @@ restgamestate(NHFILE *nhfp) u.uhp = 0; } - if (nhfp->structlevel) { - Mread(nhfp->fd, timebuf, 14); - } + Sfi_char(nhfp, timebuf, "gamestate-ubirthday", 14); timebuf[14] = '\0'; ubirthday = time_from_yyyymmddhhmmss(timebuf); - if (nhfp->structlevel) { - Mread(nhfp->fd, &urealtime.realtime, sizeof urealtime.realtime); - } - if (nhfp->structlevel) { - Mread(nhfp->fd, timebuf, 14); - } + Sfi_long(nhfp, &urealtime.realtime, "gamestate-realtime"); + Sfi_char(nhfp, timebuf, "gamestate-start_timing", 14); timebuf[14] = '\0'; urealtime.start_timing = time_from_yyyymmddhhmmss(timebuf); @@ -672,6 +600,7 @@ restgamestate(NHFILE *nhfp) /* restore dangling (not on floor or in inventory) ball and/or chain */ bc_obj = restobjchn(nhfp, FALSE); + while (bc_obj) { struct obj *nobj = bc_obj->nobj; @@ -680,13 +609,12 @@ restgamestate(NHFILE *nhfp) setworn(bc_obj, bc_obj->owornmask); bc_obj = nobj; } + gm.migrating_objs = restobjchn(nhfp, FALSE); gm.migrating_mons = restmonchn(nhfp); for (i = 0; i < NUMMONS; ++i) { - if (nhfp->structlevel) { - Mread(nhfp->fd, &svm.mvitals[i], sizeof (struct mvitals)); - } + Sfi_mvitals(nhfp, &svm.mvitals[i], "gamestate-mvitals"); } /* * There are some things after this that can have unintended display @@ -712,26 +640,19 @@ restgamestate(NHFILE *nhfp) restore_dungeon(nhfp); restlevchn(nhfp); - if (nhfp->structlevel) { - Mread(nhfp->fd, &svm.moves, sizeof svm.moves); - } + Sfi_long(nhfp, &svm.moves, "gamestate-moves"); /* hero_seq isn't saved and restored because it can be recalculated */ gh.hero_seq = svm.moves << 3; /* normally handled in moveloop() */ - if (nhfp->structlevel) { - Mread(nhfp->fd, &svq.quest_status, sizeof svq.quest_status); - } + Sfi_q_score(nhfp, &svq.quest_status, "gamestate-quest_status"); + for (i = 0; i < (MAXSPELL + 1); ++i) { - if (nhfp->structlevel) { - Mread(nhfp->fd, &svs.spl_book[i], - sizeof (struct spell)); - } + Sfi_spell(nhfp, &svs.spl_book[i], "gamestate-spl_book"); } restore_artifacts(nhfp); restore_oracles(nhfp); - if (nhfp->structlevel) { - Mread(nhfp->fd, svp.pl_character, sizeof svp.pl_character); - Mread(nhfp->fd, svp.pl_fruit, sizeof svp.pl_fruit); - } + Sfi_char(nhfp, svp.pl_character, + "gamestate-pl_character", sizeof svp.pl_character); + Sfi_char(nhfp, svp.pl_fruit, "gamestate-pl_fruit", sizeof svp.pl_fruit); freefruitchn(gf.ffruit); /* clean up fruit(s) made by initoptions() */ gf.ffruit = loadfruitchn(nhfp); @@ -782,6 +703,21 @@ restlevelfile(xint8 ltmp) return 2; } +/* + * restore_saved_game() prior to this left us at this position in + * the savefile for dorecover(): + * + * format indicator (1 byte) + * n = count of critical size list (1 byte) + * n bytes of critical sizes (n bytes) + * version info + * --> plnametmp = player name size (int, 2 bytes) + * player name (PL_NSIZ_PLUS) + * current level (including pets) + * (non-level-based) game state + * other levels + */ + int dorecover(NHFILE *nhfp) { @@ -792,6 +728,19 @@ dorecover(NHFILE *nhfp) program_state.restoring = REST_GSTATE; get_plname_from_file(nhfp, svp.plname, TRUE); + /* + * The position in the save file is now here: + * + * format indicator (1 byte) + * n = count of critical size list (1 byte) + * n bytes of critical sizes (n bytes) + * version info + * plnametmp = player name size (int, 2 bytes) + * player name (PL_NSIZ_PLUS) + * --> current level (including pets) + * (non-level-based) game state + * other levels + */ getlev(nhfp, 0, (xint8) 0); if (!restgamestate(nhfp)) { NHFILE tnhfp; @@ -855,10 +804,8 @@ dorecover(NHFILE *nhfp) #endif restoreinfo.mread_flags = 1; /* return despite error */ while (1) { - if (nhfp->structlevel) { - Mread(nhfp->fd, <mp, sizeof ltmp); - } - if (restoreinfo.mread_flags == -1) + Sfi_xint8(nhfp, <mp, "gamestate-level_number"); + if (nhfp->eof) break; getlev(nhfp, 0, ltmp); #ifdef MICRO @@ -949,16 +896,11 @@ rest_stairs(NHFILE *nhfp) stairway_free_all(); while (1) { - if (nhfp->structlevel) { - Mread(nhfp->fd, &buflen, sizeof buflen); - } - + Sfi_int(nhfp, &buflen, "stairs-staircount"); if (buflen == -1) break; - if (nhfp->structlevel) { - Mread(nhfp->fd, &stway, sizeof stway); - } + Sfi_stairway(nhfp, &stway, "stairs-stairway"); if (program_state.restoring != REST_GSTATE && stway.tolev.dnum == u.uz.dnum) { /* stairway dlevel is relative, make it absolute */ @@ -978,22 +920,29 @@ restcemetery(NHFILE *nhfp, struct cemetery **cemeteryaddr) struct cemetery *bonesinfo, **bonesaddr; int cflag = 0; - if (nhfp->structlevel) { - Mread(nhfp->fd, &cflag, sizeof cflag); - } + Sfi_int(nhfp, &cflag, "cemetery-cemetery_flag"); if (cflag == 0) { bonesaddr = cemeteryaddr; do { bonesinfo = (struct cemetery *) alloc(sizeof *bonesinfo); - if (nhfp->structlevel) { - Mread(nhfp->fd, bonesinfo, sizeof *bonesinfo); - } + Sfi_cemetery(nhfp, bonesinfo, "cemetery-bonesinfo"); *bonesaddr = bonesinfo; bonesaddr = &(*bonesaddr)->next; } while (*bonesaddr); } else { *cemeteryaddr = 0; } + if ((nhfp->mode & CONVERTING) != 0) { + struct cemetery *thisbones, *nextbones; + + /* free the memory */ + nextbones = *cemeteryaddr; + while ((thisbones = nextbones) != 0) { + nextbones = thisbones->next; + free((genericptr_t)thisbones); + } + *cemeteryaddr = 0; + } } /*ARGSUSED*/ @@ -1004,9 +953,7 @@ rest_levl(NHFILE *nhfp) for (c = 0; c < COLNO; ++c) { for (r = 0; r < ROWNO; ++r) { - if (nhfp->structlevel) { - Mread(nhfp->fd, &levl[c][r], sizeof (struct rm)); - } + Sfi_rm(nhfp, &levl[c][r], "location-rm"); } } } @@ -1043,10 +990,13 @@ getlev(NHFILE *nhfp, int pid, xint8 lev) if (ghostly) clear_id_mapping(); +#if 0 #if defined(MSDOS) || defined(OS2) if (nhfp->structlevel) setmode(nhfp->fd, O_BINARY); #endif +#endif + /* Load the old fruit info. We have to do it first, so the * information is available when restoring the objects. */ @@ -1054,13 +1004,9 @@ getlev(NHFILE *nhfp, int pid, xint8 lev) go.oldfruit = loadfruitchn(nhfp); /* First some sanity checks */ - if (nhfp->structlevel) { - Mread(nhfp->fd, &hpid, sizeof hpid); - } - - if (nhfp->structlevel) { - Mread(nhfp->fd, &dlvl, sizeof dlvl); - } + Sfi_int(nhfp, &hpid, "gamestate-hackpid"); +/* CHECK: This may prevent restoration */ + Sfi_xint8(nhfp, &dlvl, "gamestate-dlvl"); if ((pid && pid != hpid) || (lev && dlvl != lev)) { char trickbuf[BUFSZ]; @@ -1075,42 +1021,38 @@ getlev(NHFILE *nhfp, int pid, xint8 lev) } restcemetery(nhfp, &svl.level.bonesinfo); rest_levl(nhfp); - for (c = 0; c < COLNO; ++c) + + for (c = 0; c < COLNO; ++c) { for (r = 0; r < ROWNO; ++r) { - if (nhfp->structlevel) { - Mread(nhfp->fd, &svl.lastseentyp[c][r], sizeof (schar)); - } - } - Mread(nhfp->fd, &svo.omoves, sizeof svo.omoves); - elapsed = svm.moves - svo.omoves; + Sfi_schar(nhfp, &svl.lastseentyp[c][r], "lastseentyp"); + } + } + Sfi_long(nhfp, &svo.omoves, "lev-timestmp"); + elapsed = (svm.moves - svo.omoves); rest_stairs(nhfp); - if (nhfp->structlevel) { - Mread(nhfp->fd, &svu.updest, sizeof svu.updest); - Mread(nhfp->fd, &svd.dndest, sizeof svd.dndest); - Mread(nhfp->fd, &svl.level.flags, sizeof svl.level.flags); - } + Sfi_dest_area(nhfp, &svu.updest, "lev-updest"); + Sfi_dest_area(nhfp, &svd.dndest, "lev-dndest"); + Sfi_levelflags(nhfp, &svl.level.flags, "lev-level_flags"); + if (svd.doors) { free(svd.doors); svd.doors = 0; } - if (nhfp->structlevel) { - Mread(nhfp->fd, &svd.doors_alloc, sizeof svd.doors_alloc); - } + + Sfi_int(nhfp, &svd.doors_alloc, "lev-doors_alloc"); if (svd.doors_alloc) { /* avoid pointless alloc(0) */ - svd.doors = (coord *) alloc(svd.doors_alloc * sizeof(coord)); + svd.doors = (coord *) alloc(svd.doors_alloc * sizeof (coord)); tmpc = svd.doors; for (i = 0; i < svd.doors_alloc; ++i) { - if (nhfp->structlevel) { - Mread(nhfp->fd, tmpc, sizeof (coord)); - } + Sfi_nhcoord(nhfp, tmpc, "lev-doors"); tmpc++; } } rest_rooms(nhfp); /* No joke :-) */ if (svn.nroom) { gd.doorindex = svr.rooms[svn.nroom - 1].fdoor - + svr.rooms[svn.nroom - 1].doorct; + + svr.rooms[svn.nroom - 1].doorct; } else { gd.doorindex = 0; } @@ -1123,9 +1065,7 @@ getlev(NHFILE *nhfp, int pid, xint8 lev) gf.ftrap = 0; for (;;) { trap = newtrap(); - if (nhfp->structlevel) { - Mread(nhfp->fd, trap, sizeof *trap); - } + Sfi_trap(nhfp, trap, "trap"); if (trap->tx != 0) { if (program_state.restoring != REST_GSTATE && trap->dst.dnum == u.uz.dnum) { @@ -1147,6 +1087,7 @@ getlev(NHFILE *nhfp, int pid, xint8 lev) gb.billobjs = restobjchn(nhfp, FALSE); rest_engravings(nhfp); + /* reset level.monsters for new level */ for (x = 0; x < COLNO; x++) for (y = 0; y < ROWNO; y++) @@ -1192,6 +1133,7 @@ getlev(NHFILE *nhfp, int pid, xint8 lev) if (ghostly || (elapsed > 00 && elapsed > (long) rnd(10))) hide_monst(mtmp); } + restdamage(nhfp); rest_regions(nhfp); rest_bubbles(nhfp); /* for water and air; empty marker on other levels */ @@ -1265,7 +1207,6 @@ getlev(NHFILE *nhfp, int pid, xint8 lev) } } } - /* must come after all mons & objs are restored */ relink_timers(ghostly); relink_light_sources(ghostly); @@ -1288,13 +1229,12 @@ get_plname_from_file( int pltmpsiz = 0; plbuf[0] = '\0'; - if (nhfp->structlevel) { - (void) read(nhfp->fd, (genericptr_t) &pltmpsiz, sizeof pltmpsiz); - /* pltmpsiz should now be PL_NSIZ_PLUS */ - (void) read(nhfp->fd, (genericptr_t) plbuf, pltmpsiz); - /* plbuf[PL_NSIZ_PLUS-2] should be '\0'; - plbuf[PL_NSIZ_PLUS-1] should be '-' or 'X' or 'D' */ - } + + Sfi_int(nhfp, &pltmpsiz, "plname-size"); + /* pltmpsiz should now be PL_NSIZ_PLUS */ + Sfi_char(nhfp, plbuf, "plname", pltmpsiz); + /* plbuf[PL_NSIZ_PLUS-2] should be '\0'; + plbuf[PL_NSIZ_PLUS-1] should be '-' or 'X' or 'D' */ /* "-race-role-gend-algn" is already present except that it has been hidden by replacing the initial dash with NUL; if we want that information, replace the NUL with a dash */ @@ -1316,10 +1256,11 @@ rest_bubbles(NHFILE *nhfp) clouds are present is recorded during save so that we don't have to know what level is being restored */ bbubbly = 0; - if (nhfp->structlevel) { - Mread(nhfp->fd, &bbubbly, sizeof bbubbly); - } - + Sfi_xint8(nhfp, &bbubbly, "bubbles-bbubbly"); +#if 0 + if (nhfp->structlevel) + xxread(nhfp->fd, &bbubbly, sizeof bbubbly); +#endif if (bbubbly) restore_waterlevel(nhfp); } @@ -1332,20 +1273,14 @@ restore_gamelog(NHFILE *nhfp) struct gamelog_line tmp = { 0 }; while (1) { - if (nhfp->structlevel) { - Mread(nhfp->fd, &slen, sizeof slen); - } + Sfi_int(nhfp, &slen, "gamelog-length"); if (slen == -1) break; if (slen > ((BUFSZ*2) - 1)) panic("restore_gamelog: msg too big (%d)", slen); - if (nhfp->structlevel) { - Mread(nhfp->fd, msg, slen); - } + Sfi_char(nhfp, msg, "gamelog-gamelog_text", slen); msg[slen] = '\0'; - if (nhfp->structlevel) { - Mread(nhfp->fd, &tmp, sizeof tmp); - } + Sfi_gamelog_line(nhfp, &tmp, "gamelog-gamelog_line"); gamelog_add(tmp.flags, tmp.turn, msg); } } @@ -1353,20 +1288,17 @@ restore_gamelog(NHFILE *nhfp) staticfn void restore_msghistory(NHFILE *nhfp) { - int msgsize = 0, msgcount = 0; + int msgsize = 0; + int msgcount = 0; char msg[BUFSZ]; while (1) { - if (nhfp->structlevel) { - Mread(nhfp->fd, &msgsize, sizeof msgsize); - } + Sfi_int(nhfp, &msgsize, "msghistory-length"); if (msgsize == -1) break; if (msgsize > BUFSZ - 1) panic("restore_msghistory: msg too big (%d)", msgsize); - if (nhfp->structlevel) { - Mread(nhfp->fd, msg, msgsize); - } + Sfi_char(nhfp, msg, "msghistory-msg", msgsize); msg[msgsize] = '\0'; putmsghistory(msg, TRUE); ++msgcount; @@ -1552,22 +1484,4 @@ restore_menu( } #endif /* SELECTSAVED */ -int -validate(NHFILE *nhfp, const char *name, boolean without_waitsynch_perfile) -{ - unsigned long utdflags = 0L; - boolean reslt = FALSE; - - if (nhfp->structlevel) - utdflags |= UTD_CHECKSIZES; - if (without_waitsynch_perfile) - utdflags |= UTD_WITHOUT_WAITSYNCH_PERFILE; - if (!(reslt = uptodate(nhfp, name, utdflags))) - return 1; - - return 0; -} - -#undef Mread - /*restore.c*/ diff --git a/src/rumors.c b/src/rumors.c index d1d709516..2e58d6225 100644 --- a/src/rumors.c +++ b/src/rumors.c @@ -584,10 +584,10 @@ init_oracles(dlb *fp) (void) dlb_fgets(line, sizeof line, fp); if (sscanf(line, "%5d\n", &cnt) == 1 && cnt > 0) { svo.oracle_cnt = (unsigned) cnt; - go.oracle_loc = (unsigned long *) alloc((unsigned) cnt * sizeof(long)); + svo.oracle_loc = (unsigned long *) alloc((unsigned) cnt * sizeof(long)); for (i = 0; i < cnt; i++) { (void) dlb_fgets(line, sizeof line, fp); - (void) sscanf(line, "%5lx\n", &go.oracle_loc[i]); + (void) sscanf(line, "%5lx\n", &svo.oracle_loc[i]); } } return; @@ -598,17 +598,11 @@ save_oracles(NHFILE *nhfp) { int i; - if (perform_bwrite(nhfp)) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &svo.oracle_cnt, - sizeof svo.oracle_cnt); - } + if (update_file(nhfp)) { + Sfo_unsigned(nhfp, &svo.oracle_cnt, "oracle-oracle_cnt"); if (svo.oracle_cnt) { for (i = 0; (unsigned) i < svo.oracle_cnt; ++i) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &go.oracle_loc[i], - sizeof (unsigned long)); - } + Sfo_ulong(nhfp, &svo.oracle_loc[i], "oracle-oracle_loc"); } } } @@ -616,9 +610,8 @@ save_oracles(NHFILE *nhfp) if (svo.oracle_cnt) { svo.oracle_cnt = 0, go.oracle_flg = 0; } - if (go.oracle_loc) { - free((genericptr_t) go.oracle_loc); - go.oracle_loc = 0; + if (svo.oracle_loc) { + free((genericptr_t) svo.oracle_loc); } } } @@ -628,18 +621,12 @@ restore_oracles(NHFILE *nhfp) { int i; - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &svo.oracle_cnt, - sizeof svo.oracle_cnt); - } + Sfi_unsigned(nhfp, &svo.oracle_cnt, "oracle-oracle_cnt"); if (svo.oracle_cnt) { - go.oracle_loc = + svo.oracle_loc = (unsigned long *) alloc(svo.oracle_cnt * sizeof (unsigned long)); for (i = 0; (unsigned) i < svo.oracle_cnt; ++i) { - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &go.oracle_loc[i], - sizeof (unsigned long)); - } + Sfi_ulong(nhfp, &svo.oracle_loc[i], "oracle-oracle_loc"); } go.oracle_flg = 1; /* no need to call init_oracles() */ } @@ -672,9 +659,9 @@ outoracle(boolean special, boolean delphi) if (svo.oracle_cnt <= 1 && !special) goto close_oracles; /*(shouldn't happen)*/ oracle_idx = special ? 0 : rnd((int) svo.oracle_cnt - 1); - (void) dlb_fseek(oracles, (long) go.oracle_loc[oracle_idx], SEEK_SET); + (void) dlb_fseek(oracles, (long) svo.oracle_loc[oracle_idx], SEEK_SET); if (!special) /* move offset of very last one into this slot */ - go.oracle_loc[oracle_idx] = go.oracle_loc[--svo.oracle_cnt]; + svo.oracle_loc[oracle_idx] = svo.oracle_loc[--svo.oracle_cnt]; tmpwin = create_nhwindow(NHW_TEXT); if (delphi) diff --git a/src/save.c b/src/save.c index 69b9de6cb..4e4f568a3 100644 --- a/src/save.c +++ b/src/save.c @@ -115,6 +115,7 @@ dosave0(void) clear_nhwindow(WIN_MESSAGE); There("seems to be an old save file."); if (y_n("Overwrite the old file?") == 'n') { + //nh_sfconvert(fq_save); nh_compress(fq_save); goto done; } @@ -129,6 +130,10 @@ dosave0(void) (void) delete_savefile(); /* ab@unido */ goto done; } + if (nhfp && nhfp->fplog) { + /* (void) fprintf(nhfp->fplog, "# just opened\n"); */ + nhfp->count = 0L; + } vision_recalc(2); /* shut down vision to prevent problems in the event of an impossible() call */ @@ -150,8 +155,6 @@ dosave0(void) #endif nhfp->mode = WRITING | FREEING; store_version(nhfp); - if (nhfp && nhfp->fplog) - (void) fprintf(nhfp->fplog, "# post-validation\n"); store_plname_in_file(nhfp); /* savelev() might save uball and uchain, releasing their memory if FREEING, so we need to check their status now; if hero is swallowed, @@ -206,9 +209,7 @@ dosave0(void) } getlev(onhfp, svh.hackpid, ltmp); close_nhfile(onhfp); - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) <mp, sizeof ltmp); /* lvl no. */ - } + Sfo_xint8(nhfp, <mp, "gamestate-level_number"); savelev(nhfp, ltmp); /* actual level*/ delete_levelfile(ltmp); } @@ -220,6 +221,7 @@ dosave0(void) /* get rid of current level --jgm */ delete_levelfile(ledger_no(&u.uz)); delete_levelfile(0); + ///nh_sfconvert(fq_save); nh_compress(fq_save); /* this should probably come sooner... */ program_state.something_worth_saving = 0; @@ -239,28 +241,23 @@ save_gamelog(NHFILE *nhfp) while (tmp) { tmp2 = tmp->next; - if (perform_bwrite(nhfp)) { + if (nhfp->mode & (COUNTING | WRITING)) { slen = Strlen(tmp->text); - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &slen, sizeof slen); - bwrite(nhfp->fd, (genericptr_t) tmp->text, slen); - bwrite(nhfp->fd, (genericptr_t) tmp, - sizeof (struct gamelog_line)); - } + Sfo_int(nhfp, &slen, "gamelog-length"); + Sfo_char(nhfp, tmp->text, "gamelog-gamelog_text", slen); + Sfo_gamelog_line(nhfp, tmp, "gamelog-gamelog_line"); } - if (release_data(nhfp)) { + if (nhfp->mode & FREEING) { free((genericptr_t) tmp->text); free((genericptr_t) tmp); } tmp = tmp2; } - if (perform_bwrite(nhfp)) { + if (nhfp->mode & (COUNTING | WRITING)) { slen = -1; - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &slen, sizeof slen); - } + Sfo_int(nhfp, &slen, "gamelog-length"); } - if (release_data(nhfp)) + if (nhfp->mode & FREEING) gg.gamelog = NULL; } @@ -272,21 +269,16 @@ savegamestate(NHFILE *nhfp) program_state.saving++; /* caller should/did already set this... */ uid = (unsigned long) getuid(); - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &uid, sizeof uid); - bwrite(nhfp->fd, (genericptr_t) &svc.context, sizeof svc.context); - bwrite(nhfp->fd, (genericptr_t) &flags, sizeof flags); - } + Sfo_ulong(nhfp, &uid, "gamestate-uid"); + Sfo_context_info(nhfp, &svc.context, "gamestate-context"); + Sfo_flag(nhfp, &flags, "gamestate-flags"); urealtime.finish_time = getnow(); urealtime.realtime += timet_delta(urealtime.finish_time, urealtime.start_timing); - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &u, sizeof u); - bwrite(nhfp->fd, yyyymmddhhmmss(ubirthday), 14); - bwrite(nhfp->fd, (genericptr_t) &urealtime.realtime, - sizeof urealtime.realtime); - bwrite(nhfp->fd, yyyymmddhhmmss(urealtime.start_timing), 14); - } + Sfo_you(nhfp, &u, "gamestate-you"); + Sfo_char(nhfp, yyyymmddhhmmss(ubirthday), "gamestate-ubirthday", 14); + Sfo_long(nhfp, &urealtime.realtime, "gamestate-realtime"); + Sfo_char(nhfp, yyyymmddhhmmss(urealtime.start_timing), "gamestate-start_timing", 14); /* this is the value to use for the next update of urealtime.realtime */ urealtime.start_timing = urealtime.finish_time; save_killers(nhfp); @@ -307,32 +299,20 @@ savegamestate(NHFILE *nhfp) if (release_data(nhfp)) gm.migrating_mons = (struct monst *) 0; for (i = 0; i < NUMMONS; ++i) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &svm.mvitals[i], - sizeof (struct mvitals)); - } + Sfo_mvitals(nhfp, &svm.mvitals[i], "gamestate-mvitals"); } - save_dungeon(nhfp, (boolean) !!perform_bwrite(nhfp), + save_dungeon(nhfp, (boolean) !!update_file(nhfp), (boolean) !!release_data(nhfp)); savelevchn(nhfp); - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &svm.moves, sizeof svm.moves); - bwrite(nhfp->fd, (genericptr_t) &svq.quest_status, - sizeof svq.quest_status); - } + Sfo_long(nhfp, &svm.moves, "gamestate-moves"); + Sfo_q_score(nhfp, &svq.quest_status, "gamestate-quest_status"); for (i = 0; i < (MAXSPELL + 1); ++i) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &svs.spl_book[i], - sizeof(struct spell)); - } + Sfo_spell(nhfp, &svs.spl_book[i], "gamestate-spl_book"); } save_artifacts(nhfp); save_oracles(nhfp); - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) svp.pl_character, - sizeof svp.pl_character); - bwrite(nhfp->fd, (genericptr_t) svp.pl_fruit, sizeof svp.pl_fruit); - } + Sfo_char(nhfp, svp.pl_character, "gamestate-pl_character", sizeof svp.pl_character); + Sfo_char(nhfp, svp.pl_fruit, "gamestate-pl_fruit", sizeof svp.pl_fruit); savefruitchn(nhfp); savenames(nhfp); save_msghistory(nhfp); @@ -391,9 +371,7 @@ savestateinlock(void) return; } - if (nhfp->structlevel) { - (void) read(nhfp->fd, (genericptr_t) &hpid, sizeof hpid); - } + Sfi_int(nhfp, &hpid, "gamestate-hackpid"); if (svh.hackpid != hpid) { Sprintf(whynot, "Level #0 pid (%d) doesn't match ours (%d)!", hpid, svh.hackpid); @@ -416,16 +394,11 @@ savestateinlock(void) return; } nhfp->mode = WRITING; - if (nhfp->structlevel) - (void) write(nhfp->fd, (genericptr_t) &svh.hackpid, - sizeof svh.hackpid); + Sfo_int(nhfp, &svh.hackpid, "gamestate-hackpid"); if (flags.ins_chkpt) { int currlev = ledger_no(&u.uz); - if (nhfp->structlevel) { - (void) write(nhfp->fd, (genericptr_t) &currlev, - sizeof currlev); - } + Sfo_int(nhfp, &currlev, "gamestate-savestateinlock"); save_savefile_name(nhfp); store_version(nhfp); store_plname_in_file(nhfp); @@ -453,7 +426,7 @@ savelev(NHFILE *nhfp, xint8 lev) if not, we need to set it for save_bubbles(); caveat: if the player quits during character selection, u.uz won't be set yet but we'll be called during run-down */ - if (set_uz_save && perform_bwrite(nhfp)) { + if (set_uz_save && (nhfp->mode & (COUNTING | WRITING))) { if (u.uz.dnum == 0 && u.uz.dlevel == 0) { program_state.something_worth_saving = 0; panic("savelev: where are we?"); @@ -511,10 +484,8 @@ savelev_core(NHFILE *nhfp, xint8 lev) if (lev >= 0 && lev <= maxledgerno()) svl.level_info[lev].flags |= VISITED; - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &svh.hackpid, sizeof svh.hackpid); - bwrite(nhfp->fd, (genericptr_t) &lev, sizeof lev); - } + Sfo_int(nhfp, &svh.hackpid, "gamestate-hackpid"); + Sfo_xint8(nhfp, &lev, "gamestate-dlvl"); } /* bones info comes before level data; the intent is for an external @@ -528,35 +499,25 @@ savelev_core(NHFILE *nhfp, xint8 lev) goto skip_lots; savelevl(nhfp); - for (c = 0; c < COLNO; ++c) + for (c = 0; c < COLNO; ++c) { for (r = 0; r < ROWNO; ++r) { - bwrite(nhfp->fd, (genericptr_t) &svl.lastseentyp[c][r], - sizeof(schar)); + Sfo_schar(nhfp, &svl.lastseentyp[c][r], "lastseentyp"); } - /* svm.moves below will actually be read back into svo.omoves on restore */ - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &svm.moves, sizeof svm.moves); } + /* svm.moves will actually be read back into svo.omoves on restore */ + Sfo_long(nhfp, &svm.moves, "lev-timestmp"); save_stairs(nhfp); - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &svu.updest, sizeof(dest_area)); - bwrite(nhfp->fd, (genericptr_t) &svd.dndest, sizeof(dest_area)); - bwrite(nhfp->fd, (genericptr_t) &svl.level.flags, - sizeof svl.level.flags); - } - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &svd.doors_alloc, - sizeof svd.doors_alloc); - } + Sfo_dest_area(nhfp, &svu.updest, "lev-updest"); + Sfo_dest_area(nhfp, &svd.dndest, "lev-dndest"); + Sfo_levelflags(nhfp, &svl.level.flags, "lev-level_flags"); + + Sfo_int(nhfp, &svd.doors_alloc, "lev-doors_alloc"); /* don't rely on underlying write() behavior to write - * nothing if count arg is 0, just skip it */ + * nothing if count arg is 0, just skip it */ if (svd.doors_alloc) { tmpc = svd.doors; for (i = 0; i < svd.doors_alloc; ++i) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) tmpc, - sizeof (coord)); - } + Sfo_nhcoord(nhfp, tmpc, "lev-doors"); tmpc++; } } @@ -602,11 +563,8 @@ savelevl(NHFILE *nhfp) for (x = 0; x < COLNO; x++) { for (y = 0; y < ROWNO; y++) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &levl[x][y], - sizeof(struct rm)); - } - } + Sfo_rm(nhfp, &levl[x][y], "location-rm"); + } } return; } @@ -626,9 +584,12 @@ save_bubbles(NHFILE *nhfp, xint8 lev) bbubbly = 0; if (lev == ledger_no(&water_level) || lev == ledger_no(&air_level)) bbubbly = lev; /* non-zero */ - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &bbubbly, sizeof bbubbly); - } + if (update_file(nhfp)) + Sfo_xint8(nhfp, &bbubbly, "bubbles-bbubbly"); +#if 0 + if (nhfp->structlevel) + xxwrite(nhfp->fd, (genericptr_t) &bbubbly, sizeof bbubbly); +#endif if (bbubbly) save_waterlevel(nhfp); /* save air bubbles or clouds */ @@ -642,18 +603,14 @@ savecemetery(NHFILE *nhfp, struct cemetery **cemeteryaddr) int flag; flag = *cemeteryaddr ? 0 : -1; - if (perform_bwrite(nhfp)) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &flag, sizeof flag); - } + if (update_file(nhfp)) { + Sfo_int(nhfp, &flag, "cemetery-cemetery_flag"); } nextbones = *cemeteryaddr; while ((thisbones = nextbones) != 0) { nextbones = thisbones->next; - if (perform_bwrite(nhfp)) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) thisbones, sizeof *thisbones); - } + if (update_file(nhfp)) { + Sfo_cemetery(nhfp, thisbones, "cemetery-bonesinfo"); } if (release_data(nhfp)) free((genericptr_t) thisbones); @@ -671,16 +628,12 @@ savedamage(NHFILE *nhfp) damageptr = svl.level.damagelist; for (tmp_dam = damageptr; tmp_dam; tmp_dam = tmp_dam->next) xl++; - if (perform_bwrite(nhfp)) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &xl, sizeof xl); - } + if (update_file(nhfp)) { + Sfo_unsigned(nhfp, &xl, "damage-damage_count"); } while (damageptr) { - if (perform_bwrite(nhfp)) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) damageptr, sizeof *damageptr); - } + if (update_file(nhfp)) { + Sfo_damage(nhfp, damageptr, "damage"); } tmp_dam = damageptr; damageptr = damageptr->next; @@ -698,17 +651,15 @@ save_stairs(NHFILE *nhfp) int buflen = (int) sizeof *stway; while (stway) { - if (perform_bwrite(nhfp)) { + if (update_file(nhfp)) { boolean use_relative = (program_state.restoring != REST_GSTATE && stway->tolev.dnum == u.uz.dnum); if (use_relative) { /* make dlevel relative to current level */ stway->tolev.dlevel -= u.uz.dlevel; } - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof buflen); - bwrite(nhfp->fd, (genericptr_t) stway, sizeof *stway); - } + Sfo_int(nhfp, &buflen, "stairs-staircount"); + Sfo_stairway(nhfp, stway, "stairs-stairway"); if (use_relative) { /* reset stairway dlevel back to absolute */ stway->tolev.dlevel += u.uz.dlevel; @@ -716,11 +667,9 @@ save_stairs(NHFILE *nhfp) } stway = stway->next; } - if (perform_bwrite(nhfp)) { + if (update_file(nhfp)) { buflen = -1; - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof buflen); - } + Sfo_int(nhfp, &buflen, "stairs-staircount"); } } @@ -755,51 +704,38 @@ save_bc(NHFILE *nhfp) } /* save one object; - caveat: this is only for perform_bwrite(); caller handles release_data() */ + caveat: this is only for update_file(); caller handles release_data() */ staticfn void saveobj(NHFILE *nhfp, struct obj *otmp) { int buflen, zerobuf = 0; buflen = (int) sizeof (struct obj); - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof buflen); - bwrite(nhfp->fd, (genericptr_t) otmp, buflen); - } + Sfo_int(nhfp, &buflen, "obj-obj_length"); + Sfo_obj(nhfp, otmp, "obj"); if (otmp->oextra) { buflen = ONAME(otmp) ? (int) strlen(ONAME(otmp)) + 1 : 0; - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof buflen); - } + Sfo_int(nhfp, &buflen, "obj-oname_length"); + if (buflen > 0) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) ONAME(otmp), buflen); - } + Sfo_char(nhfp, ONAME(otmp), "obj-oname", buflen); } /* defer to savemon() for this one */ if (OMONST(otmp)) { savemon(nhfp, OMONST(otmp)); } else { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &zerobuf, sizeof zerobuf); - } + Sfo_int(nhfp, &zerobuf, "obj-omonst_length"); } /* extra info about scroll of mail */ buflen = OMAILCMD(otmp) ? (int) strlen(OMAILCMD(otmp)) + 1 : 0; - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof buflen); - } + Sfo_int(nhfp, &buflen, "obj-omailcmd_length"); if (buflen > 0) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) OMAILCMD(otmp), buflen); - } + Sfo_char(nhfp, OMAILCMD(otmp), "obj-omailcmd", buflen); } /* omid used to be indirect via a pointer in oextra but has become part of oextra itself; 0 means not applicable and gets saved/restored whenever any other oextra components do */ - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &OMID(otmp), sizeof OMID(otmp)); - } + Sfo_unsigned(nhfp, &OMID(otmp), "obj-omid"); } } @@ -815,7 +751,7 @@ saveobjchn(NHFILE *nhfp, struct obj **obj_p) while (otmp) { otmp2 = otmp->nobj; - if (perform_bwrite(nhfp)) { + if (update_file(nhfp)) { saveobj(nhfp, otmp); } if (Has_contents(otmp)) @@ -859,10 +795,8 @@ saveobjchn(NHFILE *nhfp, struct obj **obj_p) } otmp = otmp2; } - if (perform_bwrite(nhfp)) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &minusone, sizeof(int)); - } + if (update_file(nhfp)) { + Sfo_int(nhfp, &minusone, "obj-obj_length"); } if (release_data(nhfp)) { if (is_invent) @@ -879,80 +813,48 @@ savemon(NHFILE *nhfp, struct monst *mtmp) mtmp->mtemplit = 0; /* normally clear; if set here then a panic save * is being written while bhit() was executing */ buflen = (int) sizeof (struct monst); - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof buflen); - bwrite(nhfp->fd, (genericptr_t) mtmp, buflen); - } + Sfo_int(nhfp, &buflen, "monst-monst_length"); + Sfo_monst(nhfp, mtmp, "monst"); if (mtmp->mextra) { buflen = MGIVENNAME(mtmp) ? (int) strlen(MGIVENNAME(mtmp)) + 1 : 0; - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof buflen); - } + Sfo_int(nhfp, &buflen, "monst-mgivenname_length"); if (buflen > 0) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) MGIVENNAME(mtmp), buflen); - } + Sfo_char(nhfp, MGIVENNAME(mtmp), "monst-mgivenname", buflen); } buflen = EGD(mtmp) ? (int) sizeof (struct egd) : 0; - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof buflen); - } + Sfo_int(nhfp, &buflen, "monst-egd_length"); if (buflen > 0) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) EGD(mtmp), buflen); - } + Sfo_egd(nhfp, EGD(mtmp), "monst-egd"); } buflen = EPRI(mtmp) ? (int) sizeof (struct epri) : 0; - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof buflen); - } + Sfo_int(nhfp, &buflen, "monst-epri_length"); if (buflen > 0) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) EPRI(mtmp), buflen); - } + Sfo_epri(nhfp, EPRI(mtmp), "monst-epri"); } buflen = ESHK(mtmp) ? (int) sizeof (struct eshk) : 0; - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof(int)); - } + Sfo_int(nhfp, &buflen, "monst-eshk_length"); if (buflen > 0) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) ESHK(mtmp), buflen); - } + Sfo_eshk(nhfp, ESHK(mtmp), "monst-eshk"); } buflen = EMIN(mtmp) ? (int) sizeof (struct emin) : 0; - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof(int)); - } + Sfo_int(nhfp, &buflen, "monst-emin_length"); if (buflen > 0) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) EMIN(mtmp), buflen); - } + Sfo_emin(nhfp, EMIN(mtmp), "monst-emin"); } buflen = EDOG(mtmp) ? (int) sizeof (struct edog) : 0; - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof(int)); - } + Sfo_int(nhfp, &buflen, "monst-edog_length"); if (buflen > 0) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) EDOG(mtmp), buflen); - } + Sfo_edog(nhfp, EDOG(mtmp), "monst-edog"); } buflen = EBONES(mtmp) ? (int) sizeof (struct ebones) : 0; - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof(int)); - } + Sfo_int(nhfp, &buflen, "monst-ebones_length"); if (buflen > 0) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) EBONES(mtmp), buflen); - } + Sfo_ebones(nhfp, EBONES(mtmp), "monst-ebones"); } /* mcorpsenm is inline int rather than pointer to something, so doesn't need to be preceded by a length field */ buflen = (int) MCORPSENM(mtmp); - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof (int)); - } + Sfo_int(nhfp, &buflen, "monst-mcorpsenm"); } } @@ -964,7 +866,7 @@ savemonchn(NHFILE *nhfp, struct monst *mtmp) while (mtmp) { mtmp2 = mtmp->nmon; - if (perform_bwrite(nhfp)) { + if (update_file(nhfp)) { mtmp->mnum = monsndx(mtmp->data); if (mtmp->ispriest) forget_temple_entry(mtmp); /* EPRI() */ @@ -986,10 +888,8 @@ savemonchn(NHFILE *nhfp, struct monst *mtmp) } mtmp = mtmp2; } - if (perform_bwrite(nhfp)) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &minusone, sizeof(int)); - } + if (update_file(nhfp)) { + Sfo_int(nhfp, &minusone, "monst-monst_length"); } } @@ -1006,10 +906,8 @@ savetrapchn(NHFILE *nhfp, struct trap *trap) trap2 = trap->ntrap; if (use_relative) trap->dst.dlevel -= u.uz.dlevel; /* make it relative */ - if (perform_bwrite(nhfp)) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) trap, sizeof *trap); - } + if (update_file(nhfp)) { + Sfo_trap(nhfp, trap, "trap"); } if (use_relative) trap->dst.dlevel += u.uz.dlevel; /* reset back to absolute */ @@ -1017,10 +915,8 @@ savetrapchn(NHFILE *nhfp, struct trap *trap) dealloc_trap(trap); trap = trap2; } - if (perform_bwrite(nhfp)) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &zerotrap, sizeof zerotrap); - } + if (update_file(nhfp)) { + Sfo_trap(nhfp, &zerotrap, "trap"); } } @@ -1038,19 +934,15 @@ savefruitchn(NHFILE *nhfp) f1 = gf.ffruit; while (f1) { f2 = f1->nextf; - if (f1->fid >= 0 && perform_bwrite(nhfp)) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) f1, sizeof *f1); - } + if (f1->fid >= 0 && update_file(nhfp)) { + Sfo_fruit(nhfp, f1, "fruit"); } if (release_data(nhfp)) dealloc_fruit(f1); f1 = f2; } - if (perform_bwrite(nhfp)) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &zerofruit, sizeof zerofruit); - } + if (update_file(nhfp)) { + Sfo_fruit(nhfp, &zerofruit, "fruit"); } if (release_data(nhfp)) gf.ffruit = 0; @@ -1064,17 +956,13 @@ savelevchn(NHFILE *nhfp) for (tmplev = svs.sp_levchn; tmplev; tmplev = tmplev->next) cnt++; - if (perform_bwrite(nhfp)) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &cnt, sizeof cnt); - } + if (update_file(nhfp)) { + Sfo_int(nhfp, &cnt, "levchn-lev_count"); } for (tmplev = svs.sp_levchn; tmplev; tmplev = tmplev2) { tmplev2 = tmplev->next; - if (perform_bwrite(nhfp)) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) tmplev, sizeof *tmplev); - } + if (update_file(nhfp)) { + Sfo_s_level(nhfp, tmplev, "levchn-s_level"); } if (release_data(nhfp)) free((genericptr_t) tmplev); @@ -1107,13 +995,12 @@ store_plname_in_file(NHFILE *nhfp) assert(hero[PL_NSIZ_PLUS - 1 - 1] == '\0'); hero[PL_NSIZ_PLUS - 1] = wizard ? 'D' : discover ? 'X' : '-'; - if (nhfp->structlevel) { - bufoff(nhfp->fd); - /* bwrite() before bufon() uses plain write() */ - bwrite(nhfp->fd, (genericptr_t) &plsiztmp, sizeof plsiztmp); - bwrite(nhfp->fd, (genericptr_t) hero, plsiztmp); + if (nhfp->structlevel) + bufoff(nhfp->fd); /* bwrite() before bufon() uses plain write() */ + Sfo_int(nhfp, &plsiztmp, "plname-size"); + Sfo_char(nhfp, hero, "plname", plsiztmp); + if (nhfp->structlevel) bufon(nhfp->fd); - } return; } @@ -1121,11 +1008,11 @@ staticfn void save_msghistory(NHFILE *nhfp) { char *msg; - int msgcount = 0, msglen; - int minusone = -1; + int msgcount = 0; + int minusone = -1, msglen; boolean init = TRUE; - if (perform_bwrite(nhfp)) { + if (update_file(nhfp)) { /* ask window port for each message in sequence */ while ((msg = getmsghistory(init)) != 0) { init = FALSE; @@ -1136,15 +1023,11 @@ save_msghistory(NHFILE *nhfp) no need to modify msg[] since terminator isn't written */ if (msglen > BUFSZ - 1) msglen = BUFSZ - 1; - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &msglen, sizeof msglen); - bwrite(nhfp->fd, (genericptr_t) msg, msglen); - } + Sfo_int(nhfp, &msglen, "msghistory-length"); + Sfo_char(nhfp, msg, "msghistory-msg", msglen); ++msgcount; } - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &minusone, sizeof(int)); - } + Sfo_int(nhfp, &minusone, "msghistory-length"); } debugpline1("Stored %d messages into savefile.", msgcount); /* note: we don't attempt to handle release_data() here */ @@ -1261,6 +1144,7 @@ freedynamicdata(void) #endif discard_gamelog(); release_runtime_info(); /* build-time options and version stuff */ + //free_convert_filenames(); #endif /* FREE_ALL_MEMORY */ if (VIA_WINDOWPORT()) @@ -1275,7 +1159,6 @@ freedynamicdata(void) /* last, because it frees data that might be used by panic() to provide feedback to the user; conceivably other freeing might trigger panic */ sysopt_release(); /* SYSCF strings */ - return; } /*save.c*/ diff --git a/src/sfbase.c b/src/sfbase.c new file mode 100644 index 000000000..6a62865af --- /dev/null +++ b/src/sfbase.c @@ -0,0 +1,209 @@ +/* NetHack 3.7 sfbase.c.template $NHDT-Date$ $NHDT-Branch$:$NHDT-Revision$ */ +/* Copyright (c) Michael Allison, 2025. */ +/* NetHack may be freely redistributed. See license for details. */ + +#include "hack.h" +#include "sfprocs.h" + +/* #define DO_DEBUG */ + +struct sf_structlevel_procs sfoprocs[NUM_SAVEFORMATS], sfiprocs[NUM_SAVEFORMATS], + zerosfoprocs = {0}, zerosfiprocs = {0}; + +void sf_log(NHFILE *, const char *, size_t, int); + +#define SF_A(dtyp) \ +void sfo_##dtyp(NHFILE *nhfp, dtyp *d_##dtyp, const char *myname) \ +{ \ + if (nhfp->fplog) \ + sf_log(nhfp, myname, sizeof *d_##dtyp, 1); \ + if (nhfp->structlevel) { \ + (*sfoprocs[nhfp->fnidx].fn.sf_##dtyp)(nhfp, d_##dtyp, myname); \ + } \ +} \ + \ +void sfi_##dtyp(NHFILE *nhfp, dtyp *d_##dtyp, const char *myname) \ +{ \ + if (nhfp->structlevel) { \ + (*sfiprocs[nhfp->fnidx].fn.sf_##dtyp)(nhfp, d_##dtyp, myname); \ + } \ + if (nhfp->fplog && !nhfp->eof) \ + sf_log(nhfp, myname, sizeof *d_##dtyp, 1); \ + if (nhfp->eof) \ + return; \ + if (((nhfp->mode & CONVERTING) != 0) && nhfp->nhfpconvert) \ + sfo_##dtyp(nhfp->nhfpconvert, d_##dtyp, myname); \ +} + +#define SF_C(keyw, dtyp) \ +void sfo_##dtyp(NHFILE *nhfp, keyw dtyp *d_##dtyp, const char *myname) \ +{ \ + \ + if (nhfp->structlevel) { \ + (*sfoprocs[nhfp->fnidx].fn.sf_##dtyp)(nhfp, d_##dtyp, myname); \ + } \ + if (nhfp->fplog && !nhfp->eof) \ + sf_log(nhfp, myname, sizeof *d_##dtyp, 1); \ +} \ + \ +void sfi_##dtyp(NHFILE *nhfp, keyw dtyp *d_##dtyp, const char *myname) \ +{ \ + if (nhfp->structlevel) { \ + (*sfiprocs[nhfp->fnidx].fn.sf_##dtyp)(nhfp, d_##dtyp, myname); \ + } \ + if (nhfp->fplog && !nhfp->eof) \ + sf_log(nhfp, myname, sizeof *d_##dtyp, 1); \ + if (nhfp->eof) \ + return; \ + if (((nhfp->mode & CONVERTING) != 0) && nhfp->nhfpconvert) \ + sfo_##dtyp(nhfp->nhfpconvert, d_##dtyp, myname); \ +} + +#define SF_X(xxx, dtyp) \ +void sfo_##dtyp(NHFILE *nhfp, xxx *d_##dtyp, const char *myname, int bfsz) \ +{ \ + if (nhfp->structlevel) { \ + (*sfoprocs[nhfp->fnidx].fn.sf_##dtyp)(nhfp, d_##dtyp, myname, bfsz); \ + } \ + if (nhfp->fplog && !nhfp->eof) \ + sf_log(nhfp, myname, sizeof *d_##dtyp, 1); \ +} \ + \ +void sfi_##dtyp(NHFILE *nhfp, xxx *d_##dtyp, const char *myname, int bfsz) \ +{ \ + if (nhfp->structlevel) { \ + (*sfiprocs[nhfp->fnidx].fn.sf_##dtyp)(nhfp, d_##dtyp, myname, bfsz); \ + } \ + if (nhfp->fplog && !nhfp->eof) \ + sf_log(nhfp, myname, sizeof *d_##dtyp, 1); \ + if (nhfp->eof) \ + return; \ + if (((nhfp->mode & CONVERTING) != 0) && nhfp->nhfpconvert) \ + sfo_##dtyp(nhfp->nhfpconvert, d_##dtyp, myname, bfsz); \ +} + +SF_C(struct, arti_info) +SF_C(struct, nhrect) +SF_C(struct, branch) +SF_C(struct, bubble) +SF_C(struct, cemetery) +SF_C(struct, context_info) +SF_C(struct, nhcoord) +SF_C(struct, damage) +SF_C(struct, dest_area) +SF_C(struct, dgn_topology) +SF_C(struct, dungeon) +SF_C(struct, d_level) +SF_C(struct, ebones) +SF_C(struct, edog) +SF_C(struct, egd) +SF_C(struct, emin) +SF_C(struct, engr) +SF_C(struct, epri) +SF_C(struct, eshk) +SF_C(struct, fe) +SF_C(struct, flag) +SF_C(struct, fruit) +SF_C(struct, gamelog_line) +SF_C(struct, kinfo) +SF_C(struct, levelflags) +SF_C(struct, ls_t) +SF_C(struct, linfo) +SF_C(struct, mapseen_feat) +SF_C(struct, mapseen_flags) +SF_C(struct, mapseen_rooms) +SF_C(struct, mkroom) +SF_C(struct, monst) +SF_C(struct, mvitals) +SF_C(struct, obj) +SF_C(struct, objclass) +SF_C(struct, q_score) +SF_C(struct, rm) +SF_C(struct, spell) +SF_C(struct, stairway) +SF_C(struct, s_level) +SF_C(struct, trap) +SF_C(struct, version_info) +SF_C(struct, you) +SF_C(union, any) + +SF_A(aligntyp) +SF_A(boolean) +SF_A(coordxy) +SF_A(genericptr) +SF_A(int) +SF_A(int16) +SF_A(int32) +SF_A(int64) +SF_A(long) +SF_A(schar) +SF_A(short) +SF_A(size_t) +SF_A(time_t) +SF_A(uchar) +SF_A(uint16) +SF_A(uint32) +SF_A(uint64) +SF_A(ulong) +SF_A(unsigned) +SF_A(ushort) +SF_A(xint16) +SF_A(xint8) + +void +sfo_char(NHFILE *nhfp, char *d_char, const char *myname, int cnt) +{ + if (nhfp->structlevel) { + (*sfoprocs[nhfp->fnidx].fn.sf_char)(nhfp, d_char, myname, cnt); + } + if (nhfp->fplog && !nhfp->eof) + sf_log(nhfp, myname, sizeof (char), cnt); +} + +void +sfi_char(NHFILE *nhfp, char *d_char, const char *myname, int cnt) +{ + if (nhfp->structlevel) { + (*sfiprocs[nhfp->fnidx].fn.sf_char)(nhfp, d_char, myname, cnt); + } + if (nhfp->fplog && !nhfp->eof) + sf_log(nhfp, myname, sizeof (char), cnt); + if (nhfp->eof) + return; + if (((nhfp->mode & CONVERTING) != 0) && nhfp->nhfpconvert) + sfo_char(nhfp->nhfpconvert, d_char, myname, cnt); +} +SF_X(uint8_t, bitfield) + +/* ---------------------------------------------------------------*/ + +void +sf_log(NHFILE *nhfp, const char *t1, size_t sz, int cnt) +{ + FILE *fp = nhfp->fplog; + + if (fp) { + (void) fprintf(fp, "%ld %s sz=%zu cnt=%d\n", + nhfp->count++, + t1, sz, cnt); + fflush(fp); + } +} + +/* + *---------------------------------------------------------------------------- + * initialize the function pointers. These are called from initoptions_init(). + *---------------------------------------------------------------------------- + */ + +void +sf_init(void) +{ + sfoprocs[invalid] = zerosfoprocs; + sfiprocs[invalid] = zerosfiprocs; + sfoprocs[historical] = historical_sfo_procs; + sfiprocs[historical] = historical_sfi_procs; +} + + + diff --git a/src/sfstruct.c b/src/sfstruct.c index f4a09163f..c4eda5418 100644 --- a/src/sfstruct.c +++ b/src/sfstruct.c @@ -1,9 +1,326 @@ /* NetHack 3.7 sfstruct.c $NHDT-Date: 1606765215 2020/11/30 19:40:15 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.4 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ -/*-Copyright (c) Michael Allison, 2009. */ +/*-Copyright (c) Michael Allison, 2025. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" +#include "sfprocs.h" + +/* #define SFLOGGING */ /* debugging */ + +/* historical full struct savings */ + +#ifdef SAVEFILE_DEBUGGING +#if defined(__GNUC__) +#define DEBUGFORMATSTR64 "%s %s %ld %ld %d\n" +#elif defined(_MSC_VER) +#define DEBUGFORMATSTR64 "%s %s %lld %ld %d\n" +#endif +#endif + +#ifdef SFLOGGING +staticfn void logging_finish(void); +#endif + +#define SFO_BODY(dt) \ +{ \ + bwrite(nhfp->fd, (genericptr_t) d_##dt, sizeof *d_##dt); \ +} + +#define SFI_BODY(dt) \ +{ \ + mread(nhfp->fd, (genericptr_t) d_##dt, sizeof *d_##dt); \ + if (restoreinfo.mread_flags == -1) \ + nhfp->eof = TRUE; \ +} + +#define SF_A(dtyp) \ +void historical_sfo_##dtyp(NHFILE *, dtyp *d_##dtyp, const char *); \ +void historical_sfi_##dtyp(NHFILE *, dtyp *d_##dtyp, const char *); \ + \ +void historical_sfo_##dtyp(NHFILE *nhfp, dtyp *d_##dtyp, \ + const char *myname UNUSED) \ + SFO_BODY(dtyp) \ + \ +void historical_sfi_##dtyp(NHFILE *nhfp, dtyp *d_##dtyp, \ + const char *myname UNUSED) \ + SFI_BODY(dtyp) + + +#define SF_C(keyw, dtyp) \ +void historical_sfo_##dtyp(NHFILE *, keyw dtyp *d_##dtyp, \ + const char *); \ +void historical_sfi_##dtyp(NHFILE *, keyw dtyp *d_##dtyp, \ + const char *); \ + \ +void historical_sfo_##dtyp(NHFILE *nhfp, keyw dtyp *d_##dtyp, \ + const char *myname UNUSED) \ + SFO_BODY(dtyp) \ + \ +void historical_sfi_##dtyp(NHFILE *nhfp, keyw dtyp *d_##dtyp, \ + const char *myname UNUSED) \ + SFI_BODY(dtyp) + +#define SF_X(xxx, dtyp) \ +void historical_sfo_##dtyp(NHFILE *, xxx *d_##dtyp, const char *, int); \ +void historical_sfi_##dtyp(NHFILE *, xxx *d_##dtyp, const char *, int); \ + \ +void historical_sfo_##dtyp(NHFILE *nhfp, xxx *d_##dtyp, \ + const char *myname UNUSED, int bflen UNUSED) \ + SFO_BODY(dtyp) \ + \ +void historical_sfi_##dtyp(NHFILE *nhfp, xxx *d_##dtyp, \ + const char *myname UNUSED, int bflen UNUSED) \ + SFI_BODY(dtyp) + +SF_C(struct, arti_info) +SF_C(struct, nhrect) +SF_C(struct, branch) +SF_C(struct, bubble) +SF_C(struct, cemetery) +SF_C(struct, context_info) +SF_C(struct, nhcoord) +SF_C(struct, damage) +SF_C(struct, dest_area) +SF_C(struct, dgn_topology) +SF_C(struct, dungeon) +SF_C(struct, d_level) +SF_C(struct, ebones) +SF_C(struct, edog) +SF_C(struct, egd) +SF_C(struct, emin) +SF_C(struct, engr) +SF_C(struct, epri) +SF_C(struct, eshk) +SF_C(struct, fe) +SF_C(struct, flag) +SF_C(struct, fruit) +SF_C(struct, gamelog_line) +SF_C(struct, kinfo) +SF_C(struct, levelflags) +SF_C(struct, ls_t) +SF_C(struct, linfo) +SF_C(struct, mapseen_feat) +SF_C(struct, mapseen_flags) +SF_C(struct, mapseen_rooms) +SF_C(struct, mkroom) +SF_C(struct, monst) +SF_C(struct, mvitals) +SF_C(struct, obj) +SF_C(struct, objclass) +SF_C(struct, q_score) +SF_C(struct, rm) +SF_C(struct, spell) +SF_C(struct, stairway) +SF_C(struct, s_level) +SF_C(struct, trap) +SF_C(struct, version_info) +SF_C(struct, you) + +SF_C(union, any) +SF_A(aligntyp) +SF_A(boolean) +SF_A(coordxy) +SF_A(genericptr_t) +SF_A(int) +SF_A(int16) +SF_A(int32) +SF_A(int64) +SF_A(long) +SF_A(schar) +SF_A(short) +SF_A(size_t) +SF_A(time_t) +SF_A(uchar) +SF_A(uint16) +SF_A(uint32) +SF_A(uint64) +SF_A(ulong) +SF_A(unsigned) +SF_A(ushort) +SF_A(xint16) +SF_A(xint8) + +void historical_sfo_char(NHFILE *, char *d_char, const char *, int); +void historical_sfi_char(NHFILE *, char *d_char, const char *, int); + +void +historical_sfo_char(NHFILE *nhfp, char *d_char, + const char *myname UNUSED, int cnt) +{ + bwrite(nhfp->fd, (genericptr_t) d_char, cnt * sizeof (char)); +} + +void +historical_sfi_char(NHFILE *nhfp, char *d_char, + const char *myname UNUSED, int cnt) +{ + mread(nhfp->fd, (genericptr_t) d_char, cnt * sizeof (char)); + if (restoreinfo.mread_flags == -1) + nhfp->eof = TRUE; +} + +SF_X(uint8_t, bitfield) + +struct sf_structlevel_procs historical_sfo_procs = { + "", + /* sf */ + { + historical_sfo_arti_info, + historical_sfo_nhrect, + historical_sfo_branch, + historical_sfo_bubble, + historical_sfo_cemetery, + historical_sfo_context_info, + historical_sfo_nhcoord, + historical_sfo_damage, + historical_sfo_dest_area, + historical_sfo_dgn_topology, + historical_sfo_dungeon, + historical_sfo_d_level, + historical_sfo_ebones, + historical_sfo_edog, + historical_sfo_egd, + historical_sfo_emin, + historical_sfo_engr, + historical_sfo_epri, + historical_sfo_eshk, + historical_sfo_fe, + historical_sfo_flag, + historical_sfo_fruit, + historical_sfo_gamelog_line, + historical_sfo_kinfo, + historical_sfo_levelflags, + historical_sfo_ls_t, + historical_sfo_linfo, + historical_sfo_mapseen_feat, + historical_sfo_mapseen_flags, + historical_sfo_mapseen_rooms, + historical_sfo_mkroom, + historical_sfo_monst, + historical_sfo_mvitals, + historical_sfo_obj, + historical_sfo_objclass, + historical_sfo_q_score, + historical_sfo_rm, + historical_sfo_spell, + historical_sfo_stairway, + historical_sfo_s_level, + historical_sfo_trap, + historical_sfo_version_info, + historical_sfo_you, + historical_sfo_any, + + historical_sfo_aligntyp, + historical_sfo_boolean, + historical_sfo_coordxy, + historical_sfo_genericptr_t, + historical_sfo_int, + historical_sfo_int16, + historical_sfo_int32, + historical_sfo_int64, + historical_sfo_long, + historical_sfo_schar, + historical_sfo_short, + historical_sfo_size_t, + historical_sfo_time_t, + historical_sfo_uchar, + historical_sfo_uint16, + historical_sfo_uint32, + historical_sfo_uint64, + historical_sfo_ulong, + historical_sfo_unsigned, + historical_sfo_ushort, + historical_sfo_xint16, + historical_sfo_xint8, + historical_sfo_char, + historical_sfo_bitfield, + } +}; + +struct sf_structlevel_procs historical_sfi_procs = { + "", + /* sf */ + { + historical_sfi_arti_info, + historical_sfi_nhrect, + historical_sfi_branch, + historical_sfi_bubble, + historical_sfi_cemetery, + historical_sfi_context_info, + historical_sfi_nhcoord, + historical_sfi_damage, + historical_sfi_dest_area, + historical_sfi_dgn_topology, + historical_sfi_dungeon, + historical_sfi_d_level, + historical_sfi_ebones, + historical_sfi_edog, + historical_sfi_egd, + historical_sfi_emin, + historical_sfi_engr, + historical_sfi_epri, + historical_sfi_eshk, + historical_sfi_fe, + historical_sfi_flag, + historical_sfi_fruit, + historical_sfi_gamelog_line, + historical_sfi_kinfo, + historical_sfi_levelflags, + historical_sfi_ls_t, + historical_sfi_linfo, + historical_sfi_mapseen_feat, + historical_sfi_mapseen_flags, + historical_sfi_mapseen_rooms, + historical_sfi_mkroom, + historical_sfi_monst, + historical_sfi_mvitals, + historical_sfi_obj, + historical_sfi_objclass, + historical_sfi_q_score, + historical_sfi_rm, + historical_sfi_spell, + historical_sfi_stairway, + historical_sfi_s_level, + historical_sfi_trap, + historical_sfi_version_info, + historical_sfi_you, + historical_sfi_any, + + historical_sfi_aligntyp, + historical_sfi_boolean, + historical_sfi_coordxy, + historical_sfi_genericptr_t, + historical_sfi_int, + historical_sfi_int16, + historical_sfi_int32, + historical_sfi_int64, + historical_sfi_long, + historical_sfi_schar, + historical_sfi_short, + historical_sfi_size_t, + historical_sfi_time_t, + historical_sfi_uchar, + historical_sfi_uint16, + historical_sfi_uint32, + historical_sfi_uint64, + historical_sfi_ulong, + historical_sfi_unsigned, + historical_sfi_ushort, + historical_sfi_xint16, + historical_sfi_xint8, + historical_sfi_char, + historical_sfi_bitfield, + } +}; + +/* + * The historical bwrite() and mread() functions follow + */ + +#ifdef SAVEFILE_DEBUGGING +static long floc = 0L; +#endif /* * historical structlevel savefile writing and reading routines follow. @@ -28,6 +345,19 @@ static int bw_buffered[MAXFD] = {0,0,0,0,0}; static FILE *bw_FILE[MAXFD] = {0,0,0,0,0}; #endif +#ifdef SFLOGGING +static FILE *ofp[20] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + char ofnamebuf[80]; + static long ocnt = 0L; + + static FILE *ifp[20] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + char ifnamebuf[80]; + static long icnt = 0L; +#endif + + /* * Presumably, the fdopen() to allow use of stdio fwrite() * over write() was done for performance or functionality @@ -146,6 +476,17 @@ bclose(int fd) /* return the idx to the pool */ bw_sticky[idx] = -1; } +#ifdef SFLOGGING + if (fd >= 0 && fd <= SIZE(ofp)) { + if (ofp[fd]) { + fclose(ofp[fd]); + ofp[fd] = 0; + } else if (ifp[fd]) { + fclose(ifp[fd]); + ifp[fd] = 0; + } + } +#endif return; } @@ -171,6 +512,20 @@ bwrite(int fd, const genericptr_t loc, unsigned num) boolean failed; int idx = getidx(fd, NOFLG); +#ifdef SFLOGGING + if (fd >= 0 && fd < SIZE(ofp)) { + if (!ofp[fd]) { + Snprintf(ofnamebuf, sizeof ofnamebuf, "bwrite_%02d.log", fd); + ofp[fd] = fopen(ofnamebuf, "w"); + } + if (ofp[fd]) { + fprintf(ofp[fd], "%08ld, %08ld, %d\n", ocnt, + ftell(ofp[fd]), num); + ocnt++; + } + } +#endif + if (idx >= 0) { if (num == 0) { /* nothing to do; we need a special case to exit early @@ -209,7 +564,22 @@ bwrite(int fd, const genericptr_t loc, unsigned num) void mread(int fd, genericptr_t buf, unsigned len) { -#if defined(BSD) || defined(ULTRIX) + +#ifdef SFLOGGING + if (fd >= 0 && fd < 9) { + if (!ifp[fd]) { + Snprintf(ifnamebuf, sizeof ifnamebuf, "mread_%02d.log", fd); + ifp[fd] = fopen(ifnamebuf, "w"); + } + if (ifp[fd]) { + fprintf(ifp[fd], "%08ld, %08ld, %d\n", icnt, + ftell(ifp[fd]), (int) len); + icnt++; + } + } +#endif + +#if defined(BSD) || defined(ULTRIX) || defined(WIN32) #define readLenType int #else /* e.g. SYSV, __TURBOC__ */ #define readLenType unsigned @@ -235,3 +605,27 @@ mread(int fd, genericptr_t buf, unsigned len) } +#ifdef SFLOGGING +staticfn void +logging_finish(void) +{ + int i; + + for (i = 0; i < SIZE(ofp); ++i) { + if (ofp[i]) { + fclose(ofp[i]); + ofp[i] = 0; + } + } + ocnt = 0L; + + for (i = 0; i < SIZE(ifp); ++i) { + if (ifp[i]) { + fclose(ifp[i]); + ifp[i] = 0; + } + } + icnt = 0L; +} +#endif + diff --git a/src/sys.c b/src/sys.c index 9cdead0ba..4d8ad2dcf 100644 --- a/src/sys.c +++ b/src/sys.c @@ -99,8 +99,7 @@ sys_early_init(void) sysopt.check_plname = 0; sysopt.seduce = 1; /* if it's compiled in, default to on */ sysopt_seduce_set(sysopt.seduce); - /* default to little-endian in 3.7 */ - sysopt.saveformat[0] = sysopt.bonesformat[0] = lendian; + sysopt.saveformat[0] = sysopt.bonesformat[0] = historical; sysopt.accessibility = 0; #ifdef WIN32 sysopt.portable_device_paths = 0; diff --git a/src/timeout.c b/src/timeout.c index 34e95806a..dbfa90762 100644 --- a/src/timeout.c +++ b/src/timeout.c @@ -2022,7 +2022,7 @@ print_queue(winid win, timer_element *base) for (curr = base; curr; curr = curr->next) { #ifdef VERBOSE_TIMER Sprintf(buf, " %4ld %4ld %-6s %s(%s)", curr->timeout, - curr->tid, kind_name(curr->kind), + (long) curr->tid, kind_name(curr->kind), timeout_funcs[curr->func_index].name, fmt_ptr((genericptr_t) curr->arg.a_void)); #else @@ -2496,25 +2496,19 @@ write_timer(NHFILE *nhfp, timer_element *timer) case TIMER_GLOBAL: case TIMER_LEVEL: /* assume no pointers in arg */ - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) timer, sizeof(timer_element)); - } + Sfo_fe(nhfp, timer, "timer"); break; case TIMER_OBJECT: if (timer->needs_fixup) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) timer, sizeof(timer_element)); - } + Sfo_fe(nhfp, timer, "timer"); } else { /* replace object pointer with id */ arg_save.a_obj = timer->arg.a_obj; timer->arg = cg.zeroany; timer->arg.a_uint = (arg_save.a_obj)->o_id; timer->needs_fixup = 1; - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) timer, sizeof(timer_element)); - } + Sfo_fe(nhfp, timer, "timer"); timer->arg.a_obj = arg_save.a_obj; timer->needs_fixup = 0; } @@ -2522,18 +2516,14 @@ write_timer(NHFILE *nhfp, timer_element *timer) case TIMER_MONSTER: if (timer->needs_fixup) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) timer, sizeof(timer_element)); - } + Sfo_fe(nhfp, timer, "timer"); } else { /* replace monster pointer with id */ arg_save.a_monst = timer->arg.a_monst; timer->arg = cg.zeroany; timer->arg.a_uint = (arg_save.a_monst)->m_id; timer->needs_fixup = 1; - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) timer, sizeof(timer_element)); - } + Sfo_fe(nhfp, timer, "timer"); timer->arg.a_monst = arg_save.a_monst; timer->needs_fixup = 0; } @@ -2665,17 +2655,12 @@ save_timers(NHFILE *nhfp, int range) timer_element *curr, *prev, *next_timer = 0; int count; - if (perform_bwrite(nhfp)) { + if (update_file(nhfp)) { if (range == RANGE_GLOBAL) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &svt.timer_id, - sizeof svt.timer_id); - } + Sfo_ulong(nhfp, &svt.timer_id, "timer-timer_id"); } count = maybe_write_timer(nhfp, range, FALSE); - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &count, sizeof count); - } + Sfo_int(nhfp, &count, "timer-timer_count"); (void) maybe_write_timer(nhfp, range, TRUE); } @@ -2710,22 +2695,14 @@ restore_timers(NHFILE *nhfp, int range, long adjust) boolean ghostly = (nhfp->ftype == NHF_BONESFILE); /* from a ghost level */ if (range == RANGE_GLOBAL) { - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &svt.timer_id, - sizeof svt.timer_id); - } + Sfi_ulong(nhfp, &svt.timer_id, "timer-timer_id"); } /* restore elements */ - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &count, sizeof count); - } - + Sfi_int(nhfp, &count, "timer-timer_count"); while (count-- > 0) { curr = (timer_element *) alloc(sizeof(timer_element)); - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) curr, sizeof(timer_element)); - } + Sfi_fe(nhfp, curr, "timer"); if (ghostly) curr->timeout += adjust; insert_timer(curr); diff --git a/src/track.c b/src/track.c index 60a0d382b..6f455a694 100644 --- a/src/track.c +++ b/src/track.c @@ -69,20 +69,13 @@ hastrack(coordxy x, coordxy y) void save_track(NHFILE *nhfp) { - if (perform_bwrite(nhfp)) { + if (update_file(nhfp)) { int i; - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &utcnt, sizeof utcnt); - bwrite(nhfp->fd, (genericptr_t) &utpnt, sizeof utpnt); - } + Sfo_int(nhfp, &utcnt, "track-utcnt"); + Sfo_int(nhfp, &utpnt, "track-utpnt"); for (i = 0; i < utcnt; i++) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &utrack[i].x, - sizeof utrack[i].x); - bwrite(nhfp->fd, (genericptr_t) &utrack[i].y, - sizeof utrack[i].y); - } + Sfo_nhcoord(nhfp, &utrack[i], "utrack"); } } if (release_data(nhfp)) @@ -95,17 +88,13 @@ rest_track(NHFILE *nhfp) { int i; - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &utcnt, sizeof utcnt); - mread(nhfp->fd, (genericptr_t) &utpnt, sizeof utpnt); - } + Sfi_int(nhfp, &utcnt, "track-utcnt"); + Sfi_int(nhfp, &utpnt, "track-utpnt"); + if (utcnt > UTSZ || utpnt > UTSZ) panic("rest_track: impossible pt counts"); for (i = 0; i < utcnt; i++) { - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &utrack[i].x, sizeof utrack[i].x); - mread(nhfp->fd, (genericptr_t) &utrack[i].y, sizeof utrack[i].y); - } + Sfi_nhcoord(nhfp, &utrack[i], "utrack"); } } diff --git a/src/version.c b/src/version.c index f1303744d..dc1d0e654 100644 --- a/src/version.c +++ b/src/version.c @@ -373,6 +373,10 @@ check_version( #endif complain = FALSE; /* 'complain' requires 'filename' for pline("%s") */ } + if ((version_data->feature_set & SFCTOOL_BIT) != 0) { + gc.converted_savefile_loaded = TRUE; + version_data->feature_set &= ~(SFCTOOL_BIT); + } if ( #ifdef VERSION_COMPATIBILITY /* patchlevel.h */ version_data->incarnation < VERSION_COMPATIBILITY @@ -421,13 +425,11 @@ store_version(NHFILE *nhfp) bufoff(nhfp->fd); store_critical_bytes(nhfp); - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &version_data, - (unsigned) (sizeof version_data)); - } + Sfo_version_info(nhfp, (struct version_info *) &version_data, + "version_info"); if (nhfp->structlevel) - bufon(nhfp->fd); + bufon(nhfp->fd); return; } @@ -661,90 +663,170 @@ store_critical_bytes(NHFILE *nhfp) if (nhfp->mode & WRITING) { indicate = (nhfp->structlevel) ? 'h' - : (nhfp->fnidx == ascii) ? 'a' - : 'l'; - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &indicate, - (unsigned) sizeof indicate); - } - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &csc_count, - (unsigned) sizeof csc_count); - } + : (nhfp->fnidx == cnvascii) ? 'a' + : '?'; + Sfo_char(nhfp, &indicate, "indicate-format", 1); + Sfo_char(nhfp, &csc_count, "count-critical_sizes", 1); cnt = (int) csc_count; for (i = 0; i < cnt; ++i) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &critical_sizes[i].ucsize, - (unsigned) sizeof (uchar)); - } + Sfo_uchar(nhfp, &critical_sizes[i].ucsize, "critical_sizes"); } } } /* this used to be based on file date and somewhat OS-dependent, - but now examines the initial part of the file's contents */ -boolean + * but now examines the initial part of the file's contents. + * + * returns: + * + * SF_UPTODATE (0) everything matched and looks good + * SF_OUTDATED (1) savefile is outdated + * SF_CRITICAL_BYTE_COUNT_MISMATCH (2) critical size count mismatch + * SF_DM_IL32LLP64_ON_ILP32LL64 (3) Windows x64 savefile on x86 + * SF_DM_I32LP64_ON_ILP32LL64 (4) Unix 64 savefile on x86 + * SF_DM_ILP32LL64_ON_I32LP64 (5) x86 savefile on Unix 64 + * SF_DM_ILP32LL64_ON_IL32LLP64 (6) x86 savefile on Windows x64 + * SF_DM_I32LP64_ON_IL32LLP64 (7) Unix 64 savefile on Windows x64 + * SF_DM_IL32LLP64_ON_I32LP64 (8) Windows x64 savefile on Unix 64 + * SF_DM_MISMATCH (9) some other mismatch + */ +int uptodate(NHFILE *nhfp, const char *name, unsigned long utdflags) { struct version_info vers_info; char indicator; + int sfstatus = 0, idx_1st_mismatch = 0; + boolean quietly = (utdflags & UTD_QUIETLY) != 0; boolean verbose = name ? TRUE : FALSE; - int ccbresult = 0; - /* int you_size = (int) sizeof (struct you); */ - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &indicator, sizeof indicator); - } - if ((ccbresult = compare_critical_bytes(nhfp)) != 0) { - if (ccbresult > 0) { - raw_printf("compare of critical bytes failed at %d (%s).", - critical_sizes[ccbresult].ucsize, - critical_sizes[ccbresult].nm); + Sfi_char(nhfp, &indicator, "indicate-format", 1); + if ((sfstatus = compare_critical_bytes(nhfp, &idx_1st_mismatch, utdflags)) + != SF_UPTODATE) { + if (sfstatus > 0 && idx_1st_mismatch) { + if (!quietly) + raw_printf("comparison of critical bytes mismatched at %d (%s).", + critical_sizes[idx_1st_mismatch].ucsize, + critical_sizes[idx_1st_mismatch].nm); } - return FALSE; + return sfstatus; } - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &vers_info, sizeof vers_info); - } + Sfi_version_info(nhfp, &vers_info, "version_info"); if (!check_version(&vers_info, name, verbose, utdflags)) { if (verbose) { if ((utdflags & UTD_WITHOUT_WAITSYNCH_PERFILE) == 0) wait_synch(); } - return FALSE; + return SF_OUTDATED; } - return TRUE; + + return SF_UPTODATE; } +/* + * returns: + * + * SF_UPTODATE (0) everything matched and looks good + * SF_OUTDATED (1) savefile is outdated + * SF_CRITICAL_BYTE_COUNT_MISMATCH (2) critical size count mismatch + * SF_DM_IL32LLP64_ON_ILP32LL64 (3) Windows x64 savefile on x86 + * SF_DM_I32LP64_ON_ILP32LL64 (4) Unix 64 savefile on x86 + * SF_DM_ILP32LL64_ON_I32LP64 (5) x86 savefile on Unix 64 + * SF_DM_ILP32LL64_ON_IL32LLP64 (6) x86 savefile on Windows x64 + * SF_DM_I32LP64_ON_IL32LLP64 (7) Unix 64 savefile on Windows x64 + * SF_DM_IL32LLP64_ON_I32LP64 (8) Windows x64 savefile on Unix 64 + * SF_DM_MISMATCH (9) some other mismatch + */ int -compare_critical_bytes(NHFILE *nhfp) +compare_critical_bytes(NHFILE *nhfp, int *idx_1st_mismatch, unsigned long utdflags) { char active_csc_count = (char) SIZE(critical_sizes), - file_csc_count = 0; - int i, cnt = (int) active_csc_count; + file_csc_count; + int i, cnt = (int) active_csc_count, + dmmismatch = SF_DM_MISMATCH; + boolean quietly = (utdflags & UTD_QUIETLY) != 0; - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &file_csc_count, - sizeof file_csc_count); - } + Sfi_char(nhfp, &file_csc_count, "count-critical_sizes", 1); if (file_csc_count > cnt) { - raw_printf("critical byte counts do not match" - ", file:%d, critical_sizes:%d.", - file_csc_count, SIZE(critical_sizes)); - return -1; + if (!quietly) + raw_printf("critical byte counts do not match" + ", file:%d, critical_sizes:%d.", + file_csc_count, SIZE(critical_sizes)); + return SF_CRITICAL_BYTE_COUNT_MISMATCH; } for (i = 0; i < (int) file_csc_count; ++i) { - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &cscbuf[i], - sizeof (uchar)); - } + Sfi_uchar(nhfp, &cscbuf[i], "critical_sizes"); } for (i = 1; i < cnt; ++i) { - if (cscbuf[i] != critical_sizes[i].ucsize) - return i; + if (cscbuf[i] != critical_sizes[i].ucsize) { + const char *dm = datamodel(), *dmfile; + + dmfile = what_datamodel_is_this(cscbuf[1], /* short */ + cscbuf[2], /* int */ + cscbuf[3], /* long */ + cscbuf[4], /* long long */ + cscbuf[5]); /* ptr */ + + if (!strcmp(dmfile, "IL32LLP64") && !strcmp(dm, "ILP32LL64")) { + /* Windows x64 savefile on x86 */ + dmmismatch = SF_DM_IL32LLP64_ON_ILP32LL64; + } else if (!strcmp(dmfile, "I32LP64") + && !strcmp(dm, "ILP32LL64")) { + /* Unix 64 savefile on x86*/ + dmmismatch = SF_DM_I32LP64_ON_ILP32LL64; + } else if (!strcmp(dmfile, "ILP32LL64") + && !strcmp(dm, "I32LP64")) { + /* x86 savefile on Unix 64 */ + dmmismatch = SF_DM_ILP32LL64_ON_I32LP64; + } else if (!strcmp(dmfile, "ILP32LL64") + && !strcmp(dm, "IL32LLP64")) { + /* x86 savefile on Windows x64 */ + dmmismatch = SF_DM_ILP32LL64_ON_IL32LLP64; + } else if (!strcmp(dmfile, "I32LP64") + && !strcmp(dm, "IL32LLP64")) { + /* Unix 64 savefile on Windows x64 */ + dmmismatch = SF_DM_I32LP64_ON_IL32LLP64; + } else if (!strcmp(dmfile, "IL32LLP64") + && !strcmp(dm, "I32LP64")) { + /* Windows x64 savefile on Unix 64 */ + dmmismatch = SF_DM_IL32LLP64_ON_I32LP64; + } + if (idx_1st_mismatch) + *idx_1st_mismatch = i; + return dmmismatch; + } } - return 0; /* everything matched */ + return SF_UPTODATE; /* everything matched */ +} + +/* + * returns: + * + * SF_UPTODATE (0) everything matched and looks good + * SF_OUTDATED (1) savefile is outdated + * SF_CRITICAL_BYTE_COUNT_MISMATCH (2) critical size count mismatch + * SF_DM_IL32LLP64_ON_ILP32LL64 (3) Windows x64 savefile on x86 + * SF_DM_I32LP64_ON_ILP32LL64 (4) Unix 64 savefile on x86 + * SF_DM_ILP32LL64_ON_I32LP64 (5) x86 savefile on Unix 64 + * SF_DM_ILP32LL64_ON_IL32LLP64 (6) x86 savefile on Windows x64 + * SF_DM_I32LP64_ON_IL32LLP64 (7) Unix 64 savefile on Windows x64 + * SF_DM_IL32LLP64_ON_I32LP64 (8) Windows x64 savefile on Unix 64 + * SF_DM_MISMATCH (9) some other mismatch + */ +int +validate(NHFILE *nhfp, const char *name, boolean without_waitsynch_perfile) +{ + unsigned long utdflags = 0L; + int validsf = 0; + + if (nhfp->structlevel) + utdflags |= UTD_CHECKSIZES; + if (without_waitsynch_perfile) + utdflags |= UTD_WITHOUT_WAITSYNCH_PERFILE; + if (nhfp->fieldlevel) + utdflags |= UTD_CHECKFIELDCOUNTS | UTD_SKIP_SANITY1 | UTD_QUIETLY; + validsf = uptodate(nhfp, name, utdflags); + return validsf; } #endif /* MINIMAL_FOR_RECOVER */ diff --git a/src/worm.c b/src/worm.c index c760bc3a3..af68084d1 100644 --- a/src/worm.c +++ b/src/worm.c @@ -16,6 +16,7 @@ struct wseg { staticfn void toss_wsegs(struct wseg *, boolean) NO_NNARGS; staticfn void shrink_worm(int); + #if 0 staticfn void random_dir(int, int, int *, int *); #endif @@ -527,31 +528,22 @@ save_worm(NHFILE *nhfp) int count; struct wseg *curr, *temp; - if (perform_bwrite(nhfp)) { + if (update_file(nhfp)) { for (i = 1; i < MAX_NUM_WORMS; i++) { for (count = 0, curr = wtails[i]; curr; curr = curr->nseg) count++; /* Save number of segments */ - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &count, sizeof count); - } + Sfo_int(nhfp, &count, "worm-segment_count"); /* Save segment locations of the monster. */ if (count) { for (curr = wtails[i]; curr; curr = curr->nseg) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &(curr->wx), - sizeof curr->wx); - bwrite(nhfp->fd, (genericptr_t) &(curr->wy), - sizeof curr->wy); - } + Sfo_coordxy(nhfp, &(curr->wx), "worm-wx"); + Sfo_coordxy(nhfp, &(curr->wy), "worm-wy"); } } } - for (i = 0; i < MAX_NUM_WORMS; ++i) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &wgrowtime[i], sizeof (long)); - } - } + for (i = 0; i < MAX_NUM_WORMS; ++i) + Sfo_long(nhfp, &wgrowtime[i], "worm-wgrowtime"); } if (release_data(nhfp)) { @@ -580,22 +572,19 @@ save_worm(NHFILE *nhfp) void rest_worm(NHFILE *nhfp) { - int i, j, count = 0; + int i, j; + int count = 0; struct wseg *curr, *temp; for (i = 1; i < MAX_NUM_WORMS; i++) { - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &count, sizeof count); - } + Sfi_int(nhfp, &count, "worm-segment_count"); /* Get the segments. */ for (curr = (struct wseg *) 0, j = 0; j < count; j++) { temp = newseg(); temp->nseg = (struct wseg *) 0; - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &(temp->wx), sizeof temp->wx); - mread(nhfp->fd, (genericptr_t) &(temp->wy), sizeof temp->wy); - } + Sfi_coordxy(nhfp, &(temp->wx), "worm-wx"); + Sfi_coordxy(nhfp, &(temp->wy), "worm-wy"); if (curr) curr->nseg = temp; else @@ -605,9 +594,7 @@ rest_worm(NHFILE *nhfp) wheads[i] = curr; } for (i = 0; i < MAX_NUM_WORMS; ++i) { - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &wgrowtime[i], sizeof (long)); - } + Sfi_long(nhfp, &wgrowtime[i], "worm-wgrowtime"); } } diff --git a/sys/share/pcmain.c b/sys/share/pcmain.c index cad2bc69a..4093eff48 100644 --- a/sys/share/pcmain.c +++ b/sys/share/pcmain.c @@ -7,6 +7,7 @@ #include "hack.h" #include "dlb.h" +#include "sfproto.h" #ifndef NO_SIGNAL #include @@ -429,9 +430,7 @@ _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);*/ raw_print("Cannot create lock file"); } else { svh.hackpid = 1; - if (nhfp->structlevel) { - write(nhfp->fd, (genericptr_t) &svh.hackpid, sizeof svh.hackpid); - } + Sfo_int(nhfp, &svh.hackpid, "svh.hackpid"); close_nhfile(nhfp); } diff --git a/sys/unix/Makefile.src b/sys/unix/Makefile.src index d2e3c8e91..89836554a 100644 --- a/sys/unix/Makefile.src +++ b/sys/unix/Makefile.src @@ -518,7 +518,7 @@ HACKCSRC = allmain.c alloc.c apply.c artifact.c attrib.c ball.c bones.c \ nhlua.c nhlsel.c nhlobj.c nhmd4.c o_init.c objects.c objnam.c \ options.c pager.c pickup.c pline.c polyself.c potion.c pray.c \ priest.c quest.c questpgr.c read.c rect.c region.c report.c restore.c \ - rip.c rnd.c role.c rumors.c save.c selvar.c sfstruct.c \ + rip.c rnd.c role.c rumors.c save.c selvar.c sfbase.c sfstruct.c \ shk.c shknam.c sit.c sounds.c sp_lev.c spell.c stairs.c steal.c steed.c \ strutil.c symbols.c sys.c teleport.c \ timeout.c topten.c track.c trap.c u_init.c utf8map.c \ @@ -561,14 +561,15 @@ CSOURCES = $(HACKCSRC) $(HACKLIBSRC) $(SYSCSRC) $(WINCSRC) $(CHAINSRC) $(GENCSRC # HACKINCL = align.h artifact.h artilist.h attrib.h botl.h \ color.h config.h config1.h context.h coord.h cstd.h decl.h \ - display.h dlb.h dungeon.h engrave.h extern.h flag.h fnamesiz.h \ - func_tab.h global.h warnings.h hack.h lint.h mextra.h mfndpos.h \ - micro.h mkroom.h monattk.h mondata.h monflag.h monst.h monsters.h \ - nhmd4.h obj.h objects.h objclass.h optlist.h patchlevel.h \ - pcconf.h permonst.h prop.h rect.h region.h selvar.h sym.h defsym.h \ - rm.h sp_lev.h spell.h sndprocs.h seffects.h stairs.h sys.h tcap.h \ - timeout.h tradstdc.h trap.h unixconf.h vision.h vmsconf.h wintty.h \ - wincurs.h winX.h winprocs.h wintype.h you.h youprop.h weight.h + defsym.h display.h dlb.h dungeon.h engrave.h extern.h flag.h \ + fnamesiz.h func_tab.h global.h warnings.h hack.h lint.h mextra.h \ + micro.h mfndpos.h mkroom.h monattk.h mondata.h monflag.h monst.h \ + monsters.h nhmd4.h obj.h objects.h objclass.h optlist.h patchlevel.h \ + pcconf.h permonst.h prop.h rect.h region.h savefile.h selvar.h sym.h \ + rm.h sp_lev.h spell.h sndprocs.h seffects.h stairs.h sys.h \ + tcap.h timeout.h tradstdc.h trap.h unixconf.h vision.h vmsconf.h \ + wintty.h wincurs.h winX.h winprocs.h wintype.h you.h youprop.h \ + weight.h HSOURCES = $(HACKINCL) dgn_file.h @@ -610,7 +611,7 @@ HOBJ = $(TARGETPFX)allmain.o $(TARGETPFX)alloc.o \ $(TARGETPFX)rect.o $(TARGETPFX)region.o $(TARGETPFX)report.o \ $(TARGETPFX)restore.o $(TARGETPFX)rip.o $(TARGETPFX)rnd.o \ $(TARGETPFX)role.o $(TARGETPFX)rumors.o $(TARGETPFX)save.o \ - $(TARGETPFX)selvar.o $(TARGETPFX)sfstruct.o \ + $(TARGETPFX)selvar.o $(TARGETPFX)sfbase.o $(TARGETPFX)sfstruct.o \ $(TARGETPFX)shk.o $(TARGETPFX)shknam.o $(TARGETPFX)sit.o \ $(TARGETPFX)sounds.o $(TARGETPFX)sp_lev.o $(TARGETPFX)spell.o \ $(TARGETPFX)stairs.o $(TARGETPFX)symbols.o $(TARGETPFX)sys.o \ @@ -760,7 +761,7 @@ hacklib.a: hacklib.o ../win/gnome/gn_rip.h: ../win/X11/rip.xpm cp ../win/X11/rip.xpm ../win/gnome/gn_rip.h -$(TARGETPFX)sfstruct.o: sfstruct.c $(HACK_H) +$(TARGETPFX)sfbase.o: sfbase.c $(HACK_H) ../include/sfprocs.h # date.c should be recompiled any time any of the source or include code # is modified. @@ -1232,7 +1233,7 @@ $(TARGETPFX)role.o: role.c $(HACK_H) $(TARGETPFX)rumors.o: rumors.c $(HACK_H) ../include/dlb.h $(TARGETPFX)save.o: save.c $(HACK_H) $(TARGETPFX)selvar.o: selvar.c $(HACK_H) ../include/sp_lev.h -$(TARGETPFX)sfstruct.o: sfstruct.c $(HACK_H) +$(TARGETPFX)sfstruct.o: sfstruct.c $(HACK_H) ../include/sfprocs.h $(TARGETPFX)shk.o: shk.c $(HACK_H) $(TARGETPFX)shknam.o: shknam.c $(HACK_H) $(TARGETPFX)sit.o: sit.c $(HACK_H) ../include/artifact.h diff --git a/sys/unix/Makefile.utl b/sys/unix/Makefile.utl index c63caea3b..11a50aa1b 100644 --- a/sys/unix/Makefile.utl +++ b/sys/unix/Makefile.utl @@ -168,6 +168,7 @@ AT_V1 := @ AT = $(AT_V$(QUIETCC)) # Verbosity, end +GAME=nethack # timestamps for primary header files, matching src/Makefile CONFIG_H = ../src/config.h-t HACK_H = ../src/hack.h-t @@ -220,6 +221,7 @@ TARGET_CXX = $(CXX) TARGET_CXXFLAGS = $(CXXFLAGS) TARGET_AR = $(AR) +# # dependencies for makedefs # makedefs: $(HACKLIB) $(MAKEOBJS) mdgrep.h diff --git a/sys/vms/Makefile.src b/sys/vms/Makefile.src index f2efc62bb..dee166f8e 100644 --- a/sys/vms/Makefile.src +++ b/sys/vms/Makefile.src @@ -174,15 +174,18 @@ VERSOURCES = $(HACKCSRC) $(SYSSRC) $(WINSRC) $(RANDSRC) $(GENCSRC) # all .h files except date.h which would # cause dependency loops if run through "make depend" # -HACKINCL = align.h artifact.h artilist.h attrib.h color.h \ - config.h config1.h context.h coord.h decl.h defsym.h display.h \ - dlb.h dungeon.h engrave.h extern.h flag.h func_tab.h global.h \ - hack.h hacklib.h mextra.h mfndpos.h micro.h mkroom.h \ - monattk.h mondata.h monflag.h monst.h sym.h obj.h objclass.h \ - patchlevel.h pcconf.h permonst.h prop.h rect.h \ - region.h sym.h defsym.h rm.h sp_lev.h spell.h sys.h system.h \ - tcap.h timeout.h tradstdc.h trap.h unixconf.h vision.h \ - vmsconf.h wintty.h winX.h winprocs.h wintype.h you.h youprop.h +HACKINCL = align.h artifact.h artilist.h attrib.h botl.h \ + color.h config.h config1.h context.h coord.h cstd.h decl.h \ + defsym.h display.h dlb.h dungeon.h engrave.h extern.h flag.h \ + fnamesiz.h func_tab.h global.h warnings.h hack.h lint.h mextra.h \ + micro.h mkroom.h monattk.h mondata.h monflag.h monst.h monsters.h \ + mfndpos.h nhmd4.h obj.h objects.h objclass.h optlist.h patchlevel.h \ + pcconf.h permonst.h prop.h rect.h region.h savefile.h selvar.h sym.h \ + rm.h sp_lev.h spell.h sndprocs.h seffects.h stairs.h sys.h \ + tcap.h timeout.h tradstdc.h trap.h unixconf.h vision.h vmsconf.h \ + wintty.h wincurs.h winX.h winprocs.h wintype.h you.h youprop.h \ + weight.h + #HSOURCES = $(HACKINCL) date.h onames.h pm.h diff --git a/sys/windows/Makefile.nmake b/sys/windows/Makefile.nmake index 14273dd61..10c35a454 100644 --- a/sys/windows/Makefile.nmake +++ b/sys/windows/Makefile.nmake @@ -665,7 +665,7 @@ HACKCSRC = \ $(SRC)potion.c $(SRC)pray.c $(SRC)priest.c $(SRC)quest.c \ $(SRC)questpgr.c $(SRC)read.c $(SRC)rect.c $(SRC)region.c \ $(SRC)restore.c $(SRC)rip.c $(SRC)rnd.c $(SRC)role.c \ - $(SRC)rumors.c $(SRC)save.c $(SRC)selvar.c $(SRC)sfstruct.c \ + $(SRC)rumors.c $(SRC)save.c $(SRC)selvar.c $(SRC)sfstruct.c sfbase.c \ $(SRC)shk.c $(SRC)shknam.c $(SRC)sit.c $(SRC)sounds.c \ $(SRC)sp_lev.c $(SRC)spell.c $(SRC)stairs.c $(SRC)steal.c \ $(SRC)steed.c $(SRC)symbols.c $(SRC)sys.c $(SRC)teleport.c \ @@ -677,29 +677,30 @@ HACKCSRC = \ # all .h files except date.h HACKINCL = \ - $(INCL)align.h $(INCL)artifact.h $(INCL)artilist.h \ - $(INCL)attrib.h $(INCL)botl.h $(INCL)color.h \ - $(INCL)config.h $(INCL)config1.h $(INCL)context.h \ - $(INCL)coord.h $(INCL)cstd.h $(INCL)decl.h \ - $(INCL)display.h $(INCL)dlb.h $(INCL)dungeon.h \ - $(INCL)engrave.h $(INCL)extern.h $(INCL)flag.h \ - $(INCL)fnamesiz.h $(INCL)func_tab.h $(INCL)global.h \ - $(INCL)warnings.h $(INCL)hack.h $(INCL)lint.h \ - $(INCL)mextra.h $(INCL)mfndpos.h $(INCL)micro.h \ - $(INCL)mkroom.h $(INCL)monattk.h $(INCL)mondata.h \ - $(INCL)monflag.h $(INCL)monst.h $(INCL)monsters.h \ - $(INCL)nhmd4.h $(INCL)obj.h $(INCL)objects.h \ - $(INCL)objclass.h $(INCL)optlist.h $(INCL)patchlevel.h \ - $(INCL)pcconf.h $(INCL)permonst.h $(INCL)prop.h \ - $(INCL)rect.h $(INCL)region.h $(INCL)selvar.h \ - $(INCL)sym.h $(INCL)defsym.h $(INCL)rm.h \ - $(INCL)sp_lev.h $(INCL)spell.h $(INCL)sndprocs.h \ - $(INCL)seffects.h $(INCL)stairs.h $(INCL)sys.h \ - $(INCL)tcap.h $(INCL)timeout.h $(INCL)tradstdc.h \ - $(INCL)trap.h $(INCL)unixconf.h $(INCL)vision.h \ - $(INCL)vmsconf.h $(INCL)wintty.h $(INCL)wincurs.h \ - $(INCL)winX.h $(INCL)winprocs.h $(INCL)wintype.h \ - $(INCL)you.h $(INCL)youprop.h + $(INCL)align.h $(INCL)artifact.h $(INCL)artilist.h \ + $(INCL)attrib.h $(INCL)botl.h $(INCL)color.h \ + $(INCL)config.h $(INCL)config1.h $(INCL)context.h \ + $(INCL)coord.h $(INCL)cstd.h $(INCL)decl.h \ + $(INCL)defsym.h $(INCL)display.h $(INCL)dlb.h \ + $(INCL)dungeon.h $(INCL)engrave.h $(INCL)extern.h \ + $(INCL)flag.h $(INCL)fnamesiz.h $(INCL)func_tab.h \ + $(INCL)global.h $(INCL)warnings.h $(INCL)hack.h \ + $(INCL)lint.h $(INCL)mextra.h $(INCL)micro.h \ + $(INCL)mfndpos.h $(INCL)mkroom.h $(INCL)monattk.h \ + $(INCL)mondata.h $(INCL)monflag.h $(INCL)monst.h \ + $(INCL)monsters.h $(INCL)nhmd4.h $(INCL)obj.h \ + $(INCL)objects.h $(INCL)objclass.h $(INCL)optlist.h \ + $(INCL)patchlevel.h $(INCL)pcconf.h $(INCL)permonst.h \ + $(INCL)prop.h $(INCL)rect.h $(INCL)region.h \ + $(INCL)savefile.h $(INCL)selvar.h $(INCL)sym.h \ + $(INCL)rm.h $(INCL)sp_lev.h $(INCL)spell.h \ + $(INCL)sndprocs.h $(INCL)seffects.h $(INCL)stairs.h \ + $(INCL)sys.h $(INCL)tcap.h $(INCL)timeout.h \ + $(INCL)tradstdc.h $(INCL)trap.h $(INCL)unixconf.h \ + $(INCL)vision.h $(INCL)vmsconf.h $(INCL)wintty.h \ + $(INCL)wincurs.h $(INCL)winX.h $(INCL)winprocs.h \ + $(INCL)wintype.h $(INCL)you.h $(INCL)youprop.h \ + $(INCL)weight.h LUA_FILES = $(DAT)asmodeus.lua $(DAT)baalz.lua $(DAT)bigrm-1.lua \ $(DAT)bigrm-10.lua $(DAT)bigrm-11.lua $(DAT)bigrm-12.lua \ @@ -873,7 +874,7 @@ COREOBJTTY = \ $(OTTY)uhitm.o $(OTTY)utf8map.o $(OTTY)vault.o $(OTTY)vision.o \ $(OTTY)weapon.o $(OTTY)were.o $(OTTY)wield.o $(OTTY)windows.o \ $(OTTY)wizard.o $(OTTY)wizcmds.o $(OTTY)worm.o $(OTTY)worn.o \ - $(OTTY)write.o $(OTTY)zap.o + $(OTTY)write.o $(OTTY)zap.o $(OTTY)sfbase.o OBJSTTY = $(MDLIBTTY) $(COREOBJTTY) $(REGEXTTY) $(RANDOMTTY) @@ -936,7 +937,7 @@ COREOBJGUI = \ $(OGUI)uhitm.o $(OGUI)utf8map.o $(OGUI)vault.o $(OGUI)vision.o \ $(OGUI)weapon.o $(OGUI)were.o $(OGUI)wield.o $(OGUI)windows.o \ $(OGUI)wizard.o $(OGUI)wizcmds.o $(OGUI)worm.o $(OGUI)worn.o \ - $(OGUI)write.o $(OGUI)zap.o + $(OGUI)write.o $(OGUI)zap.o $(OGUI)sfbase.o OBJSGUI = $(MDLIBGUI) $(COREOBJGUI) $(REGEXGUI) $(RANDOMGUI) @@ -1458,6 +1459,8 @@ DLB = #========================================== {$(R_UTIL)}.c{$(R_OBJUTIL)}.o: + echo R_UTIL=$(R_UTIL) + echo R_OBJUTIL=$(R_OBJUTIL) $(Q)$(CC) $(CFLAGS) -Fo$@ $< #========================================== @@ -1864,6 +1867,14 @@ $(OGUI)date.o: $(HACKINCL) $(HACKSRC) $(HACKOBJ) $(ALLOBJGUI) @$(MAKE) /NOLOGO /A -f date.nmk !ENDIF +$(OGUI)sfbase.o: sfbase.c $(HACK_H) + $(Q)$(CC) $(CFLAGS) /EP $(@B).c > $(OGUI)$(@B).c.preproc + $(Q)$(CC) $(CFLAGS) -Fo$@ $(@B).c + +$(OTTY)sfbase.o: sfbase.c $(HACK_H) + $(Q)$(CC) $(CFLAGS) /EP $(@B).c > $(OTTY)$(@B).c.preproc + $(Q)$(CC) $(CFLAGS) -Fo$@ $(@B).c + # # date.h is not used with NetHack 3.7 # onames.h is not used with NetHack 3.7 @@ -3069,6 +3080,8 @@ $(OTTY)rumors.o: rumors.c $(HACK_H) $(INCL)dlb.h $(OTTY)save.o: save.c $(HACK_H) $(OTTY)selvar.o: selvar.c $(HACK_H) $(INCL)sp_lev.h $(OTTY)sfstruct.o: sfstruct.c $(HACK_H) + $(Q)$(CC) $(CFLAGS) /EP $(@B).c > $(OTTY)$(@B).c.preproc + $(Q)$(CC) $(CFLAGS) -Fo$@ $(@B).c $(OTTY)shk.o: shk.c $(HACK_H) $(OTTY)shknam.o: shknam.c $(HACK_H) $(OTTY)sit.o: sit.c $(HACK_H) $(INCL)artifact.h @@ -3445,6 +3458,8 @@ $(OGUI)rumors.o: rumors.c $(HACK_H) $(INCL)dlb.h $(OGUI)save.o: save.c $(HACK_H) $(OGUI)selvar.o: selvar.c $(HACK_H) $(INCL)sp_lev.h $(OGUI)sfstruct.o: sfstruct.c $(HACK_H) + $(Q)$(CC) $(CFLAGS) /EP $(@B).c > $(OGUI)$(@B).c.preproc + $(Q)$(CC) $(CFLAGS) -Fo$@ $(@B).c $(OGUI)shk.o: shk.c $(HACK_H) $(OGUI)shknam.o: shknam.c $(HACK_H) $(OGUI)sit.o: sit.c $(HACK_H) $(INCL)artifact.h diff --git a/sys/windows/vs/NetHack/NetHack.vcxproj b/sys/windows/vs/NetHack/NetHack.vcxproj index 7dfa0cf6b..bdc5d771f 100644 --- a/sys/windows/vs/NetHack/NetHack.vcxproj +++ b/sys/windows/vs/NetHack/NetHack.vcxproj @@ -220,6 +220,7 @@ + @@ -294,6 +295,8 @@ + + @@ -314,4 +317,4 @@ - + \ No newline at end of file diff --git a/sys/windows/vs/NetHackW/NetHackW.vcxproj b/sys/windows/vs/NetHackW/NetHackW.vcxproj index 78a43906d..5ba44b3dc 100644 --- a/sys/windows/vs/NetHackW/NetHackW.vcxproj +++ b/sys/windows/vs/NetHackW/NetHackW.vcxproj @@ -252,6 +252,7 @@ + @@ -353,6 +354,8 @@ + + @@ -376,4 +379,4 @@ - + \ No newline at end of file diff --git a/sys/windows/windmain.c b/sys/windows/windmain.c index 04b4668ac..a2fe2da5e 100644 --- a/sys/windows/windmain.c +++ b/sys/windows/windmain.c @@ -366,6 +366,9 @@ _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);*/ nethack_exit(EXIT_SUCCESS); if (getlock_result < 0) { + if (program_state.in_self_recover) { + program_state.in_self_recover = FALSE; + } set_savefile_name(TRUE); } /* Set up level 0 file to keep the game state. diff --git a/sys/windows/windsys.c b/sys/windows/windsys.c index ea425ce26..d7178cffa 100644 --- a/sys/windows/windsys.c +++ b/sys/windows/windsys.c @@ -505,20 +505,6 @@ get_port_id(char *buf) extern void free_winmain_stuff(void); #endif -/* return TRUE if s contains a directory, not just a filespec */ -boolean -contains_directory(const char *s) -{ - int i, slen = strlen(s); - const char *cp = s; - - for (i = 0; i < slen; ++i) { - if (*cp == '\\' || *cp == '/' || *cp == ':') - return TRUE; - } - return FALSE; -} - void nethack_exit(int code) { diff --git a/util/.gitignore b/util/.gitignore index 56d768999..11fa8a1f0 100644 --- a/util/.gitignore +++ b/util/.gitignore @@ -30,4 +30,5 @@ heaputil heaputil.c tilemappings.lst clang_rt.asan*.dll +*.sln diff --git a/util/recover.c b/util/recover.c index 07481cbc5..f43d1132c 100644 --- a/util/recover.c +++ b/util/recover.c @@ -12,9 +12,16 @@ #include "win32api.h" #endif +#define RECOVER_C + #include "config.h" #include "hacklib.h" +#include "artifact.h" +#include "rect.h" +#include "dungeon.h" +#include "hack.h" + #if !defined(O_WRONLY) && !defined(LSC) && !defined(AZTEC_C) #include #endif @@ -267,10 +274,12 @@ restore_savefile(char *basename) } /* save file should contain: - * format indicator and cmc + * format indicator (1 byte) + * n = count of critical size list (1 byte) + * n bytes of critical sizes (n bytes) * version info - * savefile info - * player name + * plnametmp = player name size (int, 2 bytes) + * player name (PL_NSIZ_PLUS) * current level (including pets) * (non-level-based) game state * other levels From 2cf7acc93b0076914bd915e669bbd2af83a45456 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 25 May 2025 15:37:46 -0400 Subject: [PATCH 641/791] Windows Makefile follow-up --- sys/windows/GNUmakefile | 2 +- sys/windows/Makefile.nmake | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/sys/windows/GNUmakefile b/sys/windows/GNUmakefile index 21c6e0d74..3253e195e 100644 --- a/sys/windows/GNUmakefile +++ b/sys/windows/GNUmakefile @@ -1010,7 +1010,7 @@ COREOBJS = $(addsuffix .o, allmain alloc apply artifact attrib ball bones botl \ nhlobj nhlsel nhlua windsound o_init objects objnam options \ pager pickup pline polyself potion pray priest quest questpgr \ random read rect region report restore rip rnd role rumors \ - safeproc save sfstruct shk shknam sit selvar sounds sp_lev \ + safeproc save sfbase sfstruct shk shknam sit selvar sounds sp_lev \ spell stairs steal steed strutil \ symbols sys teleport timeout topten track trap u_init uhitm utf8map \ vault version vision weapon were wield windmain windows windsys wizard \ diff --git a/sys/windows/Makefile.nmake b/sys/windows/Makefile.nmake index 10c35a454..c3daf54df 100644 --- a/sys/windows/Makefile.nmake +++ b/sys/windows/Makefile.nmake @@ -692,15 +692,15 @@ HACKINCL = \ $(INCL)objects.h $(INCL)objclass.h $(INCL)optlist.h \ $(INCL)patchlevel.h $(INCL)pcconf.h $(INCL)permonst.h \ $(INCL)prop.h $(INCL)rect.h $(INCL)region.h \ - $(INCL)savefile.h $(INCL)selvar.h $(INCL)sym.h \ - $(INCL)rm.h $(INCL)sp_lev.h $(INCL)spell.h \ - $(INCL)sndprocs.h $(INCL)seffects.h $(INCL)stairs.h \ - $(INCL)sys.h $(INCL)tcap.h $(INCL)timeout.h \ - $(INCL)tradstdc.h $(INCL)trap.h $(INCL)unixconf.h \ - $(INCL)vision.h $(INCL)vmsconf.h $(INCL)wintty.h \ - $(INCL)wincurs.h $(INCL)winX.h $(INCL)winprocs.h \ - $(INCL)wintype.h $(INCL)you.h $(INCL)youprop.h \ - $(INCL)weight.h + $(INCL)savefile.h $(INCL)selvar.h $(INCL)sfprocs.h \ + $(INCL)sym.h $(INCL)rm.h $(INCL)sp_lev.h \ + $(INCL)spell.h $(INCL)sndprocs.h $(INCL)seffects.h \ + $(INCL)stairs.h $(INCL)sys.h $(INCL)tcap.h \ + $(INCL)timeout.h $(INCL)tradstdc.h $(INCL)trap.h \ + $(INCL)unixconf.h $(INCL)vision.h $(INCL)vmsconf.h \ + $(INCL)wintty.h $(INCL)wincurs.h $(INCL)winX.h \ + $(INCL)winprocs.h $(INCL)wintype.h $(INCL)you.h \ + $(INCL)youprop.h $(INCL)weight.h LUA_FILES = $(DAT)asmodeus.lua $(DAT)baalz.lua $(DAT)bigrm-1.lua \ $(DAT)bigrm-10.lua $(DAT)bigrm-11.lua $(DAT)bigrm-12.lua \ From e74793597569d36c4ce40f5f526568f34aadded1 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 25 May 2025 15:43:14 -0400 Subject: [PATCH 642/791] msdos build fix --- sys/share/pcmain.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sys/share/pcmain.c b/sys/share/pcmain.c index 4093eff48..8850e2d82 100644 --- a/sys/share/pcmain.c +++ b/sys/share/pcmain.c @@ -7,7 +7,6 @@ #include "hack.h" #include "dlb.h" -#include "sfproto.h" #ifndef NO_SIGNAL #include From b036f1a3d9f26353f902148b521190f420fff168 Mon Sep 17 00:00:00 2001 From: nhw_cron Date: Sun, 25 May 2025 15:24:10 -0400 Subject: [PATCH 643/791] This is cron-daily v1-Apr-1-2024. 000files updated: Files --- Files | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/Files b/Files index f76653997..d9bc79d18 100644 --- a/Files +++ b/Files @@ -97,12 +97,12 @@ mfndpos.h micro.h mkroom.h monattk.h mondata.h monflag.h monst.h monsters.h nhmd4.h nhregex.h obj.h objclass.h objects.h optlist.h patchlevel.h pcconf.h permonst.h prop.h quest.h rect.h -region.h rm.h seffects.h selvar.h skills.h -sndprocs.h sp_lev.h spell.h stairs.h sym.h -sys.h tcap.h tileset.h timeout.h tradstdc.h -trap.h unixconf.h vision.h vmsconf.h warnings.h -weight.h winami.h wincurs.h windconf.h winprocs.h -wintype.h you.h youprop.h +region.h rm.h savefile.h seffects.h selvar.h +sfprocs.h skills.h sndprocs.h sp_lev.h spell.h +stairs.h sym.h sys.h tcap.h tileset.h +timeout.h tradstdc.h trap.h unixconf.h vision.h +vmsconf.h warnings.h weight.h winami.h wincurs.h +windconf.h winprocs.h wintype.h you.h youprop.h (file for tty versions) wintty.h @@ -306,13 +306,13 @@ nhlsel.c nhlua.c nhmd4.c o_init.c objects.c objnam.c options.c pager.c pickup.c pline.c polyself.c potion.c pray.c priest.c quest.c questpgr.c read.c rect.c region.c report.c restore.c rip.c rnd.c role.c -rumors.c save.c selvar.c sfstruct.c shk.c shknam.c -sit.c sounds.c sp_lev.c spell.c stairs.c steal.c -steed.c strutil.c symbols.c sys.c teleport.c timeout.c -topten.c track.c trap.c u_init.c uhitm.c utf8map.c -vault.c version.c vision.c weapon.c were.c wield.c -windows.c wizard.c wizcmds.c worm.c worn.c write.c -zap.c +rumors.c save.c selvar.c sfbase.c sfstruct.c shk.c +shknam.c sit.c sounds.c sp_lev.c spell.c stairs.c +steal.c steed.c strutil.c symbols.c sys.c teleport.c +timeout.c topten.c track.c trap.c u_init.c uhitm.c +utf8map.c vault.c version.c vision.c weapon.c were.c +wield.c windows.c wizard.c wizcmds.c worm.c worn.c +write.c zap.c submodules: (files in top directory) From 82fd29c429ea4eaa3247fbba9e440d0e80299d8a Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 25 May 2025 15:47:05 -0400 Subject: [PATCH 644/791] cron update --- doc/Guidebook.txt | 3602 +++++++++++++++++++++++---------------------- 1 file changed, 1834 insertions(+), 1768 deletions(-) diff --git a/doc/Guidebook.txt b/doc/Guidebook.txt index 73e12bdb0..e36569992 100644 --- a/doc/Guidebook.txt +++ b/doc/Guidebook.txt @@ -15,7 +15,7 @@ Original version - Eric S. Raymond (Edited and expanded for NetHack 3.7.0 by Mike Stephenson and others) - December 25, 2024 + May 1, 2025 @@ -126,7 +126,7 @@ - NetHack 3.7.0 December 25, 2024 + NetHack 3.7.0 May 1, 2025 @@ -192,7 +192,7 @@ NetHack continues this fine tradition. Unlike text adventure games - NetHack 3.7.0 December 25, 2024 + NetHack 3.7.0 May 1, 2025 @@ -258,7 +258,7 @@ - NetHack 3.7.0 December 25, 2024 + NetHack 3.7.0 May 1, 2025 @@ -324,7 +324,7 @@ - NetHack 3.7.0 December 25, 2024 + NetHack 3.7.0 May 1, 2025 @@ -390,7 +390,7 @@ - NetHack 3.7.0 December 25, 2024 + NetHack 3.7.0 May 1, 2025 @@ -456,7 +456,7 @@ The number of turns elapsed so far, displayed if you have the - NetHack 3.7.0 December 25, 2024 + NetHack 3.7.0 May 1, 2025 @@ -522,7 +522,7 @@ - NetHack 3.7.0 December 25, 2024 + NetHack 3.7.0 May 1, 2025 @@ -588,7 +588,7 @@ - NetHack 3.7.0 December 25, 2024 + NetHack 3.7.0 May 1, 2025 @@ -654,7 +654,7 @@ - NetHack 3.7.0 December 25, 2024 + NetHack 3.7.0 May 1, 2025 @@ -720,7 +720,7 @@ instead. Only these one-step movement commands cause you to - NetHack 3.7.0 December 25, 2024 + NetHack 3.7.0 May 1, 2025 @@ -786,7 +786,7 @@ ing . ^ is used as shorthand elsewhere in the - NetHack 3.7.0 December 25, 2024 + NetHack 3.7.0 May 1, 2025 @@ -852,7 +852,7 @@ - NetHack 3.7.0 December 25, 2024 + NetHack 3.7.0 May 1, 2025 @@ -918,7 +918,7 @@ - NetHack 3.7.0 December 25, 2024 + NetHack 3.7.0 May 1, 2025 @@ -984,7 +984,7 @@ - NetHack 3.7.0 December 25, 2024 + NetHack 3.7.0 May 1, 2025 @@ -1050,7 +1050,7 @@ at an adjacent "remembered, unseen monster" marker. - NetHack 3.7.0 December 25, 2024 + NetHack 3.7.0 May 1, 2025 @@ -1116,7 +1116,7 @@ - NetHack 3.7.0 December 25, 2024 + NetHack 3.7.0 May 1, 2025 @@ -1182,7 +1182,7 @@ (R)UNIX is a registered trademark of The Open Group. - NetHack 3.7.0 December 25, 2024 + NetHack 3.7.0 May 1, 2025 @@ -1248,7 +1248,7 @@ menu_next_page, and menu_last_page keys (`^', `<', `>', `|' by - NetHack 3.7.0 December 25, 2024 + NetHack 3.7.0 May 1, 2025 @@ -1314,7 +1314,7 @@ doesn't and give that name to the result, while splitting (count - NetHack 3.7.0 December 25, 2024 + NetHack 3.7.0 May 1, 2025 @@ -1380,7 +1380,7 @@ - NetHack 3.7.0 December 25, 2024 + NetHack 3.7.0 May 1, 2025 @@ -1446,7 +1446,7 @@ extinct. - NetHack 3.7.0 December 25, 2024 + NetHack 3.7.0 May 1, 2025 @@ -1512,7 +1512,7 @@ - NetHack 3.7.0 December 25, 2024 + NetHack 3.7.0 May 1, 2025 @@ -1578,7 +1578,7 @@ - NetHack 3.7.0 December 25, 2024 + NetHack 3.7.0 May 1, 2025 @@ -1644,7 +1644,7 @@ right away.) Since using this command by accident can cause - NetHack 3.7.0 December 25, 2024 + NetHack 3.7.0 May 1, 2025 @@ -1710,7 +1710,7 @@ Default key is `M-R'. - NetHack 3.7.0 December 25, 2024 + NetHack 3.7.0 May 1, 2025 @@ -1776,7 +1776,7 @@ (worn blindfold or towel or lenses, lit lamp(s) and/or candle(s), - NetHack 3.7.0 December 25, 2024 + NetHack 3.7.0 May 1, 2025 @@ -1842,7 +1842,7 @@ - NetHack 3.7.0 December 25, 2024 + NetHack 3.7.0 May 1, 2025 @@ -1908,7 +1908,7 @@ line will show "(no travel path)" if your character does not know - NetHack 3.7.0 December 25, 2024 + NetHack 3.7.0 May 1, 2025 @@ -1974,7 +1974,7 @@ - NetHack 3.7.0 December 25, 2024 + NetHack 3.7.0 May 1, 2025 @@ -2040,7 +2040,7 @@ Set one or more intrinsic attributes. Autocompletes. Debug mode - NetHack 3.7.0 December 25, 2024 + NetHack 3.7.0 May 1, 2025 @@ -2106,7 +2106,7 @@ "high"] bit), you can invoke many extended commands by meta-ing the - NetHack 3.7.0 December 25, 2024 + NetHack 3.7.0 May 1, 2025 @@ -2172,7 +2172,7 @@ - NetHack 3.7.0 December 25, 2024 + NetHack 3.7.0 May 1, 2025 @@ -2238,7 +2238,7 @@ - NetHack 3.7.0 December 25, 2024 + NetHack 3.7.0 May 1, 2025 @@ -2304,7 +2304,7 @@ - NetHack 3.7.0 December 25, 2024 + NetHack 3.7.0 May 1, 2025 @@ -2370,7 +2370,7 @@ them). Some monsters who can open doors can also use unlocking tools. - NetHack 3.7.0 December 25, 2024 + NetHack 3.7.0 May 1, 2025 @@ -2436,7 +2436,7 @@ been nullified, giving access to whatever is beyond them. In the - NetHack 3.7.0 December 25, 2024 + NetHack 3.7.0 May 1, 2025 @@ -2502,7 +2502,7 @@ play. - NetHack 3.7.0 December 25, 2024 + NetHack 3.7.0 May 1, 2025 @@ -2568,7 +2568,7 @@ - NetHack 3.7.0 December 25, 2024 + NetHack 3.7.0 May 1, 2025 @@ -2634,7 +2634,7 @@ attack, when guessing where an unseen monster is or when deliberately - NetHack 3.7.0 December 25, 2024 + NetHack 3.7.0 May 1, 2025 @@ -2700,7 +2700,7 @@ noid_confirmation:attack option to require a response of "yes" - NetHack 3.7.0 December 25, 2024 + NetHack 3.7.0 May 1, 2025 @@ -2766,7 +2766,7 @@ - NetHack 3.7.0 December 25, 2024 + NetHack 3.7.0 May 1, 2025 @@ -2832,7 +2832,7 @@ are encumbered, one of the conditions Burdened, Stressed, Strained, - NetHack 3.7.0 December 25, 2024 + NetHack 3.7.0 May 1, 2025 @@ -2898,7 +2898,7 @@ - NetHack 3.7.0 December 25, 2024 + NetHack 3.7.0 May 1, 2025 @@ -2964,7 +2964,7 @@ `X' command to engage or disengage that. Only some types of charac- - NetHack 3.7.0 December 25, 2024 + NetHack 3.7.0 May 1, 2025 @@ -3030,7 +3030,7 @@ - NetHack 3.7.0 December 25, 2024 + NetHack 3.7.0 May 1, 2025 @@ -3096,7 +3096,7 @@ you'll be told that you feel more confident in your skills. At that - NetHack 3.7.0 December 25, 2024 + NetHack 3.7.0 May 1, 2025 @@ -3162,7 +3162,7 @@ - NetHack 3.7.0 December 25, 2024 + NetHack 3.7.0 May 1, 2025 @@ -3228,7 +3228,7 @@ what you eat." - NetHack 3.7.0 December 25, 2024 + NetHack 3.7.0 May 1, 2025 @@ -3259,6 +3259,14 @@ or blessed, and how many uses it has left. Some objects of subtle enchantment are difficult to identify without these. + A scroll whose label is known can be read even when the hero is + blind. If a scroll has been discovered, it will be listed in inven- + tory by type rather than by label, but the label is known in that + situtaion even though it isn't shown. + + Many scrolls produce a different effect from usual if they are + blessed or cursed, or read while the hero is confused. + A mail daemon may run up and deliver mail to you as a scroll of mail (on versions compiled with this feature). To use this feature on versions where NetHack mail delivery is triggered by electronic mail @@ -3284,17 +3292,9 @@ at them. It is also sometimes very useful to dip ("#dip") an object into a potion. - The command to drink a potion is `q' (quaff). - - 7.7. Wands (`/') - - Wands usually have multiple magical charges. Some types of wands - require a direction in which to zap them. You can also zap them at - yourself (just give a `.' or `s' for the direction). Be warned, how- - ever, for this is often unwise. Other types of wands don't require a - NetHack 3.7.0 December 25, 2024 + NetHack 3.7.0 May 1, 2025 @@ -3304,6 +3304,14 @@ + The command to drink a potion is `q' (quaff). + + 7.7. Wands (`/') + + Wands usually have multiple magical charges. Some types of wands + require a direction in which to zap them. You can also zap them at + yourself (just give a `.' or `s' for the direction). Be warned, how- + ever, for this is often unwise. Other types of wands don't require a direction. The number of charges in a wand is random and decreases by one whenever you use it. @@ -3350,17 +3358,9 @@ The commands to use rings are `P' (put on) and `R' (remove). `A', `W', and `T' can also be used; see Amulets. - 7.9. Spellbooks (`+') - - Spellbooks are tomes of mighty magic. When studied with the `r' - (read) command, they transfer to the reader the knowledge of a spell - (and therefore eventually become unreadable)--unless the attempt back- - fires. Reading a cursed spellbook or one with mystic runes beyond - your ken can be harmful to your health! - - NetHack 3.7.0 December 25, 2024 + NetHack 3.7.0 May 1, 2025 @@ -3370,6 +3370,14 @@ + 7.9. Spellbooks (`+') + + Spellbooks are tomes of mighty magic. When studied with the `r' + (read) command, they transfer to the reader the knowledge of a spell + (and therefore eventually become unreadable)--unless the attempt back- + fires. Reading a cursed spellbook or one with mystic runes beyond + your ken can be harmful to your health! + A spell (even when learned) can also backfire when you cast it. If you attempt to cast a spell well above your experience level, or if you have little skill with the appropriate spell type, or cast it at a @@ -3416,17 +3424,9 @@ ple, lamps burn out after a while. Other tools are containers, which objects can be placed into or taken out of. - Some tools (such as a blindfold) can be worn and can be put on - and removed like other accessories (rings, amulets); see Amulets. - Other tools (such as pick-axe) can be wielded as weapons in addition - to being applied for their usual purpose, and in some cases (again, - pick-axe) become wielded as a weapon even when applied. - - The blind option can be set (prior to game start) to attempt to - play the entire game without being able to see (a self-imposed chal- - NetHack 3.7.0 December 25, 2024 + NetHack 3.7.0 May 1, 2025 @@ -3436,6 +3436,14 @@ + Some tools (such as a blindfold) can be worn and can be put on + and removed like other accessories (rings, amulets); see Amulets. + Other tools (such as pick-axe) can be wielded as weapons in addition + to being applied for their usual purpose, and in some cases (again, + pick-axe) become wielded as a weapon even when applied. + + The blind option can be set (prior to game start) to attempt to + play the entire game without being able to see (a self-imposed chal- lenge which is very difficult to accomplish). The command to use a tool is `a' (apply). @@ -3479,6 +3487,21 @@ tents into another container. (As of this writing, the other con- tainer must be carried rather than on the floor.) + + + + + + NetHack 3.7.0 May 1, 2025 + + + + + + NetHack Guidebook 54 + + + 7.11. Amulets (`"') Amulets are very similar to rings, and often more powerful. Like @@ -3489,19 +3512,6 @@ wearing rings, wearing an amulet affects your metabolism, causing you to grow hungry more rapidly. - - - - NetHack 3.7.0 December 25, 2024 - - - - - - NetHack Guidebook 54 - - - The commands to use amulets are the same as for rings, `P' (put on) and `R' (remove). `A' can be used to remove various worn items including amulets. Also, `W' (wear) and `T' (take off) which are nor- @@ -3546,6 +3556,18 @@ shown as ``' but by the letter representing the monster they depict instead. + + + NetHack 3.7.0 May 1, 2025 + + + + + + NetHack Guidebook 55 + + + 7.14. Gold (`$') Gold adds to your score, and you can buy things in shops with it. @@ -3556,18 +3578,6 @@ does not apply. They're always uncursed but never described as uncursed even if you turn off the implicit_uncursed option. You can set the goldX option if you prefer to have gold pieces be treated as - - - NetHack 3.7.0 December 25, 2024 - - - - - - NetHack Guidebook 55 - - - bless/curse state unknown rather than as known to be uncursed. Only matters when you're using an object selection prompt that can filter by "BUCX" state. @@ -3613,6 +3623,17 @@ your god for help with starvation does not violate any food challenges either. + + NetHack 3.7.0 May 1, 2025 + + + + + + NetHack Guidebook 56 + + + A strict vegan diet is one which avoids any food derived from animals. The primary source of nutrition is fruits and vegetables. The corpses and tins of blobs (`b'), jellies (`j'), and fungi (`F') @@ -3623,17 +3644,6 @@ that can digest it is also considered vegan food. Note however that eating such items still counts against foodless conduct. - - NetHack 3.7.0 December 25, 2024 - - - - - - NetHack Guidebook 56 - - - Vegetarians do not eat animals; however, they are less selective about eating animal byproducts than vegans. In addition to the vegan items listed above, they may eat any kind of pudding (`P') other than @@ -3679,18 +3689,8 @@ and kick weapons; use a wand, spell, or other type of item; or fight with your hands and feet. - In NetHack, a pacifist refuses to cause the death of any other - monster (i.e. if you would get experience for the death). This is a - particularly difficult challenge, although it is still possible to - gain experience by other means. - An illiterate character does not read or write. This includes - reading a scroll, spellbook, fortune cookie message, or t-shirt; writ- - ing a scroll; or making an engraving of anything other than a single - "X" (the traditional signature of an illiterate person). Reading an - - - NetHack 3.7.0 December 25, 2024 + NetHack 3.7.0 May 1, 2025 @@ -3700,6 +3700,15 @@ + In NetHack, a pacifist refuses to cause the death of any other + monster (i.e. if you would get experience for the death). This is a + particularly difficult challenge, although it is still possible to + gain experience by other means. + + An illiterate character does not read or write. This includes + reading a scroll, spellbook, fortune cookie message, or t-shirt; writ- + ing a scroll; or making an engraving of anything other than a single + "X" (the traditional signature of an illiterate person). Reading an engraving, or any item that is absolutely necessary to win the game, is not counted against this conduct. The identity of scrolls and spellbooks (and knowledge of spells) in your starting inventory is @@ -3744,6 +3753,19 @@ to make a wish for an item, you may choose "nothing" if you want to decline. + + + + NetHack 3.7.0 May 1, 2025 + + + + + + NetHack Guidebook 58 + + + 8.1. Achievements End of game disclosure will also display various achievements @@ -3754,18 +3776,6 @@ roughly in order of difficulty and not necessarily in the order in which you might accomplish them. - - - NetHack 3.7.0 December 25, 2024 - - - - - - NetHack Guidebook 58 - - - Rank - Attained rank title Rank. Shop - Entered a shop. Temple - Entered a temple. @@ -3810,6 +3820,18 @@ to revert to lower rank(s) does not discard the corresponding achieve- ment(s). + + + NetHack 3.7.0 May 1, 2025 + + + + + + NetHack Guidebook 59 + + + There's no guaranteed Novel so the achievement to read one might not always be attainable (except perhaps by wishing). Similarly, the Big Room level is not always present. Unlike with the Novel, there's @@ -3821,17 +3843,6 @@ other instances of the same objects doesn't record the corresponding achievement. - - NetHack 3.7.0 December 25, 2024 - - - - - - NetHack Guidebook 59 - - - The Medusa achievement is recorded if she dies for any reason, even if you are not directly responsible, and only if she dies. @@ -3875,6 +3886,18 @@ "%USERPROFILE%\NetHack\". The file may not exist, but it is a normal ASCII text file can can be created with any text editor. After run- ning NetHack for the first time, you should find a default template + + + NetHack 3.7.0 May 1, 2025 + + + + + + NetHack Guidebook 60 + + + for the configuration file named ".nethackrc.template" in "%USERPROFILE%\NetHack\". If you have not created the configuration file, NetHack will create one for you using the default template file. @@ -3886,18 +3909,6 @@ Any line beginning with `[' and ending in `]' is a section marker (the closing `]' can be followed by whitespace and then an arbitrary - - - NetHack 3.7.0 December 25, 2024 - - - - - - NetHack Guidebook 60 - - - comment beginning with `#'). The text between the square brackets is the section name. Section markers are only valid after a CHOOSE directive and their names are case insensitive. Lines after a section @@ -3941,6 +3952,18 @@ The location where saved games are kept. Defaults to HACKDIR, must be writable. + + + NetHack 3.7.0 May 1, 2025 + + + + + + NetHack Guidebook 61 + + + BONESDIR The location that bones files are kept. Defaults to HACKDIR, must be writable. @@ -3953,17 +3976,6 @@ The location that a record of game aborts and self-diagnosed game problems is kept. Defaults to HACKDIR, must be writable. - - NetHack 3.7.0 December 25, 2024 - - - - - - NetHack Guidebook 61 - - - AUTOCOMPLETE Enable or disable an extended command autocompletion. Autocomple- tion has no effect for the X11 windowport. You can specify multiple @@ -4006,6 +4018,18 @@ If [] is present, the preceding section is closed and no new section begins; whatever follows will be common to all sections. Otherwise + + + NetHack 3.7.0 May 1, 2025 + + + + + + NetHack Guidebook 62 + + + the last section extends to the end of the options file. MENUCOLOR @@ -4019,17 +4043,6 @@ ROGUESYMBOLS Custom symbols for the rogue level's symbol set. See SYMBOLS below. - - NetHack 3.7.0 December 25, 2024 - - - - - - NetHack Guidebook 62 - - - SOUND Define a sound mapping. See the "Configuring User Sounds" section. @@ -4061,6 +4074,28 @@ Here is an example of configuration file contents: + + + + + + + + + + + + + NetHack 3.7.0 May 1, 2025 + + + + + + NetHack Guidebook 63 + + + # Set your character's role, race, gender, and alignment. OPTIONS=role:Valkyrie, race:Human, gender:female, align:lawful # @@ -4084,18 +4119,6 @@ The NETHACKOPTIONS variable is a comma-separated list of initial values for the various options. Some can only be turned on or off. You turn one of these on by adding the name of the option to the list, - - - NetHack 3.7.0 December 25, 2024 - - - - - - NetHack Guidebook 63 - - - and turn it off by typing a `!' or "no" before the name. Others take a character string as a value. You can set string options by typing the option name, a colon or equals sign, and then the value of the @@ -4128,6 +4151,17 @@ sign) to let NetHack know that the rest is intended as a file name. If it does start with `/', the at-sign is optional. + + NetHack 3.7.0 May 1, 2025 + + + + + + NetHack Guidebook 64 + + + 9.4. Customization options Here are explanations of what the various options do. Character @@ -4150,21 +4184,11 @@ Your starting alignment (align:lawful, align:neutral, or align:chaotic). You may specify just the first letter. Many roles and the non-human races restrict which alignments are allowed. See - - - NetHack 3.7.0 December 25, 2024 - - - - - - NetHack Guidebook 64 - - - role for a description of how to use negation to exclude choices. - Default is random. Cannot be set with the `O' command. Persistent. + If align is not specified, there is no default value; player will be + prompted unless role and/or race forces a choice for alignment. + Cannot be set with the `O' command. Persistent. autodescribe Automatically describe the terrain under cursor when asked to get a @@ -4192,6 +4216,18 @@ This option controls what happens when you attempt the `f' (fire) command when nothing is quivered or readied (default false). When true, the computer will fill your quiver or quiver sack or make + + + NetHack 3.7.0 May 1, 2025 + + + + + + NetHack Guidebook 65 + + + ready some suitable weapon. Note that it will not take into account the blessed/cursed status, enchantment, damage, or quality of the weapon; you are free to manually fill your quiver or quiver sack or @@ -4216,18 +4252,6 @@ decline to use the key; has no effect on containers); Force - try to force a container's lid with your currently wielded weapon (if you omit untrap or decline to attempt - - - NetHack 3.7.0 December 25, 2024 - - - - - - NetHack Guidebook 65 - - - untrap and you omit apply-key or you lack a key or you decline to use the key; has no effect on doors); None - none of the above; can't be combined with the other @@ -4258,6 +4282,18 @@ Name your starting cat (for example "catname:Morris"). Cannot be set with the `O' command. + + + NetHack 3.7.0 May 1, 2025 + + + + + + NetHack Guidebook 66 + + + character Synonym for "role" to pick the type of your character (for example "character:Monk"). See role for more details. @@ -4282,18 +4318,6 @@ dropped_nopick If this option is on, items you dropped will not be automatically - - - NetHack 3.7.0 December 25, 2024 - - - - - - NetHack Guidebook 66 - - - picked up, even if autopickup is also on and they are in pickup_types or match a positive autopickup exception (default on). Persistent. @@ -4325,10 +4349,21 @@ ? - prompt you and default to ask on the prompt; # - disclose it without prompting, ask for sort order. - Asking refers to picking one of the orderings from a menu. The `+' - disclose without prompting choice, or being prompted and answering - `y' rather than `a', will default to showing monsters in the order - specified by the sortvanquished option. + + NetHack 3.7.0 May 1, 2025 + + + + + + NetHack Guidebook 67 + + + + Asking refers to picking one of the orderings from a menu. The + `+' disclose without prompting choice, or being prompted and + answering `y' rather than `a', will default to showing monsters + in the order specified by the sortvanquished option. Omitted categories are implicitly added with `n' prefix. Specified categories with omitted prefix implicitly use `+' prefix. Order of @@ -4348,18 +4383,6 @@ dogname Name your starting dog (for example "dogname:Fang"). Cannot be set - - - NetHack 3.7.0 December 25, 2024 - - - - - - NetHack Guidebook 67 - - - with the `O' command. extmenu @@ -4392,6 +4415,17 @@ Commands asking for an inventory item show a menu instead of a text query with possible menu letters. Default is off. + + NetHack 3.7.0 May 1, 2025 + + + + + + NetHack Guidebook 68 + + + fruit Name a fruit after something you enjoy eating (for example "fruit:mango") (default "slime mold"). Basically a nostalgic whimsy @@ -4407,25 +4441,15 @@ gender option is also present it will take precedence. See role for a description of how to use negation to exclude choices. - Default is random. Cannot be set with the `O' command. Persistent. + If gender is not specified, there is no default value; player will + be prompted unless role and/or race forces a choice for gender. + Cannot be set with the `O' command. Persistent. goldX When filtering objects based on bless/curse state (BUCX), whether to treat gold pieces as X (unknown bless/curse state, when "on") or U (known to be uncursed, when "off", the default). Gold is never blessed or cursed, but it is not described as "uncursed" even when - - - NetHack 3.7.0 December 25, 2024 - - - - - - NetHack Guidebook 68 - - - the implicit_uncursed option is "off". help @@ -4456,6 +4480,18 @@ (default off). The behavior of this option depends on the type of windowing you use. In text windowing, text highlighting or inverse video is often used; with tiles, generally displays a small plus- + + + NetHack 3.7.0 May 1, 2025 + + + + + + NetHack Guidebook 69 + + + symbol beside the object on the top of the pile. hitpointbar @@ -4480,18 +4516,6 @@ to toggle the hitpointbar option off, perform the resize while it's off, then use the same command to toggle it back on.) - - - NetHack 3.7.0 December 25, 2024 - - - - - - NetHack Guidebook 69 - - - horsename Name your starting horse (for example "horsename:Trigger"). Cannot be set with the `O' command. @@ -4522,6 +4546,18 @@ mail Enable mail delivery during the game (default on). Persistent. + + + NetHack 3.7.0 May 1, 2025 + + + + + + NetHack Guidebook 70 + + + male An obsolete synonym for "gender:male". Cannot be set with the `O' command. @@ -4546,18 +4582,6 @@ menustyle Controls the method used when you need to choose various objects (in response to the Drop (aka droptype) command, for instance). The - - - NetHack 3.7.0 December 25, 2024 - - - - - - NetHack Guidebook 70 - - - value specified should be the first letter of one of the following: traditional, combination, full, or partial. Default is full. Per- sistent. @@ -4589,6 +4613,17 @@ allowed attributes and colors, see "Configuring Menu Colors". Not all ports can actually display all types. + + NetHack 3.7.0 May 1, 2025 + + + + + + NetHack Guidebook 71 + + + menu_invert_all Key to invert all items in a menu. Default `@'. @@ -4602,8 +4637,29 @@ Key to go to the next menu page. Default `>'. menu_objsyms - Show object symbols in menu headings in menus where the object sym- - bols act as menu accelerators (default off). + Inventory and other object menus are normally separated by object + class (weapons, armor, and so forth), with a menu header line at the + beginning of each group. You can have menus add the display symbol + for the class of objects for each header line. You can also add the + display symbol for the individual item in each menu entry. For a + tiles map, that would be a small rendition of an object's tile. For + a text map, it is the same character as is used for the object's + class, which would be most useful when there are no headers separat- + ing objects among classes. Possible values are + + 0 - None - no symbols for either header lines or menu + entries; + 1 - Headers - show symbols on header lines but not entries; + 2 - Entries - show symbols on menu entry lines but not headers; + 3 - Both - show symbols on headers and entries; + 4 - Conditional - only show symbols for entries if there are no + headers; + 5 - One-or-other - show symbols on headers, or on entries if no + headers. + + Supported by tty and curses. When setting the value, it can be + specified by digit or keyword. The default value is Conditional + (4). menu_overlay Do not clear the screen before drawing menus, and align menus to the @@ -4612,18 +4668,6 @@ menu_previous_page Key to go to the previous menu page. Default `<'. - - - NetHack 3.7.0 December 25, 2024 - - - - - - NetHack Guidebook 71 - - - menu_search Key to search for some text and toggle selection state of matching menu items. Default `:'. @@ -4634,6 +4678,18 @@ menu_select_page Key to select all items on this page of a menu. Default `,'. + + + NetHack 3.7.0 May 1, 2025 + + + + + + NetHack Guidebook 72 + + + menu_shift_left Key to scroll a menu--one which has been scrolled right--back to the left. Implemented for perm_invent only by curses and X11. Default @@ -4675,21 +4731,6 @@ rently it is only supported for tty (all four choices) and for curses (`f' and `r' choices, default `r'). The possible values are: - - - - - - NetHack 3.7.0 December 25, 2024 - - - - - - NetHack Guidebook 72 - - - s - single message (default; only choice prior to 3.4.0); c - combination, two messages as "single", then as "full"; f - full window, oldest message first; @@ -4703,9 +4744,25 @@ Set your character's name (defaults to your user name). You can also set your character's role by appending a dash and one or more letters of the role (that is, by suffixing one of -A -B -C -H -K -M + + + NetHack 3.7.0 May 1, 2025 + + + + + + NetHack Guidebook 73 + + + -P -Ra -Ro -S -T -V -W). If -@ is used for the role, then a random - one will be automatically chosen. Cannot be set with the `O' com- - mand. + one will be automatically chosen. + + On some systems, the default is the player's user name; on others, + there is no default and the player will be prompted. The former can + made to behave like the latter by specifying a generic name such as + ``player''. Cannot be set with the `O' command. news Read the NetHack news file, if present (default on). Since the news @@ -4745,17 +4802,6 @@ taining the symbols for the various object types. Any omitted types are filled in at the end from the previous order. - - NetHack 3.7.0 December 25, 2024 - - - - - - NetHack Guidebook 73 - - - paranoid_confirmation A space separated list of specific situations where alternate prompting is desired. The default is "paranoid_confirmation:pray @@ -4764,6 +4810,18 @@ Confirm - for any prompts which are set to require "yes" rather than `y', also require "no" to reject instead of accepting any non-yes response as no; changes pray and + + + NetHack 3.7.0 May 1, 2025 + + + + + + NetHack Guidebook 74 + + + AutoAll to require "yes" or `no' too; quit - require "yes" rather than `y' to confirm quitting the game or switching into non-scoring explore mode; @@ -4810,18 +4868,6 @@ set without removing others, precede the first entry in the list with a minus sign, paranoid_confirmation:-swim. To both add some new entries and remove some old ones, you can use multiple para- - - - NetHack 3.7.0 December 25, 2024 - - - - - - NetHack Guidebook 74 - - - noid_confirmation option settings, or you can use the `+' form and list entries to be added by their name and entries to be removed by `!' and name. The positive (no `!') and negative (with `!') entries @@ -4831,6 +4877,17 @@ Start the character with no possessions (default false). Persis- tent. + + NetHack 3.7.0 May 1, 2025 + + + + + + NetHack Guidebook 75 + + + perm_invent If true, always display your current inventory in a window (default false). @@ -4877,17 +4934,6 @@ Loaded), you will be asked if you want to continue. (Default `S'). Persistent. - - NetHack 3.7.0 December 25, 2024 - - - - - - NetHack Guidebook 75 - - - pickup_stolen If this option is on and autopickup is also on, try to pick up things that a monster stole from you, even if they aren't in @@ -4896,6 +4942,18 @@ pickup_thrown If this option is on and autopickup is also on, try to pick up + + + NetHack 3.7.0 May 1, 2025 + + + + + + NetHack Guidebook 76 + + + things that you threw, even if they aren't in pickup_types or match an autopickup exception. Default is on. Persistent. @@ -4942,18 +5000,6 @@ query_menu Use a menu when asked specific yes/no queries, instead of a prompt. - - - NetHack 3.7.0 December 25, 2024 - - - - - - NetHack Guidebook 76 - - - quick_farsight When set, usually prevents the "you sense your surroundings" message where play pauses to allow you to browse the map whenever clairvoy- @@ -4962,13 +5008,27 @@ ance spell where pausing to examine revealed objects or monsters is less intrusive. Default is off. Persistent. + + + NetHack 3.7.0 May 1, 2025 + + + + + + NetHack Guidebook 77 + + + race Selects your race (for example, race:human). Choices are human, dwarf, elf, gnome, and orc but most roles restrict which of the non- human races are allowed. See role for a description of how to use negation to exclude choices. - Default is random. Cannot be set with the `O' command. Persistent. + If race is not specified, there is no default value; player will be + prompted unless role forces a choice for race. Cannot be set with + the `O' command. Persistent. rest_on_space Make the space bar a synonym for the `.' (#wait) command (default @@ -4992,7 +5052,8 @@ There can be multiple instances of the role option if they're all negations. - Default is random. Cannot be set with the `O' command. Persistent. + If role is not specified, there is no default value; player will be + prompted. Cannot be set with the `O' command. Persistent. roguesymset This option may be used to select one of the named symbol sets found @@ -5000,83 +5061,22 @@ rogue level. rlecomp - When writing out a save file, perform run length compression of the + When writing out a save file, perform run length compression of the map. Not all ports support run length compression. It has no effect on reading an existing save file. runmode - Controls the amount of screen updating for the map window when - engaged in multi-turn movement (running via shift+direction or con- - trol+direction and so forth, or via the travel command or mouse - - - NetHack 3.7.0 December 25, 2024 - - - - - - NetHack Guidebook 77 - - - + Controls the amount of screen updating for the map window when + engaged in multi-turn movement (running via shift+direction or con- + trol+direction and so forth, or via the travel command or mouse click). The possible values are: teleport - update the map after movement has finished; run - update the map after every seven or so steps; walk - update the map after each step; - crawl - like walk, but pause briefly after each step. - - This option only affects the game's screen display, not the actual - results of moving. The default is "run"; versions prior to 3.4.1 - used "teleport" only. Whether or not the effect is noticeable will - depend upon the window port used or on the type of terminal. Per- - sistent. - - safe_pet - Prevent you from (knowingly) attacking your pets (default on). Per- - sistent. - - safe_wait - Prevents you from waiting or searching when next to a hostile mon- - ster (default on). Persistent. - - sanity_check - Evaluate monsters, objects, and map prior to each turn (default - off). Debug mode only. - - scores - Control what parts of the score list you are shown at the end (for - example "scores:5 top scores/4 around my score/own scores"). Only - the first letter of each category (`t', `a', or `o') is necessary. - Persistent. - - showdamage - Whenever your character takes damage, show a message of the damage - taken, and the amount of hit points left. - - showexp - Show your accumulated experience points on bottom line (default - off). Persistent. - - showrace - Display yourself as the glyph for your race, rather than the glyph - for your role (default off). Note that this setting affects only - the appearance of the display, not the way the game treats you. - Persistent. - - showscore - Show your approximate accumulated score on bottom line (default - off). By default, this feature is suppressed when building the pro- - gram. Persistent. - - showvers - Include the game's version number on the status lines (default off). - Potentially useful if you switch between different versions or vari- - ants, or you are making screenshots or streaming video. Using the - NetHack 3.7.0 December 25, 2024 + NetHack 3.7.0 May 1, 2025 @@ -5086,11 +5086,72 @@ - statuslines:3 option is recommended so that there will be more room - available for status information, unless you're using nethack's Qt - interface or your terminal emulator window displays fewer than 25 + crawl - like walk, but pause briefly after each step. + + This option only affects the game's screen display, not the actual + results of moving. The default is "run"; versions prior to 3.4.1 + used "teleport" only. Whether or not the effect is noticeable will + depend upon the window port used or on the type of terminal. Per- + sistent. + + safe_pet + Prevent you from (knowingly) attacking your pets (default on). Per- + sistent. + + safe_wait + Prevents you from waiting or searching when next to a hostile mon- + ster (default on). Persistent. + + sanity_check + Evaluate monsters, objects, and map prior to each turn (default + off). Debug mode only. + + scores + Control what parts of the score list you are shown at the end (for + example "scores:5 top scores/4 around my score/own scores"). Only + the first letter of each category (`t', `a', or `o') is necessary. + Persistent. + + showdamage + Whenever your character takes damage, show a message of the damage + taken, and the amount of hit points left. + + showexp + Show your accumulated experience points on bottom line (default + off). Persistent. + + showrace + Display yourself as the glyph for your race, rather than the glyph + for your role (default off). Note that this setting affects only + the appearance of the display, not the way the game treats you. + Persistent. + + showscore + Show your approximate accumulated score on bottom line (default + off). By default, this feature is suppressed when building the pro- + gram. Persistent. + + showvers + Include the game's version number on the status lines (default off). + Potentially useful if you switch between different versions or vari- + ants, or you are making screenshots or streaming video. Using the + statuslines:3 option is recommended so that there will be more room + available for status information, unless you're using nethack's Qt + interface or your terminal emulator window displays fewer than 25 lines. Persistent. + + + NetHack 3.7.0 May 1, 2025 + + + + + + NetHack Guidebook 79 + + + silent Suppress terminal beeps (default on). Persistent. @@ -5100,32 +5161,32 @@ The possible values are: - o - list object types by class, in discovery order within each + o - list object types by class, in discovery order within each class; default; - s - list object types by sortloot classification: by class, by sub- - class within class for classes which have substantial groupings - (like helmets, boots, gloves, and so forth for armor), with - object types partly-discovered via assigned name coming before + s - list object types by sortloot classification: by class, by sub- + class within class for classes which have substantial groupings + (like helmets, boots, gloves, and so forth for armor), with + object types partly-discovered via assigned name coming before fully identified types; c - list by class, alphabetically within each class; a - list alphabetically across all classes. - Can be interactively set via the `O' command or via using the `m' + Can be interactively set via the `O' command or via using the `m' prefix before the `\' or ``' command. sortloot - Controls the sorting behavior of the pickup lists for inventory and + Controls the sorting behavior of the pickup lists for inventory and #loot commands and some others. Persistent. The possible values are: full - always sort the lists; - loot - only sort the lists that don't use inventory letters, like + loot - only sort the lists that don't use inventory letters, like with the #loot and pickup commands; none - show lists the traditional way without sorting; default. sortpack - Sort the pack contents by type when displaying inventory (default + Sort the pack contents by type when displaying inventory (default on). Persistent. sortvanquished @@ -5136,29 +5197,29 @@ t - traditional--order by monster level; ties are broken by internal monster index; default; - d - order by monster difficulty rating; ties broken by internal + d - order by monster difficulty rating; ties broken by internal index; - a - order alphabetically, first any unique monsters then all the + a - order alphabetically, first any unique monsters then all the others; - - - NetHack 3.7.0 December 25, 2024 - - - - - - NetHack Guidebook 79 - - - c - order by monster class, by low to high level within each class; n - order by count, high to low; ties are broken by internal monster index; z - order by count, low to high; ties broken by internal index. - Can be interactively set via the `m O' command or via using the `m' - prefix before either the #vanquished command or the #genocided com- + + + NetHack 3.7.0 May 1, 2025 + + + + + + NetHack Guidebook 80 + + + + Can be interactively set via the `m O' command or via using the `m' + prefix before either the #vanquished command or the #genocided com- mand. sounds @@ -5166,7 +5227,7 @@ on). sparkle - Display a sparkly effect when a monster (including yourself) is hit + Display a sparkly effect when a monster (including yourself) is hit by an attack to which it is resistant (default on). Persistent. spot_monsters @@ -5181,52 +5242,51 @@ ing Status Hilites" for further information. status_updates - Allow updates to the status lines at the bottom of the screen + Allow updates to the status lines at the bottom of the screen (default true). suppress_alert - This option may be set to a NetHack version level to suppress alert - notification messages about feature changes for that and prior ver- + This option may be set to a NetHack version level to suppress alert + notification messages about feature changes for that and prior ver- sions (for example "suppress_alert:3.3.1"). symset This option may be used to select one of the named symbol sets found - within "symbols" to alter the symbols displayed on the screen. Use + within "symbols" to alter the symbols displayed on the screen. Use "symset:default" to explicitly select the default symbols. time - Show the elapsed game time in turns on bottom line (default off). + Show the elapsed game time in turns on bottom line (default off). Persistent. timed_delay When pausing momentarily for display effect, such as with explosions and moving objects, use a timer rather than sending extra characters - to the screen. (Applies to "tty" and "curses" interfaces only; - "X11" interface always uses a timer-based delay. The default is on + to the screen. (Applies to "tty" and "curses" interfaces only; + "X11" interface always uses a timer-based delay. The default is on if configured into the program.) Persistent. - - - - NetHack 3.7.0 December 25, 2024 - - - - - - NetHack Guidebook 80 - - - tips Show some helpful tips during gameplay (default on). Persistent. tombstone Draw a tombstone graphic upon your death (default on). Persistent. + + + NetHack 3.7.0 May 1, 2025 + + + + + + NetHack Guidebook 81 + + + toptenwin - Put the ending display in a NetHack window instead of on stdout - (default off). Setting this option makes the score list visible + Put the ending display in a NetHack window instead of on stdout + (default off). Setting this option makes the score list visible when a windowing version of NetHack is started without a parent win- dow, but it no longer leaves the score list around after game end on a terminal or emulating window. @@ -5234,7 +5294,7 @@ travel Allow the travel command via mouse click (default on). Turning this option off will prevent the game from attempting unintended moves if - you make inadvertent mouse clicks on the map window. Does not + you make inadvertent mouse clicks on the map window. Does not affect traveling via the `_' ("#travel") command. Persistent. tutorial @@ -5245,8 +5305,8 @@ Provide more commentary during the game (default on). Persistent. whatis_coord - When using the `/' or `;' commands to look around on the map with - autodescribe on, display coordinates after the description. Also + When using the `/' or `;' commands to look around on the map with + autodescribe on, display coordinates after the description. Also works in other situations where you are asked to pick a location. The possible settings are: @@ -5257,90 +5317,30 @@ s - screen [row,column] (row is offset to match tty usage); n - none (no coordinates shown) [default]. - The whatis_coord option is also used with the "/m", "/M", "/o", and - "/O" sub-commands of `/', where the "none" setting is overridden + The whatis_coord option is also used with the "/m", "/M", "/o", and + "/O" sub-commands of `/', where the "none" setting is overridden with "map". whatis_filter - When getting a location on the map, and using the keys to cycle - through next and previous targets, allows filtering the possible + When getting a location on the map, and using the keys to cycle + through next and previous targets, allows filtering the possible targets. n - no filtering [default] v - in view only a - in same area only - The area-filter tries to be slightly predictive--if you're standing - on a doorway, it will consider the area on the side of the door you - - - NetHack 3.7.0 December 25, 2024 - - - - - - NetHack Guidebook 81 - - - + The area-filter tries to be slightly predictive--if you're standing + on a doorway, it will consider the area on the side of the door you were last moving towards. Filtering can also be changed when getting a location with the "get- pos.filter" key. - whatis_menu - When getting a location on the map, and using a key to cycle through - next and previous targets, use a menu instead to pick a target. - (default off) - - whatis_moveskip - When getting a location on the map, and using shifted movement keys - or meta-digit keys to fast-move, instead of moving 8 units at a - time, move by skipping the same glyphs. (default off) - - windowtype - When the program has been built to support multiple interfaces, - select which one to use, such as "tty" or "X11" (default depends on - build-time settings; use "#version" to check). Cannot be set with - the `O' command. - - When used, it should be the first option set since its value might - enable or disable the availability of various other options. For - multiple lines in a configuration file, that would be the first non- - comment line. For a comma-separated list in NETHACKOPTIONS or an - OPTIONS line in a configuration file, that would be the rightmost - option in the list. - - wizweight - Augment object descriptions with their objects' weight (default - off). Debug mode only. - - zerocomp - When writing out a save file, perform zero-comp compression of the - contents. Not all ports support zero-comp compression. It has no - effect on reading an existing save file. - - 9.5. Window Port Customization options - - Here are explanations of the various options that are used to - customize and change the characteristics of the windowtype that you - have chosen. Character strings that are too long may be truncated. - Not all window ports will adjust for all settings listed here. You - can safely add any of these options to your configuration file, and if - the window port is capable of adjusting to suit your preferences, it - will attempt to do so. If it can't it will silently ignore it. You - can find out if an option is supported by the window port that you are - currently using by checking to see if it shows up in the Options list. - Some options are dynamic and can be specified during the game with the - `O' command. - - align_message - Where to align or place the message window (top, bottom, left, or - right) - NetHack 3.7.0 December 25, 2024 + + NetHack 3.7.0 May 1, 2025 @@ -5350,16 +5350,78 @@ + whatis_menu + When getting a location on the map, and using a key to cycle through + next and previous targets, use a menu instead to pick a target. + (default off) + + whatis_moveskip + When getting a location on the map, and using shifted movement keys + or meta-digit keys to fast-move, instead of moving 8 units at a + time, move by skipping the same glyphs. (default off) + + windowtype + When the program has been built to support multiple interfaces, + select which one to use, such as "tty" or "X11" (default depends on + build-time settings; use "#version" to check). Cannot be set with + the `O' command. + + When used, it should be the first option set since its value might + enable or disable the availability of various other options. For + multiple lines in a configuration file, that would be the first non- + comment line. For a comma-separated list in NETHACKOPTIONS or an + OPTIONS line in a configuration file, that would be the rightmost + option in the list. + + wizweight + Augment object descriptions with their objects' weight (default + off). Debug mode only. + + zerocomp + When writing out a save file, perform zero-comp compression of the + contents. Not all ports support zero-comp compression. It has no + effect on reading an existing save file. + + 9.5. Window Port Customization options + + Here are explanations of the various options that are used to + customize and change the characteristics of the windowtype that you + have chosen. Character strings that are too long may be truncated. + Not all window ports will adjust for all settings listed here. You + can safely add any of these options to your configuration file, and if + the window port is capable of adjusting to suit your preferences, it + will attempt to do so. If it can't it will silently ignore it. You + can find out if an option is supported by the window port that you are + currently using by checking to see if it shows up in the Options list. + Some options are dynamic and can be specified during the game with the + `O' command. + + align_message + Where to align or place the message window (top, bottom, left, or + right) + align_status - Where to align or place the status window (top, bottom, left, or + Where to align or place the status window (top, bottom, left, or right). + + + NetHack 3.7.0 May 1, 2025 + + + + + + NetHack Guidebook 83 + + + ascii_map - If NetHack can, it should display the map using simple characters - (letters and punctuation) rather than tiles graphics. In some - cases, characters can be augmented with line-drawing symbols; use - the symset option to select a symbol set such as DECgraphics or - IBMgraphics if your display supports them. Setting ascii_map to + If NetHack can, it should display the map using simple characters + (letters and punctuation) rather than tiles graphics. In some + cases, characters can be augmented with line-drawing symbols; use + the symset option to select a symbol set such as DECgraphics or + IBMgraphics if your display supports them. Setting ascii_map to True forces tiled_map to be False. color @@ -5368,15 +5430,15 @@ eight_bit_tty If NetHack can, it should pass eight-bit character values (for exam- - ple, specified with the traps option) straight through to your ter- + ple, specified with the traps option) straight through to your ter- minal (default off). font_map - if NetHack can, it should use a font by the chosen name for the map + if NetHack can, it should use a font by the chosen name for the map window. font_menu - If NetHack can, it should use a font by the chosen name for menu + If NetHack can, it should use a font by the chosen name for menu windows. font_message @@ -5388,7 +5450,7 @@ tus window. font_text - If NetHack can, it should use a font by the chosen name for text + If NetHack can, it should use a font by the chosen name for text windows. font_size_map @@ -5403,29 +5465,28 @@ font_size_status If NetHack can, it should use this size font for the status window. - - - - NetHack 3.7.0 December 25, 2024 - - - - - - NetHack Guidebook 83 - - - font_size_text If NetHack can, it should use this size font for text windows. fullscreen If NetHack can, it should try to display on the entire screen rather + + + NetHack 3.7.0 May 1, 2025 + + + + + + NetHack Guidebook 84 + + + than in a window. guicolor - Use color text and/or highlighting attributes when displaying some - non-map data (such as menu selector letters). Curses interface + Use color text and/or highlighting attributes when displaying some + non-map data (such as menu selector letters). Curses interface only; default is on. large_font @@ -5435,17 +5496,17 @@ If NetHack can, it should display the map in the manner specified. player_selection - If NetHack can, it should pop up dialog boxes, or use prompts for + If NetHack can, it should pop up dialog boxes, or use prompts for character selection. popup_dialog If NetHack can, it should pop up dialog boxes for input. preload_tiles - If NetHack can, it should preload tiles into memory. For example, + If NetHack can, it should preload tiles into memory. For example, in the protected mode MS-DOS version, control whether tiles get pre- loaded into RAM at the start of the game. Doing so enhances perfor- - mance of the tile graphics, but uses more memory. (default on). + mance of the tile graphics, but uses more memory. (default on). Cannot be set with the `O' command. scroll_amount @@ -5462,83 +5523,22 @@ support this option. softkeyboard - Display an onscreen keyboard. Handhelds are most likely to support + Display an onscreen keyboard. Handhelds are most likely to support this option. splash_screen - If NetHack can, it should display an opening splash screen when it + If NetHack can, it should display an opening splash screen when it starts up (default yes). - - - - NetHack 3.7.0 December 25, 2024 - - - - - - NetHack Guidebook 84 - - - statuslines Number of lines for traditional below-the-map status display. Acceptable values are 2 and 3 (default is 2). When set to 3, the tty interface moves some fields around and mainly - shows status conditions on their own line. A display capable of - showing at least 25 lines is recommended. The value can be toggled - back and forth during the game with the `O' command. - - The curses interface does likewise if the align_status option is set - to top or bottom but ignores statuslines when set to left or right. - - The Qt interface already displays more than 3 lines for status so - uses the statuslines value differently. A value of 3 renders status - in the Qt interface's original format, with the status window spread - out vertically. A value of 2 makes status be slightly condensed, - moving some fields to different lines to eliminate one whole line, - reducing the height needed. (If NetHack has been built using a ver- - sion of Qt older than qt-5.9, statuslines can only be set in the - run-time configuration file or via NETHACKOPTIONS, not during play - with the `O' command.) - - term_cols and - - term_rows - Curses interface only. Number of columns and rows to use for the - display. Curses will attempt to resize to the values specified but - will settle for smaller sizes if they are too big. Default is the - current window size. - - tile_file - Specify the name of an alternative tile file to override the - default. - - Note: the X11 interface uses X resources rather than NetHack's - options to select an alternate tile file. See NetHack.ad, the sam- - ple X "application defaults" file. - - tile_height - Specify the preferred height of each tile in a tile capable port. - - tile_width - Specify the preferred width of each tile in a tile capable port - - tiled_map - If NetHack can, it should display the map using tiles graphics - rather than simple characters (letters and punctuation, possibly - augmented by line-drawing symbols). Setting tiled_map to True - forces ascii_map to be False. - - use_darkgray - Use bold black instead of blue for black glyphs (TTY only). + shows status conditions on their own line. A display capable of - - - NetHack 3.7.0 December 25, 2024 + NetHack 3.7.0 May 1, 2025 @@ -5548,63 +5548,63 @@ + showing at least 25 lines is recommended. The value can be toggled + back and forth during the game with the `O' command. + + The curses interface does likewise if the align_status option is set + to top or bottom but ignores statuslines when set to left or right. + + The Qt interface already displays more than 3 lines for status so + uses the statuslines value differently. A value of 3 renders status + in the Qt interface's original format, with the status window spread + out vertically. A value of 2 makes status be slightly condensed, + moving some fields to different lines to eliminate one whole line, + reducing the height needed. (If NetHack has been built using a ver- + sion of Qt older than qt-5.9, statuslines can only be set in the + run-time configuration file or via NETHACKOPTIONS, not during play + with the `O' command.) + + term_cols and + + term_rows + Curses interface only. Number of columns and rows to use for the + display. Curses will attempt to resize to the values specified but + will settle for smaller sizes if they are too big. Default is the + current window size. + + tile_file + Specify the name of an alternative tile file to override the + default. + + Note: the X11 interface uses X resources rather than NetHack's + options to select an alternate tile file. See NetHack.ad, the sam- + ple X "application defaults" file. + + tile_height + Specify the preferred height of each tile in a tile capable port. + + tile_width + Specify the preferred width of each tile in a tile capable port + + tiled_map + If NetHack can, it should display the map using tiles graphics + rather than simple characters (letters and punctuation, possibly + augmented by line-drawing symbols). Setting tiled_map to True + forces ascii_map to be False. + + use_darkgray + Use bold black instead of blue for black glyphs (TTY only). + use_inverse - If NetHack can, it should display inverse when the game specifies + If NetHack can, it should display inverse when the game specifies it. vary_msgcount - If NetHack can, it should display this number of messages at a time + If NetHack can, it should display this number of messages at a time in the message window. - windowborders - Whether to draw boxes around the map, status area, message area, and - persistent inventory window if enabled. Curses interface only. - Acceptable values are - 0 - off, never show borders - 1 - on, always show borders - 2 - auto, on if display is at least (24+2)x(80+2) [default] - 3 - on, except forced off for perm_invent - 4 - auto, except forced off for perm_invent - - (The 26x82 size threshold for `2' refers to number of rows and col- - umns of the display. A width of at least 110 columns (80+2+26+2) is - needed to show borders if align_status is set to left or right.) - - The persistent inventory window, when enabled, can grow until it is - too big to fit on most displays, resulting in truncation of its con- - tents. If borders are forced on (1) or the display is big enough to - show them (2), setting the value to 3 or 4 instead will keep borders - for the map, message, and status windows but have room for two addi- - tional lines of inventory plus widen each inventory line by two col- - umns. - - windowcolors - If NetHack can, it should display all windows of a particular style - with the specified foreground and background colors. Windows GUI - and curses windowport only. The format is - - OPTION=windowcolors:style foreground/background - - where style is one of "menu", "message", "status", or "text", and - foreground and background are colors, either numeric (hash sign fol- - lowed by three pairs of hexadecimal digits, #rrggbb), one of the - named colors (black, red, green, brown, blue, magenta, cyan, orange, - bright-green, yellow, bright-blue, bright-magenta, bright-cyan, - white, gray, purple, silver, maroon, fuchsia, lime, olive, navy, - teal, aqua), or (for Windows only) one of Windows UI colors (true- - black, activeborder, activecaption, appworkspace, background, btn- - face, btnshadow, btntext, captiontext, graytext, greytext, high- - light, highlighttext, inactiveborder, inactivecaption, menu, menu- - text, scrollbar, window, windowframe, windowtext). - - wraptext - If NetHack can, it should wrap long lines of text if they don't fit - in the visible area of the window. - - - - NetHack 3.7.0 December 25, 2024 + NetHack 3.7.0 May 1, 2025 @@ -5614,63 +5614,63 @@ + windowborders + Whether to draw boxes around the map, status area, message area, and + persistent inventory window if enabled. Curses interface only. + Acceptable values are + + 0 - off, never show borders + 1 - on, always show borders + 2 - auto, on if display is at least (24+2)x(80+2) [default] + 3 - on, except forced off for perm_invent + 4 - auto, except forced off for perm_invent + + (The 26x82 size threshold for `2' refers to number of rows and col- + umns of the display. A width of at least 110 columns (80+2+26+2) is + needed to show borders if align_status is set to left or right.) + + The persistent inventory window, when enabled, can grow until it is + too big to fit on most displays, resulting in truncation of its con- + tents. If borders are forced on (1) or the display is big enough to + show them (2), setting the value to 3 or 4 instead will keep borders + for the map, message, and status windows but have room for two addi- + tional lines of inventory plus widen each inventory line by two col- + umns. + + windowcolors + If NetHack can, it should display all windows of a particular style + with the specified foreground and background colors. Windows GUI + and curses windowport only. The format is + + OPTION=windowcolors:style foreground/background + + where style is one of "menu", "message", "status", or "text", and + foreground and background are colors, either numeric (hash sign fol- + lowed by three pairs of hexadecimal digits, #rrggbb), one of the + named colors (black, red, green, brown, blue, magenta, cyan, orange, + bright-green, yellow, bright-blue, bright-magenta, bright-cyan, + white, gray, purple, silver, maroon, fuchsia, lime, olive, navy, + teal, aqua), or (for Windows only) one of Windows UI colors (true- + black, activeborder, activecaption, appworkspace, background, btn- + face, btnshadow, btntext, captiontext, graytext, greytext, high- + light, highlighttext, inactiveborder, inactivecaption, menu, menu- + text, scrollbar, window, windowframe, windowtext). + + wraptext + If NetHack can, it should wrap long lines of text if they don't fit + in the visible area of the window. + 9.6. Crash Report Options - Please note that NetHack does not send any information off your + Please note that NetHack does not send any information off your computer unless you manually click submit on a form. OPTION=crash_email:email_address - OPTION=crash_name:your_name - These options are used only to save you some typing on the - crash report and #bugreport forms. - - OPTION=crash_urlmax:bytes - This option is used to limit the length of the URLs generated - and is only needed if your browser cannot handle arbitrarily - long URLs. - - 9.7. Platform-specific Customization options - - Here are explanations of options that are used by specific plat- - forms or ports to customize and change the port behavior. - - altkeyhandling - Select an alternate way to handle keystrokes (Win32 tty NetHack - only). The name of the handling type is one of "default", "ray", - "340". - - altmeta - On systems where this option is available, it can be set to tell - NetHack to convert a two character sequence beginning with ESC into - a meta-shifted version of the second character (default off). - - This conversion is only done for commands, not for other input - prompts. Note that typing one or more digits as a count prefix - prior to a command--preceded by n if the number_pad option is set-- - is also subject to this conversion, so attempting to abort the count - by typing ESC will leave NetHack waiting for another character to - complete the two character sequence. Type a second ESC to finish - cancelling such a count. At other prompts a single ESC suffices. - - BIOS - Use BIOS calls to update the screen display quickly and to read the - keyboard (allowing the use of arrow keys to move) on machines with - an IBM PC compatible BIOS ROM (default off, OS/2, PC, and ST NetHack - only). - - rawio - Force raw (non-cbreak) mode for faster output and more bulletproof - input (MS-DOS sometimes treats `^P' as a printer toggle without it) - (default off, OS/2, PC, and ST NetHack only). Note: DEC Rainbows - hang if this is turned on. Cannot be set with the `O' command. - - subkeyvalue - (Win32 tty NetHack only). May be used to alter the value of key- - strokes that the operating system returns to NetHack to help compen- - NetHack 3.7.0 December 25, 2024 + + NetHack 3.7.0 May 1, 2025 @@ -5680,63 +5680,63 @@ - sate for international keyboard issues. OPTIONS=subkeyvalue:171/92 - will return 92 to NetHack, if 171 was originally going to be - returned. You can use multiple subkeyvalue assignments in the con- + OPTION=crash_name:your_name + These options are used only to save you some typing on the + crash report and #bugreport forms. + + OPTION=crash_urlmax:bytes + This option is used to limit the length of the URLs generated + and is only needed if your browser cannot handle arbitrarily + long URLs. + + 9.7. Platform-specific Customization options + + Here are explanations of options that are used by specific plat- + forms or ports to customize and change the port behavior. + + altkeyhandling + Select an alternate way to handle keystrokes (Win32 tty NetHack + only). The name of the handling type is one of "default", "ray", + "340". + + altmeta + On systems where this option is available, it can be set to tell + NetHack to convert a two character sequence beginning with ESC into + a meta-shifted version of the second character (default off). + + This conversion is only done for commands, not for other input + prompts. Note that typing one or more digits as a count prefix + prior to a command--preceded by n if the number_pad option is set-- + is also subject to this conversion, so attempting to abort the count + by typing ESC will leave NetHack waiting for another character to + complete the two character sequence. Type a second ESC to finish + cancelling such a count. At other prompts a single ESC suffices. + + BIOS + Use BIOS calls to update the screen display quickly and to read the + keyboard (allowing the use of arrow keys to move) on machines with + an IBM PC compatible BIOS ROM (default off, OS/2, PC, and ST NetHack + only). + + rawio + Force raw (non-cbreak) mode for faster output and more bulletproof + input (MS-DOS sometimes treats `^P' as a printer toggle without it) + (default off, OS/2, PC, and ST NetHack only). Note: DEC Rainbows + hang if this is turned on. Cannot be set with the `O' command. + + subkeyvalue + (Win32 tty NetHack only). May be used to alter the value of key- + strokes that the operating system returns to NetHack to help compen- + sate for international keyboard issues. OPTIONS=subkeyvalue:171/92 + will return 92 to NetHack, if 171 was originally going to be + returned. You can use multiple subkeyvalue assignments in the con- figuration file if needed. Cannot be set with the `O' command. video Set the video mode used (PC NetHack only). Values are "autodetect", - "default", "vga", or "vesa". Setting "vesa" will cause the game to - display tiles, using the full capability of the VGA hardware. Set- - ting "vga" will cause the game to display tiles, fixed at 640x480 in - 16 colors, a mode that is compatible with all VGA hardware. Third - party tilesets will probably not work. Setting "autodetect" - attempts "vesa", then "vga", and finally sets "default" if neither - of those modes works. Cannot be set with the `O' command. - - video_height - Set the VGA mode resolution height (MS-DOS only, with video:vesa) - - video_width - Set the VGA mode resolution width (MS-DOS only, with video:vesa) - - videocolors - Set the color palette for PC systems using NO_TERMS (default - 4-2-6-1-5-3-15-12-10-14-9-13-11, (PC NetHack only). The order of - colors is red, green, brown, blue, magenta, cyan, bright.white, - bright.red, bright.green, yellow, bright.blue, bright.magenta, and - bright.cyan. Cannot be set with the `O' command. - - videoshades - Set the intensity level of the three gray scales available (default - dark normal light, PC NetHack only). If the game display is diffi- - cult to read, try adjusting these scales; if this does not correct - the problem, try !color. Cannot be set with the `O' command. - - 9.8. Regular Expressions - - Regular expressions are normally POSIX extended regular expres- - sions. It is possible to compile NetHack without regular expression - support on a platform where there is no regular expression library. - While this is not true of any modern platform, if your NetHack was - built this way, patterns are instead glob patterns; regardless, this - document refers to both as `regular expressions.' This applies to - Autopickup exceptions, Message types, Menu colors, and User sounds. - - 9.9. Configuring Autopickup Exceptions - - You can further refine the behavior of the autopickup option - beyond what is available through the pickup_types option. - - By placing autopickup_exception lines in your configuration file, - you can define patterns to be checked when the game is about to - autopickup something. - - - NetHack 3.7.0 December 25, 2024 + NetHack 3.7.0 May 1, 2025 @@ -5746,63 +5746,63 @@ + "default", "vga", or "vesa". Setting "vesa" will cause the game to + display tiles, using the full capability of the VGA hardware. Set- + ting "vga" will cause the game to display tiles, fixed at 640x480 in + 16 colors, a mode that is compatible with all VGA hardware. Third + party tilesets will probably not work. Setting "autodetect" + attempts "vesa", then "vga", and finally sets "default" if neither + of those modes works. Cannot be set with the `O' command. + + video_height + Set the VGA mode resolution height (MS-DOS only, with video:vesa) + + video_width + Set the VGA mode resolution width (MS-DOS only, with video:vesa) + + videocolors + Set the color palette for PC systems using NO_TERMS (default + 4-2-6-1-5-3-15-12-10-14-9-13-11, (PC NetHack only). The order of + colors is red, green, brown, blue, magenta, cyan, bright.white, + bright.red, bright.green, yellow, bright.blue, bright.magenta, and + bright.cyan. Cannot be set with the `O' command. + + videoshades + Set the intensity level of the three gray scales available (default + dark normal light, PC NetHack only). If the game display is diffi- + cult to read, try adjusting these scales; if this does not correct + the problem, try !color. Cannot be set with the `O' command. + + 9.8. Regular Expressions + + Regular expressions are normally POSIX extended regular expres- + sions. It is possible to compile NetHack without regular expression + support on a platform where there is no regular expression library. + While this is not true of any modern platform, if your NetHack was + built this way, patterns are instead glob patterns; regardless, this + document refers to both as `regular expressions.' This applies to + Autopickup exceptions, Message types, Menu colors, and User sounds. + + 9.9. Configuring Autopickup Exceptions + + You can further refine the behavior of the autopickup option + beyond what is available through the pickup_types option. + + By placing autopickup_exception lines in your configuration file, + you can define patterns to be checked when the game is about to + autopickup something. + autopickup_exception Sets an exception to the pickup_types option. The autopickup_excep- tion option should be followed by a regular expression to be used as - a pattern to match against the singular form of the description of + a pattern to match against the singular form of the description of an object at your location. - In addition, some characters are treated specially if they occur as + In addition, some characters are treated specially if they occur as the first character in the pattern, specifically: - < - always pickup an object that matches rest of pattern; - > - never pickup an object that matches rest of pattern. - The autopickup_exception rules are processed in the order in which - they appear in your configuration file, thus allowing a later rule - to override an earlier rule. - - Exceptions can be set with the `O' command, but because they are not - included in your configuration file, they won't be in effect if you - save and then restore your game. autopickup_exception rules and not - saved with the game. - - Here are some examples: - - autopickup_exception="<*arrow" - autopickup_exception=">*corpse" - autopickup_exception=">* cursed*" - - The first example above will result in autopickup of any type of - arrow. The second example results in the exclusion of any corpse from - autopickup. The last example results in the exclusion of items known - to be cursed from autopickup. - - 9.10. Changing Key Bindings - - It is possible to change the default key bindings of some special - commands, menu accelerator keys, and extended commands, by using BIND - stanzas in the configuration file. Format is key, followed by the - command to bind to, separated by a colon. The key can be a single - character ("x"), a control key ("^X", "C-x"), a meta key ("M-x"), a - mouse button, or a three-digit decimal ASCII code. - - For example: - - BIND=^X:getpos.autodescribe - BIND=\:menu_first_page - BIND=v:loot - - Extended command keys - You can bind multiple keys to the same extended command. Unbind a - key by using "nothing" as the extended command to bind to. You can - also bind the "", "", and "" keys. - - Menu accelerator keys - The menu control or accelerator keys can also be rebound via OPTIONS - - - NetHack 3.7.0 December 25, 2024 + NetHack 3.7.0 May 1, 2025 @@ -5812,63 +5812,63 @@ - lines in the configuration file. You cannot bind object symbols or + < - always pickup an object that matches rest of pattern; + > - never pickup an object that matches rest of pattern. + + The autopickup_exception rules are processed in the order in which + they appear in your configuration file, thus allowing a later rule + to override an earlier rule. + + Exceptions can be set with the `O' command, but because they are not + included in your configuration file, they won't be in effect if you + save and then restore your game. autopickup_exception rules and not + saved with the game. + + Here are some examples: + + autopickup_exception="<*arrow" + autopickup_exception=">*corpse" + autopickup_exception=">* cursed*" + + The first example above will result in autopickup of any type of + arrow. The second example results in the exclusion of any corpse from + autopickup. The last example results in the exclusion of items known + to be cursed from autopickup. + + 9.10. Changing Key Bindings + + It is possible to change the default key bindings of some special + commands, menu accelerator keys, and extended commands, by using BIND + stanzas in the configuration file. Format is key, followed by the + command to bind to, separated by a colon. The key can be a single + character ("x"), a control key ("^X", "C-x"), a meta key ("M-x"), a + mouse button, or a three-digit decimal ASCII code. + + For example: + + BIND=^X:getpos.autodescribe + BIND=\:menu_first_page + BIND=v:loot + + Extended command keys + You can bind multiple keys to the same extended command. Unbind a + key by using "nothing" as the extended command to bind to. You can + also bind the "", "", and "" keys. + + Menu accelerator keys + The menu control or accelerator keys can also be rebound via OPTIONS + lines in the configuration file. You cannot bind object symbols or selection letters into menu accelerators. Some interfaces only sup- port some of the menu accelerators. Mouse buttons - You can bind "mouse1" or "mouse2" to "nothing", "therecmdmenu", + You can bind "mouse1" or "mouse2" to "nothing", "therecmdmenu", "clicklook", or "mouseaction". - Special command keys - Below are the special commands you can rebind. Some of them can be - bound to same keys with no problems, others are in the same "con- - text", and if bound to same keys, only one of those commands will be - available. Special command can only be bound to a single key. - - count - Prefix key to start a count, to repeat a command this many times. - With number_pad only. Default is `n'. - - getdir.help - When asked for a direction, the key to show the help. Default is - `?'. - - getdir.mouse - When asked for a direction, the key to initiate a simulated mouse - click. You will be asked to pick a location. Use movement key- - strokes to move the cursor around the map, then type the get- - pos.pick.once key (default `,') or the getpos.pick key (default `.') - to finish as if performing a left or right click. Only useful when - using the #therecmdmenu command. Default is `_'. - - getdir.self - When asked for a direction, the key to target yourself. Default is - `.'. - - getdir.self2 - When asked for a direction, an alternate key to target yourself. - Default is `s'. - - getpos.autodescribe - When asked for a location, the key to toggle autodescribe. Default - is `#'. - - getpos.all.next - When asked for a location, the key to go to next closest interesting - thing. Default is `a'. - - getpos.all.prev - When asked for a location, the key to go to previous closest inter- - esting thing. Default is `A'. - - getpos.door.next - When asked for a location, the key to go to next closest door or - doorway. Default is `d'. - NetHack 3.7.0 December 25, 2024 + NetHack 3.7.0 May 1, 2025 @@ -5878,6 +5878,52 @@ + Special command keys + Below are the special commands you can rebind. Some of them can be + bound to same keys with no problems, others are in the same "con- + text", and if bound to same keys, only one of those commands will be + available. Special command can only be bound to a single key. + + count + Prefix key to start a count, to repeat a command this many times. + With number_pad only. Default is `n'. + + getdir.help + When asked for a direction, the key to show the help. Default is + `?'. + + getdir.mouse + When asked for a direction, the key to initiate a simulated mouse + click. You will be asked to pick a location. Use movement key- + strokes to move the cursor around the map, then type the get- + pos.pick.once key (default `,') or the getpos.pick key (default `.') + to finish as if performing a left or right click. Only useful when + using the #therecmdmenu command. Default is `_'. + + getdir.self + When asked for a direction, the key to target yourself. Default is + `.'. + + getdir.self2 + When asked for a direction, an alternate key to target yourself. + Default is `s'. + + getpos.autodescribe + When asked for a location, the key to toggle autodescribe. Default + is `#'. + + getpos.all.next + When asked for a location, the key to go to next closest interesting + thing. Default is `a'. + + getpos.all.prev + When asked for a location, the key to go to previous closest inter- + esting thing. Default is `A'. + + getpos.door.next + When asked for a location, the key to go to next closest door or + doorway. Default is `d'. + getpos.door.prev When asked for a location, the key to go to previous closest door or doorway. Default is `D'. @@ -5885,56 +5931,10 @@ getpos.help When asked for a location, the key to show help. Default is `?'. - getpos.mon.next - When asked for a location, the key to go to next closest monster. - Default is `m'. - - getpos.mon.prev - When asked for a location, the key to go to previous closest mon- - ster. Default is `M'. - - getpos.obj.next - When asked for a location, the key to go to next closest object. - Default is `o'. - - getpos.obj.prev - When asked for a location, the key to go to previous closest object. - Default is `O'. - - getpos.menu - When asked for a location, and using one of the next or previous - keys to cycle through targets, toggle showing a menu instead. - Default is `!'. - - getpos.moveskip - When asked for a location, and using the shifted movement keys or - meta-digit keys to fast-move around, move by skipping the same - glyphs instead of by 8 units. Default is `*'. - - getpos.filter - When asked for a location, change the filtering mode when using one - of the next or previous keys to cycle through targets. Toggles - between no filtering, in view only, and in the same area only. - Default is `"'. - - getpos.pick - When asked for a location, the key to choose the location, and pos- - sibly ask for more info. When simulating a mouse click after being - asked for a direction (see getdir.mouse above), the key to use to - respond as right click. Default is `.'. - - getpos.pick.once - When asked for a location, the key to choose the location, and skip - asking for more info. When simulating a mouse click after being - asked for a direction, the key to respond as left click. Default is - `,'. - - getpos.pick.quick - When asked for a location, the key to choose the location, skip ask- - ing for more info, and exit the location asking loop. Default is - NetHack 3.7.0 December 25, 2024 + + NetHack 3.7.0 May 1, 2025 @@ -5944,26 +5944,86 @@ + getpos.mon.next + When asked for a location, the key to go to next closest monster. + Default is `m'. + + getpos.mon.prev + When asked for a location, the key to go to previous closest mon- + ster. Default is `M'. + + getpos.obj.next + When asked for a location, the key to go to next closest object. + Default is `o'. + + getpos.obj.prev + When asked for a location, the key to go to previous closest object. + Default is `O'. + + getpos.menu + When asked for a location, and using one of the next or previous + keys to cycle through targets, toggle showing a menu instead. + Default is `!'. + + getpos.moveskip + When asked for a location, and using the shifted movement keys or + meta-digit keys to fast-move around, move by skipping the same + glyphs instead of by 8 units. Default is `*'. + + getpos.filter + When asked for a location, change the filtering mode when using one + of the next or previous keys to cycle through targets. Toggles + between no filtering, in view only, and in the same area only. + Default is `"'. + + getpos.pick + When asked for a location, the key to choose the location, and pos- + sibly ask for more info. When simulating a mouse click after being + asked for a direction (see getdir.mouse above), the key to use to + respond as right click. Default is `.'. + + getpos.pick.once + When asked for a location, the key to choose the location, and skip + asking for more info. When simulating a mouse click after being + asked for a direction, the key to respond as left click. Default is + `,'. + + getpos.pick.quick + When asked for a location, the key to choose the location, skip ask- + ing for more info, and exit the location asking loop. Default is `;'. getpos.pick.verbose - When asked for a location, the key to choose the location, and show + When asked for a location, the key to choose the location, and show more info without asking. Default is `:'. + + + + NetHack 3.7.0 May 1, 2025 + + + + + + NetHack Guidebook 92 + + + getpos.self - When asked for a location, the key to go to your location. Default + When asked for a location, the key to go to your location. Default is `@'. getpos.unexplored.next - When asked for a location, the key to go to next closest unexplored + When asked for a location, the key to go to next closest unexplored location. Default is `x'. getpos.unexplored.prev - When asked for a location, the key to go to previous closest unex- + When asked for a location, the key to go to previous closest unex- plored location. Default is `X'. getpos.valid - When asked for a location, the key to go to show valid target loca- + When asked for a location, the key to go to show valid target loca- tions. Default is `$'. getpos.valid.next @@ -5971,15 +6031,15 @@ tion. Default is `z'. getpos.valid.prev - When asked for a location, the key to go to previous closest valid + When asked for a location, the key to go to previous closest valid location. Default is `Z'. 9.11. Configuring Message Types - You can change the way the messages are shown in the message + You can change the way the messages are shown in the message area, when the message matches a user-defined pattern. - In general, the configuration file entries to describe the mes- + In general, the configuration file entries to describe the mes- sage types look like this: MSGTYPE=type "pattern" type - how the message should be shown; @@ -5992,81 +6052,21 @@ show - show message normally; hide - never show the message; stop - wait for user with more-prompt; - norep - show the message once, but not again if no other message is + norep - show the message once, but not again if no other message is shown in between. - Here's an example of message types using NetHack's internal pattern + Here's an example of message types using NetHack's internal pattern matching facility: - - - NetHack 3.7.0 December 25, 2024 - - - - - - NetHack Guidebook 92 - - - MSGTYPE=stop "You feel hungry." MSGTYPE=hide "You displaced *." - specifies that whenever a message "You feel hungry" is shown, the - user is prompted with more-prompt, and a message matching "You dis- + specifies that whenever a message "You feel hungry" is shown, the + user is prompted with more-prompt, and a message matching "You dis- placed ." is not shown at all. - The order of the defined MSGTYPE lines is important; the last match- - ing rule is used. Put the general case first, exceptions below them. - 9.12. Configuring Menu Colors - - Some platforms allow you to define colors used in menu lines when - the line matches a user-defined pattern. At this time the tty, - curses, win32tty and win32gui interfaces support this. - - In general, the configuration file entries to describe the menu - color mappings look like this: - - MENUCOLOR="pattern"=color&attribute - - pattern - the pattern to match; - color - the color to use for lines matching the pattern; - attribute - the attribute to use for lines matching the pat- - tern. The attribute is optional, and if left out, - you must also leave out the preceding ampersand. - If no attribute is defined, no attribute is used. - - The pattern should be a regular expression. - - Allowed colors are black, red, green, brown, blue, magenta, cyan, - gray, orange, light-green, yellow, light-blue, light-magenta, light- - cyan, and white. And no-color, the default foreground color, which - isn't necessarily the same as any of the other colors. - - Allowed attributes are none, bold, dim, italic, underline, blink, - and inverse. "Normal" is a synonym for "none". Note that the plat- - form used may interpret the attributes any way it wants. - - Here's an example of menu colors using NetHack's internal pattern - matching facility: - - MENUCOLOR="* blessed *"=green - MENUCOLOR="* cursed *"=red - MENUCOLOR="* cursed *(being worn)"=red&underline - - specifies that any menu line with " blessed " contained in it will - be shown in green color, lines with " cursed " will be shown in red, - and lines with " cursed " followed by "(being worn)" on the same - line will be shown in red color and underlined. You can have multi- - ple MENUCOLOR entries in your configuration file, and the last MENU- - COLOR line that matches a menu line will be used for the line. - - - - - NetHack 3.7.0 December 25, 2024 + NetHack 3.7.0 May 1, 2025 @@ -6076,19 +6076,80 @@ - Note that if you intend to have one or more color specifications + The order of the defined MSGTYPE lines is important; the last match- + ing rule is used. Put the general case first, exceptions below them. + + 9.12. Configuring Menu Colors + + Some platforms allow you to define colors used in menu lines when + the line matches a user-defined pattern. At this time the tty, + curses, win32tty and win32gui interfaces support this. + + In general, the configuration file entries to describe the menu + color mappings look like this: + + MENUCOLOR="pattern"=color&attribute + + pattern - the pattern to match; + color - the color to use for lines matching the pattern; + attribute - the attribute to use for lines matching the pat- + tern. The attribute is optional, and if left out, + you must also leave out the preceding ampersand. + If no attribute is defined, no attribute is used. + + The pattern should be a regular expression. + + Allowed colors are black, red, green, brown, blue, magenta, cyan, + gray, orange, light-green, yellow, light-blue, light-magenta, light- + cyan, and white. And no-color, the default foreground color, which + isn't necessarily the same as any of the other colors. + + Allowed attributes are none, bold, dim, italic, underline, blink, + and inverse. "Normal" is a synonym for "none". Note that the plat- + form used may interpret the attributes any way it wants. + + Here's an example of menu colors using NetHack's internal pattern + matching facility: + + MENUCOLOR="* blessed *"=green + MENUCOLOR="* cursed *"=red + MENUCOLOR="* cursed *(being worn)"=red&underline + + specifies that any menu line with " blessed " contained in it will + be shown in green color, lines with " cursed " will be shown in red, + and lines with " cursed " followed by "(being worn)" on the same + line will be shown in red color and underlined. You can have multi- + ple MENUCOLOR entries in your configuration file, and the last MENU- + COLOR line that matches a menu line will be used for the line. + + Note that if you intend to have one or more color specifications match " uncursed ", you will probably want to turn the - implicit_uncursed option off so that all items known to be uncursed + implicit_uncursed option off so that all items known to be uncursed are actually displayed with the "uncursed" description. + + + + + + NetHack 3.7.0 May 1, 2025 + + + + + + NetHack Guidebook 94 + + + 9.13. Configuring User Sounds - Some platforms allow you to define sound files to be played when + Some platforms allow you to define sound files to be played when a message that matches a user-defined pattern is delivered to the mes- - sage window. At this time the Qt port and the win32tty and win32gui + sage window. At this time the Qt port and the win32tty and win32gui ports support the use of user sounds. - The following configuration file entries are relevant to mapping + The following configuration file entries are relevant to mapping user sounds to messages: SOUNDDIR @@ -6098,9 +6159,9 @@ An entry that maps a sound file to a user-specified message pattern. Each SOUND entry is broken down into the following parts: - MESG - message window mapping (the only one supported in + MESG - message window mapping (the only one supported in 3.7.0); - msgtype - optional; message type to use, see "Configuring Mes- + msgtype - optional; message type to use, see "Configuring Mes- sage Types" pattern - the pattern to match; sound file - the sound file to play; @@ -6119,63 +6180,63 @@ 9.14. Configuring Status Hilites - Your copy of NetHack may have been compiled with support for - "Status Hilites". If so, you can customize your game display by set- - ting thresholds to change the color or appearance of fields in the + Your copy of NetHack may have been compiled with support for + "Status Hilites". If so, you can customize your game display by set- + ting thresholds to change the color or appearance of fields in the status display. The format for defining status colors is: OPTION=hilite_status:field-name/behavior/color&attributes - For example, the following line in your configuration file will - cause the hitpoints field to display in the color red if your hit- - - - NetHack 3.7.0 December 25, 2024 - - - - - - NetHack Guidebook 94 - - - + For example, the following line in your configuration file will + cause the hitpoints field to display in the color red if your hit- points drop to or below a threshold of 30%: OPTION=hilite_status:hitpoints/<=30%/red/normal - (That example is actually specifying red&normal for <=30% and no- + (That example is actually specifying red&normal for <=30% and no- + + + NetHack 3.7.0 May 1, 2025 + + + + + + NetHack Guidebook 95 + + + color&normal for >30%.) - For another example, the following line in your configuration + For another example, the following line in your configuration file will cause wisdom to be displayed red if it drops and green if it rises: OPTION=hilite_status:wisdom/down/red/up/green Allowed colors are black, red, green, brown, blue, magenta, cyan, - gray, orange, light-green, yellow, light-blue, light-magenta, light- - cyan, and white. And "no-color", the default foreground color on the + gray, orange, light-green, yellow, light-blue, light-magenta, light- + cyan, and white. And "no-color", the default foreground color on the display, which is not necessarily the same as black or white or any of the other colors. Allowed attributes are none, bold, dim, underline, italic, blink, - and inverse. "Normal" is a synonym for "none"; they should not be + and inverse. "Normal" is a synonym for "none"; they should not be used in combination with any of the other attributes. - To specify both a color and an attribute, use `&' to combine - them. To specify multiple attributes, use `+' to combine those. For + To specify both a color and an attribute, use `&' to combine + them. To specify multiple attributes, use `+' to combine those. For example: "magenta&inverse+dim". Note that the display may substitute or ignore particular - attributes depending upon its capabilities, and in general may inter- - pret the attributes any way it wants. For example, on some display - systems a request for bold might yield blink or vice versa. On oth- + attributes depending upon its capabilities, and in general may inter- + pret the attributes any way it wants. For example, on some display + systems a request for bold might yield blink or vice versa. On oth- ers, issuing an attribute request while another is already set up will - replace the earlier attribute rather than combine with it. Since - NetHack issues attribute requests sequentially (at least with the tty + replace the earlier attribute rather than combine with it. Since + NetHack issues attribute requests sequentially (at least with the tty interface) rather than all at once, the only way a situation like that can be controlled is to specify just one attribute. @@ -6189,82 +6250,21 @@ charisma armor-class condition alignment score - The pseudo-field "characteristics" can be used to set all six of - Str, Dex, Con, Int, Wis, and Cha at once. "HD" is "hit dice", an - approximation of experience level displayed when polymorphed. - "experience", "time", and "score" are conditionally displayed + The pseudo-field "characteristics" can be used to set all six of + Str, Dex, Con, Int, Wis, and Cha at once. "HD" is "hit dice", an + approximation of experience level displayed when polymorphed. + "experience", "time", and "score" are conditionally displayed depending upon your other option settings. - - - - NetHack 3.7.0 December 25, 2024 - - - - - - NetHack Guidebook 95 - - - - Instead of a behavior, "condition" takes the following condition - flags: stone, slime, strngl, foodpois, termill, blind, deaf, stun, + Instead of a behavior, "condition" takes the following condition + flags: stone, slime, strngl, foodpois, termill, blind, deaf, stun, conf, hallu, lev, fly, and ride. You can use "major_troubles" as an - alias for stone through termill, "minor_troubles" for blind through + alias for stone through termill, "minor_troubles" for blind through hallu, "movement" for lev, fly, and ride, and "all" for every condi- tion. - Allowed behaviors are "always", "up", "down", "changed", a percent- - age or absolute number threshold, or text to match against. For the - hitpoints field, the additional behavior "criticalhp" is available. - It overrides other behavior rules if hit points are at or below the - major problem threshold (which varies depending upon maximum hit - points and experience level). - * "always" will set the default attributes for that field. - - * "up", "down" set the field attributes for when the field value - changes upwards or downwards. This attribute times out after - statushilites turns. - - * "changed" sets the field attribute for when the field value - changes. This attribute times out after statushilites turns. - (If a field has both a "changed" rule and an "up" or "down" - rule which matches a change in the field's value, the "up" or - "down" one takes precedence.) - - * percentage sets the field attribute when the field value - matches the percentage. It is specified as a number between 0 - and 100, followed by `%' (percent sign). If the percentage is - prefixed with `<=' or `>=', it also matches when value is below - or above the percentage. Use prefix `<' or `>' to match when - strictly below or above. (The numeric limit is relaxed - slightly for those: >-1% and <101% are allowed.) Only four - fields support percentage rules. Percentages for "hitpoints" - and "power" are straightforward; they're based on the corre- - sponding maximum field. Percentage highlight rules are also - allowed for "experience level" and "experience points" (valid - when the showexp option is enabled). For those, the percentage - is based on the progress from the start of the current experi- - ence level to the start of the next level. So if level 2 - starts at 20 points and level 3 starts at 40 points, having 30 - points is 50% and 35 points is 75%. 100% is unattainable for - experience because you'll gain a level and the calculations - will be reset for that new level, but a rule for =100% is - allowed and matches the special case of being exactly 1 experi- - ence point short of the next level. - - * absolute value sets the attribute when the field value matches - that number. The number must be 0 or higher, except for - "armor-class' which allows negative values, and may optionally - be preceded by `='. If the number is preceded by `<=' or `>=' - instead, it also matches when value is below or above. If the - prefix is `<' or `>', only match when strictly above or below. - - - - NetHack 3.7.0 December 25, 2024 + NetHack 3.7.0 May 1, 2025 @@ -6274,19 +6274,79 @@ - * criticalhp only applies to the hitpoints field and only when + Allowed behaviors are "always", "up", "down", "changed", a percent- + age or absolute number threshold, or text to match against. For the + hitpoints field, the additional behavior "criticalhp" is available. + It overrides other behavior rules if hit points are at or below the + major problem threshold (which varies depending upon maximum hit + points and experience level). + + * "always" will set the default attributes for that field. + + * "up", "down" set the field attributes for when the field value + changes upwards or downwards. This attribute times out after + statushilites turns. + + * "changed" sets the field attribute for when the field value + changes. This attribute times out after statushilites turns. + (If a field has both a "changed" rule and an "up" or "down" + rule which matches a change in the field's value, the "up" or + "down" one takes precedence.) + + * percentage sets the field attribute when the field value + matches the percentage. It is specified as a number between 0 + and 100, followed by `%' (percent sign). If the percentage is + prefixed with `<=' or `>=', it also matches when value is below + or above the percentage. Use prefix `<' or `>' to match when + strictly below or above. (The numeric limit is relaxed + slightly for those: >-1% and <101% are allowed.) Only four + fields support percentage rules. Percentages for "hitpoints" + and "power" are straightforward; they're based on the corre- + sponding maximum field. Percentage highlight rules are also + allowed for "experience level" and "experience points" (valid + when the showexp option is enabled). For those, the percentage + is based on the progress from the start of the current experi- + ence level to the start of the next level. So if level 2 + starts at 20 points and level 3 starts at 40 points, having 30 + points is 50% and 35 points is 75%. 100% is unattainable for + experience because you'll gain a level and the calculations + will be reset for that new level, but a rule for =100% is + allowed and matches the special case of being exactly 1 experi- + ence point short of the next level. + + * absolute value sets the attribute when the field value matches + that number. The number must be 0 or higher, except for + "armor-class' which allows negative values, and may optionally + be preceded by `='. If the number is preceded by `<=' or `>=' + instead, it also matches when value is below or above. If the + prefix is `<' or `>', only match when strictly above or below. + + * criticalhp only applies to the hitpoints field and only when current hit points are below a threshold (which varies by maxi- - mum hit points and experience level). When the threshold is - met, a criticalhp rule takes precedence over all other hit- + mum hit points and experience level). When the threshold is + met, a criticalhp rule takes precedence over all other hit- points rules. - * text match sets the attribute when the field value matches the - text. Text matches can only be used for "alignment", "carry- - ing-capacity", "hunger", "dungeon-level", and "title". For - title, only the role's rank title is tested; the character's + + + + NetHack 3.7.0 May 1, 2025 + + + + + + NetHack Guidebook 97 + + + + * text match sets the attribute when the field value matches the + text. Text matches can only be used for "alignment", "carry- + ing-capacity", "hunger", "dungeon-level", and "title". For + title, only the role's rank title is tested; the character's name is ignored. - The in-game options menu can help you determine the correct syn- + The in-game options menu can help you determine the correct syn- tax for a configuration file. The whole feature can be disabled by setting option statushilites @@ -6311,40 +6371,41 @@ NetHack can load entire symbol sets from the symbol file. - The options that are used to select a particular symbol set from + The options that are used to select a particular symbol set from the symbol file are: symset Set the name of the symbol set that you want to load. roguesymset - Set the name of the symbol set that you want to load for display on + Set the name of the symbol set that you want to load for display on the rogue level. - You can also override one or more symbols using the SYMBOLS and - ROGUESYMBOLS configuration file options. Symbols are specified as + You can also override one or more symbols using the SYMBOLS and + ROGUESYMBOLS configuration file options. Symbols are specified as name:value pairs. Note that NetHack escape-processes the value string - in conventional C fashion. This means that \ is a prefix to take the - following character literally. Thus \ needs to be represented as \\. - The special prefix form \m switches on the meta bit in the symbol - value, and the ^ prefix causes the following character to be treated - - - NetHack 3.7.0 December 25, 2024 - - - - - - NetHack Guidebook 97 - - - + in conventional C fashion. This means that \ is a prefix to take the + following character literally. Thus \ needs to be represented as \\. + The special prefix form \m switches on the meta bit in the symbol + value, and the ^ prefix causes the following character to be treated as a control character. NetHack Symbols Symbol Name Description ----------------------------------------------------------------- + + + + NetHack 3.7.0 May 1, 2025 + + + + + + NetHack Guidebook 98 + + + S_air (air) _ S_altar (altar) " S_amulet (amulet) @@ -6393,24 +6454,24 @@ \ S_expl_tr (explosion top right) | S_expl_ml (explosion middle left) S_expl_mc (explosion middle center) - - - - NetHack 3.7.0 December 25, 2024 - - - - - - NetHack Guidebook 98 - - - | S_expl_mr (explosion middle right) \ S_expl_bl (explosion bottom left) - S_expl_bc (explosion bottom center) / S_expl_br (explosion bottom right) e S_eye (eye or sphere) + + + + NetHack 3.7.0 May 1, 2025 + + + + + + NetHack Guidebook 99 + + + ^ S_falling_rock_trap (falling rock trap) f S_feline (cat or other feline) ^ S_fire_trap (fire trap) @@ -6459,24 +6520,24 @@ N S_naga (naga) . S_ndoor (doorway without door) n S_nymph (nymph) - - - - NetHack 3.7.0 December 25, 2024 - - - - - - NetHack Guidebook 99 - - - O S_ogre (ogre) o S_orc (orc) p S_piercer (piercer) ^ S_pit (pit) # S_poisoncloud (poison cloud) + + + + NetHack 3.7.0 May 1, 2025 + + + + + + NetHack Guidebook 100 + + + ^ S_polymorph_trap (polymorph trap) } S_pool (water) ! S_potion (potion) @@ -6525,24 +6586,24 @@ # S_tree (tree) T S_troll (troll) | S_trwall (wall) - - - - NetHack 3.7.0 December 25, 2024 - - - - - - NetHack Guidebook 100 - - - - S_tuwall (wall) U S_umber (umber hulk) S_unexplored (unexplored terrain) u S_unicorn (unicorn or horse) < S_upladder (ladder up) + + + + NetHack 3.7.0 May 1, 2025 + + + + + + NetHack Guidebook 101 + + + < S_upstair (staircase up) V S_vampire (vampire) | S_vbeam (vertical beam [zap animation]) @@ -6571,96 +6632,35 @@ Notes: - * Several symbols in this table appear to be blank. They are the + * Several symbols in this table appear to be blank. They are the space character, except for S_pet_override and S_hero_override which - don't have any default value and can only be used if enabled in the + don't have any default value and can only be used if enabled in the "sysconf" file. - * S_rock is misleadingly named; rocks and stones use S_gem. Statues - and boulders are the rock being referred to, but since version - 3.6.0, statues are displayed as the monster they depict. So S_rock - is only used for boulders and not used at all if overridden by the + * S_rock is misleadingly named; rocks and stones use S_gem. Statues + and boulders are the rock being referred to, but since version + 3.6.0, statues are displayed as the monster they depict. So S_rock + is only used for boulders and not used at all if overridden by the more specific S_boulder. 9.16. Customizing Map Glyph Representations Using Unicode - If your platform or terminal supports the display of UTF-8 char- + If your platform or terminal supports the display of UTF-8 char- acter sequences, you can customize your game display by assigning Uni- - code codepoint values and red-green-blue colors to glyph representa- - tions. The customizations can be specified for use with a symset that - has a UTF8 handler within the symbols file such as the enhanced1 set, + code codepoint values and red-green-blue colors to glyph representa- + tions. The customizations can be specified for use with a symset that + has a UTF8 handler within the symbols file such as the enhanced1 set, or individually within your nethack.rc file. - - - - NetHack 3.7.0 December 25, 2024 - - - - - - NetHack Guidebook 101 - - - The format for defining a glyph representation is: OPTIONS=glyph:glyphid/U+nnnn/R-G-B - The window port that is active needs to provide support for dis- - playing UTF-8 character sequences and explicit red-green-blue colors - in order for the glyph representation to be visible. For example, the - following line in your configuration file will cause the glyph repre- - sentation for glyphid G_pool to use Unicode codepoint U+224B and the - color represented by R-G-B value 0-0-160: - - OPTIONS=glyph:G_pool/U+224B/0-0-160 - - The list of acceptable glyphid's can be produced by nethack --dumpg- - lyphids. Individual NetHack glyphs can be specified using the G_ pre- - fix, or you can use an S_ symbol for a glyphid and store the custom - representation for all NetHack glyphs that would map to that particu- - lar symbol. - - You will need to select a symset with a UTF8 handler to enable - the display of the customizations, such as the Enhanced symset. - - 9.17. Configuring NetHack for Play by the Blind - - NetHack can be set up to use only standard ASCII characters for - making maps of the dungeons. This makes even the MS-DOS versions of - NetHack (which use special line-drawing characters by default) com- - pletely accessible to the blind who use speech and/or Braille access - technologies. Players will require a good working knowledge of their - screen-reader's review features, and will have to know how to navigate - horizontally and vertically character by character. They will also - find the search capabilities of their screen-readers to be quite valu- - able. Be certain to examine this Guidebook before playing so you have - an idea what the screen layout is like. You'll also need to be able to - locate the PC cursor. It is always where your character is located. - Merely searching for an @-sign will not always find your character - since there are other humanoids represented by the same sign. Your - screen-reader should also have a function which gives you the row and - column of your review cursor and the PC cursor. These co-ordinates - are often useful in giving players a better sense of the overall loca- - tion of items on the screen. - - NetHack can also be compiled with support for sending the game - messages to an external program, such as a text-to-speech synthesizer. - If the "#version" extended command shows "external program as a mes- - sage handler", your NetHack has been compiled with the capability. - When compiling NetHack from source on Linux and other POSIX systems, - define MSGHANDLER to enable it. To use the capability, set the envi- - ronment variable NETHACK_MSGHANDLER to an executable, which will be - executed with the game message as the program's only parameter. - - The most crucial settings to make the game more accessible are: + The window port that is active needs to provide support for dis- + playing UTF-8 character sequences and explicit red-green-blue colors - - - NetHack 3.7.0 December 25, 2024 + NetHack 3.7.0 May 1, 2025 @@ -6670,63 +6670,63 @@ + in order for the glyph representation to be visible. For example, the + following line in your configuration file will cause the glyph repre- + sentation for glyphid G_pool to use Unicode codepoint U+224B and the + color represented by R-G-B value 0-0-160: + + OPTIONS=glyph:G_pool/U+224B/0-0-160 + + The list of acceptable glyphid's can be produced by nethack --dumpg- + lyphids. Individual NetHack glyphs can be specified using the G_ pre- + fix, or you can use an S_ symbol for a glyphid and store the custom + representation for all NetHack glyphs that would map to that particu- + lar symbol. + + You will need to select a symset with a UTF8 handler to enable + the display of the customizations, such as the Enhanced symset. + + 9.17. Configuring NetHack for Play by the Blind + + NetHack can be set up to use only standard ASCII characters for + making maps of the dungeons. This makes even the MS-DOS versions of + NetHack (which use special line-drawing characters by default) com- + pletely accessible to the blind who use speech and/or Braille access + technologies. Players will require a good working knowledge of their + screen-reader's review features, and will have to know how to navigate + horizontally and vertically character by character. They will also + find the search capabilities of their screen-readers to be quite valu- + able. Be certain to examine this Guidebook before playing so you have + an idea what the screen layout is like. You'll also need to be able to + locate the PC cursor. It is always where your character is located. + Merely searching for an @-sign will not always find your character + since there are other humanoids represented by the same sign. Your + screen-reader should also have a function which gives you the row and + column of your review cursor and the PC cursor. These co-ordinates + are often useful in giving players a better sense of the overall loca- + tion of items on the screen. + + NetHack can also be compiled with support for sending the game + messages to an external program, such as a text-to-speech synthesizer. + If the "#version" extended command shows "external program as a mes- + sage handler", your NetHack has been compiled with the capability. + When compiling NetHack from source on Linux and other POSIX systems, + define MSGHANDLER to enable it. To use the capability, set the envi- + ronment variable NETHACK_MSGHANDLER to an executable, which will be + executed with the game message as the program's only parameter. + + The most crucial settings to make the game more accessible are: + symset:plain Load a symbol set appropriate for use by blind players. menustyle:traditional This will assist in the interface to speech synthesizers. - nomenu_overlay - Show menus on a cleared screen and aligned to the left edge. - - number_pad - A lot of speech access programs use the number-pad to review the - screen. If this is the case, disable the number_pad option and use - the traditional Rogue-like commands. - - paranoid_confirmation:swim - Prevent walking into water or lava. - - accessiblemsg - Adds direction or location information to messages. - - spot_monsters - Shows a message when hero notices a monster; combine with accessi- - blemsg. - - mon_movement - Shows a message when hero notices a monster movement; combine with - spot_monsters and accessiblemsg. - - autodescribe - Automatically describe the terrain under the cursor when targeting. - - mention_map - Give feedback messages when interesting map locations change. - - mention_walls - Give feedback messages when walking towards a wall or when travel - command was interrupted. - - whatis_coord:compass - When targeting with cursor, describe the cursor position with coor- - dinates relative to your character. - - whatis_filter:area - When targeting with cursor, filter possible locations so only those - in the same area (eg. same room, or same corridor) are considered. - - whatis_moveskip - When targeting with cursor and using fast-move, skip the same glyphs - instead of moving 8 units at a time. - - nostatus_updates - Prevent updates to the status lines at the bottom of the screen, if - your screen-reader reads those lines. The same information can be - seen via the "#attributes" command. - NetHack 3.7.0 December 25, 2024 + + NetHack 3.7.0 May 1, 2025 @@ -6736,63 +6736,63 @@ + nomenu_overlay + Show menus on a cleared screen and aligned to the left edge. + + number_pad + A lot of speech access programs use the number-pad to review the + screen. If this is the case, disable the number_pad option and use + the traditional Rogue-like commands. + + paranoid_confirmation:swim + Prevent walking into water or lava. + + accessiblemsg + Adds direction or location information to messages. + + spot_monsters + Shows a message when hero notices a monster; combine with accessi- + blemsg. + + mon_movement + Shows a message when hero notices a monster movement; combine with + spot_monsters and accessiblemsg. + + autodescribe + Automatically describe the terrain under the cursor when targeting. + + mention_map + Give feedback messages when interesting map locations change. + + mention_walls + Give feedback messages when walking towards a wall or when travel + command was interrupted. + + whatis_coord:compass + When targeting with cursor, describe the cursor position with coor- + dinates relative to your character. + + whatis_filter:area + When targeting with cursor, filter possible locations so only those + in the same area (eg. same room, or same corridor) are considered. + + whatis_moveskip + When targeting with cursor and using fast-move, skip the same glyphs + instead of moving 8 units at a time. + + nostatus_updates + Prevent updates to the status lines at the bottom of the screen, if + your screen-reader reads those lines. The same information can be + seen via the "#attributes" command. + showdamage Give a message of damage taken and how many hit points are left. - 9.18. Global Configuration for System Administrators - - If NetHack is compiled with the SYSCF option, a system adminis- - trator should set up a global configuration; this is a file in the - same format as the traditional per-user configuration file (see - above). This file should be named sysconf and placed in the same - directory as the other NetHack support files. The options recognized - in this file are listed below. Any option not set uses a compiled-in - default (which may not be appropriate for your system). - - WIZARDS = A space-separated list of user names who are allowed to - play in debug mode (commonly referred to as wizard mode). A value - of a single asterisk (*) allows anyone to start a game in debug - mode. - - SHELLERS = A list of users who are allowed to use the shell escape - command (!). The syntax is the same as WIZARDS. - - EXPLORERS = A list of users who are allowed to use the explore mode. - The syntax is the same as WIZARDS. - - MSGHANDLER = A path and filename of executable. Whenever a message- - window message is shown, NetHack runs this program. The program - will get the message as the only parameter. - - MAXPLAYERS = Limit the maximum number of games that can be running - at the same time. - - SAVEFORMAT = A list of up to two save file formats separated by - space. The first format in the list will written as well as read. - The second format will be read only if no save file in the first - format exists. Valid choices are "historical" for binary writing of - entire structs, "lendian" for binary writing of each field in lit- - tle-endian order, "ascii" for writing the save file content in ascii - text. - - BONESFORMAT = A list of up to two bones file formats separated by - space. The first format in the list will written as well as read. - The second format will be read only if no bones files in the first - format exist. Valid choices are "historical" for binary writing of - entire structs, "lendian" for binary writing of each field in lit- - tle-endian order, "ascii" for writing the bones file content in - ascii text. - - SUPPORT = A string explaining how to get local support (no default - value). - - RECOVER = A string explaining how to recover a game on this system - (no default value). - NetHack 3.7.0 December 25, 2024 + NetHack 3.7.0 May 1, 2025 @@ -6802,14 +6802,48 @@ - SEDUCE = 0 or 1 to disable or enable, respectively, the SEDUCE + 9.18. Global Configuration for System Administrators + + If NetHack is compiled with the SYSCF option, a system adminis- + trator should set up a global configuration; this is a file in the + same format as the traditional per-user configuration file (see + above). This file should be named sysconf and placed in the same + directory as the other NetHack support files. The options recognized + in this file are listed below. Any option not set uses a compiled-in + default (which may not be appropriate for your system). + + WIZARDS = A space-separated list of user names who are allowed to + play in debug mode (commonly referred to as wizard mode). A value + of a single asterisk (*) allows anyone to start a game in debug + mode. + + SHELLERS = A list of users who are allowed to use the shell escape + command (!). The syntax is the same as WIZARDS. + + EXPLORERS = A list of users who are allowed to use the explore mode. + The syntax is the same as WIZARDS. + + MSGHANDLER = A path and filename of executable. Whenever a message- + window message is shown, NetHack runs this program. The program + will get the message as the only parameter. + + MAXPLAYERS = Limit the maximum number of games that can be running + at the same time. + + SUPPORT = A string explaining how to get local support (no default + value). + + RECOVER = A string explaining how to recover a game on this system + (no default value). + + SEDUCE = 0 or 1 to disable or enable, respectively, the SEDUCE option. When disabled, incubi and succubi behave like nymphs. - CHECK_PLNAME = Setting this to 1 will make the EXPLORERS, WIZARDS, - and SHELLERS check for the player name instead of the user's login + CHECK_PLNAME = Setting this to 1 will make the EXPLORERS, WIZARDS, + and SHELLERS check for the player name instead of the user's login name. - CHECK_SAVE_UID = 0 or 1 to disable or enable, respectively, the UID + CHECK_SAVE_UID = 0 or 1 to disable or enable, respectively, the UID (used identification number) checking for save files (to verify that the user who is restoring is the same one who saved). @@ -6819,28 +6853,40 @@ ENTRYMAX = Maximum number of entries in the score file. - POINTSMIN = Minimum number of points to get an entry in the score + POINTSMIN = Minimum number of points to get an entry in the score file. - PERS_IS_UID = 0 or 1 to use user names or numeric userids, respec- + + + NetHack 3.7.0 May 1, 2025 + + + + + + NetHack Guidebook 105 + + + + PERS_IS_UID = 0 or 1 to use user names or numeric userids, respec- tively, to identify unique people for the score file. - HIDEUSAGE = 0 or 1 to control whether the help menu entry for com- + HIDEUSAGE = 0 or 1 to control whether the help menu entry for com- mand line usage is shown or suppressed. - MAX_STATUENAME_RANK = Maximum number of score file entries to use + MAX_STATUENAME_RANK = Maximum number of score file entries to use for random statue names (default is 10). ACCESSIBILITY = 0 or 1 to disable or enable, respectively, the abil- ity for players to set S_pet_override and S_hero_override symbols in their configuration file. - PORTABLE_DEVICE_PATHS = 0 or 1 Windows OS only, the game will look - for all of its external files, and write to all of its output files + PORTABLE_DEVICE_PATHS = 0 or 1 Windows OS only, the game will look + for all of its external files, and write to all of its output files in one place rather than at the standard locations. - DUMPLOGFILE = A filename where the end-of-game dumplog is saved. - Not defining this will prevent dumplog from being created. Only + DUMPLOGFILE = A filename where the end-of-game dumplog is saved. + Not defining this will prevent dumplog from being created. Only available if your game is compiled with DUMPLOG. Allows the follow- ing placeholders: @@ -6854,77 +6900,31 @@ %n - player name %N - first character of player name - LIVELOG = A bit-mask of types of events that should be written to - the livelog file if one is present. The sample sysconf file accom- - - - NetHack 3.7.0 December 25, 2024 - - - - - - NetHack Guidebook 105 - - - - panying the program contains a comment which lists the meaning of - the various bits used. Intended for server systems supporting + LIVELOG = A bit-mask of types of events that should be written to + the livelog file if one is present. The sample sysconf file accom- + panying the program contains a comment which lists the meaning of + the various bits used. Intended for server systems supporting simultaneous play by multiple players (to be clear, each one running - a separate single player game), for displaying their game progress - to observers. Only relevant if the program was built with LIVELOG - enabled. When available, it should be left commented out on single - player installations because over time the file could grow to be + a separate single player game), for displaying their game progress + to observers. Only relevant if the program was built with LIVELOG + enabled. When available, it should be left commented out on single + player installations because over time the file could grow to be extremely large unless it is actively maintained. CRASHREPORTURL = If set to https://www.nethack.org/links/cr-37BETA.html and support is compiled - in, brings up a browser window pre-populated with the information - needed to report a problem if the game panics or ends up in an - internally inconsistent state, or if the #bugreport command is + in, brings up a browser window pre-populated with the information + needed to report a problem if the game panics or ends up in an + internally inconsistent state, or if the #bugreport command is invoked. 10. Scoring - NetHack maintains a list of the top scores or scorers on your - machine, depending on how it is set up. In the latter case, each - account on the machine can post only one non-winning score on this - list. If you score higher than someone else on this list, or better - your previous score, you will be inserted in the proper place under - your current name. How many scores are kept can also be set up when - NetHack is compiled. - - Your score is chiefly based upon how much experience you gained, - how much loot you accumulated, how deep you explored, and how the game - ended. If you quit the game, you escape with all of your gold intact. - If, however, you get killed in the Mazes of Menace, the guild will - only hear about 90% of your gold when your corpse is discovered - (adventurers have been known to collect finder's fees). So, consider - whether you want to take one last hit at that monster and possibly - live, or quit and stop with whatever you have. If you quit, you keep - all your gold, but if you swing and live, you might find more. - - If you just want to see what the current top players/games list - is, you can type nethack -s all on most versions. - - 11. Explore mode - - NetHack is an intricate and difficult game. Novices might falter - in fear, aware of their ignorance of the means to survive. Well, fear - not. Your dungeon comes equipped with an "explore" or "discovery" - mode that enables you to keep old save files and cheat death, at the - paltry cost of not getting on the high score list. - - There are two ways of enabling explore mode. One is to start the - game with the -X command-line switch or with the playmode:explore - option. The other is to issue the "#exploremode" extended command - while already playing the game. Starting a new game in explore mode - provides your character with a wand of wishing in initial inventory; - switching during play does not. The other benefits of explore mode - are left for the trepid reader to discover. + NetHack maintains a list of the top scores or scorers on your + machine, depending on how it is set up. In the latter case, each - NetHack 3.7.0 December 25, 2024 + NetHack 3.7.0 May 1, 2025 @@ -6934,63 +6934,63 @@ + account on the machine can post only one non-winning score on this + list. If you score higher than someone else on this list, or better + your previous score, you will be inserted in the proper place under + your current name. How many scores are kept can also be set up when + NetHack is compiled. + + Your score is chiefly based upon how much experience you gained, + how much loot you accumulated, how deep you explored, and how the game + ended. If you quit the game, you escape with all of your gold intact. + If, however, you get killed in the Mazes of Menace, the guild will + only hear about 90% of your gold when your corpse is discovered + (adventurers have been known to collect finder's fees). So, consider + whether you want to take one last hit at that monster and possibly + live, or quit and stop with whatever you have. If you quit, you keep + all your gold, but if you swing and live, you might find more. + + If you just want to see what the current top players/games list + is, you can type nethack -s all on most versions. + + 11. Explore mode + + NetHack is an intricate and difficult game. Novices might falter + in fear, aware of their ignorance of the means to survive. Well, fear + not. Your dungeon comes equipped with an "explore" or "discovery" + mode that enables you to keep old save files and cheat death, at the + paltry cost of not getting on the high score list. + + There are two ways of enabling explore mode. One is to start the + game with the -X command-line switch or with the playmode:explore + option. The other is to issue the "#exploremode" extended command + while already playing the game. Starting a new game in explore mode + provides your character with a wand of wishing in initial inventory; + switching during play does not. The other benefits of explore mode + are left for the trepid reader to discover. + 11.1. Debug mode Debug mode, also known as wizard mode, is undocumented aside from - this brief description and the various "debug mode only" commands - listed among the command descriptions. It is intended for tracking - down problems within the program rather than to provide god-like pow- - ers to your character, and players who attempt debugging are expected - to figure out how to use it themselves. It is initiated by starting - the game with the -D command-line switch or with the playmode:debug + this brief description and the various "debug mode only" commands + listed among the command descriptions. It is intended for tracking + down problems within the program rather than to provide god-like pow- + ers to your character, and players who attempt debugging are expected + to figure out how to use it themselves. It is initiated by starting + the game with the -D command-line switch or with the playmode:debug option. For some systems, the player must be logged in under a particular - user name to be allowed to use debug mode; for others, the hero must - be given a particular character name (but may be any role; there's no - connection between "wizard mode" and the Wizard role). Attempting to - start a game in debug mode when not allowed or not available will + user name to be allowed to use debug mode; for others, the hero must + be given a particular character name (but may be any role; there's no + connection between "wizard mode" and the Wizard role). Attempting to + start a game in debug mode when not allowed or not available will result in falling back to explore mode instead. - 12. Credits - - The original hack game was modeled on the Berkeley UNIX rogue - game. Large portions of this document were shamelessly cribbed from A - Guide to the Dungeons of Doom, by Michael C. Toy and Kenneth C. R. C. - Arnold. Small portions were adapted from Further Exploration of the - Dungeons of Doom, by Ken Arromdee. - - NetHack is the product of literally scores of people's work. - Main events in the course of the game development are described below: - - Jay Fenlason wrote the original Hack, with help from Kenny Wood- - land, Mike Thome, and Jon Payne. - - Andries Brouwer did a major re-write while at Stichting Mathema- - tisch Centrum (now Centrum Wiskunde & Informatica), transforming Hack - into a very different game. He published the Hack source code for use - on UNIX systems by posting that to Usenet newsgroup net.sources (later - renamed comp.sources) releasing version 1.0 in December of 1984, then - versions 1.0.1, 1.0.2, and finally 1.0.3 in July of 1985. Usenet - newsgroup net.games.hack (later renamed rec.games.hack, eventually - replaced by rec.games.roguelike.nethack) was created for discussing - it. - - Don G. Kneller ported Hack 1.0.3 to Microsoft C and MS-DOS, pro- - ducing PC HACK 1.01e, added support for DEC Rainbow graphics in ver- - sion 1.03g, and went on to produce at least four more versions (3.0, - 3.2, 3.51, and 3.6; note that these are old Hack version numbers, not - contemporary NetHack ones). - - R. Black ported PC HACK 3.51 to Lattice C and the Atari - 520/1040ST, producing ST Hack 1.03. - - Mike Stephenson merged these various versions back together, - incorporating many of the added features, and produced NetHack version - 1.4 in 1987. He then coordinated a cast of thousands in enhancing and - NetHack 3.7.0 December 25, 2024 + + NetHack 3.7.0 May 1, 2025 @@ -7000,63 +7000,63 @@ + 12. Credits + + The original hack game was modeled on the Berkeley UNIX rogue + game. Large portions of this document were shamelessly cribbed from A + Guide to the Dungeons of Doom, by Michael C. Toy and Kenneth C. R. C. + Arnold. Small portions were adapted from Further Exploration of the + Dungeons of Doom, by Ken Arromdee. + + NetHack is the product of literally scores of people's work. + Main events in the course of the game development are described below: + + Jay Fenlason wrote the original Hack, with help from Kenny Wood- + land, Mike Thome, and Jon Payne. + + Andries Brouwer did a major re-write while at Stichting Mathema- + tisch Centrum (now Centrum Wiskunde & Informatica), transforming Hack + into a very different game. He published the Hack source code for use + on UNIX systems by posting that to Usenet newsgroup net.sources (later + renamed comp.sources) releasing version 1.0 in December of 1984, then + versions 1.0.1, 1.0.2, and finally 1.0.3 in July of 1985. Usenet + newsgroup net.games.hack (later renamed rec.games.hack, eventually + replaced by rec.games.roguelike.nethack) was created for discussing + it. + + Don G. Kneller ported Hack 1.0.3 to Microsoft C and MS-DOS, pro- + ducing PC HACK 1.01e, added support for DEC Rainbow graphics in ver- + sion 1.03g, and went on to produce at least four more versions (3.0, + 3.2, 3.51, and 3.6; note that these are old Hack version numbers, not + contemporary NetHack ones). + + R. Black ported PC HACK 3.51 to Lattice C and the Atari + 520/1040ST, producing ST Hack 1.03. + + Mike Stephenson merged these various versions back together, + incorporating many of the added features, and produced NetHack version + 1.4 in 1987. He then coordinated a cast of thousands in enhancing and debugging NetHack 1.4 and released NetHack versions 2.2 and 2.3. Like - Hack, they were released by posting their source code to Usenet where - they remained available in various archives accessible via ftp and + Hack, they were released by posting their source code to Usenet where + they remained available in various archives accessible via ftp and uucp after expiring from the newsgroup. - Later, Mike coordinated a major re-write of the game, heading a + Later, Mike coordinated a major re-write of the game, heading a team which included Ken Arromdee, Jean-Christophe Collet, Steve Creps, - Eric Hendrickson, Izchak Miller, Eric S. Raymond, John Rupley, Mike + Eric Hendrickson, Izchak Miller, Eric S. Raymond, John Rupley, Mike Threepoint, and Janet Walz, to produce NetHack 3.0c. - NetHack 3.0 was ported to the Atari by Eric R. Smith, to OS/2 by - Timo Hakulinen, and to VMS by David Gentzel. The three of them and - Kevin Darcy later joined the main NetHack Development Team to produce + NetHack 3.0 was ported to the Atari by Eric R. Smith, to OS/2 by + Timo Hakulinen, and to VMS by David Gentzel. The three of them and + Kevin Darcy later joined the main NetHack Development Team to produce subsequent revisions of 3.0. - Olaf Seibert ported NetHack 2.3 and 3.0 to the Amiga. Norm - Meluch, Stephen Spackman and Pierre Martineau designed overlay code - for PC NetHack 3.0. Johnny Lee ported NetHack 3.0 to the Macintosh. - Along with various other Dungeoneers, they continued to enhance the - PC, Macintosh, and Amiga ports through the later revisions of 3.0. - - Version 3.0 went through ten relatively rapidly released "patch- - level" revisions. Versions at the time were known as 3.0 for the base - release and variously as "3.0a" through "3.0j", "3.0 patchlevel 1" - through "3.0 patchlevel 10", or "3.0pl1" through "3.0pl10" rather than - 3.0.0 and 3.0.1 through 3.0.10; the three component numbering scheme - began to be used with 3.1.0. - - Headed by Mike Stephenson and coordinated by Izchak Miller and - Janet Walz, the NetHack Development Team which now included Ken - Arromdee, David Cohrs, Jean-Christophe Collet, Kevin Darcy, Matt Day, - Timo Hakulinen, Steve Linhart, Dean Luick, Pat Rankin, Eric Raymond, - and Eric Smith undertook a radical revision of 3.0. They re-struc- - tured the game's design, and re-wrote major parts of the code. They - added multiple dungeons, a new display, special individual character - quests, a new endgame and many other new features, and produced - NetHack 3.1. Version 3.1.0 was released in January of 1993. - - Ken Lorber, Gregg Wonderly and Greg Olson, with help from Richard - Addison, Mike Passaretti, and Olaf Seibert, developed NetHack 3.1 for - the Amiga. - - Norm Meluch and Kevin Smolkowski, with help from Carl Schelin, - Stephen Spackman, Steve VanDevender, and Paul Winner, ported NetHack - 3.1 to the PC. - - Jon W{tte and Hao-yang Wang, with help from Ross Brown, Mike Eng- - ber, David Hairston, Michael Hamel, Jonathan Handler, Johnny Lee, Tim - Lennan, Rob Menke, and Andy Swanson, developed NetHack 3.1 for the - Macintosh, porting it for MPW. Building on their development, Bart - House added a Think C port. - - Timo Hakulinen ported NetHack 3.1 to OS/2. Eric Smith ported - NetHack 3.1 to the Atari. Pat Rankin, with help from Joshua + Olaf Seibert ported NetHack 2.3 and 3.0 to the Amiga. Norm + Meluch, Stephen Spackman and Pierre Martineau designed overlay code + for PC NetHack 3.0. Johnny Lee ported NetHack 3.0 to the Macintosh. - NetHack 3.7.0 December 25, 2024 + NetHack 3.7.0 May 1, 2025 @@ -7066,63 +7066,63 @@ - Delahunty, was responsible for the VMS version of NetHack 3.1. + Along with various other Dungeoneers, they continued to enhance the + PC, Macintosh, and Amiga ports through the later revisions of 3.0. + + Version 3.0 went through ten relatively rapidly released "patch- + level" revisions. Versions at the time were known as 3.0 for the base + release and variously as "3.0a" through "3.0j", "3.0 patchlevel 1" + through "3.0 patchlevel 10", or "3.0pl1" through "3.0pl10" rather than + 3.0.0 and 3.0.1 through 3.0.10; the three component numbering scheme + began to be used with 3.1.0. + + Headed by Mike Stephenson and coordinated by Izchak Miller and + Janet Walz, the NetHack Development Team which now included Ken + Arromdee, David Cohrs, Jean-Christophe Collet, Kevin Darcy, Matt Day, + Timo Hakulinen, Steve Linhart, Dean Luick, Pat Rankin, Eric Raymond, + and Eric Smith undertook a radical revision of 3.0. They re-struc- + tured the game's design, and re-wrote major parts of the code. They + added multiple dungeons, a new display, special individual character + quests, a new endgame and many other new features, and produced + NetHack 3.1. Version 3.1.0 was released in January of 1993. + + Ken Lorber, Gregg Wonderly and Greg Olson, with help from Richard + Addison, Mike Passaretti, and Olaf Seibert, developed NetHack 3.1 for + the Amiga. + + Norm Meluch and Kevin Smolkowski, with help from Carl Schelin, + Stephen Spackman, Steve VanDevender, and Paul Winner, ported NetHack + 3.1 to the PC. + + Jon W{tte and Hao-yang Wang, with help from Ross Brown, Mike Eng- + ber, David Hairston, Michael Hamel, Jonathan Handler, Johnny Lee, Tim + Lennan, Rob Menke, and Andy Swanson, developed NetHack 3.1 for the + Macintosh, porting it for MPW. Building on their development, Bart + House added a Think C port. + + Timo Hakulinen ported NetHack 3.1 to OS/2. Eric Smith ported + NetHack 3.1 to the Atari. Pat Rankin, with help from Joshua + Delahunty, was responsible for the VMS version of NetHack 3.1. Michael Allison ported NetHack 3.1 to Windows NT. Dean Luick, with help from David Cohrs, developed NetHack 3.1 for - X11. It drew the map as text rather than graphically but included - nh10.bdf, an optionally used custom X11 font which has tiny images in - place of letters and punctuation, a precursor of tiles. Those images + X11. It drew the map as text rather than graphically but included + nh10.bdf, an optionally used custom X11 font which has tiny images in + place of letters and punctuation, a precursor of tiles. Those images don't extend to individual monster and object types, just replacements - for monster and object classes (so one custom image for all "a" - insects and another for all "[" armor and so forth, not separate + for monster and object classes (so one custom image for all "a" + insects and another for all "[" armor and so forth, not separate images for beetles and ants or for cloaks and boots). - Warwick Allison wrote a graphically displayed version of NetHack - for the Atari where the tiny pictures were described as "icons" and - were distinct for specific types of monsters and objects rather than - just their classes. He contributed them to the NetHack Development - Team which rechristened them "tiles", original usage which has subse- - quently been picked up by various other games. NetHack's tiles sup- - port was then implemented on other platforms (initially MS-DOS but - eventually Windows, Qt, and X11 too). - - The 3.2 NetHack Development Team, comprised of Michael Allison, - Ken Arromdee, David Cohrs, Jessie Collet, Steve Creps, Kevin Darcy, - Timo Hakulinen, Steve Linhart, Dean Luick, Pat Rankin, Eric Smith, - Mike Stephenson, Janet Walz, and Paul Winner, released version 3.2.0 - in April of 1996. - - Version 3.2 marked the tenth anniversary of the formation of the - development team. In a testament to their dedication to the game, all - thirteen members of the original NetHack Development Team remained on - the team at the start of work on that release. During the interval - between the release of 3.1.3 and 3.2.0, one of the founding members of - the NetHack Development Team, Dr. Izchak Miller, was diagnosed with - cancer and passed away. That release of the game was dedicated to him - by the development and porting teams. - - Version 3.2 proved to be more stable than previous versions. - Many bugs were fixed, abuses eliminated, and game features tuned for - better game play. - - During the lifespan of NetHack 3.1 and 3.2, several enthusiasts - of the game added their own modifications to the game and made these - "variants" publicly available: - - Tom Proudfoot and Yuval Oren created NetHack++, which was quickly - renamed NetHack-- when some people incorrectly assumed that it was a - conversion of the C source code to C++. Working independently, - Stephen White wrote NetHack Plus. Tom Proudfoot later merged NetHack - Plus and his own NetHack-- to produce SLASH. Larry Stewart-Zerba and - Warwick Allison improved the spell casting system with the Wizard - Patch. Warwick Allison also ported NetHack to use the Qt interface. - - Warren Cheung combined SLASH with the Wizard Patch to produce - Slash'EM, and with the help of Kevin Hugo, added more features. Kevin + Warwick Allison wrote a graphically displayed version of NetHack + for the Atari where the tiny pictures were described as "icons" and + were distinct for specific types of monsters and objects rather than + just their classes. He contributed them to the NetHack Development + Team which rechristened them "tiles", original usage which has subse- + quently been picked up by various other games. NetHack's tiles sup- - NetHack 3.7.0 December 25, 2024 + NetHack 3.7.0 May 1, 2025 @@ -7132,63 +7132,63 @@ + port was then implemented on other platforms (initially MS-DOS but + eventually Windows, Qt, and X11 too). + + The 3.2 NetHack Development Team, comprised of Michael Allison, + Ken Arromdee, David Cohrs, Jessie Collet, Steve Creps, Kevin Darcy, + Timo Hakulinen, Steve Linhart, Dean Luick, Pat Rankin, Eric Smith, + Mike Stephenson, Janet Walz, and Paul Winner, released version 3.2.0 + in April of 1996. + + Version 3.2 marked the tenth anniversary of the formation of the + development team. In a testament to their dedication to the game, all + thirteen members of the original NetHack Development Team remained on + the team at the start of work on that release. During the interval + between the release of 3.1.3 and 3.2.0, one of the founding members of + the NetHack Development Team, Dr. Izchak Miller, was diagnosed with + cancer and passed away. That release of the game was dedicated to him + by the development and porting teams. + + Version 3.2 proved to be more stable than previous versions. + Many bugs were fixed, abuses eliminated, and game features tuned for + better game play. + + During the lifespan of NetHack 3.1 and 3.2, several enthusiasts + of the game added their own modifications to the game and made these + "variants" publicly available: + + Tom Proudfoot and Yuval Oren created NetHack++, which was quickly + renamed NetHack-- when some people incorrectly assumed that it was a + conversion of the C source code to C++. Working independently, + Stephen White wrote NetHack Plus. Tom Proudfoot later merged NetHack + Plus and his own NetHack-- to produce SLASH. Larry Stewart-Zerba and + Warwick Allison improved the spell casting system with the Wizard + Patch. Warwick Allison also ported NetHack to use the Qt interface. + + Warren Cheung combined SLASH with the Wizard Patch to produce + Slash'EM, and with the help of Kevin Hugo, added more features. Kevin later joined the NetHack Development Team and incorporated the best of these ideas into NetHack 3.3. - The final update to 3.2 was the bug fix release 3.2.3, which was - released simultaneously with 3.3.0 in December 1999 just in time for - the Year 2000. Because of the newer version, 3.2.3 was released as a - source code patch only, without any ready-to-play distribution for + The final update to 3.2 was the bug fix release 3.2.3, which was + released simultaneously with 3.3.0 in December 1999 just in time for + the Year 2000. Because of the newer version, 3.2.3 was released as a + source code patch only, without any ready-to-play distribution for systems that usually had such. (To anyone considering resurrecting an old version: all versions - before 3.2.3 had a Y2K bug. The high scores file and the log file - contained dates which were formatted using a two-digit year, and - 1999's year 99 was followed by 2000's year 100. That got written out - successfully but it unintentionally introduced an extra column in the + before 3.2.3 had a Y2K bug. The high scores file and the log file + contained dates which were formatted using a two-digit year, and + 1999's year 99 was followed by 2000's year 100. That got written out + successfully but it unintentionally introduced an extra column in the file layout which prevented score entries from being read back in cor- - rectly, interfering with insertion of new high scores and with - retrieval of old character names to use for random ghost and statue + rectly, interfering with insertion of new high scores and with + retrieval of old character names to use for random ghost and statue names in the current game.) - The 3.3 NetHack Development Team, consisting of Michael Allison, - Ken Arromdee, David Cohrs, Jessie Collet, Steve Creps, Kevin Darcy, - Timo Hakulinen, Kevin Hugo, Steve Linhart, Ken Lorber, Dean Luick, Pat - Rankin, Eric Smith, Mike Stephenson, Janet Walz, and Paul Winner, - released 3.3.0 in December 1999 and 3.3.1 in August of 2000. - Version 3.3 offered many firsts. It was the first version to sep- - arate race and profession. The Elf class was removed in preference to - an elf race, and the races of dwarves, gnomes, and orcs made their - first appearance in the game alongside the familiar human race. Monk - and Ranger roles joined Archeologists, Barbarians, Cavemen, Healers, - Knights, Priests, Rogues, Samurai, Tourists, Valkyries and of course, - Wizards. It was also the first version to allow you to ride a steed, - and was the first version to have a publicly available web-site list- - ing all the bugs that had been discovered. Despite that constantly - growing bug list, 3.3 proved stable enough to last for more than a - year and a half. - - The 3.4 NetHack Development Team initially consisted of Michael - Allison, Ken Arromdee, David Cohrs, Jessie Collet, Kevin Hugo, Ken - Lorber, Dean Luick, Pat Rankin, Mike Stephenson, Janet Walz, and Paul - Winner, with Warwick Allison joining just before the release of - NetHack 3.4.0 in March 2002. - - As with version 3.3, various people contributed to the game as a - whole as well as supporting ports on the different platforms that - NetHack runs on: - - Pat Rankin maintained 3.4 for VMS. - - Michael Allison maintained NetHack 3.4 for the MS-DOS platform. - Paul Winner and Yitzhak Sapir provided encouragement. - - Dean Luick, Mark Modrall, and Kevin Hugo maintained and enhanced - the Macintosh port of 3.4. - - - NetHack 3.7.0 December 25, 2024 + NetHack 3.7.0 May 1, 2025 @@ -7198,63 +7198,63 @@ - Michael Allison, David Cohrs, Alex Kompel, Dion Nicolaas, and - Yitzhak Sapir maintained and enhanced 3.4 for the Microsoft Windows - platform. Alex Kompel contributed a new graphical interface for the - Windows port. Alex Kompel also contributed a Windows CE port for + The 3.3 NetHack Development Team, consisting of Michael Allison, + Ken Arromdee, David Cohrs, Jessie Collet, Steve Creps, Kevin Darcy, + Timo Hakulinen, Kevin Hugo, Steve Linhart, Ken Lorber, Dean Luick, Pat + Rankin, Eric Smith, Mike Stephenson, Janet Walz, and Paul Winner, + released 3.3.0 in December 1999 and 3.3.1 in August of 2000. + + Version 3.3 offered many firsts. It was the first version to sep- + arate race and profession. The Elf class was removed in preference to + an elf race, and the races of dwarves, gnomes, and orcs made their + first appearance in the game alongside the familiar human race. Monk + and Ranger roles joined Archeologists, Barbarians, Cavemen, Healers, + Knights, Priests, Rogues, Samurai, Tourists, Valkyries and of course, + Wizards. It was also the first version to allow you to ride a steed, + and was the first version to have a publicly available web-site list- + ing all the bugs that had been discovered. Despite that constantly + growing bug list, 3.3 proved stable enough to last for more than a + year and a half. + + The 3.4 NetHack Development Team initially consisted of Michael + Allison, Ken Arromdee, David Cohrs, Jessie Collet, Kevin Hugo, Ken + Lorber, Dean Luick, Pat Rankin, Mike Stephenson, Janet Walz, and Paul + Winner, with Warwick Allison joining just before the release of + NetHack 3.4.0 in March 2002. + + As with version 3.3, various people contributed to the game as a + whole as well as supporting ports on the different platforms that + NetHack runs on: + + Pat Rankin maintained 3.4 for VMS. + + Michael Allison maintained NetHack 3.4 for the MS-DOS platform. + Paul Winner and Yitzhak Sapir provided encouragement. + + Dean Luick, Mark Modrall, and Kevin Hugo maintained and enhanced + the Macintosh port of 3.4. + + Michael Allison, David Cohrs, Alex Kompel, Dion Nicolaas, and + Yitzhak Sapir maintained and enhanced 3.4 for the Microsoft Windows + platform. Alex Kompel contributed a new graphical interface for the + Windows port. Alex Kompel also contributed a Windows CE port for 3.4.1. - Ron Van Iwaarden was the sole maintainer of NetHack for OS/2 the - past several releases. Unfortunately Ron's last OS/2 machine stopped - working in early 2006. A great many thanks to Ron for keeping NetHack + Ron Van Iwaarden was the sole maintainer of NetHack for OS/2 the + past several releases. Unfortunately Ron's last OS/2 machine stopped + working in early 2006. A great many thanks to Ron for keeping NetHack alive on OS/2 all these years. - Janne Salmijarvi and Teemu Suikki maintained and enhanced the + Janne Salmijarvi and Teemu Suikki maintained and enhanced the Amiga port of 3.4 after Janne Salmijarvi resurrected it for 3.3.1. Christian "Marvin" Bressler maintained 3.4 for the Atari after he resurrected it for 3.3.1. - The release of NetHack 3.4.3 in December 2003 marked the begin- - ning of a long release hiatus. 3.4.3 proved to be a remarkably stable - version that provided continued enjoyment by the community for more - than a decade. The NetHack Development Team slowly and quietly contin- - ued to work on the game behind the scenes during the tenure of 3.4.3. - It was during that same period that several new variants emerged - within the NetHack community. Notably sporkhack by Derek S. Ray, - unnethack by Patric Mueller, nitrohack and its successors originally - by Daniel Thaler and then by Alex Smith, and Dynahack by Tung Nguyen. - Some of those variants continue to be developed, maintained, and - enjoyed by the community to this day. - - In September 2014, an interim snapshot of the code under develop- - ment was released publicly by other parties. Since that code was a - work-in-progress and had not gone through the process of debugging it - as a suitable release, it was decided that the version numbers present - on that code snapshot would be retired and never used in an official - NetHack release. An announcement was posted on the NetHack Develop- - ment Team's official nethack.org website to that effect, stating that - there would never be a 3.4.4, 3.5, or 3.5.0 official release version. - - In January 2015, preparation began for the release of NetHack - 3.6. - - At the beginning of development for what would eventually get - released as 3.6.0, the NetHack Development Team consisted of Warwick - Allison, Michael Allison, Ken Arromdee, David Cohrs, Jessie Collet, - Ken Lorber, Dean Luick, Pat Rankin, Mike Stephenson, Janet Walz, and - Paul Winner. In early 2015, ahead of the release of 3.6.0, new mem- - bers Sean Hunt, Pasi Kallinen, and Derek S. Ray joined the NetHack - Development Team. - - Near the end of the development of 3.6.0, one of the significant - inspirations for many of the humorous and fun features found in the - game, author Terry Pratchett, passed away. NetHack 3.6.0 introduced a - tribute to him. - NetHack 3.7.0 December 25, 2024 + NetHack 3.7.0 May 1, 2025 @@ -7264,63 +7264,63 @@ - 3.6.0 was released in December 2015, and merged work done by the - development team since the release of 3.4.3 with some of the beloved - community patches. Many bugs were fixed and some code was restruc- + The release of NetHack 3.4.3 in December 2003 marked the begin- + ning of a long release hiatus. 3.4.3 proved to be a remarkably stable + version that provided continued enjoyment by the community for more + than a decade. The NetHack Development Team slowly and quietly contin- + ued to work on the game behind the scenes during the tenure of 3.4.3. + It was during that same period that several new variants emerged + within the NetHack community. Notably sporkhack by Derek S. Ray, + unnethack by Patric Mueller, nitrohack and its successors originally + by Daniel Thaler and then by Alex Smith, and Dynahack by Tung Nguyen. + Some of those variants continue to be developed, maintained, and + enjoyed by the community to this day. + + In September 2014, an interim snapshot of the code under develop- + ment was released publicly by other parties. Since that code was a + work-in-progress and had not gone through the process of debugging it + as a suitable release, it was decided that the version numbers present + on that code snapshot would be retired and never used in an official + NetHack release. An announcement was posted on the NetHack Develop- + ment Team's official nethack.org website to that effect, stating that + there would never be a 3.4.4, 3.5, or 3.5.0 official release version. + + In January 2015, preparation began for the release of NetHack + 3.6. + + At the beginning of development for what would eventually get + released as 3.6.0, the NetHack Development Team consisted of Warwick + Allison, Michael Allison, Ken Arromdee, David Cohrs, Jessie Collet, + Ken Lorber, Dean Luick, Pat Rankin, Mike Stephenson, Janet Walz, and + Paul Winner. In early 2015, ahead of the release of 3.6.0, new mem- + bers Sean Hunt, Pasi Kallinen, and Derek S. Ray joined the NetHack + Development Team. + + Near the end of the development of 3.6.0, one of the significant + inspirations for many of the humorous and fun features found in the + game, author Terry Pratchett, passed away. NetHack 3.6.0 introduced a + tribute to him. + + 3.6.0 was released in December 2015, and merged work done by the + development team since the release of 3.4.3 with some of the beloved + community patches. Many bugs were fixed and some code was restruc- tured. - The NetHack Development Team, as well as Steve VanDevender and - Kevin Smolkowski, ensured that NetHack 3.6 continued to operate on + The NetHack Development Team, as well as Steve VanDevender and + Kevin Smolkowski, ensured that NetHack 3.6 continued to operate on various UNIX flavors and maintained the X11 interface. - Ken Lorber, Haoyang Wang, Pat Rankin, and Dean Luick maintained + Ken Lorber, Haoyang Wang, Pat Rankin, and Dean Luick maintained the port of NetHack 3.6 for MacOS. - Michael Allison, David Cohrs, Bart House, Pasi Kallinen, Alex - Kompel, Dion Nicolaas, Derek S. Ray and Yitzhak Sapir maintained the + Michael Allison, David Cohrs, Bart House, Pasi Kallinen, Alex + Kompel, Dion Nicolaas, Derek S. Ray and Yitzhak Sapir maintained the port of NetHack 3.6 for Microsoft Windows. - Pat Rankin attempted to keep the VMS port running for NetHack - 3.6, hindered by limited access. Kevin Smolkowski has updated and - tested it for the most recent version of OpenVMS (V8.4 as of this - writing) on Alpha and Integrity (aka Itanium aka IA64) but not VAX. - - Ray Chason resurrected the MS-DOS port for 3.6 and contributed - the necessary updates to the community at large. - - In late April 2018, several hundred bug fixes for 3.6.0 and some - new features were assembled and released as NetHack 3.6.1. The - NetHack Development Team at the time of release of 3.6.1 consisted of - Warwick Allison, Michael Allison, Ken Arromdee, David Cohrs, Jessie - Collet, Pasi Kallinen, Ken Lorber, Dean Luick, Patric Mueller, Pat - Rankin, Derek S. Ray, Alex Smith, Mike Stephenson, Janet Walz, and - Paul Winner. - - In early May 2019, another 320 bug fixes along with some enhance- - ments and the adopted curses window port, were released as 3.6.2. - - Bart House, who had contributed to the game as a porting team - participant for decades, joined the NetHack Development Team in late - May 2019. - - NetHack 3.6.3 was released on December 5, 2019 containing over - 190 bug fixes to NetHack 3.6.2. - - NetHack 3.6.4 was released on December 18, 2019 containing a - security fix and a few bug fixes. - - NetHack 3.6.5 was released on January 27, 2020 containing some - security fixes and a small number of bug fixes. - - NetHack 3.6.6 was released on March 8, 2020 containing a security - fix and some bug fixes. - - NetHack 3.6.7 was released on February 16, 2023 containing a - security fix and some bug fixes. - NetHack 3.7.0 December 25, 2024 + NetHack 3.7.0 May 1, 2025 @@ -7330,7 +7330,45 @@ - The official NetHack web site is maintained by Ken Lorber at + Pat Rankin attempted to keep the VMS port running for NetHack + 3.6, hindered by limited access. Kevin Smolkowski has updated and + tested it for the most recent version of OpenVMS (V8.4 as of this + writing) on Alpha and Integrity (aka Itanium aka IA64) but not VAX. + + Ray Chason resurrected the MS-DOS port for 3.6 and contributed + the necessary updates to the community at large. + + In late April 2018, several hundred bug fixes for 3.6.0 and some + new features were assembled and released as NetHack 3.6.1. The + NetHack Development Team at the time of release of 3.6.1 consisted of + Warwick Allison, Michael Allison, Ken Arromdee, David Cohrs, Jessie + Collet, Pasi Kallinen, Ken Lorber, Dean Luick, Patric Mueller, Pat + Rankin, Derek S. Ray, Alex Smith, Mike Stephenson, Janet Walz, and + Paul Winner. + + In early May 2019, another 320 bug fixes along with some enhance- + ments and the adopted curses window port, were released as 3.6.2. + + Bart House, who had contributed to the game as a porting team + participant for decades, joined the NetHack Development Team in late + May 2019. + + NetHack 3.6.3 was released on December 5, 2019 containing over + 190 bug fixes to NetHack 3.6.2. + + NetHack 3.6.4 was released on December 18, 2019 containing a + security fix and a few bug fixes. + + NetHack 3.6.5 was released on January 27, 2020 containing some + security fixes and a small number of bug fixes. + + NetHack 3.6.6 was released on March 8, 2020 containing a security + fix and some bug fixes. + + NetHack 3.6.7 was released on February 16, 2023 containing a + security fix and some bug fixes. + + The official NetHack web site is maintained by Ken Lorber at https://www.nethack.org/. @@ -7348,59 +7386,83 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - 12.1. Special Thanks - - On behalf of the NetHack community, thank you very much once - again to M. Drew Streib and Pasi Kallinen for providing a public - NetHack server at nethack.alt.org. Thanks to Keith Simpson and Andy - Thomson for hardfought.org. Thanks to all those unnamed dungeoneers - who invest their time and effort into annual NetHack tournaments such - as Junethack, The November NetHack Tournament, and in days past, - devnull.net (gone for now, but not forgotten). - - - - - NetHack 3.7.0 December 25, 2024 + NetHack 3.7.0 May 1, 2025 NetHack Guidebook 113 + + + + 12.1. Special Thanks + + On behalf of the NetHack community, thank you very much once + again to M. Drew Streib and Pasi Kallinen for providing a public + NetHack server at nethack.alt.org. Thanks to Keith Simpson and Andy + Thomson for hardfought.org. Thanks to all those unnamed dungeoneers + who invest their time and effort into annual NetHack tournaments such + as Junethack, The November NetHack Tournament, and in days past, + devnull.net (gone for now, but not forgotten). + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 12.2. Dungeoneers - From time to time, some depraved individual out there in netland - sends a particularly intriguing modification to help out with the - game. The NetHack Development Team sometimes makes note of the names + From time to time, some depraved individual out there in netland + sends a particularly intriguing modification to help out with the + + + NetHack 3.7.0 May 1, 2025 + + + + + + NetHack Guidebook 114 + + + + game. The NetHack Development Team sometimes makes note of the names of the worst of these miscreants in this, the list of Dungeoneers: @@ -7449,23 +7511,23 @@ Andy Church Jeff Bailey Pasi Kallinen Andy Swanson Jochen Erwied Pat Rankin Andy Thomson John Kallen Patric Mueller - - - - NetHack 3.7.0 December 25, 2024 - - - - - - NetHack Guidebook 114 - - - Ari Huttunen John Rupley Paul Winner Bart House John S. Bien Pierre Martineau Benson I. Margulies Johnny Lee Ralf Brown Bill Dyer Jon W{tte Ray Chason + + + + NetHack 3.7.0 May 1, 2025 + + + + + + NetHack Guidebook 115 + + + Boudewijn Waijers Jonathan Handler Richard Addison Bruce Cox Joshua Delahunty Richard Beigel Bruce Holloway Karl Garrison Richard P. Hughey @@ -7518,17 +7580,21 @@ - NetHack 3.7.0 December 25, 2024 + + + + + NetHack 3.7.0 May 1, 2025 - NetHack Guidebook 115 + NetHack Guidebook 116 - Brand and product names are trademarks or registered trademarks + Brand and product names are trademarks or registered trademarks of their respective holders. @@ -7584,7 +7650,7 @@ - NetHack 3.7.0 December 25, 2024 + NetHack 3.7.0 May 1, 2025 From a654d08c3bbde3e7b31920a08a30e18d1c653c32 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 25 May 2025 20:38:17 -0400 Subject: [PATCH 645/791] save/restore changes - part 3 This is the third of a series of savefile-related changes. This adds early-days experimental support for a completely optional 'sfctool' utility (savefile conversion tool), to be able to export a savefile's contents into a more portable format. There are likely to be bugs at this stage. In this initial first-attempt, the export format is a very simple ascii output. NetHack can be built entirely, without also building this tool. NetHack has no dependencies on the tool. Attempts were made to minimize duplication of existing NetHack code. To achieve that, unfortunately, #ifdef SFCTOOL and #ifndef SFCTOOL had to be sprinkled around through some of the existing NetHack source code, so that it could be re-used for building the utility. The process for building the sfctool typically recompiles the source files with #define SFCTOOL and a distinct object file with SF- is produced. sfctool notes: Universal ctags is used and required to produce the sfctool utility. Some targets were added to the Unix and Windows Makefiles to facilitate the build process. make sfctool That should build a copy in util. Note: At present, the Unix Makefiles do not copy sfctool over to the NetHack playground during 'make install' or 'make update'. Until that gets resolved by someone, The tool will have to be manually copied there by the builder/admin if desired. cp util/sfctool ~/nh/install/games/lib/nethackdir/sfctool Also, a separate Visual Studio sfctool.sln solution was written and placed in sys/windows/vs. That has has only very limited testing. Usage: i) To convert an existing savefile to an exportascii format that co-resides with the savefile: sfctool -c savefile That *must* be executed on the same platform / architecture / data model that produced the save file in the first place. ii) To unconvert an existing exportascii format export file to a historical format savefile that can then be used by NetHack: sfctool -u savefile That must be executed on the same target platform / architecture / data model that was used to build the NetHack that will utilize the save file that results. A Windows example: sfctool -c Fred.NetHack-saved-game That should result in creation of Fred.NetHack-saved-game.exportascii from existing savefile: %USERPROFILE%\AppData\Local\NetHack\3.7\Fred.NetHack-saved-game A Unix example: sfctool -c 1000wizard That should result in creation of 1000wizard.exportascii.gz from existing savefile in the playground save directory: 1000wizard.gz Current Mechanics: 1. Makefile recipe, or script uses universal ctags to produce util/sf.tags. 2. util/sftags is built and executed to read util/sf.tags and generate: include/sfproto.h and src/sfdata.c. 3. util/sfctool is built from the following: generated file compiled with -DSFCTOOL: src/sfdata.c -> sfdata.o existing files compiled with -DSFCTOOL: util/sfctool.c -> sfctool.o util/sfexpasc.c -> sfexpasc.o src/alloc.c -> sf-alloc.o src/monst.c -> sf-monst.o src/objects.c -> sf-objects.o src/sfbase.c -> sfbase.o src/sfstruct.c -> sfstruct.o src/nhlua.c -> sf-nhlua.o util/panic.c -> panic.o src/date.c -> sf-date.o src/decl.c -> sf-decl.o src/artifact.c -> sf-artifact.o src/dungeon.c -> sf-dungeon.o src/end.c -> sf-end.o src/engrave.c -> sf-engrave.o src/cfgfiles.c -> sf-cfgfiles.o src/files.c -> sf-files.o src/light.c -> sf-light.o src/mdlib.c -> sf-mdlib.o src/mkmaze.c -> sf-mkmaze.o src/mkroom.c -> sf-mkroom.o src/o_init.c -> sf-o_init.o src/region.c -> sf-region.o src/restore.c -> sf-restore.o src/rumors.c -> sf-rumors.o src/sys.c -> sf-sys.o src/timeout.c -> sf-timeout.o src/track.c -> sf-track.o src/version.c -> sf-version.o src/worm.c -> sf-worm.o src/strutil.c -> strutil.o --- README | 9 +- include/.gitignore | 2 + include/extern.h | 13 +- include/global.h | 5 +- include/hack.h | 14 +- include/savefile.h | 6 +- include/sfprocs.h | 13 +- src/artifact.c | 13 + src/bones.c | 9 + src/cfgfiles.c | 88 +- src/dungeon.c | 15 +- src/end.c | 4 + src/engrave.c | 6 +- src/files.c | 263 ++- src/light.c | 5 +- src/mdlib.c | 11 +- src/mkmaze.c | 13 + src/mkroom.c | 6 + src/nhlua.c | 24 +- src/o_init.c | 9 + src/region.c | 10 + src/restore.c | 139 +- src/rumors.c | 4 + src/save.c | 9 +- src/sfbase.c | 1126 ++++++++- src/sfstruct.c | 64 +- src/timeout.c | 6 + src/track.c | 2 + src/version.c | 92 +- src/worm.c | 6 + sys/unix/Makefile.top | 5 + sys/unix/Makefile.utl | 166 ++ sys/unix/hints/include/cross-post.370 | 1 + sys/unix/hints/include/cross-pre2.370 | 1 + sys/windows/Makefile.nmake | 219 +- sys/windows/vs/NetHack/NetHack.vcxproj | 2 +- sys/windows/vs/NetHackW/NetHackW.vcxproj | 2 +- sys/windows/vs/dirs.props | 2 + sys/windows/vs/fetchctags/fetchctags.nmake | 49 + sys/windows/vs/fetchctags/fetchctags.vcxproj | 71 + sys/windows/vs/sfctool.sln | 58 + sys/windows/vs/sfctool/sfctool.vcxproj | 193 ++ sys/windows/vs/sftags/aftersftags.proj | 48 + sys/windows/vs/sftags/sftags.vcxproj | 156 ++ sys/windows/windsys.c | 22 +- util/.gitignore | 5 +- util/sfctool.c | 1323 +++++++++++ util/sfexpasc.c | 1296 ++++++++++ util/sftags.c | 2230 ++++++++++++++++++ 49 files changed, 7578 insertions(+), 257 deletions(-) create mode 100644 sys/windows/vs/fetchctags/fetchctags.nmake create mode 100644 sys/windows/vs/fetchctags/fetchctags.vcxproj create mode 100644 sys/windows/vs/sfctool.sln create mode 100644 sys/windows/vs/sfctool/sfctool.vcxproj create mode 100644 sys/windows/vs/sftags/aftersftags.proj create mode 100644 sys/windows/vs/sftags/sftags.vcxproj create mode 100644 util/sfctool.c create mode 100644 util/sfexpasc.c create mode 100644 util/sftags.c diff --git a/README b/README index c3d975981..9a4923d03 100644 --- a/README +++ b/README @@ -57,10 +57,11 @@ considered spoilers: level once that square's location becomes known (found or magic mapped); goes away once sanctum temple is found (entered or high altar mapped) - - savefile: add support to deconstruct internal data structures down into - their individual fields and save those fields instead of the entire - struct - - savefile: use little-endian format for fields where that makes a difference + - savefile: add support for a tool to deconstruct data structures, + that get stored in a savefile, down into their individual fields and + save those individual fields instead of the entire struct. The + intention is to provide a way to export and transport savefiles + between platforms, architectures and data models. - - - - - - - - - - - diff --git a/include/.gitignore b/include/.gitignore index 1930f4302..6f4a4f802 100644 --- a/include/.gitignore +++ b/include/.gitignore @@ -15,3 +15,5 @@ tile.h win32api.h # really obsolete... .cvsignore +sfproto.h + diff --git a/include/extern.h b/include/extern.h index 42e47a3d4..b3e2c0949 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1068,6 +1068,10 @@ extern char **get_saved_games(void); extern void free_saved_games(char **); extern void nh_compress(const char *); extern void nh_uncompress(const char *); +extern void nh_sfconvert(const char *); +extern void nh_sfunconvert(const char *); +extern int delete_convertedfile(const char *); +extern void free_convert_filenames(void); extern boolean lock_file(const char *, int, int) NONNULLARG1; extern void unlock_file(const char *) NONNULLARG1; extern void check_recordfile(const char *); @@ -1093,6 +1097,7 @@ extern boolean read_tribute(const char *, const char *, int, char *, int, extern boolean Death_quote(char *, int) NONNULLARG1; extern void livelog_add(long ll_type, const char *) NONNULLARG2; ATTRNORETURN extern void do_deferred_showpaths(int) NORETURN; +extern boolean contains_directory(const char *); /* ### fountain.c ### */ @@ -1969,7 +1974,7 @@ extern int dosuspend(void); extern void nt_regularize(char *); extern int(*nt_kbhit)(void); extern void Delay(int); -extern boolean contains_directory(const char *); +boolean get_user_home_folder(char *, size_t); # ifdef CRASHREPORT struct CRctxt; extern struct CRctxt *ctxp; @@ -2678,6 +2683,12 @@ extern boolean lookup_id_mapping(unsigned, unsigned *) NONNULLARG2; /* extern void reset_restpref(void); */ /* extern void set_restpref(const char *); */ /* extern void set_savepref(const char *); */ +#ifdef SFCTOOL +void rest_bubbles(NHFILE *); +void restore_gamelog(NHFILE *); +boolean restgamestate(NHFILE *); +void restore_msghistory(NHFILE *); +#endif /* ### rip.c ### */ diff --git a/include/global.h b/include/global.h index 727929d09..6d785ac9a 100644 --- a/include/global.h +++ b/include/global.h @@ -429,6 +429,7 @@ extern struct nomakedefs_s nomakedefs; /* PANICTRACE: Always defined for NH_DEVEL_STATUS != NH_STATUS_RELEASED but only for supported platforms. */ +#ifndef NOPANICTRACE #ifdef UNIX #if (NH_DEVEL_STATUS != NH_STATUS_RELEASED) /* see end.c */ @@ -439,6 +440,7 @@ extern struct nomakedefs_s nomakedefs; #endif /* CROSS_TO_WASM | CROSS_TO_MSDOS */ #endif /* NH_DEVEL_STATUS != NH_STATUS_RELEASED */ #endif /* UNIX */ +#endif /* !NOPANICTRACE */ /* The following are meaningless if PANICTRACE is not defined: */ #if defined(__linux__) && defined(__GLIBC__) && (__GLIBC__ >= 2) @@ -569,5 +571,6 @@ typedef enum NHL_pcall_action { NHLpa_impossible } NHL_pcall_action; -#define SFCTOOL_BIT (1UL << 30) /* needed for upcoming savefile handling */ +#define SFCTOOL_BIT (1UL << 30) + #endif /* GLOBAL_H */ diff --git a/include/hack.h b/include/hack.h index 9960d223e..fcb669d10 100644 --- a/include/hack.h +++ b/include/hack.h @@ -954,9 +954,9 @@ struct xlock_s { #define NHF_BONESFILE 3 /* modes */ #define READING 0x0 -#define COUNTING 0x1 -#define WRITING 0x2 -#define FREEING 0x4 +#define COUNTING 0x01 +#define WRITING 0x02 +#define FREEING 0x04 #define CONVERTING 0x08 #define UNCONVERTING 0x10 #if 0 @@ -972,7 +972,7 @@ struct xlock_s { enum saveformats { invalid = 0, historical = 1, /* entire struct, binary, as-is */ - cnvascii = 2, /* each field, ascii text */ + exportascii = 2, /* each field written out as ascii text */ NUM_SAVEFORMATS }; @@ -984,11 +984,11 @@ struct fieldlevel_content { struct nh_file { int fd; /* for traditional structlevel binary writes */ - int mode; /* holds READING, WRITING, or FREEING modes */ + int mode; /* holds READING, WRITING, FREEING, CONVERTING modes */ int ftype; /* NHF_LEVELFILE, NHF_SAVEFILE, or NHF_BONESFILE */ int fnidx; /* index of procs for fieldlevel saves */ - long count; /* holds current line count for default style file, - field count for binary style */ + long rcount, /* read count since opening */ + wcount; /* write count since opening */ boolean structlevel; /* traditional structure binary saves */ boolean fieldlevel; /* fieldlevel saves each field individually */ boolean addinfo; /* if set, some additional context info from core */ diff --git a/include/savefile.h b/include/savefile.h index 28cd24b23..8a4c51cf3 100644 --- a/include/savefile.h +++ b/include/savefile.h @@ -23,7 +23,7 @@ extern void sfo_uint32(NHFILE *, uint32 *, const char *); extern void sfo_uint64(NHFILE *, uint64 *, const char *); extern void sfo_size_t(NHFILE *, size_t *, const char *); extern void sfo_time_t(NHFILE *, time_t *, const char *); - +//extern void sfo_str(NHFILE *, char *, const char *, int); extern void sfo_arti_info(NHFILE *nhfp, struct arti_info *d_arti_info, const char *myname); @@ -199,7 +199,7 @@ extern void sfi_ulong(NHFILE *, ulong *, const char *); #define Sfo_uint64(a,b,c) sfo_uint64(a, b, c) #define Sfo_size_t(a,b,c) sfo_size_t(a, b, c) #define Sfo_time_t(a,b,c) sfo_time_t(a, b, c) - +#define Sfo_str(a,b,c) sfo_str(a, b, c) #define Sfo_arti_info(a,b,c) sfo_arti_info(a, b, c) #define Sfo_dgn_topology(a,b,c) sfo_dgn_topology(a, b, c) #define Sfo_dungeon(a,b,c) sfo_dungeon(a, b, c) @@ -471,7 +471,7 @@ extern void sfi_ulong(NHFILE *, ulong *, const char *); #define Sfo_uint64(a,b,c) sfo(a, b, c) #define Sfo_size_t(a,b,c) sfo(a, b, c) #define Sfo_time_t(a,b,c) sfo(a, b, c) - +#define Sfo_str(a,b,c) sfo(a, b, c) #define Sfo_arti_info(a,b,c) sfo(a, b, c) #define Sfo_dgn_topology(a,b,c) sfo(a, b, c) #define Sfo_dungeon(a,b,c) sfo(a, b, c) diff --git a/include/sfprocs.h b/include/sfprocs.h index 661d1a40a..f544b04c9 100644 --- a/include/sfprocs.h +++ b/include/sfprocs.h @@ -97,11 +97,11 @@ SF_PROTO_X(char, char); #undef SF_PROTO_C #undef SF_PROTO_X -#define SF_ENTRY(dtyp) \ +#define SF_ENTRY(dtyp) \ void (*sf_##dtyp)(NHFILE *, dtyp *, const char *) -#define SF_ENTRY_C(keyw, dtyp) \ +#define SF_ENTRY_C(keyw, dtyp) \ void (*sf_##dtyp)(NHFILE *, keyw dtyp *, const char *) -#define SF_ENTRY_X(xxx, dtyp) \ +#define SF_ENTRY_X(xxx, dtyp) \ void (*sf_##dtyp)(NHFILE *, xxx *, const char *, int bfsz) struct sf_procs { @@ -189,11 +189,14 @@ struct sf_fieldlevel_procs { struct sf_procs fn_x; /* called for fieldlevel */ }; extern struct sf_structlevel_procs sfoprocs[NUM_SAVEFORMATS], sfiprocs[NUM_SAVEFORMATS]; +extern void sf_setprocs(int, struct sf_structlevel_procs *, struct sf_structlevel_procs *); +extern void sf_setflprocs(int, struct sf_fieldlevel_procs *, struct sf_fieldlevel_procs *); +extern struct sf_structlevel_procs sfoprocs[NUM_SAVEFORMATS], sfiprocs[NUM_SAVEFORMATS]; extern struct sf_fieldlevel_procs sfoflprocs[NUM_SAVEFORMATS], sfiflprocs[NUM_SAVEFORMATS]; extern struct sf_structlevel_procs historical_sfo_procs; extern struct sf_structlevel_procs historical_sfi_procs; -extern struct sf_fieldlevel_procs cnv_sfo_procs; -extern struct sf_fieldlevel_procs cnv_sfi_procs; +extern struct sf_fieldlevel_procs exportascii_sfo_procs; +extern struct sf_fieldlevel_procs exportascii_sfi_procs; #endif /* SFPROCS_H */ diff --git a/src/artifact.c b/src/artifact.c index ddd254285..d180cb2fb 100644 --- a/src/artifact.c +++ b/src/artifact.c @@ -7,6 +7,8 @@ #include "artifact.h" #include "artilist.h" +#ifndef SFCTOOL + /* * Note: both artilist[] and artiexist[] have a dummy element #0, * so loops over them should normally start at #1. The primary @@ -57,6 +59,7 @@ staticfn void dispose_of_orig_obj(struct obj *); Note: this will still break if they have more than about half the number of hit points that will fit in a 15 bit integer. */ #define FATAL_DAMAGE_MODIFIER 200 +#endif /* SFCTOOL */ /* arti_info struct definition moved to artifact.h */ @@ -72,6 +75,7 @@ static xint16 artidisco[NROFARTIFACTS]; * and restored but that is done through this file so they can be local. */ +#ifndef SFCTOOL static const struct arti_info zero_artiexist = {0}; /* all bits zero */ staticfn void hack_artifacts(void); @@ -121,6 +125,8 @@ save_artifacts(NHFILE *nhfp) Sfo_xint16(nhfp, &artidisco[i], "artidisco"); } +#endif /* SFCTOOL */ + void restore_artifacts(NHFILE *nhfp) { @@ -130,9 +136,15 @@ restore_artifacts(NHFILE *nhfp) Sfi_arti_info(nhfp, &artiexist[i], "artiexist"); for (i = 0; i < NROFARTIFACTS; ++i) Sfi_short(nhfp, &artidisco[i], "artidisco"); +#ifndef SFCTOOL hack_artifacts(); /* redo non-saved special cases */ +#else + nhUse(artilist); +#endif } +#ifndef SFCTOOL + const char * artiname(int artinum) { @@ -2789,5 +2801,6 @@ permapoisoned(struct obj *obj) { return (obj && is_art(obj, ART_GRIMTOOTH)); } +#endif /* SFCTOOL */ /*artifact.c*/ diff --git a/src/bones.c b/src/bones.c index 31185dd28..922737fe1 100644 --- a/src/bones.c +++ b/src/bones.c @@ -5,6 +5,7 @@ #include "hack.h" +#ifndef SFCTOOL staticfn boolean no_bones_level(d_level *); staticfn void goodfruit(int); staticfn void resetobjs(struct obj *, boolean); @@ -622,6 +623,8 @@ savebones(int how, time_t when, struct obj *corpse) compress_bonesfile(); } +#endif /* !SFCTOOL */ + int getbones(void) { @@ -630,6 +633,7 @@ getbones(void) char c = 0, *bonesid, oldbonesid[40] = { 0 }; /* was [10]; more should be safer */ +#ifndef SFCTOOL if (discover) /* save bones files for real games */ return 0; @@ -641,6 +645,7 @@ getbones(void) return 0; if (no_bones_level(&u.uz)) return 0; +#endif /* !SFCTOOL */ nhfp = open_bonesfile(&u.uz, &bonesid); if (!nhfp) @@ -740,6 +745,8 @@ getbones(void) return ok; } +#ifndef SFCTOOL + /* check whether current level contains bones from a particular player */ boolean bones_include_name(const char *name) @@ -821,4 +828,6 @@ free_ebones(struct monst *mtmp) } } +#endif /* SFCTOOL */ + /*bones.c*/ diff --git a/src/cfgfiles.c b/src/cfgfiles.c index 52f45a7a4..9d8de7f86 100644 --- a/src/cfgfiles.c +++ b/src/cfgfiles.c @@ -35,6 +35,7 @@ staticfn char *is_config_section(char *); staticfn boolean handle_config_section(char *); boolean parse_config_line(char *); staticfn char *find_optparam(const char *); +#ifndef SFCTOOL staticfn boolean cnf_line_OPTIONS(char *); staticfn boolean cnf_line_AUTOPICKUP_EXCEPTION(char *); staticfn boolean cnf_line_BINDINGS(char *); @@ -53,6 +54,7 @@ staticfn boolean cnf_line_NAME(char *); staticfn boolean cnf_line_ROLE(char *); staticfn boolean cnf_line_dogname(char *); staticfn boolean cnf_line_catname(char *); +#endif /* SFCTOOL */ #ifdef SYSCF staticfn boolean cnf_line_WIZARDS(char *); staticfn boolean cnf_line_SHELLERS(char *); @@ -80,12 +82,12 @@ staticfn boolean cnf_line_PANICTRACE_GDB(char *); staticfn boolean cnf_line_GDBPATH(char *); staticfn boolean cnf_line_GREPPATH(char *); staticfn boolean cnf_line_CRASHREPORTURL(char *); -staticfn boolean cnf_line_SAVEFORMAT(char *); -staticfn boolean cnf_line_BONESFORMAT(char *); staticfn boolean cnf_line_ACCESSIBILITY(char *); + staticfn boolean cnf_line_PORTABLE_DEVICE_PATHS(char *); staticfn void parseformat(int *, char *); #endif /* SYSCF */ +#ifndef SFCTOOL staticfn boolean cnf_line_BOULDER(char *); staticfn boolean cnf_line_MENUCOLOR(char *); staticfn boolean cnf_line_HILITE_STATUS(char *); @@ -101,6 +103,7 @@ staticfn boolean cnf_line_QT_TILEWIDTH(char *); staticfn boolean cnf_line_QT_TILEHEIGHT(char *); staticfn boolean cnf_line_QT_FONTSIZE(char *); staticfn boolean cnf_line_QT_COMPACT(char *); +#endif /* SFCTOOL */ struct _cnf_parser_state; /* defined below (far below...) */ staticfn void cnf_parser_init(struct _cnf_parser_state *parser); staticfn void cnf_parser_done(struct _cnf_parser_state *parser); @@ -109,6 +112,13 @@ staticfn void parse_conf_buf(struct _cnf_parser_state *parser, /* next one is in extern.h; why here too? */ boolean parse_conf_str(const char *str, boolean (*proc)(char *arg)); +#ifdef SFCTOOL +#ifdef wait_synch +#undef wait_synch +#endif +#define wait_synch() +#endif /* SFCTOOL */ + /* ---------- BEGIN CONFIG FILE HANDLING ----------- */ /* used for messaging. Also used in options.c */ @@ -151,6 +161,8 @@ get_default_configfile(void) const char *backward_compat_configfile = "nethack.cnf"; #endif +#ifndef SFCTOOL + /* #saveoptions - save config options into file */ int do_write_config_file(void) @@ -195,6 +207,7 @@ do_write_config_file(void) } return ECMD_OK; } +#endif /* SFCTOOL */ /* remember the name of the file we're accessing; if may be used in option reject messages */ @@ -455,7 +468,11 @@ choose_random_part(char *str, char sep) nsep++; str++; } +#ifndef SFCTOOL csep = rn2(nsep); +#else + csep = 1; +#endif str = begin; while ((csep > 0) && *str) { str++; @@ -571,6 +588,8 @@ find_optparam(const char *buf) return bufp; } +#ifndef SFCTOOL + staticfn boolean cnf_line_OPTIONS(char *origbuf) { @@ -759,6 +778,7 @@ cnf_line_catname(char *bufp) (void) strncpy(gc.catname, bufp, PL_PSIZ - 1); return TRUE; } +#endif /* SFCTOOL */ #ifdef SYSCF @@ -1088,20 +1108,6 @@ cnf_line_CRASHREPORTURL(char *bufp) return TRUE; } -staticfn boolean -cnf_line_SAVEFORMAT(char *bufp) -{ - parseformat(sysopt.saveformat, bufp); - return TRUE; -} - -staticfn boolean -cnf_line_BONESFORMAT(char *bufp) -{ - parseformat(sysopt.bonesformat, bufp); - return TRUE; -} - staticfn boolean cnf_line_ACCESSIBILITY(char *bufp) { @@ -1135,6 +1141,8 @@ cnf_line_PORTABLE_DEVICE_PATHS(char *bufp) } #endif /* SYSCF */ +#ifndef SFCTOOL + staticfn boolean cnf_line_BOULDER(char *bufp) { @@ -1271,6 +1279,7 @@ cnf_line_QT_COMPACT(char *bufp) #endif return TRUE; } +#endif /* SFCTOOL */ typedef boolean (*config_line_stmt_func)(char *); @@ -1288,6 +1297,7 @@ static const struct match_config_line_stmt { boolean origbuf; config_line_stmt_func fn; } config_line_stmt[] = { +#ifndef SFCTOOL /* OPTIONS handled separately */ { "OPTIONS", 4, FALSE, TRUE, cnf_line_OPTIONS }, CNFL_N(AUTOPICKUP_EXCEPTION, 5), @@ -1309,6 +1319,7 @@ static const struct match_config_line_stmt { CNFL_NA(CHARACTER, 4, ROLE), CNFL_N(dogname, 3), CNFL_N(catname, 3), +#endif /* SFCTOOL */ #ifdef SYSCF CNFL_S(WIZARDS, 7), CNFL_S(SHELLERS, 8), @@ -1336,11 +1347,10 @@ static const struct match_config_line_stmt { CNFL_S(CRASHREPORTURL, 13), CNFL_S(GDBPATH, 7), CNFL_S(GREPPATH, 7), - CNFL_S(SAVEFORMAT, 10), - CNFL_S(BONESFORMAT, 11), CNFL_S(ACCESSIBILITY, 13), CNFL_S(PORTABLE_DEVICE_PATHS, 8), #endif /*SYSCF*/ +#ifndef SFCTOOL CNFL_N(BOULDER, 3), CNFL_N(MENUCOLOR, 9), CNFL_N(HILITE_STATUS, 6), @@ -1356,6 +1366,7 @@ static const struct match_config_line_stmt { CNFL_N(QT_TILEHEIGHT, 13), CNFL_N(QT_FONTSIZE, 11), CNFL_N(QT_COMPACT, 10) +#endif /* SFCTOOL */ }; #undef CNFL_N @@ -1485,6 +1496,7 @@ config_error_nextline(const char *line) return TRUE; } +#ifndef SFCTOOL int l_get_config_errors(lua_State *L) { @@ -1510,6 +1522,7 @@ l_get_config_errors(lua_State *L) return 1; } +#endif /* SFCTOOL */ /* varargs 'config_error_add()' moved to pline.c */ void @@ -1600,9 +1613,10 @@ read_config_file(const char *filename, int src) if (!(fp = fopen_config_file(filename, src))) return FALSE; - +#ifndef SFCTOOL /* begin detection of duplicate configfile options */ reset_duplicate_opt_detection(); +#endif /* SFCTOOL */ free_config_sections(); iflags.parse_config_file_src = src; @@ -1610,8 +1624,10 @@ read_config_file(const char *filename, int src) (void) fclose(fp); free_config_sections(); +#ifndef SFCTOOL /* turn off detection of duplicate configfile options */ reset_duplicate_opt_detection(); +#endif /* SFCTOOL */ return rv; } @@ -1859,38 +1875,6 @@ vconfig_error_add(const char *str, va_list the_args) } #ifdef SYSCF -staticfn void -parseformat(int *arr, char *str) -{ - const char *legal[] = { "historical", "cnv" }; - int i, kwi = 0, words = 0; - char *p = str, *keywords[2] = { NULL }; - - while (*p) { - while (*p && isspace((uchar) *p)) { - *p = '\0'; - p++; - } - if (*p) { - words++; - if (kwi < 2) - keywords[kwi++] = p; - } - while (*p && !isspace((uchar) *p)) - p++; - } - if (!words) { - impossible("missing format list"); - return; - } - while (--kwi >= 0) - if (kwi < 2) { - for (i = 0; i < SIZE(legal); ++i) { - if (!strcmpi(keywords[kwi], legal[i])) - arr[kwi] = i + 1; - } - } -} #ifdef SYSCF_FILE void assure_syscf_file(void) @@ -1924,8 +1908,10 @@ assure_syscf_file(void) close(fd); return; } +#ifndef SFCTOOL if (gd.deferred_showpaths) do_deferred_showpaths(1); /* does not return */ +#endif raw_printf("Unable to open SYSCF_FILE.\n"); exit(EXIT_FAILURE); } diff --git a/src/dungeon.c b/src/dungeon.c index cbc2abd8f..c3d9b8e43 100644 --- a/src/dungeon.c +++ b/src/dungeon.c @@ -34,6 +34,7 @@ struct lchoice { static mapseen *load_mapseen(NHFILE *); +#ifndef SFCTOOL #if 0 staticfn void Fread(genericptr_t, int, int, dlb *); #endif @@ -202,6 +203,7 @@ save_dungeon( svm.mapseenchn = 0; } } +#endif /* !SFCTOOL */ /* Restore the dungeon structures. */ void @@ -259,6 +261,7 @@ restore_dungeon(NHFILE *nhfp) } } +#ifndef SFCTOOL #if 0 staticfn void Fread(genericptr_t ptr, int size, int nitems, dlb *stream) @@ -1428,6 +1431,7 @@ depth(d_level *lev) { return (schar) (svd.dungeons[lev->dnum].depth_start + lev->dlevel - 1); } +#endif /* !SFCTOOL */ /* are "lev1" and "lev2" actually the same? */ boolean @@ -1437,6 +1441,7 @@ on_level(d_level *lev1, d_level *lev2) && lev1->dlevel == lev2->dlevel); } +#ifndef SFCTOOL /* is this level referenced in the special level chain? */ s_level * Is_special(d_level *lev) @@ -1602,6 +1607,8 @@ u_on_rndspot(int upflag) switch_terrain(); } +#endif /* !SFCTOOL */ +#ifndef SFCTOOL boolean Is_botlevel(d_level *lev) { @@ -2536,6 +2543,7 @@ donamelevel(void) query_annotation((d_level *) 0); return ECMD_OK; } +#endif /* !SFCTOOL */ /* exclusion zones */ void @@ -2562,7 +2570,7 @@ save_exclusions(NHFILE *nhfp) ; if (update_file(nhfp)) { - Sfo_int(nhfp, &nez, "exclusion-count"); + Sfo_int(nhfp, &nez, "exclusion_count"); for (ez = sve.exclusion_zones; ez; ez = ez->next) { Sfo_xint16(nhfp, &ez->zonetype, "exclusion-zonetype"); Sfo_coordxy(nhfp, &ez->lx, "exclusion-lx"); @@ -2593,6 +2601,8 @@ load_exclusions(NHFILE *nhfp) } } +#ifndef SFCTOOL + /* find the particular mapseen object in the chain; may return null */ staticfn mapseen * find_mapseen(d_level *lev) @@ -2673,6 +2683,7 @@ save_mapseen(NHFILE *nhfp, mapseen *mptr) } savecemetery(nhfp, &mptr->final_resting_place); } +#endif /* !SFCTOOL */ staticfn mapseen * load_mapseen(NHFILE *nhfp) @@ -2709,6 +2720,7 @@ load_mapseen(NHFILE *nhfp) restcemetery(nhfp, &load->final_resting_place); return load; } +#ifndef SFCTOOL DISABLE_WARNING_FORMAT_NONLITERAL @@ -3682,6 +3694,7 @@ print_mapseen( } } } +#endif /* !SFCTOOL */ #undef OF_INTEREST #undef ADDNTOBUF #undef ADDTOBUF diff --git a/src/end.c b/src/end.c index e17c17517..ba2ea4f19 100644 --- a/src/end.c +++ b/src/end.c @@ -14,6 +14,7 @@ #endif #include "dlb.h" +#ifndef SFCTOOL #ifndef NO_SIGNAL staticfn void done_intr(int); # if defined(UNIX) || defined(VMS) || defined(__EMX__) @@ -33,9 +34,11 @@ staticfn void dump_plines(void); #endif staticfn void dump_everything(int, time_t); staticfn void fixup_death(int); +#endif /* SFCTOOL */ staticfn int wordcount(char *); staticfn void bel_copy1(char **, char *); +#ifndef SFCTOOL #define done_stopprint program_state.stopprint /* @@ -1767,6 +1770,7 @@ save_killers(NHFILE *nhfp) } } } +#endif /* !SFCTOOL */ void restore_killers(NHFILE *nhfp) diff --git a/src/engrave.c b/src/engrave.c index 00602e0fc..9d598e341 100644 --- a/src/engrave.c +++ b/src/engrave.c @@ -37,7 +37,7 @@ struct _doengrave_ctx { size_t len; /* # of nonspace chars of new engraving text */ }; - +#ifndef SFCTOOL staticfn int stylus_ok(struct obj *); staticfn boolean u_can_engrave(void); staticfn void doengrave_ctx_init(struct _doengrave_ctx *); @@ -1542,6 +1542,7 @@ save_engravings(NHFILE *nhfp) if (release_data(nhfp)) head_engr = 0; } +#endif /* !SFCTOOL */ void rest_engravings(NHFILE *nhfp) @@ -1581,6 +1582,7 @@ rest_engravings(NHFILE *nhfp) } } +#ifndef SFCTOOL DISABLE_WARNING_FORMAT_NONLITERAL /* to support '#stats' wizard-mode command */ @@ -1728,5 +1730,5 @@ blengr(void) { return ROLL_FROM(blind_writing); } - +#endif /* !SFCTOOL */ /*engrave.c*/ diff --git a/src/files.c b/src/files.c index 238d03662..821b1cff8 100644 --- a/src/files.c +++ b/src/files.c @@ -12,6 +12,28 @@ #include "hack.h" #include "dlb.h" +#ifdef SFCTOOL +#ifdef TTY_GRAPHICS +#undef TTY_GRAPHICS +#endif +#ifdef mark_synch +#undef mark_synch +#endif +#define mark_synch() +#ifdef raw_print +#undef raw_print +#endif +#define raw_print(a) +#ifdef WINDOWPORT +#undef WINDOWPORT +#endif +#define WINDOWPORT(x) FALSE +#ifdef clear_nhwindow +#undef clear_nhwindow +#endif +#define clear_nhwindow(x) +#endif /* SFCTOOL */ + #ifdef TTY_GRAPHICS #include "wintty.h" /* more() */ #endif @@ -125,8 +147,13 @@ extern boolean get_user_home_folder(char *, size_t); #define PRAGMA_UNUSED #endif +#ifndef SFCTOOL staticfn NHFILE *new_nhfile(void); staticfn void free_nhfile(NHFILE *); +#else +NHFILE *new_nhfile(void); +void free_nhfile(NHFILE *); +#endif /* SFCTOOL */ #ifdef SELECTSAVED staticfn int QSORTCALLBACK strcmp_wrap(const void *, const void *); @@ -144,6 +171,12 @@ staticfn boolean make_compressed_name(const char *, char *); #endif staticfn NHFILE *problematic_savefile(int, const char *); +#ifndef SFCTOOL +staticfn int doconvert_file(const char *, int, boolean); +#endif /* SFCTOOL */ +staticfn boolean make_converted_name(const char *); + +#ifndef SFCTOOL staticfn NHFILE *viable_nhfile(NHFILE *); #ifdef SELECTSAVED staticfn int QSORTCALLBACK strcmp_wrap(const void *, const void *); @@ -159,6 +192,7 @@ boolean proc_wizkit_line(char *buf); void read_wizkit(void); /* in extern.h; why here too? */ staticfn FILE *fopen_sym_file(void); staticfn NHFILE *viable_nhfile(NHFILE *); +#endif /* !SFCTOOL */ /* return a file's name without its path and optionally trailing 'type' */ const char * @@ -354,6 +388,7 @@ fqname(const char *basenam, #endif /* !PREFIXES_IN_USE */ } +#ifndef SFCTOOL /* reasonbuf must be at least BUFSZ, supplied by caller */ int validate_prefix_locations(char *reasonbuf) @@ -414,6 +449,7 @@ fopen_datafile(const char *filename, const char *mode, int prefix) fp = fopen(filename, mode); return fp; } +#endif /* !SFCTOOL */ /* ---------- EXTERNAL FILE SUPPORT ----------- */ @@ -433,7 +469,7 @@ zero_nhfile(NHFILE *nhfp) nhfp->fpdef = (FILE *) 0; nhfp->fplog = (FILE *) 0; nhfp->fpdebug = (FILE *) 0; - nhfp->count = 0; + nhfp->rcount = nhfp->wcount = 0; nhfp->eof = FALSE; nhfp->fnidx = 0; nhfp->style.deflt = FALSE; @@ -441,7 +477,10 @@ zero_nhfile(NHFILE *nhfp) nhfp->nhfpconvert = 0; } -staticfn NHFILE * +#ifndef SFCTOOL +staticfn +#endif +NHFILE * new_nhfile(void) { NHFILE *nhfp = (NHFILE *) alloc(sizeof(NHFILE)); @@ -450,7 +489,10 @@ new_nhfile(void) return nhfp; } -staticfn void +#ifndef SFCTOOL +staticfn +#endif +void free_nhfile(NHFILE *nhfp) { if (nhfp) { @@ -477,13 +519,18 @@ close_nhfile(NHFILE *nhfp) void rewind_nhfile(NHFILE *nhfp) { + if (nhfp->structlevel) { #ifdef BSD - (void) lseek(nhfp->fd, 0L, 0); + (void) lseek(nhfp->fd, 0L, 0); #else - (void) lseek(nhfp->fd, (off_t) 0, 0); + (void) lseek(nhfp->fd, (off_t) 0, 0); #endif + } else { + rewind(nhfp->fpdef); + } } +#ifndef SFCTOOL staticfn NHFILE * viable_nhfile(NHFILE *nhfp) { @@ -517,6 +564,7 @@ viable_nhfile(NHFILE *nhfp) } return nhfp; } +#endif /* !SFCTOOL */ int nhclose(int fd) @@ -534,6 +582,7 @@ nhclose(int fd) /* ---------- BEGIN LEVEL FILE HANDLING ----------- */ +#ifndef SFCTOOL /* Construct a file name for a level-type file, which is of the form * something.level (with any old level stripped off). * This assumes there is space on the end of 'file' to append @@ -881,7 +930,7 @@ open_bonesfile(d_level *lev, char **bonesid) nhfp->mode = READING; nhfp->addinfo = TRUE; nhfp->style.deflt = TRUE; - nhfp->style.binary = (sysopt.bonesformat[0] != cnvascii); + nhfp->style.binary = (sysopt.bonesformat[0] != exportascii); nhfp->fnidx = sysopt.bonesformat[0]; nhfp->fd = -1; nhfp->fpdef = fopen(fq_bones, nhfp->style.binary ? RDBMODE : RDTMODE); @@ -912,6 +961,7 @@ delete_bonesfile(d_level *lev) (void) set_bonesfile_name(gb.bones, lev); reslt = unlink(fqname(gb.bones, BONESPREFIX, 0)); + delete_convertedfile(fqname(gb.bones, BONESPREFIX, 0)); return !(reslt < 0); } @@ -920,8 +970,10 @@ delete_bonesfile(d_level *lev) void compress_bonesfile(void) { + nh_sfconvert(fqname(gb.bones, BONESPREFIX, 0)); nh_compress(fqname(gb.bones, BONESPREFIX, 0)); } +#endif /* !SFCTOOL */ /* ---------- END BONES FILE HANDLING ----------- */ @@ -1035,6 +1087,7 @@ set_savefile_name(boolean regularize_it) #endif } +#ifndef SFCTOOL #ifdef INSURANCE void save_savefile_name(NHFILE *nhfp) @@ -1172,6 +1225,7 @@ delete_savefile(void) const char *sfname = fqname(gs.SAVEF, SAVEPREFIX, 0); (void) unlink(sfname); + (void) delete_convertedfile(sfname); return 0; /* for restore_saved_game() (ex-xxxmain.c) test */ } @@ -1439,6 +1493,7 @@ free_saved_games(char **saved) free((genericptr_t) saved); } } +#endif /* !SFCTOOL */ /* ---------- END SAVE FILE HANDLING ----------- */ @@ -1490,13 +1545,20 @@ docompress_file(const char *filename, boolean uncomp) #ifdef TTY_GRAPHICS boolean istty = WINDOWPORT(tty); #endif + #ifdef COMPRESS_EXTENSION xtra = COMPRESS_EXTENSION; #else xtra = ""; #endif +#ifdef SFCTOOL + ln = strlen(filename) + sizeof COMPRESS_EXTENSION; + cfn = (char *) alloc(ln); +#else /* SFCTOOL */ ln = (unsigned) (strlen(filename) + strlen(xtra)); cfn = (char *) alloc(ln + 1); +#endif /* SFCTOOL */ + Strcpy(cfn, filename); Strcat(cfn, xtra); @@ -1540,8 +1602,9 @@ docompress_file(const char *filename, boolean uncomp) * there is an error message from the compression, the 'y' or 'n' can * end up being displayed after the error message. */ - if (istty) + if (istty) { mark_synch(); + } #endif f = fork(); if (f == 0) { /* child */ @@ -1551,8 +1614,9 @@ docompress_file(const char *filename, boolean uncomp) * them will have to clear the first line. This should be * invisible if there are no error messages. */ - if (istty) + if (istty) { raw_print(""); + } #endif /* run compressor without privileges, in case other programs * have surprises along the line of gzip once taking filenames @@ -1715,10 +1779,17 @@ docompress_file(const char *filename, boolean uncomp) { gzFile compressedfile; FILE *uncompressedfile; +#ifndef SFCTOOL char cfn[256]; +#else + char *cfn; +#endif char buf[1024]; unsigned len, len2; +#ifdef SFCTOOL + cfn = (char *) alloc(strlen(filename) + strlen(COMPRESS_EXTENSION) + 1); +#endif if (!make_compressed_name(filename, cfn)) return; @@ -1739,6 +1810,9 @@ docompress_file(const char *filename, boolean uncomp) } else { panic("Error in docompress_file %d", errno); } +#ifdef SFCTOOL + free(cfn); +#endif fclose(uncompressedfile); return; } @@ -1753,6 +1827,9 @@ docompress_file(const char *filename, boolean uncomp) fclose(uncompressedfile); gzclose(compressedfile); (void) unlink(cfn); +#ifdef SFCTOOL + free(cfn); +#endif return; } if (len == 0) @@ -1765,6 +1842,9 @@ docompress_file(const char *filename, boolean uncomp) fclose(uncompressedfile); gzclose(compressedfile); (void) unlink(cfn); +#ifdef SFCTOOL + free(cfn); +#endif return; } } @@ -1790,12 +1870,18 @@ docompress_file(const char *filename, boolean uncomp) panic("Error in zlib docompress_file %s, %d", filename, errno); } +#ifdef SFCTOOL + free(cfn); +#endif return; } uncompressedfile = fopen(filename, WRBMODE); if (!uncompressedfile) { pline("Error in zlib docompress file uncompress %s", filename); gzclose(compressedfile); +#ifdef SFCTOOL + free(cfn); +#endif return; } @@ -1809,6 +1895,9 @@ docompress_file(const char *filename, boolean uncomp) fclose(uncompressedfile); gzclose(compressedfile); (void) unlink(filename); +#ifdef SFCTOOL + free(cfn); +#endif return; } if (len == 0) @@ -1821,6 +1910,9 @@ docompress_file(const char *filename, boolean uncomp) fclose(uncompressedfile); gzclose(compressedfile); (void) unlink(filename); +#ifdef SFCTOOL + free(cfn); +#endif return; } } @@ -1831,6 +1923,9 @@ docompress_file(const char *filename, boolean uncomp) /* Delete the file left behind */ (void) unlink(cfn); } +#ifdef SFCTOOL + free(cfn); +#endif } #endif /* RLC 09 Mar 1999: End ZLIB patch */ @@ -1840,7 +1935,7 @@ docompress_file(const char *filename, boolean uncomp) /* ---------- BEGIN PROBLEMATIC SAVEFILE HANDLING ----------- */ - +#ifndef SFCTOOL static struct sfstatus_to_msg { int sfstatus; const char *msg; @@ -1873,6 +1968,8 @@ problematic_savefile(int sfstatus, const char *savefilenm) case SF_DM_ILP32LL64_ON_IL32LLP64: case SF_DM_I32LP64_ON_IL32LLP64: case SF_DM_IL32LLP64_ON_I32LP64: + FALLTHROUGH; + /*FALLTHRU*/ case SF_DM_MISMATCH: case SF_OUTDATED: case SF_CRITICAL_BYTE_COUNT_MISMATCH: @@ -1889,11 +1986,155 @@ problematic_savefile(int sfstatus, const char *savefilenm) } return nhfp; } +#endif /* !SFCTOOL */ /* ---------- END PROBLEMATIC SAVEFILE HANDLING ----------- */ +/* ---------- BEGIN EXTERNAL CONVERSION HANDLING ----------- */ + +static boolean cvtinit = FALSE; + +#ifndef SFCTOOL +static char *unconverted_filename = 0, *converted_filename = 0; + +/* + * Returns non-zero if unconvert was successful + */ +staticfn int +doconvert_file(const char *filename, int sfstatus, boolean unconvert) +{ + nhUse(sfstatus); + nhUse(unconvert); + return 1; +} + +/* convert file */ +void nh_sfconvert(const char *filename) +{ + (void) doconvert_file(filename, 0, FALSE); +} + +/* unconvert file if it exists */ +void nh_sfunconvert(const char *filename) +{ + (void) doconvert_file(filename, 0, TRUE); +} + +#else /* !SFCTOOL */ +/* in sfctool, these are in sfctool.c, not in here */ +extern char *unconverted_filename, *converted_filename; +#endif /* !SFCTOOL */ + +staticfn boolean +make_converted_name(const char *filename) +{ + unsigned ln; + const char *xtra, *finaldirchar; + const char *dir = NULL; + boolean needsep = FALSE; +#if defined(WIN32) + static char folderbuf[MAX_PATH]; +#endif + + if (!filename) + return FALSE; + + if (unconverted_filename) + free((genericptr_t) unconverted_filename), unconverted_filename = 0; + if (converted_filename) + free((genericptr_t) converted_filename), converted_filename = 0; + +#ifndef SHORT_FILENAMES + /* do we need to do some ms-dos processing here? */ +#endif /* SHORT_FILENAMES */ + + ln = (unsigned) strlen(filename); + if (!contains_directory(filename)) { +#if defined(UNIX) + dir = nh_getenv("NETHACKDIR"); + if (!dir) + dir = nh_getenv("HACKDIR"); +#ifdef HACKDIR + if (!dir) + dir = HACKDIR; +#endif +#elif defined(WIN32) + if (get_user_home_folder(folderbuf, sizeof folderbuf)) { + size_t sz = strlen(folderbuf); + + Snprintf(eos(folderbuf), sizeof folderbuf - sz, + "\\AppData\\Local\\NetHack\\3.7\\"); + dir = (const char *) folderbuf; + } +#endif /* UNIX || WIN32 */ + if (dir) { + finaldirchar = c_eos(dir); + finaldirchar--; + if (!(*finaldirchar == '/' || *finaldirchar == '\\' + || *finaldirchar == ':')) { + needsep = TRUE; + ln += 1; + } + ln += strlen(dir); + } + } + unconverted_filename = (char *) alloc(ln + 1); + Snprintf(unconverted_filename, ln + 1, "%s%s%s", + dir ? dir : "", + (dir && needsep) ? "/" : "", + filename); + xtra = ".exportascii"; + ln += (unsigned) strlen(xtra); + converted_filename = (char *) alloc(ln + 1); + Strcpy(converted_filename, unconverted_filename); + Strcat(converted_filename, xtra); + return TRUE; +} + +/* delete converted savefile as a normal course of action */ +int +delete_convertedfile(const char *basefilename) +{ + if (!converted_filename) + make_converted_name(basefilename); + if (converted_filename) { + (void) unlink(converted_filename); + } + return 0; +} + +void free_convert_filenames(void) +{ + if (converted_filename) + free((genericptr_t) converted_filename), converted_filename = 0; + if (unconverted_filename) + free((genericptr_t) unconverted_filename), unconverted_filename = 0; + cvtinit = FALSE; +} + +/* return TRUE if s contains a directory, not just a filespec */ +boolean +contains_directory(const char *s) +{ + int i, slen = strlen(s); + const char *cp = s; + + for (i = 0; i < slen; ++i) { + if (*cp == '\\' || *cp == '/' || *cp == ':') + return TRUE; + cp++; + } + return FALSE; +} + +/* =========================================================================*/ + +/* ---------- END EXTERNAL CONVERSION HANDLING ----------- */ + /* ---------- BEGIN FILE LOCKING HANDLING ----------- */ +#ifndef SFCTOOL + #if defined(NO_FILE_LINKS) || defined(USE_FCNTL) /* implies UNIX */ static int lockfd = -1; /* for lock_file() to pass to unlock_file() */ #endif @@ -2802,6 +3043,7 @@ do_deferred_showpaths(int code) #endif #endif } +#endif /* !SFCTOOL */ #ifdef DEBUG /* used by debugpline() to decide whether to issue a message @@ -2856,6 +3098,7 @@ debugcore(const char *filename, boolean wildcards) #endif /*DEBUG*/ +#ifndef SFCTOOL #ifdef UNIX #ifndef PATH_MAX #include @@ -3346,6 +3589,8 @@ Death_quote(char *buf, int bufsz) } /* ---------- END TRIBUTE ----------- */ +#endif /* !SFCTOOL */ + #ifdef LIVELOG #define LLOG_SEP "\t" /* livelog field separator, as a string literal */ #define LLOG_EOL "\n" /* end-of-line, for abstraction consistency */ diff --git a/src/light.c b/src/light.c index 618ba5684..574665fa9 100644 --- a/src/light.c +++ b/src/light.c @@ -42,6 +42,7 @@ #define LSF_NEEDS_FIXUP 0x2 /* need oid fixup */ #define LSF_IS_PROBLEMATIC 0x4 /* impossible situation encountered */ +#ifndef SFCTOOL staticfn light_source *new_light_core(coordxy, coordxy, int, int, anything *) NONNULLPTRS; staticfn void delete_ls(light_source *); @@ -468,6 +469,7 @@ save_light_sources(NHFILE *nhfp, int range) } } } +#endif /* !SFCTOOL */ /* * Pull in the structures from disk, but don't recalculate the object @@ -490,6 +492,7 @@ restore_light_sources(NHFILE *nhfp) } } +#ifndef SFCTOOL DISABLE_WARNING_FORMAT_NONLITERAL @@ -970,7 +973,7 @@ wiz_light_sources(void) return ECMD_OK; } - +#endif /* !SFCTOOL */ /* for 'onefile' processing where end of this file isn't necessarily the end of the source code seen by the compiler */ #undef LSF_SHOW diff --git a/src/mdlib.c b/src/mdlib.c index 95d4f1f2a..701b39901 100644 --- a/src/mdlib.c +++ b/src/mdlib.c @@ -61,7 +61,10 @@ char *version_id_string(char *, size_t, const char *) NONNULL NONNULLPTRS; char *bannerc_string(char *, size_t, const char *) NONNULL NONNULLPTRS; int case_insensitive_comp(const char *, const char *) NONNULLPTRS; -staticfn void make_version(void); +#ifndef SFCTOOL +staticfn +#endif /* SFCTOOL */ +void make_version(void); #ifndef HAS_NO_MKSTEMP #ifdef _MSC_VER @@ -234,10 +237,14 @@ md_ignored_features(void) { return (0UL | (1UL << 19) /* SCORE_ON_BOTL */ + | SFCTOOL_BIT /* stored by SFCTOOL, not NetHack itself */ ); } -staticfn void +#ifndef SFCTOOL +staticfn +#endif +void make_version(void) { int i; diff --git a/src/mkmaze.c b/src/mkmaze.c index af12ba15e..9c665a37e 100644 --- a/src/mkmaze.c +++ b/src/mkmaze.c @@ -6,6 +6,7 @@ #include "hack.h" #include "sp_lev.h" +#ifndef SFCTOOL staticfn int iswall(coordxy, coordxy); staticfn int iswall_or_stone(coordxy, coordxy); staticfn boolean is_solid(coordxy, coordxy); @@ -1736,6 +1737,7 @@ save_waterlevel(NHFILE *nhfp) if (release_data(nhfp)) unsetup_waterlevel(); } +#endif /* !SFCTOOL */ /* restoring air bubbles on Plane of Water or clouds on Plane of Air */ void @@ -1744,6 +1746,11 @@ restore_waterlevel(NHFILE *nhfp) struct bubble *b = (struct bubble *) 0, *btmp; int i, n = 0; +#ifdef SFCTOOL + svb.bbubbles = (struct bubble *) 0; + /* set_wportal(); */ +#endif + Sfi_int(nhfp, &n, "waterlevel-bubble_count"); Sfi_int(nhfp, &svx.xmin, "waterlevel-xmin"); Sfi_int(nhfp, &svy.ymin, "waterlevel-ymin"); @@ -1760,8 +1767,11 @@ restore_waterlevel(NHFILE *nhfp) svb.bbubbles = b; b->prev = (struct bubble *) 0; } +#ifndef SFCTOOL mv_bubble(b, 0, 0, TRUE); +#endif } +#ifndef SFCTOOL ge.ebubbles = b; if (b) { b->next = (struct bubble *) 0; @@ -1778,8 +1788,10 @@ restore_waterlevel(NHFILE *nhfp) : "air bubbles or clouds"); program_state.something_worth_saving = 1; } +#endif } +#ifndef SFCTOOL staticfn void set_wportal(void) { @@ -2087,5 +2099,6 @@ mv_bubble(struct bubble *b, coordxy dx, coordxy dy, boolean ini) } } } +#endif /* !SFCTOOL */ /*mkmaze.c*/ diff --git a/src/mkroom.c b/src/mkroom.c index 21dd56912..c859b1c0e 100644 --- a/src/mkroom.c +++ b/src/mkroom.c @@ -17,6 +17,7 @@ #include "hack.h" +#ifndef SFCTOOL staticfn boolean isbig(struct mkroom *); staticfn struct mkroom *pick_room(boolean); staticfn void mkshop(void), mkzoo(int), mkswamp(void); @@ -25,10 +26,12 @@ staticfn void mktemple(void); staticfn coord *shrine_pos(int); staticfn struct permonst *morguemon(void); staticfn struct permonst *squadmon(void); +#endif /* SFCTOOL */ staticfn void save_room(NHFILE *, struct mkroom *); staticfn void rest_room(NHFILE *, struct mkroom *); +#ifndef SFCTOOL staticfn boolean invalid_shop_shape(struct mkroom *sroom); #define sq(x) ((x) * (x)) @@ -866,6 +869,7 @@ save_rooms(NHFILE *nhfp) for (i = 0; i < svn.nroom; i++) save_room(nhfp, &svr.rooms[i]); } +#endif /* !SFCTOOL */ staticfn void rest_room(NHFILE *nhfp, struct mkroom *r) @@ -901,6 +905,7 @@ rest_rooms(NHFILE *nhfp) gs.subrooms[gn.nsubroom].hx = -1; } +#ifndef SFCTOOL /* convert a display symbol for terrain into topology type; used for remembered terrain when mimics pose as furniture */ int @@ -1089,5 +1094,6 @@ invalid_shop_shape(struct mkroom *sroom) } return FALSE; } +#endif /* !SFCTOOL */ /*mkroom.c*/ diff --git a/src/nhlua.c b/src/nhlua.c index 0a77eb108..3ed150392 100644 --- a/src/nhlua.c +++ b/src/nhlua.c @@ -25,6 +25,7 @@ struct e; +#ifndef SFCTOOL /* lua_CFunction prototypes */ #ifdef DUMPLOG staticfn int nhl_dump_fmtstr(lua_State *); @@ -91,7 +92,9 @@ staticfn void nhl_warn(void *, const char *, int); staticfn void nhl_clearfromtable(lua_State *, int, int, struct e *); staticfn int nhl_panic(lua_State *); staticfn void nhl_hookfn(lua_State *, lua_Debug *); +#endif /* !SFCTOOL */ +#ifndef SFCTOOL static const char *const nhcore_call_names[NUM_NHCORE_CALLS] = { "start_new_game", "restore_old_game", @@ -102,6 +105,7 @@ static const char *const nhcore_call_names[NUM_NHCORE_CALLS] = { "leave_tutorial", }; static boolean nhcore_call_available[NUM_NHCORE_CALLS]; +#endif /* internal structure that hangs off L->ud (but use lua_getallocf() ) * Note that we use it for both memory use tracking and instruction counting. @@ -126,6 +130,7 @@ typedef struct nhl_user_data { #endif } nhl_user_data; +#ifndef SFCTOOL static lua_State *luapat; /* instance for file pattern matching */ void @@ -1264,20 +1269,26 @@ get_nh_lua_variables(void) RESTORE_WARNING_UNREACHABLE_CODE -/* char *lua_data; */ +#endif /* !SFCTOOL */ + +#ifdef SFCTOOL +char *lua_data; +#endif /* save nh_lua_variables table to file */ void save_luadata(NHFILE *nhfp) { unsigned lua_data_len; +#ifndef SFCTOOL char *lua_data = get_nh_lua_variables(); /* note: '\0' terminated */ +#endif if (!lua_data) lua_data = dupstr(emptystr); lua_data_len = Strlen(lua_data) + 1; /* +1: include the terminator */ Sfo_unsigned(nhfp, &lua_data_len, "luadata-lua_data_len"); - Sfo_char(nhfp, lua_data, "lua_data", lua_data_len); + Sfo_char(nhfp, lua_data, "luadata", lua_data_len); free(lua_data); } @@ -1286,18 +1297,25 @@ void restore_luadata(NHFILE *nhfp) { unsigned lua_data_len = 0; +#ifndef SFCTOOL char *lua_data; +#endif /* !SFCTOOL */ Sfi_unsigned(nhfp, &lua_data_len, "luadata-lua_data_len"); lua_data = (char *) alloc(lua_data_len); Sfi_char(nhfp, lua_data, "luadata", lua_data_len); + +#ifndef SFCTOOL if (!gl.luacore) l_nhcore_init(); luaL_loadstring(gl.luacore, lua_data); free(lua_data); nhl_pcall_handle(gl.luacore, 0, 0, "restore_luadata", NHLpa_panic); +#endif /* !SFCTOOL */ } +#ifndef SFCTOOL + /* local stairs = stairways(); */ staticfn int nhl_stairways(lua_State *L) @@ -2977,6 +2995,8 @@ nhlL_newstate(nhl_sandbox_info *sbi, const char *name) return L; } +#endif /* !SFCTOOL */ + /* (See end of comment for conclusion.) to make packages safe, we need something like: diff --git a/src/o_init.c b/src/o_init.c index 04730e3a2..c62ca0a0c 100644 --- a/src/o_init.c +++ b/src/o_init.c @@ -5,6 +5,7 @@ #include "hack.h" +#ifndef SFCTOOL staticfn void setgemprobs(d_level *); staticfn void randomize_gem_colors(void); staticfn void shuffle(int, int, boolean); @@ -403,6 +404,7 @@ savenames(NHFILE *nhfp) } } } +#endif /* !SFCTOOL */ void restnames(NHFILE *nhfp) @@ -426,11 +428,14 @@ restnames(NHFILE *nhfp) Sfi_char(nhfp, objects[i].oc_uname, "names-oc_uname", (int) len); } } +#ifndef SFCTOOL #ifdef TILES_IN_GLYPHMAP shuffle_tiles(); #endif +#endif } +#ifndef SFCTOOL void discover_object( int oindx, @@ -562,6 +567,7 @@ sortloot_descr(int otyp, char *outbuf) sl_cookie.orderclass, sl_cookie.subclass, sl_cookie.disco); return outbuf; } +#endif /* !SFCTOOL */ #define DISCO_BYCLASS 0 /* by discovery order within each class */ #define DISCO_SORTLOOT 1 /* by discovery order within each subclass */ @@ -577,6 +583,8 @@ static const char *const disco_orders_descr[] = { (char *) 0 }; +#ifndef SFCTOOL + int choose_disco_sort( int mode) /* 0 => 'O' cmd, 1 => full discoveries; 2 => class disco */ @@ -1110,6 +1118,7 @@ rename_disco(void) destroy_nhwindow(tmpwin); return; } +#endif /* !SFCTOOL */ void get_sortdisco(char *opts, boolean cnf) diff --git a/src/region.c b/src/region.c index b0aeb1127..796d48fc1 100644 --- a/src/region.c +++ b/src/region.c @@ -13,6 +13,7 @@ #define NO_CALLBACK (-1) void free_region(NhRegion *); +#ifndef SFCTOOL boolean inside_gas_cloud(genericptr, genericptr); boolean expire_gas_cloud(genericptr, genericptr); boolean inside_rect(NhRect *, int, int); @@ -253,6 +254,7 @@ clone_region(NhRegion *reg) } #endif /*0*/ +#endif /* !SFCTOOL */ /* * Free mem from region. @@ -273,6 +275,7 @@ free_region(NhRegion *reg) } } +#ifndef SFCTOOL /* * Add a region to the list. * This actually activates the region. @@ -381,6 +384,7 @@ remove_region(NhRegion *reg) } free_region(reg); } +#endif /* !SFCTOOL */ /* * Remove all regions and clear all related data. This must be done @@ -400,6 +404,7 @@ clear_regions(void) gr.regions = (NhRegion **) 0; } +#ifndef SFCTOOL /* * This function is called every turn. * It makes the regions age, if necessary and calls the appropriate @@ -788,6 +793,7 @@ save_regions(NHFILE *nhfp) if (release_data(nhfp)) clear_regions(); } +#endif /* !SFCTOOL */ void rest_regions(NHFILE *nhfp) @@ -872,6 +878,7 @@ rest_regions(NHFILE *nhfp) Sfi_int(nhfp, &r->glyph, "region-glyph"); Sfi_any(nhfp, &r->arg, "region-arg"); } +#ifndef SFCTOOL /* remove expired regions, do not trigger the expire_f callback (yet!); also update monster lists if this data is coming from a bones file */ for (i = svn.n_regions - 1; i >= 0; i--) { @@ -881,8 +888,10 @@ rest_regions(NHFILE *nhfp) else if (ghostly && r->n_monst > 0) reset_region_mids(r); } +#endif /* !SFCTOOL */ } +#ifndef SFCTOOL DISABLE_WARNING_FORMAT_NONLITERAL /* to support '#stats' wizard-mode command */ @@ -1394,5 +1403,6 @@ region_safety(void) if (BlindedTimeout == 1L) make_blinded(0L, TRUE); } +#endif /* !SFCTOOL */ /*region.c*/ diff --git a/src/restore.c b/src/restore.c index 77e4e2383..dc87cb696 100644 --- a/src/restore.c +++ b/src/restore.c @@ -22,6 +22,7 @@ staticfn struct fruit *loadfruitchn(NHFILE *); staticfn void freefruitchn(struct fruit *); staticfn void rest_levl(NHFILE *); staticfn void rest_stairs(NHFILE *); +#ifndef SFCTOOL staticfn void ghostfruit(struct obj *); staticfn boolean restgamestate(NHFILE *); staticfn void restlevelstate(void); @@ -29,10 +30,12 @@ staticfn int restlevelfile(xint8); staticfn void rest_bubbles(NHFILE *); staticfn void restore_gamelog(NHFILE *); staticfn void reset_oattached_mids(boolean); +/* these ones are declared non-static in extern.h if SFCTOOL is defined */ staticfn boolean restgamestate(NHFILE *); staticfn void rest_bubbles(NHFILE *); staticfn void restore_gamelog(NHFILE *); staticfn void restore_msghistory(NHFILE *); +#endif /* * Save a mapping of IDs from ghost levels to the current level. This @@ -47,8 +50,10 @@ struct bucket { } map[N_PER_BUCKET]; }; +#ifndef SFCTOOL staticfn void clear_id_mapping(void); staticfn void add_id_mapping(unsigned, unsigned); +#endif /* SFCTOOL */ #ifdef AMII_GRAPHICS void amii_setpens(int); /* use colors from save file */ @@ -59,6 +64,7 @@ extern int amii_numcolors; #define Is_IceBox(o) ((o)->otyp == ICE_BOX ? TRUE : FALSE) +#ifndef SFCTOOL /* Recalculate svl.level.objects[x][y], since this info was not saved. */ staticfn void @@ -118,6 +124,8 @@ inven_inuse(boolean quietly) } } +#endif /* SFCTOOL */ + staticfn void restlevchn(NHFILE *nhfp) { @@ -147,7 +155,9 @@ restdamage(NHFILE *nhfp) unsigned int dmgcount = 0; int counter; struct damage *tmp_dam; +#ifndef SFCTOOL boolean ghostly = (nhfp->ftype == NHF_BONESFILE); +#endif Sfi_unsigned(nhfp, &dmgcount, "damage-damage_count"); counter = (int) dmgcount; @@ -158,11 +168,13 @@ restdamage(NHFILE *nhfp) tmp_dam = (struct damage *) alloc(sizeof *tmp_dam); Sfi_damage(nhfp, tmp_dam, "damage"); +#ifndef SFCTOOL if (ghostly) tmp_dam->when += (svm.moves - svo.omoves); tmp_dam->next = svl.level.damagelist; svl.level.damagelist = tmp_dam; +#endif /* !SFCTOOL */ } while (--counter > 0); } @@ -199,7 +211,7 @@ restobj(NHFILE *nhfp, struct obj *otmp) } /* omailcmd - feedback mechanism for scroll of mail */ - Sfi_int(nhfp, &buflen, "obj-omail_length"); + Sfi_int(nhfp, &buflen, "obj-omailcmd_length"); if (buflen > 0) { char *omailcmd = (char *) alloc(buflen); @@ -210,7 +222,7 @@ restobj(NHFILE *nhfp, struct obj *otmp) /* omid - monster id number, connecting corpse to ghost */ newomid(otmp); /* superfluous; we're already allocated otmp->oextra */ - Sfi_unsigned(nhfp, &omid, "obj-omid_length"); + Sfi_unsigned(nhfp, &omid, "obj-omid"); OMID(otmp) = omid; } } @@ -221,10 +233,15 @@ restobjchn(NHFILE *nhfp, boolean frozen) struct obj *otmp, *otmp2 = 0; struct obj *first = (struct obj *) 0; int buflen = 0; +#ifndef SFCTOOL boolean ghostly = (nhfp->ftype == NHF_BONESFILE); +#endif + boolean trouble = FALSE; while (1) { Sfi_int(nhfp, &buflen, "obj-obj_length"); + if (!(buflen != -1 || buflen != sizeof (struct obj))) + trouble = TRUE; if (buflen == -1) break; @@ -236,6 +253,7 @@ restobjchn(NHFILE *nhfp, boolean frozen) else otmp2->nobj = otmp; +#ifndef SFCTOOL if (ghostly) { unsigned nid = next_ident(); @@ -250,6 +268,7 @@ restobjchn(NHFILE *nhfp, boolean frozen) */ if (ghostly && !frozen && !age_is_relative(otmp)) otmp->age = svm.moves - svo.omoves + otmp->age; +#endif /* !SFCTOOL */ /* get contents of a container or statue */ if (Has_contents(otmp)) { @@ -261,6 +280,7 @@ restobjchn(NHFILE *nhfp, boolean frozen) otmp3->ocontainer = otmp; } +#ifndef SFCTOOL if (otmp->bypass) otmp->bypass = 0; if (!ghostly) { @@ -272,12 +292,17 @@ restobjchn(NHFILE *nhfp, boolean frozen) if (otmp->o_id == svc.context.spbook.o_id) svc.context.spbook.book = otmp; } +#endif /* !SFADUSTER */ otmp2 = otmp; } if (first && otmp2->nobj) { impossible("Restobjchn: error reading objchn."); otmp2->nobj = 0; } +#ifdef SFCTOOL + nhUse(frozen); +#endif + nhUse(trouble); return first; } @@ -353,8 +378,11 @@ restmonchn(NHFILE *nhfp) { struct monst *mtmp, *mtmp2 = 0; struct monst *first = (struct monst *) 0; - int offset, buflen = 0; + int buflen = 0; +#ifndef SFCTOOL + int offset; boolean ghostly = (nhfp->ftype == NHF_BONESFILE); +#endif while (1) { Sfi_int(nhfp, &buflen, "monst-monst_length"); @@ -369,6 +397,7 @@ restmonchn(NHFILE *nhfp) else mtmp2->nmon = mtmp; +#ifndef SFCTOOL if (ghostly) { unsigned nid = next_ident(); @@ -386,13 +415,21 @@ restmonchn(NHFILE *nhfp) mtmp->mhpmax = DEFUNCT_MONSTER; } } +#endif /* !SFCTOOL */ + if (mtmp->minvent) { struct obj *obj; mtmp->minvent = restobjchn(nhfp, FALSE); +#ifndef SFCTOOL /* restore monster back pointer */ for (obj = mtmp->minvent; obj; obj = obj->nobj) obj->ocarry = mtmp; +#else + nhUse(obj); +#endif } + +#ifndef SFCTOOL if (mtmp->mw) { struct obj *obj; @@ -416,12 +453,15 @@ restmonchn(NHFILE *nhfp) if (mtmp->m_id == svc.context.polearm.m_id) svc.context.polearm.hitmon = mtmp; } +#endif /* !SFCTOOL */ mtmp2 = mtmp; } +#ifndef SFCTOOL if (first && mtmp2->nmon) { impossible("Restmonchn: error reading monchn."); mtmp2->nmon = 0; } +#endif return first; } @@ -456,6 +496,7 @@ freefruitchn(struct fruit *flist) } } +#ifndef SFCTOOL staticfn void ghostfruit(struct obj *otmp) { @@ -470,6 +511,7 @@ ghostfruit(struct obj *otmp) else otmp->spe = fruitadd(oldf->fname, (struct fruit *) 0); } +#endif /* !SFCTOOL */ #ifdef SYSCF #define SYSOPT_CHECK_SAVE_UID sysopt.check_save_uid @@ -477,7 +519,10 @@ ghostfruit(struct obj *otmp) #define SYSOPT_CHECK_SAVE_UID TRUE #endif -staticfn boolean +#ifndef SFCTOOL +staticfn +#endif +boolean restgamestate(NHFILE *nhfp) { int i; @@ -486,15 +531,18 @@ restgamestate(NHFILE *nhfp) struct obj *bc_obj; char timebuf[15]; unsigned long uid = 0; +#ifndef SFCTOOL boolean defer_perm_invent, restoring_special; struct obj *otmp; +#endif Sfi_ulong(nhfp, &uid, "gamestate-uid"); +#ifndef SFCTOOL if (SYSOPT_CHECK_SAVE_UID && uid != (unsigned long) getuid()) { /* strange ... */ if (!gc.converted_savefile_loaded) /* for wizard mode, issue a reminder; for others, treat it - as an attempt to cheat and refuse to restore this file */ + * as an attempt to cheat and refuse to restore this file */ pline("Saved game was not yours."); if (wizard || gc.converted_savefile_loaded) { if (gc.converted_savefile_loaded) @@ -503,7 +551,7 @@ restgamestate(NHFILE *nhfp) return FALSE; } } - +#endif /* SFCTOOL */ newgamecontext = svc.context; /* copy statically init'd context */ Sfi_context_info(nhfp, &svc.context, "gamestate-context"); svc.context.warntype.species = (ismnum(svc.context.warntype.speciesidx)) @@ -519,6 +567,7 @@ restgamestate(NHFILE *nhfp) newgameflags = flags; Sfi_flag(nhfp, &flags, "gamestate-flags"); +#ifndef SFCTOOL /* avoid keeping permanent inventory window up to date during restore (setworn() calls update_inventory); attempting to include the cost of unpaid items before shopkeeper's bill is available is a no-no; @@ -545,16 +594,18 @@ restgamestate(NHFILE *nhfp) #ifdef AMII_GRAPHICS amii_setpens(amii_numcolors); /* use colors from save file */ #endif - +#endif /* !SFCTOOL */ Sfi_you(nhfp, &u, "gamestate-you"); gy.youmonst.cham = u.mcham; +#ifndef SFCTOOL if (restoring_special && iflags.explore_error_flag) { /* savefile has wizard or explore mode, but player is no longer authorized to access either; can't downgrade mode any further, so fail restoration. */ u.uhp = 0; } +#endif Sfi_char(nhfp, timebuf, "gamestate-ubirthday", 14); timebuf[14] = '\0'; @@ -562,6 +613,7 @@ restgamestate(NHFILE *nhfp) Sfi_long(nhfp, &urealtime.realtime, "gamestate-realtime"); Sfi_char(nhfp, timebuf, "gamestate-start_timing", 14); timebuf[14] = '\0'; +#ifndef SFCTOOL urealtime.start_timing = time_from_yyyymmddhhmmss(timebuf); /* current time is the time to use for next urealtime.realtime update */ @@ -590,6 +642,7 @@ restgamestate(NHFILE *nhfp) } /* in case hangup save occurred in midst of level change */ assign_level(&u.uz0, &u.uz); +#endif /* !SFCTOOL */ /* this stuff comes after potential aborted restore attempts */ restore_killers(nhfp); @@ -600,7 +653,7 @@ restgamestate(NHFILE *nhfp) /* restore dangling (not on floor or in inventory) ball and/or chain */ bc_obj = restobjchn(nhfp, FALSE); - +#ifndef SFCTOOL while (bc_obj) { struct obj *nobj = bc_obj->nobj; @@ -609,13 +662,15 @@ restgamestate(NHFILE *nhfp) setworn(bc_obj, bc_obj->owornmask); bc_obj = nobj; } - +#endif gm.migrating_objs = restobjchn(nhfp, FALSE); gm.migrating_mons = restmonchn(nhfp); for (i = 0; i < NUMMONS; ++i) { Sfi_mvitals(nhfp, &svm.mvitals[i], "gamestate-mvitals"); } + +#ifndef SFCTOOL /* * There are some things after this that can have unintended display * side-effects too early in the game. @@ -637,6 +692,7 @@ restgamestate(NHFILE *nhfp) setuwep(otmp); /* (don't need any null check here) */ if (!uwep || uwep->otyp == PICK_AXE || uwep->otyp == GRAPPLING_HOOK) gu.unweapon = TRUE; +#endif /* !SFCTOOL */ restore_dungeon(nhfp); restlevchn(nhfp); @@ -660,15 +716,22 @@ restgamestate(NHFILE *nhfp) restore_msghistory(nhfp); restore_gamelog(nhfp); restore_luadata(nhfp); +#ifndef SFCTOOL /* must come after all mons & objs are restored */ relink_timers(FALSE); relink_light_sources(FALSE); adj_erinys(u.ualign.abuse); /* inventory display is now viable */ iflags.perm_invent = defer_perm_invent; +#else + nhUse(bc_obj); + nhUse(newgamecontext); + nhUse(newgameflags); +#endif /* !SFCTOOL */ return TRUE; } +#ifndef SFCTOOL /* update game state pointers to those valid for the current level (so we don't dereference a wild u.ustuck when saving game state, for instance) */ staticfn void @@ -886,15 +949,20 @@ dorecover(NHFILE *nhfp) check_special_room(FALSE); return 1; } +#endif /* !SFCTOOL */ staticfn void rest_stairs(NHFILE *nhfp) { int buflen = 0; stairway stway = UNDEFINED_VALUES; +#ifndef SFCTOOL stairway *newst; +#endif +#ifndef SFCTOOL stairway_free_all(); +#endif while (1) { Sfi_int(nhfp, &buflen, "stairs-staircount"); if (buflen == -1) @@ -906,11 +974,13 @@ rest_stairs(NHFILE *nhfp) /* stairway dlevel is relative, make it absolute */ stway.tolev.dlevel += u.uz.dlevel; } +#ifndef SFCTOOL stairway_add(stway.sx, stway.sy, stway.up, stway.isladder, &(stway.tolev)); newst = stairway_at(stway.sx, stway.sy); if (newst) newst->u_traversed = stway.u_traversed; +#endif } } @@ -932,7 +1002,8 @@ restcemetery(NHFILE *nhfp, struct cemetery **cemeteryaddr) } else { *cemeteryaddr = 0; } - if ((nhfp->mode & CONVERTING) != 0) { + if (((nhfp->mode & CONVERTING) != 0) + || ((nhfp->mode & UNCONVERTING) != 0)) { struct cemetery *thisbones, *nextbones; /* free the memory */ @@ -958,6 +1029,8 @@ rest_levl(NHFILE *nhfp) } } +#ifndef SFCTOOL + void trickery(char *reason) { @@ -967,14 +1040,17 @@ trickery(char *reason) Strcpy(svk.killer.name, reason ? reason : ""); done(TRICKED); } +#endif /* !SFCTOOL */ void getlev(NHFILE *nhfp, int pid, xint8 lev) { struct trap *trap; +#ifndef SFCTOOL struct monst *mtmp; branch *br; int x, y; +#endif long elapsed = 0L; int hpid = 0; xint8 dlvl = 0; @@ -986,9 +1062,11 @@ getlev(NHFILE *nhfp, int pid, xint8 lev) #endif program_state.in_getlev = TRUE; +#ifndef SFCTOOL if (ghostly) clear_id_mapping(); +#endif /* !SFCTOOL */ #if 0 #if defined(MSDOS) || defined(OS2) @@ -1007,6 +1085,7 @@ getlev(NHFILE *nhfp, int pid, xint8 lev) Sfi_int(nhfp, &hpid, "gamestate-hackpid"); /* CHECK: This may prevent restoration */ Sfi_xint8(nhfp, &dlvl, "gamestate-dlvl"); +#ifndef SFCTOOL if ((pid && pid != hpid) || (lev && dlvl != lev)) { char trickbuf[BUFSZ]; @@ -1019,6 +1098,7 @@ getlev(NHFILE *nhfp, int pid, xint8 lev) pline1(trickbuf); trickery(trickbuf); } +#endif restcemetery(nhfp, &svl.level.bonesinfo); rest_levl(nhfp); @@ -1051,10 +1131,14 @@ getlev(NHFILE *nhfp, int pid, xint8 lev) } rest_rooms(nhfp); /* No joke :-) */ if (svn.nroom) { +#ifndef SFCTOOL gd.doorindex = svr.rooms[svn.nroom - 1].fdoor + svr.rooms[svn.nroom - 1].doorct; } else { gd.doorindex = 0; +#else + gd.doorindex = 0; +#endif /* !SFCTOOL */ } restore_timers(nhfp, RANGE_LEVEL, elapsed); @@ -1080,14 +1164,16 @@ getlev(NHFILE *nhfp, int pid, xint8 lev) dealloc_trap(trap); fobj = restobjchn(nhfp, FALSE); +#ifndef SFCTOOL find_lev_obj(); +#endif /* !SFCTOOL */ /* restobjchn()'s `frozen' argument probably ought to be a callback routine so that we can check for objects being buried under ice */ svl.level.buriedobjlist = restobjchn(nhfp, FALSE); gb.billobjs = restobjchn(nhfp, FALSE); rest_engravings(nhfp); - +#ifndef SFCTOOL /* reset level.monsters for new level */ for (x = 0; x < COLNO; x++) for (y = 0; y < ROWNO; y++) @@ -1133,6 +1219,7 @@ getlev(NHFILE *nhfp, int pid, xint8 lev) if (ghostly || (elapsed > 00 && elapsed > (long) rnd(10))) hide_monst(mtmp); } +#endif /* !SFCTOOL */ restdamage(nhfp); rest_regions(nhfp); @@ -1140,6 +1227,7 @@ getlev(NHFILE *nhfp, int pid, xint8 lev) load_exclusions(nhfp); rest_track(nhfp); +#ifndef SFCTOOL if (ghostly) { stairway *stway = gs.stairs; while (stway) { @@ -1215,6 +1303,11 @@ getlev(NHFILE *nhfp, int pid, xint8 lev) if (ghostly) clear_id_mapping(); program_state.in_getlev = FALSE; +#else + nhUse(pid); + nhUse(lev); +#endif /* !SFCTOOL */ + program_state.in_getlev = FALSE; } /* "name-role-race-gend-algn" occurs very early in a save file; sometimes we @@ -1247,7 +1340,10 @@ get_plname_from_file( } /* restore Plane of Water's air bubbles and Plane of Air's clouds */ -staticfn void +#ifndef SFCTOOL +staticfn +#endif +void rest_bubbles(NHFILE *nhfp) { xint8 bbubbly; @@ -1265,7 +1361,10 @@ rest_bubbles(NHFILE *nhfp) restore_waterlevel(nhfp); } -staticfn void +#ifndef SFCTOOL +staticfn +#endif +void restore_gamelog(NHFILE *nhfp) { int slen = 0; @@ -1281,11 +1380,16 @@ restore_gamelog(NHFILE *nhfp) Sfi_char(nhfp, msg, "gamelog-gamelog_text", slen); msg[slen] = '\0'; Sfi_gamelog_line(nhfp, &tmp, "gamelog-gamelog_line"); +#ifndef SFCTOOL gamelog_add(tmp.flags, tmp.turn, msg); +#endif /* !SFCTOOL */ } } -staticfn void +#ifndef SFCTOOL +staticfn +#endif +void restore_msghistory(NHFILE *nhfp) { int msgsize = 0; @@ -1300,14 +1404,20 @@ restore_msghistory(NHFILE *nhfp) panic("restore_msghistory: msg too big (%d)", msgsize); Sfi_char(nhfp, msg, "msghistory-msg", msgsize); msg[msgsize] = '\0'; +#ifndef SFCTOOL putmsghistory(msg, TRUE); +#endif /* !SFCTOOL */ ++msgcount; } +#ifndef SFCTOOL if (msgcount) putmsghistory((char *) 0, TRUE); debugpline1("Read %d messages from savefile.", msgcount); +#endif /* !SFCTOOL */ } +#ifndef SFCTOOL + /* Clear all structures for object and monster ID mapping. */ staticfn void clear_id_mapping(void) @@ -1483,5 +1593,6 @@ restore_menu( return (ch > 0) ? 1 : ch; } #endif /* SELECTSAVED */ +#endif /* !SFCTOOL */ /*restore.c*/ diff --git a/src/rumors.c b/src/rumors.c index 2e58d6225..711d08516 100644 --- a/src/rumors.c +++ b/src/rumors.c @@ -41,6 +41,7 @@ * and placed there by 'makedefs'. */ +#ifndef SFCTOOL staticfn void unpadline(char *); staticfn void init_rumors(dlb *); staticfn char *get_rnd_line(dlb *, char *, unsigned, int (*)(int), @@ -615,6 +616,7 @@ save_oracles(NHFILE *nhfp) } } } +#endif /* !SFCTOOL */ void restore_oracles(NHFILE *nhfp) @@ -632,6 +634,7 @@ restore_oracles(NHFILE *nhfp) } } +#ifndef SFCTOOL void outoracle(boolean special, boolean delphi) { @@ -947,5 +950,6 @@ free_CapMons(void) } CapMonSiz = 0; } +#endif /* !SFCTOOL */ /*rumors.c*/ diff --git a/src/save.c b/src/save.c index 4e4f568a3..bc420a041 100644 --- a/src/save.c +++ b/src/save.c @@ -115,7 +115,7 @@ dosave0(void) clear_nhwindow(WIN_MESSAGE); There("seems to be an old save file."); if (y_n("Overwrite the old file?") == 'n') { - //nh_sfconvert(fq_save); + nh_sfconvert(fq_save); nh_compress(fq_save); goto done; } @@ -131,8 +131,7 @@ dosave0(void) goto done; } if (nhfp && nhfp->fplog) { - /* (void) fprintf(nhfp->fplog, "# just opened\n"); */ - nhfp->count = 0L; + nhfp->rcount = nhfp->wcount = 0L; } vision_recalc(2); /* shut down vision to prevent problems @@ -221,7 +220,7 @@ dosave0(void) /* get rid of current level --jgm */ delete_levelfile(ledger_no(&u.uz)); delete_levelfile(0); - ///nh_sfconvert(fq_save); + nh_sfconvert(fq_save); nh_compress(fq_save); /* this should probably come sooner... */ program_state.something_worth_saving = 0; @@ -1144,7 +1143,7 @@ freedynamicdata(void) #endif discard_gamelog(); release_runtime_info(); /* build-time options and version stuff */ - //free_convert_filenames(); + free_convert_filenames(); #endif /* FREE_ALL_MEMORY */ if (VIA_WINDOWPORT()) diff --git a/src/sfbase.c b/src/sfbase.c index 6a62865af..580f5f001 100644 --- a/src/sfbase.c +++ b/src/sfbase.c @@ -4,82 +4,242 @@ #include "hack.h" #include "sfprocs.h" +#ifdef SFCTOOL +//#include "sfproto.h" +#endif /* #define DO_DEBUG */ +//#define TURN_OFF_LOGGING 0x20 +#define TURN_OFF_LOGGING (UNCONVERTING << 1) + struct sf_structlevel_procs sfoprocs[NUM_SAVEFORMATS], sfiprocs[NUM_SAVEFORMATS], zerosfoprocs = {0}, zerosfiprocs = {0}; +struct sf_fieldlevel_procs sfoflprocs[NUM_SAVEFORMATS], sfiflprocs[NUM_SAVEFORMATS], + zerosfoflprocs = {0}, zerosfiflprocs = {0}; -void sf_log(NHFILE *, const char *, size_t, int); +char *sfvalue_aligntyp(aligntyp *a); +char *sfvalue_any(anything *a); +char *sfvalue_genericptr(genericptr a); +char *sfvalue_int16(int16 *a); +char *sfvalue_int32(int32 *a); +char *sfvalue_int64(int64 *a); +char *sfvalue_uchar(uchar *a); +char *sfvalue_uint16(uint16 *a); +char *sfvalue_uint32(uint32 *a); +char *sfvalue_uint64(uint64 *a); +char *sfvalue_size_t(size_t *a); +char *sfvalue_time_t(time_t *a); +char *sfvalue_short(short *a); +char *sfvalue_ushort(ushort *a); +char *sfvalue_int(int *a); +char *sfvalue_unsigned(unsigned *a); +char *sfvalue_long(long *a); +char *sfvalue_ulong(ulong *a); +char *sfvalue_xint8(xint8 *a); +char *sfvalue_xint16(xint16 *a); +char *sfvalue_char(char *a, int n); +char *sfvalue_boolean(boolean *a); +char *sfvalue_schar(schar *a); +char *sfvalue_bitfield(uint8 *a); +char *complex_dump(uchar *a); +char *bitfield_dump(uint8 *a); + +void sf_log(NHFILE *, const char *, size_t, int, char *); + +#if NH_C < 202300L +#define Sfvalue_aligntyp(a) sfvalue_aligntyp(a) +#define Sfvalue_any(a) sfvalue_any(a) +#define Sfvalue_genericptr(a) sfvalue_genericptr(a) +#define Sfvalue_coordxy(a) sfvalue_int16(a) +#define Sfvalue_int16(a) sfvalue_int16(a) +#define Sfvalue_int32(a) sfvalue_int32(a) +#define Sfvalue_int64(a) sfvalue_int64(a) +#define Sfvalue_uchar(a) sfvalue_uchar(a) +#define Sfvalue_uint16(a) sfvalue_uint16(a) +#define Sfvalue_uint32(a) sfvalue_uint32(a) +#define Sfvalue_uint64(a) sfvalue_uint64(a) +#define Sfvalue_size_t(a) sfvalue_size_t(a) +#define Sfvalue_time_t(a) sfvalue_time_t(a) +#define Sfvalue_short(a) sfvalue_short(a) +#define Sfvalue_ushort(a) sfvalue_ushort(a) +#define Sfvalue_int(a) sfvalue_int(a) +#define Sfvalue_unsigned(a) sfvalue_unsigned(a) +#define Sfvalue_long(a) sfvalue_long(a) +#define Sfvalue_ulong(a) sfvalue_ulong(a) +#define Sfvalue_xint8(a) sfvalue_xint8(a) +#define Sfvalue_xint16(a) sfvalue_xint16(a) + +#else + +#define sfvalue(x) \ + _Generic( (x), \ + anything *: sfvalue_any, \ + genericptr_t *: sfvalue_genericptr, \ + int16_t *: sfvalue_int16, \ + int32_t *: sfvalue_int32, \ + int64_t *: sfvalue_int64, \ + uchar *: sfvalue_uchar, \ + uint16_t *: sfvalue_uint16, \ + uint32_t *: sfvalue_uint32, \ + uint64_t *: sfvalue_uint64, \ + long *: sfvalue_long, \ + unsigned long *: sfvalue_ulong, \ + xint8 *: sfvalue_xint8 \ + )(x) + +#define Sfvalue_any(a) sfvalue(a) +#define Sfvalue_aligntyp(a) sfvalue(a) +#define Sfvalue_genericptr(a) sfvalue(a) +#define Sfvalue_coordxy(a) sfvalue(a) +#define Sfvalue_int16(a) sfvalue(a) +#define Sfvalue_int32(a) sfvalue(a) +#define Sfvalue_int64(a) sfvalue(a) +#define Sfvalue_uchar(a) sfvalue(a) +#define Sfvalue_unsigned(a) sfvalue(a) +#define Sfvalue_uchar(a) sfvalue(a) +#define Sfvalue_uint16(a) sfvalue(a) +#define Sfvalue_uint32(a) sfvalue(a) +#define Sfvalue_uint64(a) sfvalue(a) +#define Sfvalue_size_t(a) sfvalue(a) +#define Sfvalue_time_t(a) sfvalue(a) +#define Sfvalue_short(a) sfvalue(a) +#define Sfvalue_ushort(a) sfvalue(a) +#define Sfvalue_int(a) sfvalue(a) +#define Sfvalue_unsigned(a) sfvalue(a) +#define Sfvalue_long(a) sfvalue(a) +#define Sfvalue_ulong(a) sfvalue(a) +#define Sfvalue_xint8(a) sfvalue(a) +#define Sfvalue_xint16(a) sfvalue(a) +#endif + +/* not in _Generic */ +#define Sfvalue_char(a, d) sfvalue_char(a, d) +#define Sfvalue_boolean(a) sfvalue_boolean(a) +#define Sfvalue_schar(a) sfvalue_schar(a) +#define Sfvalue_bitfield(a) sfvalue_bitfield(a) #define SF_A(dtyp) \ -void sfo_##dtyp(NHFILE *nhfp, dtyp *d_##dtyp, const char *myname) \ -{ \ - if (nhfp->fplog) \ - sf_log(nhfp, myname, sizeof *d_##dtyp, 1); \ - if (nhfp->structlevel) { \ - (*sfoprocs[nhfp->fnidx].fn.sf_##dtyp)(nhfp, d_##dtyp, myname); \ - } \ -} \ - \ -void sfi_##dtyp(NHFILE *nhfp, dtyp *d_##dtyp, const char *myname) \ -{ \ - if (nhfp->structlevel) { \ - (*sfiprocs[nhfp->fnidx].fn.sf_##dtyp)(nhfp, d_##dtyp, myname); \ - } \ - if (nhfp->fplog && !nhfp->eof) \ - sf_log(nhfp, myname, sizeof *d_##dtyp, 1); \ - if (nhfp->eof) \ - return; \ - if (((nhfp->mode & CONVERTING) != 0) && nhfp->nhfpconvert) \ - sfo_##dtyp(nhfp->nhfpconvert, d_##dtyp, myname); \ +void sfo_##dtyp(NHFILE *nhfp, dtyp *d_##dtyp, const char *myname) \ +{ \ + if (nhfp->fplog) \ + sf_log(nhfp, myname, sizeof *d_##dtyp, 1, Sfvalue_##dtyp(d_##dtyp)); \ + if (nhfp->structlevel) { \ + (*sfoprocs[nhfp->fnidx].fn.sf_##dtyp)(nhfp, d_##dtyp, myname); \ + } else { \ + FILE *save_fplog = nhfp->fplog; \ + \ + nhfp->fplog = 0; \ + (*sfoflprocs[nhfp->fnidx].fn_x.sf_##dtyp)(nhfp, d_##dtyp, myname); \ + nhfp->fplog = save_fplog; \ + } \ +} \ + \ +void sfi_##dtyp(NHFILE *nhfp, dtyp *d_##dtyp, const char *myname) \ +{ \ + if (nhfp->structlevel) { \ + (*sfiprocs[nhfp->fnidx].fn.sf_##dtyp)(nhfp, d_##dtyp, myname); \ + } else { \ + int save_mode = nhfp->mode; \ + \ + nhfp->mode &= ~(CONVERTING | UNCONVERTING); \ + nhfp->mode |= TURN_OFF_LOGGING; \ + (*sfiflprocs[nhfp->fnidx].fn_x.sf_##dtyp)(nhfp, d_##dtyp, myname); \ + nhfp->mode = save_mode; \ + } \ + if (!nhfp->eof) { \ + if ((((nhfp->mode & CONVERTING) != 0) \ + || ((nhfp->mode & UNCONVERTING) != 0)) && nhfp->nhfpconvert) { \ + sfo_##dtyp(nhfp->nhfpconvert, d_##dtyp, myname); \ + } \ + if (nhfp->fplog) \ + sf_log(nhfp, myname, sizeof *d_##dtyp, 1, \ + Sfvalue_##dtyp(d_##dtyp)); \ + } \ } #define SF_C(keyw, dtyp) \ -void sfo_##dtyp(NHFILE *nhfp, keyw dtyp *d_##dtyp, const char *myname) \ -{ \ - \ - if (nhfp->structlevel) { \ - (*sfoprocs[nhfp->fnidx].fn.sf_##dtyp)(nhfp, d_##dtyp, myname); \ - } \ - if (nhfp->fplog && !nhfp->eof) \ - sf_log(nhfp, myname, sizeof *d_##dtyp, 1); \ -} \ - \ -void sfi_##dtyp(NHFILE *nhfp, keyw dtyp *d_##dtyp, const char *myname) \ -{ \ - if (nhfp->structlevel) { \ - (*sfiprocs[nhfp->fnidx].fn.sf_##dtyp)(nhfp, d_##dtyp, myname); \ - } \ - if (nhfp->fplog && !nhfp->eof) \ - sf_log(nhfp, myname, sizeof *d_##dtyp, 1); \ - if (nhfp->eof) \ - return; \ - if (((nhfp->mode & CONVERTING) != 0) && nhfp->nhfpconvert) \ - sfo_##dtyp(nhfp->nhfpconvert, d_##dtyp, myname); \ +void sfo_##dtyp(NHFILE *nhfp, keyw dtyp *d_##dtyp, const char *myname) \ +{ \ + if (nhfp->fplog) \ + sf_log(nhfp, myname, sizeof *d_##dtyp, 1, \ + complex_dump((uchar *) d_##dtyp)); \ + if (nhfp->structlevel) { \ + (*sfoprocs[nhfp->fnidx].fn.sf_##dtyp)(nhfp, d_##dtyp, myname); \ + } else { \ + FILE *save_fplog = nhfp->fplog; \ + \ + nhfp->fplog = 0; \ + (*sfoflprocs[nhfp->fnidx].fn_x.sf_##dtyp)(nhfp, d_##dtyp, myname); \ + nhfp->fplog = save_fplog; \ + } \ +} \ + \ +void sfi_##dtyp(NHFILE *nhfp, keyw dtyp *d_##dtyp, const char *myname) \ +{ \ + if (nhfp->structlevel) { \ + (*sfiprocs[nhfp->fnidx].fn.sf_##dtyp)(nhfp, d_##dtyp, myname); \ + } else { \ + int save_mode = nhfp->mode; \ + \ + nhfp->mode &= ~(CONVERTING | UNCONVERTING); \ + nhfp->mode |= TURN_OFF_LOGGING; \ + (*sfiflprocs[nhfp->fnidx].fn_x.sf_##dtyp)(nhfp, d_##dtyp, myname); \ + nhfp->mode = save_mode; \ + } \ + if (!nhfp->eof) { \ + if ((((nhfp->mode & CONVERTING) != 0) \ + || ((nhfp->mode & UNCONVERTING) != 0)) \ + && nhfp->nhfpconvert) { \ + sfo_##dtyp(nhfp->nhfpconvert, d_##dtyp, myname); \ + } \ + if (nhfp->fplog) \ + sf_log(nhfp, myname, sizeof *d_##dtyp, 1, \ + complex_dump((uchar *) d_##dtyp)); \ + } \ } - + #define SF_X(xxx, dtyp) \ -void sfo_##dtyp(NHFILE *nhfp, xxx *d_##dtyp, const char *myname, int bfsz) \ -{ \ - if (nhfp->structlevel) { \ - (*sfoprocs[nhfp->fnidx].fn.sf_##dtyp)(nhfp, d_##dtyp, myname, bfsz); \ - } \ - if (nhfp->fplog && !nhfp->eof) \ - sf_log(nhfp, myname, sizeof *d_##dtyp, 1); \ -} \ - \ -void sfi_##dtyp(NHFILE *nhfp, xxx *d_##dtyp, const char *myname, int bfsz) \ -{ \ - if (nhfp->structlevel) { \ - (*sfiprocs[nhfp->fnidx].fn.sf_##dtyp)(nhfp, d_##dtyp, myname, bfsz); \ - } \ - if (nhfp->fplog && !nhfp->eof) \ - sf_log(nhfp, myname, sizeof *d_##dtyp, 1); \ - if (nhfp->eof) \ - return; \ - if (((nhfp->mode & CONVERTING) != 0) && nhfp->nhfpconvert) \ - sfo_##dtyp(nhfp->nhfpconvert, d_##dtyp, myname, bfsz); \ +void sfo_##dtyp(NHFILE *nhfp, xxx *d_##dtyp, const char *myname, int bfsz) \ +{ \ + if (nhfp->fplog) \ + sf_log(nhfp, myname, sizeof *d_##dtyp, 1, \ + Sfvalue_##dtyp(d_##dtyp)); \ + if (nhfp->structlevel) { \ + (*sfoprocs[nhfp->fnidx].fn.sf_##dtyp)(nhfp, d_##dtyp, myname, bfsz); \ + } else { \ + FILE *save_fplog = nhfp->fplog; \ + \ + nhfp->fplog = 0; \ + (*sfoflprocs[nhfp->fnidx].fn_x.sf_##dtyp)(nhfp, d_##dtyp, myname, bfsz); \ + nhfp->fplog = save_fplog; \ + } \ + if (nhfp->fplog && !nhfp->eof) \ + sf_log(nhfp, myname, sizeof *d_##dtyp, 1, Sfvalue_##dtyp(d_##dtyp)); \ +} \ + \ +void sfi_##dtyp(NHFILE *nhfp, xxx *d_##dtyp, const char *myname, int bfsz) \ +{ \ + if (nhfp->structlevel) { \ + (*sfiprocs[nhfp->fnidx].fn.sf_##dtyp)(nhfp, d_##dtyp, myname, bfsz); \ + } else { \ + int save_mode = nhfp->mode; \ + \ + nhfp->mode &= ~(CONVERTING | UNCONVERTING); \ + nhfp->mode |= TURN_OFF_LOGGING; \ + (*sfiflprocs[nhfp->fnidx].fn_x.sf_##dtyp)(nhfp, d_##dtyp, myname, bfsz); \ + nhfp->mode = save_mode; \ + } \ + if (!nhfp->eof) { \ + if ((((nhfp->mode & CONVERTING) != 0) \ + || ((nhfp->mode & UNCONVERTING) != 0)) \ + && nhfp->nhfpconvert) { \ + sfo_##dtyp(nhfp->nhfpconvert, d_##dtyp, myname, bfsz); \ + } \ + if (nhfp->fplog) \ + sf_log(nhfp, myname, sizeof *d_##dtyp, 1, \ + dtyp##_dump(d_##dtyp)); \ + } \ } SF_C(struct, arti_info) @@ -123,14 +283,13 @@ SF_C(struct, spell) SF_C(struct, stairway) SF_C(struct, s_level) SF_C(struct, trap) -SF_C(struct, version_info) SF_C(struct, you) SF_C(union, any) SF_A(aligntyp) SF_A(boolean) SF_A(coordxy) -SF_A(genericptr) +//SF_A(genericptr) SF_A(int) SF_A(int16) SF_A(int32) @@ -149,15 +308,22 @@ SF_A(unsigned) SF_A(ushort) SF_A(xint16) SF_A(xint8) +SF_X(uint8_t, bitfield) void sfo_char(NHFILE *nhfp, char *d_char, const char *myname, int cnt) { + if (nhfp->fplog) + sf_log(nhfp, myname, sizeof(char), cnt, Sfvalue_char(d_char, cnt)); if (nhfp->structlevel) { (*sfoprocs[nhfp->fnidx].fn.sf_char)(nhfp, d_char, myname, cnt); + } else { + FILE *save_fplog = nhfp->fplog; + + nhfp->fplog = 0; + (*sfoflprocs[nhfp->fnidx].fn_x.sf_char)(nhfp, d_char, myname, cnt); + nhfp->fplog = save_fplog; } - if (nhfp->fplog && !nhfp->eof) - sf_log(nhfp, myname, sizeof (char), cnt); } void @@ -165,31 +331,379 @@ sfi_char(NHFILE *nhfp, char *d_char, const char *myname, int cnt) { if (nhfp->structlevel) { (*sfiprocs[nhfp->fnidx].fn.sf_char)(nhfp, d_char, myname, cnt); + } else { + int save_mode = nhfp->mode; + + nhfp->mode &= ~(CONVERTING | UNCONVERTING); + nhfp->mode |= TURN_OFF_LOGGING; + (*sfiflprocs[nhfp->fnidx].fn_x.sf_char)(nhfp, d_char, myname, cnt); + nhfp->mode = save_mode; + } + if (!nhfp->eof) { + if ((((nhfp->mode & CONVERTING) != 0) + || ((nhfp->mode & UNCONVERTING) != 0)) + && nhfp->nhfpconvert) { + sfo_char(nhfp->nhfpconvert, d_char, myname, cnt); + } + if (nhfp->fplog) + sf_log(nhfp, myname, sizeof(char), cnt, + Sfvalue_char(d_char, cnt)); + } +} + +void +sfo_genericptr(NHFILE *nhfp, void **d_genericptr, const char *myname) +{ + if (nhfp->fplog) + sf_log(nhfp, myname, sizeof *d_genericptr, 1, + Sfvalue_genericptr(d_genericptr)); + if (nhfp->structlevel) { + (*sfoprocs[nhfp->fnidx].fn.sf_genericptr)(nhfp, d_genericptr, myname); + } else { + FILE *save_fplog = nhfp->fplog; + nhfp->fplog = 0; + (*sfoflprocs[nhfp->fnidx].fn_x.sf_genericptr)(nhfp, d_genericptr, + myname); + nhfp->fplog = save_fplog; + } +} +void +sfi_genericptr(NHFILE *nhfp, void **d_genericptr, const char *myname) +{ + if (nhfp->structlevel) { + (*sfiprocs[nhfp->fnidx].fn.sf_genericptr)(nhfp, d_genericptr, myname); + } else { + int save_mode = nhfp->mode; + nhfp->mode &= ~(CONVERTING | UNCONVERTING); + nhfp->mode |= TURN_OFF_LOGGING; + (*sfiflprocs[nhfp->fnidx].fn_x.sf_genericptr)(nhfp, d_genericptr, + myname); + nhfp->mode = save_mode; + } + if (!nhfp->eof) { + if ((((nhfp->mode & CONVERTING) != 0) || ((nhfp->mode & UNCONVERTING) != 0)) + && nhfp->nhfpconvert) { + sfo_genericptr(nhfp->nhfpconvert, d_genericptr, myname); + } + if (nhfp->fplog) + sf_log(nhfp, myname, sizeof *d_genericptr, 1, + Sfvalue_genericptr(d_genericptr)); + } +} + +void +sfo_version_info(NHFILE *nhfp, struct version_info *d_version_info, + const char *myname) +{ + if (nhfp->fplog) + sf_log(nhfp, myname, sizeof *d_version_info, 1, + complex_dump((uchar *) d_version_info)); + if (nhfp->structlevel) { + (*sfoprocs[nhfp->fnidx].fn.sf_version_info)(nhfp, d_version_info, + myname); + } else { + FILE *save_fplog = nhfp->fplog; + nhfp->fplog = 0; + (*sfoflprocs[nhfp->fnidx].fn_x.sf_version_info)(nhfp, d_version_info, + myname); + nhfp->fplog = save_fplog; + } +} +void +sfi_version_info(NHFILE *nhfp, struct version_info *d_version_info, + const char *myname) +{ + if (nhfp->structlevel) { + (*sfiprocs[nhfp->fnidx].fn.sf_version_info)(nhfp, d_version_info, + myname); + } else { + int save_mode = nhfp->mode; + nhfp->mode &= ~(CONVERTING | UNCONVERTING); + nhfp->mode |= TURN_OFF_LOGGING; + (*sfiflprocs[nhfp->fnidx].fn_x.sf_version_info)(nhfp, d_version_info, + myname); + nhfp->mode = save_mode; + } + if (!nhfp->eof) { + if ((((nhfp->mode & CONVERTING) != 0) || ((nhfp->mode & UNCONVERTING) != 0)) + && nhfp->nhfpconvert) { + d_version_info->feature_set |= SFCTOOL_BIT; + sfo_version_info(nhfp->nhfpconvert, d_version_info, myname); + } + if (nhfp->fplog) + sf_log(nhfp, myname, sizeof *d_version_info, 1, + complex_dump((uchar *) d_version_info)); } - if (nhfp->fplog && !nhfp->eof) - sf_log(nhfp, myname, sizeof (char), cnt); - if (nhfp->eof) - return; - if (((nhfp->mode & CONVERTING) != 0) && nhfp->nhfpconvert) - sfo_char(nhfp->nhfpconvert, d_char, myname, cnt); } -SF_X(uint8_t, bitfield) /* ---------------------------------------------------------------*/ void -sf_log(NHFILE *nhfp, const char *t1, size_t sz, int cnt) +sf_log(NHFILE *nhfp, const char *t1, size_t sz, int cnt, char *txtvalue) { FILE *fp = nhfp->fplog; + long *iocount; + boolean dolog = ((nhfp->mode & TURN_OFF_LOGGING) == 0); - if (fp) { - (void) fprintf(fp, "%ld %s sz=%zu cnt=%d\n", - nhfp->count++, - t1, sz, cnt); + if (fp && dolog) { + iocount = ((nhfp->mode & WRITING) == 0) ? &nhfp->rcount : &nhfp->wcount; + (void) fprintf(fp, "%08ld %s sz=%zu cnt=%d |%s|\n", + *iocount, + t1, sz, cnt, txtvalue); +// (*iocount)++; +// if (*iocount == 87) +// __debugbreak(); fflush(fp); } } +char *sfvalue_char(char *a, int n) +{ + int i; + static char buf[120]; + char *cp; + + cp = &buf[0]; + if (n < (int) (sizeof buf - 1)) + buf[n] = '\0'; + else + buf[(int) (sizeof buf - 1)] = '\0'; + for (i = 0; i < n; ++i, ++cp, ++a) + *cp = *a; + *cp = '\0'; + return buf; +} + +char *sfvalue_boolean(boolean *a) +{ + static char buf[20]; + + Snprintf(buf, sizeof buf, "%s", + (*a == 0) ? "false" : "true"); + return buf; +} + +char *sfvalue_schar(schar *a) +{ + static char buf[20]; + + Snprintf(buf, sizeof buf, "%d", (int) *a); + return buf; +} + +char * sfvalue_aligntyp(aligntyp *a) +{ + static char buf[20]; + + Snprintf(buf, sizeof buf, "%d", (int) *a); + return buf; +} + +char * +sfvalue_any(anything *a) +{ + static char buf[20]; +#ifdef UNIX + Snprintf(buf, sizeof buf, + "%ld", + a->a_int64); +#else + Snprintf(buf, sizeof buf, + "%lld", + a->a_int64); +#endif + return buf; +} + +char * +sfvalue_genericptr(genericptr a) +{ + static char buf[20]; + + Snprintf(buf, sizeof buf, "%s", + (a == 0) ? "0" : "glorkum"); + return buf; +} + +char * sfvalue_int16(int16 *a) +{ + static char buf[20]; + + Snprintf(buf, sizeof buf, "%d", *a); + return buf; +} + +char * sfvalue_int32(int32 *a) +{ + static char buf[20]; + + Snprintf(buf, sizeof buf, "%d", *a); + return buf; +} + +char * sfvalue_int64(int64 *a) +{ + static char buf[20]; +#ifdef UNIX + Snprintf(buf, sizeof buf, "%ld", *a); +#else + Snprintf(buf, sizeof buf, "%lld", *a); +#endif + return buf; +} + +char * sfvalue_uchar(uchar *a) +{ + static char buf[20]; + unsigned x; + + x = *a; + Snprintf(buf, sizeof buf, "%03u", x); + return buf; +} + +char * sfvalue_uint16(uint16 *a) +{ + static char buf[20]; + + Snprintf(buf, sizeof buf, "%u", (uint) *a); + return buf; +} + +char * sfvalue_uint32(uint32 *a) +{ + static char buf[20]; + + Snprintf(buf, sizeof buf, "%u", *a); + return buf; +} + +char * sfvalue_uint64(uint64 *a) +{ + static char buf[20]; + +#ifdef UNIX + Snprintf(buf, sizeof buf, "%lu", *a); +#else + Snprintf(buf, sizeof buf, "%llu", *a); +#endif + return buf; +} + +char * sfvalue_size_t(size_t *a UNUSED) +{ + static char buf[20]; + + Snprintf(buf, sizeof buf, "%s", (char *) ""); + return buf; +} + +char * sfvalue_time_t(time_t *a UNUSED) +{ + static char buf[20]; + + Snprintf(buf, sizeof buf, "%s", (char *) ""); + return buf; +} + +char * sfvalue_short(short *a) +{ + static char buf[20]; + + Snprintf(buf, sizeof buf, "%d", (int) *a); + return buf; +} + +char * sfvalue_ushort(ushort *a) +{ + static char buf[20]; + + Snprintf(buf, sizeof buf, "%u", (unsigned) *a); + return buf; +} + +char * sfvalue_int(int *a) +{ + static char buf[20]; + + Snprintf(buf, sizeof buf, "%d", *a); + return buf; +} + +char * sfvalue_unsigned(unsigned *a) +{ + static char buf[20]; + + Snprintf(buf, sizeof buf, "%u", *a); + return buf; +} + +char * sfvalue_long(long *a) +{ + static char buf[20]; + + Snprintf(buf, sizeof buf, "%ld", *a); + return buf; +} + +char * sfvalue_ulong(ulong *a) +{ + static char buf[20]; + + Snprintf(buf, sizeof buf, "%lu", *a); + return buf; +} + +char * sfvalue_xint8(xint8 *a) +{ + static char buf[20]; + + Snprintf(buf, sizeof buf, "%d", (int) *a); + return buf; +} + +char * sfvalue_xint16(xint16 *a) +{ + static char buf[20]; + + + Snprintf(buf, sizeof buf, "%d", (int) *a); + return buf; +} + +char * +sfvalue_bitfield(uint8 *a) +{ + static char buf[20]; + + Snprintf(buf, sizeof buf, "%u", (uint) *a); + return buf; +} + +char * +bitfield_dump(uint8 *a) +{ + static char buf[20]; + + Snprintf(buf, sizeof buf, "%u", (uint) *a); + return buf; +} +char * +complex_dump(uchar *a) +{ + int i; + uchar *uc = a; + static char buf[50]; + unsigned x[10]; + + for (i = 0; i < SIZE(x); ++i) { + x[i] = *uc++; + } + Snprintf(buf, sizeof buf, "%03x %03x %03x %03x %03x %03x %03x %03x %03x %03x", + x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7], x[8], x[9]); + buf[40] = '\0'; + return buf; +} /* *---------------------------------------------------------------------------- * initialize the function pointers. These are called from initoptions_init(). @@ -203,7 +717,461 @@ sf_init(void) sfiprocs[invalid] = zerosfiprocs; sfoprocs[historical] = historical_sfo_procs; sfiprocs[historical] = historical_sfi_procs; + sfoflprocs[exportascii] = zerosfoflprocs; + sfiflprocs[exportascii] = zerosfiflprocs; } +void +sf_setprocs(int idx, struct sf_structlevel_procs *sfi, struct sf_structlevel_procs *sfo) +{ + sfoprocs[idx] = *sfo; + sfiprocs[idx] = *sfi; +} +void +sf_setflprocs(int idx, struct sf_fieldlevel_procs *flsfi, + struct sf_fieldlevel_procs *flsfo) +{ + sfoflprocs[idx] = *flsfo; + sfiflprocs[idx] = *flsfi; +} +#ifndef SFCTOOL +void normalize_pointers_any(union any *d_any); +void normalize_pointers_align(struct align *d_align); +void normalize_pointers_arti_info(struct arti_info *d_arti_info); +void normalize_pointers_attribs(struct attribs *d_attribs); +void normalize_pointers_bill_x(struct bill_x *d_bill_x); +void normalize_pointers_branch(struct branch *d_branch); +void normalize_pointers_bubble(struct bubble *d_bubble); +void normalize_pointers_cemetery(struct cemetery *d_cemetery); +void normalize_pointers_context_info(struct context_info *d_context_info); +void normalize_pointers_achievement_tracking( + struct achievement_tracking *d_achievement_tracking); +void normalize_pointers_book_info(struct book_info *d_book_info); +void normalize_pointers_dig_info(struct dig_info *d_dig_info); +void normalize_pointers_engrave_info(struct engrave_info *d_engrave_info); +void normalize_pointers_obj_split(struct obj_split *d_obj_split); +void normalize_pointers_polearm_info(struct polearm_info *d_polearm_info); +void normalize_pointers_takeoff_info(struct takeoff_info *d_takeoff_info); +void normalize_pointers_tin_info(struct tin_info *d_tin_info); +void normalize_pointers_tribute_info(struct tribute_info *d_tribute_info); +void normalize_pointers_victual_info(struct victual_info *d_victual_info); +void normalize_pointers_warntype_info(struct warntype_info *d_warntype_info); +void normalize_pointers_d_flags(struct d_flags *d_d_flags); +void normalize_pointers_d_level(struct d_level *d_d_level); +void normalize_pointers_damage(struct damage *d_damage); +void normalize_pointers_dest_area(struct dest_area *d_dest_area); +void normalize_pointers_dgn_topology(struct dgn_topology *d_dgn_topology); +void normalize_pointers_dungeon(struct dungeon *d_dungeon); +void normalize_pointers_ebones(struct ebones *d_ebones); +void normalize_pointers_edog(struct edog *d_edog); +void normalize_pointers_egd(struct egd *d_egd); +void normalize_pointers_emin(struct emin *d_emin); +void normalize_pointers_engr(struct engr *d_engr); +void normalize_pointers_epri(struct epri *d_epri); +void normalize_pointers_eshk(struct eshk *d_eshk); +void normalize_pointers_fakecorridor(struct fakecorridor *d_fakecorridor); +void normalize_pointers_fe(struct fe *d_fe); +void normalize_pointers_flag(struct flag *d_flag); +void normalize_pointers_fruit(struct fruit *d_fruit); +void normalize_pointers_gamelog_line(struct gamelog_line *d_gamelog_line); +void normalize_pointers_kinfo(struct kinfo *d_kinfo); +void normalize_pointers_levelflags(struct levelflags *d_levelflags); +void normalize_pointers_linfo(struct linfo *d_linfo); +void normalize_pointers_ls_t(struct ls_t *d_ls_t); +void normalize_pointers_mapseen_feat(struct mapseen_feat *d_mapseen_feat); +void normalize_pointers_mapseen_flags(struct mapseen_flags *d_mapseen_flags); +void normalize_pointers_mapseen_rooms(struct mapseen_rooms *d_mapseen_rooms); +void normalize_pointers_mapseen(struct mapseen *d_mapseen); +void normalize_pointers_mextra(struct mextra *d_mextra); +void normalize_pointers_mkroom(struct mkroom *d_mkroom); +void normalize_pointers_monst(struct monst *d_monst); +void normalize_pointers_mvitals(struct mvitals *d_mvitals); +void normalize_pointers_nhcoord(struct nhcoord *d_nhcoord); +void normalize_pointers_nhrect(struct nhrect *d_nhrect); +void normalize_pointers_novel_tracking(struct novel_tracking *d_novel_tracking); +void normalize_pointers_obj(struct obj *d_obj); +void normalize_pointers_objclass(struct objclass *d_objclass); +void normalize_pointers_oextra(struct oextra *d_oextra); +void normalize_pointers_prop(struct prop *d_prop); +void normalize_pointers_q_score(struct q_score *d_q_score); +void normalize_pointers_rm(struct rm *d_rm); +void normalize_pointers_s_level(struct s_level *d_s_level); +void normalize_pointers_skills(struct skills *d_skills); +void normalize_pointers_spell(struct spell *d_spell); +void normalize_pointers_stairway(struct stairway *d_stairway); +void normalize_pointers_trap(struct trap *d_trap); +void normalize_pointers_u_conduct(struct u_conduct *d_u_conduct); +void normalize_pointers_u_event(struct u_event *d_u_event); +void normalize_pointers_u_have(struct u_have *d_u_have); +void normalize_pointers_u_realtime(struct u_realtime *d_u_realtime); +void normalize_pointers_u_roleplay(struct u_roleplay *d_u_roleplay); +void normalize_pointers_version_info(struct version_info *d_version_info); +void normalize_pointers_vlaunchinfo(union vlaunchinfo *d_vlaunchinfo); +void normalize_pointers_vptrs(union vptrs *d_vptrs); +void normalize_pointers_you(struct you *d_you); +void +normalize_pointers_any(union any *d_any UNUSED) +{ +} +void +normalize_pointers_align(struct align *d_align UNUSED) +{ +} + +void +normalize_pointers_arti_info(struct arti_info *d_arti_info UNUSED) +{ +} + +void +normalize_pointers_attribs(struct attribs *d_attribs UNUSED) +{ +} + +void +normalize_pointers_bill_x(struct bill_x *d_bill_x UNUSED) +{ +} + +void +normalize_pointers_branch(struct branch *d_branch UNUSED) +{ +} + +void +normalize_pointers_bubble(struct bubble *d_bubble UNUSED) +{ +} + +void +normalize_pointers_cemetery(struct cemetery *d_cemetery UNUSED) +{ +} + +void +normalize_pointers_context_info(struct context_info *d_context_info UNUSED) +{ +} + +void +normalize_pointers_achievement_tracking(struct achievement_tracking *d_achievement_tracking UNUSED) +{ +} + +void +normalize_pointers_book_info(struct book_info *d_book_info UNUSED) +{ +} + +void +normalize_pointers_dig_info(struct dig_info *d_dig_info UNUSED) +{ +} + +void +normalize_pointers_engrave_info(struct engrave_info *d_engrave_info UNUSED) +{ +} + +void +normalize_pointers_obj_split(struct obj_split *d_obj_split UNUSED) +{ +} + +void +normalize_pointers_polearm_info(struct polearm_info *d_polearm_info UNUSED) +{ +} + +void +normalize_pointers_takeoff_info(struct takeoff_info *d_takeoff_info UNUSED) +{ +} + +void +normalize_pointers_tin_info(struct tin_info *d_tin_info UNUSED) +{ +} + +void +normalize_pointers_tribute_info(struct tribute_info *d_tribute_info UNUSED) +{ +} + +void +normalize_pointers_victual_info(struct victual_info *d_victual_info UNUSED) +{ +} + +void +normalize_pointers_warntype_info(struct warntype_info *d_warntype_info UNUSED) +{ +} + +void +normalize_pointers_d_flags(struct d_flags *d_d_flags UNUSED) +{ +} + +void +normalize_pointers_d_level(struct d_level *d_d_level UNUSED) +{ +} + +void +normalize_pointers_damage(struct damage *d_damage UNUSED) +{ +} + +void +normalize_pointers_dest_area(struct dest_area *d_dest_area UNUSED) +{ +} + +void +normalize_pointers_dgn_topology(struct dgn_topology *d_dgn_topology UNUSED) +{ +} + +void +normalize_pointers_dungeon(struct dungeon *d_dungeon UNUSED) +{ +} + +void +normalize_pointers_ebones(struct ebones *d_ebones UNUSED) +{ +} + +void +normalize_pointers_edog(struct edog *d_edog UNUSED) +{ +} + +void +normalize_pointers_egd(struct egd *d_egd UNUSED) +{ +} + +void +normalize_pointers_emin(struct emin *d_emin UNUSED) +{ +} + +void +normalize_pointers_engr(struct engr *d_engr UNUSED) +{ +} + +void +normalize_pointers_epri(struct epri *d_epri UNUSED) +{ +} + +void +normalize_pointers_eshk(struct eshk *d_eshk UNUSED) +{ +} + +void +normalize_pointers_fakecorridor(struct fakecorridor *d_fakecorridor UNUSED) +{ +} + +void +normalize_pointers_fe(struct fe *d_fe UNUSED) +{ +} + +void +normalize_pointers_flag(struct flag *d_flag UNUSED) +{ +} + +void +normalize_pointers_fruit(struct fruit *d_fruit UNUSED) +{ +} + +void +normalize_pointers_gamelog_line(struct gamelog_line *d_gamelog_line UNUSED) +{ +} + +void +normalize_pointers_kinfo(struct kinfo *d_kinfo UNUSED) +{ +} + +void +normalize_pointers_levelflags(struct levelflags *d_levelflags UNUSED) +{ +} + +void +normalize_pointers_linfo(struct linfo *d_linfo UNUSED) +{ +} + +void +normalize_pointers_ls_t(struct ls_t *d_ls_t UNUSED) +{ +} + +void +normalize_pointers_mapseen_feat(struct mapseen_feat *d_mapseen_feat UNUSED) +{ +} + +void +normalize_pointers_mapseen_flags(struct mapseen_flags *d_mapseen_flags UNUSED) +{ +} + +void +normalize_pointers_mapseen_rooms(struct mapseen_rooms *d_mapseen_rooms UNUSED) +{ +} + +void +normalize_pointers_mapseen(struct mapseen *d_mapseen UNUSED) +{ +} + +void +normalize_pointers_mextra(struct mextra *d_mextra UNUSED) +{ +} + +void +normalize_pointers_mkroom(struct mkroom *d_mkroom UNUSED) +{ +} + +void +normalize_pointers_monst(struct monst *d_monst UNUSED) +{ +} + +void +normalize_pointers_mvitals(struct mvitals *d_mvitals UNUSED) +{ +} + +void +normalize_pointers_nhcoord(struct nhcoord *d_nhcoord UNUSED) +{ +} + +void +normalize_pointers_nhrect(struct nhrect *d_nhrect UNUSED) +{ +} + +void +normalize_pointers_novel_tracking(struct novel_tracking *d_novel_tracking UNUSED) +{ +} + +void +normalize_pointers_obj(struct obj *d_obj UNUSED) +{ +} + +void +normalize_pointers_objclass(struct objclass *d_objclass UNUSED) +{ +} + +void +normalize_pointers_oextra(struct oextra *d_oextra UNUSED) +{ +} + +void +normalize_pointers_prop(struct prop *d_prop UNUSED) +{ +} + +void +normalize_pointers_q_score(struct q_score *d_q_score UNUSED) +{ +} + +void +normalize_pointers_rm(struct rm *d_rm UNUSED) +{ +} + +void +normalize_pointers_s_level(struct s_level *d_s_level UNUSED) +{ +} + +void +normalize_pointers_skills(struct skills *d_skills UNUSED) +{ +} + +void +normalize_pointers_spell(struct spell *d_spell UNUSED) +{ +} + +void +normalize_pointers_stairway(struct stairway *d_stairway UNUSED) +{ +} + +void +normalize_pointers_trap(struct trap *d_trap UNUSED) +{ +} + +void +normalize_pointers_u_conduct(struct u_conduct *d_u_conduct UNUSED) +{ +} + +void +normalize_pointers_u_event(struct u_event *d_u_event UNUSED) +{ +} + +void +normalize_pointers_u_have(struct u_have *d_u_have UNUSED) +{ +} + +void +normalize_pointers_u_realtime(struct u_realtime *d_u_realtime UNUSED) +{ +} + +void +normalize_pointers_u_roleplay(struct u_roleplay *d_u_roleplay UNUSED) +{ +} + +void +normalize_pointers_version_info(struct version_info *d_version_info UNUSED) +{ +} + +void +normalize_pointers_vlaunchinfo(union vlaunchinfo *d_vlaunchinfo UNUSED) +{ +} + +void +normalize_pointers_vptrs(union vptrs *d_vptrs UNUSED) +{ +} + +void +normalize_pointers_you(struct you *d_you UNUSED) +{ +} +#endif /* SFCTOOL */ diff --git a/src/sfstruct.c b/src/sfstruct.c index c4eda5418..971676c52 100644 --- a/src/sfstruct.c +++ b/src/sfstruct.c @@ -8,6 +8,8 @@ /* #define SFLOGGING */ /* debugging */ +staticfn void sfstruct_read_error(void); + /* historical full struct savings */ #ifdef SAVEFILE_DEBUGGING @@ -29,6 +31,9 @@ staticfn void logging_finish(void); #define SFI_BODY(dt) \ { \ + if (nhfp->eof) { \ + sfstruct_read_error(); \ + } \ mread(nhfp->fd, (genericptr_t) d_##dt, sizeof *d_##dt); \ if (restoreinfo.mread_flags == -1) \ nhfp->eof = TRUE; \ @@ -46,20 +51,37 @@ void historical_sfi_##dtyp(NHFILE *nhfp, dtyp *d_##dtyp, const char *myname UNUSED) \ SFI_BODY(dtyp) +#define SFO_CBODY(dt) \ + { \ + normalize_pointers_##dt(d_##dt); \ + bwrite(nhfp->fd, (genericptr_t) d_##dt, sizeof *d_##dt); \ + } + +#define SFI_CBODY(dt) \ + { \ + if (nhfp->eof) { \ + sfstruct_read_error(); \ + } \ + mread(nhfp->fd, (genericptr_t) d_##dt, sizeof *d_##dt); \ + normalize_pointers_##dt(d_##dt); \ + if (restoreinfo.mread_flags == -1) \ + nhfp->eof = TRUE; \ + } #define SF_C(keyw, dtyp) \ void historical_sfo_##dtyp(NHFILE *, keyw dtyp *d_##dtyp, \ const char *); \ void historical_sfi_##dtyp(NHFILE *, keyw dtyp *d_##dtyp, \ const char *); \ +extern void normalize_pointers_##dtyp(keyw dtyp *d_##dtyp); \ \ void historical_sfo_##dtyp(NHFILE *nhfp, keyw dtyp *d_##dtyp, \ const char *myname UNUSED) \ - SFO_BODY(dtyp) \ + SFO_CBODY(dtyp) \ \ void historical_sfi_##dtyp(NHFILE *nhfp, keyw dtyp *d_##dtyp, \ const char *myname UNUSED) \ - SFI_BODY(dtyp) + SFI_CBODY(dtyp) #define SF_X(xxx, dtyp) \ void historical_sfo_##dtyp(NHFILE *, xxx *d_##dtyp, const char *, int); \ @@ -121,7 +143,7 @@ SF_C(union, any) SF_A(aligntyp) SF_A(boolean) SF_A(coordxy) -SF_A(genericptr_t) +//SF_A(genericptr_t) SF_A(int) SF_A(int16) SF_A(int32) @@ -159,6 +181,32 @@ historical_sfi_char(NHFILE *nhfp, char *d_char, if (restoreinfo.mread_flags == -1) nhfp->eof = TRUE; } +//extern void sfo_genericptr(NHFILE *, void **, const char *); +//extern void sfi_genericptr(NHFILE *, void **, const char *); +//extern void sfo_x_genericptr(NHFILE *, void **, const char *); +//extern void sfi_x_genericptr(NHFILE *, void **, const char *); + +void historical_sfo_genericptr_t(NHFILE *, genericptr_t *d_genericptr_t, + const char *); +void historical_sfi_genericptr_t(NHFILE *, genericptr_t *d_genericptr_t, + const char *); +void +historical_sfo_genericptr_t(NHFILE *nhfp, genericptr_t *d_genericptr_t, + const char *myname UNUSED) +{ + bwrite(nhfp->fd, (genericptr_t) d_genericptr_t, sizeof *d_genericptr_t); +} +void +historical_sfi_genericptr_t(NHFILE *nhfp, genericptr_t *d_genericptr_t, + const char *myname UNUSED) +{ + if (nhfp->eof) { + sfstruct_read_error(); + } + mread(nhfp->fd, (genericptr_t) d_genericptr_t, sizeof *d_genericptr_t); + if (restoreinfo.mread_flags == -1) + nhfp->eof = TRUE; +} SF_X(uint8_t, bitfield) @@ -592,6 +640,7 @@ mread(int fd, genericptr_t buf, unsigned len) restoreinfo.mread_flags = -1; return; } else { +#ifndef SFCTOOL pline("Read %d instead of %u bytes.", (int) rlen, len); display_nhwindow(WIN_MESSAGE, TRUE); /* flush before error() */ if (program_state.restoring) { @@ -600,10 +649,18 @@ mread(int fd, genericptr_t buf, unsigned len) error("Error restoring old game."); } panic("Error reading level file."); +#else + printf("Read %d instead of %u bytes.\n", (int) rlen, len); +#endif } } } +staticfn void +sfstruct_read_error(void) +{ + /* problem */; +} #ifdef SFLOGGING staticfn void @@ -628,4 +685,3 @@ logging_finish(void) icnt = 0L; } #endif - diff --git a/src/timeout.c b/src/timeout.c index dbfa90762..248dde41f 100644 --- a/src/timeout.c +++ b/src/timeout.c @@ -5,6 +5,7 @@ #include "hack.h" +#ifndef SFCTOOL staticfn void stoned_dialogue(void); staticfn void vomiting_dialogue(void); staticfn void sleep_dialogue(void); @@ -2682,6 +2683,7 @@ save_timers(NHFILE *nhfp, int range) } } } +#endif /* !SFCTOOL */ /* * Pull in the structures from disk, but don't recalculate the object and @@ -2705,10 +2707,13 @@ restore_timers(NHFILE *nhfp, int range, long adjust) Sfi_fe(nhfp, curr, "timer"); if (ghostly) curr->timeout += adjust; +#ifndef SFCTOOL insert_timer(curr); +#endif } } +#ifndef SFCTOOL DISABLE_WARNING_FORMAT_NONLITERAL /* to support '#stats' wizard-mode command */ @@ -2753,5 +2758,6 @@ relink_timers(boolean ghostly) } } } +#endif /* !SFCTOOL */ /*timeout.c*/ diff --git a/src/track.c b/src/track.c index 6f455a694..f5b915f22 100644 --- a/src/track.c +++ b/src/track.c @@ -18,6 +18,7 @@ initrack(void) (void) memset((genericptr_t) &utrack, 0, sizeof(utrack)); } +#ifndef SFCTOOL /* add to track */ void settrack(void) @@ -51,6 +52,7 @@ gettrack(coordxy x, coordxy y) } return (coord *) 0; } +#endif /* !SFCTOOL */ /* return TRUE if x,y has hero tracks on it */ boolean diff --git a/src/version.c b/src/version.c index dc1d0e654..04987929c 100644 --- a/src/version.c +++ b/src/version.c @@ -8,6 +8,7 @@ #include "dlb.h" #ifndef MINIMAL_FOR_RECOVER +#ifndef SFCTOOL #ifndef OPTIONS_AT_RUNTIME #define OPTIONS_AT_RUNTIME @@ -357,6 +358,14 @@ comp_times(long filetime) return ((unsigned long) filetime < (unsigned long) nomakedefs.build_time); } #endif +#endif /* !SFCTOOL */ + +#ifdef SFCTOOL +#ifdef wait_synch +#undef wait_synch +#endif +#define wait_synch() +#endif /* SFCTOOL */ boolean check_version( @@ -385,11 +394,13 @@ check_version( version_data->incarnation != nomakedefs.version_number #endif ) { +#ifndef SFCTOOL if (complain) { pline("Version mismatch for file \"%s\".", filename); if (WIN_MESSAGE != WIN_ERR) display_nhwindow(WIN_MESSAGE, TRUE); } +#endif return FALSE; } else if ( (version_data->feature_set & ~nomakedefs.ignored_features) @@ -397,42 +408,18 @@ check_version( || ((utdflags & UTD_SKIP_SANITY1) == 0 && version_data->entity_count != nomakedefs.version_sanity1) ) { +#ifndef SFCTOOL if (complain) { pline("Configuration incompatibility for file \"%s\".", filename); display_nhwindow(WIN_MESSAGE, TRUE); } +#endif return FALSE; } return TRUE; } -void -store_version(NHFILE *nhfp) -{ - struct version_info version_data = { - 0UL, 0UL, 0UL, - }; - - /* actual version number */ - version_data.incarnation = nomakedefs.version_number; - /* bitmask of config settings */ - version_data.feature_set = nomakedefs.version_features; - /* # of monsters and objects */ - version_data.entity_count = nomakedefs.version_sanity1; - - /* bwrite() before bufon() uses plain write() */ - if (nhfp->structlevel) - bufoff(nhfp->fd); - - store_critical_bytes(nhfp); - Sfo_version_info(nhfp, (struct version_info *) &version_data, - "version_info"); - - if (nhfp->structlevel) - bufon(nhfp->fd); - return; -} - +#ifndef SFCTOOL #ifdef AMIGA const char amiga_version_string[] = AMIGA_VERSION_STRING; #endif @@ -518,6 +505,34 @@ dump_version_info(void) release_runtime_info(); return; } +void +store_version(NHFILE *nhfp) +{ + struct version_info version_data = { + 0UL, + 0UL, + 0UL, + }; + /* actual version number */ + version_data.incarnation = nomakedefs.version_number; + /* bitmask of config settings */ + version_data.feature_set = nomakedefs.version_features; + /* # of monsters and objects */ + version_data.entity_count = nomakedefs.version_sanity1; + + /* bwrite() before bufon() uses plain write() */ + if (nhfp->structlevel) + bufoff(nhfp->fd); + + store_critical_bytes(nhfp); + Sfo_version_info(nhfp, (struct version_info *) &version_data, + "version_info"); + + if (nhfp->structlevel) + bufon(nhfp->fd); + return; +} +#endif /* !SFCTOOL */ #endif /* MINIMAL_FOR_RECOVER */ struct critical_sizes_with_names { @@ -662,9 +677,10 @@ store_critical_bytes(NHFILE *nhfp) /* int cmc = 0; */ if (nhfp->mode & WRITING) { - indicate = (nhfp->structlevel) ? 'h' - : (nhfp->fnidx == cnvascii) ? 'a' - : '?'; + indicate = (nhfp->structlevel) ? 'h' + : (nhfp->fnidx == exportascii) + ? 'a' + : '?'; Sfo_char(nhfp, &indicate, "indicate-format", 1); Sfo_char(nhfp, &csc_count, "count-critical_sizes", 1); cnt = (int) csc_count; @@ -693,7 +709,11 @@ store_critical_bytes(NHFILE *nhfp) int uptodate(NHFILE *nhfp, const char *name, unsigned long utdflags) { +#ifdef SFCTOOL + extern struct version_info vers_info; +#else struct version_info vers_info; +#endif char indicator; int sfstatus = 0, idx_1st_mismatch = 0; boolean quietly = (utdflags & UTD_QUIETLY) != 0; @@ -708,19 +728,18 @@ uptodate(NHFILE *nhfp, const char *name, unsigned long utdflags) critical_sizes[idx_1st_mismatch].ucsize, critical_sizes[idx_1st_mismatch].nm); } - return sfstatus; } Sfi_version_info(nhfp, &vers_info, "version_info"); if (!check_version(&vers_info, name, verbose, utdflags)) { if (verbose) { - if ((utdflags & UTD_WITHOUT_WAITSYNCH_PERFILE) == 0) + if ((utdflags & UTD_WITHOUT_WAITSYNCH_PERFILE) == 0) { wait_synch(); + } } return SF_OUTDATED; } - - return SF_UPTODATE; + return sfstatus; } /* @@ -819,12 +838,15 @@ validate(NHFILE *nhfp, const char *name, boolean without_waitsynch_perfile) unsigned long utdflags = 0L; int validsf = 0; +#ifdef SFCTOOL + utdflags |= UTD_QUIETLY; +#endif if (nhfp->structlevel) utdflags |= UTD_CHECKSIZES; if (without_waitsynch_perfile) utdflags |= UTD_WITHOUT_WAITSYNCH_PERFILE; if (nhfp->fieldlevel) - utdflags |= UTD_CHECKFIELDCOUNTS | UTD_SKIP_SANITY1 | UTD_QUIETLY; + utdflags |= UTD_CHECKFIELDCOUNTS | UTD_SKIP_SANITY1; validsf = uptodate(nhfp, name, utdflags); return validsf; } diff --git a/src/worm.c b/src/worm.c index af68084d1..e2bb61c3b 100644 --- a/src/worm.c +++ b/src/worm.c @@ -14,6 +14,7 @@ struct wseg { coordxy wx, wy; /* the segment's position */ }; +#ifndef SFCTOOL staticfn void toss_wsegs(struct wseg *, boolean) NO_NNARGS; staticfn void shrink_worm(int); @@ -21,6 +22,7 @@ staticfn void shrink_worm(int); staticfn void random_dir(int, int, int *, int *); #endif staticfn struct wseg *create_worm_tail(int); /* may return NULL */ +#endif /* !SFCTOOL */ /* Description of long worm implementation. * @@ -76,6 +78,7 @@ static struct wseg *wheads[MAX_NUM_WORMS] = DUMMY, *wtails[MAX_NUM_WORMS] = DUMMY; static long wgrowtime[MAX_NUM_WORMS] = DUMMY; +#ifndef SFCTOOL /* * get_wormno() * @@ -563,6 +566,7 @@ save_worm(NHFILE *nhfp) } } } +#endif /* !SFCTOOL */ /* * rest_worm() @@ -598,6 +602,7 @@ rest_worm(NHFILE *nhfp) } } +#ifndef SFCTOOL /* * place_wsegs() * @@ -991,5 +996,6 @@ redraw_worm(struct monst *worm) curr = curr->nseg; } } +#endif /* !SFCTOOL */ /*worm.c*/ diff --git a/sys/unix/Makefile.top b/sys/unix/Makefile.top index 9323f42c8..6e45eafa9 100644 --- a/sys/unix/Makefile.top +++ b/sys/unix/Makefile.top @@ -288,6 +288,11 @@ package: $(GAME) recover $(VARDAT) spec_levs recover: $(GAME) ( cd util ; $(MAKE) $(RECOVERBIN) ) +# sfctool can be configured by the sysadmin to convert the savefile +# content format as necessary. +sfctool: $(GAME) + ( cd util ; $(MAKE) sfctool ) + dofiles: target=`sed -n \ -e '/librarian/{' \ diff --git a/sys/unix/Makefile.utl b/sys/unix/Makefile.utl index 11a50aa1b..f402bf0c3 100644 --- a/sys/unix/Makefile.utl +++ b/sys/unix/Makefile.utl @@ -118,6 +118,12 @@ LIBS = OBJDIR = ../src +# This is the universal ctags utility which produces the tags in the +# format that util/readtags requires. +# https://github.com/universal-ctags/ctags.git +#CTAGSCMD = universal-ctags +CTAGSCMD = ctags + # if you change this to 1, feedback while building will omit -Dthis -Wthat # -Isomewhere so that each file being compiled is listed on one short line; # it requires support for '$<' in rules with more than one prerequisite @@ -288,6 +294,166 @@ recover.o: recover.c $(CONFIG_H) recover-version.o: ../src/version.c $(HACK_H) $(CC) $(CFLAGS) $(CSTD) -DMINIMAL_FOR_RECOVER -c ../src/version.c -o $@ +# +# dependencies for optional sfctool +# +# object files for sfctool utility +SFCTOOLOBJS = $(TARGETPFX)sfctool.o $(TARGETPFX)sf-alloc.o \ + $(TARGETPFX)sf-monst.o $(TARGETPFX)sf-objects.o \ + $(TARGETPFX)sfbase.o $(TARGETPFX)sfstruct.o \ + $(TARGETPFX)sfexpasc.o \ + $(TARGETPFX)sfdata.o $(TARGETPFX)sf-nhlua.o \ + $(TARGETPFX)panic.o $(TARGETPFX)sf-date.o \ + $(TARGETPFX)sf-decl.o $(TARGETPFX)sf-artifact.o \ + $(TARGETPFX)sf-dungeon.o $(TARGETPFX)sf-end.o \ + $(TARGETPFX)sf-engrave.o $(TARGETPFX)sf-cfgfiles.o \ + $(TARGETPFX)sf-files.o $(TARGETPFX)sf-light.o \ + $(TARGETPFX)sf-mdlib.o $(TARGETPFX)sf-mkmaze.o \ + $(TARGETPFX)sf-mkroom.o $(TARGETPFX)sf-o_init.o \ + $(TARGETPFX)sf-region.o $(TARGETPFX)sf-restore.o \ + $(TARGETPFX)sf-rumors.o $(TARGETPFX)sf-sys.o \ + $(TARGETPFX)sf-timeout.o $(TARGETPFX)sf-track.o \ + $(TARGETPFX)sf-version.o $(TARGETPFX)sf-worm.o \ + $(TARGETPFX)strutil.o +SFCTOOLBIN = sfctool + +SFFLAGS=-DSFCTOOL -DNOPANICTRACE -DNOCRASHREPORT -DNO_CHRONICLE +sfutil: $(SFCTOOLBIN) + @echo '$(SFCTOOLBIN) is up to date.' +$(SFCTOOLBIN): $(SFCTOOLOBJS) $(HACKLIB) + $(TARGET_CLINK) $(TARGET_LFLAGS) -o $@ $(SFCTOOLOBJS) $(HACKLIB) $(TARGET_LIBS) +$(TARGETPFX)sfctool.o: sfctool.c $(HACK_H) ../include/sfprocs.h + $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c sfctool.c +$(TARGETPFX)sfdata.o: sfdata.c $(HACK_H) ../include/sfprocs.h ../include/sfproto.h + $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c sfdata.c +$(TARGETPFX)sfexpasc.o: sfexpasc.c $(HACK_H) ../include/sfprocs.h ../include/sfproto.h + $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c sfexpasc.c +$(TARGETPFX)sf-alloc.o: ../src/alloc.c + $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/alloc.c +$(TARGETPFX)sf-date.o: ../src/date.c + $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/date.c +$(TARGETPFX)sf-decl.o: ../src/decl.c + $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/decl.c +$(TARGETPFX)sf-panic.o: panic.c $(CONFIG_H) + $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c panic.c +$(TARGETPFX)sf-monst.o: ../src/monst.c + $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/monst.c +$(TARGETPFX)sf-objects.o: ../src/objects.c + $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/objects.c +$(TARGETPFX)sf-sfbase.o: ../src/sfbase.c + $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/sfbase.c +$(TARGETPFX)sfstruct.o: ../src/sfstruct.c + $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/sfstruct.c +$(TARGETPFX)sf-artifact.o: ../src/artifact.c + $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/artifact.c +$(TARGETPFX)sf-dungeon.o: ../src/dungeon.c + $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/dungeon.c +$(TARGETPFX)sf-end.o: ../src/end.c + $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/end.c +$(TARGETPFX)sf-engrave.o: ../src/engrave.c + $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/engrave.c +$(TARGETPFX)sf-cfgfiles.o: ../src/cfgfiles.c + $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/cfgfiles.c +$(TARGETPFX)sf-files.o: ../src/files.c + $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/files.c +$(TARGETPFX)sf-light.o: ../src/light.c + $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/light.c +$(TARGETPFX)sf-mdlib.o: ../src/mdlib.c + $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/mdlib.c +$(TARGETPFX)sf-mkmaze.o: ../src/mkmaze.c + $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/mkmaze.c +$(TARGETPFX)sf-mkroom.o: ../src/mkroom.c + $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/mkroom.c +$(TARGETPFX)sf-o_init.o: ../src/o_init.c + $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/o_init.c +$(TARGETPFX)sf-region.o: ../src/region.c + $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/region.c +$(TARGETPFX)sf-restore.o: ../src/restore.c + $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/restore.c +$(TARGETPFX)sf-rumors.o: ../src/rumors.c + $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/rumors.c +$(TARGETPFX)sf-sys.o: ../src/sys.c + $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/sys.c +$(TARGETPFX)sf-timeout.o: ../src/timeout.c + $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/timeout.c +$(TARGETPFX)sf-track.o: ../src/track.c + $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/track.c +$(TARGETPFX)sf-version.o: ../src/version.c + $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/version.c +$(TARGETPFX)sf-worm.o: ../src/worm.c + $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/worm.c +$(TARGETPFX)sf-nhlua.o: ../src/nhlua.c + $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/nhlua.c +$(TARGETPFX)sfbase.o: ../src/sfbase.c + $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/sfbase.c +$(TARGETPFX)strutil.o: ../src/strutil.c + $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/strutil.c + +sftags: sftags.o + $(CLINK) $(LFLAGS) -o $@ sftags.o $(LIBS) +sftags.o: sftags.c $(HACK_H) + $(CC) $(CFLAGS) -c sftags.c +../include/sfproto.h: sf.tags sftags + ./sftags +sfdata.c: sf.tags sftags + ./sftags +# dependencies for sftags +# # +CTAGDEP = ../include/align.h ../include/artifact.h ../include/artilist.h \ + ../include/attrib.h ../include/context.h ../include/coord.h \ + ../include/decl.h ../include/dungeon.h ../include/engrave.h \ + ../include/flag.h ../include/func_tab.h ../include/global.h \ + ../include/hack.h ../include/mextra.h \ + ../include/mkroom.h ../include/monst.h ../include/defsym.h \ + ../include/obj.h ../include/objclass.h ../include/prop.h \ + ../include/quest.h ../include/rect.h ../include/region.h \ + ../include/rm.h ../include/skills.h ../include/spell.h \ + ../include/sys.h ../include/timeout.h ../include/trap.h \ + ../include/you.h ../include/onames.h ../include/wintype.h +# ../include/permonst.h +CTAGSOPT = --language-force=c --sort=no -D"Bitfield(x,n)=unsigned x : n" --excmd=pattern +# +INCL=../include/ +SRC=../src/ +sf.tags: $(CTAGDEP) + $(CTAGSCMD) $(CTAGSOPT) -f $@ $(INCL)align.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)artifact.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(SRC)artifact.c + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)artilist.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)attrib.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(SRC)bones.c + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)context.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)coord.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)decl.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(SRC)decl.c + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)dungeon.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)engrave.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(SRC)engrave.c + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)flag.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)func_tab.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)global.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)hack.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)mextra.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)mkroom.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)monst.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)defsym.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)obj.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)objclass.h +# $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)permonst.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)prop.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)quest.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)rect.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)region.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)rm.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)skills.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)spell.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)stairs.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)sys.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)timeout.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)trap.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)you.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)onames.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)wintype.h # dependencies for dlb # diff --git a/sys/unix/hints/include/cross-post.370 b/sys/unix/hints/include/cross-post.370 index 3e9a9cd39..9d7c5b548 100644 --- a/sys/unix/hints/include/cross-post.370 +++ b/sys/unix/hints/include/cross-post.370 @@ -49,6 +49,7 @@ dospkg: dodata dosfonts $(GAMEBIN) $(TARGETPFX)recover.exe ../dat/nhtiles.bmp mkdir -p $(TARGETPFX)pkg cp $(GAMEBIN) $(TARGETPFX)pkg/NETHACK.EXE cp $(TARGETPFX)recover.exe $(TARGETPFX)pkg/RECOVER.EXE + -cp $(SFCTOOLBIN) $(TARGETPFX)pkg/SFCTOOL.EXE cp ../dat/nhdat $(TARGETPFX)pkg/NHDAT cp ../dat/license $(TARGETPFX)pkg/LICENSE cp ../dat/nhtiles.bmp $(TARGETPFX)pkg/NHTILES.BMP diff --git a/sys/unix/hints/include/cross-pre2.370 b/sys/unix/hints/include/cross-pre2.370 index 9730be4da..df4ef6105 100644 --- a/sys/unix/hints/include/cross-pre2.370 +++ b/sys/unix/hints/include/cross-pre2.370 @@ -228,6 +228,7 @@ override LUALIBS= override TOPLUALIB= override GAMEBIN = $(TARGETPFX)nethack.exe override RECOVERBIN = $(TARGETPFX)recover.exe +override SFCTOOLBIN = $(TARGETPFX)sfctool.exe override PACKAGE = dospkg override PREGAME += mkdir -p $(TARGETDIR) ; make $(TARGETPFX)exceptn.o ; override CLEANMORE += rm -f -r $(TARGETDIR) ; rm -f -r $(FONTTARGETS) ; diff --git a/sys/windows/Makefile.nmake b/sys/windows/Makefile.nmake index c3daf54df..8f19c209c 100644 --- a/sys/windows/Makefile.nmake +++ b/sys/windows/Makefile.nmake @@ -866,15 +866,15 @@ COREOBJTTY = \ $(OTTY)quest.o $(OTTY)questpgr.o $(OTTY)read.o $(OTTY)rect.o \ $(OTTY)region.o $(OTTY)report.o $(OTTY)restore.o $(OTTY)rip.o \ $(OTTY)rnd.o $(OTTY)role.o $(OTTY)rumors.o $(OTTY)save.o \ - $(OTTY)selvar.o $(OTTY)sfstruct.o $(OTTY)shk.o $(OTTY)shknam.o \ - $(OTTY)sit.o $(OTTY)sounds.o $(OTTY)sp_lev.o $(OTTY)spell.o \ - $(OTTY)stairs.o $(OTTY)steal.o $(OTTY)steed.o $(OTTY)strutil.o \ - $(OTTY)symbols.o $(OTTY)sys.o $(OTTY)teleport.o $(OTTY)timeout.o \ - $(OTTY)topten.o $(OTTY)track.o $(OTTY)trap.o $(OTTY)u_init.o \ - $(OTTY)uhitm.o $(OTTY)utf8map.o $(OTTY)vault.o $(OTTY)vision.o \ - $(OTTY)weapon.o $(OTTY)were.o $(OTTY)wield.o $(OTTY)windows.o \ - $(OTTY)wizard.o $(OTTY)wizcmds.o $(OTTY)worm.o $(OTTY)worn.o \ - $(OTTY)write.o $(OTTY)zap.o $(OTTY)sfbase.o + $(OTTY)selvar.o $(OTTY)sfbase.o $(OTTY)sfstruct.o $(OTTY)shk.o \ + $(OTTY)shknam.o $(OTTY)sit.o $(OTTY)sounds.o $(OTTY)sp_lev.o \ + $(OTTY)spell.o $(OTTY)stairs.o $(OTTY)steal.o $(OTTY)steed.o \ + $(OTTY)strutil.o $(OTTY)symbols.o $(OTTY)sys.o $(OTTY)teleport.o \ + $(OTTY)timeout.o $(OTTY)topten.o $(OTTY)track.o $(OTTY)trap.o \ + $(OTTY)u_init.o $(OTTY)uhitm.o $(OTTY)utf8map.o $(OTTY)vault.o \ + $(OTTY)vision.o $(OTTY)weapon.o $(OTTY)were.o $(OTTY)wield.o \ + $(OTTY)windows.o $(OTTY)wizard.o $(OTTY)wizcmds.o $(OTTY)worm.o \ + $(OTTY)worn.o $(OTTY)write.o $(OTTY)zap.o OBJSTTY = $(MDLIBTTY) $(COREOBJTTY) $(REGEXTTY) $(RANDOMTTY) @@ -929,15 +929,15 @@ COREOBJGUI = \ $(OGUI)quest.o $(OGUI)questpgr.o $(OGUI)read.o $(OGUI)rect.o \ $(OGUI)region.o $(OGUI)report.o $(OGUI)restore.o $(OGUI)rip.o \ $(OGUI)rnd.o $(OGUI)role.o $(OGUI)rumors.o $(OGUI)save.o \ - $(OGUI)selvar.o $(OGUI)sfstruct.o $(OGUI)shk.o $(OGUI)shknam.o \ - $(OGUI)sit.o $(OGUI)sounds.o $(OGUI)sp_lev.o $(OGUI)spell.o \ - $(OGUI)stairs.o $(OGUI)steal.o $(OGUI)steed.o $(OGUI)strutil.o \ - $(OGUI)symbols.o $(OGUI)sys.o $(OGUI)teleport.o $(OGUI)timeout.o \ - $(OGUI)topten.o $(OGUI)track.o $(OGUI)trap.o $(OGUI)u_init.o \ - $(OGUI)uhitm.o $(OGUI)utf8map.o $(OGUI)vault.o $(OGUI)vision.o \ - $(OGUI)weapon.o $(OGUI)were.o $(OGUI)wield.o $(OGUI)windows.o \ - $(OGUI)wizard.o $(OGUI)wizcmds.o $(OGUI)worm.o $(OGUI)worn.o \ - $(OGUI)write.o $(OGUI)zap.o $(OGUI)sfbase.o + $(OGUI)selvar.o $(OGUI)sfbase.o $(OGUI)sfstruct.o $(OGUI)shk.o \ + $(OGUI)shknam.o $(OGUI)sit.o $(OGUI)sounds.o $(OGUI)sp_lev.o \ + $(OGUI)spell.o $(OGUI)stairs.o $(OGUI)steal.o $(OGUI)steed.o \ + $(OGUI)strutil.o $(OGUI)symbols.o $(OGUI)sys.o $(OGUI)teleport.o \ + $(OGUI)timeout.o $(OGUI)topten.o $(OGUI)track.o $(OGUI)trap.o \ + $(OGUI)u_init.o $(OGUI)uhitm.o $(OGUI)utf8map.o $(OGUI)vault.o \ + $(OGUI)vision.o $(OGUI)weapon.o $(OGUI)were.o $(OGUI)wield.o \ + $(OGUI)windows.o $(OGUI)wizard.o $(OGUI)wizcmds.o $(OGUI)worm.o \ + $(OGUI)worn.o $(OGUI)write.o $(OGUI)zap.o OBJSGUI = $(MDLIBGUI) $(COREOBJGUI) $(REGEXGUI) $(RANDOMGUI) @@ -1155,7 +1155,7 @@ R_CTAGSDIR=$(LIBDIR)ctags CTAGSDIR=$(R_CTAGSDIR)$(BACKSLASH) #U_CTAGSDIR=$(CTAGSDIR:\=/) !ELSE -R_CTAGSDIR=..\..\..\ctags +R_CTAGSDIR=..\lib\ctags CTAGSDIR=$(R_CTAGSDIR)$(BACKSLASH) #U_CTAGSDIR=$(CTAGSDIR:\=/) !ENDIF @@ -1724,6 +1724,7 @@ binary.tag: $(DAT)data $(DAT)rumors $(DAT)oracles $(DLB) \ if exist $(DAT)symbols copy $(DAT)symbols $(GAMEDIR)symbols if exist $(DOC)guidebook.txt copy $(DOC)guidebook.txt $(GAMEDIR)Guidebook.txt if exist $(DOC)nethack.txt copy $(DOC)nethack.txt $(GAMEDIR)NetHack.txt +# if exist $(UTIL)sfctool.pdb copy $(UTIL)sfctool.pdb $(GAMEDIR)sfctool.pdb @if exist $(GAMEDIR)NetHack.PDB echo NOTE: You may want to remove $(U_GAMEDIR)/NetHack.PDB to conserve space @if exist $(GAMEDIR)NetHackW.PDB echo NOTE: You may want to remove $(U_GAMEDIR)/NetHackW.PDB to conserve space -if exist $(MSWSYS)nethackrc.template copy $(MSWSYS)nethackrc.template $(R_GAMEDIR) @@ -2471,6 +2472,174 @@ $(DAT)epitaph: $(U)makedefs.exe $(DAT)epitaph.txt $(DAT)bogusmon: $(U)makedefs.exe $(DAT)bogusmon.txt $(U)makedefs -3 +# This is the universal ctags utility which produces the tags in the +# format that util/readtags requires. +# https://github.com/universal-ctags/ctags.git + +#=============================================================================== +# sfutil +#=============================================================================== +SFCTOOLOBJS = $(OUTL)sfctool.o $(OUTL)sf-alloc.o \ + $(OUTL)sf-monst.o $(OUTL)sf-objects.o \ + $(OUTL)sfbase.o $(OUTL)sf-struct.o \ + $(OUTL)sfexpasc.o \ + $(OUTL)sfdata.o $(OUTL)sf-nhlua.o \ + $(OUTL)panic.o $(OUTL)sf-date.o $(OUTL)sf-decl.o \ + $(OUTL)sf-artifact.o $(OUTL)sf-cfgfiles.o \ + $(OUTL)sf-dungeon.o $(OUTL)sf-end.o \ + $(OUTL)sf-engrave.o $(OUTL)sf-files.o $(OUTL)sf-light.o \ + $(OUTL)sf-mdlib.o $(OUTL)sf-mkmaze.o $(OUTL)sf-mkroom.o \ + $(OUTL)sf-o_init.o $(OUTL)sf-region.o \ + $(OUTL)sf-restore.o $(OUTL)sf-rumors.o \ + $(OUTL)sf-sys.o $(OUTL)sf-timeout.o $(OUTL)sf-track.o \ + $(OUTL)sf-version.o $(OUTL)sf-worm.o \ + $(OUTL)strutil.o $(OUTL)sf-windsys.o + +SFCTOOLBIN = $(BinDir)sfctool.exe +SFFLAGS = -DSFCTOOL -DNOPANICTRACE -DNOCRASHREPORT -DNO_CHRONICLE + +#CTAGSCMD = $(LIB)\ctags\ctags.exe + +# +# dependencies for optional sfctool +# +# $(Q)$(CC) $(CFLAGS) -Fo$@ monst.c + +#$(UTIL)sfutil.exe: $(SFCTOOLBIN) +#$(UTIL)sfctool.exe: $(SFCTOOLBIN) + +$(SFCTOOLBIN): $(OUTLHACKLIB) $(SFCTOOLOBJS) + $(link) $(lflags) -out:$@ /PDB:$(BinDir)$(@B).PDB $(SFCTOOLOBJS) \ + $(LIBS) ole32.lib Shell32.lib userenv.lib advapi32.lib $(OUTLHACKLIB) + @echo '$(SFCTOOLBIN) is up to date.' +$(OUTL)sfctool.o: $(UTIL)sfctool.c $(HACK_H) $(INCL)sfprocs.h + $(Q)$(CC) $(CFLAGS) $(SFFLAGS) -Fo$@ -c $(UTIL)sfctool.c +$(OUTL)sfdata.o: $(UTIL)sfdata.c $(HACK_H) $(INCL)sfprocs.h $(INCL)sfproto.h + $(Q)$(CC) $(CFLAGS) $(SFFLAGS) -Fo$@ -c $(UTIL)sfdata.c +$(OUTL)sfexpasc.o: $(UTIL)sfexpasc.c $(HACK_H) $(INCL)sfprocs.h $(INCL)sfproto.h + $(Q)$(CC) $(CFLAGS) $(SFFLAGS) -Fo$@ -c $(UTIL)sfexpasc.c +$(OUTL)sf-alloc.o: $(SRC)alloc.c + $(Q)$(CC) $(CFLAGS) $(SFFLAGS) -Fo$@ -c $(SRC)alloc.c +$(OUTL)sf-date.o: $(SRC)date.c + $(Q)$(CC) $(CFLAGS) $(SFFLAGS) -Fo$@ -c $(SRC)date.c +$(OUTL)sf-decl.o: $(SRC)decl.c + $(Q)$(CC) $(CFLAGS) $(SFFLAGS) -Fo$@ -c $(SRC)decl.c +$(OUTL)sf-monst.o: $(SRC)monst.c + $(Q)$(CC) $(CFLAGS) $(SFFLAGS) -Fo$@ -c $(SRC)monst.c +$(OUTL)sf-objects.o: $(SRC)objects.c + $(Q)$(CC) $(CFLAGS) $(SFFLAGS) -Fo$@ -c $(SRC)objects.c +$(OUTL)sfbase.o: $(SRC)sfbase.c + $(Q)$(CC) $(CFLAGS) $(SFFLAGS) -Fo$@ -c $(SRC)sfbase.c +$(OUTL)sf-struct.o: $(SRC)sfstruct.c + $(Q)$(CC) $(CFLAGS) $(SFFLAGS) -Fo$@ -c $(SRC)sfstruct.c +$(OUTL)sf-artifact.o: $(SRC)artifact.c + $(Q)$(CC) $(CFLAGS) $(SFFLAGS) -Fo$@ -c $(SRC)artifact.c +$(OUTL)sf-cfgfiles.o: $(SRC)cfgfiles.c + $(Q)$(CC) $(CFLAGS) $(SFFLAGS) -Fo$@ -c $(SRC)cfgfiles.c +$(OUTL)sf-dungeon.o: $(SRC)dungeon.c + $(Q)$(CC) $(CFLAGS) $(SFFLAGS) -Fo$@ -c $(SRC)dungeon.c +$(OUTL)sf-end.o: $(SRC)end.c + $(Q)$(CC) $(CFLAGS) $(SFFLAGS) -Fo$@ -c $(SRC)end.c +$(OUTL)sf-engrave.o: $(SRC)engrave.c + $(Q)$(CC) $(CFLAGS) $(SFFLAGS) -Fo$@ -c $(SRC)engrave.c +$(OUTL)sf-files.o: $(SRC)files.c + $(Q)$(CC) $(CFLAGS) $(SFFLAGS) -Fo$@ -c $(SRC)files.c +$(OUTL)sf-light.o: $(SRC)light.c + $(Q)$(CC) $(CFLAGS) $(SFFLAGS) -Fo$@ -c $(SRC)light.c +$(OUTL)sf-mdlib.o: $(SRC)mdlib.c + $(Q)$(CC) $(CFLAGS) $(SFFLAGS) -Fo$@ -c $(SRC)mdlib.c +$(OUTL)sf-mkmaze.o: $(SRC)mkmaze.c + $(Q)$(CC) $(CFLAGS) $(SFFLAGS) -Fo$@ -c $(SRC)mkmaze.c +$(OUTL)sf-mkroom.o: $(SRC)mkroom.c + $(Q)$(CC) $(CFLAGS) $(SFFLAGS) -Fo$@ -c $(SRC)mkroom.c +$(OUTL)sf-o_init.o: $(SRC)o_init.c + $(Q)$(CC) $(CFLAGS) $(SFFLAGS) -Fo$@ -c $(SRC)o_init.c +$(OUTL)sf-region.o: $(SRC)region.c + $(Q)$(CC) $(CFLAGS) $(SFFLAGS) -Fo$@ -c $(SRC)region.c +$(OUTL)sf-restore.o: $(SRC)restore.c + $(Q)$(CC) $(CFLAGS) $(SFFLAGS) -Fo$@ -c $(SRC)restore.c +$(OUTL)sf-rumors.o: $(SRC)\rumors.c + $(Q)$(CC) $(CFLAGS) $(SFFLAGS) -Fo$@ -c $(SRC)rumors.c +$(OUTL)sf-timeout.o: $(SRC)timeout.c + $(Q)$(CC) $(CFLAGS) $(SFFLAGS) -Fo$@ -c $(SRC)timeout.c +$(OUTL)sf-version.o: $(SRC)version.c + $(Q)$(CC) $(CFLAGS) $(SFFLAGS) -Fo$@ -c $(SRC)version.c +$(OUTL)sf-worm.o: $(SRC)worm.c + $(Q)$(CC) $(CFLAGS) $(SFFLAGS) -Fo$@ -c $(SRC)worm.c +$(OUTL)sf-nhlua.o: $(SRC)nhlua.c + $(Q)$(CC) $(CFLAGS) $(SFFLAGS) -Fo$@ -c $(SRC)nhlua.c +$(OUTL)sf-track.o: $(SRC)track.c + $(Q)$(CC) $(CFLAGS) $(SFFLAGS) -Fo$@ -c $(SRC)track.c +$(OUTL)sf-sys.o: $(SRC)sys.c + $(Q)$(CC) $(CFLAGS) $(SFFLAGS) -Fo$@ -c $(SRC)sys.c +$(OUTL)sf-windsys.o: $(MSWSYS)windsys.c + $(Q)$(CC) $(CFLAGS) $(SFFLAGS) -Fo$@ -c $(MSWSYS)windsys.c + +$(UTIL)sftags.exe: $(OUTL)sftags.o + $(link) $(LFLAGS) /OUT:$@ $(OUTL)sftags.o +$(OUTL)sftags.o: $(UTIL)sftags.c $(HACK_H) + $(Q)$(CC) $(CFLAGS) -Fo$@ -c $(UTIL)sftags.c +$(INCL)sfproto.h: $(UTIL)sftags.exe $(UTIL)sf.tags + $(UTIL)sftags.exe +$(UTIL)sfdata.c: $(UTIL)sftags.exe $(UTIL)sf.tags + $(UTIL)sftags.exe +# dependencies for sftags +# # +CTAGDEP = $(INCL)align.h $(INCL)artifact.h $(INCL)artilist.h \ + $(INCL)attrib.h $(INCL)context.h $(INCL)coord.h \ + $(INCL)decl.h $(INCL)dungeon.h $(INCL)engrave.h \ + $(INCL)flag.h $(INCL)func_tab.h $(INCL)global.h \ + $(INCL)hack.h $(INCL)mextra.h \ + $(INCL)mkroom.h $(INCL)monst.h \ + $(INCL)obj.h $(INCL)objclass.h $(INCL)prop.h \ + $(INCL)quest.h $(INCL)rect.h $(INCL)region.h \ + $(INCL)rm.h $(INCL)skills.h $(INCL)spell.h \ + $(INCL)stairs.h $(INCL)sys.h $(INCL)timeout.h \ + $(INCL)trap.h $(INCL)you.h $(INCL)onames.h \ + $(INCL)wintype.h +# $(INCL)permonst.h +CTAGSOPT = --language-force=c --sort=no -D"Bitfield(x,n)=unsigned x : n" --excmd=pattern +# +$(UTIL)sf.tags: $(CTAGDEP) + $(CTAGSCMD) $(CTAGSOPT) -f $@ $(INCL)align.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)artifact.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(SRC)artifact.c + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)artilist.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)attrib.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(SRC)bones.c + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)context.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)coord.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)decl.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(SRC)decl.c + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)dungeon.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)engrave.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(SRC)engrave.c + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)flag.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)func_tab.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)global.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)hack.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)mextra.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)mkroom.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)monst.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)defsym.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)obj.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)objclass.h +# $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)permonst.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)prop.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)quest.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)rect.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)region.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)rm.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)skills.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)spell.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)stairs.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)sys.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)timeout.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)trap.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)you.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)onames.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)wintype.h + #=============================================================================== # Integrated sound files #=============================================================================== @@ -2541,13 +2710,15 @@ $(SndWavDir)sa2_xplevelup.wav: $(SndWavDir)sa2_xplevelup.uu $(U)uudecode.exe #=============================================================================== PKGFILES = nethackrc.template Guidebook.txt license NetHack.exe NetHack.txt \ - NetHackW.exe opthelp nhdat370 record symbols sysconf.template + NetHackW.exe opthelp nhdat370 record symbols sysconf.template \ + sfctool.exe FILESTOZIP = $(BinDir)nethackrc.template $(BinDir)Guidebook.txt $(BinDir)license \ $(BinDir)NetHack.exe $(BinDir)NetHack.txt $(BinDir)NetHackW.exe \ $(BinDir)opthelp $(BinDir)nhdat370 $(BinDir)record \ - $(BinDir)symbols $(BinDir)sysconf.template -DBGSYMS = NetHack.PDB NetHackW.PDB -PDBTOZIP = $(BinDir)NetHack.PDB $(BinDir)NetHackW.PDB + $(BinDir)symbols $(BinDir)sysconf.template $(BinDir)sfctool.exe + +DBGSYMS = NetHack.PDB NetHackW.PDB sfctool.PDB +PDBTOZIP = $(BinDir)NetHack.PDB $(BinDir)NetHackW.PDB $(BinDir)sfctool.PDB MAINZIP = $(PkgDir)nethack-$(NHV)-win-$(TARGET_CPU).zip DBGSYMZIP = $(PkgDir)nethack-$(NHV)-win-$(TARGET_CPU)-debugsymbols.zip @@ -2568,7 +2739,7 @@ binary: envchk.tag libdir.tag ottydir$(TARGET_CPU).tag \ $(INCL)nhlua.h $(OUTL)utility.tag \ $(DAT)data $(DAT)rumors $(DAT)oracles $(DAT)engrave \ $(DAT)epitaph $(DAT)bogusmon $(GAMEDIR)NetHack.exe \ - $(GAMEDIR)NetHackW.exe $(GAMEDIRDLLS) binary.tag + $(GAMEDIR)NetHackW.exe $(GAMEDIR)sfctool.exe $(GAMEDIRDLLS) binary.tag @echo NetHack is up to date. #=============================================================================== diff --git a/sys/windows/vs/NetHack/NetHack.vcxproj b/sys/windows/vs/NetHack/NetHack.vcxproj index bdc5d771f..002d5c9be 100644 --- a/sys/windows/vs/NetHack/NetHack.vcxproj +++ b/sys/windows/vs/NetHack/NetHack.vcxproj @@ -317,4 +317,4 @@ - \ No newline at end of file + diff --git a/sys/windows/vs/NetHackW/NetHackW.vcxproj b/sys/windows/vs/NetHackW/NetHackW.vcxproj index 5ba44b3dc..8db832c65 100644 --- a/sys/windows/vs/NetHackW/NetHackW.vcxproj +++ b/sys/windows/vs/NetHackW/NetHackW.vcxproj @@ -379,4 +379,4 @@ - \ No newline at end of file + diff --git a/sys/windows/vs/dirs.props b/sys/windows/vs/dirs.props index dc3f7ca7b..8f1f17062 100644 --- a/sys/windows/vs/dirs.props +++ b/sys/windows/vs/dirs.props @@ -29,6 +29,8 @@ $(RootDir)win\curses\ $(RootDir)submodules\ $(LibDir)lua-$(LUA_VERSION)\src\ + $(RootDir)\sys\windows\vs\sftags\ + $(RootDir)\sys\windows\vs\sfctool\ $(LibDir)pdcursesmod\ diff --git a/sys/windows/vs/fetchctags/fetchctags.nmake b/sys/windows/vs/fetchctags/fetchctags.nmake new file mode 100644 index 000000000..70023ce1d --- /dev/null +++ b/sys/windows/vs/fetchctags/fetchctags.nmake @@ -0,0 +1,49 @@ +# NetHack 3.7 fetchctags.nmake +#============================================================================== +# +# The version of the game this Makefile was designed for +NETHACK_VERSION="3.7.0" + +# A brief version for use in macros +NHV=$(NETHACK_VERSION:.=) +NHV=$(NHV:"=) + +# The location of the ctags that we want +CTAGS_VERSION=6.1.0 +CURLCTAGSSRC=https://github.com/universal-ctags/ctags-win32/releases/download/v$(CTAGS_VERSION)/ctags-v$(CTAGS_VERSION)-x64.zip +CURLCTAGSDST=ctags-v$(CTAGS_VERSION)-x64.zip + +# +# relative directories from root of NetHack tree. +# + +ROOTDIR=..\..\..\.. # root of NetHack tree relative to project file +LIBDIR=$(ROOTDIR)\lib +CTAGSDIR=$(LIBDIR)\ctags + +default: fetchall + +fetchall: fetch-ctags + +fetch-ctags: $(CTAGSDIR) + cd $(LIBDIR) + curl --insecure -L -R -O $(CURLCTAGSSRC) +# cd ctags + tar zxf $(CURLCTAGSDST) -C ctags + cd ..\sys\windows\vs\fetchctags + @echo ctags.exe has been fetched into $(LIBDIR)\ctags + +$(CTAGSDIR): $(LIBDIR) + @if not exist $(CTAGSDIR)\*.* echo creating directory $(CTAGSDIR:\=/) + @if not exist $(CTAGSDIR)\*.* mkdir $(CTAGSDIR) + +$(LIBDIR): + @if not exist $(LIBDIR)\*.* echo creating directory $(LIBDIR:\=/) + @if not exist $(LIBDIR)\*.* mkdir $(LIBDIR) + +rebuild: + @if exist $(CTAGSDIR)\ctags.exe echo nothing to do for $(CTAGSDIR)\ctags.exe + +clean: + if exist $(CURLCTAGSDST) del $(CURLCTAGSDST) + diff --git a/sys/windows/vs/fetchctags/fetchctags.vcxproj b/sys/windows/vs/fetchctags/fetchctags.vcxproj new file mode 100644 index 000000000..58df9ec83 --- /dev/null +++ b/sys/windows/vs/fetchctags/fetchctags.vcxproj @@ -0,0 +1,71 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + + + 17.0 + {AAE63AD3-8185-4E19-B6A3-13F4CB891AAD} + Win32Proj + 10.0 + + + + Makefile + true + + + Makefile + false + + + Makefile + true + + + Makefile + false + + + + + + + + + + + + echo ..\lib\ctags is already present + pushd $(vsDir)fetchctags %26%26 nmake -F fetchctags.nmake clean %26%26 popd + echo rebuilding $(vsDir)fetchctags + _DEBUG;$(NMakePreprocessorDefinitions) + + + pushd $(vsDir)fetchctags %26%26 nmake -F fetchctags.nmake %26%26 popd + pushd $(vsDir)fetchctags %26%26 nmake -F fetchctags.nmake clean %26%26 popd + pushd $(vsDir)fetchprereq %26%26 nmake -F fetchctags.nmake rebuild %26%26 popd + _DEBUG;$(NMakePreprocessorDefinitions) + + + + + + diff --git a/sys/windows/vs/sfctool.sln b/sys/windows/vs/sfctool.sln new file mode 100644 index 000000000..c997bd45f --- /dev/null +++ b/sys/windows/vs/sfctool.sln @@ -0,0 +1,58 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.13.35913.81 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sfctool", "sfctool\sfctool.vcxproj", "{3BFA3C14-6DA2-4750-B1C6-028B9BCE825E}" + ProjectSection(ProjectDependencies) = postProject + {628C594A-7565-4366-9FCA-41DB67C6B615} = {628C594A-7565-4366-9FCA-41DB67C6B615} + {AAE63AD3-8185-4E19-B6A3-13F4CB891AAD} = {AAE63AD3-8185-4E19-B6A3-13F4CB891AAD} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sftags", "sftags\sftags.vcxproj", "{628C594A-7565-4366-9FCA-41DB67C6B615}" + ProjectSection(ProjectDependencies) = postProject + {AAE63AD3-8185-4E19-B6A3-13F4CB891AAD} = {AAE63AD3-8185-4E19-B6A3-13F4CB891AAD} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fetchctags", "fetchctags\fetchctags.vcxproj", "{AAE63AD3-8185-4E19-B6A3-13F4CB891AAD}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {3BFA3C14-6DA2-4750-B1C6-028B9BCE825E}.Debug|x64.ActiveCfg = Debug|x64 + {3BFA3C14-6DA2-4750-B1C6-028B9BCE825E}.Debug|x64.Build.0 = Debug|x64 + {3BFA3C14-6DA2-4750-B1C6-028B9BCE825E}.Debug|x86.ActiveCfg = Debug|Win32 + {3BFA3C14-6DA2-4750-B1C6-028B9BCE825E}.Debug|x86.Build.0 = Debug|Win32 + {3BFA3C14-6DA2-4750-B1C6-028B9BCE825E}.Release|x64.ActiveCfg = Release|x64 + {3BFA3C14-6DA2-4750-B1C6-028B9BCE825E}.Release|x64.Build.0 = Release|x64 + {3BFA3C14-6DA2-4750-B1C6-028B9BCE825E}.Release|x86.ActiveCfg = Release|Win32 + {3BFA3C14-6DA2-4750-B1C6-028B9BCE825E}.Release|x86.Build.0 = Release|Win32 + {628C594A-7565-4366-9FCA-41DB67C6B615}.Debug|x64.ActiveCfg = Debug|x64 + {628C594A-7565-4366-9FCA-41DB67C6B615}.Debug|x64.Build.0 = Debug|x64 + {628C594A-7565-4366-9FCA-41DB67C6B615}.Debug|x86.ActiveCfg = Debug|Win32 + {628C594A-7565-4366-9FCA-41DB67C6B615}.Debug|x86.Build.0 = Debug|Win32 + {628C594A-7565-4366-9FCA-41DB67C6B615}.Release|x64.ActiveCfg = Release|x64 + {628C594A-7565-4366-9FCA-41DB67C6B615}.Release|x64.Build.0 = Release|x64 + {628C594A-7565-4366-9FCA-41DB67C6B615}.Release|x86.ActiveCfg = Release|Win32 + {628C594A-7565-4366-9FCA-41DB67C6B615}.Release|x86.Build.0 = Release|Win32 + {AAE63AD3-8185-4E19-B6A3-13F4CB891AAD}.Debug|x64.ActiveCfg = Debug|x64 + {AAE63AD3-8185-4E19-B6A3-13F4CB891AAD}.Debug|x64.Build.0 = Debug|x64 + {AAE63AD3-8185-4E19-B6A3-13F4CB891AAD}.Debug|x86.ActiveCfg = Debug|Win32 + {AAE63AD3-8185-4E19-B6A3-13F4CB891AAD}.Debug|x86.Build.0 = Debug|Win32 + {AAE63AD3-8185-4E19-B6A3-13F4CB891AAD}.Release|x64.ActiveCfg = Release|x64 + {AAE63AD3-8185-4E19-B6A3-13F4CB891AAD}.Release|x64.Build.0 = Release|x64 + {AAE63AD3-8185-4E19-B6A3-13F4CB891AAD}.Release|x86.ActiveCfg = Release|Win32 + {AAE63AD3-8185-4E19-B6A3-13F4CB891AAD}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {1000CD98-D3C0-493F-9EA7-E2D81FA96432} + EndGlobalSection +EndGlobal diff --git a/sys/windows/vs/sfctool/sfctool.vcxproj b/sys/windows/vs/sfctool/sfctool.vcxproj new file mode 100644 index 000000000..f86aa0b8b --- /dev/null +++ b/sys/windows/vs/sfctool/sfctool.vcxproj @@ -0,0 +1,193 @@ + + + + + + + + + + + $(BinDir) + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 17.0 + Win32Proj + {3bfa3c14-6da2-4750-b1c6-028b9bce825e} + sfctool + 10.0 + + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + + + + + + + + + + + + + + + + + + + + $(WinWin32Dir);$(IncDir);$(SysWindDir);$(SysShareDir);$(WinShareDir);$(LuaDir);$(UtilDir);%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;WIN32CON;NO_TILE_C;DLB;SAFEPROCS;SND_LIB_WINDSOUND;USER_SOUNDS;_LIB;HAS_STDINT_H;SFCTOOL;NOPANICTRACE;NOCRASHREPORT;NO_CHRONICLE;%(PreprocessorDefinitions) + Level3 + true + true + + + Console + true + $(ToolsDir);%(AdditionalLibraryDirectories) + hacklib.lib;%(AdditionalDependencies) + + + + + $(WinWin32Dir);$(IncDir);$(SysWindDir);$(SysShareDir);$(WinShareDir);$(LuaDir);$(UtilDir);%(AdditionalIncludeDirectories) + WIN32;_NDEBUG;_CONSOLE;WIN32CON;NO_TILE_C;DLB;SAFEPROCS;SND_LIB_WINDSOUND;USER_SOUNDS;_LIB;HAS_STDINT_H;SFCTOOL;NOPANICTRACE;NOCRASHREPORT;NO_CHRONICLE;%(PreprocessorDefinitions) + Level3 + true + true + true + true + + + Console + true + true + true + $(ToolsDir);%(AdditionalLibraryDirectories) + hacklib.lib;%(AdditionalDependencies) + + + + + $(WinWin32Dir);$(IncDir);$(SysWindDir);$(SysShareDir);$(WinShareDir);$(LuaDir);$(UtilDir);%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;WIN32CON;NO_TILE_C;DLB;SAFEPROCS;SND_LIB_WINDSOUND;USER_SOUNDS;_LIB;HAS_STDINT_H;SFCTOOL;NOPANICTRACE;NOCRASHREPORT;NO_CHRONICLE;%(PreprocessorDefinitions) + Level3 + true + true + + + Console + true + $(ToolsDir);%(AdditionalLibraryDirectories) + hacklib.lib;userenv.lib;advapi32.lib;%(AdditionalDependencies) + + + + + $(WinWin32Dir);$(IncDir);$(SysWindDir);$(SysShareDir);$(WinShareDir);$(LuaDir);$(UtilDir);%(AdditionalIncludeDirectories) + WIN32;_NDEBUG;_CONSOLE;WIN32CON;NO_TILE_C;DLB;SAFEPROCS;SND_LIB_WINDSOUND;USER_SOUNDS;_LIB;HAS_STDINT_H;SFCTOOL;NOPANICTRACE;NOCRASHREPORT;NO_CHRONICLE;%(PreprocessorDefinitions) + Level3 + true + true + true + true + + + Console + true + true + true + $(ToolsDir);%(AdditionalLibraryDirectories) + hacklib.lib;userenv.lib;advapi32.lib;$(CoreLibraryDependencies);%(AdditionalDependencies) + + + + + + diff --git a/sys/windows/vs/sftags/aftersftags.proj b/sys/windows/vs/sftags/aftersftags.proj new file mode 100644 index 000000000..a79669104 --- /dev/null +++ b/sys/windows/vs/sftags/aftersftags.proj @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sys/windows/vs/sftags/sftags.vcxproj b/sys/windows/vs/sftags/sftags.vcxproj new file mode 100644 index 000000000..4131dcd5c --- /dev/null +++ b/sys/windows/vs/sftags/sftags.vcxproj @@ -0,0 +1,156 @@ + + + + + + + + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + + + + 17.0 + Win32Proj + {628c594a-7565-4366-9fca-41db67c6b615} + sftags + 10.0 + + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + + + + + + + + + + + + + + + + + + + + $(WinWin32Dir);$(IncDir);$(SysWindDir);$(SysShareDir);$(WinShareDir);$(LuaDir);$(UtilDir);%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;WIN32CON;NO_TILE_C;DLB;SAFEPROCS;SND_LIB_WINDSOUND;USER_SOUNDS;_LIB;HAS_STDINT_H;SFCTOOL;NOPANICTRACE;NOCRASHREPORT;NO_CHRONICLE;%(PreprocessorDefinitions) + Level3 + true + true + + + Console + true + + + + + $(WinWin32Dir);$(IncDir);$(SysWindDir);$(SysShareDir);$(WinShareDir);$(LuaDir);$(UtilDir);%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;WIN32CON;NO_TILE_C;DLB;SAFEPROCS;SND_LIB_WINDSOUND;USER_SOUNDS;_LIB;HAS_STDINT_H;SFCTOOL;NOPANICTRACE;NOCRASHREPORT;NO_CHRONICLE;%(PreprocessorDefinitions) + Level3 + true + true + true + true + + + Console + true + true + true + + + + + $(WinWin32Dir);$(IncDir);$(SysWindDir);$(SysShareDir);$(WinShareDir);$(LuaDir);$(UtilDir);%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;WIN32CON;NO_TILE_C;DLB;SAFEPROCS;SND_LIB_WINDSOUND;USER_SOUNDS;_LIB;HAS_STDINT_H;SFCTOOL;NOPANICTRACE;NOCRASHREPORT;NO_CHRONICLE;%(PreprocessorDefinitions) + Level3 + true + true + + + Console + true + + + + + $(WinWin32Dir);$(IncDir);$(SysWindDir);$(SysShareDir);$(WinShareDir);$(LuaDir);$(UtilDir);%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;WIN32CON;NO_TILE_C;DLB;SAFEPROCS;SND_LIB_WINDSOUND;USER_SOUNDS;_LIB;HAS_STDINT_H;SFCTOOL;NOPANICTRACE;NOCRASHREPORT;NO_CHRONICLE;%(PreprocessorDefinitions) + Level3 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + + + + + + + + + + + diff --git a/sys/windows/windsys.c b/sys/windows/windsys.c index d7178cffa..6be9b6407 100644 --- a/sys/windows/windsys.c +++ b/sys/windows/windsys.c @@ -44,6 +44,10 @@ static char portable_device_path[MAX_PATH]; +static boolean path_buffer_set = FALSE; +static char path_buffer[MAX_PATH]; + +#ifndef SFCTOOL /* runtime cursor display control switch */ boolean win32_cursorblink; @@ -53,6 +57,9 @@ WIN32_FIND_DATA ffd; extern int GUILaunched; extern boolean getreturn_enabled; int redirect_stdout; +static char *get_executable_path(void); + + #ifdef WIN32CON typedef HWND(WINAPI *GETCONSOLEWINDOW)(void); @@ -780,7 +787,9 @@ nt_assert_failed(const char *expression, const char *filepath, int line) impossible("nhassert(%s) failed in file '%s' at line %d", expression, filename, line); } +#endif /* SFCTOOL */ +/* used by util/sfctool.c as well as files.c */ boolean get_user_home_folder(char *homebuf, size_t sz) { @@ -794,13 +803,12 @@ get_user_home_folder(char *homebuf, size_t sz) result = GetUserProfileDirectoryA(hToken, szHomeDirBuf, &BufSize); // Close handle opened via OpenProcessToken CloseHandle(hToken); + if (result != 0) { + Snprintf(homebuf, sz, "%s", szHomeDirBuf); + } return (result != 0); } -static char *get_executable_path(void); - -static boolean path_buffer_set = FALSE; -static char path_buffer[MAX_PATH]; char * get_executable_path(void) @@ -1019,6 +1027,7 @@ set_default_prefix_locations(const char *programPath UNUSED) strcpy(executable_path, get_executable_path()); append_slash(executable_path); +#ifndef SFCTOOL if (test_portable_config(executable_path, portable_device_path, sizeof portable_device_path)) { gf.fqn_prefix[SYSCONFPREFIX] = executable_path; @@ -1032,6 +1041,7 @@ set_default_prefix_locations(const char *programPath UNUSED) gf.fqn_prefix[TROUBLEPREFIX] = portable_device_path; gf.fqn_prefix[DATAPREFIX] = executable_path; } else { +#endif /* SFCTOOL */ if (!build_known_folder_path(&FOLDERID_Profile, profile_path, sizeof(profile_path), FALSE)) strcpy(profile_path, executable_path); @@ -1061,7 +1071,9 @@ set_default_prefix_locations(const char *programPath UNUSED) gf.fqn_prefix[LOCKPREFIX] = versioned_global_data_path; gf.fqn_prefix[TROUBLEPREFIX] = versioned_profile_path; gf.fqn_prefix[DATAPREFIX] = executable_path; +#ifndef SFCTOOL } +#endif /* SFCTOOL */ } /* @@ -1138,6 +1150,7 @@ get_portable_device(void) return (const char *) portable_device_path; } +#ifndef SFCTOOL /* Windows helpers for CRASHREPORT etc */ #ifdef CRASHREPORT struct CRctxt { @@ -1429,6 +1442,7 @@ win32_cr_shellexecute(const char *url){ return rv; } #endif /* CRASHREPORT */ +#endif /* SFCTOOL */ #endif /* WIN32 */ diff --git a/util/.gitignore b/util/.gitignore index 11fa8a1f0..a16d5c640 100644 --- a/util/.gitignore +++ b/util/.gitignore @@ -31,4 +31,7 @@ heaputil.c tilemappings.lst clang_rt.asan*.dll *.sln - +sf.tags +sfdata.c +sfctool +sftags diff --git a/util/sfctool.c b/util/sfctool.c new file mode 100644 index 000000000..cc3f9e464 --- /dev/null +++ b/util/sfctool.c @@ -0,0 +1,1323 @@ +/* NetHack 3.7 sfctool.c */ +/* Copyright (c) Michael Allison, 2025. */ +/* NetHack may be freely redistributed. See license for details. */ + +/* + * Utility for reading a binary save file in the native historical + * format of the accompanying NetHack executable, and writing it out + * in an export format, possibly destined for a different platform, + * architecture, or data model. + * + * The resulting export file will only be useful for transport + * between different platforms and architectures that share the exact + * same version of NetHack with the same features. That is, the same + * fields must be present in the NetHack data structures, in the same + * sequence. The fields do not have to be the same size or use the same + * data model. + * + */ + +#if defined(WIN32) && !defined(__GNUC__) +#include "win32api.h" +#endif + +#include "hack.h" + +#include +#include +#include +#ifdef UNIX +#include +#define O_BINARY 0 +#endif +#include "integer.h" +#include "sfprocs.h" + +#ifdef WIN32 +#include +#endif + +#ifndef RDTMODE +#define RDTMODE "r" +#endif +#ifndef WRTMODE +#if (defined(MSDOS) || defined(WIN32)) +#define WRTMODE "w+b" +#else +#define WRTMODE "w+" +#endif +#endif +#ifndef RDBMODE +#if (defined(MICRO) || defined(WIN32)) +#define RDBMODE "rb" +#else +#define RDBMODE "r" +#endif +#endif +#ifndef WRBMODE +#if (defined(MICRO) || defined(WIN32)) +#define WRBMODE "w+b" +#else +#define WRBMODE "w+" +#endif +#endif + +#ifdef PANICTRACE +#error PANICTRACE is defined +#endif +#ifdef CRASHREPORT +#error CRASHREPORT is defined +#endif + +/* functions in this file */ +static int process_savefile(const char *, enum saveformats, char *, enum saveformats, boolean); +static void my_sf_init(void); +static NHFILE *open_srcfile(const char *, enum saveformats); +static NHFILE *create_dstfile(char *, enum saveformats); +static const char *style_to_text(enum saveformats style); +static void read_sysconf(void); +static int length_without_val(const char *user_string, int len); + +void zero_nhfile(NHFILE *); +NHFILE *new_nhfile(void); +void free_nhfile(NHFILE *); +void my_close_nhfile(NHFILE *); +int delete_savefile(void); +int nhclose(int fd); +int util_strncmpi(const char *s1, const char *s2, size_t sz); + +#ifdef UNIX +#define nethack_exit exit +void nh_terminate(int) NORETURN; /* bwrite() calls this */ +static void chdirx(const char *); +#else +extern void nethack_exit(int) NORETURN; +#ifdef WIN32 +boolean get_user_home_folder(char *homebuf, size_t sz); +int GUILaunched; +#endif /* WIN32 */ +#endif +#define Fprintf (void) fprintf + +/* Global data */ + +struct link_compat1 { + volatile int done_hup; +}; + +/* worm segment structure */ +struct wseg { + struct wseg *nseg; + coordxy wx, wy; /* the segment's position */ +}; + +enum { UNCONVERTED = 0, CONVERTED }; +char *unconverted_filename = 0; +char *converted_filename = 0; + +/* from sfstruct.c */ +extern struct restore_info restoreinfo; +/* from sfbase.c */ +extern struct sf_structlevel_procs sfoprocs[NUM_SAVEFORMATS], sfiprocs[NUM_SAVEFORMATS]; +extern struct sf_structlevel_procs zerosfoprocs, zerosfiprocs; +extern struct sf_fieldlevel_procs sfoflprocs[NUM_SAVEFORMATS], sfiflprocs[NUM_SAVEFORMATS]; +extern struct sf_structlevel_procs zerosfodlprocs, zerosfidlprocs; +extern boolean close_check(int); +extern void bclose(int); +extern void config_error_init(boolean, const char *, boolean); /* files.c */ +extern boolean get_user_home_folder(char *, size_t); +extern void make_version(void); + +char plname[PL_NSIZ_PLUS]; +struct version_info vers_info; +int renidx = -1; + +const char *const rensuffixes[] = { + "IL32LLP64", /* (3) Windows x64 savefile on x86 */ + "I32LP64", /* (4) Unix 64 savefile on x86 */ + "ILP32LL64", /* (5) x86 savefile on Unix 64 */ + "ILP32LL64", /* (6) x86 savefile on Windows x64 */ + "I32LP64", /* (7) Unix 64 savefile on Windows x64 */ + "IL32LLP64", /* (8) Windows x64 savefile on Unix 64 */ + "OTHER", /* (9) */ +}; + +#ifdef WIN32 +extern boolean get_user_home_folder(char *homebuf, size_t sz); /* files.c */ +extern void set_default_prefix_locations(const char *programPath); +#endif + +enum saveformats convertstyle = exportascii; + +boolean chosen_unconvert = FALSE, explicit_option = FALSE; +const char *thisdatamodel; +static char srclogfilenm[BUFSZ], dstlogfilenm[BUFSZ]; + +/********* + * main * + *********/ + +int +main(int argc UNUSED, char *argv[]) +{ + int arg; + char folderbuf[5000]; + const char *suffix = (convertstyle == exportascii) ? ".exportascii" : ""; + boolean add_folder = TRUE; +#ifdef WIN32 + size_t sz; +#endif + + if (argc < 3) + exit(EXIT_FAILURE); + + runtime_info_init(); /* mdlib.c */ +#ifdef UNIX + folderbuf[0] = '.'; + folderbuf[1] = '/'; + folderbuf[2] = '\0'; +#ifdef CHDIR + chdirx(HACKDIR); +#endif +#endif +#ifdef UNIX + Strcpy(folderbuf, "save/"); +#endif +#ifdef WIN32 + if (!get_user_home_folder(folderbuf, sizeof folderbuf)) + exit(EXIT_FAILURE); + sz = strlen(folderbuf); + (void) snprintf(eos(folderbuf), sizeof folderbuf - sz, + "\\AppData\\Local\\NetHack\\3.7\\"); + //initoptions_init(); // This allows OPTIONS in syscf on Windows. + set_default_prefix_locations(argv[0]); +#endif + + read_sysconf(); + for (arg = 1; arg < argc; ++arg) { + if (arg == 1 && !strcmp(argv[arg], "-u")) { + explicit_option = TRUE; + chosen_unconvert = TRUE; + continue; + } + if (arg == 1 && !strcmp(argv[arg], "-c")) { + if (explicit_option && chosen_unconvert) { + fprintf(stderr, "\nsfctool error - conflicting options.\n"); + exit(EXIT_FAILURE); /* both -u and -c not allowed */ + } + explicit_option = TRUE; + chosen_unconvert = FALSE; + continue; + } + if (arg == 2) { + size_t ln = strlen(argv[arg]); + boolean addseparator = FALSE; + + if (!contains_directory(argv[arg])) { + char finalchar = *(eos(folderbuf) - 1); + + if (!(finalchar == '\\' || finalchar == '/')) { + ln += 1; + addseparator = TRUE; + } + } else { + add_folder = FALSE; + } + if (explicit_option) { + if (add_folder) + ln += strlen(folderbuf); + unconverted_filename = (char *) alloc((int) ln + 1); + Snprintf(unconverted_filename, ln + 1, "%s%s%s", + add_folder ? folderbuf : "", + addseparator ? "/" : "", argv[arg]); + ln += strlen(suffix); + converted_filename = (char *) alloc((int) ln + 1); + Snprintf(converted_filename, ln + 1, "%s%s", + unconverted_filename, suffix); + } else { + fprintf(stderr, "\nsfctool error - missing -c or -u before " + "save filename.\n"); + exit(EXIT_FAILURE); /* need both filenames */ + } + } + } + if (!converted_filename || !unconverted_filename) { + fprintf(stderr, "\nsfctool error - missing %sconverted file name.\n", + !converted_filename ? "" : "un"); + exit(EXIT_FAILURE); /* need both filenames */ + } + thisdatamodel = datamodel(); + my_sf_init(); + if (chosen_unconvert) { + process_savefile(converted_filename, convertstyle, + unconverted_filename, historical, chosen_unconvert); + } else { + process_savefile(unconverted_filename, historical, converted_filename, + convertstyle, chosen_unconvert); + } +} + +/* ======================================================================== */ +/* Process the src savefile and create the dst file */ +/* Return 1 for success, 0 for failure */ +/* ======================================================================== */ + +static int +process_savefile(const char *srcfnam, enum saveformats srcstyle, + char *dstfnam, enum saveformats cvtstyle, boolean unconvert) +{ + NHFILE *nhfp[2]; /* one for UNCONVERTED, one for CONVERTED */ + int srcidx = unconvert ? CONVERTED : UNCONVERTED, + dstidx = unconvert ? UNCONVERTED : CONVERTED, + sfstatus = 0, i; + char indicator, file_csc_count; + extern struct version_info vers_info; + extern uchar cscbuf[]; + /* nh_uncompress(fq_save); */ + + if ((nhfp[srcidx] = open_srcfile(srcfnam, srcstyle)) == 0) + return 0; + sfstatus = validate(nhfp[srcidx], srcfnam, FALSE); + if (sfstatus > SF_UPTODATE + && ((sfstatus <= SF_CRITICAL_BYTE_COUNT_MISMATCH) || !unconvert)) { + fprintf(stderr, + "This savefile is not compatible with %sutility.\n%s\n", + !unconvert ? "the datamodel of this particular " : "this ", + srcfnam); + return 0; + } + if (sfstatus >= SF_DM_IL32LLP64_ON_ILP32LL64) { + renidx = sfstatus - SF_DM_IL32LLP64_ON_ILP32LL64; + } else if (sfstatus == SF_UPTODATE) { + renidx = -2; + } + if ((nhfp[dstidx] = create_dstfile(dstfnam, cvtstyle)) == 0) { + close_nhfile(nhfp[dstidx]); + nh_compress(unconverted_filename); + return 0; + } + if (unconvert) { + nhfp[srcidx]->nhfpconvert = nhfp[UNCONVERTED]; + } else { + /* converting */ + nhfp[srcidx]->nhfpconvert = nhfp[CONVERTED]; + } + if (unconvert) + fprintf(stdout, "\n\nunconverting %s to %s %s\n", + style_to_text(srcstyle), style_to_text(cvtstyle), + thisdatamodel); + else + fprintf(stdout, "\n\nconverting %s %s to %s\n", + style_to_text(srcstyle), thisdatamodel, style_to_text(cvtstyle)); + + rewind_nhfile(nhfp[srcidx]); +#ifdef SAVEFILE_DEBUGGING + nhfp[srcidx]->fplog = fopen(srclogfilenm, "w"); +#endif + if (unconvert) { + nhfp[srcidx]->mode |= UNCONVERTING; + } else { + /* converting */ + nhfp[srcidx]->mode |= CONVERTING; + } + nhfp[srcidx]->rcount = 0; + Sfi_char(nhfp[srcidx], &indicator, "indicate-format", 1); + Sfi_char(nhfp[srcidx], &file_csc_count, "count-critical_sizes", 1); + for (i = 0; i < (int) file_csc_count; ++i) { + Sfi_uchar(nhfp[srcidx], &cscbuf[i], "critical_sizes"); + } + rewind_nhfile(nhfp[dstidx]); +#ifdef SAVEFILE_DEBUGGING + nhfp[dstidx]->fplog = fopen(dstlogfilenm, "w"); +#endif + /* + * store_critical_bytes() will take care of inserting the + * indicate-format, count-critical_sizes, and critical_sizes for + * this platform/data-model destination, instead of copying those + * values from the savefile that was converted. + */ + store_critical_bytes(nhfp[dstidx]); + + Sfi_version_info(nhfp[srcidx], &vers_info, "version_info"); + svm.moves = 1L; /* match u_init.c */ + + /******************** + * player name info * + ********************/ + + get_plname_from_file(nhfp[srcidx], plname, TRUE); + + { + /******************** + * lev 0 * + ********************/ + xint8 lev = 0; + + getlev(nhfp[srcidx], lev, FALSE); + } + + + { + /******************** + * gamestate * + ********************/ +/* unsigned int stuckid, steedid; */ + (void) restgamestate(nhfp[srcidx]); + } + + { + /******************** + * Do all levels * + ********************/ + xint8 ltmp; + + restoreinfo.mread_flags = 1; /* return despite error */ + while (1) { + ltmp = -1; + Sfi_xint8(nhfp[srcidx], <mp, "gamestate-level_number"); + if (nhfp[srcidx]->eof || ltmp == -1) + break; + + getlev(nhfp[srcidx], 0, ltmp); + } + restoreinfo.mread_flags = 0; + } + nhfp[srcidx]->mode &= ~(CONVERTING | UNCONVERTING); + nhfp[srcidx]->nhfpconvert = (NHFILE *) 0; + close_nhfile(nhfp[srcidx]); + close_nhfile(nhfp[dstidx]); + nh_compress(dstfnam); + nh_compress(srcfnam); + return 1; +} + +/* open srcfile for reading */ +static NHFILE * +open_srcfile(const char *fnam, enum saveformats mystyle) +{ + int fd; + const char *fq_name; + NHFILE *nhfp = (NHFILE *) 0; + + nhfp = new_nhfile(); + if (nhfp) { + nhfp->mode = READING; + nhfp->structlevel = (mystyle == historical); + nhfp->fieldlevel = (mystyle > historical); + nhfp->ftype = NHF_SAVEFILE; + nhfp->fnidx = mystyle; + nhfp->fd = -1; + nhfp->addinfo = + (nhfp->fieldlevel && (mystyle = exportascii)) + ? TRUE + : FALSE; + (void) snprintf(srclogfilenm, sizeof srclogfilenm, "srcfile.%s.log", + (mystyle == historical) ? "historical" : "exportascii"); + } + + fq_name = fqname(fnam, SAVEPREFIX, 0); + nh_uncompress(fq_name); + if (nhfp && nhfp->structlevel) { + fd = open(fq_name, O_RDONLY | O_BINARY, 0); + if (fd < 0) { + zero_nhfile(nhfp); + free_nhfile(nhfp); + fprintf(stderr, + "\nsfctool error - unable to open historical-style " + "source file %s.\n", + fnam); + nhfp = (NHFILE *) 0; + nh_compress(fq_name); + } else { + nhfp->fd = fd; +#if defined(MSDOS) + setmode(nhfp->fd, O_BINARY); +#endif + } + } + if (nhfp && nhfp->fieldlevel) { + /* char savenamebuf[BUFSZ]; */ + + nhfp->fpdef = fopen(fnam, RDBMODE); + if (!nhfp->fpdef) { + zero_nhfile(nhfp); + free_nhfile(nhfp); + fprintf(stderr, + "\nsfctool error - unable to open fieldlevel-style " + "source file %s.\n", + fnam); + nhfp = (NHFILE *) 0; + nh_compress(fq_name); + } + } + return nhfp; +} + +/* create dst file, overwriting one if it already exists */ +static NHFILE * +create_dstfile(char *fnam, enum saveformats mystyle) +{ + int fd, ret; + unsigned ln = 0; + FILE *cf; + NHFILE *nhfp = (NHFILE *) 0; + const char *fq_name; + char dstfnam[2048]; + char *dsttmp; + boolean dst_file_exists = FALSE, ren_file_exists = FALSE; + + nhUse(ret); + Snprintf(dstfnam, sizeof dstfnam, "%s", fnam); + if ((cf = fopen(dstfnam, RDBMODE)) != (FILE *) 0) { + dst_file_exists = TRUE; + (void) fclose(cf); + } + + if (dst_file_exists) { + if (chosen_unconvert) { + ln = strlen(fnam); + if (renidx >= 0) { + ln += strlen(rensuffixes[renidx]) + 1; /* +1 for '.' */ + } else if (renidx == -2) { + ln += strlen(thisdatamodel) + 1; /* +1 for '.' */ + } else { + ln += strlen(thisdatamodel) + 1 + + 4; /* +1 for '.'; +4 for "not_" */ + } + dsttmp = (char *) alloc(ln + 1); + Strcpy(dsttmp, fnam); + Strcat(dsttmp, "."); + if (renidx >= 0) { + Strcat(dsttmp, rensuffixes[renidx]); + } else if (renidx == -2) { + Strcat(dsttmp, thisdatamodel); + } else { + Strcat(dsttmp, "not_"); + Strcat(dsttmp, thisdatamodel); + } + if ((cf = fopen(dsttmp, RDBMODE)) != (FILE *) 0) { + ren_file_exists = TRUE; + (void) fclose(cf); + } + if (ren_file_exists) { + (void) unlink(dsttmp); + } + ret = rename(fnam, dsttmp); + free((genericptr_t) dsttmp), dsttmp = 0; + } else { + if ((cf = fopen(dstfnam, RDBMODE)) != (FILE *) 0) { + ren_file_exists = TRUE; + (void) fclose(cf); + } + if (ren_file_exists) { + (void) unlink(dstfnam); + } + } + } + + nhfp = new_nhfile(); + if (nhfp) { + nhfp->mode = WRITING; + nhfp->ftype = NHF_SAVEFILE; + nhfp->structlevel = (mystyle == historical); + nhfp->fieldlevel = (mystyle > historical); + nhfp->fnidx = mystyle; + nhfp->fd = -1; + (void) snprintf(dstlogfilenm, sizeof dstlogfilenm, "dstfile.%s.log", + (mystyle == historical) ? "historical" : "exportascii"); + } + + if (nhfp && nhfp->structlevel) { + fq_name = fqname(dstfnam, SAVEPREFIX, 0); +#if defined(MICRO) || defined(WIN32) + fd = open(dstfnam, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC, FCMASK); +#else + fd = creat(dstfnam, FCMASK); +#endif + if (fd < 0) { + zero_nhfile(nhfp); + free_nhfile(nhfp); + fprintf( + stderr, + "Unable to create historical-style destination file %s.\n", + fnam); + nhfp = (NHFILE *) 0; + } else { + nhfp->fd = fd; +#if defined(MSDOS) + setmode(nhfp->fd, O_BINARY); +#endif + } + } else if (nhfp && nhfp->fieldlevel) { + fq_name = fqname(dstfnam, SAVEPREFIX, 0); + nhfp->fpdef = fopen(fq_name, WRBMODE); + if (!nhfp->fpdef) { + zero_nhfile(nhfp); + free_nhfile(nhfp); + fprintf( + stderr, + "Unable to create fieldlevel-style destination file %s.\n", + fnam); + nhfp = (NHFILE *) 0; + } + } + return nhfp; +} + +static const char * +style_to_text(enum saveformats style) +{ + const char *txt; + + switch (style) { + case historical: + txt = "historical"; + break; + case exportascii: + txt = "exportascii"; + break; + case invalid: + default: + txt = "invalid"; + break; + } + return txt; +} + +void +my_sf_init(void) +{ + decl_globals_init(); + sfoprocs[invalid] = zerosfoprocs; + sfiprocs[invalid] = zerosfiprocs; + sfoprocs[historical] = historical_sfo_procs; + sfiprocs[historical] = historical_sfi_procs; + sfoflprocs[exportascii] = exportascii_sfo_procs; + sfiflprocs[exportascii] = exportascii_sfi_procs; +} + +/* delete savefile */ +int +delete_savefile(void) +{ + return 0; /* for restore_saved_game() (ex-xxxmain.c) test */ +} + +static void +read_sysconf(void) +{ +#ifdef SYSCF +/* someday there may be other SYSCF alternatives besides text file */ +#ifdef SYSCF_FILE + /* If SYSCF_FILE is specified, it _must_ exist... */ + assure_syscf_file(); + config_error_init(TRUE, SYSCF_FILE, FALSE); + if (!read_config_file(SYSCF_FILE, set_in_sysconf)) { + if (config_error_done() && !iflags.initoptions_noterminate) + nh_terminate(EXIT_FAILURE); + } + config_error_done(); + /* + * TODO [maybe]: parse the sysopt entries which are space-separated + * lists of usernames into arrays with one name per element. + */ +#endif +#endif /* SYSCF */ +} + + +DISABLE_WARNING_FORMAT_NONLITERAL + +/* provided for linkage only */ +void +error(const char *s, ...) +{ + va_list the_args; + + va_start(the_args, s); + printf(s, the_args); + va_end(the_args); + exit(EXIT_FAILURE); +} + +void +pline(const char *s, ...) +{ + va_list the_args; + + va_start(the_args, s); + printf(s, the_args); + va_end(the_args); +} + +void +impossible(const char *s, ...) +{ + va_list the_args; + + va_start(the_args, s); + printf(s, the_args); + va_end(the_args); + exit(EXIT_FAILURE); +} + +RESTORE_WARNING_FORMAT_NONLITERAL + +/* TIME_type: type of the argument to time(); we actually use &(time_t) */ +#if defined(BSD) && !defined(POSIX_TYPES) +#define TIME_type long * +#else +#define TIME_type time_t * +#endif +/* LOCALTIME_type: type of the argument to localtime() */ +#if (defined(ULTRIX) && !(defined(ULTRIX_PROTO) || defined(NHSTDC))) \ + || (defined(BSD) && !defined(POSIX_TYPES)) +#define LOCALTIME_type long * +#else +#define LOCALTIME_type time_t * +#endif + +#if defined(AMIGA) && !defined(AZTEC_C) && !defined(__SASC_60) \ + && !defined(_DCC) && !defined(__GNUC__) +extern struct tm *localtime(time_t *); +#endif +static struct tm *getlt(void); + +time_t +getnow(void) +{ + time_t datetime = 0; + + (void) time((TIME_type) &datetime); + return datetime; +} + +static struct tm * +getlt(void) +{ + time_t date = getnow(); + + return localtime((LOCALTIME_type) &date); +} + +int +getyear(void) +{ + return (1900 + getlt()->tm_year); +} + +time_t +time_from_yyyymmddhhmmss(char *buf) +{ + int k; + time_t timeresult = (time_t) 0; + struct tm t, *lt; + char *d, *p, y[5], mo[3], md[3], h[3], mi[3], s[3]; + + if (buf && strlen(buf) == 14) { + d = buf; + p = y; /* year */ + for (k = 0; k < 4; ++k) + *p++ = *d++; + *p = '\0'; + p = mo; /* month */ + for (k = 0; k < 2; ++k) + *p++ = *d++; + *p = '\0'; + p = md; /* day */ + for (k = 0; k < 2; ++k) + *p++ = *d++; + *p = '\0'; + p = h; /* hour */ + for (k = 0; k < 2; ++k) + *p++ = *d++; + *p = '\0'; + p = mi; /* minutes */ + for (k = 0; k < 2; ++k) + *p++ = *d++; + *p = '\0'; + p = s; /* seconds */ + for (k = 0; k < 2; ++k) + *p++ = *d++; + *p = '\0'; + lt = getlt(); + if (lt) { + t = *lt; + t.tm_year = atoi(y) - 1900; + t.tm_mon = atoi(mo) - 1; + t.tm_mday = atoi(md); + t.tm_hour = atoi(h); + t.tm_min = atoi(mi); + t.tm_sec = atoi(s); + timeresult = mktime(&t); + } + return timeresult; + } + return (time_t) 0; +} + +char * +yyyymmddhhmmss(time_t date) +{ + long datenum; + static char datestr[15]; + struct tm *lt; + + if (date == 0) + lt = getlt(); + else +#if (defined(ULTRIX) && !(defined(ULTRIX_PROTO) || defined(NHSTDC))) \ + || defined(BSD) + lt = localtime((long *) (&date)); +#else + lt = localtime(&date); +#endif + /* just in case somebody's localtime supplies (year % 100) + rather than the expected (year - 1900) */ + if (lt->tm_year < 70) + datenum = (long) lt->tm_year + 2000L; + else + datenum = (long) lt->tm_year + 1900L; + Snprintf(datestr, sizeof datestr, "%04ld%02d%02d%02d%02d%02d", + datenum, lt->tm_mon + 1, + lt->tm_mday, lt->tm_hour, lt->tm_min, lt->tm_sec); + return datestr; +} + +DISABLE_WARNING_FORMAT_NONLITERAL + +void +raw_printf(const char *line, ...) +{ + va_list the_args; + + va_start(the_args, line); + fprintf(stdout, line, the_args); + va_end(the_args); +} + +RESTORE_WARNING_FORMAT_NONLITERAL + +#ifdef UNIX +/* normalize file name - we don't like .'s, /'s, spaces */ +void +regularize(char *s) +{ + register char *lp; + + while ((lp = strchr(s, '.')) != 0 || (lp = strchr(s, '/')) != 0 + || (lp = strchr(s, ' ')) != 0) + *lp = '_'; +#if defined(SYSV) && !defined(AIX_31) && !defined(SVR4) && !defined(LINUX) \ + && !defined(__APPLE__) +/* avoid problems with 14 character file name limit */ +#ifdef COMPRESS + /* leave room for .e from error and .Z from compress appended to + * save files */ + { +#ifdef COMPRESS_EXTENSION + int i = 12 - strlen(COMPRESS_EXTENSION); +#else + int i = 10; /* should never happen... */ +#endif + if (strlen(s) > i) + s[i] = '\0'; + } +#else + if (strlen(s) > 11) + /* leave room for .nn appended to level files */ + s[11] = '\0'; +#endif +#endif +} +#endif + +int +util_strncmpi(const char *s1, const char *s2, size_t sz) +{ + register char t1, t2; + + while (sz--) { + if (!*s2) + return (*s1 != 0); /* s1 >= s2 */ + else if (!*s1) + return -1; /* s1 < s2 */ + t1 = lowc(*s1++); + t2 = lowc(*s2++); + if (t1 != t2) + return (t1 > t2) ? 1 : -1; + } + return 0; /* s1 == s2 */ +} + +/* should be called with either EXIT_SUCCESS or EXIT_FAILURE */ +void +nh_terminate(int status) +{ + nethack_exit(status); +} + +#ifndef UNIX +void +nethack_exit(int code) +{ + exit(code); +} +#endif /* UNIX */ + +#ifdef UNIX +#ifdef CHDIR +static void +chdirx(const char *dir) +{ + if (dir) { +#ifdef SECURE + (void) setgid(getgid()); + (void) setuid(getuid()); /* Ron Wessels */ +#endif + } else { + /* non-default data files is a sign that scores may not be + * compatible, or perhaps that a binary not fitting this + * system's layout is being used. + */ +#ifdef VAR_PLAYGROUND + int len = strlen(VAR_PLAYGROUND); + + gf.fqn_prefix[SCOREPREFIX] = (char *) alloc(len + 2); + Strcpy(gf.fqn_prefix[SCOREPREFIX], VAR_PLAYGROUND); + if (gf.fqn_prefix[SCOREPREFIX][len - 1] != '/') { + gf.fqn_prefix[SCOREPREFIX][len] = '/'; + gf.fqn_prefix[SCOREPREFIX][len + 1] = '\0'; + } + +#endif + } + +#ifdef HACKDIR + if (dir == (const char *) 0) + dir = HACKDIR; +#endif + + if (dir && chdir(dir) < 0) { + perror(dir); + error("Cannot chdir to %s.", dir); + } +} +#endif /* CHDIR */ +#endif /* UNIX */ + +#ifdef WIN32 + +/* + * Strip out troublesome file system characters. + */ + +void nt_regularize(char* s) /* normalize file name */ +{ + unsigned char *lp; + + for (lp = (unsigned char *) s; *lp; lp++) + if (*lp == '?' || *lp == '"' || *lp == '\\' || *lp == '/' + || *lp == '>' || *lp == '<' || *lp == '*' || *lp == '|' + || *lp == ':' || (*lp > 127)) + *lp = '_'; +} +#endif /* WIN32 */ + +/* duplicated code from options.c */ +/* most environment variables will eventually be printed in an error + * message if they don't work, and most error message paths go through + * BUFSZ buffers, which could be overflowed by a maliciously long + * environment variable. If a variable can legitimately be long, or + * if it's put in a smaller buffer, the responsible code will have to + * bounds-check itself. + */ +char * +nh_getenv(const char *ev) +{ + char *getev = getenv(ev); + + if (getev && strlen(getev) <= (BUFSZ / 2)) + return getev; + else + return (char *) 0; +} + +void +done1(int sig_unused UNUSED) +{ +#ifndef NO_SIGNAL + (void) signal(SIGINT, SIG_IGN); +#endif + if (flags.ignintr) { +#ifndef NO_SIGNAL + (void) signal(SIGINT, (SIG_RET_TYPE) done1); +#endif + } +} + +/* + * I hate having to duplicate this code here, but it is much simpler to + * add these here than take steps to link with mkobj.c, do_name.c, priest.c, + * vault.c, shknam.c, minion.c, dog.c, etc. + */ + +/* allocate space for a monster's name; removes old name if there is one */ +void +new_mgivenname(struct monst *mon, + int lth) /* desired length (caller handles adding 1 + for terminator) */ +{ + if (lth) { + /* allocate mextra if necessary; otherwise get rid of old name */ + if (!mon->mextra) + mon->mextra = newmextra(); + else + free_mgivenname(mon); /* already has mextra, might also have name */ + MGIVENNAME(mon) = (char *) alloc((unsigned) lth); + } else { + /* zero length: the new name is empty; get rid of the old name */ + if (has_mgivenname(mon)) + free_mgivenname(mon); + } +} + +/* release a monster's name; retains mextra even if all fields are now null */ +void +free_mgivenname(struct monst *mon) +{ + if (has_mgivenname(mon)) { + free((genericptr_t) MGIVENNAME(mon)); + MGIVENNAME(mon) = (char *) 0; + } +} +void +newegd(struct monst *mtmp) +{ + if (!mtmp->mextra) + mtmp->mextra = newmextra(); + if (!EGD(mtmp)) { + EGD(mtmp) = (struct egd *) alloc(sizeof (struct egd)); + (void) memset((genericptr_t) EGD(mtmp), 0, sizeof (struct egd)); + } +} + +void +free_egd(struct monst *mtmp) +{ + if (mtmp->mextra && EGD(mtmp)) { + free((genericptr_t) EGD(mtmp)); + EGD(mtmp) = (struct egd *) 0; + } + mtmp->isgd = 0; +} +void +newepri(struct monst *mtmp) +{ + if (!mtmp->mextra) + mtmp->mextra = newmextra(); + if (!EPRI(mtmp)) { + EPRI(mtmp) = (struct epri *) alloc(sizeof(struct epri)); + (void) memset((genericptr_t) EPRI(mtmp), 0, sizeof(struct epri)); + } +} + +void +free_epri(struct monst *mtmp) +{ + if (mtmp->mextra && EPRI(mtmp)) { + free((genericptr_t) EPRI(mtmp)); + EPRI(mtmp) = (struct epri *) 0; + } + mtmp->ispriest = 0; +} +void +neweshk(struct monst* mtmp) +{ + if (!mtmp->mextra) + mtmp->mextra = newmextra(); + if (!ESHK(mtmp)) + ESHK(mtmp) = (struct eshk *) alloc(sizeof(struct eshk)); + (void) memset((genericptr_t) ESHK(mtmp), 0, sizeof(struct eshk)); + ESHK(mtmp)->bill_p = (struct bill_x *) 0; +} + +void +free_eshk(struct monst* mtmp) +{ + if (mtmp->mextra && ESHK(mtmp)) { + free((genericptr_t) ESHK(mtmp)); + ESHK(mtmp) = (struct eshk *) 0; + } + mtmp->isshk = 0; +} + +void +newemin(struct monst *mtmp) +{ + if (!mtmp->mextra) + mtmp->mextra = newmextra(); + if (!EMIN(mtmp)) { + EMIN(mtmp) = (struct emin *) alloc(sizeof(struct emin)); + (void) memset((genericptr_t) EMIN(mtmp), 0, sizeof(struct emin)); + } +} + +void +free_emin(struct monst *mtmp) +{ + if (mtmp->mextra && EMIN(mtmp)) { + free((genericptr_t) EMIN(mtmp)); + EMIN(mtmp) = (struct emin *) 0; + } + mtmp->isminion = 0; +} + +void +newedog(struct monst *mtmp) +{ + if (!mtmp->mextra) + mtmp->mextra = newmextra(); + if (!EDOG(mtmp)) { + EDOG(mtmp) = (struct edog *) alloc(sizeof(struct edog)); + (void) memset((genericptr_t) EDOG(mtmp), 0, sizeof(struct edog)); + } +} + +void +free_edog(struct monst *mtmp) +{ + if (mtmp->mextra && EDOG(mtmp)) { + free((genericptr_t) EDOG(mtmp)); + EDOG(mtmp) = (struct edog *) 0; + } + mtmp->mtame = 0; +} + +void +newebones(struct monst *mtmp) +{ + if (!mtmp->mextra) + mtmp->mextra = newmextra(); + if (!EBONES(mtmp)) { + EBONES(mtmp) = (struct ebones *) alloc(sizeof(struct ebones)); + (void) memset((genericptr_t) EBONES(mtmp), 0, sizeof(struct ebones)); + } +} + +void +free_ebones(struct monst *mtmp) +{ + if (mtmp->mextra && EBONES(mtmp)) { + free((genericptr_t) EBONES(mtmp)); + EBONES(mtmp) = (struct ebones *) 0; + } +} + +static const struct mextra zeromextra = DUMMY; + +static void +init_mextra(struct mextra *mex) +{ + *mex = zeromextra; + mex->mcorpsenm = NON_PM; +} + +struct mextra * +newmextra(void) +{ + struct mextra *mextra; + + mextra = (struct mextra *) alloc(sizeof(struct mextra)); + init_mextra(mextra); + return mextra; +} + +void +newomonst(struct obj* otmp) +{ + if (!otmp->oextra) + otmp->oextra = newoextra(); + + if (!OMONST(otmp)) { + struct monst *m = newmonst(); + + *m = cg.zeromonst; + OMONST(otmp) = m; + } +} + +void +free_omonst(struct obj* otmp) +{ + if (otmp->oextra) { + struct monst *m = OMONST(otmp); + + if (m) { + if (m->mextra) + dealloc_mextra(m); + free((genericptr_t) m); + OMONST(otmp) = (struct monst *) 0; + } + } +} + +void +newomid(struct obj* otmp) +{ + if (!otmp->oextra) + otmp->oextra = newoextra(); + OMID(otmp) = 0; +} + +void +free_omid(struct obj* otmp) +{ + OMID(otmp) = 0; +} + +void +new_omailcmd(struct obj* otmp, const char * response_cmd) +{ + if (!otmp->oextra) + otmp->oextra = newoextra(); + if (OMAILCMD(otmp)) + free_omailcmd(otmp); + OMAILCMD(otmp) = dupstr(response_cmd); +} + +void +free_omailcmd(struct obj* otmp) +{ + if (otmp->oextra && OMAILCMD(otmp)) { + free((genericptr_t) OMAILCMD(otmp)); + OMAILCMD(otmp) = (char *) 0; + } +} + +static const struct oextra zerooextra = DUMMY; + +static void +init_oextra(struct oextra* oex) +{ + *oex = zerooextra; +} + + +struct oextra * +newoextra(void) +{ + struct oextra *oextra; + + oextra = (struct oextra *) alloc(sizeof (struct oextra)); + init_oextra(oextra); + return oextra; +} + +void +dealloc_mextra(struct monst* m) +{ + struct mextra *x = m->mextra; + + if (x) { + if (x->mgivenname) + free((genericptr_t) x->mgivenname); + if (x->egd) + free((genericptr_t) x->egd); + if (x->epri) + free((genericptr_t) x->epri); + if (x->eshk) + free((genericptr_t) x->eshk); + if (x->emin) + free((genericptr_t) x->emin); + if (x->edog) + free((genericptr_t) x->edog); + if (x->ebones) + free((genericptr_t) x->ebones); + /* [no action needed for x->mcorpsenm] */ + + free((genericptr_t) x); + m->mextra = (struct mextra *) 0; + } +} + +void +dealloc_monst(struct monst* mon) +{ + if (mon->mextra) + dealloc_mextra(mon); + free((genericptr_t) mon); +} + +/* allocate space for an object's name; removes old name if there is one */ +void +new_oname(struct obj *obj, + int lth) /* desired length (caller handles adding 1 + for terminator) */ +{ + if (lth) { + /* allocate oextra if necessary; otherwise get rid of old name */ + if (!obj->oextra) + obj->oextra = newoextra(); + else + free_oname(obj); /* already has oextra, might also have name */ + ONAME(obj) = (char *) alloc((unsigned) lth); + } else { + /* zero length: the new name is empty; get rid of the old name */ + if (has_oname(obj)) + free_oname(obj); + } +} + +/* release an object's name; retains oextra even if all fields are now null */ +void +free_oname(struct obj *obj) +{ + if (has_oname(obj)) { + free((genericptr_t) ONAME(obj)); + ONAME(obj) = (char *) 0; + } +} + +#ifdef WIN32 +void +win32_abort(void) +{ + abort(); +} +#endif + +static int +length_without_val(const char *user_string, int len) +{ + const char *p = strchr(user_string, ':'), *q = strchr(user_string, '='); + + if (!p || (q && q < p)) + p = q; + if (p) { + /* 'user_string' hasn't necessarily been through mungspaces() + so might have tabs or consecutive spaces */ + while (p > user_string && isspace((uchar) * (p - 1))) + p--; + len = (int) (p - user_string); + } + return len; +} + +/* check whether a user-supplied option string is a proper leading + substring of a particular option name; option string might have + a colon or equals sign and arbitrary value appended to it */ +boolean +match_optname(const char *user_string, const char *optn_name, int min_length, + boolean val_allowed) +{ + int len = (int) strlen(user_string); + + if (val_allowed) + len = length_without_val(user_string, len); + + return (boolean) (len >= min_length + && !strncmpi(optn_name, user_string, len)); +} + +/* sfctool.c */ diff --git a/util/sfexpasc.c b/util/sfexpasc.c new file mode 100644 index 000000000..f129efe6c --- /dev/null +++ b/util/sfexpasc.c @@ -0,0 +1,1296 @@ +/* NetHack 3.7 sfexpasc.c.c $NHDT-Date$ $NHDT-Branch$:$NHDT-Revision$ */ +/* Copyright (c) Michael Allison, 2025. */ +/* NetHack may be freely redistributed. See license for details. */ + +/* avoid the global.h define */ +#define STRNCMPI + +#include "hack.h" +#include "integer.h" +#include "sfprocs.h" +#include "sfproto.h" + +#if defined(MACOSX) || defined(VMS) +extern long long atoll(const char *); +#endif + +static void put_savefield(NHFILE *, char *, size_t); +char *get_savefield(NHFILE *, char *, size_t); +#ifdef SAVEFILE_DEBUGGING +void report_problem_exportascii(NHFILE *, const char *, const char *, + const char *); +#endif + +#ifdef _MSC_VER +#define strcmpi _stricmp +#else +#define strcmpi strcasecmp +#endif + +static char linebuf[BUFSZ * 10]; +static char outbuf[BUFSZ * 10]; + +#if 0 +void exportascii_sfo_any(NHFILE *nhfp, union any *d_any, const char *myname UNUSED); +void exportascii_sfi_any(NHFILE *nhfp, union any *d_any, const char *myname UNUSED); +void exportascii_sfo_aligntyp(NHFILE *nhfp, aligntyp *d_aligntyp, const char *myname UNUSED); +void exportascii_sfo_bitfield(NHFILE *nhfp, uint8_t *d_bitfield, const char *myname UNUSED, int); +void exportascii_sfo_boolean(NHFILE *nhfp, boolean *d_boolean, const char *myname UNUSED); +void exportascii_sfo_genericptr(NHFILE *nhfp, genericptr_t *d_genericptr, const char *myname UNUSED); +void exportascii_sfo_int32(NHFILE *nhfp, int *d_int, const char *myname UNUSED); +void exportascii_sfo_long(NHFILE *nhfp, long *d_long, const char *myname UNUSED); +void exportascii_sfo_schar(NHFILE *nhfp, schar *d_schar, const char *myname UNUSED); +void exportascii_sfo_int16(NHFILE *nhfp, short *d_short, const char *myname UNUSED); +void exportascii_sfo_size_t(NHFILE *nhfp, size_t *d_size_t, const char *myname UNUSED); +void exportascii_sfo_time_t(NHFILE *nhfp, time_t *d_time_t, const char *myname UNUSED); +void exportascii_sfo_uint32(NHFILE *nhfp, unsigned *d_unsigned, const char *myname); +void exportascii_sfo_uint(NHFILE *nhfp, unsigned *d_unsigned, const char *myname); +void exportascii_sfo_uchar(NHFILE *nhfp, unsigned char *d_uchar, const char *myname UNUSED); +void exportascii_sfo_uint(NHFILE *nhfp, unsigned int *d_uint, const char *myname UNUSED); +void exportascii_sfo_ulong(NHFILE *nhfp, unsigned long *d_ulong, const char *myname UNUSED); +void exportascii_sfo_ushort(NHFILE *nhfp, unsigned short *d_ushort, const char *myname UNUSED); +void exportascii_sfo_coordxy(NHFILE *nhfp, coordxy *d_coordxy, const char *myname UNUSED); +void exportascii_sfo_char(NHFILE *nhfp, xint8 *d_xint8, const char *myname UNUSED); +void exportascii_sfo_xint16(NHFILE *nhfp, xint16 *d_xint16, const char *myname UNUSED); +void exportascii_sfo_char(NHFILE *nhfp, char *d_str, const char *myname UNUSED, int cnt); +void exportascii_sfo_addinfo(NHFILE *nhfp UNUSED, const char *parent UNUSED, const char *action UNUSED, const char *myname UNUSED, int indx UNUSED); +void exportascii_sfi_aligntyp(NHFILE *nhfp, aligntyp *d_aligntyp, const char *myname UNUSED); +void exportascii_sfi_bitfield(NHFILE *nhfp, uint8_t *d_bitfield, const char *myname UNUSED, int); +void exportascii_sfi_boolean(NHFILE *nhfp, boolean *d_boolean, const char *myname UNUSED); +void exportascii_sfi_genericptr(NHFILE *nhfp, genericptr_t *d_genericptr, const char *myname UNUSED); +void exportascii_sfi_int32(NHFILE *nhfp, int *d_int, const char *myname UNUSED); +void exportascii_sfi_long(NHFILE *nhfp, long *d_long, const char *myname UNUSED); +void exportascii_sfi_schar(NHFILE *nhfp, schar *d_schar, const char *myname UNUSED); +void exportascii_sfi_int16(NHFILE *nhfp, short *d_short, const char *myname UNUSED); +void exportascii_sfi_size_t(NHFILE *nhfp, size_t *d_size_t, const char *myname UNUSED); +void exportascii_sfi_time_t(NHFILE *nhfp, time_t *d_time_t, const char *myname UNUSED); +void exportascii_sfi_uint32(NHFILE *nhfp, unsigned *d_unsigned, const char *myname); +void exportascii_sfi_uint(NHFILE *nhfp, unsigned *d_unsigned, const char *myname); +void exportascii_sfi_uchar(NHFILE *nhfp, unsigned char *d_uchar, const char *myname UNUSED); +void exportascii_sfi_uint(NHFILE *nhfp, unsigned int *d_uint, const char *myname UNUSED); +void exportascii_sfi_ulong(NHFILE *nhfp, unsigned long *d_ulong, const char *myname UNUSED); +void exportascii_sfi_ushort(NHFILE *nhfp, unsigned short *d_ushort, const char *myname UNUSED); +void exportascii_sfi_coordxy(NHFILE *nhfp, coordxy *d_coordxy, const char *myname UNUSED); +void exportascii_sfi_xint8(NHFILE *nhfp, xint8 *d_xint8, const char *myname UNUSED); +void exportascii_sfi_xint16(NHFILE *nhfp, xint16 *d_xint16, const char *myname UNUSED); +void exportascii_sfi_cnt(NHFILE *nhfp, char *d_str, const char *myname UNUSED, int cnt); +#endif + +#define SFO_BODY(dt) \ +{ \ +} + +#define SFI_BODY(dt) \ +{ \ +} + +#define SF_A(dtyp) \ +void exportascii_sfo_##dtyp(NHFILE *, dtyp *d_##dtyp, \ + const char *); \ +void exportascii_sfi_##dtyp(NHFILE *, dtyp *d_##dtyp, \ + const char *); + +/* +void exportascii_sfo_##dtyp(NHFILE *nhfp, dtyp *d_##dtyp, \ + const char *myname UNUSED) \ + SFO_BODY(dtyp) \ + \ +void exportascii_sfi_##dtyp(NHFILE *nhfp, dtyp *d_##dtyp, \ + const char *myname UNUSED) \ + SFI_BODY(dtyp) +*/ + +#define SF_C(keyw, dtyp) \ +void exportascii_sfo_##dtyp(NHFILE * UNUSED, keyw dtyp *d_##dtyp UNUSED, \ + const char *); \ +void exportascii_sfi_##dtyp(NHFILE *UNUSED, keyw dtyp *d_##dtyp, \ + const char *); \ + \ +void exportascii_sfo_##dtyp(NHFILE *nhfp UNUSED, keyw dtyp *d_##dtyp UNUSED, \ + const char *myname UNUSED) \ + SFO_BODY(dtyp) \ + \ +void exportascii_sfi_##dtyp(NHFILE *nhfp UNUSED, keyw dtyp *d_##dtyp UNUSED, \ + const char *myname UNUSED) \ + SFI_BODY(dtyp) + + +#define SF_X(xxx, dtyp) \ +void exportascii_sfo_##dtyp(NHFILE * UNUSED, xxx *d_##dtyp UNUSED, \ + const char * UNUSED); \ +void exportascii_sfi_##dtyp(NHFILE *, xxx *d_##dtyp, \ + const char *); \ + \ +void exportascii_sfo_##dtyp(NHFILE *nhfp UNUSED, xxx *d_##dtyp UNUSED, \ + const char *myname UNUSED) \ + SFO_BODY(dtyp) \ + \ +void exportascii_sfi_##dtyp(NHFILE *nhfp, xxx *d_##dtyp, \ + const char *myname UNUSED) \ + SFI_BODY(dtyp) + + +#define SF_BF(xxx, dtyp) \ +void exportascii_sfo_##dtyp(NHFILE *, xxx *d_##dtyp, \ + const char *, int); \ +void exportascii_sfi_##dtyp(NHFILE *, xxx *d_##dtyp, \ + const char *, int); + +SF_C(struct, arti_info) +SF_C(struct, nhrect) +SF_C(struct, branch) +SF_C(struct, bubble) +SF_C(struct, cemetery) +SF_C(struct, context_info) +SF_C(struct, nhcoord) +SF_C(struct, damage) +SF_C(struct, dest_area) +SF_C(struct, dgn_topology) +SF_C(struct, dungeon) +SF_C(struct, d_level) +SF_C(struct, ebones) +SF_C(struct, edog) +SF_C(struct, egd) +SF_C(struct, emin) +SF_C(struct, engr) +SF_C(struct, epri) +SF_C(struct, eshk) +SF_C(struct, fe) +SF_C(struct, flag) +SF_C(struct, fruit) +SF_C(struct, gamelog_line) +SF_C(struct, kinfo) +SF_C(struct, levelflags) +SF_C(struct, ls_t) +SF_C(struct, linfo) +SF_C(struct, mapseen_feat) +SF_C(struct, mapseen_flags) +SF_C(struct, mapseen_rooms) +SF_C(struct, mkroom) +SF_C(struct, monst) +SF_C(struct, mvitals) +SF_C(struct, obj) +SF_C(struct, objclass) +SF_C(struct, q_score) +SF_C(struct, rm) +SF_C(struct, spell) +SF_C(struct, stairway) +SF_C(struct, s_level) +SF_C(struct, trap) +SF_C(struct, version_info) +SF_C(struct, you) +/* SF_C(union, any) */ +void exportascii_sfo_any(NHFILE *nhfp, union any *d_any, const char *myname UNUSED); +void exportascii_sfi_any(NHFILE *nhfp, union any *d_any, const char *myname UNUSED); + +SF_A(aligntyp) +SF_A(boolean) +SF_A(coordxy) +SF_A(genericptr) +SF_A(int) +SF_A(int16) +SF_A(int32) +SF_A(int64) +SF_A(long) +SF_A(schar) +SF_A(short) +SF_A(size_t) +SF_A(time_t) +SF_A(uchar) +SF_A(uint16) +SF_A(uint32) +SF_A(uint64) +SF_A(ulong) +SF_A(unsigned) +SF_A(ushort) +SF_A(xint16) +SF_A(xint8) +void exportascii_sfo_char(NHFILE *nhfp, char *d_char, const char *myname UNUSED, int cnt); +void exportascii_sfi_char(NHFILE *nhfp, char *d_char, const char *myname UNUSED, int cnt); +void exportascii_sfo_bitfield(NHFILE *nhfp, uint8_t *d_bitfield, + const char *myname UNUSED, int bflen UNUSED); +void exportascii_sfi_bitfield(NHFILE *nhfp, uint8_t *d_bitfield, + const char *myname UNUSED, int bflen UNUSED); +int critical_members_count_core(NHFILE *nhfp); + + +/* + *---------------------------------------------------------------------------- + * Sfo_def_ routines + * + * Default output routines. + * + *---------------------------------------------------------------------------- + */ + + +void +exportascii_sfo_any(NHFILE *nhfp, union any *d_any, const char *myname UNUSED) +{ + /* const char *parent = "any"; */ + + /* nhUse(parent); */ + Sprintf(outbuf, "%llx", (unsigned long long) d_any->a_void); + put_savefield(nhfp, outbuf, sizeof outbuf); + + Sprintf(outbuf, "%lu", d_any->a_ulong); + put_savefield(nhfp, outbuf, sizeof outbuf); + + Sprintf(outbuf, "%ld", d_any->a_long); + put_savefield(nhfp, outbuf, sizeof outbuf); + + Sprintf(outbuf, "%d", d_any->a_uint); + put_savefield(nhfp, outbuf, sizeof outbuf); + + Sprintf(outbuf, "%d", d_any->a_int);; + put_savefield(nhfp, outbuf, sizeof outbuf); + + Sprintf(outbuf, "%hd", (short) d_any->a_char); + put_savefield(nhfp, outbuf, sizeof outbuf); + +#if 0 + Sfo_genericptr(nhfp, d_any->a_void, parent, "a_void", 1); /* (genericptr_t) */ + Sfo_genericptr(nhfp, d_any->a_obj, parent, "a_obj", 1); /* (struct obj *) */ + Sfo_genericptr(nhfp, d_any->a_monst, parent, "a_monst", 1); /* (struct monst *) */ + Sfo_int32(nhfp, &d_any->a_int, parent, "a_int", 1); /* (int) */ + Sfo_char(nhfp, &d_any->a_char, parent, "a_char", 1); /* (char) */ + Sfo_schar(nhfp, &d_any->a_schar, parent, "a_schar", 1); /* (schar) */ + Sfo_uchar(nhfp, &d_any->a_uchar, parent, "a_uchar", 1); /* (uchar) */ + Sfo_uint(nhfp, &d_any->a_uint, parent, "a_uint", 1); /* (unsigned int) */ + Sfo_long(nhfp, &d_any->a_long, parent, "a_long", 1); /* (long) */ + Sfo_ulong(nhfp, &d_any->a_ulong, parent, "a_ulong", 1); /* (unsigned long) */ + Sfo_genericptr(nhfp, d_any->a_iptr, parent, "a_iptr", 1); /* (int *) */ + Sfo_genericptr(nhfp, d_any->a_lptr, parent, "a_lptr", 1); /* (long *) */ + Sfo_genericptr(nhfp, d_any->a_ulptr, parent, "a_ulptr", 1); /* (unsigned long *) */ + Sfo_genericptr(nhfp, d_any->a_uptr, parent, "a_uptr", 1); /* (unsigned *) */my + Sfo_genericptr(nhfp, d_any->a_string, parent, "a_string", 1); /* (const char *) */ + Sfo_ulong(nhfp, &d_any->a_mask32, parent, "a_mask32", 1); /* (unsigned long) */ +#endif +} + +void +exportascii_sfo_aligntyp(NHFILE *nhfp, aligntyp *d_aligntyp, const char *myname UNUSED) +{ + int itmp; + itmp = (int) *d_aligntyp; + Sprintf(outbuf, "%d", (short) itmp); + put_savefield(nhfp, outbuf, sizeof outbuf); +} + +void +exportascii_sfo_bitfield(NHFILE *nhfp, uint8_t *d_bitfield, const char *myname UNUSED, int bflen UNUSED) +{ + /* for bitfields, cnt is the number of bits, not an array */ + Sprintf(outbuf, "%hu", (unsigned short) *d_bitfield); + put_savefield(nhfp, outbuf, sizeof outbuf); +} + +void +exportascii_sfo_boolean(NHFILE *nhfp, boolean *d_boolean, const char *myname UNUSED) +{ + if (nhfp->fpdebug) + fprintf(nhfp->fpdebug, "(%s)\n", (*d_boolean) ? "TRUE" : "FALSE"); + Sprintf(outbuf, "%s", *d_boolean ? "true" : "false"); + put_savefield(nhfp, outbuf, sizeof outbuf); + d_boolean++; +} + +void exportascii_sfo_genericptr(NHFILE *nhfp, genericptr_t *d_genericptr, + const char *myname UNUSED); + +void +exportascii_sfo_genericptr(NHFILE *nhfp, genericptr_t *d_genericptr, const char *myname UNUSED) +{ + unsigned long tmp; + char *byteptr = (char *) d_genericptr; + /* + * sbrooms is an array of pointers to mkroom. + * That array dimension is MAX_SUBROOMS. + * Even though the pointers themselves won't + * be valid, we need to account for the existence + * of that array and perhaps zero or non-zero. + */ + tmp = (*d_genericptr) ? 1UL : 0UL; + Sprintf(outbuf, "%08lu", tmp); + put_savefield(nhfp, outbuf, sizeof outbuf); + byteptr += sizeof(void *); + d_genericptr = (genericptr_t) byteptr; +} + +#if 0 +void +exportascii_sfo_int32(NHFILE *nhfp, int *d_int, const char *myname UNUSED) +{ + Sprintf(outbuf, "%d", *d_int); + put_savefield(nhfp, outbuf, sizeof outbuf); + d_int++; +} +#endif + +void +exportascii_sfo_long(NHFILE *nhfp, long *d_long, const char *myname UNUSED) +{ + Sprintf(outbuf, "%ld", *d_long); + put_savefield(nhfp, outbuf, sizeof outbuf); + d_long++; +} + +void +exportascii_sfo_schar(NHFILE *nhfp, schar *d_schar, const char *myname UNUSED) +{ + int itmp; + itmp = (int) *d_schar; + Sprintf(outbuf, "%d", itmp); + put_savefield(nhfp, outbuf, sizeof outbuf); + d_schar++; +} + +void +exportascii_sfo_int16(NHFILE *nhfp, short *d_short, const char *myname UNUSED) +{ + Sprintf(outbuf, "%hd", *d_short); + put_savefield(nhfp, outbuf, sizeof outbuf); + d_short++; +} + +void +exportascii_sfo_size_t(NHFILE *nhfp, size_t *d_size_t, const char *myname UNUSED) +{ + unsigned long ul = (unsigned long) *d_size_t; + + Sprintf(outbuf, "%lu", ul); + put_savefield(nhfp, outbuf, sizeof outbuf); + d_size_t++; +} + +void +exportascii_sfo_time_t(NHFILE *nhfp, time_t *d_time_t, const char *myname UNUSED) +{ + Sprintf(outbuf, "%s", yyyymmddhhmmss(*d_time_t)); + put_savefield(nhfp, outbuf, sizeof outbuf); +} +void +exportascii_sfo_xint8(NHFILE *nhfp, int8 *d_int8, const char *myname UNUSED) +{ + Sprintf(outbuf, "%d", (int) *d_int8); + put_savefield(nhfp, outbuf, sizeof outbuf); + d_int8++; +} +#if 0 +void +exportascii_sfo_int16(NHFILE *nhfp, int16 *d_int16, const char *myname UNUSED) +{ + Sprintf(outbuf, "%d", (int) *d_int16); + put_savefield(nhfp, outbuf, sizeof outbuf); + d_uint16++; +} +#endif + +#if 0 +void +exportascii_sfo_char(NHFILE *nhfp, xint8 *d_xint8, const char *myname UNUSED, int cnt) +{ + short tmp; + + tmp = (int) *d_xint8; + Sprintf(outbuf, "%d", tmp); + put_savefield(nhfp, outbuf, sizeof outbuf); + d_xint8++; +} +#endif + +void +exportascii_sfo_int32(NHFILE *nhfp, int32 *d_int32, const char *myname UNUSED) +{ + Sprintf(outbuf, "%d", *d_int32); + put_savefield(nhfp, outbuf, sizeof outbuf); + d_int32++; +} + +void +exportascii_sfo_int64(NHFILE *nhfp, int64 *d_int64, const char *myname UNUSED) +{ + Sprintf(outbuf, "%lld", (long long) *d_int64); + put_savefield(nhfp, outbuf, sizeof outbuf); + d_int64++; +} + +void +exportascii_sfo_int(NHFILE *nhfp, int *d_int, const char *myname UNUSED) +{ + Sprintf(outbuf, "%d", *d_int); + put_savefield(nhfp, outbuf, sizeof outbuf); + d_int++; +} +void +exportascii_sfo_short(NHFILE *nhfp, short *d_short, const char *myname UNUSED) +{ + Sprintf(outbuf, "%d", (int) *d_short); + put_savefield(nhfp, outbuf, sizeof outbuf); + d_short++; +} +/* aka exportascii_sfo_uint8 */ +void +exportascii_sfo_uchar(NHFILE *nhfp, unsigned char *d_uchar, const char *myname UNUSED) +{ + unsigned x_uint32 = (uint32) *d_uchar; + + Sprintf(outbuf, "%u", x_uint32); + put_savefield(nhfp, outbuf, sizeof outbuf); + d_uchar++; +} + +void +exportascii_sfo_uint16(NHFILE *nhfp, uint16 *d_uint16, const char *myname UNUSED) +{ + Sprintf(outbuf, "%u", (uint32) *d_uint16); + put_savefield(nhfp, outbuf, sizeof outbuf); + d_uint16++; +} + +void +exportascii_sfo_uint32(NHFILE *nhfp, uint32 *d_uint32, const char *myname UNUSED) +{ + Sprintf(outbuf, "%u", *d_uint32); + put_savefield(nhfp, outbuf, sizeof outbuf); + d_uint32++; +} + +void +exportascii_sfo_uint64(NHFILE *nhfp, uint64 *d_uint64, const char *myname UNUSED) +{ + Sprintf(outbuf, "%llu", (unsigned long long) *d_uint64); + put_savefield(nhfp, outbuf, sizeof outbuf); + d_uint64++; +} + +void +exportascii_sfo_ulong(NHFILE *nhfp, unsigned long *d_ulong, const char *myname UNUSED) +{ + Sprintf(outbuf, "%lu", *d_ulong); + put_savefield(nhfp, outbuf, sizeof outbuf); + d_ulong++; +} + + +void +exportascii_sfo_ushort(NHFILE *nhfp, unsigned short *d_ushort, const char *myname UNUSED) +{ + Sprintf(outbuf, "%hu", *d_ushort); + put_savefield(nhfp, outbuf, sizeof outbuf); + d_ushort++; +} + +void +exportascii_sfo_unsigned(NHFILE *nhfp, unsigned *d_unsigned, const char *myname UNUSED) +{ + Sprintf(outbuf, "%u", *d_unsigned); + put_savefield(nhfp, outbuf, sizeof outbuf); + d_unsigned++; +} + +void +exportascii_sfo_coordxy(NHFILE *nhfp, coordxy *d_coordxy, const char *myname UNUSED) +{ + short tmp; + + tmp = (short) *d_coordxy; + Sprintf(outbuf, "%hu", tmp); + put_savefield(nhfp, outbuf, sizeof outbuf); + d_coordxy++; +} + + +void +exportascii_sfo_xint16(NHFILE *nhfp, xint16 *d_xint16, const char *myname UNUSED) +{ + short tmp; + + tmp = (short) *d_xint16; + Sprintf(outbuf, "%hu", tmp); + put_savefield(nhfp, outbuf, sizeof outbuf); + d_xint16++; +} + +static char strbuf[BUFSZ * 10]; + +void +exportascii_sfo_char(NHFILE *nhfp, char *d_char, const char *myname UNUSED, int cnt) +{ + int i, j; + uint uintval; + char sval[QBUFSZ]; + uchar *usrc = (uchar *) d_char, *udest = (uchar *)strbuf; + + /* cnt is the number of characters */ + for (i = 0; i < cnt; ++i) { + if ((*usrc < 32) || (*usrc == '\\') || (*usrc == '|')) { + *udest++ = '\\'; + uintval = *usrc++; + Sprintf(sval, "%03u", uintval); + for (j = 0; j < 3; ++j) + *udest++ = (uchar) sval[j]; + } else { + *udest++ = *usrc++; + } + } + *udest = '\0'; + put_savefield(nhfp, strbuf, strlen(strbuf)); +} + +static void +put_savefield(NHFILE *nhfp, char *obuf, size_t outbufsz UNUSED) +{ + nhfp->wcount++; + fprintf(nhfp->fpdef, "%07ld|%s\n", nhfp->wcount, obuf); + fflush(nhfp->fpdef); +} + +/* + *---------------------------------------------------------------------------- + * exportascii_sfi_ routines called from functions in Sfi_base.c + *---------------------------------------------------------------------------- + */ + +void exportascii_sfi_any(NHFILE *nhfp, union any *d_any, const char *myname UNUSED); + +void +exportascii_sfi_any(NHFILE *nhfp, union any *d_any, const char *myname UNUSED) +{ + char *rstr; + long long tmp; + + rstr = get_savefield(nhfp, linebuf, BUFSZ); + tmp = atoll(rstr); + d_any->a_uint64 = (uint64) tmp; + + rstr = get_savefield(nhfp, linebuf, BUFSZ); + tmp = atoll(rstr); + d_any->a_ulong = (unsigned long) tmp; + rstr = get_savefield(nhfp, linebuf, BUFSZ); + d_any->a_long = atol(rstr); + + rstr = get_savefield(nhfp, linebuf, BUFSZ); + tmp = atoll(rstr); + d_any->a_uint = (unsigned int) tmp; + + rstr = get_savefield(nhfp, linebuf, BUFSZ); + d_any->a_int = atoi(rstr); + + rstr = get_savefield(nhfp, linebuf, BUFSZ); + d_any->a_char = (char) atoi(rstr); + +#if 0 + Sfi_genericptr(nhfp, d_any->a_void, parent, "a_void", 1); + Sfi_genericptr(nhfp, d_any->a_obj, parent, "a_obj", 1); + Sfi_genericptr(nhfp, d_any->a_monst, parent, "a_monst", 1); + Sfi_int32(nhfp, &d_any->a_int, parent, "a_int", 1); + Sfi_char(nhfp, &d_any->a_char, parent, "a_char", 1); + Sfi_schar(nhfp, &d_any->a_schar, parent, "a_schar", 1); + Sfi_uchar(nhfp, &d_any->a_uchar, parent, "a_uchar", 1); + Sfi_uint(nhfp, &d_any->a_uint, parent, "a_uint", 1); + Sfi_long(nhfp, &d_any->a_long, parent, "a_long", 1); + Sfi_ulong(nhfp, &d_any->a_ulong, parent, "a_ulong", 1); + Sfi_genericptr(nhfp, d_any->a_iptr, parent, "a_iptr", 1); + Sfi_genericptr(nhfp, d_any->a_lptr, parent, "a_lptr", 1); + Sfi_genericptr(nhfp, d_any->a_ulptr, parent, "a_ulptr", 1); + Sfi_genericptr(nhfp, d_any->a_uptr, parent, "a_uptr", 1); + Sfi_genericptr(nhfp, d_any->a_string, parent, "a_string", 1); + Sfi_ulong(nhfp, &d_any->a_mask32, parent, "a_mask32", 1); +#endif +} + +void +exportascii_sfi_aligntyp(NHFILE *nhfp, aligntyp *d_aligntyp, const char *myname UNUSED) +{ + char *rstr; + aligntyp tmp; + long long lltmp; + + rstr = get_savefield(nhfp, linebuf, BUFSZ); + lltmp = atoll(rstr); + tmp = (aligntyp) lltmp; +#ifdef SAVEFILE_DEBUGGING + if (nhfp->structlevel && tmp != *d_aligntyp) + report_problem_ascii(nhfp, myparent, myname, parent); + else +#endif + *d_aligntyp = tmp; +} + +void +exportascii_sfi_bitfield(NHFILE *nhfp, uint8_t *d_bitfield, const char *myname UNUSED, int bflen UNUSED) +{ + char *rstr; + uint8_t tmp; + + /* cnt is the number of bits in the bitfield, not an array dimension */ + rstr = get_savefield(nhfp, linebuf, BUFSZ); + tmp = (uint8_t) atoi(rstr); +#ifdef SAVEFILE_DEBUGGING + if (nhfp->structlevel && tmp != *d_bitfield) + report_problem_ascii(nhfp, myparent, myname, parent); + else +#endif + *d_bitfield = tmp; +} + +void +exportascii_sfi_boolean(NHFILE *nhfp, boolean *d_boolean, const char *myname UNUSED) +{ + char *rstr; + + rstr = get_savefield(nhfp, linebuf, BUFSZ); +#ifdef SAVEFILE_DEBUGGING + if (!strcmpi(rstr, "false") && + !strcmpi(rstr, "true")) + report_problem_ascii(nhfp, myparent, myname, parent); + else +#endif + if (!strcmpi(rstr, "false")) + *d_boolean = FALSE; + else + *d_boolean = TRUE; + d_boolean++; +} + +void exportascii_sfi_genericptr(NHFILE *nhfp, genericptr_t *d_genericptr, + const char *myname UNUSED); + +void +exportascii_sfi_genericptr(NHFILE *nhfp, genericptr_t *d_genericptr, const char *myname UNUSED) +{ + long long lltmp; + char *rstr; + static const char *glorkum = "glorkum"; + + /* + * sbrooms is an array of pointers to mkroom. + * That array dimension is MAX_SUBROOMS. + * Even though the pointers themselves won't + * be valid, we need to account for the existence + * of that array. + */ + /* these pointers can't actually be valid */ + rstr = get_savefield(nhfp, linebuf, sizeof linebuf); + lltmp = atoll(rstr); + *d_genericptr = lltmp ? (genericptr_t) glorkum : (genericptr_t) 0; +} + +void +exportascii_sfi_int32(NHFILE *nhfp, int32 *d_int32, const char *myname UNUSED) +{ + int32 tmp; + char *rstr; + long ltmp; + + rstr = get_savefield(nhfp, linebuf, BUFSZ); + ltmp = atol(rstr); + tmp = (int32) ltmp; +#ifdef SAVEFILE_DEBUGGING + if (nhfp->structlevel && tmp != *d_int32) + report_problem_ascii(nhfp, myparent, myname, parent); + else +#endif + *d_int32 = (int32) tmp; + d_int32++; +} + +void +exportascii_sfi_int(NHFILE *nhfp, int *d_int, const char *myname UNUSED) +{ + int tmp; + char *rstr; + long ltmp; + + rstr = get_savefield(nhfp, linebuf, BUFSZ); + ltmp = atol(rstr); + tmp = (int) ltmp; +#ifdef SAVEFILE_DEBUGGING + if (nhfp->structlevel && tmp != *d_int) + report_problem_ascii(nhfp, myparent, myname, parent); + else +#endif + *d_int = (int32) tmp; + d_int++; +} +void +exportascii_sfi_long(NHFILE *nhfp, long *d_long, const char *myname UNUSED) +{ + long tmp; + long long lltmp; + char *rstr; + + rstr = get_savefield(nhfp, linebuf, BUFSZ); + lltmp = atoll(rstr); + tmp = (long) lltmp; +#ifdef SAVEFILE_DEBUGGING + if (nhfp->structlevel && tmp != *d_long) + report_problem_ascii(nhfp, myparent, myname, parent); + else +#endif + *d_long = tmp; + d_long++; +} + +void +exportascii_sfi_schar(NHFILE *nhfp, schar *d_schar, const char *myname UNUSED) +{ + schar tmp; + char *rstr; + + rstr = get_savefield(nhfp, linebuf, BUFSZ); + tmp = (schar) atoi(rstr); +#ifdef SAVEFILE_DEBUGGING + if (nhfp->structlevel && tmp != *d_schar) + report_problem_ascii(nhfp, myparent, myname, parent); + else +#endif + *d_schar = tmp; + d_schar++; +} + +void +exportascii_sfi_int16(NHFILE *nhfp, short *d_short, const char *myname UNUSED) +{ + short tmp; + char *rstr; + + rstr = get_savefield(nhfp, linebuf, BUFSZ); + tmp = (short) atoi(rstr); +#ifdef SAVEFILE_DEBUGGING + if (nhfp->structlevel && tmp != *d_short) + report_problem_ascii(nhfp, myparent, myname, parent); + else +#endif + *d_short = tmp; + d_short++; +} + +void +exportascii_sfi_int64(NHFILE *nhfp, int64 *d_int64, const char *myname UNUSED) +{ + int64 tmp; + char *rstr; + + rstr = get_savefield(nhfp, linebuf, BUFSZ); + tmp = (int64) atol(rstr); +#ifdef SAVEFILE_DEBUGGING + if (nhfp->structlevel && tmp != *d_int64) + report_problem_ascii(nhfp, myparent, myname, parent); + else +#endif + *d_int64 = tmp; + d_int64++; +} +void +exportascii_sfi_size_t(NHFILE *nhfp, size_t *d_size_t, const char *myname UNUSED) +{ + size_t tmp; + char *rstr; + + rstr = get_savefield(nhfp, linebuf, BUFSZ); + tmp = (size_t) atol(rstr); +#ifdef SAVEFILE_DEBUGGING + if (nhfp->structlevel && tmp != *d_size_t) + report_problem_ascii(nhfp, myparent, myname, parent); + else +#endif + *d_size_t = tmp; + d_size_t++; +} + +void +exportascii_sfi_time_t(NHFILE *nhfp, time_t *d_time_t, const char *myname UNUSED) +{ + time_t tmp; + char *rstr; + + rstr = get_savefield(nhfp, linebuf, BUFSZ); + tmp = time_from_yyyymmddhhmmss(rstr); +#ifdef SAVEFILE_DEBUGGING + if (nhfp->structlevel && tmp != *d_time_t) + report_problem_ascii(nhfp, myparent, myname, parent); + else +#endif + *d_time_t = tmp; + d_time_t++; +} + +#if 0 +void +exportascii_sfi_uint32(NHFILE *nhfp, unsigned *d_unsigned, const char *myname) +{ + /* deferal */ + exportascii_sfi_uint(nhfp, d_unsigned, myname); +} +#endif + +void +exportascii_sfi_uchar(NHFILE *nhfp, unsigned char *d_uchar, const char *myname UNUSED) +{ + uchar tmp; + int itmp; + char *rstr; + + rstr = get_savefield(nhfp, linebuf, BUFSZ); + itmp = atoi(rstr); + tmp = (char ) itmp; +#ifdef SAVEFILE_DEBUGGING + if (nhfp->structlevel && tmp != *d_uchar) + report_problem_ascii(nhfp, myparent, myname, parent); + else +#endif + *d_uchar = tmp; + d_uchar++; +} + +void +exportascii_sfi_uint16(NHFILE *nhfp, uint16 *d_uint16, const char *myname UNUSED) +{ + char *rstr; + unsigned int tmp; + long long lltmp; + + rstr = get_savefield(nhfp, linebuf, BUFSZ); + lltmp = atoll(rstr); + tmp = (unsigned int) lltmp; +#ifdef SAVEFILE_DEBUGGING + if (nhfp->structlevel && tmp != *d_uint) + report_problem_ascii(nhfp, myparent, myname, parent); + else +#endif + *d_uint16 = tmp; + d_uint16++; +} + +void +exportascii_sfi_uint32(NHFILE *nhfp, uint32 *d_uint32, const char *myname UNUSED) +{ + char *rstr; + uint32 tmp; + long long lltmp; + + rstr = get_savefield(nhfp, linebuf, BUFSZ); + lltmp = atoll(rstr); + tmp = (uint32) lltmp; +#ifdef SAVEFILE_DEBUGGING + if (nhfp->structlevel && tmp != *d_uint) + report_problem_ascii(nhfp, myparent, myname, parent); + else +#endif + *d_uint32 = tmp; + d_uint32++; +} + +void +exportascii_sfi_uint64(NHFILE *nhfp, uint64 *d_uint64, const char *myname UNUSED) +{ + char *rstr; + uint64 tmp; + long long lltmp; + + rstr = get_savefield(nhfp, linebuf, BUFSZ); + lltmp = atoll(rstr); + tmp = (uint64) lltmp; +#ifdef SAVEFILE_DEBUGGING + if (nhfp->structlevel && tmp != *d_uint) + report_problem_ascii(nhfp, myparent, myname, parent); + else +#endif + *d_uint64 = tmp; + d_uint64++; +} + +void +exportascii_sfi_unsigned(NHFILE *nhfp, unsigned *d_unsigned, const char *myname UNUSED) +{ + char *rstr; + uint32 tmp; + long long lltmp; + + rstr = get_savefield(nhfp, linebuf, BUFSZ); + lltmp = atoll(rstr); + tmp = (uint32) lltmp; +#ifdef SAVEFILE_DEBUGGING + if (nhfp->structlevel && tmp != *d_unsigned) + report_problem_ascii(nhfp, "", myname, parent); + else +#endif + *d_unsigned = tmp; + d_unsigned++; +} + +void +exportascii_sfi_ulong(NHFILE *nhfp, unsigned long *d_ulong, const char *myname UNUSED) +{ + unsigned long tmp; + long long lltmp; + char *rstr; + + rstr = get_savefield(nhfp, linebuf, BUFSZ); + lltmp = atoll(rstr); + tmp = (unsigned long) lltmp; +#ifdef SAVEFILE_DEBUGGING + if (nhfp->structlevel && tmp != *d_ulong) + report_problem_ascii(nhfp, myparent, myname, parent); + else +#endif + *d_ulong = tmp; + d_ulong++; +} + +void +exportascii_sfi_ushort(NHFILE *nhfp, unsigned short *d_ushort, const char *myname UNUSED) +{ + short tmp; + long long lltmp; + char *rstr; + + rstr = get_savefield(nhfp, linebuf, BUFSZ); + lltmp = atoll(rstr); + tmp = (unsigned short) lltmp; +#ifdef SAVEFILE_DEBUGGING + if (nhfp->structlevel && tmp != *d_ushort) + report_problem_ascii(nhfp, myparent, myname, parent); + else +#endif + *d_ushort = tmp; + d_ushort++; +} + +void +exportascii_sfi_coordxy(NHFILE *nhfp, coordxy *d_coordxy, const char *myname UNUSED) +{ + coordxy tmp; + int itmp; + char *rstr; + + rstr = get_savefield(nhfp, linebuf, BUFSZ); + itmp = atoi(rstr); + tmp = (coordxy) itmp; +#ifdef SAVEFILE_DEBUGGING + if (nhfp->structlevel && tmp != *d_coordxy) + report_problem_ascii(nhfp, myparent, myname, parent); + else +#endif + *d_coordxy = tmp; + d_coordxy++; +} + +void +exportascii_sfi_xint8(NHFILE *nhfp, xint8 *d_xint8, const char *myname UNUSED) +{ + xint8 tmp; + int itmp; + char *rstr; + + rstr = get_savefield(nhfp, linebuf, BUFSZ); + if (!nhfp->eof) { + itmp = atoi(rstr); + tmp = (xint8) itmp; + } else { + return; + } +#ifdef SAVEFILE_DEBUGGING + if (nhfp->structlevel && tmp != *d_xint8) + report_problem_ascii(nhfp, myparent, myname, parent); + else +#endif + *d_xint8 = tmp; + d_xint8++; +} + +void +exportascii_sfi_xint16(NHFILE *nhfp, xint16 *d_xint16, const char *myname UNUSED) +{ + xint16 tmp; + int itmp; + char *rstr; + + rstr = get_savefield(nhfp, linebuf, BUFSZ); + itmp = atoi(rstr); + tmp = (xint16) itmp; +#ifdef SAVEFILE_DEBUGGING + if (nhfp->structlevel && tmp != *d_xint16) + report_problem_ascii(nhfp, myparent, myname, parent); + else +#endif + *d_xint16 = tmp; + d_xint16++; +} + +void +exportascii_sfi_short(NHFILE *nhfp, short *d_short, const char *myname UNUSED) +{ + xint16 tmp; + int itmp; + char *rstr; + + rstr = get_savefield(nhfp, linebuf, BUFSZ); + itmp = atoi(rstr); + tmp = (xint16) itmp; +#ifdef SAVEFILE_DEBUGGING + if (nhfp->structlevel && tmp != *d_short) + report_problem_ascii(nhfp, "", myname, parent); + else +#endif + *d_short = tmp; + d_short++; +} + + +void +exportascii_sfi_char(NHFILE *nhfp, char *d_char, const char *myname UNUSED, int cnt) +{ + int i, j, sval; + char n[4], *rstr; + char *src, *dest; + + /* cnt is the length of the string */ + rstr = get_savefield(nhfp, strbuf, sizeof strbuf); + if (!rstr) { + nhfp->eof = TRUE; + return; + } + src = rstr; + dest = +#ifdef SAVEFILE_DEBUGGING + testbuf; +#else + d_char; +#endif + + for (i = 0; i < cnt; ++i) { + if (*src == '\\') { + src++; + for (j = 0; j < 4; ++j) { + if (j < 3) + n[j] = *src++; + else + n[j] = '\0'; + } + sval = atoi(n); + *dest++ = (char) sval; + } else + *dest++ = *src++; + } +#ifdef SAVEFILE_DEBUGGING + if (nhfp->structlevel) { + src = testbuf; + dest = d_char; + match = TRUE; + for (i = 0; i < cnt; ++i) { + if (*src++ != *dest++) + match = FALSE; + } + if (!match) + report_problem_ascii(nhfp, myparent, myname, parent); + else { + src = testbuf; + dest = d_char; + for (i = 0; i < cnt; ++i) + *dest++ = *src++; + } + } +#endif +} + +char * +get_savefield(NHFILE *nhfp, char *inbuf, size_t inbufsz) +{ + char *ep, *sep; + char *res = 0; + + if ((res =fgets(inbuf, (int) inbufsz, nhfp->fpdef)) != 0) { + nhfp->rcount++; + ep = strchr(inbuf, '\n'); + if (!ep) { /* newline missing */ + if (strlen(inbuf) < (inbufsz - 2)) { + /* likely the last line of file is just + missing a newline; process it anyway */ + ep = eos(inbuf); + } + } + if (ep) + *ep = '\0'; /* remove newline */ + sep = strchr(inbuf, '|'); + if (sep) + sep++; + + return sep; + } + inbuf[0] = '\0'; + nhfp->eof = TRUE; + return inbuf; +} + +#ifdef SAVEFILE_DEBUGGING +void +report_problem_ascii(NHFILE *nhfp, const char *s1, const char *s2, const char *s3) +{ + fprintf(nhfp->fpdebug, "faulty value preservation " + "(%ld, %s, %s, %s)\n", + ((nhfp->mode & READING) != 0) ? nhfp->rcount : nhfp->wcount, s1, s2, s3); +} +#endif + +int exportascii_critical_members_count(void); + +int +exportascii_critical_members_count(void) +{ + return 0; +} + +struct sf_fieldlevel_procs exportascii_sfo_procs = { + "exportascii", + /* sf_x */ + { + sfo_x_arti_info, + sfo_x_nhrect, + sfo_x_branch, + sfo_x_bubble, + sfo_x_cemetery, + sfo_x_context_info, + sfo_x_nhcoord, + sfo_x_damage, + sfo_x_dest_area, + sfo_x_dgn_topology, + sfo_x_dungeon, + sfo_x_d_level, + sfo_x_ebones, + sfo_x_edog, + sfo_x_egd, + sfo_x_emin, + sfo_x_engr, + sfo_x_epri, + sfo_x_eshk, + sfo_x_fe, + sfo_x_flag, + sfo_x_fruit, + sfo_x_gamelog_line, + sfo_x_kinfo, + sfo_x_levelflags, + sfo_x_ls_t, + sfo_x_linfo, + sfo_x_mapseen_feat, + sfo_x_mapseen_flags, + sfo_x_mapseen_rooms, + sfo_x_mkroom, + sfo_x_monst, + sfo_x_mvitals, + sfo_x_obj, + sfo_x_objclass, + sfo_x_q_score, + sfo_x_rm, + sfo_x_spell, + sfo_x_stairway, + sfo_x_s_level, + sfo_x_trap, + sfo_x_version_info, + sfo_x_you, + + exportascii_sfo_any, + exportascii_sfo_aligntyp, + exportascii_sfo_boolean, + exportascii_sfo_coordxy, + exportascii_sfo_genericptr, + exportascii_sfo_int, + exportascii_sfo_int16, + exportascii_sfo_int32, + exportascii_sfo_int64, + exportascii_sfo_long, + exportascii_sfo_schar, + exportascii_sfo_short, + exportascii_sfo_size_t, + exportascii_sfo_time_t, + exportascii_sfo_uchar, + exportascii_sfo_uint16, + exportascii_sfo_uint32, + exportascii_sfo_uint64, + exportascii_sfo_ulong, + exportascii_sfo_unsigned, + exportascii_sfo_ushort, + exportascii_sfo_xint16, + exportascii_sfo_xint8, + exportascii_sfo_char, + exportascii_sfo_bitfield, + } +}; + +struct sf_fieldlevel_procs exportascii_sfi_procs = { + "le", + /* sf_x */ + { + sfi_x_arti_info, + sfi_x_nhrect, + sfi_x_branch, + sfi_x_bubble, + sfi_x_cemetery, + sfi_x_context_info, + sfi_x_nhcoord, + sfi_x_damage, + sfi_x_dest_area, + sfi_x_dgn_topology, + sfi_x_dungeon, + sfi_x_d_level, + sfi_x_ebones, + sfi_x_edog, + sfi_x_egd, + sfi_x_emin, + sfi_x_engr, + sfi_x_epri, + sfi_x_eshk, + sfi_x_fe, + sfi_x_flag, + sfi_x_fruit, + sfi_x_gamelog_line, + sfi_x_kinfo, + sfi_x_levelflags, + sfi_x_ls_t, + sfi_x_linfo, + sfi_x_mapseen_feat, + sfi_x_mapseen_flags, + sfi_x_mapseen_rooms, + sfi_x_mkroom, + sfi_x_monst, + sfi_x_mvitals, + sfi_x_obj, + sfi_x_objclass, + sfi_x_q_score, + sfi_x_rm, + sfi_x_spell, + sfi_x_stairway, + sfi_x_s_level, + sfi_x_trap, + sfi_x_version_info, + sfi_x_you, + + exportascii_sfi_any, + exportascii_sfi_aligntyp, + exportascii_sfi_boolean, + exportascii_sfi_coordxy, + exportascii_sfi_genericptr, + exportascii_sfi_int, + exportascii_sfi_int16, + exportascii_sfi_int32, + exportascii_sfi_int64, + exportascii_sfi_long, + exportascii_sfi_schar, + exportascii_sfi_short, + exportascii_sfi_size_t, + exportascii_sfi_time_t, + exportascii_sfi_uchar, + exportascii_sfi_uint16, + exportascii_sfi_uint32, + exportascii_sfi_uint64, + exportascii_sfi_ulong, + exportascii_sfi_unsigned, + exportascii_sfi_ushort, + exportascii_sfi_xint16, + exportascii_sfi_xint8, + exportascii_sfi_char, + exportascii_sfi_bitfield, + } +}; diff --git a/util/sftags.c b/util/sftags.c new file mode 100644 index 000000000..cdb8f3a7a --- /dev/null +++ b/util/sftags.c @@ -0,0 +1,2230 @@ +/* NetHack 3.6 sftags.c $Date$ $Revision$ */ +/* Copyright (c) Michael Allison, 2025 */ +/* NetHack may be freely redistributed. See license for details. */ + +/* + * Read the given ctags file and generate: + * Intermediate temp files: + * include/sfo_proto.tmp + * include/sfi_proto.tmp + * util/sfi_data.tmp + * util/sfo_data.tmp + * util/sfnormalize.tmp + * Final files: + * sfdata.c + * sfproto.h + * + */ + +/* avoid global.h define */ +#define STRNCMPI + +#include "hack.h" +#include "integer.h" +#include "wintype.h" + +#ifdef __GNUC__ +#include +#define strncmpi strncasecmp +#define strcmpi strcasecmp +#elif defined(_MSC_VER) +#define strcmpi _stricmp +#ifndef strncmpi +#define strncmpi _strnicmp +#endif +#endif + +#if 0 +/* version information */ +#ifdef SHORT_FILENAMES +#include "patchlev.h" +#else +#include "patchlevel.h" +#endif +#endif + +#define NHTYPE_SIMPLE 1 +#define NHTYPE_COMPLEX 2 +struct nhdatatypes_t { + uint dtclass; + char *dtype; + size_t dtsize; +}; + +struct tagstruct { + uint marker; + int linenum; + char ptr[128]; + char tag[100]; + char filename[128]; + char searchtext[255]; + char tagtype; + char parent[100]; + char parenttype[100]; + char arraysize1[100]; + char arraysize2[100]; + struct tagstruct *next; +}; + +struct needs_array_handling { + const char *nm; + const char *parent; +}; + +#define SFO_DATA c_sfodata +#define SFI_DATA c_sfidata +#define SFDATATMP c_sfdatatmp +#define SFO_PROTO c_sfoproto +#define SFI_PROTO c_sfiproto +#define SFDATA c_sfdata +#define SFPROTO c_sfproto +#define SF_NORMALIZE_POINTERS c_sfnormalize +#define SFPROTO_NAME "../include/sfproto.h" +#define SFDATA_NAME "../util/sfdata.c" + +static char *fgetline(FILE*); +static void quit(void); +static void out_of_memory(void); +static void doline(char *); +static void chain(struct tagstruct *); +#if 0 +static void showthem(void); +static char *stripspecial(char *); +#endif +static char *deblank(char *); +static char *deeol(char *); +static void generate_c_files(void); +static char *findtype(char *, char *); +#if 0 +static boolean is_prim(char *); +#endif +static void taglineparse(char *, struct tagstruct *); +static void parseExtensionFields(struct tagstruct *, char *); +static void set_member_array_size(struct tagstruct *); +#if 0 +static char *member_array_dims(struct tagstruct *, char *); +static char *member_array_size(struct tagstruct *, char *); +#endif +static void output_types(FILE *); +#if 0 +static char *dtmacro(const char *,int); +#endif +static char *dtfn(const char *,int, boolean *); +static char *bfsize(const char *); +static char *fieldfix(char *,char *); +static boolean listed(struct tagstruct *t); +static const char *fn(const char *f); +static boolean no_x(const char *s); + +#ifdef VMS +static FILE *vms_fopen(name, mode) const char *name, *mode; +{ + return fopen(name, mode, "mbc=64", "shr=nil"); +} +# define fopen(f,m) vms_fopen(f,m) +#endif + +#define Fprintf (void) fprintf +#ifndef __GO32__ +#define DEFAULTTAGNAME "../util/sf.tags" +#else +#define DEFAULTTAGNAME "../util/sftags.tag" +#endif +#ifndef _MAX_PATH +#define _MAX_PATH 120 +#endif + +#define TAB '\t' +#define SPACE ' ' + +struct tagstruct *first; +struct tagstruct zerotag = { 0 }; + +static int tagcount; +static const char *infilenm; +static FILE *infile; +static char line[2048]; +static long lineno; +static char ssdef[BUFSZ]; +static char fieldfixbuf[BUFSZ]; +static boolean suppress_count; + +#define NHTYPE_SIMPLE 1 +#define NHTYPE_COMPLEX 2 + +struct nhdatatypes_t readtagstypes[] = { + { NHTYPE_SIMPLE, (char *) "any", sizeof(anything) }, + { NHTYPE_SIMPLE, (char *) "genericptr_t", sizeof(genericptr_t) }, + { NHTYPE_SIMPLE, (char *) "aligntyp", sizeof(aligntyp) }, + { NHTYPE_SIMPLE, (char *) "Bitfield", sizeof(uint8_t) }, + { NHTYPE_SIMPLE, (char *) "boolean", sizeof(boolean) }, + { NHTYPE_SIMPLE, (char *) "char", sizeof(char) }, + { NHTYPE_SIMPLE, (char *) "int", sizeof(int) }, + { NHTYPE_SIMPLE, (char *) "long", sizeof(long) }, + { NHTYPE_SIMPLE, (char *) "schar", sizeof(schar) }, + { NHTYPE_SIMPLE, (char *) "short", sizeof(short) }, + { NHTYPE_SIMPLE, (char *) "size_t", sizeof(size_t) }, + { NHTYPE_SIMPLE, (char *) "string", 1 }, + { NHTYPE_SIMPLE, (char *) "time_t", sizeof(time_t) }, + { NHTYPE_SIMPLE, (char *) "uchar", sizeof(uchar) }, + { NHTYPE_SIMPLE, (char *) "unsigned char", sizeof(unsigned char) }, + { NHTYPE_SIMPLE, (char *) "uint", sizeof(uint) }, + { NHTYPE_SIMPLE, (char *) "unsigned long", sizeof(unsigned long) }, + { NHTYPE_SIMPLE, (char *) "unsigned short", sizeof(unsigned short) }, + { NHTYPE_SIMPLE, (char *) "unsigned", sizeof(unsigned) }, + { NHTYPE_SIMPLE, (char *) "xint8", sizeof(xint8) }, + { NHTYPE_SIMPLE, (char *) "xint16", sizeof(xint16) }, + { NHTYPE_SIMPLE, (char *) "coordxy", sizeof(coordxy) }, + { NHTYPE_COMPLEX, (char *) "align", sizeof(struct align) }, + /* { NHTYPE_COMPLEX, (char *) "attack", sizeof(struct attack) }, */ + /* ^ permonst affil */ + { NHTYPE_COMPLEX, (char *) "arti_info", sizeof(struct arti_info) }, + { NHTYPE_COMPLEX, (char *) "attribs", sizeof(struct attribs) }, + { NHTYPE_COMPLEX, (char *) "bill_x", sizeof(struct bill_x) }, + { NHTYPE_COMPLEX, (char *) "branch", sizeof(struct branch) }, + { NHTYPE_COMPLEX, (char *) "bubble", sizeof(struct bubble) }, + { NHTYPE_COMPLEX, (char *) "cemetery", sizeof(struct cemetery) }, + /*{ NHTYPE_COMPLEX, (char *) "container", sizeof(struct container) }, */ + { NHTYPE_COMPLEX, (char *) "context_info", sizeof(struct context_info) }, + /* context sub-structures */ + { NHTYPE_COMPLEX, (char *) "achievement_tracking", + sizeof(struct achievement_tracking) }, + { NHTYPE_COMPLEX, (char *) "book_info", sizeof(struct book_info) }, + { NHTYPE_COMPLEX, (char *) "dig_info", + sizeof(struct dig_info) }, /* context */ + { NHTYPE_COMPLEX, (char *) "engrave_info", sizeof(struct engrave_info) }, + { NHTYPE_COMPLEX, (char *) "obj_split", sizeof(struct obj_split) }, + { NHTYPE_COMPLEX, (char *) "polearm_info", sizeof(struct polearm_info) }, + { NHTYPE_COMPLEX, (char *) "takeoff_info", sizeof(struct takeoff_info) }, + { NHTYPE_COMPLEX, (char *) "tin_info", sizeof(struct tin_info) }, + { NHTYPE_COMPLEX, (char *) "tribute_info", sizeof(struct tribute_info) }, + { NHTYPE_COMPLEX, (char *) "victual_info", sizeof(struct victual_info) }, + { NHTYPE_COMPLEX, (char *) "warntype_info", + sizeof(struct warntype_info) }, + /* end of context sub-structures */ + { NHTYPE_COMPLEX, (char *) "d_flags", sizeof(struct d_flags) }, + { NHTYPE_COMPLEX, (char *) "d_level", sizeof(struct d_level) }, + { NHTYPE_COMPLEX, (char *) "damage", sizeof(struct damage) }, + { NHTYPE_COMPLEX, (char *) "dest_area", sizeof(struct dest_area) }, + { NHTYPE_COMPLEX, (char *) "dgn_topology", sizeof(struct dgn_topology) }, + { NHTYPE_COMPLEX, (char *) "dungeon", sizeof(struct dungeon) }, + { NHTYPE_COMPLEX, (char *) "ebones", sizeof(struct ebones) }, + { NHTYPE_COMPLEX, (char *) "edog", sizeof(struct edog) }, + { NHTYPE_COMPLEX, (char *) "egd", sizeof(struct egd) }, + { NHTYPE_COMPLEX, (char *) "emin", sizeof(struct emin) }, + { NHTYPE_COMPLEX, (char *) "engr", sizeof(struct engr) }, + { NHTYPE_COMPLEX, (char *) "epri", sizeof(struct epri) }, + { NHTYPE_COMPLEX, (char *) "eshk", sizeof(struct eshk) }, + { NHTYPE_COMPLEX, (char *) "fakecorridor", sizeof(struct fakecorridor) }, + { NHTYPE_COMPLEX, (char *) "fe", sizeof(struct fe) }, + { NHTYPE_COMPLEX, (char *) "flag", sizeof(struct flag) }, + { NHTYPE_COMPLEX, (char *) "fruit", sizeof(struct fruit) }, + { NHTYPE_COMPLEX, (char *) "gamelog_line", sizeof(struct gamelog_line) }, + { NHTYPE_COMPLEX, (char *) "kinfo", sizeof(struct kinfo) }, + { NHTYPE_COMPLEX, (char *) "levelflags", sizeof(struct levelflags) }, + { NHTYPE_COMPLEX, (char *) "linfo", sizeof(struct linfo) }, + { NHTYPE_COMPLEX, (char *) "ls_t", sizeof(struct ls_t) }, + { NHTYPE_COMPLEX, (char *) "mapseen_feat", sizeof(struct mapseen_feat) }, + { NHTYPE_COMPLEX, (char *) "mapseen_flags", + sizeof(struct mapseen_flags) }, + { NHTYPE_COMPLEX, (char *) "mapseen_rooms", + sizeof(struct mapseen_rooms) }, + { NHTYPE_COMPLEX, (char *) "mapseen", sizeof(mapseen) }, + { NHTYPE_COMPLEX, (char *) "mextra", sizeof(struct mextra) }, + { NHTYPE_COMPLEX, (char *) "mkroom", sizeof(struct mkroom) }, + { NHTYPE_COMPLEX, (char *) "monst", sizeof(struct monst) }, + { NHTYPE_COMPLEX, (char *) "mvitals", sizeof(struct mvitals) }, + { NHTYPE_COMPLEX, (char *) "nhcoord", sizeof(struct nhcoord) }, + { NHTYPE_COMPLEX, (char *) "nhrect", sizeof(struct nhrect) }, + { NHTYPE_COMPLEX, (char *) "novel_tracking", + sizeof(struct novel_tracking) }, + { NHTYPE_COMPLEX, (char *) "obj", sizeof(struct obj) }, + { NHTYPE_COMPLEX, (char *) "objclass", sizeof(struct objclass) }, + { NHTYPE_COMPLEX, (char *) "oextra", sizeof(struct oextra) }, + /* {NHTYPE_COMPLEX, (char *) "permonst", sizeof(struct permonst)}, */ + { NHTYPE_COMPLEX, (char *) "prop", sizeof(struct prop) }, + { NHTYPE_COMPLEX, (char *) "q_score", sizeof(struct q_score) }, + { NHTYPE_COMPLEX, (char *) "rm", sizeof(struct rm) }, + { NHTYPE_COMPLEX, (char *) "s_level", sizeof(struct s_level) }, + { NHTYPE_COMPLEX, (char *) "skills", sizeof(struct skills) }, + { NHTYPE_COMPLEX, (char *) "spell", sizeof(struct spell) }, + { NHTYPE_COMPLEX, (char *) "stairway", sizeof(struct stairway) }, +#ifdef SYSFLAGS + { NHTYPE_COMPLEX, (char *) "sysflag", sizeof(struct sysflag) }, +#endif + { NHTYPE_COMPLEX, (char *) "trap", sizeof(struct trap) }, + /* {NHTYPE_COMPLEX, (char *) "u_achieve", sizeof(struct u_achieve)}, */ + { NHTYPE_COMPLEX, (char *) "u_conduct", sizeof(struct u_conduct) }, + { NHTYPE_COMPLEX, (char *) "u_event", sizeof(struct u_event) }, + { NHTYPE_COMPLEX, (char *) "u_have", sizeof(struct u_have) }, + { NHTYPE_COMPLEX, (char *) "u_realtime", sizeof(struct u_realtime) }, + { NHTYPE_COMPLEX, (char *) "u_roleplay", sizeof(struct u_roleplay) }, + { NHTYPE_COMPLEX, (char *) "version_info", sizeof(struct version_info) }, + { NHTYPE_COMPLEX, (char *) "vlaunchinfo", sizeof(union vlaunchinfo) }, + { NHTYPE_COMPLEX, (char *) "vptrs", sizeof(union vptrs) }, + { NHTYPE_COMPLEX, (char *) "you", sizeof(struct you) } + +}; + + +/* + * These have arrays of other structs, not just arrays of + * simple types. We need to put array handling right into + * the code for these ones. + */ +struct needs_array_handling nah[] = { + {"fakecorr", (char *) "egd"}, + {"bill", "eshk"}, + {"msrooms", "mapseen"}, + {"mtrack", "monst"}, + {"ualignbase", "you"}, + {"weapon_skills", "you"}, +}; + +/* conditional code tags - eecch */ +const char *condtag[] = { +#ifdef SYSFLAGS + "sysflag","altmeta","#ifdef AMIFLUSH", "", + "sysflag","amiflush","","#endif /*AMIFLUSH*/", + "sysflag","numcols", "#ifdef AMII_GRAPHICS", "", + "sysflag","amii_dripens","","", + "sysflag","amii_curmap","","#endif", + "sysflag","fast_map", "#ifdef OPT_DISMAP", "#endif", + "sysflag","asksavedisk","#ifdef MFLOPPY","#endif", + "sysflag","page_wait", "#ifdef MAC", "#endif", +#endif + "linfo","where","#ifdef MFLOPPY","", + "linfo","time","","", + "linfo","size","","#endif /*MFLOPPY*/", + "obj","oinvis","#ifdef INVISIBLE_OBJECTS", "#endif", + (char *)0,(char *)0,(char *)0, (char *)0 +}; + +DISABLE_WARNING_UNREACHABLE_CODE + +int main(int argc, char *argv[]) +{ + tagcount = 0; + + if (argc > 1) infilenm = argv[1]; + if (!infilenm || !*infilenm) infilenm = DEFAULTTAGNAME; + + infile = fopen(infilenm,"r"); + if (!infile) { + printf("%s not found or unavailable\n",infilenm); + quit(); + } else { + while (fgets(line, sizeof line, infile)) { + ++lineno; + /* if (lineno == 868) DebugBreak(); */ + doline(line); + } + + fclose(infile); + printf("\nRead in %ld lines and stored %d tags in memory.\n", lineno, + tagcount); +#if 0 + showthem(); +#endif + generate_c_files(); + printf("Created %s\n", SFDATA_NAME); + printf("Created %s\n", SFPROTO_NAME); + exit(EXIT_SUCCESS); + /*NOTREACHED*/ + return 0; + } +} + +RESTORE_WARNINGS + +static void doline(char *aline) +{ + char buf[255]; + struct tagstruct *tmptag; + + if (!aline || (aline && *aline == '!')) { + return; + } + tmptag = malloc(sizeof(struct tagstruct)); + + if (!tmptag) { + out_of_memory(); + } + assert(tmptag != 0); + *tmptag = zerotag; + tmptag->marker = 0xDEADBEEF; + + strncpy(buf, deeol(aline), sizeof buf - 1); + taglineparse(buf, tmptag); + chain(tmptag); + return; +} + +static struct tagstruct *prevtag = (struct tagstruct *) 0; + +static void chain(struct tagstruct *tag) +{ + + if (!first) { + tag->next = (struct tagstruct *)0; + first = tag; + } else { + tag->next = (struct tagstruct *)0; + if (prevtag) { + if (prevtag->marker == 0xDEADBEEF) { + prevtag->next = tag; + } else { + printf("Possible corruption."); + quit(); + } + } else { + printf("Error - No previous tag at %s\n", tag->tag); + } + } + prevtag = tag; + ++tagcount; +} +static void quit(void) +{ + exit(EXIT_FAILURE); +} + +static void out_of_memory(void) +{ + printf("maketags: out of memory at line %ld of %s\n", + lineno, infilenm); + quit(); +} + +#if 0 +static char empt[] = {0, 0, 0, 0, 0, 0, 0, 0}; +#endif + +#if 0 +static char *member_array_dims(struct tagstruct *tmptag, char *buf) +{ + if (buf && tmptag) { + if (tmptag->arraysize1[0]) + Sprintf(buf, "[%s]", tmptag->arraysize1); + if (tmptag->arraysize2[0]) + Sprintf(eos(buf), "[%s]", tmptag->arraysize2); + return buf; + } + return empt; +} + +static char *member_array_size(struct tagstruct *tmptag, char *buf) +{ + if (buf && tmptag) { + if (tmptag->arraysize1[0]) + strcpy(buf, tmptag->arraysize1); + if (tmptag->arraysize2[0]) + Sprintf(eos(buf), " * %s", tmptag->arraysize2); + return buf; + } + return empt; +} +#endif + +void set_member_array_size(struct tagstruct *tmptag) +{ + char buf[BUFSZ]; + /* static char result[49]; */ + char *arr1 = (char *)0, *arr2 = (char *)0, *tmp; + int cnt = 0; + + if (!tmptag) return; + strcpy(buf, tmptag->searchtext); + + tmptag->arraysize1[0] = '\0'; + tmptag->arraysize2[0] = '\0'; + + /* find left-open square bracket */ + tmp = strchr(buf, '['); + if (tmp) { + arr1 = tmp; + *tmp = '\0'; + --tmp; + /* backup and make sure the [] are on the right tag */ + while (!(*tmp == SPACE || *tmp == TAB || *tmp ==',' || cnt > 50)) { + --tmp; + cnt++; + } + if (cnt > 50) return; + tmp++; + if (strcmp(tmp, tmptag->tag) == 0) { + ++arr1; + tmp = strchr(arr1, ']'); + if (tmp) { + arr2 = tmp; + ++arr2; + *tmp = '\0'; + if (*arr2 == '[') { /* two-dimensional array */ + ++arr2; + tmp = strchr(arr2, ']'); + if (tmp) *tmp = '\0'; + } else { + arr2 = (char *)0; + } + } + } else { + arr1 = (char *)0; + } + } + if (arr1) (void)strcpy(tmptag->arraysize1, arr1); + if (arr2) (void)strcpy(tmptag->arraysize2, arr2); +} + +static void parseExtensionFields (struct tagstruct *tmptag, char *buf) +{ + char *p = buf; + while (p != (char *)0 && *p != '\0') { + while (*p == TAB) + *p++ = '\0'; + if (*p != '\0') { + char *colon; + char *field = p; + + p = strchr (p, TAB); + if (p != (char *)0) + *p++ = '\0'; + colon = strchr (field, ':'); + if (colon == (char *)0) { + tmptag->tagtype = *field; + } else { + const char *key = field; + const char *value = colon + 1; + *colon = '\0'; + if ((strcmp (key, "struct") == 0) || + (strcmp (key, "union") == 0)) { + colon = strstr(value,"::"); + if (colon) + value = colon +2; + strcpy(tmptag->parenttype, key); + strcpy(tmptag->parent, value); + } + } + } + } +} + +void +taglineparse(char *p, struct tagstruct *tmptag) +{ + int fieldsPresent = 0; + char *pattern = 0, *tmp1 = 0; + int linenumber = 0; + char *tab = strchr (p, TAB); + + if (tab != NULL) { + *tab = '\0'; + strcpy(tmptag->tag,p); + p = tab + 1; + tab = strchr (p, TAB); + if (tab != NULL) { + *tab = '\0'; + p = tab + 1; + if (*p == '/' || *p == '?') { + /* parse pattern */ + int delimiter = *(unsigned char *) p; + linenumber = 0; + pattern = p; + do { + p = strchr (p + 1, delimiter); + } while (p != (char *)0 && *(p - 1) == '\\'); + + if (p == (char *)0) { + /* invalid pattern */ + } else + ++p; + } else if (isdigit ((int) *(unsigned char *) p)) { + /* parse line number */ + pattern = p; + linenumber = atol(p); + while (isdigit((int) *(unsigned char *) p)) + ++p; + } else { + /* invalid pattern */ + } + fieldsPresent = (strncmp (p, ";\"", 2) == 0); + *p = '\0'; + + if (fieldsPresent) + parseExtensionFields (tmptag, p + 2); + } + } + assert(pattern != NULL); + + strcpy(tmptag->searchtext, pattern); + tmptag->linenum = linenumber; + + /* add the array dimensions */ + set_member_array_size(tmptag); + + /* determine if this is a pointer and mark it as such */ + if (tmptag->searchtext[0] && + (tmptag->tagtype == 'm' || tmptag->tagtype == 's')) { + char ptrbuf[BUFSZ], searchbuf[BUFSZ]; + + (void) strcpy(ptrbuf, tmptag->searchtext); + Sprintf(searchbuf,"*%s", tmptag->tag); + tmp1 = strstr(ptrbuf, searchbuf); + if (!tmp1) { + Sprintf(searchbuf,"* %s", tmptag->tag); + tmp1 = strstr(ptrbuf, searchbuf); + } + if (tmp1) { + while ((tmp1 > ptrbuf) && (*tmp1 != SPACE) && + (*tmp1 != TAB) && (*tmp1 != ',')) + tmp1--; + tmp1++; + while (*tmp1 == '*') + tmp1++; + *tmp1 = '\0'; + /* now find the first * before this in case multiple things + are declared on this line */ + tmp1 = strchr(ptrbuf+2, '*'); + if (tmp1) { + tmp1++; + *tmp1 = '\0'; + tmp1 = ptrbuf + 2; + while (*tmp1 == SPACE || *tmp1 == TAB || *tmp1 == ',') + ++tmp1; + (void)strcpy(tmptag->ptr, tmp1); + } + } + } +} + +/* eos() is copied from hacklib.c */ +/* return the end of a string (pointing at '\0') */ +char * +eos(char *s) +{ + while (*s) s++; /* s += strlen(s); */ + return s; +} + +static char stripbuf[255]; + +#if 0 +static char *stripspecial(char *st) +{ + char *out = stripbuf; + *out = '\0'; + if (!st) return st; + while(*st) { + if (*st >= SPACE) + *out++ = *st++; + else + st++; + } + *out = '\0'; + return stripbuf; +} +#endif + +static char *deblank(char *st) +{ + char *out = stripbuf; + *out = '\0'; + if (!st) return st; + while(*st) { + if (*st == SPACE) { + *out++ = '_'; + st++; + } else + *out++ = *st++; + } + *out = '\0'; + return stripbuf; +} + +static char *deeol(char *st) +{ + char *out = stripbuf; + *out = '\0'; + if (!st) return st; + while(*st) { + if ((*st == '\r') || (*st == '\n')) { + st++; + } else + *out++ = *st++; + } + *out = '\0'; + return stripbuf; +} + +#if 0 +static void showthem(void) +{ + char buf[BUFSZ], *tmp; + struct tagstruct *t = first; + while(t) { + printf("%-28s %c, %-16s %-10s", t->tag, t->tagtype, + t->parent, t->parenttype); +#if 0 + t->parent[0] ? t->searchtext : ""); +#endif + buf[0] = '\0'; + tmp = member_array_dims(t,buf); + if (tmp) printf("%s", tmp); + printf("%s","\n"); + t = t->next; + } +} +#endif + +#if 0 +static boolean +is_prim(char *sdt) +{ + int k = 0; + if (sdt) { + /* special case where we don't match entire thing */ + if (!strncmpi(sdt, "Bitfield",8)) + return TRUE; + for (k = 0; k < SIZE(readtagstypes); ++k) { + if (!strcmpi(readtagstypes[k].dtype, sdt)) { + if (readtagstypes[k].dtclass == NHTYPE_SIMPLE) + return TRUE; + else + return FALSE; + } + } + } + return FALSE; +} +#endif + +char * +findtype(char *st, char *tag) +{ + static char ftbuf[512]; + static char prevbuf[512]; + char *tmp1, *tmp2, *tmp3, *tmp4; + const char *r; + + if (!st) return (char *)0; + + if (st && strstr(st, "mapseen")) { + int xx = 0; + + xx++; + } + if (st[0] == '/' && st[1] == '^') { + tmp2 = tmp3 = tmp4 = (char *)0; + tmp1 = &st[3]; + while (*tmp1) { + if (isspace(*tmp1)) + ; /* skip it */ + else + break; + ++tmp1; + } + if (!strncmp(tmp1, tag, strlen(tag))) { + if(strlen(tag) == 1) { + char *sc = tmp1; + /* Kludge: single char match is too iffy, + check to make sure its a complete + token that we're comparing to. */ + ++sc; + if (!(*sc == '_' || (*sc > 'a' && *sc < 'z') || + (*sc > 'A' && *sc < 'Z') || (*sc > '0' && *sc < '9'))) + return (char *)0; + } else { + return (char *)0; + } + } + if (*tmp1) { + if (!strncmp(tmp1, "Bitfield", 8)) { + strcpy(ftbuf, tmp1); + tmp1 = ftbuf; + tmp3 = strchr(tmp1, ')'); + if (tmp3) { + tmp3++; + *tmp3 = '\0'; + return ftbuf; + } + return (char *)0; + } + } + if (*tmp1) { + int prevchar = 0; + strcpy(ftbuf, tmp1); + tmp1 = ftbuf; + /* find space separating first word with second */ + while (!isspace(*tmp1)) { + prevchar = *tmp1; + ++tmp1; + } + + prevchar = 0; + /* some oddball cases */ + if (prevchar == ',' || prevchar == ';') { + tmp3 = strchr(ftbuf, ','); + tmp2 = strstr(ftbuf, tag); + return prevbuf; + } else { + int chkcnt = 0; + + /* a comma means that more than one thing declared on ine */ + tmp3 = strchr(tmp1, ','); + while (chkcnt < 3 && (tmp2 = strstr(tmp1, tag)) + && (prevchar = *(tmp2 - 1)) + && ((prevchar == '_') + || (prevchar >= 'a' && prevchar <= 'z') + || (prevchar >= 'A' && prevchar <= 'Z') + || (prevchar >= '0' && prevchar <= '9'))) { + tmp1 = tmp2 + 1; + chkcnt++; + } + } + /* make sure we're matching a complete token */ + if (tmp2) { + tmp4 = tmp2 + strlen(tag); + if ((*tmp4 == '_') || (*tmp4 >= 'a' && *tmp4 <= 'z') || + (*tmp4 >= 'A' && *tmp4 <= 'Z') || (*tmp4 >= '0' && *tmp4 <= '9')) + /* jump to next occurence then */ + tmp2 = strstr(tmp4, tag); + } + /* tag w/o comma OR tag found w comma and tag before comma */ + if ((tmp2 && !tmp3) || ((tmp2 && tmp3) && (tmp2 < tmp3))) { + *tmp2 = '\0'; + --tmp2; + while (isspace(*tmp2)) + --tmp2; + tmp2++; + *tmp2 = '\0'; + } + /* comma and no tag OR tag w comma and comma before tag */ + else if ((tmp3 && !tmp2) || ((tmp2 && tmp3) && (tmp3 < tmp2))) { + --tmp3; + if (isspace(*tmp3)) { + while (isspace(*tmp3)) + --tmp3; + } + while (!isspace(*tmp3) && (*tmp3 != '*')) + --tmp3; + while (isspace(*tmp3)) + --tmp3; + tmp3++; + *tmp3 = '\0'; + } + /* comma or semicolon immediately following tag */ + else { + volatile int y = 0; + nhUse(y); + y = 1; + } + if (strncmpi(ftbuf, "struct ", 7) == 0) + r = (const char *) (ftbuf + 7); + else if (strncmpi(ftbuf, "union ", 6) == 0) + r = (const char *) (ftbuf + 6); + /* a couple of kludges follow unfortunately */ + else if (strncmpi(ftbuf, "coord", 5) == 0 + && strncmpi(ftbuf, "coordxy", 7) != 0) + r = "nhcoord"; + else if (strncmpi(ftbuf, "anything", 8) == 0) + r = "any"; + else if (strncmpi(ftbuf, "const char", 10) == 0) + r = "char"; + else + r = (const char *) ftbuf; + strcpy(prevbuf, r); + return prevbuf; + } + } + prevbuf[0] = '\0'; + return (char *)0; +} + +int current_type = 64, gotit = 0; + +boolean +listed(struct tagstruct *t) +{ + int k; + + if ((strncmpi(t->tag, "Bitfield", 8) == 0) || + (strcmpi(t->tag, "string") == 0)) + return TRUE; + for (k = 0; k < SIZE(readtagstypes); ++k) { + if (k == current_type) + gotit = k; + /* This needs to be case-sensitive to avoid generating collision + * between 'align' and 'Align'. + */ + if (strcmp(readtagstypes[k].dtype, t->tag) == 0) + return TRUE; + } + return FALSE; +} + +/* TIME_type: type of the argument to time(); we actually use &(time_t) */ +#if defined(BSD) && !defined(POSIX_TYPES) +#define TIME_type long * +#else +#define TIME_type time_t * +#endif +/* LOCALTIME_type: type of the argument to localtime() */ +#if (defined(ULTRIX) && !(defined(ULTRIX_PROTO) || defined(NHSTDC))) \ + || (defined(BSD) && !defined(POSIX_TYPES)) +#define LOCALTIME_type long * +#else +#define LOCALTIME_type time_t * +#endif + +const char *preamble[] = { + "/* Copyright (c) NetHack Development Team %d. */\n", + "/* NetHack may be freely redistributed. See license for details. */\n\n", + "/* THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE! */\n\n", + "#include \"hack.h\"\n", + "#include \"artifact.h\"\n", + "#include \"func_tab.h\"\n", + "#include \"integer.h\"\n", + "#include \"wintype.h\"\n", + (char *)0 +}; +char crbuf[BUFSZ]; + +DISABLE_WARNING_FORMAT_NONLITERAL + +static const char *get_preamble(int n) +{ + const char *r = preamble[n]; + + if (!n) { + time_t datetime = 0; + struct tm *lt; + + (void) time((TIME_type) &datetime); + lt = localtime((LOCALTIME_type) &datetime); + Sprintf(crbuf, preamble[0], (1900 + lt->tm_year)); + r = crbuf; + } + return r; +} + +RESTORE_WARNING_FORMAT_NONLITERAL + +static void output_types(FILE *fp1) +{ + int k, cnt /*, hcnt = 1 */; + struct tagstruct *t = first; + + Fprintf(fp1, "%s", + "struct nhdatatypes_t nhdatatypes[] = {\n"); + + for (k = 0; k < SIZE(readtagstypes); ++k) { + if (readtagstypes[k].dtclass == NHTYPE_SIMPLE) { + Fprintf(fp1,"\t{NHTYPE_SIMPLE, (char *) \"%s\", sizeof(%s)},\n", + readtagstypes[k].dtype, + (strncmpi(readtagstypes[k].dtype, "Bitfield", 8) == 0) ? + "uint8_t" : + (strcmpi(readtagstypes[k].dtype, "string") == 0) ? + "uchar" : + (strcmpi(readtagstypes[k].dtype, "any") == 0) ? + "anything" : readtagstypes[k].dtype); +/* dtmacro(readtagstypes[k].dtype,0)); */ +#if 0 + Fprintf(fp2, "#define %s\t%s%d\n", dtmacro(readtagstypes[k].dtype,1), + (strlen(readtagstypes[k].dtype) > 12) ? "" : + (strlen(readtagstypes[k].dtype) < 5) ? "\t\t" : + "\t", hcnt++); +#endif + } + } + cnt = 0; + while(t) { + if (listed(t) && ((t->tagtype == 's') || (t->tagtype == 'u'))) { + if (!strcmp(t->tag, "any")) { + t = t->next; + continue; + } + if (cnt > 0) + Fprintf(fp1, "%s", ",\n"); + Fprintf(fp1, "\t{NHTYPE_COMPLEX, (char *) \"%s\", sizeof(%s %s)}", + t->tag, + (t->tagtype == 's') ? "struct" : "union", t->tag); + cnt += 1; + } + t = t->next; + } + Fprintf(fp1, "%s", "\n};\n\n"); + Fprintf(fp1, "int nhdatatypes_size(void)\n{\n\treturn SIZE(nhdatatypes);\n}\n\n"); +} + +static void generate_c_files(void) +{ + struct tagstruct *t = first; +#ifdef KR1ED + long clocktim = 0; +#else + time_t clocktim = 0; +#endif + char *c, cbuf[60], sfparent[BUFSZ], funcnam[2][BUFSZ], *substruct, *gline, + norm_param_buf[BUFSZ]; + FILE *SFO_DATA, *SFI_DATA, *SFDATATMP, *SFO_PROTO, *SFI_PROTO, + *SFDATA, *SFPROTO, *SF_NORMALIZE_POINTERS; + int k = 0, j /*, opening, , closetag = 0 */; + const char *pt; + /* char *layout; */ + char *ft, *last_ft = (char *)0; + int okeydokey, x, a; + boolean did_i; + boolean normalize_param_used; + + SFDATA = fopen(SFDATA_NAME, "w"); + if (!SFDATA) return; + + SFPROTO = fopen(SFPROTO_NAME, "w"); + if (!SFPROTO) return; + + SFO_DATA = fopen("../util/sfo_data.tmp", "w"); + if (!SFO_DATA) return; + + SFO_PROTO = fopen("../include/sfo_proto.tmp", "w"); + if (!SFO_PROTO) return; + + SFI_PROTO = fopen("../include/sfi_proto.tmp", "w"); + if (!SFI_PROTO) return; + + SFI_DATA = fopen("../util/sfi_data.tmp", "w"); + if (!SFI_DATA) return; + + SFDATATMP = fopen("../util/sfdata.tmp", "w"); + if (!SFDATATMP) return; + + SF_NORMALIZE_POINTERS = fopen("../util/sfnormptrs.tmp", "w"); + if (!SF_NORMALIZE_POINTERS) return; + + (void) time(&clocktim); + Strcpy(cbuf, ctime(&clocktim)); + + for (c = cbuf; *c; c++) + if (*c == '\n') + break; + *c = '\0'; /* strip off the '\n' */ + + /* begin sfproto.h */ + Fprintf(SFPROTO,"/* NetHack %d.%d sfproto.h */\n", + VERSION_MAJOR, VERSION_MINOR); + for (j = 0; j < 3; ++j) + Fprintf(SFPROTO, "%s", get_preamble(j)); + Fprintf(SFPROTO, "#ifndef SFPROTO_H\n#define SFPROTO_H\n\n"); + Fprintf(SFPROTO, "#include \"hack.h\"\n#include \"integer.h\"\n#include \"wintype.h\"\n\n"); + + Fprintf(SFPROTO,"%s\n", "extern int critical_members_count(void);"); + Fprintf(SFPROTO,"%s\n", "extern void sfo_bitfield(NHFILE *, uint8_t *, const char *, int);"); + Fprintf(SFPROTO,"%s\n", "extern void sfi_bitfield(NHFILE *, uint8_t *, const char *, int);"); + Fprintf(SFO_PROTO, "/* generated output functions */\n"); + Fprintf(SFI_PROTO, "/* generated input functions */\n"); + + /* begin sfdata.c */ + Fprintf(SFDATA,"/* NetHack %d.%d sfdata.c */\n", + VERSION_MAJOR, VERSION_MINOR); + for (j = 0; preamble[j]; ++j) + Fprintf(SFDATA, "%s", get_preamble(j)); + Fprintf(SFDATA, "#include \"sfprocs.h\"\n"); + Fprintf(SFDATA, "#include \"sfproto.h\"\n\n"); + Fprintf(SFDATA, "#define NHTYPE_SIMPLE 1\n"); + Fprintf(SFDATA, "#define NHTYPE_COMPLEX 2\n\n"); + Fprintf(SFDATA, "struct nhdatatypes_t {\n"); + Fprintf(SFDATA, " uint dtclass;\n"); + Fprintf(SFDATA, " char *dtype;\n"); + Fprintf(SFDATA, " size_t dtsize;\n};\n\n"); + Fprintf(SFDATA,"static uint8_t bitfield = 0;\n"); + + /* begin sfnormptrs.tmp */ + Fprintf(SF_NORMALIZE_POINTERS, + "void normalize_pointers_any(union any *d_any);\n\n"); + Fprintf(SF_NORMALIZE_POINTERS, + "void\n" + "normalize_pointers_any(union any *d_any UNUSED)\n" + "{\n" + "}\n"); + + output_types(SFDATATMP); + Fprintf(SFDATATMP, "const char *critical_members[] = {\n"); + + k = 0; + did_i = FALSE; + while(k < SIZE(readtagstypes)) { + boolean insert_const = FALSE; + suppress_count = TRUE; + + if (readtagstypes[k].dtclass == NHTYPE_COMPLEX) { + + if (!strncmpi(readtagstypes[k].dtype,"Bitfield",8)) { + Fprintf(SFO_DATA, + "\nvoid\nsfo_bitfield(nhfp,\n" + "NHFILE *nhfp,\n" + "uint8_t *d_bitfield,\n" + "const char *myname\n" + "int bflen)\n" + "{\n"); + + Fprintf(SFI_DATA, + "\nvoid\nsfi_bitfield(\n" + "NHFILE *nhfp,\n" + "uint8_t *d_bitfield,\n" + "const char *myname\n" + "int bflen)\n" + "{\n"); + } + + +#if 0 + if (!strncmpi(readtagstypes[k].dtype,"version_info",8)) + insert_const = TRUE; +#endif + + pt = (const char *) 0; + t = first; + while(t) { + if (t->tagtype == 'u' && !strcmp(t->tag, readtagstypes[k].dtype)) { + pt = "union"; + break; + } + t = t->next; + } + + if (!pt) { + pt = "struct"; + } + + (void) snprintf(funcnam[0], sizeof funcnam[0], "sfo_x_%s", readtagstypes[k].dtype); + Fprintf(SFO_PROTO, + "extern void %s(NHFILE *, %s%s %s *, const char *);\n", + fn(funcnam[0]), + insert_const ? "const " : "", + pt, readtagstypes[k].dtype); + + Fprintf(SFO_DATA, + "\nvoid\n%s(\n" + "NHFILE *nhfp,\n" + "%s%s %s *d_%s,\n" + "const char *myname)\n" + "{\n", + fn(funcnam[0]), +/* deblank(readtagstypes[k].dtype), */ + insert_const ? "const " : "", + pt, readtagstypes[k].dtype, + deblank(readtagstypes[k].dtype)); + +#if 0 + Fprintf(SFO_DATA, + " const char *parent = \"%s\";\n", + readtagstypes[k].dtype); +#endif + + (void) snprintf(funcnam[0], sizeof funcnam[0], "sfi_x_%s", + readtagstypes[k].dtype); + Fprintf(SFI_PROTO, + "extern void %s(NHFILE *, %s%s %s *, const char *);\n", + fn(funcnam[0]), + insert_const ? "const " : "", + pt, readtagstypes[k].dtype); + + Fprintf(SFI_DATA, + "\nvoid\n%s(\n" + "NHFILE *nhfp,\n" + "%s%s %s *d_%s,\n" + "const char *myname)\n" + "{\n", + fn(funcnam[0]), +/* deblank(readtagstypes[k].dtype), */ + insert_const ? "const " : "", + pt, readtagstypes[k].dtype, + deblank(readtagstypes[k].dtype)); + +#if 0 + Fprintf(SFI_DATA, + " const char *parent = \"%s\";\n", + readtagstypes[k].dtype); +#endif + + Sprintf(sfparent, "%s %s", pt, readtagstypes[k].dtype); + + + Fprintf(SF_NORMALIZE_POINTERS, + "\nvoid normalize_pointers_%s(%s " + "*d_%s);\n", + readtagstypes[k].dtype, sfparent, readtagstypes[k].dtype); + Fprintf(SF_NORMALIZE_POINTERS, + "\nvoid\nnormalize_pointers_%s(%s " + "*d_%s)\n{\n", + readtagstypes[k].dtype, sfparent, readtagstypes[k].dtype); + Snprintf(norm_param_buf, sizeof norm_param_buf, "d_%s", + readtagstypes[k].dtype); + + for (a = 0; a < SIZE(nah); ++a) { + if (!strcmp(nah[a].parent, readtagstypes[k].dtype)) { + if (!did_i) { + Fprintf(SFO_DATA, " int i;\n"); + Fprintf(SFI_DATA, " int i;\n"); + did_i = TRUE; + } + } + } + + Fprintf(SFO_DATA, "\n"); + Fprintf(SFI_DATA, "\n"); + + Fprintf(SFO_DATA, " nhUse(myname);\n"); + Fprintf(SFI_DATA, " nhUse(myname);\n"); + Fprintf(SFO_DATA, "\n"); + Fprintf(SFI_DATA, "\n"); + + /******************************************************** + * cycle through all the tags and find every tag with * + * a parent matching readtagstypes[k].dtype * + ********************************************************/ + + t = first; + normalize_param_used = FALSE; + + while(t) { + x = 0; + okeydokey = 0; +/* + if (!strcmp(t->tag, "nextc") + && !strcmp(readtagstypes[k].dtype, "engrave_info")) + __debugbreak(); +*/ + if (t->tagtype == 's') { + char *ss = strstr(t->searchtext,"{$/"); + + if (ss) { + strcpy(ssdef, t->tag); + } + t = t->next; + continue; + } + + /************insert opening conditional if needed ********/ + while(condtag[x]) { + if (!strcmp(condtag[x],readtagstypes[k].dtype) && + !strcmp(condtag[x+1],t->tag)) { + okeydokey = 1; + break; + } + x = x + 4; + } + + /* some structs are entirely defined within another struct declaration. + * Legal, but a greater challenge for us here. + */ + substruct = strstr(t->parent, "::"); + if (substruct) { + substruct += 2; + } + + if ((strcmp(readtagstypes[k].dtype, t->parent) == 0) || + (substruct && strcmp(readtagstypes[k].dtype, substruct) == 0)) { + ft = (char *)0; + + if (t->ptr[0] != '\0') + ft = &t->ptr[0]; + else + ft = findtype(t->searchtext, t->tag); + + if (ft) { + last_ft = ft; + if (okeydokey && condtag[x+2] && strlen(condtag[x+2]) > 0) { + Fprintf(SFO_DATA,"%s\n", condtag[x+2]); + Fprintf(SFI_DATA,"%s\n", condtag[x+2]); + Fprintf(SFDATATMP,"%s\n", condtag[x+2]); + } + } else { + /* use the last found one as last resort then */ + ft = last_ft; + } + + /***************** Bitfield *******************/ + if (!strncmpi(ft, "Bitfield", 8)) { + char lbuf[BUFSZ]; + int j2, z; + + Sprintf(lbuf, + " " + "bitfield = d_%s->%s;", + readtagstypes[k].dtype, t->tag); + z = (int) strlen(lbuf); + for (j2 = 0; j2 < (65 - z); ++j2) + Strcat(lbuf, " "); + Sprintf(eos(lbuf), "/* (%s) */\n", ft); + Fprintf(SFO_DATA, "%s", lbuf); + Fprintf(SFO_DATA, + " " + "sfo_bitfield(nhfp, &bitfield, \"%s\", %s);\n", + t->tag, bfsize(ft)); +#if 0 + Fprintf(SFI_DATA, + " " + "bitfield = 0;\n"); +#else + Fprintf(SFI_DATA, + " " + "bitfield = d_%s->%s; /* set it to current value for testing */\n", + readtagstypes[k].dtype, t->tag); +#endif + Fprintf(SFI_DATA, + " " + "sfi_bitfield(nhfp, &bitfield, \"%s\", %s);\n", + t->tag, bfsize(ft)); + + Fprintf(SFI_DATA, + " " + "d_%s->%s = bitfield;\n\n", + readtagstypes[k].dtype, t->tag); + Fprintf(SFDATATMP, + "\t\"%s:%s:%s\",\n", + sfparent, t->tag, ft); + } else { + /**************** not a bitfield ****************/ + char arrbuf[BUFSZ]; + char lbuf[BUFSZ * 2]; /* sprintf target for others, gcc + complaint */ + char fnbuf[BUFSZ]; + char altbuf[BUFSZ]; + boolean isptr = FALSE, kludge_sbrooms = FALSE, array_of_ptrs = FALSE; + boolean insert_loop = FALSE; + int j2, z; + + altbuf[0] = '\0'; + /*************** kludge for sbrooms *************/ + if (!strcmp(t->tag, "sbrooms")) { + kludge_sbrooms = TRUE; + (void) strcpy(t->arraysize1, "MAX_SUBROOMS"); + insert_loop = TRUE; + array_of_ptrs = TRUE; + } + if (!strcmp(t->parent, "engr") + && !strcmp(t->tag, "engr_txt")) { + (void) strcpy(t->arraysize1, "text_states"); + insert_loop = TRUE; + array_of_ptrs = TRUE; + } + if (t->arraysize2[0]) { + Sprintf(arrbuf, "(%s * %s)", t->arraysize1, + t->arraysize2); + isptr = TRUE; /* suppress the & in function args */ + } else if (t->arraysize1[0]) { + Sprintf(arrbuf, "%s", t->arraysize1); + isptr = TRUE; /* suppress the & in function args */ + } else { + Strcpy(arrbuf, "1"); + } + Strcpy(fnbuf, dtfn(ft, 0, &isptr)); + /* + * determine if this is one of the special cases + * where there's an array of structs instead of + * an array of simple types. We need to insert + * a for loop in those cases. + */ + for (a = 0; a < SIZE(nah); ++a) { + if (!strcmp(nah[a].parent, t->parent)) + if (!strcmp(nah[a].nm, t->tag)) + insert_loop = TRUE; + } + if (isptr && !strcmp(fnbuf, readtagstypes[k].dtype)) { + Strcpy(altbuf, "genericptr"); + } else if (isptr + && (!strcmp(t->ptr, "struct permonst *") + || !strcmp(t->ptr, "struct monst *") + || !strcmp(t->ptr, "struct obj *") + || !strcmp(t->ptr, "struct cemetery *") + || !strcmp(t->ptr, "struct container *") + || !strcmp(t->ptr, "struct mextra *") + || !strcmp(t->ptr, "struct oextra *") + || !strcmp(t->ptr, "struct s_level *") + || !strcmp(t->ptr, "struct bill_x *") + || !strcmp(t->ptr, "struct trap *") + || !strcmp(t->ptr, "struct egd *") + || !strcmp(t->ptr, "struct epri *") + || !strcmp(t->ptr, "struct eshk *") + || !strcmp(t->ptr, "struct emin *") + || !strcmp(t->ptr, "struct ebones *") + || !strcmp(t->ptr, "struct edog *"))) { + Strcpy(altbuf, "genericptr"); + } else if (isptr + && (!strcmp(t->parent, "engr") + && !strcmp(t->tag, "engr_txt"))) { + Strcpy(altbuf, "genericptr"); + } else if (isptr + && (!strcmp(t->parent, "mapseen") + && !strcmp(t->tag, "br"))) { + Strcpy(altbuf, "genericptr"); + + // } else if (isptr + // && + // (!strcmp(t->parent, + // "engrave_info") + // && + // !strcmp(t->tag, + // "nextc"))) { + // Strcpy(altbuf, + // "genericptr"); + + } else if ( + (isptr && !strcmp(t->ptr, "char *")) + && ((!strcmp(t->parent, "engrave_info") + && !strcmp(t->tag, "nextc")) + || (!strcmp(t->parent, "mapseen") + && !strcmp(t->tag, "custom")) + || (!strcmp(t->parent, "mapseen") + && !strcmp(t->tag, "custom")) + || (!strcmp(t->parent, "mextra") + && !strcmp(t->tag, "mgivenname")) + || (!strcmp(t->parent, "gamelog_line") + && !strcmp(t->tag, "text")) + || (!strcmp(t->parent, "oextra") + && !strcmp(t->tag, "oname")) + || (!strcmp(t->parent, "oextra") + && !strcmp(t->tag, "omailcmd")))) { + Strcpy(altbuf, "genericptr"); + } else if (isptr && !strcmp(t->tag, "oc_uname")) { + Strcpy(altbuf, "genericptr"); + } else { + Strcpy(altbuf, fnbuf); + } + if (isptr && (strcmp(altbuf, "genericptr") != 0) + && (t->ptr[0] != 0 + && (*(t->ptr + (strlen(t->ptr) - 1)) == '*') + && (strcmp(t->ptr, altbuf) != 0))) { + fprintf( + stderr, + "WARNING - \"%s\" in %s called \"%s\" " + "resulted in an unexpected set of inputs/outputs " + "(%s)\n", + (t->ptr[0] != 0 && strlen(t->ptr)) ? t->ptr : "unknown", + (t->parent[0] != 0 && strlen(t->parent)) ? t->parent + : "?", + (t->tag[0] != 0 && strlen(t->tag)) ? t->tag : "?", + altbuf); + } + /* kludge for attribs */ + if (!strcmp(readtagstypes[k].dtype, "attribs") + && !strcmp(arrbuf, "A_MAX")) { + insert_loop = TRUE; + } + if (insert_loop) { + Fprintf(SFO_DATA, " for (%si = 0; i < %s; ++i)\n", + did_i ? "" : "int ", arrbuf); + Fprintf(SFI_DATA, " for (%si = 0; i < %s; ++i)\n", + did_i ? "" : "int ", arrbuf); + if (array_of_ptrs) { + Fprintf(SF_NORMALIZE_POINTERS, + " for (%si = 0; i < %s; ++i)\n", + did_i ? "" : "int ", arrbuf); + } + arrbuf[0] = '1'; + arrbuf[1] = '\0'; + } + if (isptr + && (t->ptr[0] != 0 + && (*(t->ptr + (strlen(t->ptr) - 1)) == '*') + && (strcmp(t->ptr, altbuf) != 0))) { + Fprintf( + SF_NORMALIZE_POINTERS, + " %sd_%s->%s%s%s%s = d_%s->%s%s%s%s ? (%s) 1 : (%s) 0;\n", + (insert_loop && array_of_ptrs) ? " " : "", + t->parent, t->tag, + (insert_loop && array_of_ptrs) ? "[" : "", + (insert_loop && array_of_ptrs) ? "i" : "", + (insert_loop && array_of_ptrs) ? "]" : "", + t->parent, t->tag, + (insert_loop && array_of_ptrs) ? "[" : "", + (insert_loop && array_of_ptrs) ? "i" : "", + (insert_loop && array_of_ptrs) ? "]" : "", + t->ptr, + t->ptr); + normalize_param_used = TRUE; + } + Snprintf(lbuf, sizeof lbuf, + " " + "%ssfo%s_%s(nhfp, %s%sd_%s->%s%s, \"%s\"%s%s);", + insert_loop ? " " : "", + (readtagstypes[k].dtclass == NHTYPE_SIMPLE || no_x(altbuf)) ? "" + : "_x", + altbuf, + (isptr && !strcmp(altbuf, "genericptr")) + ? "(genericptr_t) " + : "", + (isptr && !insert_loop && !kludge_sbrooms + && strcmp(altbuf, "genericptr")) + ? "" + : "&", + readtagstypes[k].dtype, t->tag, + insert_loop ? "[i]" + : "", + t->tag, strcmp(altbuf, "char") != 0 ? "" : ", ", + strcmp(altbuf, "char") != 0 ? "" : arrbuf); + /* align comments */ + z = (int) strlen(lbuf); + for (j2 = 0; j2 < (65 - z); ++j2) + Strcat(lbuf, " "); + Sprintf(eos(lbuf), "/* (%s) */\n", ft); + Fprintf(SFO_DATA, "%s", lbuf); + + Snprintf( + lbuf, sizeof lbuf, + " " + "%ssfi%s_%s(nhfp, %s%sd_%s->%s%s, \"%s\"%s%s);\n", + insert_loop ? " " : "", + (readtagstypes[k].dtclass == NHTYPE_SIMPLE + || no_x(altbuf)) + ? "" + : "_x", + altbuf, + (isptr && !strcmp(altbuf, "genericptr")) + ? "(genericptr_t) " + : "", + (isptr && !insert_loop && !kludge_sbrooms + && strcmp(altbuf, "genericptr")) + ? "" + : "&", + readtagstypes[k].dtype, t->tag, + kludge_sbrooms ? "[0]" + : insert_loop ? "[i]" + : "", + t->tag, strcmp(altbuf, "char") != 0 ? "" : ", ", + strcmp(altbuf, "char") != 0 ? "" : arrbuf); + Fprintf(SFI_DATA, "%s", lbuf); + Fprintf(SFDATATMP, + "\t\"%s:%s:%s\",\n", + sfparent, t->tag,fieldfix(ft,ssdef)); + kludge_sbrooms = FALSE; + array_of_ptrs = FALSE; + altbuf[0] = '\0'; + } + + /************insert closing conditional if needed ********/ + if (okeydokey && condtag[x+3] && strlen(condtag[x+3]) > 0) { + Fprintf(SFO_DATA,"%s\n", condtag[x+3]); + Fprintf(SFI_DATA,"%s\n", condtag[x+3]); + Fprintf(SFDATATMP,"%s\n", condtag[x+3]); + } + } + t = t->next; + } + + Fprintf(SFO_DATA, "\n"); + Fprintf(SFI_DATA, "\n"); + + Fprintf(SFO_DATA, "}\n"); + Fprintf(SFI_DATA, "}\n"); + if (!normalize_param_used) { + Fprintf(SF_NORMALIZE_POINTERS, " nhUse(%s);\n", + norm_param_buf); + } + Fprintf(SF_NORMALIZE_POINTERS, "}\n"); + } + ++k; + did_i = FALSE; + } + + Fprintf(SFDATATMP,"};\n\n"); + Fprintf(SFDATATMP, "int critical_members_count(void)\n{\n\treturn SIZE(critical_members);\n}\n\n"); + + fclose(SFO_DATA); + fclose(SFI_DATA); + fclose(SFO_PROTO); + fclose(SFI_PROTO); + fclose(SFDATATMP); + fclose(SF_NORMALIZE_POINTERS); + + /* Consolidate SFO_* and SFI_* etc into single files */ + + SFO_DATA = fopen("../util/sfo_data.tmp", "r"); + if (!SFO_DATA) return; + while ((gline = fgetline(SFO_DATA)) != 0) { + (void) fputs(gline, SFDATA); + free(gline); + } + (void) fclose(SFO_DATA); + (void) remove("../util/sfo_data.tmp"); + + SFI_DATA = fopen("../util/sfi_data.tmp", "r"); + if (!SFI_DATA) return; + while ((gline = fgetline(SFI_DATA)) != 0) { + (void) fputs(gline, SFDATA); + free(gline); + } + (void) fclose(SFI_DATA); + (void) remove("../util/sfi_data.tmp"); + + SFO_PROTO = fopen("../include/sfo_proto.tmp", "r"); + if (!SFO_PROTO) return; + while ((gline = fgetline(SFO_PROTO)) != 0) { + (void) fputs(gline, SFPROTO); + free(gline); + } + (void) fclose(SFO_PROTO); + (void) remove("../include/sfo_proto.tmp"); + + SFI_PROTO = fopen("../include/sfi_proto.tmp", "r"); + if (!SFI_PROTO) return; + while ((gline = fgetline(SFI_PROTO)) != 0) { + (void) fputs(gline, SFPROTO); + free(gline); + } + (void) fclose(SFI_PROTO); + (void) remove("../include/sfi_proto.tmp"); + + SFDATATMP = fopen("../util/sfdata.tmp", "r"); + if (!SFDATATMP) return; + while ((gline = fgetline(SFDATATMP)) != 0) { + (void) fputs(gline, SFDATA); + free(gline); + } + (void) fclose(SFDATATMP); + (void) remove("../util/sfdata.tmp"); + + SF_NORMALIZE_POINTERS = fopen("../util/sfnormptrs.tmp", "r"); + if (!SF_NORMALIZE_POINTERS) + return; + while ((gline = fgetline(SF_NORMALIZE_POINTERS)) != 0) { + (void) fputs(gline, SFDATA); + free(gline); + } + (void) fclose(SF_NORMALIZE_POINTERS); + (void) remove("../util/sfnormptrs.tmp"); + + Fprintf(SFDATA, "/*sfdata.c*/\n"); + Fprintf(SFPROTO,"#endif /* SFPROTO_H */\n"); + (void) fclose(SFDATA); + (void) fclose(SFPROTO); +} + +#if 0 +static char * +dtmacro(const char *str, + int n) /* 1 = supress appending |SF_PTRMASK */ +{ + static char buf[128], buf2[128]; + char *nam, *c; + int ispointer = 0; + + if (!str) + return (char *)0; + (void)strncpy(buf, str, 127); + + c = buf; + while (*c) + c++; /* eos */ + + c--; + if (*c == '*') { + ispointer = 1; + *c = '\0'; + c--; + } + while(isspace(*c)) { + c--; + } + *(c+1) = '\0'; + c = buf; + + if (strncmpi(c, "Bitfield", 8) == 0) { + *(c+8) = '\0'; + } else if (strcmpi(c, "genericptr_t") == 0) { + ispointer = 1; + } else if (strncmpi(c, "const ", 6) == 0) { + c = buf + 6; + } else if ((strncmpi(c, "struct ", 7) == 0) || + (strncmpi(c, "struct\t", 7) == 0)) { + c = buf + 7; + } else if (strncmpi(c, "union ", 6) == 0) { + c = buf + 6; + } + + /* end of substruct within struct definition */ + if (strcmp(buf,"}") == 0 && strlen(ssdef) > 0) { + strcpy(buf,ssdef); + c = buf; + } + + for (nam = c; *c; c++) { + if (*c >= 'a' && *c <= 'z') + *c -= (char)('a' - 'A'); + else if (*c < 'A' || *c > 'Z') + *c = '_'; + } + (void)sprintf(buf2, "SF_%s%s", nam, + (ispointer && (n == 0)) ? " | SF_PTRMASK" : ""); + return buf2; +} +#endif + +static char * +dtfn(const char *str, + int n, /* 1 = supress appending |SF_PTRMASK */ + boolean *isptr) +{ + static char buf[128], buf2[128]; + const char *nam; + char *c; + int ispointer = 0; + + if (!str) + return (char *)0; + (void)strncpy(buf, str, 127); + + c = buf; + while (*c) c++; /* eos */ + + c--; + if (*c == '*') { + ispointer = 1; + *c = '\0'; + c--; + } + while(isspace(*c)) { + c--; + } + *(c+1) = '\0'; + c = buf; + + if (strncmpi(c, "Bitfield", 8) == 0) { + *(c+8) = '\0'; + } else if (strcmpi(c, "genericptr_t") == 0) { + ispointer = 1; + } else if (strncmpi(c, "const ", 6) == 0) { + c = buf + 6; + } else if ((strncmpi(c, "struct ", 7) == 0) || + (strncmpi(c, "struct\t", 7) == 0)) { + c = buf + 7; + } else if (strncmpi(c, "union ", 6) == 0) { + c = buf + 6; + } + + /* end of substruct within struct definition */ + if (strcmp(buf,"}") == 0 && strlen(ssdef) > 0) { + strcpy(buf,ssdef); + c = buf; + } + + for (nam = (const char *) c; *c; c++) { + if (*c >= 'A' && *c <= 'Z') + *c = tolower(*c); + else if (*c == ' ') + *c = '_'; + } + /* some fix-ups */ + if (!strcmp(nam, "genericptr_t")) + nam = "genericptr"; + else if (!strcmp(nam, "unsigned_int")) + nam = "uint"; + else if (!strcmp(nam, "unsigned_long")) + nam = "ulong"; + else if (!strcmp(nam, "unsigned_char")) + nam = "uchar"; + else if (!strcmp(nam, "unsigned_short")) + nam = "ushort"; + + if (ispointer && isptr && n == 0) + *isptr = TRUE; + (void)sprintf(buf2, "%s%s", nam, ""); + return buf2; +} + +static char * +fieldfix(char *f, char *ss) +{ + char *c /*, *dest = fieldfixbuf */; + + if (strcmp(f,"}") == 0 && strlen(ss) > 0 && strlen(ss) < BUFSZ - 1) { + /* (void)sprintf(fieldfixbuf,"struct %s", ss); */ + strcpy(fieldfixbuf,ss); + } else { + if (strlen(f) < BUFSZ - 1) strcpy(fieldfixbuf,f); + } + + /* converting any tabs to space */ + for (c = fieldfixbuf; *c; c++) + if (*c == TAB) *c = SPACE; + + return fieldfixbuf; +} + +static char * +bfsize(const char *str) +{ + static char buf[128]; + const char *c1; + char *c2, *subst; + + if (!str) + return (char *)0; + + /* kludge */ + subst = strstr(str, ",$/"); + if (subst != 0) { + subst++; + *subst++ = ' '; + *subst++ = '1'; + } + + c2 = buf; + c1 = str; + while (*c1) { + if (*c1 == ',') + break; + c1++; + } + + if (*c1 == ',') { + c1++; + while (*c1 && *c1 != ')') { + *c2++ = *c1++; + } + *c2 = '\0'; + } else { + return (char *)0; + } + return buf; +} + +/* Read one line from input, up to and including the next newline + * character. Returns a pointer to the heap-allocated string, or a + * null pointer if no characters were read. + */ +static char * +fgetline(FILE *fd) +{ + static const int inc = 256; + int len = inc; + char *c = malloc(len), *ret; + + for (;;) { + ret = fgets(c + len - inc, inc, fd); + if (!ret) { + free(c); + c = NULL; + break; + } else if (strchr(c, '\n')) { + /* normal case: we have a full line */ + break; + } + len += inc; + c = realloc(c, len); + } + return c; +} + +int +strncmpi(register const char *s1, register const char *s2, size_t n) +{ + register char t1, t2; + + while (n--) { + if (!*s2) + return (*s1 != 0); /* s1 >= s2 */ + else if (!*s1) + return -1; /* s1 < s2 */ + t1 = lowc(*s1++); + t2 = lowc(*s2++); + if (t1 != t2) + return (t1 > t2) ? 1 : -1; + } + return 0; /* s1 == s2 */ +} + +/* force 'c' into uppercase */ +char +highc(char c) +{ + return (char) (('a' <= c && c <= 'z') ? (c & ~040) : c); +} + +/* force 'c' into lowercase */ +char +lowc(char c) +{ + return (char) (('A' <= c && c <= 'Z') ? (c | 040) : c); +} + +DISABLE_WARNING_FORMAT_NONLITERAL + +/* + * Wrap snprintf for use in the main code. + * + * Wrap reasons: + * 1. If there are any platform issues, we have one spot to fix them - + * snprintf is a routine with a troubling history of bad implementations. + * 2. Add combersome error checking in one spot. Problems with text wrangling + * do not have to be fatal. + * 3. Gcc 9+ will issue a warning unless the return value is used. + * Annoyingly, explicitly casting to void does not remove the error. + * So, use the result - see reason #2. + */ +void +nh_snprintf(const char *func, int myline, char *str, size_t size, + const char *fmt, ...) +{ + va_list ap; + int n; + + va_start(ap, fmt); +#ifdef NO_VSNPRINTF + n = vsprintf(str, fmt, ap); +#else + n = vsnprintf(str, size, fmt, ap); +#endif + va_end(ap); + if (n < 0 || (size_t)n >= size) { /* is there a problem? */ + fprintf(stderr, "snprintf %s: func %s, file line %d", + n < 0 ? "format error" + : "overflow", + func, myline); + str[size-1] = 0; /* make sure it is nul terminated */ + } +} + +RESTORE_WARNING_FORMAT_NONLITERAL + +struct already_in_sfbase { + int typ; + const char *actual; + const char *replacement; +}; + +/* The ones that can't be broken down into subfields + * are NHTYPE_SIMPLE. + */ +const struct already_in_sfbase already[] = { + /* input */ + { NHTYPE_SIMPLE, "Sfi_any", "Sfi_any" }, + { NHTYPE_SIMPLE, "Sfi_boolean", "Sfi_boolean" }, + { NHTYPE_SIMPLE, "Sfi_char", "Sfi_char" }, + { NHTYPE_SIMPLE, "Sfi_coordxy", "Sfi_coordxy" }, + { NHTYPE_SIMPLE, "Sfi_int16", "Sfi_int16" }, + { NHTYPE_SIMPLE, "Sfi_int32", "Sfi_int32" }, + { NHTYPE_SIMPLE, "Sfi_long", "Sfi_long" }, + { NHTYPE_SIMPLE, "Sfi_nhcoord", "Sfi_nhcoord" }, + { NHTYPE_SIMPLE, "Sfi_schar", "Sfi_schar" }, + { NHTYPE_SIMPLE, "Sfi_uint32", "Sfi_uint32" }, + { NHTYPE_SIMPLE, "Sfi_ulong", "Sfi_ulong" }, + { NHTYPE_SIMPLE, "Sfi_xint8", "Sfi_xint8" }, + { NHTYPE_COMPLEX, "Sfi_arti_info", "Sfi_x_arti_info" }, + { NHTYPE_COMPLEX, "Sfi_branch", "Sfi_x_branch" }, + { NHTYPE_COMPLEX, "Sfi_bubble", "Sfi_x_bubble" }, + { NHTYPE_COMPLEX, "Sfi_cemetery", "Sfi_x_cemetery" }, + { NHTYPE_COMPLEX, "Sfi_context_info", "Sfi_x_context_info" }, + { NHTYPE_COMPLEX, "Sfi_d_level", "Sfi_x_d_level" }, + { NHTYPE_COMPLEX, "Sfi_damage", "Sfi_x_damage" }, + { NHTYPE_COMPLEX, "Sfi_dest_area", "Sfi_x_dest_area" }, + { NHTYPE_COMPLEX, "Sfi_dgn_topology", "Sfi_x_dgn_topology" }, + { NHTYPE_COMPLEX, "Sfi_dungeon", "Sfi_x_dungeon" }, + { NHTYPE_COMPLEX, "Sfi_ebones", "Sfi_x_ebones" }, + { NHTYPE_COMPLEX, "Sfi_edog", "Sfi_x_edog" }, + { NHTYPE_COMPLEX, "Sfi_egd", "Sfi_x_egd" }, + { NHTYPE_COMPLEX, "Sfi_emin", "Sfi_x_emin" }, + { NHTYPE_COMPLEX, "Sfi_engr", "Sfi_x_engr" }, + { NHTYPE_COMPLEX, "Sfi_epri", "Sfi_x_epri" }, + { NHTYPE_COMPLEX, "Sfi_eshk", "Sfi_x_eshk" }, + { NHTYPE_COMPLEX, "Sfi_fe", "Sfi_x_fe" }, + { NHTYPE_COMPLEX, "Sfi_flag", "Sfi_x_flag" }, + { NHTYPE_COMPLEX, "Sfi_fruit", "Sfi_x_fruit" }, + { NHTYPE_COMPLEX, "Sfi_gamelog_line", "Sfi_x_gamelog_line" }, + { NHTYPE_COMPLEX, "Sfi_kinfo", "Sfi_x_kinfo" }, + { NHTYPE_COMPLEX, "Sfi_levelflags", "Sfi_x_levelflags" }, + { NHTYPE_COMPLEX, "Sfi_linfo", "Sfi_x_linfo" }, + { NHTYPE_COMPLEX, "Sfi_ls_t", "Sfi_x_ls_t" }, + { NHTYPE_COMPLEX, "Sfi_mapseen_feat", "Sfi_x_mapseen_feat" }, + { NHTYPE_COMPLEX, "Sfi_mapseen_flags", "Sfi_x_mapseen_flags" }, + { NHTYPE_COMPLEX, "Sfi_mapseen_rooms", "Sfi_x_mapseen_rooms" }, + { NHTYPE_COMPLEX, "Sfi_mkroom", "Sfi_x_mkroom" }, + { NHTYPE_COMPLEX, "Sfi_monst", "Sfi_x_monst" }, + { NHTYPE_COMPLEX, "Sfi_mvitals", "Sfi_x_mvitals" }, + { NHTYPE_COMPLEX, "Sfi_nhrect", "Sfi_x_nhrect" }, + { NHTYPE_COMPLEX, "Sfi_obj", "Sfi_x_obj" }, + { NHTYPE_COMPLEX, "Sfi_objclass", "Sfi_x_objclass" }, + { NHTYPE_COMPLEX, "Sfi_q_score", "Sfi_x_q_score" }, + { NHTYPE_COMPLEX, "Sfi_rm", "Sfi_x_rm" }, + { NHTYPE_COMPLEX, "Sfi_s_level", "Sfi_x_s_level" }, + { NHTYPE_COMPLEX, "Sfi_spell", "Sfi_x_spell" }, + { NHTYPE_COMPLEX, "Sfi_stairway", "Sfi_x_stairway" }, + { NHTYPE_COMPLEX, "Sfi_trap", "Sfi_x_trap" }, + { NHTYPE_COMPLEX, "Sfi_version_info", "Sfi_x_version_info" }, + { NHTYPE_COMPLEX, "Sfi_you", "Sfi_x_you" }, + /* output */ + { NHTYPE_SIMPLE, "Sfo_any", "Sfo_any" }, + { NHTYPE_SIMPLE, "Sfo_boolean", "Sfo_boolean" }, + { NHTYPE_SIMPLE, "Sfo_char", "Sfo_char" }, + { NHTYPE_SIMPLE, "Sfo_coordxy", "Sfo_coordxy" }, + { NHTYPE_SIMPLE, "Sfo_int16", "Sfo_int16" }, + { NHTYPE_SIMPLE, "Sfo_int32", "Sfo_int32" }, + { NHTYPE_SIMPLE, "Sfo_long", "Sfo_long" }, + { NHTYPE_SIMPLE, "Sfo_nhcoord", "Sfo_nhcoord" }, + { NHTYPE_SIMPLE, "Sfo_schar", "Sfo_schar" }, + { NHTYPE_SIMPLE, "Sfo_uint32", "Sfo_uint32" }, + { NHTYPE_SIMPLE, "Sfo_ulong", "Sfo_ulong" }, + { NHTYPE_SIMPLE, "Sfo_xint8", "Sfo_xint8" }, + { NHTYPE_COMPLEX, "Sfo_arti_info", "Sfo_x_arti_info" }, + { NHTYPE_COMPLEX, "Sfo_branch", "Sfo_x_branch" }, + { NHTYPE_COMPLEX, "Sfo_bubble", "Sfo_x_bubble" }, + { NHTYPE_COMPLEX, "Sfo_cemetery", "Sfo_x_cemetery" }, + { NHTYPE_COMPLEX, "Sfo_context_info", "Sfo_x_context_info" }, + { NHTYPE_COMPLEX, "Sfo_d_level", "Sfo_x_d_level" }, + { NHTYPE_COMPLEX, "Sfo_damage", "Sfo_x_damage" }, + { NHTYPE_COMPLEX, "Sfo_dest_area", "Sfo_x_dest_area" }, + { NHTYPE_COMPLEX, "Sfo_dgn_topology", "Sfo_x_dgn_topology" }, + { NHTYPE_COMPLEX, "Sfo_dungeon", "Sfo_x_dungeon" }, + { NHTYPE_COMPLEX, "Sfo_ebones", "Sfo_x_ebones" }, + { NHTYPE_COMPLEX, "Sfo_edog", "Sfo_x_edog" }, + { NHTYPE_COMPLEX, "Sfo_egd", "Sfo_x_egd" }, + { NHTYPE_COMPLEX, "Sfo_emin", "Sfo_x_emin" }, + { NHTYPE_COMPLEX, "Sfo_engr", "Sfo_x_engr" }, + { NHTYPE_COMPLEX, "Sfo_epri", "Sfo_x_epri" }, + { NHTYPE_COMPLEX, "Sfo_eshk", "Sfo_x_eshk" }, + { NHTYPE_COMPLEX, "Sfo_fe", "Sfo_x_fe" }, + { NHTYPE_COMPLEX, "Sfo_flag", "Sfo_x_flag" }, + { NHTYPE_COMPLEX, "Sfo_fruit", "Sfo_x_fruit" }, + { NHTYPE_COMPLEX, "Sfo_gamelog_line", "Sfo_x_gamelog_line" }, + { NHTYPE_COMPLEX, "Sfo_kinfo", "Sfo_x_kinfo" }, + { NHTYPE_COMPLEX, "Sfo_levelflags", "Sfo_x_levelflags" }, + { NHTYPE_COMPLEX, "Sfo_linfo", "Sfo_x_linfo" }, + { NHTYPE_COMPLEX, "Sfo_ls_t", "Sfo_x_ls_t" }, + { NHTYPE_COMPLEX, "Sfo_mapseen_feat", "Sfo_x_mapseen_feat" }, + { NHTYPE_COMPLEX, "Sfo_mapseen_flags", "Sfo_x_mapseen_flags" }, + { NHTYPE_COMPLEX, "Sfo_mapseen_rooms", "Sfo_x_mapseen_rooms" }, + { NHTYPE_COMPLEX, "Sfo_mkroom", "Sfo_x_mkroom" }, + { NHTYPE_COMPLEX, "Sfo_monst", "Sfo_x_monst" }, + { NHTYPE_COMPLEX, "Sfo_mvitals", "Sfo_x_mvitals" }, + { NHTYPE_COMPLEX, "Sfo_nhrect", "Sfo_x_nhrect" }, + { NHTYPE_COMPLEX, "Sfo_obj", "Sfo_x_obj" }, + { NHTYPE_COMPLEX, "Sfo_objclass", "Sfo_x_objclass" }, + { NHTYPE_COMPLEX, "Sfo_q_score", "Sfo_x_q_score" }, + { NHTYPE_COMPLEX, "Sfo_rm", "Sfo_x_rm" }, + { NHTYPE_COMPLEX, "Sfo_s_level", "Sfo_x_s_level" }, + { NHTYPE_COMPLEX, "Sfo_spell", "Sfo_x_spell" }, + { NHTYPE_COMPLEX, "Sfo_stairway", "Sfo_x_stairway" }, + { NHTYPE_COMPLEX, "Sfo_trap", "Sfo_x_trap" }, + { NHTYPE_COMPLEX, "Sfo_version_info", "Sfo_x_version_info" }, + { NHTYPE_COMPLEX, "Sfo_you", "Sfo_x_you" }, +}; + +static const char * +fn(const char *f) +{ + int i; + + for (i = 0; i < SIZE(already); ++i) { + if (!strcmp(already[i].actual, f)) + return already[i].replacement; + } + return f; +} + +const char *force_no_x[] = { + "aligntyp", "any", "boolean", "char", "coordxy", "genericptr", + "int", "int16", "int32", "int64", "long", "schar", + "short", "size_t", "time_t", "uchar", "uint32", "uint64", + "ulong", "unsigned", "ushort", "xint16", "xint8", +}; + +static boolean +no_x(const char *s) +{ + int i; + + for (i = 0; i < SIZE(force_no_x); ++i) { + if (!strcmp(force_no_x[i], s)) + return TRUE; + } + return FALSE; +} + +struct nh_classification { + int in_sfbase; + uint dtclass; + const char *fn; + const char *replacement_fn; +}; + +struct nh_classification nhdatatypes[] = { + { 0, NHTYPE_COMPLEX, "sfi_achievement_tracking", + "sfi_achievement_tracking" }, + { 0, NHTYPE_COMPLEX, "sfi_align", "sfi_align" }, + { 0, NHTYPE_COMPLEX, "sfi_attribs", "sfi_attribs" }, + { 0, NHTYPE_COMPLEX, "sfi_bill_x", "sfi_bill_x" }, + { 0, NHTYPE_COMPLEX, "sfi_book_info", "sfi_book_info" }, + { 0, NHTYPE_COMPLEX, "sfi_branch", "sfi_branch" }, + { 0, NHTYPE_COMPLEX, "sfi_bubble", "sfi_bubble" }, + { 0, NHTYPE_COMPLEX, "sfi_cemetery", "sfi_cemetery" }, + { 0, NHTYPE_COMPLEX, "sfi_context_info", "sfi_context_info" }, + { 0, NHTYPE_COMPLEX, "sfi_d_flags", "sfi_d_flags" }, + { 0, NHTYPE_COMPLEX, "sfi_d_level", "sfi_d_level" }, + { 0, NHTYPE_COMPLEX, "sfi_damage", "sfi_damage" }, + { 0, NHTYPE_COMPLEX, "sfi_dest_area", "sfi_dest_area" }, + { 0, NHTYPE_COMPLEX, "sfi_dgn_topology", "sfi_dgn_topology" }, + { 0, NHTYPE_COMPLEX, "sfi_dig_info", "sfi_dig_info" }, + { 0, NHTYPE_COMPLEX, "sfi_dungeon", "sfi_dungeon" }, + { 0, NHTYPE_COMPLEX, "sfi_ebones", "sfi_ebones" }, + { 0, NHTYPE_COMPLEX, "sfi_edog", "sfi_edog" }, + { 0, NHTYPE_COMPLEX, "sfi_egd", "sfi_egd" }, + { 0, NHTYPE_COMPLEX, "sfi_emin", "sfi_emin" }, + { 0, NHTYPE_COMPLEX, "sfi_engr", "sfi_engr" }, + { 0, NHTYPE_COMPLEX, "sfi_engrave_info", "sfi_engrave_info" }, + { 0, NHTYPE_COMPLEX, "sfi_epri", "sfi_epri" }, + { 0, NHTYPE_COMPLEX, "sfi_eshk", "sfi_eshk" }, + { 0, NHTYPE_COMPLEX, "sfi_fakecorridor", "sfi_fakecorridor" }, + { 0, NHTYPE_COMPLEX, "sfi_fe", "sfi_fe" }, + { 0, NHTYPE_COMPLEX, "sfi_flag", "sfi_flag" }, + { 0, NHTYPE_COMPLEX, "sfi_fruit", "sfi_fruit" }, + { 0, NHTYPE_COMPLEX, "sfi_kinfo", "sfi_kinfo" }, + { 0, NHTYPE_COMPLEX, "sfi_levelflags", "sfi_levelflags" }, + { 0, NHTYPE_COMPLEX, "sfi_linfo", "sfi_linfo" }, + { 0, NHTYPE_COMPLEX, "sfi_ls_t", "sfi_ls_t" }, + { 0, NHTYPE_COMPLEX, "sfi_mapseen", "sfi_mapseen" }, + { 0, NHTYPE_COMPLEX, "sfi_mapseen_feat", "sfi_mapseen_feat" }, + { 0, NHTYPE_COMPLEX, "sfi_mapseen_flags", "sfi_mapseen_flags" }, + { 0, NHTYPE_COMPLEX, "sfi_mapseen_rooms", "sfi_mapseen_rooms" }, + { 0, NHTYPE_COMPLEX, "sfi_mextra", "sfi_mextra" }, + { 0, NHTYPE_COMPLEX, "sfi_mkroom", "sfi_mkroom" }, + { 0, NHTYPE_COMPLEX, "sfi_monst", "sfi_monst" }, + { 0, NHTYPE_COMPLEX, "sfi_mvitals", "sfi_mvitals" }, + { 0, NHTYPE_COMPLEX, "sfi_nhcoord", "sfi_nhcoord" }, + { 0, NHTYPE_COMPLEX, "sfi_nhrect", "sfi_nhrect" }, + { 0, NHTYPE_COMPLEX, "sfi_novel_tracking", "sfi_novel_tracking" }, + { 0, NHTYPE_COMPLEX, "sfi_obj", "sfi_obj" }, + { 0, NHTYPE_COMPLEX, "sfi_obj_split", "sfi_obj_split" }, + { 0, NHTYPE_COMPLEX, "sfi_objclass", "sfi_objclass" }, + { 0, NHTYPE_COMPLEX, "sfi_oextra", "sfi_oextra" }, + { 0, NHTYPE_COMPLEX, "sfi_polearm_info", "sfi_polearm_info" }, + { 0, NHTYPE_COMPLEX, "sfi_prop", "sfi_prop" }, + { 0, NHTYPE_COMPLEX, "sfi_q_score", "sfi_q_score" }, + { 0, NHTYPE_COMPLEX, "sfi_rm", "sfi_rm" }, + { 0, NHTYPE_COMPLEX, "sfi_s_level", "sfi_s_level" }, + { 0, NHTYPE_COMPLEX, "sfi_skills", "sfi_skills" }, + { 0, NHTYPE_COMPLEX, "sfi_spell", "sfi_spell" }, + { 0, NHTYPE_COMPLEX, "sfi_stairway", "sfi_stairway" }, + { 0, NHTYPE_COMPLEX, "sfi_takeoff_info", "sfi_takeoff_info" }, + { 0, NHTYPE_COMPLEX, "sfi_tin_info", "sfi_tin_info" }, + { 0, NHTYPE_COMPLEX, "sfi_trap", "sfi_trap" }, + { 0, NHTYPE_COMPLEX, "sfi_tribute_info", "sfi_tribute_info" }, + { 0, NHTYPE_COMPLEX, "sfi_u_conduct", "sfi_u_conduct" }, + { 0, NHTYPE_COMPLEX, "sfi_u_event", "sfi_u_event" }, + { 0, NHTYPE_COMPLEX, "sfi_u_have", "sfi_u_have" }, + { 0, NHTYPE_COMPLEX, "sfi_u_realtime", "sfi_u_realtime" }, + { 0, NHTYPE_COMPLEX, "sfi_u_roleplay", "sfi_u_roleplay" }, + { 0, NHTYPE_COMPLEX, "sfi_version_info", "sfi_version_info" }, + { 0, NHTYPE_COMPLEX, "sfi_victual_info", "sfi_victual_info" }, + { 0, NHTYPE_COMPLEX, "sfi_vlaunchinfo", "sfi_vlaunchinfo" }, + { 0, NHTYPE_COMPLEX, "sfi_vptrs", "sfi_vptrs" }, + { 0, NHTYPE_COMPLEX, "sfi_warntype_info", "sfi_warntype_info" }, + { 0, NHTYPE_COMPLEX, "sfi_you", "sfi_you" }, + { 0, NHTYPE_COMPLEX, "sfo_achievement_tracking", + "sfo_achievement_tracking" }, + { 0, NHTYPE_COMPLEX, "sfo_align", "sfo_align" }, + { 0, NHTYPE_COMPLEX, "sfo_attribs", "sfo_attribs" }, + { 0, NHTYPE_COMPLEX, "sfo_bill_x", "sfo_bill_x" }, + { 0, NHTYPE_COMPLEX, "sfo_book_info", "sfo_book_info" }, + { 0, NHTYPE_COMPLEX, "sfo_branch", "sfo_branch" }, + { 0, NHTYPE_COMPLEX, "sfo_bubble", "sfo_bubble" }, + { 0, NHTYPE_COMPLEX, "sfo_cemetery", "sfo_cemetery" }, + { 0, NHTYPE_COMPLEX, "sfo_context_info", "sfo_context_info" }, + { 0, NHTYPE_COMPLEX, "sfo_d_flags", "sfo_d_flags" }, + { 0, NHTYPE_COMPLEX, "sfo_d_level", "sfo_d_level" }, + { 0, NHTYPE_COMPLEX, "sfo_damage", "sfo_damage" }, + { 0, NHTYPE_COMPLEX, "sfo_dest_area", "sfo_dest_area" }, + { 0, NHTYPE_COMPLEX, "sfo_dgn_topology", "sfo_dgn_topology" }, + { 0, NHTYPE_COMPLEX, "sfo_dig_info", "sfo_dig_info" }, + { 0, NHTYPE_COMPLEX, "sfo_dungeon", "sfo_dungeon" }, + { 0, NHTYPE_COMPLEX, "sfo_ebones", "sfo_ebones" }, + { 0, NHTYPE_COMPLEX, "sfo_edog", "sfo_edog" }, + { 0, NHTYPE_COMPLEX, "sfo_egd", "sfo_egd" }, + { 0, NHTYPE_COMPLEX, "sfo_emin", "sfo_emin" }, + { 0, NHTYPE_COMPLEX, "sfo_engr", "sfo_engr" }, + { 0, NHTYPE_COMPLEX, "sfo_engrave_info", "sfo_engrave_info" }, + { 0, NHTYPE_COMPLEX, "sfo_epri", "sfo_epri" }, + { 0, NHTYPE_COMPLEX, "sfo_eshk", "sfo_eshk" }, + { 0, NHTYPE_COMPLEX, "sfo_fakecorridor", "sfo_fakecorridor" }, + { 0, NHTYPE_COMPLEX, "sfo_fe", "sfo_fe" }, + { 0, NHTYPE_COMPLEX, "sfo_flag", "sfo_flag" }, + { 0, NHTYPE_COMPLEX, "sfo_fruit", "sfo_fruit" }, + { 0, NHTYPE_COMPLEX, "sfo_kinfo", "sfo_kinfo" }, + { 0, NHTYPE_COMPLEX, "sfo_levelflags", "sfo_levelflags" }, + { 0, NHTYPE_COMPLEX, "sfo_linfo", "sfo_linfo" }, + { 0, NHTYPE_COMPLEX, "sfo_ls_t", "sfo_ls_t" }, + { 0, NHTYPE_COMPLEX, "sfo_mapseen", "sfo_mapseen" }, + { 0, NHTYPE_COMPLEX, "sfo_mapseen_feat", "sfo_mapseen_feat" }, + { 0, NHTYPE_COMPLEX, "sfo_mapseen_flags", "sfo_mapseen_flags" }, + { 0, NHTYPE_COMPLEX, "sfo_mapseen_rooms", "sfo_mapseen_rooms" }, + { 0, NHTYPE_COMPLEX, "sfo_mextra", "sfo_mextra" }, + { 0, NHTYPE_COMPLEX, "sfo_mkroom", "sfo_mkroom" }, + { 0, NHTYPE_COMPLEX, "sfo_monst", "sfo_monst" }, + { 0, NHTYPE_COMPLEX, "sfo_mvitals", "sfo_mvitals" }, + { 0, NHTYPE_COMPLEX, "sfo_nhcoord", "sfo_nhcoord" }, + { 0, NHTYPE_COMPLEX, "sfo_nhrect", "sfo_nhrect" }, + { 0, NHTYPE_COMPLEX, "sfo_novel_tracking", "sfo_novel_tracking" }, + { 0, NHTYPE_COMPLEX, "sfo_obj", "sfo_obj" }, + { 0, NHTYPE_COMPLEX, "sfo_obj_split", "sfo_obj_split" }, + { 0, NHTYPE_COMPLEX, "sfo_objclass", "sfo_objclass" }, + { 0, NHTYPE_COMPLEX, "sfo_oextra", "sfo_oextra" }, + { 0, NHTYPE_COMPLEX, "sfo_polearm_info", "sfo_polearm_info" }, + { 0, NHTYPE_COMPLEX, "sfo_prop", "sfo_prop" }, + { 0, NHTYPE_COMPLEX, "sfo_q_score", "sfo_q_score" }, + { 0, NHTYPE_COMPLEX, "sfo_rm", "sfo_rm" }, + { 0, NHTYPE_COMPLEX, "sfo_s_level", "sfo_s_level" }, + { 0, NHTYPE_COMPLEX, "sfo_skills", "sfo_skills" }, + { 0, NHTYPE_COMPLEX, "sfo_spell", "sfo_spell" }, + { 0, NHTYPE_COMPLEX, "sfo_stairway", "sfo_stairway" }, + { 0, NHTYPE_COMPLEX, "sfo_takeoff_info", "sfo_takeoff_info" }, + { 0, NHTYPE_COMPLEX, "sfo_tin_info", "sfo_tin_info" }, + { 0, NHTYPE_COMPLEX, "sfo_trap", "sfo_trap" }, + { 0, NHTYPE_COMPLEX, "sfo_tribute_info", "sfo_tribute_info" }, + { 0, NHTYPE_COMPLEX, "sfo_u_conduct", "sfo_u_conduct" }, + { 0, NHTYPE_COMPLEX, "sfo_u_event", "sfo_u_event" }, + { 0, NHTYPE_COMPLEX, "sfo_u_have", "sfo_u_have" }, + { 0, NHTYPE_COMPLEX, "sfo_u_realtime", "sfo_u_realtime" }, + { 0, NHTYPE_COMPLEX, "sfo_u_roleplay", "sfo_u_roleplay" }, + { 0, NHTYPE_COMPLEX, "sfo_version_info", "sfo_version_info" }, + { 0, NHTYPE_COMPLEX, "sfo_victual_info", "sfo_victual_info" }, + { 0, NHTYPE_COMPLEX, "sfo_vlaunchinfo", "sfo_vlaunchinfo" }, + { 0, NHTYPE_COMPLEX, "sfo_vptrs", "sfo_vptrs" }, + { 0, NHTYPE_COMPLEX, "sfo_warntype_info", "sfo_warntype_info" }, + { 0, NHTYPE_COMPLEX, "sfo_you", "sfo_you" }, + { 0, NHTYPE_SIMPLE, "sfi_any", "sfi_any" }, + { 0, NHTYPE_SIMPLE, "sfi_aligntyp", "Sfi_aligntyp" }, + { 0, NHTYPE_SIMPLE, "sfi_Bitfield", "Sfi_Bitfield" }, + { 0, NHTYPE_SIMPLE, "sfi_boolean", "Sfi_boolean" }, + { 0, NHTYPE_SIMPLE, "sfi_char", "Sfi_char" }, + { 0, NHTYPE_SIMPLE, "sfi_coordxy", "Sfi_Coordxy" }, + { 0, NHTYPE_SIMPLE, "sfi_int", "Sfi_int32" }, + { 0, NHTYPE_SIMPLE, "sfi_long", "Sfi_long" }, + { 0, NHTYPE_SIMPLE, "sfi_schar", "Sfi_schar" }, + { 0, NHTYPE_SIMPLE, "sfi_short", "Sfi_int16" }, + { 0, NHTYPE_SIMPLE, "sfi_size_t", "Sfi_size_t" }, + { 0, NHTYPE_SIMPLE, "sfi_string", "Sfi_string" }, + { 0, NHTYPE_SIMPLE, "sfi_time_t", "Sfi_time_t" }, + { 0, NHTYPE_SIMPLE, "sfi_uchar", "Sfi_uchar" }, + { 0, NHTYPE_SIMPLE, "sfi_unsigned", "Sfi_uint32" }, + { 0, NHTYPE_SIMPLE, "sfi_xint16", "Sfi_int16" }, + { 0, NHTYPE_SIMPLE, "sfi_xint8", "Sfi_xint8" }, + { 0, NHTYPE_SIMPLE, "sfo_aligntyp", "Sfo_aligntyp" }, + { 0, NHTYPE_SIMPLE, "sfo_any", "Sfo_any" }, + { 0, NHTYPE_SIMPLE, "sfo_Bitfield", "Sfo_Bitfield" }, + { 0, NHTYPE_SIMPLE, "sfo_boolean", "Sfo_boolean" }, + { 0, NHTYPE_SIMPLE, "sfo_char", "Sfo_char" }, + { 0, NHTYPE_SIMPLE, "sfo_coordxy", "Sfo_coordxy" }, + { 0, NHTYPE_SIMPLE, "sfo_int", "Sfo_int32" }, + { 0, NHTYPE_SIMPLE, "sfo_long", "sfo_long" }, + { 0, NHTYPE_SIMPLE, "sfo_schar", "Sfo_schar" }, + { 0, NHTYPE_SIMPLE, "sfo_short", "Sfo_short" }, + { 0, NHTYPE_SIMPLE, "sfo_size_t", "Sfo_size_t" }, + { 0, NHTYPE_SIMPLE, "sfo_string", "Sfo_string" }, + { 0, NHTYPE_SIMPLE, "sfo_time_t", "Sfo_time_t" }, + { 0, NHTYPE_SIMPLE, "sfo_uchar", "Sfo_uchar" }, + { 0, NHTYPE_SIMPLE, "sfo_unsigned", "Sfo_uint32" }, + { 0, NHTYPE_SIMPLE, "sfo_xint16", "Sfo_int16" }, + { 0, NHTYPE_SIMPLE, "sfo_xint8", "Sfo_xint8" } +}; + + /*sftags.c*/ + + From 92f4e191d9d33c396190bdf239e92795ba21ceaa Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 25 May 2025 20:47:33 -0400 Subject: [PATCH 646/791] follow-up: fix a warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit files.c:2004:28: warning: unused parameter ‘filename’ [-Wunused-parameter] 2004 | doconvert_file(const char *filename, int sfstatus, boolean unconvert) | ~~~~~~~~~~~~^~~~~~~~ --- src/files.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/files.c b/src/files.c index 821b1cff8..f69189f66 100644 --- a/src/files.c +++ b/src/files.c @@ -2003,6 +2003,7 @@ static char *unconverted_filename = 0, *converted_filename = 0; staticfn int doconvert_file(const char *filename, int sfstatus, boolean unconvert) { + nhUse(filename); nhUse(sfstatus); nhUse(unconvert); return 1; From aa5c325bd4ae3d964b91bedc61242bc620c86014 Mon Sep 17 00:00:00 2001 From: nhw_cron Date: Sun, 25 May 2025 21:24:08 -0400 Subject: [PATCH 647/791] This is cron-daily v1-Apr-1-2024. 000files updated: Files --- Files | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/Files b/Files index d9bc79d18..07b39a821 100644 --- a/Files +++ b/Files @@ -449,7 +449,7 @@ config.props console.props cpp.hint default.props default_dll.props default_lib.props dirs.props dll.props -files.props +files.props sfctool.sln sys/windows/vs/FetchPrereq: (files for Visual Studio 2019 or 2022 Community Edition builds) @@ -530,6 +530,10 @@ sys/windows/vs/dlb: (files for Visual Studio 2019 or 2022 Community Edition builds) afterdlb.proj dlb.vcxproj +sys/windows/vs/fetchctags: +(files for Visual Studio 2019 or 2022 Community Edition builds) +fetchctags.nmake fetchctags.vcxproj + sys/windows/vs/hacklib: (file for Visual Studio 2019 or 2022 Community Edition builds) hacklib.vcxproj @@ -550,6 +554,14 @@ sys/windows/vs/recover: (files for Visual Studio 2019 or 2022 Community Edition builds) afterrecover.proj recover.vcxproj +sys/windows/vs/sfctool: +(file for Visual Studio 2019 or 2022 Community Edition builds) +sfctool.vcxproj + +sys/windows/vs/sftags: +(files for Visual Studio 2019 or 2022 Community Edition builds) +aftersftags.proj sftags.vcxproj + sys/windows/vs/tile2bmp: (files for Visual Studio 2019 or 2022 Community Edition builds) aftertile2bmp.proj tile2bmp.vcxproj @@ -574,7 +586,7 @@ test_sel.lua test_shk.lua test_src.lua testmove.lua testwish.lua util: (files for all versions) dlb_main.c makedefs.c mdgrep.h mdgrep.pl panic.c recover.c -stripbs.c +sfctool.c sfexpasc.c sftags.c stripbs.c win/Qt: (files for the Qt 4 or 5 widget library - X11, Windows, Mac OS X) From 86a7bfa7e9c5ea52f9d35152900cdf0978dda1e2 Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 26 May 2025 11:50:23 -0400 Subject: [PATCH 648/791] Windows visual studio vs gcc long and ulong The visual studio compiler behaves diffently with _Generic than with gcc on Linux _Generic around long and ulong. On Windows they aren't recognized as one of the stdint types. On Linux gcc, it considers them equivalent to int64_t and uint64_t. Leave it out of the _Generic to avoid the behaviour difference between platforms/compilers. --- include/savefile.h | 18 ++++++------------ src/sfbase.c | 8 ++------ 2 files changed, 8 insertions(+), 18 deletions(-) diff --git a/include/savefile.h b/include/savefile.h index 8a4c51cf3..f96c041c0 100644 --- a/include/savefile.h +++ b/include/savefile.h @@ -249,8 +249,6 @@ extern void sfi_ulong(NHFILE *, ulong *, const char *); #define Sfo_ushort(a, b, c) sfo_ushort(a, b, c) #define Sfo_int(a, b, c) sfo_int(a, b, c) #define Sfo_unsigned(a, b, c) sfo_unsigned(a, b, c) -#define Sfo_long(a,b,c) sfo_long(a, b, c); -#define Sfo_ulong(a,b,c) sfo_ulong(a, b, c); #define Sfo_boolean(a,b,c) sfo_boolean(a, b, c); #define Sfo_xint8(a, b, c) sfo_xint8(a, b, c); #define Sfo_xint16(a, b, c) sfo_xint16(a, b, c) @@ -319,8 +317,6 @@ extern void sfi_ulong(NHFILE *, ulong *, const char *); #define Sfi_ushort(a, b, c) sfi_ushort(a, b, c) #define Sfi_int(a, b, c) sfi_int(a, b, c); #define Sfi_unsigned(a, b, c) sfi_unsigned(a, b, c); -#define Sfi_long(a,b,c) sfi_long(a, b, c); -#define Sfi_ulong(a,b,c) sfi_ulong(a, b, c); #define Sfi_boolean(a,b,c) sfi_boolean(a, b, c); #define Sfi_xint8(a, b, c) sfi_xint8(a, b, c); #define Sfi_xint16(a, b, c) sfi_xint16(a, b, c); @@ -336,8 +332,6 @@ extern void sfi_ulong(NHFILE *, ulong *, const char *); uint16_t * : sfo_uint16, \ uint32_t * : sfo_uint32, \ uint64_t * : sfo_uint64, \ - long * : sfo_long, \ - unsigned long * : sfo_ulong, \ xint8 * : sfo_xint8, \ struct arti_info * : sfo_arti_info, \ struct nhrect * : sfo_nhrect, \ @@ -400,8 +394,6 @@ extern void sfi_ulong(NHFILE *, ulong *, const char *); uint16_t * : sfi_uint16, \ uint32_t * : sfi_uint32, \ uint64_t * : sfi_uint64, \ - long * : sfi_long, \ - unsigned long * : sfi_ulong, \ xint8 * : sfi_xint8, \ struct arti_info * : sfi_arti_info, \ struct nhrect * : sfi_nhrect, \ @@ -520,11 +512,12 @@ extern void sfi_ulong(NHFILE *, ulong *, const char *); #define Sfo_ushort(a, b, c) sfo(a, b, c) #define Sfo_int(a, b, c) sfo(a, b, c) #define Sfo_unsigned(a, b, c) sfo(a, b, c) -#define Sfo_long(a,b,c) sfo(a, b, c) -#define Sfo_ulong(a,b,c) sfo(a, b, c) #define Sfo_xint8(a, b, c) sfo(a, b, c) #define Sfo_xint16(a, b, c) sfo(a, b, c) + /* not in _Generic */ +#define Sfo_long(a,b,c) sfo_long(a, b, c); +#define Sfo_ulong(a,b,c) sfo_ulong(a, b, c); #define Sfo_char(a,b,c,d) sfo_char(a, b, c, d) #define Sfo_boolean(a,b,c) sfo_boolean(a, b, c) #define Sfo_schar(a,b,c) sfo_schar(a, b, c) @@ -591,11 +584,12 @@ extern void sfi_ulong(NHFILE *, ulong *, const char *); #define Sfi_ushort(a, b, c) sfi(a, b, c) #define Sfi_int(a,b,c) sfi(a, b, c) #define Sfi_unsigned(a, b, c) sfi(a, b, c) -#define Sfi_long(a,b,c) sfi(a, b, c) -#define Sfi_ulong(a,b,c) sfi(a, b, c) #define Sfi_xint8(a, b, c) sfi(a, b, c) #define Sfi_xint16(a, b, c) sfi(a, b, c) + /* not in _Generic */ +#define Sfi_long(a,b,c) sfi_long(a, b, c); +#define Sfi_ulong(a,b,c) sfi_ulong(a, b, c); #define Sfi_char(a,b,c,d) sfi_char(a, b, c, d) #define Sfi_boolean(a,b,c) sfi_boolean(a, b, c) #define Sfi_schar(a,b,c) sfi_schar(a, b, c) diff --git a/src/sfbase.c b/src/sfbase.c index 580f5f001..30924d754 100644 --- a/src/sfbase.c +++ b/src/sfbase.c @@ -65,8 +65,6 @@ void sf_log(NHFILE *, const char *, size_t, int, char *); #define Sfvalue_ushort(a) sfvalue_ushort(a) #define Sfvalue_int(a) sfvalue_int(a) #define Sfvalue_unsigned(a) sfvalue_unsigned(a) -#define Sfvalue_long(a) sfvalue_long(a) -#define Sfvalue_ulong(a) sfvalue_ulong(a) #define Sfvalue_xint8(a) sfvalue_xint8(a) #define Sfvalue_xint16(a) sfvalue_xint16(a) @@ -83,8 +81,6 @@ void sf_log(NHFILE *, const char *, size_t, int, char *); uint16_t *: sfvalue_uint16, \ uint32_t *: sfvalue_uint32, \ uint64_t *: sfvalue_uint64, \ - long *: sfvalue_long, \ - unsigned long *: sfvalue_ulong, \ xint8 *: sfvalue_xint8 \ )(x) @@ -107,13 +103,13 @@ void sf_log(NHFILE *, const char *, size_t, int, char *); #define Sfvalue_ushort(a) sfvalue(a) #define Sfvalue_int(a) sfvalue(a) #define Sfvalue_unsigned(a) sfvalue(a) -#define Sfvalue_long(a) sfvalue(a) -#define Sfvalue_ulong(a) sfvalue(a) #define Sfvalue_xint8(a) sfvalue(a) #define Sfvalue_xint16(a) sfvalue(a) #endif /* not in _Generic */ +#define Sfvalue_long(a) sfvalue_long(a) +#define Sfvalue_ulong(a) sfvalue_ulong(a) #define Sfvalue_char(a, d) sfvalue_char(a, d) #define Sfvalue_boolean(a) sfvalue_boolean(a) #define Sfvalue_schar(a) sfvalue_schar(a) From b303f91f3ab93cfe296b1822b7aef4f707e40c47 Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 26 May 2025 12:56:44 -0400 Subject: [PATCH 649/791] engraving pristine text field not properly filled level creation was not populating the pristine text field of engraving appropriately --- doc/fixes3-7-0.txt | 2 ++ include/extern.h | 4 ++-- src/engrave.c | 25 ++++++++++++++++++------- src/mklev.c | 8 ++++---- src/shknam.c | 2 +- src/sp_lev.c | 2 +- src/zap.c | 5 +++-- 7 files changed, 31 insertions(+), 17 deletions(-) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index 7aff12fb6..c1c24371f 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -1515,6 +1515,8 @@ Fire and Frost Brand can be invoked for expert level fireball or cone of cold wielding Trollsbane grants hungerless regeneration hitting with Ogresmasher gives a higher chance of knockback Snickersnee can hit at a distance once per turn for free +the engraving pristine text field was not being appropriately populated during + level creation Fixes to 3.7.0-x General Problems Exposed Via git Repository diff --git a/include/extern.h b/include/extern.h index b3e2c0949..533523198 100644 --- a/include/extern.h +++ b/include/extern.h @@ -975,7 +975,7 @@ extern char *build_english_list(char *) NONNULLARG1; /* ### engrave.c ### */ -extern char *random_engraving(char *) NONNULLARG1; +extern char *random_engraving(char *, char *) NONNULLARG12; extern void wipeout_text(char *, int, unsigned) NONNULLARG1; extern boolean can_reach_floor(boolean); extern void cant_reach_floor(coordxy, coordxy, boolean, boolean); @@ -984,7 +984,7 @@ extern struct engr *sengr_at(const char *, coordxy, coordxy, boolean) NONNULLARG extern void u_wipe_engr(int); extern void wipe_engr_at(coordxy, coordxy, xint16, boolean); extern void read_engr_at(coordxy, coordxy); -extern void make_engr_at(coordxy, coordxy, const char *, long, int) NONNULLARG3; +extern void make_engr_at(coordxy, coordxy, const char *, const char *, long, int) NONNULLARG3; extern void del_engr_at(coordxy, coordxy); extern int freehand(void); extern int doengrave(void); diff --git a/src/engrave.c b/src/engrave.c index 9d598e341..226f6b30b 100644 --- a/src/engrave.c +++ b/src/engrave.c @@ -48,15 +48,16 @@ staticfn int engrave(void); staticfn const char *blengr(void); char * -random_engraving(char *outbuf) +random_engraving(char *outbuf, char *pristine_copy) { const char *rumor; /* a random engraving may come from the "rumors" file, or from the "engrave" file (formerly in an array here) */ - if (!rn2(4) || !(rumor = getrumor(0, outbuf, TRUE)) || !*rumor) - (void) get_rnd_text(ENGRAVEFILE, outbuf, rn2, MD_PAD_RUMORS); + if (!rn2(4) || !(rumor = getrumor(0, pristine_copy, TRUE)) || !*rumor) + (void) get_rnd_text(ENGRAVEFILE, pristine_copy, rn2, MD_PAD_RUMORS); + Strcpy(outbuf, pristine_copy); wipeout_text(outbuf, (int) (strlen(outbuf) / 4), 0); return outbuf; } @@ -391,13 +392,21 @@ void make_engr_at( coordxy x, coordxy y, const char *s, + const char *pristine_s, long e_time, int e_type) { int i; struct engr *ep; unsigned smem = Strlen(s) + 1; + boolean havepristine = FALSE; + if (pristine_s != NULL) { + unsigned prmem = Strlen(pristine_s) + 1; + if (prmem > smem) + smem = prmem; + havepristine = TRUE; + } if ((ep = engr_at(x, y)) != 0) del_engr(ep); @@ -412,6 +421,8 @@ make_engr_at( ep->engr_txt[pristine_text] = ep->engr_txt[remembered_text] + smem; for(i = 0; i < text_states; ++i) Strcpy(ep->engr_txt[i], s); + if (havepristine) + Strcpy(ep->engr_txt[pristine_text], pristine_s); if (!strcmp(s, "Elbereth")) { /* engraving "Elbereth": if done when making a level, it creates an old-style Elbereth that deters monsters when any objects are @@ -591,7 +602,7 @@ doengrave_sfx_item_WAN(struct _doengrave_ctx *de) if (de->oep) { if (!Blind) { de->type = (xint16) 0; /* random */ - (void) random_engraving(de->buf); + (void) random_engraving(de->buf, de->ebuf); } else { /* keep the same type so that feels don't change and only the text is altered, @@ -1036,7 +1047,7 @@ doengrave(void) if (*de->buf) { struct engr *tmp_ep; - make_engr_at(u.ux, u.uy, de->buf, svm.moves, de->type); + make_engr_at(u.ux, u.uy, de->buf, de->ebuf, svm.moves, de->type); tmp_ep = engr_at(u.ux, u.uy); if (!Blind) { if (tmp_ep != 0) { @@ -1422,7 +1433,7 @@ engrave(void) (void) strncat(buf, svc.context.engraving.nextc, min(space_left, endc - svc.context.engraving.nextc)); - make_engr_at(u.ux, u.uy, buf, svm.moves - gm.multi, + make_engr_at(u.ux, u.uy, buf, NULL, svm.moves - gm.multi, svc.context.engraving.type); oep = engr_at(u.ux, u.uy); if (oep) { @@ -1662,7 +1673,7 @@ make_grave(coordxy x, coordxy y, const char *str) del_engr_at(x, y); if (!str) str = get_rnd_text(EPITAPHFILE, buf, rn2, MD_PAD_RUMORS); - make_engr_at(x, y, str, 0L, HEADSTONE); + make_engr_at(x, y, str, NULL, 0L, HEADSTONE); return; } diff --git a/src/mklev.c b/src/mklev.c index bab79e46d..a455639c6 100644 --- a/src/mklev.c +++ b/src/mklev.c @@ -763,7 +763,7 @@ makeniche(int trap_type) ttmp->once = 1; if (trap_engravings[trap_type]) { make_engr_at(xx, yy - dy, - trap_engravings[trap_type], 0L, + trap_engravings[trap_type], NULL, 0L, DUST); wipe_engr_at(xx, yy - dy, 5, FALSE); /* age it a little */ @@ -1136,8 +1136,8 @@ fill_ordinary_room( /* maybe make some graffiti */ if (!rn2(27 + 3 * abs(depth(&u.uz)))) { - char buf[BUFSZ]; - const char *mesg = random_engraving(buf); + char buf[BUFSZ], pristinebuf[BUFSZ]; + const char *mesg = random_engraving(buf, pristinebuf); if (mesg) { do { @@ -1146,7 +1146,7 @@ fill_ordinary_room( y = pos.y; } while (levl[x][y].typ != ROOM && !rn2(40)); if (levl[x][y].typ == ROOM) - make_engr_at(x, y, mesg, 0L, MARK); + make_engr_at(x, y, mesg, pristinebuf, 0L, MARK); } } diff --git a/src/shknam.c b/src/shknam.c index 58a45ceea..ecf12f938 100644 --- a/src/shknam.c +++ b/src/shknam.c @@ -755,7 +755,7 @@ stock_room(int shp_indx, struct mkroom *sroom) else if (inside_shop(sx, sy - 1)) n++; Sprintf(buf, "Closed for inventory"); - make_engr_at(m, n, buf, 0L, DUST); + make_engr_at(m, n, buf, NULL, 0L, DUST); if (levl[m][n].typ != CORR && levl[m][n].typ != ROOM) levl[m][n].typ = (Is_special(&u.uz) || *in_rooms(m, n, 0)) ? ROOM : CORR; diff --git a/src/sp_lev.c b/src/sp_lev.c index e9064f10d..3bccc196c 100644 --- a/src/sp_lev.c +++ b/src/sp_lev.c @@ -3912,7 +3912,7 @@ lspo_engraving(lua_State *L) ecoord = SP_COORD_PACK(x, y); get_location_coord(&x, &y, DRY, gc.coder->croom, ecoord); - make_engr_at(x, y, txt, 0L, etyp); + make_engr_at(x, y, txt, NULL, 0L, etyp); Free(txt); ep = engr_at(x, y); if (ep) { diff --git a/src/zap.c b/src/zap.c index e1d199035..a6935402f 100644 --- a/src/zap.c +++ b/src/zap.c @@ -3628,7 +3628,7 @@ zap_map( ttmp = t_at(x, y); /* refresh in case trap was altered or is gone */ if (u.dz > 0) { /* zapping down */ - char ebuf[BUFSZ]; + char ebuf[BUFSZ], pristinebuf[BUFSZ], *etxt; struct engr *e = engr_at(x, y); /* subset of engraving effects; none sets `disclose' */ @@ -3637,7 +3637,8 @@ zap_map( case WAN_POLYMORPH: case SPE_POLYMORPH: del_engr(e); - make_engr_at(x, y, random_engraving(ebuf), svm.moves, 0); + etxt = random_engraving(ebuf, pristinebuf); + make_engr_at(x, y, etxt, pristinebuf, svm.moves, 0); break; case WAN_CANCELLATION: case SPE_CANCELLATION: From 1d42aaf96a0bd741737d755daea2dd623da8e711 Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 26 May 2025 13:18:32 -0400 Subject: [PATCH 650/791] follow-up build fix --- include/savefile.h | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/include/savefile.h b/include/savefile.h index f96c041c0..dc569c771 100644 --- a/include/savefile.h +++ b/include/savefile.h @@ -244,12 +244,10 @@ extern void sfi_ulong(NHFILE *, ulong *, const char *); #define Sfo_gamelog_line(a,b,c) sfo_gamelog_line(a, b, c) #define Sfo_fruit(a,b,c) sfo_fruit(a, b, c) #define Sfo_s_level(a,b,c) sfo_s_level(a, b, c) -#define Sfo_schar(a,b,c) sfo_schar(a, b, c); #define Sfo_short(a, b, c) sfo_short(a, b, c) #define Sfo_ushort(a, b, c) sfo_ushort(a, b, c) #define Sfo_int(a, b, c) sfo_int(a, b, c) #define Sfo_unsigned(a, b, c) sfo_unsigned(a, b, c) -#define Sfo_boolean(a,b,c) sfo_boolean(a, b, c); #define Sfo_xint8(a, b, c) sfo_xint8(a, b, c); #define Sfo_xint16(a, b, c) sfo_xint16(a, b, c) /* sfbase.c input functions */ @@ -258,7 +256,6 @@ extern void sfi_ulong(NHFILE *, ulong *, const char *); #define Sfi_any(a,b,c) sfi_any(a, b, c) #define Sfi_genericptr(a,b,c) sfi_genericptr(a, b, c) #define Sfi_coordxy(a,b,c) sfi_int16(a, b, c) -#define Sfi_char(a,b,c,d) sfi_char(a, b, c, d) #define Sfi_int16(a,b,c) sfi_int16(a, b, c) #define Sfi_int32(a,b,c) sfi_int32(a, b, c) #define Sfi_int64(a,b,c) sfi_int64(a, b, c) @@ -312,12 +309,10 @@ extern void sfi_ulong(NHFILE *, ulong *, const char *); #define Sfi_fruit(a,b,c) sfi_fruit(a, b, c) #define Sfi_gamelog_line(a,b,c) sfi_gamelog_line(a, b, c) #define Sfi_s_level(a,b,c) sfi_s_level(a, b, c) -#define Sfi_schar(a,b,c) sfi_schar(a, b, c); #define Sfi_short(a, b, c) sfi_short(a, b, c) #define Sfi_ushort(a, b, c) sfi_ushort(a, b, c) #define Sfi_int(a, b, c) sfi_int(a, b, c); #define Sfi_unsigned(a, b, c) sfi_unsigned(a, b, c); -#define Sfi_boolean(a,b,c) sfi_boolean(a, b, c); #define Sfi_xint8(a, b, c) sfi_xint8(a, b, c); #define Sfi_xint16(a, b, c) sfi_xint16(a, b, c); #else @@ -515,12 +510,6 @@ extern void sfi_ulong(NHFILE *, ulong *, const char *); #define Sfo_xint8(a, b, c) sfo(a, b, c) #define Sfo_xint16(a, b, c) sfo(a, b, c) -/* not in _Generic */ -#define Sfo_long(a,b,c) sfo_long(a, b, c); -#define Sfo_ulong(a,b,c) sfo_ulong(a, b, c); -#define Sfo_char(a,b,c,d) sfo_char(a, b, c, d) -#define Sfo_boolean(a,b,c) sfo_boolean(a, b, c) -#define Sfo_schar(a,b,c) sfo_schar(a, b, c) /* sfbase.c input functions */ #define Sfi_addinfo(a,b,c) sfi(a, b, c) #define Sfi_aligntyp(a,b,c) sfi(a, b, c) @@ -586,14 +575,20 @@ extern void sfi_ulong(NHFILE *, ulong *, const char *); #define Sfi_unsigned(a, b, c) sfi(a, b, c) #define Sfi_xint8(a, b, c) sfi(a, b, c) #define Sfi_xint16(a, b, c) sfi(a, b, c) +#endif /* not in _Generic */ +#define Sfo_long(a,b,c) sfo_long(a, b, c); +#define Sfo_ulong(a,b,c) sfo_ulong(a, b, c); +#define Sfo_char(a,b,c,d) sfo_char(a, b, c, d) +#define Sfo_boolean(a,b,c) sfo_boolean(a, b, c) +#define Sfo_schar(a,b,c) sfo_schar(a, b, c) + #define Sfi_long(a,b,c) sfi_long(a, b, c); #define Sfi_ulong(a,b,c) sfi_ulong(a, b, c); #define Sfi_char(a,b,c,d) sfi_char(a, b, c, d) #define Sfi_boolean(a,b,c) sfi_boolean(a, b, c) #define Sfi_schar(a,b,c) sfi_schar(a, b, c) -#endif #endif /* SAVEFILE_H */ From 956c82622316a97f410adb007037bc2378fffa94 Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 26 May 2025 13:34:31 -0400 Subject: [PATCH 651/791] Makefile.src bit --- sys/unix/Makefile.src | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sys/unix/Makefile.src b/sys/unix/Makefile.src index 89836554a..623d19c12 100644 --- a/sys/unix/Makefile.src +++ b/sys/unix/Makefile.src @@ -887,7 +887,8 @@ $(HACK_H): $(CONFIG_H) ../include/align.h ../include/artilist.h \ ../include/nhlua.h ../include/obj.h ../include/objclass.h \ ../include/objects.h ../include/permonst.h ../include/prop.h \ ../include/quest.h ../include/rect.h ../include/region.h \ - ../include/rm.h ../include/seffects.h ../include/selvar.h \ + ../include/rm.h ../include/savefile.h ../include/sfprocs.h \ + ../include/seffects.h ../include/selvar.h \ ../include/skills.h ../include/sndprocs.h ../include/spell.h \ ../include/stairs.h ../include/sym.h ../include/sys.h \ ../include/timeout.h ../include/trap.h ../include/vision.h \ From 62f9b0d15c8eb3eefb10dd5ee109a0c47196b3b0 Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 26 May 2025 20:06:20 -0400 Subject: [PATCH 652/791] fix some reported warnings --- include/integer.h | 17 ++++++++++------- src/cfgfiles.c | 1 - src/sfbase.c | 27 +++++++-------------------- 3 files changed, 17 insertions(+), 28 deletions(-) diff --git a/include/integer.h b/include/integer.h index d38ea80ca..637e18d8b 100644 --- a/include/integer.h +++ b/include/integer.h @@ -39,26 +39,29 @@ #define HAS_INTTYPES_H #else /*!__DECC*/ -#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) \ - && !defined(HAS_STDINT_H) +#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) +#if !defined(HAS_STDINT_H) /* The compiler claims to conform to C99. Use stdint.h */ #define HAS_STDINT_H -#endif +#endif /* !HAS_STDINT_H */ +#if !defined(HAS_INTTYPES_H) +/* The compiler claims to conform to C99. Use inttypes.h */ +#define HAS_INTTYPES_H +#endif /* claims to be C99 */ #if defined(__GNUC__) && defined(__INT64_MAX__) && !defined(HAS_STDINT_H) #define HAS_STDINT_H #endif +#endif #endif /*?__DECC*/ #ifdef HAS_STDINT_H #include #define SKIP_STDINT_WORKAROUND -#else /*!stdint*/ +#endif #ifdef HAS_INTTYPES_H #include -#define SKIP_STDINT_WORKAROUND -#endif -#endif /*?stdint*/ +#endif /* HAS_INTTYPES_H */ #ifndef SKIP_STDINT_WORKAROUND /* !C99 */ /* diff --git a/src/cfgfiles.c b/src/cfgfiles.c index 9d8de7f86..2fded6d51 100644 --- a/src/cfgfiles.c +++ b/src/cfgfiles.c @@ -85,7 +85,6 @@ staticfn boolean cnf_line_CRASHREPORTURL(char *); staticfn boolean cnf_line_ACCESSIBILITY(char *); staticfn boolean cnf_line_PORTABLE_DEVICE_PATHS(char *); -staticfn void parseformat(int *, char *); #endif /* SYSCF */ #ifndef SFCTOOL staticfn boolean cnf_line_BOULDER(char *); diff --git a/src/sfbase.c b/src/sfbase.c index 30924d754..3a735cd1c 100644 --- a/src/sfbase.c +++ b/src/sfbase.c @@ -4,6 +4,7 @@ #include "hack.h" #include "sfprocs.h" + #ifdef SFCTOOL //#include "sfproto.h" #endif @@ -499,15 +500,9 @@ char * sfvalue_any(anything *a) { static char buf[20]; -#ifdef UNIX Snprintf(buf, sizeof buf, - "%ld", - a->a_int64); -#else - Snprintf(buf, sizeof buf, - "%lld", - a->a_int64); -#endif + PRId64, + (int64_t) a->a_int64); return buf; } @@ -533,18 +528,14 @@ char * sfvalue_int32(int32 *a) { static char buf[20]; - Snprintf(buf, sizeof buf, "%d", *a); + Snprintf(buf, sizeof buf, PRId32, *a); return buf; } char * sfvalue_int64(int64 *a) { static char buf[20]; -#ifdef UNIX - Snprintf(buf, sizeof buf, "%ld", *a); -#else - Snprintf(buf, sizeof buf, "%lld", *a); -#endif + Snprintf(buf, sizeof buf, PRId64, *a); return buf; } @@ -570,7 +561,7 @@ char * sfvalue_uint32(uint32 *a) { static char buf[20]; - Snprintf(buf, sizeof buf, "%u", *a); + Snprintf(buf, sizeof buf, PRIu32, *a); return buf; } @@ -578,11 +569,7 @@ char * sfvalue_uint64(uint64 *a) { static char buf[20]; -#ifdef UNIX - Snprintf(buf, sizeof buf, "%lu", *a); -#else - Snprintf(buf, sizeof buf, "%llu", *a); -#endif + Snprintf(buf, sizeof buf, PRId64, *a); return buf; } From 317490b49d55b906795fc701266ebe66d051bbb3 Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 26 May 2025 20:12:54 -0400 Subject: [PATCH 653/791] correct preprocessor comments --- include/integer.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/integer.h b/include/integer.h index 637e18d8b..b632d4b5e 100644 --- a/include/integer.h +++ b/include/integer.h @@ -47,11 +47,11 @@ #if !defined(HAS_INTTYPES_H) /* The compiler claims to conform to C99. Use inttypes.h */ #define HAS_INTTYPES_H -#endif /* claims to be C99 */ +#endif /* !HAS_INTTYPES_H */ #if defined(__GNUC__) && defined(__INT64_MAX__) && !defined(HAS_STDINT_H) #define HAS_STDINT_H -#endif -#endif +#endif +#endif /* claims to be C99 */ #endif /*?__DECC*/ From 35e35b2cbda613c167c6729e2b850af97615b1d1 Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 26 May 2025 20:18:00 -0400 Subject: [PATCH 654/791] fix paste error --- src/sfbase.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sfbase.c b/src/sfbase.c index 3a735cd1c..4863dfd46 100644 --- a/src/sfbase.c +++ b/src/sfbase.c @@ -569,7 +569,7 @@ char * sfvalue_uint64(uint64 *a) { static char buf[20]; - Snprintf(buf, sizeof buf, PRId64, *a); + Snprintf(buf, sizeof buf, PRIu64, *a); return buf; } From df602f5d3138de9e4224182fd1c97cae886d0d55 Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 26 May 2025 20:33:06 -0400 Subject: [PATCH 655/791] fix Qt issue --- include/integer.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/integer.h b/include/integer.h index b632d4b5e..f12cf21bf 100644 --- a/include/integer.h +++ b/include/integer.h @@ -89,8 +89,13 @@ typedef unsigned int uint32_t; 64-bit integers, you should comment out USE_ISAAC64 in config.h so that the previous RNG gets used instead. Then this file will be inhibited and it won't matter what the int64_t and uint64_t lines are. */ + +#if defined(__cplusplus) +#include +#else typedef long long int int64_t; typedef unsigned long long int uint64_t; +#endif #endif /* !C99 */ From 41aee443c05b2affbd72fe6e9591e798a4167399 Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 26 May 2025 22:03:49 -0400 Subject: [PATCH 656/791] vcxproj bit for sfctool --- sys/windows/vs/sfctool/sfctool.vcxproj | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sys/windows/vs/sfctool/sfctool.vcxproj b/sys/windows/vs/sfctool/sfctool.vcxproj index f86aa0b8b..e63a0c61d 100644 --- a/sys/windows/vs/sfctool/sfctool.vcxproj +++ b/sys/windows/vs/sfctool/sfctool.vcxproj @@ -124,6 +124,7 @@ $(WinWin32Dir);$(IncDir);$(SysWindDir);$(SysShareDir);$(WinShareDir);$(LuaDir);$(UtilDir);%(AdditionalIncludeDirectories) WIN32;_DEBUG;_CONSOLE;WIN32CON;NO_TILE_C;DLB;SAFEPROCS;SND_LIB_WINDSOUND;USER_SOUNDS;_LIB;HAS_STDINT_H;SFCTOOL;NOPANICTRACE;NOCRASHREPORT;NO_CHRONICLE;%(PreprocessorDefinitions) Level3 + stdclatest true true @@ -139,6 +140,7 @@ $(WinWin32Dir);$(IncDir);$(SysWindDir);$(SysShareDir);$(WinShareDir);$(LuaDir);$(UtilDir);%(AdditionalIncludeDirectories) WIN32;_NDEBUG;_CONSOLE;WIN32CON;NO_TILE_C;DLB;SAFEPROCS;SND_LIB_WINDSOUND;USER_SOUNDS;_LIB;HAS_STDINT_H;SFCTOOL;NOPANICTRACE;NOCRASHREPORT;NO_CHRONICLE;%(PreprocessorDefinitions) Level3 + stdclatest true true true @@ -158,6 +160,7 @@ $(WinWin32Dir);$(IncDir);$(SysWindDir);$(SysShareDir);$(WinShareDir);$(LuaDir);$(UtilDir);%(AdditionalIncludeDirectories) WIN32;_DEBUG;_CONSOLE;WIN32CON;NO_TILE_C;DLB;SAFEPROCS;SND_LIB_WINDSOUND;USER_SOUNDS;_LIB;HAS_STDINT_H;SFCTOOL;NOPANICTRACE;NOCRASHREPORT;NO_CHRONICLE;%(PreprocessorDefinitions) Level3 + stdclatest true true @@ -173,6 +176,7 @@ $(WinWin32Dir);$(IncDir);$(SysWindDir);$(SysShareDir);$(WinShareDir);$(LuaDir);$(UtilDir);%(AdditionalIncludeDirectories) WIN32;_NDEBUG;_CONSOLE;WIN32CON;NO_TILE_C;DLB;SAFEPROCS;SND_LIB_WINDSOUND;USER_SOUNDS;_LIB;HAS_STDINT_H;SFCTOOL;NOPANICTRACE;NOCRASHREPORT;NO_CHRONICLE;%(PreprocessorDefinitions) Level3 + stdclatest true true true From 8207d66a16d446d164fefc37e609e0d3d24cd40a Mon Sep 17 00:00:00 2001 From: nhmall Date: Tue, 27 May 2025 03:05:27 -0400 Subject: [PATCH 657/791] follow-up --- src/sfbase.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/sfbase.c b/src/sfbase.c index 4863dfd46..9d2e6006d 100644 --- a/src/sfbase.c +++ b/src/sfbase.c @@ -500,9 +500,10 @@ char * sfvalue_any(anything *a) { static char buf[20]; + Snprintf(buf, sizeof buf, - PRId64, - (int64_t) a->a_int64); + "%" PRId64, + a->a_int64); return buf; } @@ -528,14 +529,14 @@ char * sfvalue_int32(int32 *a) { static char buf[20]; - Snprintf(buf, sizeof buf, PRId32, *a); + Snprintf(buf, sizeof buf, "%" PRId32, *a); return buf; } char * sfvalue_int64(int64 *a) { static char buf[20]; - Snprintf(buf, sizeof buf, PRId64, *a); + Snprintf(buf, sizeof buf, "%" PRId64, *a); return buf; } @@ -561,7 +562,7 @@ char * sfvalue_uint32(uint32 *a) { static char buf[20]; - Snprintf(buf, sizeof buf, PRIu32, *a); + Snprintf(buf, sizeof buf, "%" PRIu32, *a); return buf; } @@ -569,7 +570,7 @@ char * sfvalue_uint64(uint64 *a) { static char buf[20]; - Snprintf(buf, sizeof buf, PRIu64, *a); + Snprintf(buf, sizeof buf, "%" PRIu64, *a); return buf; } From 90b674c1eb1da4e899d0757a4849a9767ff690ef Mon Sep 17 00:00:00 2001 From: nhmall Date: Tue, 27 May 2025 03:41:49 -0400 Subject: [PATCH 658/791] CI include nroff on latest macOS --- azure-pipelines.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index a54d8662f..187f3287d 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -214,6 +214,7 @@ steps: workingDirectory: $(Agent.BuildDirectory)/$(netHackPath) - bash: | + brew install nroff cd sys/unix sh setup.sh hints/macos.370 cd ../.. From fb4c4e16b6c80d987a0d5c216acea17da66e8ffe Mon Sep 17 00:00:00 2001 From: nhmall Date: Tue, 27 May 2025 03:52:58 -0400 Subject: [PATCH 659/791] CI change brew install to groff --- azure-pipelines.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 187f3287d..44cb76f79 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -214,7 +214,7 @@ steps: workingDirectory: $(Agent.BuildDirectory)/$(netHackPath) - bash: | - brew install nroff + brew install groff cd sys/unix sh setup.sh hints/macos.370 cd ../.. @@ -222,7 +222,7 @@ steps: make WANT_MACSOUND=1 all condition: eq( variables['Agent.OS'], 'Darwin' ) workingDirectory: $(Agent.BuildDirectory)/$(netHackPath) - displayName: 'Building mac full build' + displayName: 'Building mac full build - bash: | sudo apt -qq -y install libfl2 From 8f1bab8c8d482fdb55d3f7d437537554fdc506ee Mon Sep 17 00:00:00 2001 From: nhmall Date: Tue, 27 May 2025 03:57:34 -0400 Subject: [PATCH 660/791] CI yml typo fix --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 44cb76f79..b11fdc3be 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -222,7 +222,7 @@ steps: make WANT_MACSOUND=1 all condition: eq( variables['Agent.OS'], 'Darwin' ) workingDirectory: $(Agent.BuildDirectory)/$(netHackPath) - displayName: 'Building mac full build + displayName: 'Building mac full build' - bash: | sudo apt -qq -y install libfl2 From c258011fbcfa60e0bbbeae943a759a014141b23c Mon Sep 17 00:00:00 2001 From: nhmall Date: Wed, 28 May 2025 21:32:21 -0400 Subject: [PATCH 661/791] update tested versions of Visual Studio 2025-05-28 --- sys/windows/Makefile.nmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sys/windows/Makefile.nmake b/sys/windows/Makefile.nmake index 8f19c209c..e8d97fd09 100644 --- a/sys/windows/Makefile.nmake +++ b/sys/windows/Makefile.nmake @@ -9,7 +9,7 @@ # # Visual Studio Compilers Tested: # - Microsoft Visual Studio 2019 Community Edition v 16.11.42 -# - Microsoft Visual Studio 2022 Community Edition v 17.14.0 +# - Microsoft Visual Studio 2022 Community Edition v 17.14.3 # #============================================================================== # This is used for building two distinct executables of NetHack: @@ -1178,7 +1178,7 @@ rc=Rc.exe # # Recently tested versions: TESTEDVS2019 = 14.29.30157.0 -TESTEDVS2022 = 14.44.35207.1 +TESTEDVS2022 = 14.44.35208.0 VS2019CUR = $(TESTEDVS2019:.=) VS2022CUR = $(TESTEDVS2022:.=) From a99944fb09c765bb8006ad65233f67a58db05348 Mon Sep 17 00:00:00 2001 From: nhmall Date: Thu, 29 May 2025 09:59:29 -0400 Subject: [PATCH 662/791] improve sfctool messages --- include/hacklib.h | 4 +- src/hacklib.c | 19 +++-- src/mdlib.c | 4 +- src/version.c | 5 +- sys/windows/vs/sfctool.sln | 10 +++ sys/windows/vs/sfctool/sfctool.vcxproj | 2 +- util/sfctool.c | 110 ++++++++++++++++++++----- 7 files changed, 117 insertions(+), 37 deletions(-) diff --git a/include/hacklib.h b/include/hacklib.h index 96b6bdf39..18630e1b1 100644 --- a/include/hacklib.h +++ b/include/hacklib.h @@ -79,8 +79,8 @@ extern unsigned Strlen_(const char *, const char *, int) NONNULLPTRS; #endif extern int unicodeval_to_utf8str(int, uint8 *, size_t); extern boolean copy_bytes(int, int); -extern const char *datamodel(void); -extern const char *what_datamodel_is_this(int, int, int, int, int); +extern const char *datamodel(int); +extern const char *what_datamodel_is_this(int, int, int, int, int, int); #endif /* HACKLIB_H */ diff --git a/src/hacklib.c b/src/hacklib.c index fd8f20c91..209982751 100644 --- a/src/hacklib.c +++ b/src/hacklib.c @@ -957,20 +957,21 @@ copy_bytes(int ifd, int ofd) struct datamodel_information { int sz[MAX_D]; const char *datamodel; + const char *dmplatform; }; static struct datamodel_information dm[] = { { { (int) sizeof(short), (int) sizeof(int), (int) sizeof(long), (int) sizeof(long long), (int) sizeof(genericptr_t) }, - "" }, - { { 2, 4, 4, 8, 4 }, "ILP32LL64" }, /* Windows, Unix x86 */ - { { 2, 4, 4, 8, 8 }, "IL32LLP64" }, /* Windows x64 */ - { { 2, 4, 8, 8, 8 }, "I32LP64" }, /* Unix 64-bit */ - { { 2, 8, 8, 8, 8 }, "ILP64" }, /* HAL, SPARC64 */ + "", "" }, + { { 2, 4, 4, 8, 4 }, "ILP32LL64", "x86 32-bit" }, /* Windows or Unix */ + { { 2, 4, 4, 8, 8 }, "IL32LLP64", "Windows x64 64-bit" }, + { { 2, 4, 8, 8, 8 }, "I32LP64", "Unix 64-bit"}, + { { 2, 8, 8, 8, 8 }, "ILP64", "Unix ILP64"}, /* HAL, SPARC64 */ }; const char * -datamodel(void) +datamodel(int retidx) { int i, j, matchcount; static const char *unknown = "Unknown"; @@ -982,13 +983,13 @@ datamodel(void) ++matchcount; } if (matchcount == MAX_D) - return dm[i].datamodel; + return (retidx == 0) ? dm[i].datamodel : dm[i].dmplatform; } return unknown; } const char * -what_datamodel_is_this(int szshort, int szint, int szlong, int szll, +what_datamodel_is_this(int retidx, int szshort, int szint, int szlong, int szll, int szptr) { int i; @@ -998,7 +999,7 @@ what_datamodel_is_this(int szshort, int szint, int szlong, int szll, if (szshort == dm[i].sz[0] && szint == dm[i].sz[1] && szlong == dm[i].sz[2] && szll == dm[i].sz[3] && szptr == dm[i].sz[4]) - return dm[i].datamodel; + return (retidx == 0) ? dm[i].datamodel : dm[i].dmplatform; } return unknown; } diff --git a/src/mdlib.c b/src/mdlib.c index 701b39901..fb4155dab 100644 --- a/src/mdlib.c +++ b/src/mdlib.c @@ -56,7 +56,7 @@ static boolean date_via_env = FALSE; extern unsigned long md_ignored_features(void); -extern const char *datamodel(void); +extern const char *datamodel(int); char *version_id_string(char *, size_t, const char *) NONNULL NONNULLPTRS; char *bannerc_string(char *, size_t, const char *) NONNULL NONNULLPTRS; int case_insensitive_comp(const char *, const char *) NONNULLPTRS; @@ -696,7 +696,7 @@ build_options(void) STOREOPTTEXT(optbuf); optbuf[0] = '\0'; length = COLNO + 1; /* force 1st item onto new line */ - Strcat(strcpy(buf, datamodel()), " data model,"); + Strcat(strcpy(buf, datamodel(0)), " data model,"); opt_out_words(buf, &length); for (i = 0; i < SIZE(build_opts); i++) { #if !defined(MAKEDEFS_C) && defined(FOR_RUNTIME) diff --git a/src/version.c b/src/version.c index 04987929c..99c36efdf 100644 --- a/src/version.c +++ b/src/version.c @@ -778,9 +778,10 @@ compare_critical_bytes(NHFILE *nhfp, int *idx_1st_mismatch, unsigned long utdfla } for (i = 1; i < cnt; ++i) { if (cscbuf[i] != critical_sizes[i].ucsize) { - const char *dm = datamodel(), *dmfile; + const char *dm = datamodel(0), *dmfile; - dmfile = what_datamodel_is_this(cscbuf[1], /* short */ + dmfile = what_datamodel_is_this(0, + cscbuf[1], /* short */ cscbuf[2], /* int */ cscbuf[3], /* long */ cscbuf[4], /* long long */ diff --git a/sys/windows/vs/sfctool.sln b/sys/windows/vs/sfctool.sln index c997bd45f..06ef30f69 100644 --- a/sys/windows/vs/sfctool.sln +++ b/sys/windows/vs/sfctool.sln @@ -16,6 +16,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sftags", "sftags\sftags.vcx EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fetchctags", "fetchctags\fetchctags.vcxproj", "{AAE63AD3-8185-4E19-B6A3-13F4CB891AAD}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "hacklib", "hacklib\hacklib.vcxproj", "{096FD6BB-256A-4E68-9B09-2ACA7C606FF3}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 @@ -48,6 +50,14 @@ Global {AAE63AD3-8185-4E19-B6A3-13F4CB891AAD}.Release|x64.Build.0 = Release|x64 {AAE63AD3-8185-4E19-B6A3-13F4CB891AAD}.Release|x86.ActiveCfg = Release|Win32 {AAE63AD3-8185-4E19-B6A3-13F4CB891AAD}.Release|x86.Build.0 = Release|Win32 + {096FD6BB-256A-4E68-9B09-2ACA7C606FF3}.Debug|x64.ActiveCfg = Debug|x64 + {096FD6BB-256A-4E68-9B09-2ACA7C606FF3}.Debug|x64.Build.0 = Debug|x64 + {096FD6BB-256A-4E68-9B09-2ACA7C606FF3}.Debug|x86.ActiveCfg = Debug|Win32 + {096FD6BB-256A-4E68-9B09-2ACA7C606FF3}.Debug|x86.Build.0 = Debug|Win32 + {096FD6BB-256A-4E68-9B09-2ACA7C606FF3}.Release|x64.ActiveCfg = Release|x64 + {096FD6BB-256A-4E68-9B09-2ACA7C606FF3}.Release|x64.Build.0 = Release|x64 + {096FD6BB-256A-4E68-9B09-2ACA7C606FF3}.Release|x86.ActiveCfg = Release|Win32 + {096FD6BB-256A-4E68-9B09-2ACA7C606FF3}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/sys/windows/vs/sfctool/sfctool.vcxproj b/sys/windows/vs/sfctool/sfctool.vcxproj index e63a0c61d..7a64f39c9 100644 --- a/sys/windows/vs/sfctool/sfctool.vcxproj +++ b/sys/windows/vs/sfctool/sfctool.vcxproj @@ -194,4 +194,4 @@ - + \ No newline at end of file diff --git a/util/sfctool.c b/util/sfctool.c index cc3f9e464..c79be9254 100644 --- a/util/sfctool.c +++ b/util/sfctool.c @@ -77,6 +77,8 @@ static NHFILE *create_dstfile(char *, enum saveformats); static const char *style_to_text(enum saveformats style); static void read_sysconf(void); static int length_without_val(const char *user_string, int len); +static void usage(int argc, char **argv); +static const char *briefname(const char *fnam); void zero_nhfile(NHFILE *); NHFILE *new_nhfile(void); @@ -158,18 +160,19 @@ static char srclogfilenm[BUFSZ], dstlogfilenm[BUFSZ]; *********/ int -main(int argc UNUSED, char *argv[]) +main(int argc, char *argv[]) { int arg; char folderbuf[5000]; const char *suffix = (convertstyle == exportascii) ? ".exportascii" : ""; - boolean add_folder = TRUE; -#ifdef WIN32 - size_t sz; -#endif + boolean add_folder = TRUE, add_extension = FALSE; - if (argc < 3) - exit(EXIT_FAILURE); +#ifdef WIN32 + const char *default_extension = ".NetHack-saved-game"; + size_t sz; +#else + const char *default_extension = ""; +#endif runtime_info_init(); /* mdlib.c */ #ifdef UNIX @@ -188,13 +191,26 @@ main(int argc UNUSED, char *argv[]) exit(EXIT_FAILURE); sz = strlen(folderbuf); (void) snprintf(eos(folderbuf), sizeof folderbuf - sz, - "\\AppData\\Local\\NetHack\\3.7\\"); - //initoptions_init(); // This allows OPTIONS in syscf on Windows. + "\\AppData\\Local\\NetHack\\3.7\\"); + // initoptions_init(); // This allows OPTIONS in syscf on Windows. set_default_prefix_locations(argv[0]); #endif read_sysconf(); + thisdatamodel = datamodel(0); + if (argc < 3 && !(argc == 2 && !strcmp(argv[1], "-d"))) { + usage(argc, argv); + exit(EXIT_FAILURE); + } for (arg = 1; arg < argc; ++arg) { + if (arg == 1 && !strcmp(argv[arg], "-d")) { + fprintf( + stdout, + "\nThe historical savefile datamodel supported by this utility is %s (%s).\n", + thisdatamodel, datamodel(1)); + exit(EXIT_SUCCESS); + } + if (arg == 1 && !strcmp(argv[arg], "-u")) { explicit_option = TRUE; chosen_unconvert = TRUE; @@ -209,6 +225,7 @@ main(int argc UNUSED, char *argv[]) chosen_unconvert = FALSE; continue; } + if (arg == 2) { size_t ln = strlen(argv[arg]); boolean addseparator = FALSE; @@ -223,13 +240,23 @@ main(int argc UNUSED, char *argv[]) } else { add_folder = FALSE; } +#ifdef WIN32 + /* On Windows we allow specifying the savefile name without the extention + * in the arguments */ + if (strstr(argv[arg], default_extension) == 0) + add_extension = TRUE; +#endif if (explicit_option) { if (add_folder) ln += strlen(folderbuf); + if (add_extension) + ln += strlen(default_extension); unconverted_filename = (char *) alloc((int) ln + 1); - Snprintf(unconverted_filename, ln + 1, "%s%s%s", + Snprintf(unconverted_filename, ln + 1, "%s%s%s%s", add_folder ? folderbuf : "", - addseparator ? "/" : "", argv[arg]); + addseparator ? "/" : "", + argv[arg], + add_extension ? default_extension : ""); ln += strlen(suffix); converted_filename = (char *) alloc((int) ln + 1); Snprintf(converted_filename, ln + 1, "%s%s", @@ -246,7 +273,7 @@ main(int argc UNUSED, char *argv[]) !converted_filename ? "" : "un"); exit(EXIT_FAILURE); /* need both filenames */ } - thisdatamodel = datamodel(); + my_sf_init(); if (chosen_unconvert) { process_savefile(converted_filename, convertstyle, @@ -274,16 +301,27 @@ process_savefile(const char *srcfnam, enum saveformats srcstyle, extern struct version_info vers_info; extern uchar cscbuf[]; /* nh_uncompress(fq_save); */ + const char *dmfile; if ((nhfp[srcidx] = open_srcfile(srcfnam, srcstyle)) == 0) return 0; sfstatus = validate(nhfp[srcidx], srcfnam, FALSE); + dmfile = what_datamodel_is_this(0, + cscbuf[1], /* short */ + cscbuf[2], /* int */ + cscbuf[3], /* long */ + cscbuf[4], /* long long */ + cscbuf[5]); /* ptr */ if (sfstatus > SF_UPTODATE && ((sfstatus <= SF_CRITICAL_BYTE_COUNT_MISMATCH) || !unconvert)) { fprintf(stderr, - "This savefile is not compatible with %sutility.\n%s\n", - !unconvert ? "the datamodel of this particular " : "this ", - srcfnam); + "The %s savefile %s%s%s not compatible with this %s%sutility.\n", + briefname(srcfnam), + dmfile ? "is a " : "", + dmfile ? dmfile : "", + dmfile ? " savefile, thus" : " is", + thisdatamodel ? thisdatamodel : "", + thisdatamodel ? " " : ""); return 0; } if (sfstatus >= SF_DM_IL32LLP64_ON_ILP32LL64) { @@ -303,12 +341,16 @@ process_savefile(const char *srcfnam, enum saveformats srcstyle, nhfp[srcidx]->nhfpconvert = nhfp[CONVERTED]; } if (unconvert) - fprintf(stdout, "\n\nunconverting %s to %s %s\n", - style_to_text(srcstyle), style_to_text(cvtstyle), - thisdatamodel); + fprintf(stdout, "\n\nunconverting %s to %s savefile called %s.\n", + briefname((const char *) converted_filename), + dmfile, + briefname((const char *) unconverted_filename)); else - fprintf(stdout, "\n\nconverting %s %s to %s\n", - style_to_text(srcstyle), thisdatamodel, style_to_text(cvtstyle)); + fprintf(stdout, "\n\nconverting %s %s format %s to %s format\n", + style_to_text(srcstyle), + thisdatamodel, + briefname((const char *) unconverted_filename), + style_to_text(cvtstyle)); rewind_nhfile(nhfp[srcidx]); #ifdef SAVEFILE_DEBUGGING @@ -564,6 +606,17 @@ create_dstfile(char *fnam, enum saveformats mystyle) return nhfp; } +static const char * +briefname(const char *fnam) +{ + const char *bn = fnam, *sep = (const char *) 0; + + if ((sep = strrchr(fnam, '/')) || (sep = strrchr(fnam, '\\')) + || (sep = strrchr(fnam, ':'))) + bn = sep + 1; + return bn; +} + static const char * style_to_text(enum saveformats style) { @@ -1279,7 +1332,7 @@ free_oname(struct obj *obj) } } -#ifdef WIN32 +#ifdef WIN32 void win32_abort(void) { @@ -1320,4 +1373,19 @@ match_optname(const char *user_string, const char *optn_name, int min_length, && !strncmpi(optn_name, user_string, len)); } +staticfn void +usage(int argc, char **argv) +{ + char *cp = argv[0], *sep = (char *) 0; + + if ((sep = strrchr(cp, '/')) || (sep = strrchr(cp, '\\')) + || (sep = strrchr(cp, ':'))) + cp = sep + 1; + fprintf(stderr, + "\nTo convert a savefile to export format:\n %s %s %s\n", cp, + "-c", "savefile"); + fprintf(stderr, + "\nTo unconvert an exported savefile back into a savefile:\n %s %s %s\n", cp, + "-u", "savefile"); +} /* sfctool.c */ From 789d0e6676b2288eeeed331e82cc5c14f4273a1d Mon Sep 17 00:00:00 2001 From: nhmall Date: Thu, 29 May 2025 10:02:05 -0400 Subject: [PATCH 663/791] fix a warning in sfctool build --- util/sfctool.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/sfctool.c b/util/sfctool.c index c79be9254..fe016748f 100644 --- a/util/sfctool.c +++ b/util/sfctool.c @@ -1374,7 +1374,7 @@ match_optname(const char *user_string, const char *optn_name, int min_length, } staticfn void -usage(int argc, char **argv) +usage(int argc UNUSED, char **argv) { char *cp = argv[0], *sep = (char *) 0; From 228870706b7ad412953aa67ec4cddad458f16e9b Mon Sep 17 00:00:00 2001 From: Alex Smith Date: Thu, 29 May 2025 15:57:29 +0100 Subject: [PATCH 664/791] Balance fixes to monster/monster zombie creation attacks These were unbalancing the game a) in the Castle and b) if they woke up unique monsters (most notably the Wizard of Yendor). I considered adding a difficulty check, but this commit instead just directly fixes the symptoms. (It doesn't make sense for the Castle to contain a monster that would kill or be killed by its inhabitants: they should have died long before the hero arrived. So for liches/zombies to exist in the Castle at all, there must be a truce.) --- src/mon.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/mon.c b/src/mon.c index 049d21d14..ade679695 100644 --- a/src/mon.c +++ b/src/mon.c @@ -2347,9 +2347,21 @@ mfndpos( staticfn long mm_2way_aggression(struct monst *magr, struct monst *mdef) { - /* zombies vs things that can be zombified */ + /* liches/zombies vs things that can be zombified + + Note: avoid this on the Castle level, partly for balance reasons + (the monster-versus-monster fights clear out significant portions of + the Castle and make it easier than it should be), partly for flavor + reasons (monsters who attacked other monsters to zombify them would + have been counterattacked to death long before the hero arried). + + Also don't include unique monsters in this, otherwise it leads to + them waking up early (e.g. because a zombie decided to attack the + Wizard of Yendor). */ if (zombie_maker(magr) && zombie_form(mdef->data) != NON_PM) - return (ALLOW_M | ALLOW_TM); + if (!Is_stronghold(&u.uz) && + !unique_corpstat(magr->data) && !unique_corpstat(mdef->data)) + return (ALLOW_M | ALLOW_TM); return 0; } From 47724f01374300151a4900939407259c79b14c62 Mon Sep 17 00:00:00 2001 From: Alex Smith Date: Thu, 29 May 2025 17:50:09 +0100 Subject: [PATCH 665/791] Increase generation depth of soldier ants and killer bees These two types of monster were extreme outliers in terms of where they appeared versus how lethal they were (3-4 times as deadly as other monsters that appeared at similar depth, based on statistics from actual play), so their generation depth has been manually modified. Breaks save and bones files (because monster type IDs have to be sorted numerically by difficulty, and changing difficulties thus changes the IDs, but the IDs are used to identify the monsters in save files). --- include/monsters.h | 18 +++++++++--------- include/patchlevel.h | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/include/monsters.h b/include/monsters.h index 0573e882d..5b5e2423b 100644 --- a/include/monsters.h +++ b/include/monsters.h @@ -97,15 +97,7 @@ NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1, 5, MS_BUZZ, MZ_TINY), MR_POISON, MR_POISON, M1_ANIMAL | M1_FLY | M1_NOHANDS | M1_POIS, M2_HOSTILE | M2_FEMALE, 0, - 5, CLR_YELLOW, KILLER_BEE), - MON(NAM("soldier ant"), S_ANT, - LVL(3, 18, 3, 0, 0), (G_GENO | G_SGROUP | 2), - A(ATTK(AT_BITE, AD_PHYS, 2, 4), ATTK(AT_STNG, AD_DRST, 3, 4), - NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), - SIZ(20, 5, MS_SILENT, MZ_TINY), MR_POISON, MR_POISON, - M1_ANIMAL | M1_NOHANDS | M1_OVIPAROUS | M1_POIS | M1_CARNIVORE, - M2_HOSTILE, 0, - 6, CLR_BLUE, SOLDIER_ANT), + 6, CLR_YELLOW, KILLER_BEE), MON(NAM("fire ant"), S_ANT, LVL(3, 18, 3, 10, 0), (G_GENO | G_SGROUP | 1), A(ATTK(AT_BITE, AD_PHYS, 2, 4), ATTK(AT_BITE, AD_FIRE, 2, 4), @@ -121,6 +113,14 @@ SIZ(200, 50, MS_SILENT, MZ_LARGE), MR_POISON, MR_POISON, M1_ANIMAL | M1_NOHANDS | M1_POIS | M1_CARNIVORE, M2_HOSTILE, 0, 6, CLR_BLACK, GIANT_BEETLE), + MON(NAM("soldier ant"), S_ANT, + LVL(3, 18, 3, 0, 0), (G_GENO | G_SGROUP | 2), + A(ATTK(AT_BITE, AD_PHYS, 2, 4), ATTK(AT_STNG, AD_DRST, 3, 4), + NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), + SIZ(20, 5, MS_SILENT, MZ_TINY), MR_POISON, MR_POISON, + M1_ANIMAL | M1_NOHANDS | M1_OVIPAROUS | M1_POIS | M1_CARNIVORE, + M2_HOSTILE, 0, + 7, CLR_BLUE, SOLDIER_ANT), MON(NAM("queen bee"), S_ANT, LVL(9, 24, -4, 0, 0), (G_GENO | G_NOGEN), A(ATTK(AT_STNG, AD_DRST, 1, 8), diff --git a/include/patchlevel.h b/include/patchlevel.h index bfb185ef1..37b02ac79 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 124 +#define EDITLEVEL 125 /* * Development status possibilities. From 90e3abdf9b4521da12e82c352823af5fd0076244 Mon Sep 17 00:00:00 2001 From: Alex Smith Date: Thu, 29 May 2025 18:15:24 +0100 Subject: [PATCH 666/791] Hidden (object-form) mimics aren't hit by thrown objects This is both a bugfix (the hero would be unlikely to aim their throw at what appeared to be an object) and a balance fix (it was possible to, somewhat tediously, defend yourself from mimics by throwing gold pieces at them, and for many players this became standard strategy in shops, negating the threat from mimics). --- src/zap.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/zap.c b/src/zap.c index a6935402f..67eac9bbe 100644 --- a/src/zap.c +++ b/src/zap.c @@ -3957,9 +3957,15 @@ bhit( give message and skip it in order to keep going; if attack is light and mtmp is a mimic pretending to be an object, behave as if there is no monster here (if pretending - to be furniture, it will be revealed by flash_hits_mon()) */ + to be furniture, it will be revealed by flash_hits_mon()); + thrown objects don't hit mimics pretending to be objects (both + because the hero is likely aiming to throw over what seems to + be an object rather than at it, and for balance because + otherwise mimics are too easy to identify by throwing gold at + them) */ if (mtmp && (((weapon == THROWN_WEAPON || weapon == KICKED_WEAPON) - && shade_miss(&gy.youmonst, mtmp, obj, TRUE, TRUE)) + && (shade_miss(&gy.youmonst, mtmp, obj, TRUE, TRUE) + || M_AP_TYPE(mtmp) == M_AP_OBJECT)) || (weapon == FLASHED_LIGHT && M_AP_TYPE(mtmp) == M_AP_OBJECT))) mtmp = (struct monst *) 0; From 45bd98f10e2374376e0867fb476fd35b678e57c8 Mon Sep 17 00:00:00 2001 From: Alex Smith Date: Thu, 29 May 2025 18:58:40 +0100 Subject: [PATCH 667/791] Change #wizmondiff to account for soldier ant, killer bee changes --- src/mondata.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/mondata.c b/src/mondata.c index e7710f01a..4c2cea0ce 100644 --- a/src/mondata.c +++ b/src/mondata.c @@ -479,6 +479,12 @@ mstrength(struct permonst *ptr) if (!strcmp(ptr->pmnames[NEUTRAL], "leprechaun")) n -= 2; + /* Soldier ants and killer bees are underestimated by the formula, + so have an artificial +1 difficulty */ + if (!strcmp(ptr->pmnames[NEUTRAL], "killer bee") || + !strcmp(ptr->pmnames[NEUTRAL], "soldier ant")) + tmp += 1; + /* finally, adjust the monster level 0 <= n <= 24 (approx.) */ if (n == 0) tmp -= 1; From 2bf00395f1955d8e2d0a08b77d0fcfcf5bbbc7e6 Mon Sep 17 00:00:00 2001 From: Alex Smith Date: Thu, 29 May 2025 19:04:42 +0100 Subject: [PATCH 668/791] Vault guards are more reluctant to turn up if they keep dying This is primarily meant as a fix for a farming strategy, although it also makes sense in terms of the decisions the guards would likely make. --- src/vault.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/vault.c b/src/vault.c index dc95128d0..90157b7fa 100644 --- a/src/vault.c +++ b/src/vault.c @@ -320,12 +320,19 @@ invault(void) struct obj *otmp; boolean spotted; int trycount, vaultroom = (int) vault_occupied(u.urooms); + int vgdeathcount; if (!vaultroom) { u.uinvault = 0; return; } - ++u.uinvault; + /* after a couple of guards don't come back from their trips to + the vault, future guards become more reluctant to turn up (even + if summoned via whistle) */ + vgdeathcount = svm.mvitals[PM_GUARD].died; + if (vgdeathcount < 2 || + (vgdeathcount < 50 && !rn2(vgdeathcount * vgdeathcount))) + ++u.uinvault; if (u.uinvault < VAULT_GUARD_TIME || (u.uinvault % (VAULT_GUARD_TIME / 2)) != 0) return; @@ -409,6 +416,10 @@ invault(void) EGD(guard)->vroom = vaultroom; EGD(guard)->warncnt = 0; + /* ensure the guard doesn't respawn again next turn if killed + immediately */ + ++u.uinvault; + reset_faint(); /* if fainted - wake up */ /* if there are any boulders in the guard's way, destroy them; perhaps the guard knows a touch equivalent of force bolt; From 0e50adcc1eb4b9580bc124da38999b74083eb087 Mon Sep 17 00:00:00 2001 From: Alex Smith Date: Thu, 29 May 2025 19:14:10 +0100 Subject: [PATCH 669/791] Restore monsters.h to its previous order This causes the difficulties to get out of sequence, but we agreed that this is a less important rule than keeping monster IDs stable. Breaks save and bones files, because it changes monster IDs. --- include/monsters.h | 22 ++++++++++++---------- include/patchlevel.h | 2 +- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/include/monsters.h b/include/monsters.h index 5b5e2423b..d13cc9178 100644 --- a/include/monsters.h +++ b/include/monsters.h @@ -47,8 +47,10 @@ * Rule #1: monsters of a given class are contiguous in the * mons[] array. * - * Rule #2: monsters of a given class are presented in ascending - * order of strength. + * Rule #2: monsters of a given class are generally kept in + * the same order as in previous versions of NetHack + * (they used to be presented in ascending order of + * strength, but this rule no longer applies). * * Rule #3: monster frequency is included in the geno mask; * the frequency can be from 0 to 7. 0's will also @@ -98,6 +100,14 @@ SIZ(1, 5, MS_BUZZ, MZ_TINY), MR_POISON, MR_POISON, M1_ANIMAL | M1_FLY | M1_NOHANDS | M1_POIS, M2_HOSTILE | M2_FEMALE, 0, 6, CLR_YELLOW, KILLER_BEE), + MON(NAM("soldier ant"), S_ANT, + LVL(3, 18, 3, 0, 0), (G_GENO | G_SGROUP | 2), + A(ATTK(AT_BITE, AD_PHYS, 2, 4), ATTK(AT_STNG, AD_DRST, 3, 4), + NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), + SIZ(20, 5, MS_SILENT, MZ_TINY), MR_POISON, MR_POISON, + M1_ANIMAL | M1_NOHANDS | M1_OVIPAROUS | M1_POIS | M1_CARNIVORE, + M2_HOSTILE, 0, + 7, CLR_BLUE, SOLDIER_ANT), MON(NAM("fire ant"), S_ANT, LVL(3, 18, 3, 10, 0), (G_GENO | G_SGROUP | 1), A(ATTK(AT_BITE, AD_PHYS, 2, 4), ATTK(AT_BITE, AD_FIRE, 2, 4), @@ -113,14 +123,6 @@ SIZ(200, 50, MS_SILENT, MZ_LARGE), MR_POISON, MR_POISON, M1_ANIMAL | M1_NOHANDS | M1_POIS | M1_CARNIVORE, M2_HOSTILE, 0, 6, CLR_BLACK, GIANT_BEETLE), - MON(NAM("soldier ant"), S_ANT, - LVL(3, 18, 3, 0, 0), (G_GENO | G_SGROUP | 2), - A(ATTK(AT_BITE, AD_PHYS, 2, 4), ATTK(AT_STNG, AD_DRST, 3, 4), - NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), - SIZ(20, 5, MS_SILENT, MZ_TINY), MR_POISON, MR_POISON, - M1_ANIMAL | M1_NOHANDS | M1_OVIPAROUS | M1_POIS | M1_CARNIVORE, - M2_HOSTILE, 0, - 7, CLR_BLUE, SOLDIER_ANT), MON(NAM("queen bee"), S_ANT, LVL(9, 24, -4, 0, 0), (G_GENO | G_NOGEN), A(ATTK(AT_STNG, AD_DRST, 1, 8), diff --git a/include/patchlevel.h b/include/patchlevel.h index 37b02ac79..339095f25 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 125 +#define EDITLEVEL 126 /* * Development status possibilities. From 3fd30c4ec82ffa3a70a1f8e21ecdd6fc421ca572 Mon Sep 17 00:00:00 2001 From: Alex Smith Date: Fri, 30 May 2025 01:11:41 +0100 Subject: [PATCH 670/791] Special effects for Vlad's throne Part 1 of implementing wish spreading. Vlad's throne is now guaranteed to eventually give a wish, but has a range of other powerful (and mostly bad) effects, like removing intrinsics, that can be much harder to deal with than typical throne effects. --- src/sit.c | 136 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 132 insertions(+), 4 deletions(-) diff --git a/src/sit.c b/src/sit.c index 324e1d75c..40628c1b0 100644 --- a/src/sit.c +++ b/src/sit.c @@ -7,6 +7,7 @@ #include "artifact.h" staticfn void throne_sit_effect(void); +staticfn void rndcurse_inner(boolean); staticfn int lay_an_egg(void); /* take away the hero's money */ @@ -32,12 +33,16 @@ take_gold(void) } } +staticfn void special_throne_effect(int effect); + /* maybe do something when hero sits on a throne */ staticfn void throne_sit_effect(void) { coordxy tx = u.ux, ty = u.uy; + boolean special_throne = !!In_V_tower(&u.uz); + if (rnd(6) > 4) { /* [why so convoluted? it's the same as '!rn2(3)'] */ int effect = rnd(13); @@ -56,6 +61,11 @@ throne_sit_effect(void) effect = which; } + if (special_throne) { + special_throne_effect(effect); + return; + } + switch (effect) { case 1: (void) adjattrib(rn2(A_MAX), -rn1(4, 3), FALSE); @@ -212,7 +222,8 @@ throne_sit_effect(void) only happened when teleporting back to the same point where hero started from.] "Analyzing a throne" doesn't really make any sense but if the answer is yes than it will vanish in a puff of logic. */ - if (!rn2(3) && (!wizard || y_n("Analyze throne?") == 'y')) { + if (!special_throne && + !rn2(3) && (!wizard || y_n("Analyze throne?") == 'y')) { levl[tx][ty].typ = ROOM, levl[tx][ty].flags = 0; map_background(tx, ty, FALSE); newsym_force(tx, ty); @@ -223,6 +234,110 @@ throne_sit_effect(void) } } +/* special throne in Vlad's tower: effect is 1 to 13 inclusive */ +staticfn void +special_throne_effect(int effect) { + coordxy tx = u.ux, ty = u.uy; + + switch (effect) { + case 1: + case 2: + case 3: + case 4: + /* 4 chances of a wish, but then the throne disappears. + + This is the only way the throne can disappear from sitting + on it, so if you sit on it enough (enduring the negative + effects) you are guaranteed an eventual wish. */ + makewish(); + levl[tx][ty].typ = ROOM, levl[tx][ty].flags = 0; + map_background(tx, ty, FALSE); + newsym_force(tx, ty); + pline_The("throne disintegrates, having spent its power."); + break; + case 5: + /* permanent level drain */ + pline("Sitting on the throne was a terrible experience."); + if (!Drain_resistance) { + losexp("a bad experience sitting on a throne"); + if (u.ulevelmax > u.ulevel) + u.ulevelmax -= 1; + } + break; + case 6: + /* containers become cursed */ + rndcurse_inner(TRUE); + break; + case 7: + /* lose an intrinsic */ + attrcurse(); + pline_The("throne somehow seems to be amused."); + break; + case 8: + { + /* level teleport to Vibrating Square level */ + d_level vs_level; + find_hell(&vs_level); + vs_level.dlevel = svd.dungeons[vs_level.dnum].num_dunlevs - 1; + if (u.uhave.amulet) + You_feel("extremely disoriented for a moment."); + else + schedule_goto( + &vs_level, UTOTYPE_NONE, (char *) 0, + "You feel extremely out of place."); + break; + } + case 9: + { + /* summon demons; a NULL argument to msummon summons demons as + though they were summoned by the Wizard of Yendor */ + pline_The("throne seeems to be calling for help!"); + msummon(NULL); + msummon(NULL); + msummon(NULL); + break; + } + case 10: + { + /* confused blessed remove curse effect */ + struct obj fake_spellbook; + long save_confusion = HConfusion; + + fake_spellbook = cg.zeroobj; + fake_spellbook.otyp = SPE_REMOVE_CURSE; + fake_spellbook.oclass = SPBOOK_CLASS; + fake_spellbook.blessed = 1; + HConfusion = 1L; + (void) seffects(&fake_spellbook); + HConfusion = save_confusion; + break; + } + case 11: + /* polymorph effect (not blocked by magic resistance) */ + pline("This throne was not meant for those such as you!"); + You_feel("a change coming over you."); + polyself(POLY_NOFLAGS); + break; + case 12: + /* acid damage */ + pline("The throne is covered in acid!"); + losehp(Acid_resistance ? rnd(16) : rnd(80), "acidic chair", + KILLED_BY_AN); + exercise(A_CON, FALSE); + break; + case 13: + { + /* ability shuffle */ + int ability; + pline("As you sit on the throne, your body and mind start to warp."); + for (ability = 0; ability < A_MAX; ++ability) { + adjattrib(ability, rn2(5) - 2, -1); + } + break; + } + } +} + /* hero lays an egg */ staticfn int lay_an_egg(void) @@ -436,6 +551,12 @@ dosit(void) /* curse a few inventory items at random! */ void rndcurse(void) +{ + rndcurse_inner(FALSE); +} + +staticfn void +rndcurse_inner(boolean prefer_containers) { int nobj = 0; int cnt, onum; @@ -449,23 +570,30 @@ rndcurse(void) if (Antimagic) { shieldeff(u.ux, u.uy); - You(mal_aura, "you"); } + You(mal_aura, "you"); + for (otmp = gi.invent; otmp; otmp = otmp->nobj) { /* gold isn't subject to being cursed or blessed */ if (otmp->oclass == COIN_CLASS) continue; + if (prefer_containers && !otmp->cobj) + continue; nobj++; } + cnt = rnd(6 / ((!!Antimagic) + (!!Half_spell_damage) + 1)); + if (prefer_containers) + cnt = nobj * 2; if (nobj) { - for (cnt = rnd(6 / ((!!Antimagic) + (!!Half_spell_damage) + 1)); - cnt > 0; cnt--) { + for (; cnt > 0; cnt--) { onum = rnd(nobj); for (otmp = gi.invent; otmp; otmp = otmp->nobj) { /* as above */ if (otmp->oclass == COIN_CLASS) continue; + if (prefer_containers && !otmp->cobj) + continue; if (--onum == 0) break; /* found the target */ } From 615edb1c7625c0c00a1e2817e4efc8aa575d02e6 Mon Sep 17 00:00:00 2001 From: Alex Smith Date: Fri, 30 May 2025 01:23:43 +0100 Subject: [PATCH 671/791] Wands of wishing start at (0:1) and can recharge only one charge Part 2 of implementing wish spreading. This reduces the average number of wishes at the Castle from 6 to 3. --- src/mkobj.c | 2 +- src/read.c | 20 +++++++++++++++++--- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/mkobj.c b/src/mkobj.c index bece8cd44..57060e4c5 100644 --- a/src/mkobj.c +++ b/src/mkobj.c @@ -1111,7 +1111,7 @@ mksobj_init(struct obj **obj, boolean artif) break; case WAND_CLASS: if (otmp->otyp == WAN_WISHING) - otmp->spe = rnd(3); + otmp->spe = 1; else otmp->spe = rn1(5, (objects[otmp->otyp].oc_dir == NODIR) ? 11 : 4); diff --git a/src/read.c b/src/read.c index 9f0383de7..5ebe8ab64 100644 --- a/src/read.c +++ b/src/read.c @@ -16,6 +16,7 @@ staticfn int read_ok(struct obj *); staticfn void stripspe(struct obj *); staticfn void p_glow1(struct obj *); staticfn void p_glow2(struct obj *, const char *); +staticfn void p_glow3(struct obj *, const char *); staticfn void forget(int); staticfn int maybe_tame(struct monst *, struct obj *); staticfn boolean can_center_cloud(coordxy, coordxy); @@ -674,6 +675,14 @@ p_glow2(struct obj *otmp, const char *color) Blind ? "" : " ", Blind ? "" : hcolor(color)); } +staticfn void +p_glow3(struct obj *otmp, const char *color) +{ + pline("%s feebly%s%s for a moment.", + Yobjnam2(otmp, Blind ? "vibrate" : "glow"), + Blind ? "" : " ", Blind ? "" : hcolor(color)); +} + /* getobj callback for object to charge */ int charge_ok(struct obj *obj) @@ -726,7 +735,7 @@ recharge(struct obj *obj, int curse_bless) if (obj->oclass == WAND_CLASS) { int lim = (obj->otyp == WAN_WISHING) - ? 3 + ? 1 : (objects[obj->otyp].oc_dir != NODIR) ? 8 : 15; /* undo any prior cancellation, even when is_cursed */ @@ -760,7 +769,7 @@ recharge(struct obj *obj, int curse_bless) if (is_cursed) { stripspe(obj); } else { - n = (lim == 3) ? 3 : rn1(5, lim + 1 - 5); + n = (lim == 1) ? 1 : rn1(5, lim + 1 - 5); if (!is_blessed) n = rnd(n); @@ -769,10 +778,15 @@ recharge(struct obj *obj, int curse_bless) else obj->spe++; if (obj->otyp == WAN_WISHING && obj->spe > 3) { + /* wands can't give more than three wishes; this code is + currently unreachable but left in case the rules for + wands of wishing change in future */ wand_explode(obj, 1); return; } - if (obj->spe >= lim) + if (lim == 1) + p_glow3(obj, NH_BLUE); + else if (obj->spe >= lim) p_glow2(obj, NH_BLUE); else p_glow1(obj); From b92b0bbc69d3ba10fd668f583c8e1445dad232e4 Mon Sep 17 00:00:00 2001 From: Alex Smith Date: Fri, 30 May 2025 01:40:42 +0100 Subject: [PATCH 672/791] Add a random magic marker or magic lamp to Orcustown Part 3 of implementing wish spreading. These items are each worth most of a wish for non-illiterate games (most games wish for a magic marker, and a magic lamp gives a wish 80% of the time). The placement of the random item could be better (currently it is purely random, which is occasionally interesting but often boring), but this will serve as a base for experimenting with the balance properties of the moved wishes. --- dat/orcus.lua | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/dat/orcus.lua b/dat/orcus.lua index d00aac53c..67406d8e2 100644 --- a/dat/orcus.lua +++ b/dat/orcus.lua @@ -102,6 +102,13 @@ local orcus1 = des.map({ halign = "right", valign = "center", map = [[ des.object() des.object() des.object() + -- An object that's worth most of a wish + -- (this is part of the compensation for the reduced wishes at the Castle) + if math.random(0, 1) == 1 then + des.object("magic marker") + else + des.object("magic lamp") + end -- The resident nasty des.monster("Orcus",33,15) -- And its preferred companions From a8800a9acd509456156e978b7b743f62a564e8b1 Mon Sep 17 00:00:00 2001 From: Alex Smith Date: Fri, 30 May 2025 01:45:30 +0100 Subject: [PATCH 673/791] Add a potion of gain level to the Castle chest This is partly for balance reasons (so that clearing the Castle helps towards the level 14 Quest unlock) and partly as a clue to players spoiled on previous versions that the Castle wand now works differently. --- dat/castle.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/dat/castle.lua b/dat/castle.lua index 83eaecae6..0a2b7f243 100644 --- a/dat/castle.lua +++ b/dat/castle.lua @@ -144,6 +144,7 @@ local loc = place:rndcoord(1); des.object({ id = "chest", trapped = 0, locked = 1, coord = loc , contents = function() des.object("wishing"); + des.object("potion of gain level"); end }); -- Prevent monsters from eating it. (@'s never eat objects) From 308c5ab237ee3c7925e77fee299e48f8b1414203 Mon Sep 17 00:00:00 2001 From: Alex Smith Date: Fri, 30 May 2025 02:10:58 +0100 Subject: [PATCH 674/791] The Amulet of Yendor gives a wish when initially picked up Part 4 of implementing wish spreading. (This is now a complete implementation, although the details are likely to change - but it makes sense to commit something with the right balance properties, and then tweak it based on feedback from playtesting.) This helps to make the Amulet of Yendor feel special, and restores approximately the same average number of wishes per game as existed prior to the nerf to wands of wishing. Placing the wish in allmain helps to avoid the wish happening at an awkward place in the game's control flow, and is simpler than testing every possible mechanism for gaining items for bugs (message order is a common issue when trying to place it in addinv-related functions, and this also avoids issues with the wished-for item immediately invalidating an assumption that was made by the calling code). It is possible that this would be better as an invoke effect, although I like the impact of picking up the Amulet and immediately being given a wish. --- include/patchlevel.h | 2 +- include/you.h | 3 +++ src/allmain.c | 7 +++++++ src/u_init.c | 1 + 4 files changed, 12 insertions(+), 1 deletion(-) diff --git a/include/patchlevel.h b/include/patchlevel.h index 339095f25..4992b7f3a 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 126 +#define EDITLEVEL 127 /* * Development status possibilities. diff --git a/include/you.h b/include/you.h index 2683eec8f..bbd679d8f 100644 --- a/include/you.h +++ b/include/you.h @@ -52,6 +52,9 @@ struct u_event { Bitfield(udemigod, 1); /* killed the wiz */ Bitfield(uvibrated, 1); /* stepped on "vibrating square" */ Bitfield(ascended, 1); /* has offered the Amulet */ + + Bitfield(amulet_wish, 1); /* has gained a wish from the Amulet */ + /* 7 free bits */ }; /* diff --git a/src/allmain.c b/src/allmain.c index 5620e1eac..d80e50a78 100644 --- a/src/allmain.c +++ b/src/allmain.c @@ -428,6 +428,13 @@ moveloop_core(void) /****************************************/ clear_splitobjs(); + + /* the Amulet of Yendor gives a wish when initially picked up */ + if (u.uhave.amulet && !u.uevent.amulet_wish) { + u.uevent.amulet_wish = 1; + makewish(); + } + find_ac(); if (!svc.context.mv || Blind) { /* redo monsters if hallu or wearing a helm of telepathy */ diff --git a/src/u_init.c b/src/u_init.c index 1d0913f80..e4d60dd62 100644 --- a/src/u_init.c +++ b/src/u_init.c @@ -963,6 +963,7 @@ u_init(void) u.uevent.uheard_tune = 0; u.uevent.uopened_dbridge = 0; u.uevent.udemigod = 0; /* not a demi-god yet... */ + u.uevent.amulet_wish = 0; u.udg_cnt = 0; u.mh = u.mhmax = u.mtimedone = 0; u.uz.dnum = u.uz0.dnum = 0; From 9ed1e6201a31c75cab8ade3b1d6893e981d9a499 Mon Sep 17 00:00:00 2001 From: nhmall Date: Fri, 30 May 2025 09:09:10 -0400 Subject: [PATCH 675/791] try to help out onefile --- src/sfbase.c | 7 +++++++ src/sfstruct.c | 9 ++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/sfbase.c b/src/sfbase.c index 9d2e6006d..8c722eeb4 100644 --- a/src/sfbase.c +++ b/src/sfbase.c @@ -1159,3 +1159,10 @@ normalize_pointers_you(struct you *d_you UNUSED) { } #endif /* SFCTOOL */ + +#undef SF_X +#undef SF_C +#undef SF_A + +/* end of sfbase.c */ + diff --git a/src/sfstruct.c b/src/sfstruct.c index 971676c52..ef9dbdf37 100644 --- a/src/sfstruct.c +++ b/src/sfstruct.c @@ -684,4 +684,11 @@ logging_finish(void) } icnt = 0L; } -#endif +#endif /* SFLOGGING */ + +#undef SF_X +#undef SF_C +#undef SF_A + +/* end of sfstruct.c */ + From 8a2b8796cd8a5911bb7b4e177f5240cf90a29838 Mon Sep 17 00:00:00 2001 From: nhmall Date: Fri, 30 May 2025 09:46:19 -0400 Subject: [PATCH 676/791] file descriptor leak reported by analyzer --- src/files.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/files.c b/src/files.c index f69189f66..675fcc668 100644 --- a/src/files.c +++ b/src/files.c @@ -506,6 +506,8 @@ close_nhfile(NHFILE *nhfp) { if (nhfp->structlevel && nhfp->fd != -1) (void) nhclose(nhfp->fd), nhfp->fd = -1; + else if (nhfp->fpdef) + (void) fclose(nhfp->fpdef), nhfp->fpdef = (FILE *) 0; if (nhfp->fplog) (void) fprintf(nhfp->fplog, "# closing\n"); if (nhfp->fplog) @@ -847,6 +849,7 @@ create_bonesfile(d_level *lev, char **bonesid, char errbuf[]) failed = errno; } if (nhfp->structlevel) { +#ifndef UNIX #if defined(MICRO) || defined(WIN32) /* Use O_TRUNC to force the file to be shortened if it already * exists and is currently longer. @@ -854,12 +857,14 @@ create_bonesfile(d_level *lev, char **bonesid, char errbuf[]) nhfp->fd = open(file, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, FCMASK); #else +/* implies UNIX or MAC (MAC is for OS9 or earlier) */ #ifdef MAC nhfp->fd = maccreat(file, BONE_TYPE); #else nhfp->fd = creat(file, FCMASK); -#endif -#endif +#endif /* ?MAC */ +#endif /* ?MICRO || WIN32 */ +#endif /* UNIX */ if (nhfp->fd < 0) failed = errno; #if defined(MSDOS) @@ -1145,21 +1150,24 @@ create_savefile(void) #ifdef SAVEFILE_DEBUGGING nhfp->fplog = fopen("create-savefile.log", "w"); #endif - } +#ifndef UNIX #if defined(MICRO) || defined(WIN32) nhfp->fd = open(fq_save, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC, FCMASK); -#else +#else /* !MICRO && !WIN32 */ +/* UNIX || MAC implied (MAC is OS9 or earlier only) */ #ifdef MAC - nhfp->fd = maccreat(fq_save, SAVE_TYPE); + nhfp->fd = maccreat(fq_save, SAVE_TYPE); #else - nhfp->fd = creat(fq_save, FCMASK); + nhfp->fd = creat(fq_save, FCMASK); #endif #endif /* MICRO || WIN32 */ + } #if defined(MSDOS) || defined(WIN32) if (nhfp->fd >= 0) (void) setmode(nhfp->fd, O_BINARY); #endif +#endif /* UNIX */ } #if defined(VMS) && !defined(SECURE) /* From 1bf92496f4651347515efd6a4cd3254d2496717a Mon Sep 17 00:00:00 2001 From: nhmall Date: Fri, 30 May 2025 10:00:42 -0400 Subject: [PATCH 677/791] follow-up --- src/files.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/files.c b/src/files.c index 675fcc668..a1a49d527 100644 --- a/src/files.c +++ b/src/files.c @@ -849,14 +849,13 @@ create_bonesfile(d_level *lev, char **bonesid, char errbuf[]) failed = errno; } if (nhfp->structlevel) { -#ifndef UNIX #if defined(MICRO) || defined(WIN32) /* Use O_TRUNC to force the file to be shortened if it already * exists and is currently longer. */ nhfp->fd = open(file, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, FCMASK); -#else +#else /* ?MICRO || WIN32 */ /* implies UNIX or MAC (MAC is for OS9 or earlier) */ #ifdef MAC nhfp->fd = maccreat(file, BONE_TYPE); @@ -864,7 +863,6 @@ create_bonesfile(d_level *lev, char **bonesid, char errbuf[]) nhfp->fd = creat(file, FCMASK); #endif /* ?MAC */ #endif /* ?MICRO || WIN32 */ -#endif /* UNIX */ if (nhfp->fd < 0) failed = errno; #if defined(MSDOS) @@ -1150,7 +1148,6 @@ create_savefile(void) #ifdef SAVEFILE_DEBUGGING nhfp->fplog = fopen("create-savefile.log", "w"); #endif -#ifndef UNIX #if defined(MICRO) || defined(WIN32) nhfp->fd = open(fq_save, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC, FCMASK); @@ -1162,12 +1159,11 @@ create_savefile(void) nhfp->fd = creat(fq_save, FCMASK); #endif #endif /* MICRO || WIN32 */ - } #if defined(MSDOS) || defined(WIN32) if (nhfp->fd >= 0) (void) setmode(nhfp->fd, O_BINARY); #endif -#endif /* UNIX */ + } } #if defined(VMS) && !defined(SECURE) /* From e365b5b18fc95be696ffefbd8c5914b8e58ce4c2 Mon Sep 17 00:00:00 2001 From: nhmall Date: Fri, 30 May 2025 14:01:41 -0400 Subject: [PATCH 678/791] more static analyzer adjustments --- include/extern.h | 3 ++- src/cmd.c | 8 ++++---- src/files.c | 45 +++++++++++++++++++++++++++++++++++---------- src/restore.c | 10 +++------- src/save.c | 40 +++++++++++++++++++++------------------- util/sfctool.c | 10 +++++----- 6 files changed, 70 insertions(+), 46 deletions(-) diff --git a/include/extern.h b/include/extern.h index 533523198..e3375627f 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1036,7 +1036,7 @@ extern char *fname_encode(const char *, char, extern char *fname_decode(char, char *, char *, int) NONNULLPTRS; extern const char *fqname(const char *, int, int); extern FILE *fopen_datafile(const char *, const char *, int) NONNULLPTRS; -extern void zero_nhfile(NHFILE *) NONNULLARG1; +extern void init_nhfile(NHFILE *) NONNULLARG1; extern void close_nhfile(NHFILE *) NONNULLARG1; extern void rewind_nhfile(NHFILE *) NONNULLARG1; extern void set_levelfile_name(char *, int) NONNULLARG1; @@ -1059,6 +1059,7 @@ extern void set_error_savefile(void); extern NHFILE *create_savefile(void); extern NHFILE *open_savefile(void); extern int delete_savefile(void); +extern NHFILE *get_freeing_nhfile(void); extern NHFILE *restore_saved_game(void); extern int check_panic_save(void); #ifdef SELECTSAVED diff --git a/src/cmd.c b/src/cmd.c index 8b912dc40..68a8b1304 100644 --- a/src/cmd.c +++ b/src/cmd.c @@ -981,7 +981,7 @@ enter_explore_mode(void) void makemap_prepost(boolean pre, boolean wiztower) { - NHFILE tmpnhfp; + NHFILE *tmpnhfp; struct monst *mtmp; if (pre) { @@ -1029,9 +1029,9 @@ makemap_prepost(boolean pre, boolean wiztower) dobjsfree(); /* discard current level; "saving" is used to release dynamic data */ - zero_nhfile(&tmpnhfp); /* also sets fd to -1 as desired */ - tmpnhfp.mode = FREEING; - savelev(&tmpnhfp, ledger_no(&u.uz)); + tmpnhfp = get_freeing_nhfile(); + savelev(tmpnhfp, ledger_no(&u.uz)); + close_nhfile(tmpnhfp); } else { vision_reset(); gv.vision_full_recalc = 1; diff --git a/src/files.c b/src/files.c index a1a49d527..c9e90562e 100644 --- a/src/files.c +++ b/src/files.c @@ -458,23 +458,35 @@ static const int bei = 1; #define IS_BIGENDIAN() ( (*(char*)&bei) == 0 ) void -zero_nhfile(NHFILE *nhfp) +init_nhfile(NHFILE *nhfp) { + if (nhfp->structlevel) { + if (nhfp->fd != -1) { + impossible("Warning - Unclosed structlevel file being reinitialized"); + (void) nhclose(nhfp->fd); + } + } else if (nhfp->fpdef) { + if (nhfp->fpdef) { + impossible("Warning - Unclosed fieldlevel file being reinitialized"); + (void) fclose(nhfp->fpdef); + } + } nhfp->fd = -1; + nhfp->fpdef = (FILE *) 0; + nhfp->mode = COUNTING; nhfp->structlevel = TRUE; nhfp->fieldlevel = FALSE; nhfp->addinfo = FALSE; nhfp->bendian = IS_BIGENDIAN(); - nhfp->fpdef = (FILE *) 0; nhfp->fplog = (FILE *) 0; nhfp->fpdebug = (FILE *) 0; nhfp->rcount = nhfp->wcount = 0; nhfp->eof = FALSE; nhfp->fnidx = 0; - nhfp->style.deflt = FALSE; - nhfp->style.binary = TRUE; - nhfp->nhfpconvert = 0; + nhfp->style.deflt = FALSE; + nhfp->style.binary = TRUE; + nhfp->nhfpconvert = 0; } #ifndef SFCTOOL @@ -483,9 +495,10 @@ staticfn NHFILE * new_nhfile(void) { - NHFILE *nhfp = (NHFILE *) alloc(sizeof(NHFILE)); + NHFILE *nhfp = (NHFILE *) alloc(sizeof *nhfp); - zero_nhfile(nhfp); + memset((genericptr_t) nhfp, 0, sizeof *nhfp); + init_nhfile(nhfp); return nhfp; } @@ -496,7 +509,7 @@ void free_nhfile(NHFILE *nhfp) { if (nhfp) { - zero_nhfile(nhfp); + init_nhfile(nhfp); free(nhfp); } } @@ -514,7 +527,7 @@ close_nhfile(NHFILE *nhfp) (void) fclose(nhfp->fplog); if (nhfp->fpdebug) (void) fclose(nhfp->fpdebug); - zero_nhfile(nhfp); + init_nhfile(nhfp); free_nhfile(nhfp); } @@ -559,7 +572,7 @@ viable_nhfile(NHFILE *nhfp) if (nhfp->fpdebug) (void) fclose(nhfp->fpdebug); } - zero_nhfile(nhfp); + init_nhfile(nhfp); free_nhfile(nhfp); nhfp = (NHFILE *) 0; } @@ -1254,6 +1267,18 @@ restore_saved_game(void) return nhfp; } +NHFILE * +get_freeing_nhfile(void) +{ + NHFILE *nhfp = (NHFILE *) 0; + + nhfp = new_nhfile(); /* also sets fd to -1 */ + if (nhfp) { + nhfp->mode = FREEING; + } + return nhfp; +} + /* called if there is no save file for current character */ int check_panic_save(void) diff --git a/src/restore.c b/src/restore.c index dc87cb696..25f96f239 100644 --- a/src/restore.c +++ b/src/restore.c @@ -806,15 +806,11 @@ dorecover(NHFILE *nhfp) */ getlev(nhfp, 0, (xint8) 0); if (!restgamestate(nhfp)) { - NHFILE tnhfp; + NHFILE *tnhfp = get_freeing_nhfile(); display_nhwindow(WIN_MESSAGE, TRUE); - zero_nhfile(&tnhfp); - tnhfp.mode = FREEING; - tnhfp.fd = -1; - savelev(&tnhfp, 0); /* discard current level */ - /* no need for close_nhfile(&tnhfp), which - is not really affiliated with an open file */ + savelev(tnhfp, 0); /* discard current level */ + close_nhfile(tnhfp); close_nhfile(nhfp); (void) delete_savefile(); u.usteed_mid = u.ustuck_mid = 0; diff --git a/src/save.c b/src/save.c index bc420a041..aa9e32c3d 100644 --- a/src/save.c +++ b/src/save.c @@ -1037,13 +1037,12 @@ void free_dungeons(void) { #ifdef FREE_ALL_MEMORY - NHFILE tnhfp; + NHFILE *tnhfp = get_freeing_nhfile(); - zero_nhfile(&tnhfp); /* also sets fd to -1 */ - tnhfp.mode = FREEING; - savelevchn(&tnhfp); - save_dungeon(&tnhfp, FALSE, TRUE); + savelevchn(tnhfp); + save_dungeon(tnhfp, FALSE, TRUE); free_luathemes(all_themes); + close_nhfile(tnhfp); #endif return; } @@ -1054,13 +1053,11 @@ extern int options_set_window_colors_flag; /* options.c */ void freedynamicdata(void) { - NHFILE tnhfp; + NHFILE *tnhfp = get_freeing_nhfile(); #if defined(UNIX) && defined(MAIL) free_maildata(); #endif - zero_nhfile(&tnhfp); /* also sets fd to -1 */ - tnhfp.mode = FREEING; free_menu_coloring(); free_invbuf(); /* let_to_name (invent.c) */ free_youbuf(); /* You_buf,&c (pline.c) */ @@ -1069,18 +1066,18 @@ freedynamicdata(void) tmp_at(DISP_FREEMEM, 0); /* temporary display effects */ purge_all_custom_entries(); #ifdef FREE_ALL_MEMORY -#define free_current_level() savelev(&tnhfp, -1) -#define freeobjchn(X) (saveobjchn(&tnhfp, &X), X = 0) -#define freemonchn(X) (savemonchn(&tnhfp, X), X = 0) -#define freefruitchn() savefruitchn(&tnhfp) -#define freenames() savenames(&tnhfp) -#define free_killers() save_killers(&tnhfp) -#define free_oracles() save_oracles(&tnhfp) -#define free_waterlevel() save_waterlevel(&tnhfp) -#define free_timers(R) save_timers(&tnhfp, R) -#define free_light_sources(R) save_light_sources(&tnhfp, R) +#define free_current_level() savelev(tnhfp, -1) +#define freeobjchn(X) (saveobjchn(tnhfp, &X), X = 0) +#define freemonchn(X) (savemonchn(tnhfp, X), X = 0) +#define freefruitchn() savefruitchn(tnhfp) +#define freenames() savenames(tnhfp) +#define free_killers() save_killers(tnhfp) +#define free_oracles() save_oracles(tnhfp) +#define free_waterlevel() save_waterlevel(tnhfp) +#define free_timers(R) save_timers(tnhfp, R) +#define free_light_sources(R) save_light_sources(tnhfp, R) #define free_animals() mon_animal_list(FALSE) -#define discard_gamelog() save_gamelog(&tnhfp); +#define discard_gamelog() save_gamelog(tnhfp); /* move-specific data */ dmonsfree(); /* release dead monsters */ @@ -1155,6 +1152,11 @@ freedynamicdata(void) if (glyphid_cache_status()) free_glyphid_cache(); + if (tnhfp) { + close_nhfile(tnhfp); + tnhfp = 0; + } + /* last, because it frees data that might be used by panic() to provide feedback to the user; conceivably other freeing might trigger panic */ sysopt_release(); /* SYSCF strings */ diff --git a/util/sfctool.c b/util/sfctool.c index fe016748f..de25963a4 100644 --- a/util/sfctool.c +++ b/util/sfctool.c @@ -80,7 +80,7 @@ static int length_without_val(const char *user_string, int len); static void usage(int argc, char **argv); static const char *briefname(const char *fnam); -void zero_nhfile(NHFILE *); +void init_nhfile(NHFILE *); NHFILE *new_nhfile(void); void free_nhfile(NHFILE *); void my_close_nhfile(NHFILE *); @@ -462,7 +462,7 @@ open_srcfile(const char *fnam, enum saveformats mystyle) if (nhfp && nhfp->structlevel) { fd = open(fq_name, O_RDONLY | O_BINARY, 0); if (fd < 0) { - zero_nhfile(nhfp); + init_nhfile(nhfp); free_nhfile(nhfp); fprintf(stderr, "\nsfctool error - unable to open historical-style " @@ -482,7 +482,7 @@ open_srcfile(const char *fnam, enum saveformats mystyle) nhfp->fpdef = fopen(fnam, RDBMODE); if (!nhfp->fpdef) { - zero_nhfile(nhfp); + init_nhfile(nhfp); free_nhfile(nhfp); fprintf(stderr, "\nsfctool error - unable to open fieldlevel-style " @@ -577,7 +577,7 @@ create_dstfile(char *fnam, enum saveformats mystyle) fd = creat(dstfnam, FCMASK); #endif if (fd < 0) { - zero_nhfile(nhfp); + init_nhfile(nhfp); free_nhfile(nhfp); fprintf( stderr, @@ -594,7 +594,7 @@ create_dstfile(char *fnam, enum saveformats mystyle) fq_name = fqname(dstfnam, SAVEPREFIX, 0); nhfp->fpdef = fopen(fq_name, WRBMODE); if (!nhfp->fpdef) { - zero_nhfile(nhfp); + init_nhfile(nhfp); free_nhfile(nhfp); fprintf( stderr, From 50e5715ca5646d0ac28adc89c07db2005d57cebb Mon Sep 17 00:00:00 2001 From: nhmall Date: Fri, 30 May 2025 21:17:07 -0400 Subject: [PATCH 679/791] fix X11 warning with gcc-15 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ../win/X11/winX.c: In function ‘init_standard_windows’: ../win/X11/winX.c:2769:46: warning: passing argument 2 of ‘XtAppSetErrorHandler’ makes ‘__attribute__((noreturn))’ qualified function pointer from unqualified [-Wdiscarded-qualifiers] 2769 | (void) XtAppSetErrorHandler(app_context, X11_error_handler); | ^~~~~~~~~~~~~~~~~ In file included from ../win/X11/winX.c:27: /usr/include/X11/Intrinsic.h:1771:5: note: expected ‘__attribute__((noreturn)) void (*)(char *)’ but argument is of type ‘void (*)(char *)’ 1771 | XtErrorHandler /* handler */ _X_NORETURN | ^ --- win/X11/winX.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/win/X11/winX.c b/win/X11/winX.c index db95dea15..54c3579f6 100644 --- a/win/X11/winX.c +++ b/win/X11/winX.c @@ -100,7 +100,7 @@ int click_x, click_y, click_button; /* Click position on a map window int updated_inventory; /* used to indicate perm_invent updating */ color_attr X11_menu_promptstyle = { NO_COLOR, ATR_NONE }; -static void X11_error_handler(String) NORETURN; +ATTRNORETURN static void X11_error_handler(String) NORETURN; static int X11_io_error_handler(Display *); static int (*old_error_handler)(Display *, XErrorEvent *); @@ -175,7 +175,7 @@ static void X11_sig_cb(XtPointer, XtSignalId *); #endif static void d_timeout(XtPointer, XtIntervalId *); static void X11_hangup(Widget, XEvent *, String *, Cardinal *); -static void X11_bail(const char *) NORETURN; +ATTRNORETURN static void X11_bail(const char *) NORETURN; static void askname_delete(Widget, XEvent *, String *, Cardinal *); static void askname_done(Widget, XtPointer, XtPointer); static void done_button(Widget, XtPointer, XtPointer); From 9ef5e886eeee2c4854fe115fa8e61a88a680ad73 Mon Sep 17 00:00:00 2001 From: nhmall Date: Fri, 30 May 2025 22:01:20 -0400 Subject: [PATCH 680/791] consistent ATTRNORETURN prefix and NORETURN suffix --- sys/vms/Makefile_src.vms | 4 ++-- sys/vms/Makefile_top.vms | 2 +- sys/vms/vmsbuild.com | 2 +- sys/vms/vmsmisc.c | 4 ++-- sys/windows/GNUmakefile | 2 +- sys/windows/Makefile.nmake | 2 +- sys/windows/vs/FetchPrereq/fetchprereq.nmake | 2 +- sys/windows/vs/hacklib/hacklib.vcxproj | 2 +- sys/windows/vs/lualib/lualib.vcxproj | 2 +- util/sfctool.c | 4 ++-- 10 files changed, 13 insertions(+), 13 deletions(-) diff --git a/sys/vms/Makefile_src.vms b/sys/vms/Makefile_src.vms index 5123dfe4c..334145b22 100644 --- a/sys/vms/Makefile_src.vms +++ b/sys/vms/Makefile_src.vms @@ -319,7 +319,7 @@ hacklib.olb: $(HACKLIBOBJLIST) $(INCL)nhlua.h: echo "/* nhlua.h - generated by Makefile.vms */" > $@ @echo \#"include ""$(LUASRCINCDIR)lua.h""" >> $@ - @echo "LUA_API int (lua_error) (lua_State *L) NORETURN;" >>$@ + @echo "ATTRNORETURN LUA_API int (lua_error) (lua_State *L) NORETURN;" >>$@ @echo \#"include ""$(LUASRCINCDIR)lualib.h""" >> $@ @echo \#"include ""$(LUASRCINCDIR)lauxlib.h""" >> $@ @echo "/*nhlua.h*/" >> $@ @@ -327,7 +327,7 @@ $(INCL)nhlua.h: #$(INCL)nhlua.h: # echo "/* nhlua.h - generated by -vms9 */" > $@ # @echo \#"include ""sys$$common:[lua.include]lua.h""" >> $@ -# @echo "LUA_API int (lua_error) (lua_State *L) NORETURN;" >>$@ +# @echo "ATTRNORETURN LUA_API int (lua_error) (lua_State *L) NORETURN;" >>$@ # @echo \#"include ""sys$$common:[lua.include]lualib.h""" >> $@ # @echo \#"include ""sys$$common:[lua.include]lauxlib.h""" >> $@ # @echo "/*nhlua.h*/" >> $@ diff --git a/sys/vms/Makefile_top.vms b/sys/vms/Makefile_top.vms index 505b797b0..7a28ff098 100644 --- a/sys/vms/Makefile_top.vms +++ b/sys/vms/Makefile_top.vms @@ -314,7 +314,7 @@ dofiles-nodlb: $(INCL)nhlua.h: echo "/* nhlua.h - generated by top-level Makefile.vms */" > $@ @echo \#"include ""lua.h""" >> $@ - @echo "LUA_API int (lua_error) (lua_State *L) NORETURN;" >>$@ + @echo "ATTRNORETURN LUA_API int (lua_error) (lua_State *L) NORETURN;" >>$@ @echo \#"include ""lualib.h""" >> $@ @echo \#"include ""lauxlib.h""" >> $@ @echo "/*nhlua.h*/" >> $@ diff --git a/sys/vms/vmsbuild.com b/sys/vms/vmsbuild.com index b9f8cc721..737fbf015 100755 --- a/sys/vms/vmsbuild.com +++ b/sys/vms/vmsbuild.com @@ -377,7 +377,7 @@ $ set file/att=(RFM:STM) [-.include]nhlua.h $ open/Append f [-.include]nhlua.h $ write f "/* nhlua.h - generated by vmsbuild.com */" $ write f "#include ""[-.lib.lua''luaver'.src]lua.h""" -$ write f "LUA_API int (lua_error) (lua_State *L) NORETURN;" +$ write f "ATTRNORETURN LUA_API int (lua_error) (lua_State *L) NORETURN;" $ write f "#include ""[-.lib.lua''luaver'.src]lualib.h""" $ write f "#include ""[-.lib.lua''luaver'.src]lauxlib.h""" $ write f "/*nhlua.h*/" diff --git a/sys/vms/vmsmisc.c b/sys/vms/vmsmisc.c index 2c1226174..fa705161c 100644 --- a/sys/vms/vmsmisc.c +++ b/sys/vms/vmsmisc.c @@ -16,8 +16,8 @@ int debuggable = 0; /* 1 if we can debug or show a call trace */ -ATTRNORETURN void vms_exit(int); -ATTRNORETURN void vms_abort(void); +ATTRNORETURN void vms_exit(int) NORETURN; +ATTRNORETURN void vms_abort(void) NORETURN; /* first arg should be unsigned long but has unsigned int */ diff --git a/sys/windows/GNUmakefile b/sys/windows/GNUmakefile index 3253e195e..8ba1ee4b2 100644 --- a/sys/windows/GNUmakefile +++ b/sys/windows/GNUmakefile @@ -435,7 +435,7 @@ NHLUAH = $(INCL)/nhlua.h $(NHLUAH): echo "/* nhlua.h - generated by GNUmakefile */" > $@ @echo "#include \"$(LUASRC)/lua.h\"" >> $@ - @echo "LUA_API int (lua_error) (lua_State *L) NORETURN;" >>$@ + @echo "ATTRNORETURN LUA_API int (lua_error) (lua_State *L) NORETURN;" >>$@ @echo "#include \"$(LUASRC)/lualib.h\"" >> $@ @echo "#include \"$(LUASRC)/lauxlib.h\"" >> $@ @echo "/*nhlua.h*/" >> $@ diff --git a/sys/windows/Makefile.nmake b/sys/windows/Makefile.nmake index e8d97fd09..f63336683 100644 --- a/sys/windows/Makefile.nmake +++ b/sys/windows/Makefile.nmake @@ -1769,7 +1769,7 @@ $(OUTL)utility.tag: $(INCL)nhlua.h outldir$(TARGET_CPU).tag $(OUTLHACKLIB) $(U)t $(INCL)nhlua.h: @echo /* nhlua.h - generated by Makefile from Makefile.nmake */ > $@ @echo #include "lua.h" >> $@ - @echo LUA_API int (lua_error) (lua_State *L) NORETURN; >> $@ + @echo ATTRNORETURN LUA_API int (lua_error) (lua_State *L) NORETURN; >> $@ @echo #include "lualib.h" >> $@ @echo #include "lauxlib.h" >> $@ @echo /*nhlua.h*/ >> $@ diff --git a/sys/windows/vs/FetchPrereq/fetchprereq.nmake b/sys/windows/vs/FetchPrereq/fetchprereq.nmake index 3b0ea1b8c..07c62dbb6 100644 --- a/sys/windows/vs/FetchPrereq/fetchprereq.nmake +++ b/sys/windows/vs/FetchPrereq/fetchprereq.nmake @@ -59,7 +59,7 @@ fetch-pdcurses: ..\..\..\..\include\nhlua.h: @echo /* nhlua.h - generated by Makefile from fetchprereq.nmake */ > $@ @echo #include "lua.h" >> $@ - @echo LUA_API int (lua_error) (lua_State *L) NORETURN; >> $@ + @echo ATTRNORETURN LUA_API int (lua_error) (lua_State *L) NORETURN; >> $@ @echo #include "lualib.h" >> $@ @echo #include "lauxlib.h" >> $@ @echo /*nhlua.h*/ >> $@ diff --git a/sys/windows/vs/hacklib/hacklib.vcxproj b/sys/windows/vs/hacklib/hacklib.vcxproj index 3be14bb62..23b673271 100644 --- a/sys/windows/vs/hacklib/hacklib.vcxproj +++ b/sys/windows/vs/hacklib/hacklib.vcxproj @@ -172,7 +172,7 @@ - + diff --git a/sys/windows/vs/lualib/lualib.vcxproj b/sys/windows/vs/lualib/lualib.vcxproj index 537be7191..13c01453e 100644 --- a/sys/windows/vs/lualib/lualib.vcxproj +++ b/sys/windows/vs/lualib/lualib.vcxproj @@ -471,7 +471,7 @@ - + diff --git a/util/sfctool.c b/util/sfctool.c index de25963a4..f568a793f 100644 --- a/util/sfctool.c +++ b/util/sfctool.c @@ -90,10 +90,10 @@ int util_strncmpi(const char *s1, const char *s2, size_t sz); #ifdef UNIX #define nethack_exit exit -void nh_terminate(int) NORETURN; /* bwrite() calls this */ +ATTRNORETURN void nh_terminate(int) NORETURN; /* bwrite() calls this */ static void chdirx(const char *); #else -extern void nethack_exit(int) NORETURN; +ATTRNORETURN extern void nethack_exit(int) NORETURN; #ifdef WIN32 boolean get_user_home_folder(char *homebuf, size_t sz); int GUILaunched; From 45332084736265390fa391468226c859572030ec Mon Sep 17 00:00:00 2001 From: PatR Date: Fri, 30 May 2025 19:50:14 -0700 Subject: [PATCH 681/791] killer ants and soldier bees This started out as an indentation fix but ended up tweaking a couple of comments. The other value adjustments all use 'n += X' rather than directly modify 'tmp', so this changed more than just the indentation. --- src/mondata.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/mondata.c b/src/mondata.c index 4c2cea0ce..d7ea80245 100644 --- a/src/mondata.c +++ b/src/mondata.c @@ -474,16 +474,16 @@ mstrength(struct permonst *ptr) n += ((int) (ptr->mattk[i].damd * ptr->mattk[i].damn) > 23); } - /* Leprechauns are special cases. They have many hit dice so they - can hit and are hard to kill, but they don't really do much damage. */ + /* Leprechauns are a special case. They have many hit dice so they can + hit and are hard to kill, but they don't really do much damage. */ if (!strcmp(ptr->pmnames[NEUTRAL], "leprechaun")) n -= 2; - /* Soldier ants and killer bees are underestimated by the formula, - so have an artificial +1 difficulty */ + /* despite group and poison increments, soldier ants and killer bees are + underestimated by the formula, so have an artificial +1 difficulty */ if (!strcmp(ptr->pmnames[NEUTRAL], "killer bee") || !strcmp(ptr->pmnames[NEUTRAL], "soldier ant")) - tmp += 1; + n += 2; /* +1 after 'tmp += n/2' below */ /* finally, adjust the monster level 0 <= n <= 24 (approx.) */ if (n == 0) From d2810a4bcd7a667373b9d2705cb108e5e1c9bd34 Mon Sep 17 00:00:00 2001 From: PatR Date: Fri, 30 May 2025 22:20:21 -0700 Subject: [PATCH 682/791] fix github issue #1413 - mimic feedback for gold Issue reported by ars3niy: if a mimic was given the shape of a gold piece it gets reported as 2 gold pieces but the message was |A gold pieces appears next to you. Avoid article "A" prefix, and use plural verb "appear" instead of singular "appears", yielding |Gold pieces appear next to you. Fixes #1413 --- doc/fixes3-7-0.txt | 1 + src/makemon.c | 4 +++- src/pager.c | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index c1c24371f..cc3076cb2 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -2116,6 +2116,7 @@ successfully disarming a chest trap was clearing the chest's 'tknown' bit used up the trap when game ended with 'force_invmenu' On, final disclosure of inventory would contain spurious menu entry "? - (list likely candidates)" +avoid reporting "a gold pieces appears next to you" for mimic Fixes to 3.7.0-x Platform and/or Interface Problems Exposed Via git Repository diff --git a/src/makemon.c b/src/makemon.c index 2de8003ae..f9578b586 100644 --- a/src/makemon.c +++ b/src/makemon.c @@ -1485,8 +1485,10 @@ makemon( } if (what) { set_msg_xy(mtmp->mx, mtmp->my); - Norep("%s%s appears%s%c", what, + Norep("%s%s %s%s%c", what, exclaim ? " suddenly" : "", + /* 'what' might be "gold pieces" so need plural verb */ + vtense(what, "appear"), next2u(x, y) ? " next to you" : (distu(x, y) <= (BOLT_LIM * BOLT_LIM)) ? " close by" : "", diff --git a/src/pager.c b/src/pager.c index 0b83c4910..e2e0c06a9 100644 --- a/src/pager.c +++ b/src/pager.c @@ -220,7 +220,7 @@ mhidden_description( what = (otmp && otmp->otyp != STRANGE_OBJECT) ? simpleonames(otmp) : obj_descr[STRANGE_OBJECT].oc_name; - if (incl_article) + if (incl_article && (!otmp || otmp->quan == 1L)) what = an(what); Strcat(outbuf, what); From aa50f30653a870de05838558763534cb1182c0a7 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 31 May 2025 07:11:36 -0400 Subject: [PATCH 683/791] free_nhfile() will already call init_nhfile() --- src/files.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/files.c b/src/files.c index c9e90562e..d91a85fc3 100644 --- a/src/files.c +++ b/src/files.c @@ -527,7 +527,6 @@ close_nhfile(NHFILE *nhfp) (void) fclose(nhfp->fplog); if (nhfp->fpdebug) (void) fclose(nhfp->fpdebug); - init_nhfile(nhfp); free_nhfile(nhfp); } @@ -572,7 +571,6 @@ viable_nhfile(NHFILE *nhfp) if (nhfp->fpdebug) (void) fclose(nhfp->fpdebug); } - init_nhfile(nhfp); free_nhfile(nhfp); nhfp = (NHFILE *) 0; } From c05766e99f3b490efa663788490411c20db4f643 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 31 May 2025 07:17:40 -0400 Subject: [PATCH 684/791] get_freeing_nhfile() comment --- src/files.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/files.c b/src/files.c index d91a85fc3..ab4ba9ed8 100644 --- a/src/files.c +++ b/src/files.c @@ -1265,6 +1265,15 @@ restore_saved_game(void) return nhfp; } +/* + * This doesn't open any files. It provides a valid (NHFILE *) + * to provide to functions that take one as a parameter, with + * only the FREEING bit set. + * + * close_nhfile() can, and should, be called on the returned + * (NHFILE *), and it will handle it correctly. + */ + NHFILE * get_freeing_nhfile(void) { From 31369c210107f1c35e63c80ca58ed1a3493669d8 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 31 May 2025 07:36:44 -0400 Subject: [PATCH 685/791] more free_nhfile() will already call init_nhfile() --- util/sfctool.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/util/sfctool.c b/util/sfctool.c index f568a793f..f87976381 100644 --- a/util/sfctool.c +++ b/util/sfctool.c @@ -80,12 +80,17 @@ static int length_without_val(const char *user_string, int len); static void usage(int argc, char **argv); static const char *briefname(const char *fnam); -void init_nhfile(NHFILE *); -NHFILE *new_nhfile(void); -void free_nhfile(NHFILE *); -void my_close_nhfile(NHFILE *); +extern void init_nhfile(NHFILE *); /* files.c */ +extern NHFILE *new_nhfile(void); /* files.c */ +extern void free_nhfile(NHFILE *); /* files.c */ + +/* + * This is a replacement tempered down version of same-named + * function in files.c within #ifndef SFCTOOL blocks. + */ int delete_savefile(void); -int nhclose(int fd); + +// int nhclose(int fd); int util_strncmpi(const char *s1, const char *s2, size_t sz); #ifdef UNIX @@ -462,7 +467,6 @@ open_srcfile(const char *fnam, enum saveformats mystyle) if (nhfp && nhfp->structlevel) { fd = open(fq_name, O_RDONLY | O_BINARY, 0); if (fd < 0) { - init_nhfile(nhfp); free_nhfile(nhfp); fprintf(stderr, "\nsfctool error - unable to open historical-style " @@ -482,7 +486,6 @@ open_srcfile(const char *fnam, enum saveformats mystyle) nhfp->fpdef = fopen(fnam, RDBMODE); if (!nhfp->fpdef) { - init_nhfile(nhfp); free_nhfile(nhfp); fprintf(stderr, "\nsfctool error - unable to open fieldlevel-style " @@ -577,7 +580,6 @@ create_dstfile(char *fnam, enum saveformats mystyle) fd = creat(dstfnam, FCMASK); #endif if (fd < 0) { - init_nhfile(nhfp); free_nhfile(nhfp); fprintf( stderr, @@ -594,7 +596,6 @@ create_dstfile(char *fnam, enum saveformats mystyle) fq_name = fqname(dstfnam, SAVEPREFIX, 0); nhfp->fpdef = fopen(fq_name, WRBMODE); if (!nhfp->fpdef) { - init_nhfile(nhfp); free_nhfile(nhfp); fprintf( stderr, From 3aef3eef86ef926ab4acdaa2394d7f0072a0e46f Mon Sep 17 00:00:00 2001 From: Michael Allison Date: Sat, 31 May 2025 10:55:06 -0400 Subject: [PATCH 686/791] try to prevent a segfault on macOS --- util/sftags.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/util/sftags.c b/util/sftags.c index cdb8f3a7a..ba821aa6f 100644 --- a/util/sftags.c +++ b/util/sftags.c @@ -137,6 +137,12 @@ static FILE *vms_fopen(name, mode) const char *name, *mode; #define TAB '\t' #define SPACE ' ' +#ifdef MACOS +#define ALIGN32 __attribute__((aligned(32))) +#else +#define ALIGN32 +#endif + struct tagstruct *first; struct tagstruct zerotag = { 0 }; @@ -339,14 +345,20 @@ RESTORE_WARNINGS static void doline(char *aline) { - char buf[255]; - struct tagstruct *tmptag; + char buf[255], *cp; + struct tagstruct * ALIGN32 tmptag; + size_t slen; if (!aline || (aline && *aline == '!')) { return; } - tmptag = malloc(sizeof(struct tagstruct)); + cp = deeol(aline); + slen = strlen(cp); + if (slen > sizeof buf - 1) { + slen = sizeof buf - 1; + } + tmptag = malloc(sizeof *tmptag); if (!tmptag) { out_of_memory(); } @@ -354,13 +366,14 @@ static void doline(char *aline) *tmptag = zerotag; tmptag->marker = 0xDEADBEEF; - strncpy(buf, deeol(aline), sizeof buf - 1); + strncpy(buf, cp, slen); + buf[sizeof buf - 1] = '\0'; taglineparse(buf, tmptag); chain(tmptag); return; } -static struct tagstruct *prevtag = (struct tagstruct *) 0; +static struct tagstruct * ALIGN32 prevtag = NULL; static void chain(struct tagstruct *tag) { @@ -707,11 +720,13 @@ findtype(char *st, char *tag) if (!st) return (char *)0; +#if 0 if (st && strstr(st, "mapseen")) { int xx = 0; xx++; } +#endif if (st[0] == '/' && st[1] == '^') { tmp2 = tmp3 = tmp4 = (char *)0; tmp1 = &st[3]; From 32e8aa10683128b9db1cf8b6e19f531e8d47ec5c Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 31 May 2025 11:19:46 -0400 Subject: [PATCH 687/791] more descriptive message in sfctool for outdated savefile --- util/sfctool.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/util/sfctool.c b/util/sfctool.c index f87976381..83b13884e 100644 --- a/util/sfctool.c +++ b/util/sfctool.c @@ -319,15 +319,29 @@ process_savefile(const char *srcfnam, enum saveformats srcstyle, cscbuf[5]); /* ptr */ if (sfstatus > SF_UPTODATE && ((sfstatus <= SF_CRITICAL_BYTE_COUNT_MISMATCH) || !unconvert)) { - fprintf(stderr, - "The %s savefile %s%s%s not compatible with this %s%sutility.\n", + if (sfstatus == SF_OUTDATED) { + fprintf(stderr, + "The %s savefile is outdated with respect to this %d.%d.%d EDITLEVEL %ld " + "%s%s%s.\n", + briefname(srcfnam), + VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL, + (long) EDITLEVEL, + thisdatamodel ? thisdatamodel : "", + thisdatamodel ? " " : "", + "sfctool"); + return 0; + } else { + fprintf(stderr, + "The %s savefile %s%s%s not compatible with this %s%s %s utility.\n", briefname(srcfnam), dmfile ? "is a " : "", dmfile ? dmfile : "", dmfile ? " savefile, thus" : " is", thisdatamodel ? thisdatamodel : "", - thisdatamodel ? " " : ""); - return 0; + thisdatamodel ? " " : "", + "sfctool"); + return 0; + } } if (sfstatus >= SF_DM_IL32LLP64_ON_ILP32LL64) { renidx = sfstatus - SF_DM_IL32LLP64_ON_ILP32LL64; From 468be966fea5cdbb6a38bb155a64012ce53c6559 Mon Sep 17 00:00:00 2001 From: PatR Date: Sat, 31 May 2025 09:15:25 -0700 Subject: [PATCH 688/791] wishing for " amulet" I saw a mimic disguised as an octagonal amulet and wished for an amulet of that shape to see what it was trying to tempt me with. I got a random amulet instead of one with the requested description. That was happening for any valid shape (it's expected behavior for invalid descriptions, where only "amulet" matches). --- src/objnam.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/objnam.c b/src/objnam.c index 32091dfcc..e05ea1c12 100644 --- a/src/objnam.c +++ b/src/objnam.c @@ -4538,8 +4538,8 @@ readobjnam_postparse1(struct _readobjnam_data *d) return 4; /*goto any;*/ } - /* Search for class names: XXXXX potion, scroll of XXXXX. Avoid */ - /* false hits on, e.g., rings for "ring mail". */ + /* Search for class names: XXXXX potion, scroll of XXXXX. + Avoid false hits on, e.g., rings for "ring mail". */ if (strncmpi(d->bp, "enchant ", 8) && strncmpi(d->bp, "destroy ", 8) && strncmpi(d->bp, "detect food", 11) @@ -4579,12 +4579,26 @@ readobjnam_postparse1(struct _readobjnam_data *d) if (d->p > d->bp && d->p[-1] == ' ') d->p[-1] = '\0'; } else { + int k, l; + char amubuf[BUFSZ]; + /* amulet without "of"; convoluted wording but better a special case that's handled than one that's missing */ if (!strncmpi(d->bp, "versus poison ", 14)) { d->typ = AMULET_VERSUS_POISON; return 2; /*goto typfnd;*/ } + /* check for " amulet"; strip off trailing + " amulet" for that w/o changing contents of d->bp */ + l = (int) strlen(d->bp) - j; + if (l > 0 && d->bp[l - 1] == ' ') + l -= 1; + copynchars(amubuf, d->bp, min(l, (int) sizeof amubuf - 1)); + k = rnd_otyp_by_namedesc(amubuf, AMULET_CLASS, 0); + if (k != STRANGE_OBJECT) { + d->typ = k; + return 2; /*goto typfnd;*/ + } } d->actualn = d->dn = d->bp; return 1; /*goto srch;*/ From 79be47b1ad92611716b3122995c6edab59ca61e5 Mon Sep 17 00:00:00 2001 From: PatR Date: Sat, 31 May 2025 16:41:43 -0700 Subject: [PATCH 689/791] montraits of weapon-wielding monsters Have save_mtraits() clear wielded weapon when attaching monster attributes to a corpse object. And have monster sanity check verify that wielded weapon is in the monster's inventory. --- src/mkobj.c | 1 + src/mon.c | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/src/mkobj.c b/src/mkobj.c index 57060e4c5..2f93d43c8 100644 --- a/src/mkobj.c +++ b/src/mkobj.c @@ -2154,6 +2154,7 @@ save_mtraits(struct obj *obj, struct monst *mtmp) mtmp2->nmon = (struct monst *) 0; mtmp2->data = (struct permonst *) 0; mtmp2->minvent = (struct obj *) 0; + MON_NOWEP(mtmp2); /* mtmp2->mw = (struct obj *) 0; */ if (mtmp->mextra) copy_mextra(mtmp2, mtmp); /* if mtmp is a long worm with segments, its saved traits will diff --git a/src/mon.c b/src/mon.c index ade679695..92a71c12a 100644 --- a/src/mon.c +++ b/src/mon.c @@ -233,6 +233,19 @@ sanity_check_single_mon( mtmp->m_id, distu(mtmp->mx, mtmp->my)); #endif } + if (MON_WEP(mtmp)) { /* mtmp->mw */ + struct obj *o; + + for (o = mtmp->minvent; o; o = o->nobj) + if (o == MON_WEP(mtmp)) + break; + if (!o) { + o = MON_WEP(mtmp); + impossible("monst (%s: %u) wielding %s (%u) not in inventory", + pmname(mtmp->data, Mgender(mtmp)), mtmp->m_id, + safe_typename(o->otyp), o->o_id); + } + } } void From 66007e67830e17cae954c63687a28a463e94fa37 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 1 Jun 2025 15:32:55 -0400 Subject: [PATCH 690/791] remove duplicated code from sfctool.c, sftags.c Link with hacklib to provide them instead --- sys/unix/Makefile.utl | 71 +++--- sys/windows/Makefile.nmake | 27 ++- sys/windows/vs/sfctool/sfctool.vcxproj | 1 + sys/windows/vs/sftags/sftags.vcxproj | 8 + util/sfctool.c | 156 ++------------ util/sftags.c | 285 ++++++++++++++----------- 6 files changed, 233 insertions(+), 315 deletions(-) diff --git a/sys/unix/Makefile.utl b/sys/unix/Makefile.utl index f402bf0c3..bcd2c4da4 100644 --- a/sys/unix/Makefile.utl +++ b/sys/unix/Makefile.utl @@ -298,23 +298,24 @@ recover-version.o: ../src/version.c $(HACK_H) # dependencies for optional sfctool # # object files for sfctool utility -SFCTOOLOBJS = $(TARGETPFX)sfctool.o $(TARGETPFX)sf-alloc.o \ - $(TARGETPFX)sf-monst.o $(TARGETPFX)sf-objects.o \ - $(TARGETPFX)sfbase.o $(TARGETPFX)sfstruct.o \ - $(TARGETPFX)sfexpasc.o \ - $(TARGETPFX)sfdata.o $(TARGETPFX)sf-nhlua.o \ - $(TARGETPFX)panic.o $(TARGETPFX)sf-date.o \ - $(TARGETPFX)sf-decl.o $(TARGETPFX)sf-artifact.o \ +SFCTOOLOBJS = $(TARGETPFX)sfctool.o \ + $(TARGETPFX)sf-alloc.o $(TARGETPFX)sfdata.o \ + $(TARGETPFX)sfexpasc.o $(TARGETPFX)sf-cfgfiles.o \ + $(TARGETPFX)sf-date.o $(TARGETPFX)sf-artifact.o \ + $(TARGETPFX)sf-calendar.o $(TARGETPFX)sf-decl.o \ $(TARGETPFX)sf-dungeon.o $(TARGETPFX)sf-end.o \ - $(TARGETPFX)sf-engrave.o $(TARGETPFX)sf-cfgfiles.o \ - $(TARGETPFX)sf-files.o $(TARGETPFX)sf-light.o \ - $(TARGETPFX)sf-mdlib.o $(TARGETPFX)sf-mkmaze.o \ - $(TARGETPFX)sf-mkroom.o $(TARGETPFX)sf-o_init.o \ - $(TARGETPFX)sf-region.o $(TARGETPFX)sf-restore.o \ - $(TARGETPFX)sf-rumors.o $(TARGETPFX)sf-sys.o \ + $(TARGETPFX)sf-engrave.o $(TARGETPFX)sf-files.o \ + $(TARGETPFX)sf-light.o $(TARGETPFX)sf-mdlib.o \ + $(TARGETPFX)sf-mkmaze.o $(TARGETPFX)sf-mkroom.o \ + $(TARGETPFX)sf-monst.o $(TARGETPFX)sf-nhlua.o \ + $(TARGETPFX)sf-objects.o $(TARGETPFX)sf-o_init.o \ + $(TARGETPFX)panic.o $(TARGETPFX)sf-region.o \ + $(TARGETPFX)sf-restore.o $(TARGETPFX)sf-rumors.o \ + $(TARGETPFX)sfbase.o $(TARGETPFX)sf-struct.o \ + $(TARGETPFX)strutil.o $(TARGETPFX)sf-sys.o \ $(TARGETPFX)sf-timeout.o $(TARGETPFX)sf-track.o \ - $(TARGETPFX)sf-version.o $(TARGETPFX)sf-worm.o \ - $(TARGETPFX)strutil.o + $(TARGETPFX)sf-version.o $(TARGETPFX)sf-worm.o + SFCTOOLBIN = sfctool SFFLAGS=-DSFCTOOL -DNOPANICTRACE -DNOCRASHREPORT -DNO_CHRONICLE @@ -324,26 +325,22 @@ $(SFCTOOLBIN): $(SFCTOOLOBJS) $(HACKLIB) $(TARGET_CLINK) $(TARGET_LFLAGS) -o $@ $(SFCTOOLOBJS) $(HACKLIB) $(TARGET_LIBS) $(TARGETPFX)sfctool.o: sfctool.c $(HACK_H) ../include/sfprocs.h $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c sfctool.c -$(TARGETPFX)sfdata.o: sfdata.c $(HACK_H) ../include/sfprocs.h ../include/sfproto.h - $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c sfdata.c -$(TARGETPFX)sfexpasc.o: sfexpasc.c $(HACK_H) ../include/sfprocs.h ../include/sfproto.h - $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c sfexpasc.c $(TARGETPFX)sf-alloc.o: ../src/alloc.c $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/alloc.c +$(TARGETPFX)sf-calendar.o: ../src/calendar.c + $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/calendar.c +$(TARGETPFX)sf-cfgfiles.o: ../src/cfgfiles.c + $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/cfgfiles.c $(TARGETPFX)sf-date.o: ../src/date.c $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/date.c $(TARGETPFX)sf-decl.o: ../src/decl.c $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/decl.c -$(TARGETPFX)sf-panic.o: panic.c $(CONFIG_H) - $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c panic.c $(TARGETPFX)sf-monst.o: ../src/monst.c $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/monst.c $(TARGETPFX)sf-objects.o: ../src/objects.c $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/objects.c -$(TARGETPFX)sf-sfbase.o: ../src/sfbase.c - $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/sfbase.c -$(TARGETPFX)sfstruct.o: ../src/sfstruct.c - $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/sfstruct.c +$(TARGETPFX)sf-panic.o: panic.c $(CONFIG_H) + $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c panic.c $(TARGETPFX)sf-artifact.o: ../src/artifact.c $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/artifact.c $(TARGETPFX)sf-dungeon.o: ../src/dungeon.c @@ -352,8 +349,6 @@ $(TARGETPFX)sf-end.o: ../src/end.c $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/end.c $(TARGETPFX)sf-engrave.o: ../src/engrave.c $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/engrave.c -$(TARGETPFX)sf-cfgfiles.o: ../src/cfgfiles.c - $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/cfgfiles.c $(TARGETPFX)sf-files.o: ../src/files.c $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/files.c $(TARGETPFX)sf-light.o: ../src/light.c @@ -364,6 +359,8 @@ $(TARGETPFX)sf-mkmaze.o: ../src/mkmaze.c $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/mkmaze.c $(TARGETPFX)sf-mkroom.o: ../src/mkroom.c $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/mkroom.c +$(TARGETPFX)sf-nhlua.o: ../src/nhlua.c + $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/nhlua.c $(TARGETPFX)sf-o_init.o: ../src/o_init.c $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/o_init.c $(TARGETPFX)sf-region.o: ../src/region.c @@ -372,6 +369,16 @@ $(TARGETPFX)sf-restore.o: ../src/restore.c $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/restore.c $(TARGETPFX)sf-rumors.o: ../src/rumors.c $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/rumors.c +$(TARGETPFX)sfbase.o: ../src/sfbase.c + $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/sfbase.c +$(TARGETPFX)sfdata.o: sfdata.c $(HACK_H) ../include/sfprocs.h ../include/sfproto.h + $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c sfdata.c +$(TARGETPFX)sfexpasc.o: sfexpasc.c $(HACK_H) ../include/sfprocs.h ../include/sfproto.h + $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c sfexpasc.c +$(TARGETPFX)sf-struct.o: ../src/sfstruct.c + $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/sfstruct.c +$(TARGETPFX)strutil.o: ../src/strutil.c + $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/strutil.c $(TARGETPFX)sf-sys.o: ../src/sys.c $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/sys.c $(TARGETPFX)sf-timeout.o: ../src/timeout.c @@ -382,15 +389,9 @@ $(TARGETPFX)sf-version.o: ../src/version.c $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/version.c $(TARGETPFX)sf-worm.o: ../src/worm.c $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/worm.c -$(TARGETPFX)sf-nhlua.o: ../src/nhlua.c - $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/nhlua.c -$(TARGETPFX)sfbase.o: ../src/sfbase.c - $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/sfbase.c -$(TARGETPFX)strutil.o: ../src/strutil.c - $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/strutil.c -sftags: sftags.o - $(CLINK) $(LFLAGS) -o $@ sftags.o $(LIBS) +sftags: sftags.o $(HACKLIB) + $(CLINK) $(LFLAGS) -o $@ sftags.o $(HACKLIB) $(LIBS) sftags.o: sftags.c $(HACK_H) $(CC) $(CFLAGS) -c sftags.c ../include/sfproto.h: sf.tags sftags diff --git a/sys/windows/Makefile.nmake b/sys/windows/Makefile.nmake index f63336683..5f3223117 100644 --- a/sys/windows/Makefile.nmake +++ b/sys/windows/Makefile.nmake @@ -2479,21 +2479,18 @@ $(DAT)bogusmon: $(U)makedefs.exe $(DAT)bogusmon.txt #=============================================================================== # sfutil #=============================================================================== -SFCTOOLOBJS = $(OUTL)sfctool.o $(OUTL)sf-alloc.o \ - $(OUTL)sf-monst.o $(OUTL)sf-objects.o \ - $(OUTL)sfbase.o $(OUTL)sf-struct.o \ - $(OUTL)sfexpasc.o \ - $(OUTL)sfdata.o $(OUTL)sf-nhlua.o \ - $(OUTL)panic.o $(OUTL)sf-date.o $(OUTL)sf-decl.o \ - $(OUTL)sf-artifact.o $(OUTL)sf-cfgfiles.o \ - $(OUTL)sf-dungeon.o $(OUTL)sf-end.o \ +SFCTOOLOBJS = $(OUTL)sfctool.o \ + $(OUTL)sf-alloc.o $(OUTL)sf-artifact.o $(OUTL)sfdata.o \ + $(OUTL)sf-date.o $(OUTL)sf-decl.o $(OUTL)sf-calendar.o \ + $(OUTL)sf-cfgfiles.o $(OUTL)sf-dungeon.o $(OUTL)sf-end.o \ $(OUTL)sf-engrave.o $(OUTL)sf-files.o $(OUTL)sf-light.o \ $(OUTL)sf-mdlib.o $(OUTL)sf-mkmaze.o $(OUTL)sf-mkroom.o \ - $(OUTL)sf-o_init.o $(OUTL)sf-region.o \ - $(OUTL)sf-restore.o $(OUTL)sf-rumors.o \ + $(OUTL)sf-monst.o $(OUTL)sf-nhlua.o $(OUTL)sf-objects.o \ + $(OUTL)sf-o_init.o $(OUTL)panic.o $(OUTL)sf-region.o \ + $(OUTL)sf-restore.o $(OUTL)sf-rumors.o $(OUTL)sfbase.o \ + $(OUTL)sfexpasc.o $(OUTL)sf-struct.o $(OUTL)strutil.o \ $(OUTL)sf-sys.o $(OUTL)sf-timeout.o $(OUTL)sf-track.o \ - $(OUTL)sf-version.o $(OUTL)sf-worm.o \ - $(OUTL)strutil.o $(OUTL)sf-windsys.o + $(OUTL)sf-version.o $(OUTL)sf-worm.o $(OUTL)sf-windsys.o SFCTOOLBIN = $(BinDir)sfctool.exe SFFLAGS = -DSFCTOOL -DNOPANICTRACE -DNOCRASHREPORT -DNO_CHRONICLE @@ -2534,6 +2531,8 @@ $(OUTL)sf-struct.o: $(SRC)sfstruct.c $(Q)$(CC) $(CFLAGS) $(SFFLAGS) -Fo$@ -c $(SRC)sfstruct.c $(OUTL)sf-artifact.o: $(SRC)artifact.c $(Q)$(CC) $(CFLAGS) $(SFFLAGS) -Fo$@ -c $(SRC)artifact.c +$(OUTL)sf-calendar.o: $(SRC)calendar.c + $(Q)$(CC) $(CFLAGS) $(SFFLAGS) -Fo$@ -c $(SRC)calendar.c $(OUTL)sf-cfgfiles.o: $(SRC)cfgfiles.c $(Q)$(CC) $(CFLAGS) $(SFFLAGS) -Fo$@ -c $(SRC)cfgfiles.c $(OUTL)sf-dungeon.o: $(SRC)dungeon.c @@ -2575,8 +2574,8 @@ $(OUTL)sf-sys.o: $(SRC)sys.c $(OUTL)sf-windsys.o: $(MSWSYS)windsys.c $(Q)$(CC) $(CFLAGS) $(SFFLAGS) -Fo$@ -c $(MSWSYS)windsys.c -$(UTIL)sftags.exe: $(OUTL)sftags.o - $(link) $(LFLAGS) /OUT:$@ $(OUTL)sftags.o +$(UTIL)sftags.exe: $(OUTL)sftags.o $(OUTLHACKLIB) + $(link) $(LFLAGS) /OUT:$@ $(OUTL)sftags.o $(OUTLHACKLIB) $(OUTL)sftags.o: $(UTIL)sftags.c $(HACK_H) $(Q)$(CC) $(CFLAGS) -Fo$@ -c $(UTIL)sftags.c $(INCL)sfproto.h: $(UTIL)sftags.exe $(UTIL)sf.tags diff --git a/sys/windows/vs/sfctool/sfctool.vcxproj b/sys/windows/vs/sfctool/sfctool.vcxproj index 7a64f39c9..73fee3c05 100644 --- a/sys/windows/vs/sfctool/sfctool.vcxproj +++ b/sys/windows/vs/sfctool/sfctool.vcxproj @@ -62,6 +62,7 @@ + diff --git a/sys/windows/vs/sftags/sftags.vcxproj b/sys/windows/vs/sftags/sftags.vcxproj index 4131dcd5c..f2979e613 100644 --- a/sys/windows/vs/sftags/sftags.vcxproj +++ b/sys/windows/vs/sftags/sftags.vcxproj @@ -91,6 +91,8 @@ Console true + $(ToolsDir);%(AdditionalLibraryDirectories) + hacklib.lib;%(AdditionalDependencies) @@ -108,6 +110,8 @@ true true true + $(ToolsDir);%(AdditionalLibraryDirectories) + hacklib.lib;%(AdditionalDependencies) @@ -121,6 +125,8 @@ Console true + $(ToolsDir);%(AdditionalLibraryDirectories) + hacklib.lib;%(AdditionalDependencies) @@ -139,6 +145,8 @@ true true true + $(ToolsDir);%(AdditionalLibraryDirectories) + hacklib.lib;%(AdditionalDependencies) diff --git a/util/sfctool.c b/util/sfctool.c index 83b13884e..d1ecaaceb 100644 --- a/util/sfctool.c +++ b/util/sfctool.c @@ -153,7 +153,6 @@ const char *const rensuffixes[] = { extern boolean get_user_home_folder(char *homebuf, size_t sz); /* files.c */ extern void set_default_prefix_locations(const char *programPath); #endif - enum saveformats convertstyle = exportascii; boolean chosen_unconvert = FALSE, explicit_option = FALSE; @@ -693,17 +692,27 @@ read_sysconf(void) #endif /* SYSCF */ } +/* provided for linkage only */ DISABLE_WARNING_FORMAT_NONLITERAL -/* provided for linkage only */ +void +raw_printf(const char *line, ...) +{ + va_list the_args; + + va_start(the_args, line); + vfprintf(stdout, line, the_args); + va_end(the_args); +} + void error(const char *s, ...) { va_list the_args; va_start(the_args, s); - printf(s, the_args); + vprintf(s, the_args); va_end(the_args); exit(EXIT_FAILURE); } @@ -714,7 +723,7 @@ pline(const char *s, ...) va_list the_args; va_start(the_args, s); - printf(s, the_args); + vprintf(s, the_args); va_end(the_args); } @@ -724,148 +733,13 @@ impossible(const char *s, ...) va_list the_args; va_start(the_args, s); - printf(s, the_args); + vprintf(s, the_args); va_end(the_args); exit(EXIT_FAILURE); } RESTORE_WARNING_FORMAT_NONLITERAL -/* TIME_type: type of the argument to time(); we actually use &(time_t) */ -#if defined(BSD) && !defined(POSIX_TYPES) -#define TIME_type long * -#else -#define TIME_type time_t * -#endif -/* LOCALTIME_type: type of the argument to localtime() */ -#if (defined(ULTRIX) && !(defined(ULTRIX_PROTO) || defined(NHSTDC))) \ - || (defined(BSD) && !defined(POSIX_TYPES)) -#define LOCALTIME_type long * -#else -#define LOCALTIME_type time_t * -#endif - -#if defined(AMIGA) && !defined(AZTEC_C) && !defined(__SASC_60) \ - && !defined(_DCC) && !defined(__GNUC__) -extern struct tm *localtime(time_t *); -#endif -static struct tm *getlt(void); - -time_t -getnow(void) -{ - time_t datetime = 0; - - (void) time((TIME_type) &datetime); - return datetime; -} - -static struct tm * -getlt(void) -{ - time_t date = getnow(); - - return localtime((LOCALTIME_type) &date); -} - -int -getyear(void) -{ - return (1900 + getlt()->tm_year); -} - -time_t -time_from_yyyymmddhhmmss(char *buf) -{ - int k; - time_t timeresult = (time_t) 0; - struct tm t, *lt; - char *d, *p, y[5], mo[3], md[3], h[3], mi[3], s[3]; - - if (buf && strlen(buf) == 14) { - d = buf; - p = y; /* year */ - for (k = 0; k < 4; ++k) - *p++ = *d++; - *p = '\0'; - p = mo; /* month */ - for (k = 0; k < 2; ++k) - *p++ = *d++; - *p = '\0'; - p = md; /* day */ - for (k = 0; k < 2; ++k) - *p++ = *d++; - *p = '\0'; - p = h; /* hour */ - for (k = 0; k < 2; ++k) - *p++ = *d++; - *p = '\0'; - p = mi; /* minutes */ - for (k = 0; k < 2; ++k) - *p++ = *d++; - *p = '\0'; - p = s; /* seconds */ - for (k = 0; k < 2; ++k) - *p++ = *d++; - *p = '\0'; - lt = getlt(); - if (lt) { - t = *lt; - t.tm_year = atoi(y) - 1900; - t.tm_mon = atoi(mo) - 1; - t.tm_mday = atoi(md); - t.tm_hour = atoi(h); - t.tm_min = atoi(mi); - t.tm_sec = atoi(s); - timeresult = mktime(&t); - } - return timeresult; - } - return (time_t) 0; -} - -char * -yyyymmddhhmmss(time_t date) -{ - long datenum; - static char datestr[15]; - struct tm *lt; - - if (date == 0) - lt = getlt(); - else -#if (defined(ULTRIX) && !(defined(ULTRIX_PROTO) || defined(NHSTDC))) \ - || defined(BSD) - lt = localtime((long *) (&date)); -#else - lt = localtime(&date); -#endif - /* just in case somebody's localtime supplies (year % 100) - rather than the expected (year - 1900) */ - if (lt->tm_year < 70) - datenum = (long) lt->tm_year + 2000L; - else - datenum = (long) lt->tm_year + 1900L; - Snprintf(datestr, sizeof datestr, "%04ld%02d%02d%02d%02d%02d", - datenum, lt->tm_mon + 1, - lt->tm_mday, lt->tm_hour, lt->tm_min, lt->tm_sec); - return datestr; -} - -DISABLE_WARNING_FORMAT_NONLITERAL - -void -raw_printf(const char *line, ...) -{ - va_list the_args; - - va_start(the_args, line); - fprintf(stdout, line, the_args); - va_end(the_args); -} - -RESTORE_WARNING_FORMAT_NONLITERAL - #ifdef UNIX /* normalize file name - we don't like .'s, /'s, spaces */ void @@ -898,7 +772,7 @@ regularize(char *s) #endif #endif } -#endif +#endif /* UNIX */ int util_strncmpi(const char *s1, const char *s2, size_t sz) diff --git a/util/sftags.c b/util/sftags.c index ba821aa6f..5845b2ff5 100644 --- a/util/sftags.c +++ b/util/sftags.c @@ -30,7 +30,7 @@ #elif defined(_MSC_VER) #define strcmpi _stricmp #ifndef strncmpi -#define strncmpi _strnicmp +#define strncmpi _strnicmp #endif #endif @@ -83,7 +83,7 @@ struct needs_array_handling { #define SFDATA_NAME "../util/sfdata.c" static char *fgetline(FILE*); -static void quit(void); +ATTRNORETURN static void quit(void) NORETURN; static void out_of_memory(void); static void doline(char *); static void chain(struct tagstruct *); @@ -154,6 +154,16 @@ static long lineno; static char ssdef[BUFSZ]; static char fieldfixbuf[BUFSZ]; static boolean suppress_count; +static char folderprefix[BUFSZ]; +static char filenmbuf[ +#if defined(UNIX) && defined(PATHLEN) + PATHLEN +#elif defined(WIN32) && defined(_MAX_PATH) + _MAX_PATH +#else + BUFSZ * 4 +#endif + ]; #define NHTYPE_SIMPLE 1 #define NHTYPE_COMPLEX 2 @@ -268,8 +278,7 @@ struct nhdatatypes_t readtagstypes[] = { { NHTYPE_COMPLEX, (char *) "version_info", sizeof(struct version_info) }, { NHTYPE_COMPLEX, (char *) "vlaunchinfo", sizeof(union vlaunchinfo) }, { NHTYPE_COMPLEX, (char *) "vptrs", sizeof(union vptrs) }, - { NHTYPE_COMPLEX, (char *) "you", sizeof(struct you) } - + { NHTYPE_COMPLEX, (char *) "you", sizeof(struct you) }, }; @@ -311,13 +320,30 @@ DISABLE_WARNING_UNREACHABLE_CODE int main(int argc, char *argv[]) { tagcount = 0; - +#if defined(WIN32) + char fbuf[_MAX_PATH]; +#endif + + folderprefix[0] = '\0'; if (argc > 1) infilenm = argv[1]; if (!infilenm || !*infilenm) infilenm = DEFAULTTAGNAME; +#if defined(WIN32) + if (!file_exists(infilenm)) { + /* (void) GetCurrentDirectoryA(sizeof cdir, (LPSTR) cdir); */ + Strcpy(folderprefix, "../../../"); + (void) snprintf(fbuf, sizeof fbuf, "%s%s", folderprefix, DEFAULTTAGNAME); + if (!file_exists(fbuf)) { + fprintf(stdout, "%s doesn't exist\n", fbuf); + exit(EXIT_SUCCESS); + } + infilenm = (const char *) fbuf; + } +#endif + infile = fopen(infilenm,"r"); if (!infile) { - printf("%s not found or unavailable\n",infilenm); + printf("%s not found or unavailable\n", infilenm); quit(); } else { while (fgets(line, sizeof line, infile)) { @@ -341,6 +367,20 @@ int main(int argc, char *argv[]) } } +#ifdef WIN32 +boolean +file_exists(const char *path) +{ + struct stat sb; + + /* Just see if it's there */ + if (stat(path, &sb)) { + return FALSE; + } + return TRUE; +} +#endif + RESTORE_WARNINGS static void doline(char *aline) @@ -373,23 +413,19 @@ static void doline(char *aline) return; } -static struct tagstruct * ALIGN32 prevtag = NULL; +struct tagstruct * ALIGN32 prevtag = 0; -static void chain(struct tagstruct *tag) +static void +chain(struct tagstruct *tag) { - if (!first) { - tag->next = (struct tagstruct *)0; + tag->next = (struct tagstruct *) 0; first = tag; } else { - tag->next = (struct tagstruct *)0; - if (prevtag) { - if (prevtag->marker == 0xDEADBEEF) { - prevtag->next = tag; - } else { - printf("Possible corruption."); - quit(); - } + tag->next = (struct tagstruct *) 0; + + if (prevtag->marker == 0xDEADBEEF) { + prevtag->next = tag; } else { printf("Error - No previous tag at %s\n", tag->tag); } @@ -448,7 +484,7 @@ void set_member_array_size(struct tagstruct *tmptag) if (!tmptag) return; strcpy(buf, tmptag->searchtext); - + tmptag->arraysize1[0] = '\0'; tmptag->arraysize2[0] = '\0'; @@ -491,13 +527,17 @@ void set_member_array_size(struct tagstruct *tmptag) static void parseExtensionFields (struct tagstruct *tmptag, char *buf) { char *p = buf; +#ifdef WIN32 + int debug_catch = 0; +#endif + while (p != (char *)0 && *p != '\0') { while (*p == TAB) *p++ = '\0'; if (*p != '\0') { char *colon; char *field = p; - + p = strchr (p, TAB); if (p != (char *)0) *p++ = '\0'; @@ -510,6 +550,10 @@ static void parseExtensionFields (struct tagstruct *tmptag, char *buf) *colon = '\0'; if ((strcmp (key, "struct") == 0) || (strcmp (key, "union") == 0)) { +#ifdef WIN32 + if (!strcmp(key, "union")) + debug_catch = 1; +#endif colon = strstr(value,"::"); if (colon) value = colon +2; @@ -609,15 +653,6 @@ taglineparse(char *p, struct tagstruct *tmptag) } } -/* eos() is copied from hacklib.c */ -/* return the end of a string (pointing at '\0') */ -char * -eos(char *s) -{ - while (*s) s++; /* s += strlen(s); */ - return s; -} - static char stripbuf[255]; #if 0 @@ -643,7 +678,7 @@ static char *deblank(char *st) *out = '\0'; if (!st) return st; while(*st) { - if (*st == SPACE) { + if (*st == SPACE) { *out++ = '_'; st++; } else @@ -659,7 +694,7 @@ static char *deeol(char *st) *out = '\0'; if (!st) return st; while(*st) { - if ((*st == '\r') || (*st == '\n')) { + if ((*st == '\r') || (*st == '\n')) { st++; } else *out++ = *st++; @@ -680,7 +715,7 @@ static void showthem(void) t->parent[0] ? t->searchtext : ""); #endif buf[0] = '\0'; - tmp = member_array_dims(t,buf); + tmp = member_array_dims(t,buf); if (tmp) printf("%s", tmp); printf("%s","\n"); t = t->next; @@ -819,7 +854,7 @@ findtype(char *st, char *tag) while (isspace(*tmp3)) --tmp3; } - while (!isspace(*tmp3) && (*tmp3 != '*')) + while (!isspace(*tmp3) && (*tmp3 != '*')) --tmp3; while (isspace(*tmp3)) --tmp3; @@ -990,28 +1025,45 @@ static void generate_c_files(void) boolean did_i; boolean normalize_param_used; - SFDATA = fopen(SFDATA_NAME, "w"); +#ifdef WIN32 + int debug_catch = 0; +#endif + + Snprintf(filenmbuf, sizeof filenmbuf, "%s%s", folderprefix,SFDATA_NAME); + SFDATA = fopen(filenmbuf, "w"); if (!SFDATA) return; - SFPROTO = fopen(SFPROTO_NAME, "w"); + Snprintf(filenmbuf, sizeof filenmbuf, "%s%s", folderprefix, SFPROTO_NAME); + SFPROTO = fopen(filenmbuf, "w"); if (!SFPROTO) return; - SFO_DATA = fopen("../util/sfo_data.tmp", "w"); + Snprintf(filenmbuf, sizeof filenmbuf, "%s%s", folderprefix, + "../util/sfo_data.tmp"); + SFO_DATA = fopen(filenmbuf, "w"); if (!SFO_DATA) return; - SFO_PROTO = fopen("../include/sfo_proto.tmp", "w"); + Snprintf(filenmbuf, sizeof filenmbuf, "%s%s", folderprefix, "../include/sfo_proto.tmp"); + SFO_PROTO = fopen(filenmbuf, "w"); if (!SFO_PROTO) return; - SFI_PROTO = fopen("../include/sfi_proto.tmp", "w"); + Snprintf(filenmbuf, sizeof filenmbuf, "%s%s", folderprefix, + "../include/sfi_proto.tmp"); + SFI_PROTO = fopen(filenmbuf, "w"); if (!SFI_PROTO) return; - SFI_DATA = fopen("../util/sfi_data.tmp", "w"); + Snprintf(filenmbuf, sizeof filenmbuf, "%s%s", folderprefix, + "../util/sfi_data.tmp"); + SFI_DATA = fopen(filenmbuf, "w"); if (!SFI_DATA) return; - SFDATATMP = fopen("../util/sfdata.tmp", "w"); + Snprintf(filenmbuf, sizeof filenmbuf, "%s%s", folderprefix, + "../util/sfdata.tmp"); + SFDATATMP = fopen(filenmbuf, "w"); if (!SFDATATMP) return; - SF_NORMALIZE_POINTERS = fopen("../util/sfnormptrs.tmp", "w"); + Snprintf(filenmbuf, sizeof filenmbuf, "%s%s", folderprefix, + "../util/sfnormptrs.tmp"); + SF_NORMALIZE_POINTERS = fopen(filenmbuf, "w"); if (!SF_NORMALIZE_POINTERS) return; (void) time(&clocktim); @@ -1023,7 +1075,7 @@ static void generate_c_files(void) *c = '\0'; /* strip off the '\n' */ /* begin sfproto.h */ - Fprintf(SFPROTO,"/* NetHack %d.%d sfproto.h */\n", + Fprintf(SFPROTO,"/* NetHack %d.%d sfproto.h */\n", VERSION_MAJOR, VERSION_MINOR); for (j = 0; j < 3; ++j) Fprintf(SFPROTO, "%s", get_preamble(j)); @@ -1035,7 +1087,7 @@ static void generate_c_files(void) Fprintf(SFPROTO,"%s\n", "extern void sfi_bitfield(NHFILE *, uint8_t *, const char *, int);"); Fprintf(SFO_PROTO, "/* generated output functions */\n"); Fprintf(SFI_PROTO, "/* generated input functions */\n"); - + /* begin sfdata.c */ Fprintf(SFDATA,"/* NetHack %d.%d sfdata.c */\n", VERSION_MAJOR, VERSION_MINOR); @@ -1062,7 +1114,7 @@ static void generate_c_files(void) output_types(SFDATATMP); Fprintf(SFDATATMP, "const char *critical_members[] = {\n"); - + k = 0; did_i = FALSE; while(k < SIZE(readtagstypes)) { @@ -1070,7 +1122,8 @@ static void generate_c_files(void) suppress_count = TRUE; if (readtagstypes[k].dtclass == NHTYPE_COMPLEX) { - + + if (!strncmpi(readtagstypes[k].dtype,"Bitfield",8)) { Fprintf(SFO_DATA, "\nvoid\nsfo_bitfield(nhfp,\n" @@ -1094,17 +1147,22 @@ static void generate_c_files(void) if (!strncmpi(readtagstypes[k].dtype,"version_info",8)) insert_const = TRUE; #endif +#ifdef WIN32 + if (!strncmpi(readtagstypes[k].dtype, "vlaunchinfo", 11) + || !strncmpi(readtagstypes[k].dtype, "vptrs", 5) + || k == SIZE(readtagstypes) - 2) + debug_catch = TRUE; +#endif pt = (const char *) 0; t = first; while(t) { - if (t->tagtype == 'u' && !strcmp(t->tag, readtagstypes[k].dtype)) { - pt = "union"; + if (!strcmp(t->tag, readtagstypes[k].dtype)) { + pt = (t->tagtype == 'u') ? "union" : "struct"; break; } t = t->next; } - if (!pt) { pt = "struct"; } @@ -1127,7 +1185,7 @@ static void generate_c_files(void) insert_const ? "const " : "", pt, readtagstypes[k].dtype, deblank(readtagstypes[k].dtype)); - + #if 0 Fprintf(SFO_DATA, " const char *parent = \"%s\";\n", @@ -1152,7 +1210,7 @@ static void generate_c_files(void) /* deblank(readtagstypes[k].dtype), */ insert_const ? "const " : "", pt, readtagstypes[k].dtype, - deblank(readtagstypes[k].dtype)); + deblank(readtagstypes[k].dtype)); #if 0 Fprintf(SFI_DATA, @@ -1162,7 +1220,7 @@ static void generate_c_files(void) Sprintf(sfparent, "%s %s", pt, readtagstypes[k].dtype); - + Fprintf(SF_NORMALIZE_POINTERS, "\nvoid normalize_pointers_%s(%s " "*d_%s);\n", @@ -1200,14 +1258,15 @@ static void generate_c_files(void) t = first; normalize_param_used = FALSE; - while(t) { + while(t) { x = 0; okeydokey = 0; -/* - if (!strcmp(t->tag, "nextc") +/* + if (!strcmp(t->tag, "nextc") && !strcmp(readtagstypes[k].dtype, "engrave_info")) __debugbreak(); */ + if (t->tagtype == 's') { char *ss = strstr(t->searchtext,"{$/"); @@ -1262,7 +1321,7 @@ static void generate_c_files(void) char lbuf[BUFSZ]; int j2, z; - Sprintf(lbuf, + Sprintf(lbuf, " " "bitfield = d_%s->%s;", readtagstypes[k].dtype, t->tag); @@ -1274,7 +1333,7 @@ static void generate_c_files(void) Fprintf(SFO_DATA, " " "sfo_bitfield(nhfp, &bitfield, \"%s\", %s);\n", - t->tag, bfsize(ft)); + t->tag, bfsize(ft)); #if 0 Fprintf(SFI_DATA, " " @@ -1450,7 +1509,7 @@ static void generate_c_files(void) (insert_loop && array_of_ptrs) ? "[" : "", (insert_loop && array_of_ptrs) ? "i" : "", (insert_loop && array_of_ptrs) ? "]" : "", - t->parent, t->tag, + t->parent, t->tag, (insert_loop && array_of_ptrs) ? "[" : "", (insert_loop && array_of_ptrs) ? "i" : "", (insert_loop && array_of_ptrs) ? "]" : "", @@ -1553,52 +1612,64 @@ static void generate_c_files(void) /* Consolidate SFO_* and SFI_* etc into single files */ - SFO_DATA = fopen("../util/sfo_data.tmp", "r"); + Snprintf(filenmbuf, sizeof filenmbuf, "%s%s", folderprefix, + "../util/sfo_data.tmp"); + SFO_DATA = fopen(filenmbuf, "r"); if (!SFO_DATA) return; while ((gline = fgetline(SFO_DATA)) != 0) { (void) fputs(gline, SFDATA); free(gline); } (void) fclose(SFO_DATA); - (void) remove("../util/sfo_data.tmp"); + (void) remove(filenmbuf); - SFI_DATA = fopen("../util/sfi_data.tmp", "r"); + Snprintf(filenmbuf, sizeof filenmbuf, "%s%s", folderprefix, + "../util/sfi_data.tmp"); + SFI_DATA = fopen(filenmbuf, "r"); if (!SFI_DATA) return; while ((gline = fgetline(SFI_DATA)) != 0) { (void) fputs(gline, SFDATA); free(gline); } (void) fclose(SFI_DATA); - (void) remove("../util/sfi_data.tmp"); + (void) remove(filenmbuf); - SFO_PROTO = fopen("../include/sfo_proto.tmp", "r"); + Snprintf(filenmbuf, sizeof filenmbuf, "%s%s", folderprefix, + "../include/sfo_proto.tmp"); + SFO_PROTO = fopen(filenmbuf, "r"); if (!SFO_PROTO) return; while ((gline = fgetline(SFO_PROTO)) != 0) { (void) fputs(gline, SFPROTO); free(gline); } (void) fclose(SFO_PROTO); - (void) remove("../include/sfo_proto.tmp"); + (void) remove(filenmbuf); - SFI_PROTO = fopen("../include/sfi_proto.tmp", "r"); + Snprintf(filenmbuf, sizeof filenmbuf, "%s%s", folderprefix, + "../include/sfi_proto.tmp"); + SFI_PROTO = fopen(filenmbuf, "r"); if (!SFI_PROTO) return; while ((gline = fgetline(SFI_PROTO)) != 0) { (void) fputs(gline, SFPROTO); free(gline); } (void) fclose(SFI_PROTO); - (void) remove("../include/sfi_proto.tmp"); + (void) remove(filenmbuf); - SFDATATMP = fopen("../util/sfdata.tmp", "r"); + Snprintf(filenmbuf, sizeof filenmbuf, "%s%s", folderprefix, + "../util/sfdata.tmp"); + SFDATATMP = fopen(filenmbuf, "r"); if (!SFDATATMP) return; while ((gline = fgetline(SFDATATMP)) != 0) { (void) fputs(gline, SFDATA); free(gline); } (void) fclose(SFDATATMP); - (void) remove("../util/sfdata.tmp"); - - SF_NORMALIZE_POINTERS = fopen("../util/sfnormptrs.tmp", "r"); + (void) remove(filenmbuf); + + Snprintf(filenmbuf, sizeof filenmbuf, "%s%s", folderprefix, + "../util/sfnormptrs.tmp"); + SF_NORMALIZE_POINTERS = fopen(filenmbuf, "r"); if (!SF_NORMALIZE_POINTERS) return; while ((gline = fgetline(SF_NORMALIZE_POINTERS)) != 0) { @@ -1606,7 +1677,7 @@ static void generate_c_files(void) free(gline); } (void) fclose(SF_NORMALIZE_POINTERS); - (void) remove("../util/sfnormptrs.tmp"); + (void) remove(filenmbuf); Fprintf(SFDATA, "/*sfdata.c*/\n"); Fprintf(SFPROTO,"#endif /* SFPROTO_H */\n"); @@ -1687,6 +1758,7 @@ dtfn(const char *str, if (!str) return (char *)0; (void)strncpy(buf, str, 127); + buf[sizeof buf - 1] = '\0'; c = buf; while (*c) c++; /* eos */ @@ -1782,7 +1854,7 @@ bfsize(const char *str) *subst++ = ' '; *subst++ = '1'; } - + c2 = buf; c1 = str; while (*c1) { @@ -1812,10 +1884,18 @@ fgetline(FILE *fd) { static const int inc = 256; int len = inc; - char *c = malloc(len), *ret; + char *c = malloc(len), *ret, *loc, *avoidleak; + if (!c) { + fprintf(stderr, "Memory issue\n"); + quit(); + } for (;;) { - ret = fgets(c + len - inc, inc, fd); + loc = c + len - inc; + if (!loc) { + quit(); + } + ret = fgets(loc, inc, fd); if (!ret) { free(c); c = NULL; @@ -1825,13 +1905,19 @@ fgetline(FILE *fd) break; } len += inc; + avoidleak = c; c = realloc(c, len); + if (!c) { + free(avoidleak); + quit(); + } } return c; } +#ifndef _MSC_VER int -strncmpi(register const char *s1, register const char *s2, size_t n) +strncmpi(const char *s1, const char *s2, size_t n) { register char t1, t2; @@ -1847,59 +1933,8 @@ strncmpi(register const char *s1, register const char *s2, size_t n) } return 0; /* s1 == s2 */ } - -/* force 'c' into uppercase */ -char -highc(char c) -{ - return (char) (('a' <= c && c <= 'z') ? (c & ~040) : c); -} - -/* force 'c' into lowercase */ -char -lowc(char c) -{ - return (char) (('A' <= c && c <= 'Z') ? (c | 040) : c); -} - -DISABLE_WARNING_FORMAT_NONLITERAL - -/* - * Wrap snprintf for use in the main code. - * - * Wrap reasons: - * 1. If there are any platform issues, we have one spot to fix them - - * snprintf is a routine with a troubling history of bad implementations. - * 2. Add combersome error checking in one spot. Problems with text wrangling - * do not have to be fatal. - * 3. Gcc 9+ will issue a warning unless the return value is used. - * Annoyingly, explicitly casting to void does not remove the error. - * So, use the result - see reason #2. - */ -void -nh_snprintf(const char *func, int myline, char *str, size_t size, - const char *fmt, ...) -{ - va_list ap; - int n; - - va_start(ap, fmt); -#ifdef NO_VSNPRINTF - n = vsprintf(str, fmt, ap); -#else - n = vsnprintf(str, size, fmt, ap); #endif - va_end(ap); - if (n < 0 || (size_t)n >= size) { /* is there a problem? */ - fprintf(stderr, "snprintf %s: func %s, file line %d", - n < 0 ? "format error" - : "overflow", - func, myline); - str[size-1] = 0; /* make sure it is nul terminated */ - } -} -RESTORE_WARNING_FORMAT_NONLITERAL struct already_in_sfbase { int typ; From 2414e56646048ecc37ab258037549f73559b92a9 Mon Sep 17 00:00:00 2001 From: Michael Allison Date: Sun, 1 Jun 2025 22:04:44 -0400 Subject: [PATCH 691/791] Xcode project update to include: cfgfiles.c sfbase.c --- sys/unix/NetHack.xcodeproj/project.pbxproj | 264 +++++++++++++++++++-- 1 file changed, 243 insertions(+), 21 deletions(-) diff --git a/sys/unix/NetHack.xcodeproj/project.pbxproj b/sys/unix/NetHack.xcodeproj/project.pbxproj index f42f2a312..39863734e 100644 --- a/sys/unix/NetHack.xcodeproj/project.pbxproj +++ b/sys/unix/NetHack.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 54; + objectVersion = 70; objects = { /* Begin PBXBuildFile section */ @@ -100,7 +100,6 @@ 31B8A3C721A238060055BD01 /* monmove.c in Sources */ = {isa = PBXBuildFile; fileRef = 31B8A36121A238040055BD01 /* monmove.c */; }; 31B8A3C821A238060055BD01 /* options.c in Sources */ = {isa = PBXBuildFile; fileRef = 31B8A36221A238040055BD01 /* options.c */; }; 31B8A3C921A238060055BD01 /* sounds.c in Sources */ = {isa = PBXBuildFile; fileRef = 31B8A36321A238040055BD01 /* sounds.c */; }; - 31B8A3CA21A238060055BD01 /* hacklib.c in Sources */ = {isa = PBXBuildFile; fileRef = 31B8A36421A238040055BD01 /* hacklib.c */; }; 31B8A3CB21A238060055BD01 /* alloc.c in Sources */ = {isa = PBXBuildFile; fileRef = 31B8A36521A238040055BD01 /* alloc.c */; }; 31B8A3CC21A238060055BD01 /* pickup.c in Sources */ = {isa = PBXBuildFile; fileRef = 31B8A36621A238040055BD01 /* pickup.c */; }; 31B8A3CD21A238060055BD01 /* write.c in Sources */ = {isa = PBXBuildFile; fileRef = 31B8A36721A238040055BD01 /* write.c */; }; @@ -165,7 +164,6 @@ 5493735A277AAE830031FE02 /* alloc.c in Sources */ = {isa = PBXBuildFile; fileRef = 31B8A36521A238040055BD01 /* alloc.c */; }; 54A3D3EC282C55A900143F8C /* utf8map.c in Sources */ = {isa = PBXBuildFile; fileRef = 54A3D3EB282C55A900143F8C /* utf8map.c */; }; 54BD340D2D8B70350073C484 /* hacklib.c in Sources */ = {isa = PBXBuildFile; fileRef = 31B8A36421A238040055BD01 /* hacklib.c */; }; - 54EBA6D32DDED3F100CD20EC /* cfgfiles.c in Sources */ = {isa = PBXBuildFile; fileRef = 54EBA6D22DDED3F100CD20EC /* cfgfiles.c */; }; 54FB2B4B246310A600397C0E /* symbols.c in Sources */ = {isa = PBXBuildFile; fileRef = 54FB2B4A246310A600397C0E /* symbols.c */; }; 54FCE8292223261F00F393C8 /* isaac64.c in Sources */ = {isa = PBXBuildFile; fileRef = 54FCE8282223261F00F393C8 /* isaac64.c */; }; BAB57DB527C1C3E200FCF150 /* libnhlua.a in Frameworks */ = {isa = PBXBuildFile; fileRef = BAE8010A27B97760002B3786 /* libnhlua.a */; }; @@ -204,6 +202,12 @@ BAE8015627B99CAE002B3786 /* lstrlib.c in Sources */ = {isa = PBXBuildFile; fileRef = BAE8013427B99CAD002B3786 /* lstrlib.c */; }; BAE8015727B99CAE002B3786 /* lzio.c in Sources */ = {isa = PBXBuildFile; fileRef = BAE8013527B99CAD002B3786 /* lzio.c */; }; BAE8015A27B9C872002B3786 /* date.c in Sources */ = {isa = PBXBuildFile; fileRef = 5439B3BB275AADC600B8FB2F /* date.c */; }; + F5457B212DED146B00039D83 /* hacklib.c in Sources */ = {isa = PBXBuildFile; fileRef = F5457B202DED146B00039D83 /* hacklib.c */; }; + F5457B2C2DED16F200039D83 /* libhacklib.a in Frameworks */ = {isa = PBXBuildFile; fileRef = F5457B1C2DED143E00039D83 /* libhacklib.a */; }; + F5457B2D2DED171800039D83 /* libhacklib.a in Frameworks */ = {isa = PBXBuildFile; fileRef = F5457B1C2DED143E00039D83 /* libhacklib.a */; }; + F5857AA22DED026700A8CB4F /* version.c in Sources */ = {isa = PBXBuildFile; fileRef = 31B8A32721A238010055BD01 /* version.c */; }; + F5857AA42DED032D00A8CB4F /* cfgfiles.c in Sources */ = {isa = PBXBuildFile; fileRef = F5857AA32DED032C00A8CB4F /* cfgfiles.c */; }; + F5857AA62DED03BB00A8CB4F /* sfbase.c in Sources */ = {isa = PBXBuildFile; fileRef = F5857AA52DED03BB00A8CB4F /* sfbase.c */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -242,13 +246,6 @@ remoteGlobalIDString = 3189577E21A1FDA400FB2ABE; remoteInfo = makedefs; }; - BAE8011027B9865F002B3786 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 3189576921A1FCC100FB2ABE /* Project object */; - proxyType = 1; - remoteGlobalIDString = BAE8010927B97760002B3786; - remoteInfo = nhlua.a; - }; BAE8011227B9996A002B3786 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 3189576921A1FCC100FB2ABE /* Project object */; @@ -256,6 +253,20 @@ remoteGlobalIDString = BAE8010927B97760002B3786; remoteInfo = nhlua.a; }; + F5457B222DED148700039D83 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 3189576921A1FCC100FB2ABE /* Project object */; + proxyType = 1; + remoteGlobalIDString = F5457B1B2DED143E00039D83; + remoteInfo = hacklib; + }; + F5457B242DED149500039D83 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 3189576921A1FCC100FB2ABE /* Project object */; + proxyType = 1; + remoteGlobalIDString = F5457B1B2DED143E00039D83; + remoteInfo = hacklib; + }; /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -546,7 +557,7 @@ 54BD34102D8B711E0073C484 /* selvar.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = selvar.h; path = ../../include/selvar.h; sourceTree = ""; }; 54BD34112D8B711E0073C484 /* stairs.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = stairs.h; path = ../../include/stairs.h; sourceTree = ""; }; 54BD34122D8B711E0073C484 /* weight.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = weight.h; path = ../../include/weight.h; sourceTree = ""; }; - 54EBA6D22DDED3F100CD20EC /* cfgfiles.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = cfgfiles.c; path = /Users/mikeallison/Documents/git/NHsource/src/cfgfiles.c; sourceTree = ""; }; + 54EBA6D22DDED3F100CD20EC /* cfgfiles.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = cfgfiles.c; path = ../../src/cfgfiles.c; sourceTree = ""; }; 54FB2B4A246310A600397C0E /* symbols.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = symbols.c; path = ../../src/symbols.c; sourceTree = ""; }; 54FCE8282223261F00F393C8 /* isaac64.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = isaac64.c; path = ../../src/isaac64.c; sourceTree = ""; }; BAE8010A27B97760002B3786 /* libnhlua.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libnhlua.a; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -584,13 +595,51 @@ BAE8013327B99CAD002B3786 /* lmathlib.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = lmathlib.c; path = "../../lib/lua-5.4.6/src/lmathlib.c"; sourceTree = ""; }; BAE8013427B99CAD002B3786 /* lstrlib.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = lstrlib.c; path = "../../lib/lua-5.4.6/src/lstrlib.c"; sourceTree = ""; }; BAE8013527B99CAD002B3786 /* lzio.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = lzio.c; path = "../../lib/lua-5.4.6/src/lzio.c"; sourceTree = ""; }; + F515A6F32DED074D006E1F63 /* sfctool.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = sfctool.c; path = ../../util/sfctool.c; sourceTree = ""; }; + F515A6F52DED0916006E1F63 /* date.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = date.c; path = ../../src/date.c; sourceTree = ""; }; + F515A6F62DED0916006E1F63 /* sfbase.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = sfbase.c; path = ../../src/sfbase.c; sourceTree = ""; }; + F515A6F72DED0916006E1F63 /* sys.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = sys.c; path = ../../src/sys.c; sourceTree = ""; }; + F515A6F82DED0917006E1F63 /* calendar.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = calendar.c; path = ../../src/calendar.c; sourceTree = ""; }; + F515A6F92DED0917006E1F63 /* sfstruct.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = sfstruct.c; path = ../../src/sfstruct.c; sourceTree = ""; }; + F515A6FA2DED0917006E1F63 /* engrave.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = engrave.c; path = ../../src/engrave.c; sourceTree = ""; }; + F515A6FB2DED0917006E1F63 /* mdlib.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = mdlib.c; path = ../../src/mdlib.c; sourceTree = ""; }; + F515A6FC2DED0917006E1F63 /* o_init.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = o_init.c; path = ../../src/o_init.c; sourceTree = ""; }; + F515A6FD2DED0917006E1F63 /* mkmaze.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = mkmaze.c; path = ../../src/mkmaze.c; sourceTree = ""; }; + F515A6FE2DED0917006E1F63 /* version.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = version.c; path = ../../src/version.c; sourceTree = ""; }; + F515A6FF2DED0918006E1F63 /* alloc.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = alloc.c; path = ../../src/alloc.c; sourceTree = ""; }; + F515A7002DED0918006E1F63 /* artifact.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = artifact.c; path = ../../src/artifact.c; sourceTree = ""; }; + F515A7012DED0918006E1F63 /* cfgfiles.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = cfgfiles.c; path = ../../src/cfgfiles.c; sourceTree = ""; }; + F515A7022DED0918006E1F63 /* nhlua.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = nhlua.c; path = ../../src/nhlua.c; sourceTree = ""; }; + F515A7032DED0918006E1F63 /* objects.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = objects.c; path = ../../src/objects.c; sourceTree = ""; }; + F515A7042DED0918006E1F63 /* strutil.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = strutil.c; path = ../../src/strutil.c; sourceTree = ""; }; + F515A7052DED0919006E1F63 /* decl.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = decl.c; path = ../../src/decl.c; sourceTree = ""; }; + F515A7062DED0919006E1F63 /* mkroom.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = mkroom.c; path = ../../src/mkroom.c; sourceTree = ""; }; + F515A7072DED0919006E1F63 /* rumors.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = rumors.c; path = ../../src/rumors.c; sourceTree = ""; }; + F515A7082DED0919006E1F63 /* monst.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = monst.c; path = ../../src/monst.c; sourceTree = ""; }; + F515A7092DED0919006E1F63 /* files.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = files.c; path = ../../src/files.c; sourceTree = ""; }; + F515A70A2DED091A006E1F63 /* restore.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = restore.c; path = ../../src/restore.c; sourceTree = ""; }; + F515A70B2DED091A006E1F63 /* end.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = end.c; path = ../../src/end.c; sourceTree = ""; }; + F515A70C2DED091A006E1F63 /* worm.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = worm.c; path = ../../src/worm.c; sourceTree = ""; }; + F515A7252DED0978006E1F63 /* sfexpasc.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = sfexpasc.c; path = ../../util/sfexpasc.c; sourceTree = ""; }; + F515A7262DED0978006E1F63 /* panic.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = panic.c; path = ../../util/panic.c; sourceTree = ""; }; + F515A72A2DED0A7C006E1F63 /* sftags.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = sftags.c; path = ../../util/sftags.c; sourceTree = ""; }; + F515A73B2DED0B47006E1F63 /* hacklib.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = hacklib.c; path = ../../src/hacklib.c; sourceTree = ""; }; + F5457B1C2DED143E00039D83 /* libhacklib.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libhacklib.a; sourceTree = BUILT_PRODUCTS_DIR; }; + F5457B202DED146B00039D83 /* hacklib.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = hacklib.c; path = ../../src/hacklib.c; sourceTree = ""; }; + F5857AA32DED032C00A8CB4F /* cfgfiles.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = cfgfiles.c; path = ../../src/cfgfiles.c; sourceTree = ""; }; + F5857AA52DED03BB00A8CB4F /* sfbase.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = sfbase.c; path = ../../src/sfbase.c; sourceTree = ""; }; /* End PBXFileReference section */ +/* Begin PBXFileSystemSynchronizedRootGroup section */ + F515A7322DED0B08006E1F63 /* hacklib */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = hacklib; sourceTree = ""; }; +/* End PBXFileSystemSynchronizedRootGroup section */ + /* Begin PBXFrameworksBuildPhase section */ 3189576E21A1FCC100FB2ABE /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + F5457B2C2DED16F200039D83 /* libhacklib.a in Frameworks */, BAB57DB527C1C3E200FCF150 /* libnhlua.a in Frameworks */, 31B8A41721A243E80055BD01 /* libncurses.tbd in Frameworks */, ); @@ -600,6 +649,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + F5457B2D2DED171800039D83 /* libhacklib.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -624,12 +674,51 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + F5457B1A2DED143E00039D83 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 3189576821A1FCC100FB2ABE = { isa = PBXGroup; children = ( + F515A73B2DED0B47006E1F63 /* hacklib.c */, + F5457B202DED146B00039D83 /* hacklib.c */, + F515A72A2DED0A7C006E1F63 /* sftags.c */, + F515A7262DED0978006E1F63 /* panic.c */, + F515A7252DED0978006E1F63 /* sfexpasc.c */, + F515A6FF2DED0918006E1F63 /* alloc.c */, + F515A7002DED0918006E1F63 /* artifact.c */, + F515A6F82DED0917006E1F63 /* calendar.c */, + F515A7012DED0918006E1F63 /* cfgfiles.c */, + F515A6F52DED0916006E1F63 /* date.c */, + F515A7052DED0919006E1F63 /* decl.c */, + F515A70B2DED091A006E1F63 /* end.c */, + F515A6FA2DED0917006E1F63 /* engrave.c */, + F515A7092DED0919006E1F63 /* files.c */, + F515A6FB2DED0917006E1F63 /* mdlib.c */, + F515A6FD2DED0917006E1F63 /* mkmaze.c */, + F515A7062DED0919006E1F63 /* mkroom.c */, + F515A7082DED0919006E1F63 /* monst.c */, + F515A7022DED0918006E1F63 /* nhlua.c */, + F515A6FC2DED0917006E1F63 /* o_init.c */, + F515A7032DED0918006E1F63 /* objects.c */, + F515A70A2DED091A006E1F63 /* restore.c */, + F515A7072DED0919006E1F63 /* rumors.c */, + F515A6F62DED0916006E1F63 /* sfbase.c */, + F515A6F92DED0917006E1F63 /* sfstruct.c */, + F515A7042DED0918006E1F63 /* strutil.c */, + F515A6F72DED0916006E1F63 /* sys.c */, + F515A6FE2DED0917006E1F63 /* version.c */, + F515A70C2DED091A006E1F63 /* worm.c */, + F515A6F32DED074D006E1F63 /* sfctool.c */, + F5857AA52DED03BB00A8CB4F /* sfbase.c */, + F5857AA32DED032C00A8CB4F /* cfgfiles.c */, 54AEB886297EE7E9005F1B13 /* sound */, 54AEB885297EE7C4005F1B13 /* macsound.m */, BAE8015827B99D44002B3786 /* nhlualib */, @@ -639,6 +728,7 @@ 3189579621A2046700FB2ABE /* include */, 3189579321A200EC00FB2ABE /* util */, 3189578C21A1FF8200FB2ABE /* src */, + F515A7322DED0B08006E1F63 /* hacklib */, 3189577221A1FCC100FB2ABE /* Products */, 31B8A41421A243CB0055BD01 /* Frameworks */, ); @@ -652,6 +742,7 @@ 31B8A44A21A26A4B0055BD01 /* recover */, 31B8A45721A26A970055BD01 /* dlb */, BAE8010A27B97760002B3786 /* libnhlua.a */, + F5457B1C2DED143E00039D83 /* libhacklib.a */, ); name = Products; sourceTree = ""; @@ -1033,6 +1124,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + F5457B182DED143E00039D83 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ @@ -1051,6 +1149,7 @@ buildRules = ( ); dependencies = ( + F5457B232DED148700039D83 /* PBXTargetDependency */, BAE8011327B9996A002B3786 /* PBXTargetDependency */, 31B8A31421A2355C0055BD01 /* PBXTargetDependency */, 3192867621A3AAFE00325BEB /* PBXTargetDependency */, @@ -1079,7 +1178,7 @@ buildRules = ( ); dependencies = ( - BAE8011127B9865F002B3786 /* PBXTargetDependency */, + F5457B252DED149500039D83 /* PBXTargetDependency */, ); name = makedefs; productName = makedefs; @@ -1146,6 +1245,25 @@ productReference = BAE8010A27B97760002B3786 /* libnhlua.a */; productType = "com.apple.product-type.library.static"; }; + F5457B1B2DED143E00039D83 /* hacklib */ = { + isa = PBXNativeTarget; + buildConfigurationList = F5457B1D2DED143E00039D83 /* Build configuration list for PBXNativeTarget "hacklib" */; + buildPhases = ( + F5457B182DED143E00039D83 /* Headers */, + F5457B192DED143E00039D83 /* Sources */, + F5457B1A2DED143E00039D83 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = hacklib; + packageProductDependencies = ( + ); + productName = hacklib; + productReference = F5457B1C2DED143E00039D83 /* libhacklib.a */; + productType = "com.apple.product-type.library.static"; + }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ @@ -1170,6 +1288,9 @@ BAE8010927B97760002B3786 = { CreatedOnToolsVersion = 13.2.1; }; + F5457B1B2DED143E00039D83 = { + CreatedOnToolsVersion = 16.4; + }; }; }; buildConfigurationList = 3189576C21A1FCC100FB2ABE /* Build configuration list for PBXProject "NetHack" */; @@ -1189,6 +1310,7 @@ 3189577E21A1FDA400FB2ABE /* makedefs */, 31B8A44921A26A4B0055BD01 /* recover */, 31B8A45621A26A970055BD01 /* dlb */, + F5457B1B2DED143E00039D83 /* hacklib */, BAE8010927B97760002B3786 /* nhlua */, ); }; @@ -1722,6 +1844,8 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + F5857AA62DED03BB00A8CB4F /* sfbase.c in Sources */, + F5857AA42DED032D00A8CB4F /* cfgfiles.c in Sources */, BAE8015A27B9C872002B3786 /* date.c in Sources */, 54435B52247999CB00804CB3 /* nhlobj.c in Sources */, 31B8A3BC21A238060055BD01 /* eat.c in Sources */, @@ -1793,7 +1917,6 @@ 31B8A3D121A238060055BD01 /* do.c in Sources */, 31B8A39021A238060055BD01 /* objnam.c in Sources */, 31B8A3B621A238060055BD01 /* bones.c in Sources */, - 54EBA6D32DDED3F100CD20EC /* cfgfiles.c in Sources */, 31B8A3C521A238060055BD01 /* timeout.c in Sources */, 31B8A3AD21A238060055BD01 /* uhitm.c in Sources */, 31B8A3B321A238060055BD01 /* track.c in Sources */, @@ -1827,7 +1950,6 @@ 31B8A41121A23EEC0055BD01 /* cursstat.c in Sources */, 31B8A3E021A238060055BD01 /* wield.c in Sources */, 31B8A41821A2448C0055BD01 /* monst.c in Sources */, - 31B8A3CA21A238060055BD01 /* hacklib.c in Sources */, 31B8A3A121A238060055BD01 /* rip.c in Sources */, 31B8A39321A238060055BD01 /* were.c in Sources */, 31B8A3EF21A23D420055BD01 /* ioctl.c in Sources */, @@ -1890,6 +2012,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + F5857AA22DED026700A8CB4F /* version.c in Sources */, 54BD340D2D8B70350073C484 /* hacklib.c in Sources */, 31B8A45221A26A750055BD01 /* recover.c in Sources */, ); @@ -1948,6 +2071,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + F5457B192DED143E00039D83 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + F5457B212DED146B00039D83 /* hacklib.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ @@ -1976,16 +2107,21 @@ target = 3189577E21A1FDA400FB2ABE /* makedefs */; targetProxy = 31B8A31321A2355C0055BD01 /* PBXContainerItemProxy */; }; - BAE8011127B9865F002B3786 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = BAE8010927B97760002B3786 /* nhlua */; - targetProxy = BAE8011027B9865F002B3786 /* PBXContainerItemProxy */; - }; BAE8011327B9996A002B3786 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = BAE8010927B97760002B3786 /* nhlua */; targetProxy = BAE8011227B9996A002B3786 /* PBXContainerItemProxy */; }; + F5457B232DED148700039D83 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = F5457B1B2DED143E00039D83 /* hacklib */; + targetProxy = F5457B222DED148700039D83 /* PBXContainerItemProxy */; + }; + F5457B252DED149500039D83 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = F5457B1B2DED143E00039D83 /* hacklib */; + targetProxy = F5457B242DED149500039D83 /* PBXContainerItemProxy */; + }; /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ @@ -2163,6 +2299,7 @@ CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Automatic; DEAD_CODE_STRIPPING = YES; + DEVELOPMENT_TEAM = 5J8MP36Y73; GCC_C_LANGUAGE_STANDARD = c99; INSTALL_PATH = "$(NH_INSTALL_DIR)"; MACOSX_DEPLOYMENT_TARGET = "$(RECOMMENDED_MACOSX_DEPLOYMENT_TARGET)"; @@ -2195,6 +2332,7 @@ CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Automatic; DEAD_CODE_STRIPPING = YES; + DEVELOPMENT_TEAM = 5J8MP36Y73; GCC_C_LANGUAGE_STANDARD = c99; INSTALL_PATH = "$(NH_INSTALL_DIR)"; MACOSX_DEPLOYMENT_TARGET = "$(RECOMMENDED_MACOSX_DEPLOYMENT_TARGET)"; @@ -2247,6 +2385,22 @@ CODE_SIGN_STYLE = Automatic; DEAD_CODE_STRIPPING = YES; MACOSX_DEPLOYMENT_TARGET = "$(RECOMMENDED_MACOSX_DEPLOYMENT_TARGET)"; + OTHER_CFLAGS = ( + "-DMINIMAL_FOR_RECOVER", + "-DNOMAIL", + "-DNOTPARMDECL", + "-DDEFAULT_WINDOW_SYS=\\\"tty\\\"", + "-DDLB", + "-DGREPPATH=\\\"/usr/bin/grep\\\"", + "-DSYSCF", + "-DSYSCF_FILE=\\\"$(NH_INSTALL_DIR)/sysconf\\\"", + "-DHACKDIR=\\\"$(NH_INSTALL_DIR)\\\"", + "-DSECURE", + "-DCURSES_GRAPHICS", + "-DSND_LIB_MACSOUND", + "-DSND_SOUNDEFFECTS_AUTOMAP", + "-DUSER_SOUNDS", + ); PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; @@ -2258,6 +2412,19 @@ CODE_SIGN_STYLE = Automatic; DEAD_CODE_STRIPPING = YES; MACOSX_DEPLOYMENT_TARGET = "$(RECOMMENDED_MACOSX_DEPLOYMENT_TARGET)"; + OTHER_CFLAGS = ( + "-DMINIMAL_FOR_RECOVER", + "-DNOMAIL", + "-DNOTPARMDECL", + "-DDEFAULT_WINDOW_SYS=\\\"tty\\\"", + "-DDLB", + "-DGREPPATH=\\\"/usr/bin/grep\\\"", + "-DSYSCF", + "-DSYSCF_FILE=\\\"$(NH_INSTALL_DIR)/sysconf\\\"", + "-DHACKDIR=\\\"$(NH_INSTALL_DIR)\\\"", + "-DSECURE", + "-DCURSES_GRAPHICS", + ); PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Release; @@ -2295,7 +2462,7 @@ CLANG_WARN_UNREACHABLE_CODE = YES; CODE_SIGN_STYLE = Automatic; DEAD_CODE_STRIPPING = YES; - DEVELOPMENT_TEAM = 6978C4Q2VB; + DEVELOPMENT_TEAM = 5J8MP36Y73; ENABLE_USER_SCRIPT_SANDBOXING = NO; EXECUTABLE_PREFIX = lib; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -2332,7 +2499,7 @@ CLANG_WARN_UNREACHABLE_CODE = YES; CODE_SIGN_STYLE = Automatic; DEAD_CODE_STRIPPING = YES; - DEVELOPMENT_TEAM = 6978C4Q2VB; + DEVELOPMENT_TEAM = 5J8MP36Y73; ENABLE_USER_SCRIPT_SANDBOXING = NO; EXECUTABLE_PREFIX = lib; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -2358,6 +2525,52 @@ }; name = Release; }; + F5457B1E2DED143E00039D83 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_WARN_COMMA = NO; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 5J8MP36Y73; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + EXECUTABLE_PREFIX = lib; + GCC_C_LANGUAGE_STANDARD = gnu17; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MACOSX_DEPLOYMENT_TARGET = 15.5; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + }; + name = Debug; + }; + F5457B1F2DED143E00039D83 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_WARN_COMMA = NO; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 5J8MP36Y73; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + EXECUTABLE_PREFIX = lib; + GCC_C_LANGUAGE_STANDARD = gnu17; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MACOSX_DEPLOYMENT_TARGET = 15.5; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + }; + name = Release; + }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ @@ -2415,6 +2628,15 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + F5457B1D2DED143E00039D83 /* Build configuration list for PBXNativeTarget "hacklib" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + F5457B1E2DED143E00039D83 /* Debug */, + F5457B1F2DED143E00039D83 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; /* End XCConfigurationList section */ }; rootObject = 3189576921A1FCC100FB2ABE /* Project object */; From 8d5ffbd6e311071c9e2db7409b63850929af20e1 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 1 Jun 2025 22:31:09 -0400 Subject: [PATCH 692/791] permapoisoned follow-up otmp can be 0 in mk_artifact. In fact, it is explicitly being set to 0 three lines above the recently added call to permapoisoned(). The static analyzer was griping also. --- src/artifact.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/artifact.c b/src/artifact.c index d180cb2fb..e4f4c89bf 100644 --- a/src/artifact.c +++ b/src/artifact.c @@ -301,7 +301,7 @@ mk_artifact( otmp = 0; } /* otherwise, otmp has not changed; just fallthrough to return it */ } - if (permapoisoned(otmp)) + if (otmp && permapoisoned(otmp)) otmp->opoisoned = 1; return otmp; } From a0da9168b720112ad806f176218ea766436f490b Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 1 Jun 2025 22:43:34 -0400 Subject: [PATCH 693/791] remove a debugging bit in restore.c --- src/restore.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/restore.c b/src/restore.c index 25f96f239..086f21d99 100644 --- a/src/restore.c +++ b/src/restore.c @@ -236,12 +236,9 @@ restobjchn(NHFILE *nhfp, boolean frozen) #ifndef SFCTOOL boolean ghostly = (nhfp->ftype == NHF_BONESFILE); #endif - boolean trouble = FALSE; while (1) { Sfi_int(nhfp, &buflen, "obj-obj_length"); - if (!(buflen != -1 || buflen != sizeof (struct obj))) - trouble = TRUE; if (buflen == -1) break; @@ -302,7 +299,6 @@ restobjchn(NHFILE *nhfp, boolean frozen) #ifdef SFCTOOL nhUse(frozen); #endif - nhUse(trouble); return first; } From afafc69eed93bbdb9b04416504f807442c523591 Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 2 Jun 2025 08:50:10 -0400 Subject: [PATCH 694/791] MSYS2 build fixes --- sys/windows/GNUmakefile | 6 +++++- sys/windows/GNUmakefile.depend | 3 +++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/sys/windows/GNUmakefile b/sys/windows/GNUmakefile index 8ba1ee4b2..a3e2cde61 100644 --- a/sys/windows/GNUmakefile +++ b/sys/windows/GNUmakefile @@ -325,9 +325,11 @@ CFLAGS = -mms-bitfields -I../include -I../sys/windows LDFLAGS = ifeq "$(DEBUGINFO)" "Y" CFLAGS += -g -D_DEBUG +LIBUCRT = -lucrtbased else CFLAGS += -DNDEBUG LDFLAGS += -s +LIBUCRT= endif ifeq "$(USE_DLB)" "Y" @@ -362,7 +364,8 @@ CONSOLEDEF = $(COMMONDEF) -D_CONSOLE # To build util targets CFLAGSU = $(CFLAGS) $(CONSOLEDEF) $(DLBFLG) -LIBS = -lcomctl32 -lgdi32 -lole32 -lshell32 -luserenv -luuid -lwinmm -lbcrypt +LIBS = -lcomctl32 -lgdi32 -lole32 -lshell32 -luserenv -luuid -lwinmm \ + -lrpcrt4 -lbcrypt $(LIBUCRT) $(GAMEDIR): @mkdir -p $@ @@ -536,6 +539,7 @@ $(GAMEDIR)/recover.exe: $(ROBJS) $(HLHACKLIB) | $(GAMEDIR) $(OR)/recover.o: $(U)recover.c | $(OR) $(cc) $(CFLAGSU) $< -o$@ + $(OR)/rversion.o: $(SRC)/version.c | $(OR) $(cc) $(CFLAGSU) -DMINIMAL_FOR_RECOVER $< -o$@ diff --git a/sys/windows/GNUmakefile.depend b/sys/windows/GNUmakefile.depend index 230bf8e38..c28f9eb1b 100644 --- a/sys/windows/GNUmakefile.depend +++ b/sys/windows/GNUmakefile.depend @@ -21,6 +21,9 @@ $(OM)/%.d: $(U)%.c $(NHLUAH) | $(OM) $(OR)/recover.d: $(U)recover.c | $(OR) $(cce) $(CFLAGSU) $< -o$@ +$(OR)/rversion.d: $(SRC)/version.c | $(OR) + $(cce) $(CFLAGSU) -DMINIMAL_FOR_RECOVER $< -o$@ + $(OT)/tiletxt.d: $(WSHR)/tilemap.c $(NHLUAH) | $(OT) $(cce) $(CFLAGSU) -DTILETEXT $< -o$@ From a9c0cd624fa1e357f165c698b4c8c75fcf18068c Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 2 Jun 2025 10:32:36 -0400 Subject: [PATCH 695/791] a build fix, due to compile issue for pdcursesmod GCC15 switched its default to -std=gnu23 and there's a bug in pdcursesmod as a result. That impacts MSYS2/Mingw64 NetHack builds. See: https://github.com/Bill-Gray/PDCursesMod/issues/333 The suggestion there is to force --std=gnu17 as a workaround. --- src/.gitignore | 1 + sys/windows/GNUmakefile | 16 +++++++++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/.gitignore b/src/.gitignore index dda3abdac..13097d000 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -31,3 +31,4 @@ bundle/* GNUmakefile GNUmakefile.depend .*.c +.depend diff --git a/sys/windows/GNUmakefile b/sys/windows/GNUmakefile index a3e2cde61..3a79e7324 100644 --- a/sys/windows/GNUmakefile +++ b/sys/windows/GNUmakefile @@ -301,9 +301,11 @@ USE_DLB = Y ifdef CI_COMPILER cc = gcc -c +cxx = g++ -c ld = gcc else cc = gcc -c +cxx = g++ -c ld = gcc endif ifeq "$(MSYSTEM)" "MINGW32" @@ -552,6 +554,10 @@ CLEAN_FILE += $(RTARGETS) $(ROBJS) # PDCurses #========================================== ifeq "$(ADD_CURSES)" "Y" + +#https://github.com/Bill-Gray/PDCursesMod/issues/333 +PDCMOD_WORKAROUND = -std=gnu17 + PDCCOMMONSRC = addch addchstr addstr attr beep bkgd border clear \ color debug delch deleteln getch getstr getyx inch \ inchstr initscr inopts insch insstr kernel keyname \ @@ -574,10 +580,10 @@ $(PDCLIB): $(PDCOBJS) ar rcs $@ $^ $(OP)/%.o: $(PDCSRC)/%.c | $(OP) - $(cc) $(CFLAGS) $(PDCURSESFLAGS) $(PDCINCL) -D_LIB $< -o$@ + $(cc) $(CFLAGS) $(PDCMOD_WORKAROUND) $(PDCURSESFLAGS) $(PDCINCL) -D_LIB $< -o$@ $(OP)/%.o: $(PDCWINCON)/%.c | $(OP) - $(cc) $(CFLAGS) $(PDCURSESFLAGS) $(PDCINCL) -I$(PDCWINCON) -D_LIB $< -o$@ + $(cc) $(CFLAGS) $(PDCMOD_WORKAROUND) $(PDCURSESFLAGS) $(PDCINCL) -I$(PDCWINCON) -D_LIB $< -o$@ $(OP): @mkdir -p $@ @@ -599,10 +605,10 @@ $(PDCWLIB): $(PDCWOBJS) ar rcs $@ $^ $(OPW)/%.o: $(PDCSRC)/%.c | $(OPW) - $(cc) $(CFLAGS) $(PDCURSESFLAGS) $(PDCINCL) -D_LIB $< -o$@ + $(cc) $(CFLAGS) $(PDCMOD_WORKAROUND) $(PDCURSESFLAGS) $(PDCINCL) -D_LIB $< -o$@ $(OPW)/%.o: $(PDCWINGUI)/%.c | $(OPW) - $(cc) $(CFLAGS) $(PDCURSESFLAGS) $(PDCINCL) -I$(PDCWINGUI) -D_LIB $< -o$@ + $(cc) $(CFLAGS) $(PDCMOD_WORKAROUND) $(PDCURSESFLAGS) $(PDCINCL) -I$(PDCWINGUI) -D_LIB $< -o$@ $(OPW): @mkdir -p $@ @@ -844,7 +850,7 @@ else # GIT_AVAILABLE no CURLLUASRC=http://www.lua.org/ftp/lua-5.4.6.tar.gz CURLLUADST=lua-5.4.6.tar.gz -CURLPDCSRC=https://github.com/Bill-Gray/PDCursesMod/archive/refs/tags/v4.4.0.zip +CURLPDCSRC=https://github.com/Bill-Gray/PDCursesMod/archive/refs/tags/v4.5.1.zip CURLPDCDST=$(PDCURSES).zip fetchlua: From 40c1842010812fc8cff41027be4bb86235b3afab Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 2 Jun 2025 10:42:21 -0400 Subject: [PATCH 696/791] update Windows Makefile.nmake --- sys/windows/Makefile.nmake | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sys/windows/Makefile.nmake b/sys/windows/Makefile.nmake index 5f3223117..e13f2efd0 100644 --- a/sys/windows/Makefile.nmake +++ b/sys/windows/Makefile.nmake @@ -378,9 +378,9 @@ ADD_CURSES=Y INCLCURSES_H=-I$(R_PDCURSES_TOP) ! ELSE # Cannot do it, sorry - PDCINCL= - INCLCURSES_H= - ADD_CURSES = N +PDCINCL= +INCLCURSES_H= +ADD_CURSES = N ! ENDIF # If we found a copy of curses.h ! ENDIF # ADD_CURSES == Y !ENDIF # WANT_CURSES @@ -1340,7 +1340,7 @@ guilflags = $(lflags) -subsystem:windows # basic subsystem specific libraries, less the C Run-Time baselibs = kernel32.lib $(optlibs) $(winsocklibs) advapi32.lib gdi32.lib \ - ole32.lib Shell32.lib UserEnv.lib dbghelp.lib + ole32.lib Shell32.lib UserEnv.lib dbghelp.lib Rpcrt4.lib winlibs = $(baselibs) user32.lib comdlg32.lib winspool.lib # for Windows applications that use the C Run-Time libraries @@ -2043,7 +2043,7 @@ fetch-pdcurses: @if not exist $(LIBDIR)*.* mkdir $(R_LIBDIR) cd $(LIBDIR) # curl -L -R https://codeload.github.com/wmcbrine/PDCurses/zip/master -o pdcurses.zip - curl -L -R https://github.com/Bill-Gray/PDCursesMod/archive/refs/tags/v4.3.5.zip -o $(PDCDIST).zip + curl -L -R https://github.com/Bill-Gray/PDCursesMod/archive/refs/tags/v4.5.1.zip -o $(PDCDIST).zip powershell -command "Expand-Archive -Path .\$(PDCDIST).zip -DestinationPath ./$(PDCDIST)-temp" if exist .\$(PDCDIST)\* rd .\$(PDCDIST) /s /Q move .\$(PDCDIST)-temp\PDCurses-master . From 4e93cfc825d416551bb6794f72b31fb5230858bb Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 2 Jun 2025 11:13:43 -0400 Subject: [PATCH 697/791] CI update for mingw --- azure-pipelines.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index b11fdc3be..da07c4122 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -140,7 +140,8 @@ steps: # # 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/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 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 CURLSRC=https://github.com/brechtsanders/winlibs_mingw/releases/download/15.1.0posix-12.0.0-ucrt-r1/winlibs-i686-posix-dwarf-gcc-15.1.0-mingw-w64ucrt-12.0.0-r1.zip export CURLDST=mingw-x86.zip export MINGWBIN=mingw32 export MSYSTEM=MINGW32 From f262b8b015782ad468892ee1a02277c40214df72 Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 2 Jun 2025 12:00:42 -0400 Subject: [PATCH 698/791] CI mingw update --- sys/windows/GNUmakefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/windows/GNUmakefile b/sys/windows/GNUmakefile index 3a79e7324..be6c20538 100644 --- a/sys/windows/GNUmakefile +++ b/sys/windows/GNUmakefile @@ -54,7 +54,7 @@ SOUND_LIBRARIES = windsound # Do you want debug information in the executable? # -DEBUGINFO = Y +DEBUGINFO = N # #--------------------------------------------------------------- From 4fcbd91d222a73c2174a1380d209a2c2b7ef7af3 Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 2 Jun 2025 12:03:30 -0400 Subject: [PATCH 699/791] fix a CI warning -> ##[warning]The windows-2019 runner image is being deprecated, consider switching to windows-2022(windows-latest) or windows-2025 instead. For more details see https://github.com/actions/runner-images/issues/12045. --- azure-pipelines.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index da07c4122..2461ba45a 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -29,7 +29,7 @@ strategy: toolchainName: vs buildTargetName: all windows-mingw: - imageName: 'windows-2019' + imageName: 'windows-2025' toolchainName: mingw buildTargetName: all linux_noble_cross_msdos: @@ -132,14 +132,13 @@ steps: export LUA_VERSION=5.4.6 # # 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 CURLSRC=https://github.com/brechtsanders/winlibs_mingw/releases/download/15.1.0posix-12.0.0-ucrt-r1/winlibs-x86_64-posix-seh-gcc-15.1.0-mingw-w64ucrt-12.0.0-r1.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/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 CURLSRC=https://github.com/brechtsanders/winlibs_mingw/releases/download/15.1.0posix-12.0.0-ucrt-r1/winlibs-i686-posix-dwarf-gcc-15.1.0-mingw-w64ucrt-12.0.0-r1.zip export CURLDST=mingw-x86.zip From e33cf7a6d61d02d73885533fc7b246356587b232 Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 2 Jun 2025 12:07:11 -0400 Subject: [PATCH 700/791] more CI, GNUmakefile interaction --- sys/windows/GNUmakefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sys/windows/GNUmakefile b/sys/windows/GNUmakefile index be6c20538..4f078c3ec 100644 --- a/sys/windows/GNUmakefile +++ b/sys/windows/GNUmakefile @@ -54,7 +54,7 @@ SOUND_LIBRARIES = windsound # Do you want debug information in the executable? # -DEBUGINFO = N +DEBUGINFO = Y # #--------------------------------------------------------------- @@ -303,6 +303,7 @@ ifdef CI_COMPILER cc = gcc -c cxx = g++ -c ld = gcc +DEBUGINFO = N else cc = gcc -c cxx = g++ -c From c7484730cc49ef3998c7762de7e7ba414063c755 Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 2 Jun 2025 12:25:30 -0400 Subject: [PATCH 701/791] CI remove msbuild@1 task Per https://devblogs.microsoft.com/devops/upcoming-updates-for-azure-pipelines-agents-images/ --- azure-pipelines.yml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 2461ba45a..6339d52e8 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -114,14 +114,6 @@ steps: condition: eq( variables.toolchain, 'vs' ) displayName: 'Copying store key' -- task: MSBuild@1 - inputs: - solution: $(Agent.BuildDirectory)/$(netHackPath)/sys/windows/vs/NetHack.sln - platform: Win32 - configuration: Debug - condition: eq( variables.toolchain, 'vs' ) - displayName: 'Visual Studio Build' - - bash: | export ADD_LUA=Y export WANT_LUAC=N From 436b26c699bcf3898be5d831af7721de2f25e8b5 Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 2 Jun 2025 12:32:28 -0400 Subject: [PATCH 702/791] Revert "CI remove msbuild@1 task" This reverts commit c7484730cc49ef3998c7762de7e7ba414063c755. --- azure-pipelines.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 6339d52e8..2461ba45a 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -114,6 +114,14 @@ steps: condition: eq( variables.toolchain, 'vs' ) displayName: 'Copying store key' +- task: MSBuild@1 + inputs: + solution: $(Agent.BuildDirectory)/$(netHackPath)/sys/windows/vs/NetHack.sln + platform: Win32 + configuration: Debug + condition: eq( variables.toolchain, 'vs' ) + displayName: 'Visual Studio Build' + - bash: | export ADD_LUA=Y export WANT_LUAC=N From f385f36c063936e8edaec1fe8a7ab5a3474d47fc Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 2 Jun 2025 12:35:31 -0400 Subject: [PATCH 703/791] more Windows CI testing --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 2461ba45a..9da64ea50 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -114,7 +114,7 @@ steps: condition: eq( variables.toolchain, 'vs' ) displayName: 'Copying store key' -- task: MSBuild@1 +- task: VSBuild@1 inputs: solution: $(Agent.BuildDirectory)/$(netHackPath)/sys/windows/vs/NetHack.sln platform: Win32 From 1aafd7dfcd7df69e2aea0815e4623892dc3d9711 Mon Sep 17 00:00:00 2001 From: PatR Date: Mon, 2 Jun 2025 13:20:55 -0700 Subject: [PATCH 704/791] monster weapon sanity check In the context of sanity checking, an extra pass though the inventory of every monster wielding a weapon is completely negligible, but it is trivial to avoid so take it out. --- src/mkobj.c | 14 +++++++++++++- src/mon.c | 13 ------------- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/mkobj.c b/src/mkobj.c index 2f93d43c8..a7687ca8a 100644 --- a/src/mkobj.c +++ b/src/mkobj.c @@ -3189,7 +3189,7 @@ mon_obj_sanity(struct monst *monlist, const char *mesg) for (mon = monlist; mon; mon = mon->nmon) { if (DEADMONSTER(mon)) continue; - mwep = MON_WEP(mon); + mwep = MON_WEP(mon); /* mon->mw */ if (mwep) { if (!mcarried(mwep)) insane_object(mwep, mfmt1, mesg, mon); @@ -3209,6 +3209,18 @@ mon_obj_sanity(struct monst *monlist, const char *mesg) if (obj->in_use || obj->bypass || obj->nomerge || (obj->otyp == BOULDER && obj->next_boulder)) insane_obj_bits(obj, mon); + if (obj == mwep) + mwep = (struct obj *) 0; + } + if (mwep) { + /* this is a monster check rather than an object check, but doing + it here avoids making an extra pass through mon's minvent; + if the full pass through that list hasn't reset mwep to Null, + then mwep isn't in that list where it should be */ + impossible("monst (%s: %u) wielding %s (%u) not in %s inventory", + pmname(mon->data, Mgender(mon)), mon->m_id, + safe_typename(mwep->otyp), mwep->o_id, mhis(mon)); + } } } diff --git a/src/mon.c b/src/mon.c index 92a71c12a..ade679695 100644 --- a/src/mon.c +++ b/src/mon.c @@ -233,19 +233,6 @@ sanity_check_single_mon( mtmp->m_id, distu(mtmp->mx, mtmp->my)); #endif } - if (MON_WEP(mtmp)) { /* mtmp->mw */ - struct obj *o; - - for (o = mtmp->minvent; o; o = o->nobj) - if (o == MON_WEP(mtmp)) - break; - if (!o) { - o = MON_WEP(mtmp); - impossible("monst (%s: %u) wielding %s (%u) not in inventory", - pmname(mtmp->data, Mgender(mtmp)), mtmp->m_id, - safe_typename(o->otyp), o->o_id); - } - } } void From 1fb403f29996ea280a3684c7fb8059f021dcad22 Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 2 Jun 2025 21:08:38 -0400 Subject: [PATCH 705/791] sfctool MSYS2 build --- sys/windows/GNUmakefile | 172 ++++++++++++++++++++++++++++++++++++++++ util/sftags.c | 2 + 2 files changed, 174 insertions(+) diff --git a/sys/windows/GNUmakefile b/sys/windows/GNUmakefile index 4f078c3ec..8d6124a2e 100644 --- a/sys/windows/GNUmakefile +++ b/sys/windows/GNUmakefile @@ -752,6 +752,178 @@ $(MSWIN)/NetHack.ico: $(U)uudecode.exe $(MSWSYS)/nhico.uu CLEAN_FILE += $(UTARGETS) $(UOBJS) +#========================================== +# sfctool +#========================================== +# +# Requires universal-ctags. +# pacman -S ctags +# + +.PHONEY: sfctool + +OSFC = $(O)sfctool +SFCTARGETS = $(U)sftags.exe $(GAMEDIR)/sfctool.exe +SFCCOREOBJS = +SFCCOREOBJS = sfctool sf-alloc sf-artifact sf-calendar sf-cfgfiles sfdata \ + sf-date sf-decl sf-dungeon sf-end sf-engrave \ + sf-files sf-light sf-mdlib sf-mkmaze sf-mkroom sf-monst \ + sf-nhlua sf-objects sf-o_init panic sf-region sf-restore \ + sf-rumors sfbase sfexpasc sf-struct strutil sf-sys \ + sf-timeout sf-track sf-version sf-worm sf-windsys +SFCTOOLOBJS = $(addprefix $(OSFC)/, $(addsuffix .o, $(SFCCOREOBJS))) +SFCTOOLBIN = $(GAMEDIR)/sfctool.exe +SFFLAGS = -DSFCTOOL -DNOPANICTRACE -DNOCRASHREPORT -DNO_CHRONICLE + +sfctool: $(SFCTARGETS) + +#$(info SFCTOOLOBJS=$(SFCTOOLOBJS)) + +$(SFCTOOLBIN): $(HLHACKLIB) $(SFCTOOLOBJS) + $(ld) $(LDFLAGS) $^ $(HLHACKLIB) $(LIBS) -o$@ + +$(OSFC)/sfctool.o: $(U)sfctool.c $(HACK_H) $(INCL)/sfprocs.h | $(OSFC) + $(cc) $(CFLAGSU) $(SFFLAGS) -c $(U)sfctool.c -o$@ +$(OSFC)/sf-alloc.o: $(SRC)/alloc.c $(HACK_H) | $(OSFC) + $(cc) $(CFLAGSU) $(SFFLAGS) -c $(SRC)/alloc.c -o$@ +$(OSFC)/sf-artifact.o: $(SRC)/artifact.c $(HACK_H) | $(OSFC) + $(cc) $(CFLAGSU) $(SFFLAGS) -c $(SRC)/artifact.c -o$@ +$(OSFC)/sf-calendar.o: $(SRC)/calendar.c $(HACK_H) | $(OSFC) + $(cc) $(CFLAGSU) $(SFFLAGS) -c $(SRC)/calendar.c -o$@ +$(OSFC)/sf-cfgfiles.o: $(SRC)/cfgfiles.c $(HACK_H) | $(OSFC) + $(cc) $(CFLAGSU) $(SFFLAGS) -c $(SRC)/cfgfiles.c -o$@ +$(OSFC)/sfdata.o: $(U)sfdata.c $(HACK_H) $(INCL)/sfprocs.h $(INCL)/sfproto.h | $(OSFC) + $(cc) $(CFLAGSU) $(SFFLAGS) -c $(U)sfdata.c -o$@ +$(OSFC)/sf-date.o: $(SRC)/date.c $(HACK_H) | $(OSFC) + $(cc) $(CFLAGSU) $(SFFLAGS) -c $(SRC)/date.c -o$@ +$(OSFC)/sf-decl.o: $(SRC)/decl.c $(HACK_H) | $(OSFC) + $(cc) $(CFLAGSU) $(SFFLAGS) -c $(SRC)/decl.c -o$@ +$(OSFC)/sf-dungeon.o: $(SRC)/dungeon.c $(HACK_H) | $(OSFC) + $(cc) $(CFLAGSU) $(SFFLAGS) -c $(SRC)/dungeon.c -o$@ +$(OSFC)/sf-end.o: $(SRC)/end.c $(HACK_H) | $(OSFC) + $(cc) $(CFLAGSU) $(SFFLAGS) -c $(SRC)/end.c -o$@ +$(OSFC)/sf-engrave.o: $(SRC)/engrave.c $(HACK_H) | $(OSFC) + $(cc) $(CFLAGSU) $(SFFLAGS) -c $(SRC)/engrave.c -o$@ +$(OSFC)/sf-files.o: $(SRC)/files.c $(HACK_H) | $(OSFC) + $(cc) $(CFLAGSU) $(SFFLAGS) -c $(SRC)/files.c -o$@ +$(OSFC)/sf-light.o: $(SRC)/light.c $(HACK_H) | $(OSFC) + $(cc) $(CFLAGSU) $(SFFLAGS) -c $(SRC)/light.c -o$@ +$(OSFC)/sf-mdlib.o: $(SRC)/mdlib.c $(HACK_H) | $(OSFC) + $(cc) $(CFLAGSU) $(SFFLAGS) -c $(SRC)/mdlib.c -o$@ +$(OSFC)/sf-mkmaze.o: $(SRC)/mkmaze.c $(HACK_H) | $(OSFC) + $(cc) $(CFLAGSU) $(SFFLAGS) -c $(SRC)/mkmaze.c -o$@ +$(OSFC)/sf-mkroom.o: $(SRC)/mkroom.c $(HACK_H) | $(OSFC) + $(cc) $(CFLAGSU) $(SFFLAGS) -c $(SRC)/mkroom.c -o$@ +$(OSFC)/sf-monst.o: $(SRC)/monst.c $(HACK_H) | $(OSFC) + $(cc) $(CFLAGSU) $(SFFLAGS) -c $(SRC)/monst.c -o$@ +$(OSFC)/sf-nhlua.o: $(SRC)/nhlua.c $(HACK_H) | $(OSFC) + $(cc) $(CFLAGSU) $(SFFLAGS) -c $(SRC)/nhlua.c -o$@ +$(OSFC)/sf-objects.o: $(SRC)/objects.c $(HACK_H) | $(OSFC) + $(cc) $(CFLAGSU) $(SFFLAGS) -c $(SRC)/objects.c -o$@ +$(OSFC)/sf-o_init.o: $(SRC)/o_init.c $(HACK_H) | $(OSFC) + $(cc) $(CFLAGSU) $(SFFLAGS) -c $(SRC)/o_init.c -o$@ +$(OSFC)/panic.o: $(U)panic.c $(HACK_H) | $(OSFC) + $(cc) $(CFLAGSU) $(SFFLAGS) -c $(U)panic.c -o$@ +$(OSFC)/sf-region.o: $(SRC)/region.c $(HACK_H) | $(OSFC) + $(cc) $(CFLAGSU) $(SFFLAGS) -c $(SRC)/region.c -o$@ +$(OSFC)/sf-restore.o: $(SRC)/restore.c $(HACK_H) | $(OSFC) + $(cc) $(CFLAGSU) $(SFFLAGS) -c $(SRC)/restore.c -o$@ +$(OSFC)/sf-rumors.o: $(SRC)/\rumors.c $(HACK_H) | $(OSFC) + $(cc) $(CFLAGSU) $(SFFLAGS) -c $(SRC)/rumors.c -o$@ +$(OSFC)/sfbase.o: $(SRC)/sfbase.c $(HACK_H) | $(OSFC) + $(cc) $(CFLAGSU) $(SFFLAGS) -c $(SRC)/sfbase.c -o$@ +$(OSFC)/sfexpasc.o: $(U)sfexpasc.c $(HACK_H) $(INCL)/sfprocs.h $(INCL)/sfproto.h | $(OSFC) + $(cc) $(CFLAGSU) $(SFFLAGS) -c $(U)sfexpasc.c -o$@ +$(OSFC)/sf-struct.o: $(SRC)/sfstruct.c $(HACK_H) | $(OSFC) + $(cc) $(CFLAGSU) $(SFFLAGS) -c $(SRC)/sfstruct.c -o$@ +$(OSFC)/strutil.o: $(SRC)/strutil.c $(HACK_H) | $(OSFC) + $(cc) $(CFLAGSU) $(SFFLAGS) -c $(SRC)/strutil.c -o$@ +$(OSFC)/sf-sys.o: $(SRC)/sys.c $(HACK_H) | $(OSFC) + $(cc) $(CFLAGSU) $(SFFLAGS) -c $(SRC)/sys.c -o$@ +$(OSFC)/sf-timeout.o: $(SRC)/timeout.c $(HACK_H) | $(OSFC) + $(cc) $(CFLAGSU) $(SFFLAGS) -c $(SRC)/timeout.c -o$@ +$(OSFC)/sf-track.o: $(SRC)/track.c $(HACK_H) | $(OSFC) + $(cc) $(CFLAGSU) $(SFFLAGS) -c $(SRC)/track.c -o$@ +$(OSFC)/sf-version.o: $(SRC)/version.c $(HACK_H) | $(OSFC) + $(cc) $(CFLAGSU) $(SFFLAGS) -c $(SRC)/version.c -o$@ +$(OSFC)/sf-worm.o: $(SRC)/worm.c $(HACK_H) | $(OSFC) + $(cc) $(CFLAGSU) $(SFFLAGS) -c $(SRC)/worm.c -o$@ +$(OSFC)/sf-windsys.o: $(MSWSYS)/windsys.c $(HACK_H) | $(OSFC) + $(cc) $(CFLAGSU) $(SFFLAGS) -c $(MSWSYS)/windsys.c -o$@ + +CTAGSCMD = ctags +CTAGSOPT = --language-force=c --sort=no -D"Bitfield(x,n)=unsigned x : n" --excmd=pattern + +$(U)sftags.exe: $(HLHACKLIB) $(OSFC)/sftags.o + $(ld) $(LDFLAGS) -mwindows $(OSFC)/sftags.o $(HLHACKLIB) $(LIBS) -o$@ +$(OSFC)/sftags.o: $(U)sftags.c $(HACK_H) | $(OSFC) + $(cc) $(CFLAGSU) -c $(U)sftags.c -o$@ +$(INCL)/sfproto.h: $(U)sf.tags $(U)sftags.exe + $(U)sftags +$(U)sfdata.c: $(U)sf.tags $(U)sftags.exe + $(U)sftags + +# dependencies for sftags +# +CTAGDEP = $(INCL)/align.h $(INCL)/artifact.h $(SRC)/artifact.c \ + $(INCL)/artilist.h $(INCL)/attrib.h $(SRC)/bones.c \ + $(INCL)/context.h $(INCL)/coord.h $(INCL)/decl.h \ + $(SRC)/decl.c $(INCL)/dungeon.h $(INCL)/engrave.h \ + $(SRC)/engrave.c $(INCL)/flag.h $(INCL)/func_tab.h \ + $(INCL)/global.h $(INCL)/hack.h $(INCL)/mextra.h \ + $(INCL)/mkroom.h $(INCL)/monst.h $(INCL)/defsym.h \ + $(INCL)/obj.h $(INCL)/objclass.h $(INCL)/prop.h \ + $(INCL)/quest.h $(INCL)/rect.h $(INCL)/region.h \ + $(INCL)/rm.h $(INCL)/skills.h $(INCL)/spell.h \ + $(INCL)/stairs.h $(INCL)/sys.h $(INCL)/timeout.h \ + $(INCL)/trap.h $(INCL)/you.h $(INCL)/wintype.h + +$(U)sf.tags: $(CTAGDEP) + $(CTAGSCMD) $(CTAGSOPT) -f $@ $(INCL)/align.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)/artifact.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(SRC)/artifact.c + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)/artilist.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)/attrib.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(SRC)/bones.c + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)/context.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)/coord.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)/decl.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(SRC)/decl.c + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)/dungeon.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)/engrave.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(SRC)/engrave.c + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)/flag.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)/func_tab.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)/global.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)/hack.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)/mextra.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)/mkroom.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)/monst.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)/defsym.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)/obj.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)/objclass.h +# $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)/permonst.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)/prop.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)/quest.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)/rect.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)/region.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)/rm.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)/skills.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)/spell.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)/stairs.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)/sys.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)/timeout.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)/trap.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)/you.h + $(CTAGSCMD) $(CTAGSOPT) -a -f $@ $(INCL)/wintype.h + +$(OSFC): + @mkdir -p $@ + +CLEAN_DIR += $(OSFC) +CLEAN_FILE += $(SFCTARGETS) $(SFCTOOLOBJS) $(U)sf.tags $(U)sfdata.c $(INCL)/sfproto.h + + #========================================== # Data librarian #========================================== diff --git a/util/sftags.c b/util/sftags.c index 5845b2ff5..db1d9b870 100644 --- a/util/sftags.c +++ b/util/sftags.c @@ -25,7 +25,9 @@ #ifdef __GNUC__ #include +#ifndef WIN32 #define strncmpi strncasecmp +#endif #define strcmpi strcasecmp #elif defined(_MSC_VER) #define strcmpi _stricmp From 5d9656c80106aec93671406ee53a113bcc2c6be0 Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 2 Jun 2025 21:17:40 -0400 Subject: [PATCH 706/791] typo fix in sys/windows/GNUmakefile --- sys/windows/GNUmakefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/windows/GNUmakefile b/sys/windows/GNUmakefile index 8d6124a2e..98d561c2b 100644 --- a/sys/windows/GNUmakefile +++ b/sys/windows/GNUmakefile @@ -760,7 +760,7 @@ CLEAN_FILE += $(UTARGETS) $(UOBJS) # pacman -S ctags # -.PHONEY: sfctool +.PHONY: sfctool OSFC = $(O)sfctool SFCTARGETS = $(U)sftags.exe $(GAMEDIR)/sfctool.exe From 34c010579b448e12ff29875ae2623b45ab9c69c1 Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 2 Jun 2025 21:20:47 -0400 Subject: [PATCH 707/791] update sys/windows/Makefile.nmake for sfctool --- sys/windows/Makefile.nmake | 58 +++++++++++++++++++------------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/sys/windows/Makefile.nmake b/sys/windows/Makefile.nmake index e13f2efd0..04dc2c59f 100644 --- a/sys/windows/Makefile.nmake +++ b/sys/windows/Makefile.nmake @@ -2515,63 +2515,63 @@ $(OUTL)sfdata.o: $(UTIL)sfdata.c $(HACK_H) $(INCL)sfprocs.h $(INCL)sfproto.h $(Q)$(CC) $(CFLAGS) $(SFFLAGS) -Fo$@ -c $(UTIL)sfdata.c $(OUTL)sfexpasc.o: $(UTIL)sfexpasc.c $(HACK_H) $(INCL)sfprocs.h $(INCL)sfproto.h $(Q)$(CC) $(CFLAGS) $(SFFLAGS) -Fo$@ -c $(UTIL)sfexpasc.c -$(OUTL)sf-alloc.o: $(SRC)alloc.c +$(OUTL)sf-alloc.o: $(SRC)alloc.c $(HACK_H) $(Q)$(CC) $(CFLAGS) $(SFFLAGS) -Fo$@ -c $(SRC)alloc.c -$(OUTL)sf-date.o: $(SRC)date.c +$(OUTL)sf-date.o: $(SRC)date.c $(HACK_H) $(Q)$(CC) $(CFLAGS) $(SFFLAGS) -Fo$@ -c $(SRC)date.c -$(OUTL)sf-decl.o: $(SRC)decl.c +$(OUTL)sf-decl.o: $(SRC)decl.c $(HACK_H) $(Q)$(CC) $(CFLAGS) $(SFFLAGS) -Fo$@ -c $(SRC)decl.c -$(OUTL)sf-monst.o: $(SRC)monst.c +$(OUTL)sf-monst.o: $(SRC)monst.c $(HACK_H) $(Q)$(CC) $(CFLAGS) $(SFFLAGS) -Fo$@ -c $(SRC)monst.c -$(OUTL)sf-objects.o: $(SRC)objects.c +$(OUTL)sf-objects.o: $(SRC)objects.c $(HACK_H) $(Q)$(CC) $(CFLAGS) $(SFFLAGS) -Fo$@ -c $(SRC)objects.c -$(OUTL)sfbase.o: $(SRC)sfbase.c +$(OUTL)sfbase.o: $(SRC)sfbase.c $(HACK_H) $(Q)$(CC) $(CFLAGS) $(SFFLAGS) -Fo$@ -c $(SRC)sfbase.c -$(OUTL)sf-struct.o: $(SRC)sfstruct.c +$(OUTL)sf-struct.o: $(SRC)sfstruct.c $(HACK_H) $(Q)$(CC) $(CFLAGS) $(SFFLAGS) -Fo$@ -c $(SRC)sfstruct.c -$(OUTL)sf-artifact.o: $(SRC)artifact.c +$(OUTL)sf-artifact.o: $(SRC)artifact.c $(HACK_H) $(Q)$(CC) $(CFLAGS) $(SFFLAGS) -Fo$@ -c $(SRC)artifact.c -$(OUTL)sf-calendar.o: $(SRC)calendar.c +$(OUTL)sf-calendar.o: $(SRC)calendar.c $(HACK_H) $(Q)$(CC) $(CFLAGS) $(SFFLAGS) -Fo$@ -c $(SRC)calendar.c -$(OUTL)sf-cfgfiles.o: $(SRC)cfgfiles.c +$(OUTL)sf-cfgfiles.o: $(SRC)cfgfiles.c $(HACK_H) $(Q)$(CC) $(CFLAGS) $(SFFLAGS) -Fo$@ -c $(SRC)cfgfiles.c -$(OUTL)sf-dungeon.o: $(SRC)dungeon.c +$(OUTL)sf-dungeon.o: $(SRC)dungeon.c $(HACK_H) $(Q)$(CC) $(CFLAGS) $(SFFLAGS) -Fo$@ -c $(SRC)dungeon.c -$(OUTL)sf-end.o: $(SRC)end.c +$(OUTL)sf-end.o: $(SRC)end.c $(HACK_H) $(Q)$(CC) $(CFLAGS) $(SFFLAGS) -Fo$@ -c $(SRC)end.c -$(OUTL)sf-engrave.o: $(SRC)engrave.c +$(OUTL)sf-engrave.o: $(SRC)engrave.c $(HACK_H) $(Q)$(CC) $(CFLAGS) $(SFFLAGS) -Fo$@ -c $(SRC)engrave.c -$(OUTL)sf-files.o: $(SRC)files.c +$(OUTL)sf-files.o: $(SRC)files.c $(HACK_H) $(Q)$(CC) $(CFLAGS) $(SFFLAGS) -Fo$@ -c $(SRC)files.c -$(OUTL)sf-light.o: $(SRC)light.c +$(OUTL)sf-light.o: $(SRC)light.c $(HACK_H) $(Q)$(CC) $(CFLAGS) $(SFFLAGS) -Fo$@ -c $(SRC)light.c -$(OUTL)sf-mdlib.o: $(SRC)mdlib.c +$(OUTL)sf-mdlib.o: $(SRC)mdlib.c $(HACK_H) $(Q)$(CC) $(CFLAGS) $(SFFLAGS) -Fo$@ -c $(SRC)mdlib.c -$(OUTL)sf-mkmaze.o: $(SRC)mkmaze.c +$(OUTL)sf-mkmaze.o: $(SRC)mkmaze.c $(HACK_H) $(Q)$(CC) $(CFLAGS) $(SFFLAGS) -Fo$@ -c $(SRC)mkmaze.c -$(OUTL)sf-mkroom.o: $(SRC)mkroom.c +$(OUTL)sf-mkroom.o: $(SRC)mkroom.c $(HACK_H) $(Q)$(CC) $(CFLAGS) $(SFFLAGS) -Fo$@ -c $(SRC)mkroom.c -$(OUTL)sf-o_init.o: $(SRC)o_init.c +$(OUTL)sf-o_init.o: $(SRC)o_init.c $(HACK_H) $(Q)$(CC) $(CFLAGS) $(SFFLAGS) -Fo$@ -c $(SRC)o_init.c -$(OUTL)sf-region.o: $(SRC)region.c +$(OUTL)sf-region.o: $(SRC)region.c $(HACK_H) $(Q)$(CC) $(CFLAGS) $(SFFLAGS) -Fo$@ -c $(SRC)region.c -$(OUTL)sf-restore.o: $(SRC)restore.c +$(OUTL)sf-restore.o: $(SRC)restore.c $(HACK_H) $(Q)$(CC) $(CFLAGS) $(SFFLAGS) -Fo$@ -c $(SRC)restore.c -$(OUTL)sf-rumors.o: $(SRC)\rumors.c +$(OUTL)sf-rumors.o: $(SRC)\rumors.c $(HACK_H) $(Q)$(CC) $(CFLAGS) $(SFFLAGS) -Fo$@ -c $(SRC)rumors.c -$(OUTL)sf-timeout.o: $(SRC)timeout.c +$(OUTL)sf-timeout.o: $(SRC)timeout.c $(HACK_H) $(Q)$(CC) $(CFLAGS) $(SFFLAGS) -Fo$@ -c $(SRC)timeout.c -$(OUTL)sf-version.o: $(SRC)version.c +$(OUTL)sf-version.o: $(SRC)version.c $(HACK_H) $(Q)$(CC) $(CFLAGS) $(SFFLAGS) -Fo$@ -c $(SRC)version.c -$(OUTL)sf-worm.o: $(SRC)worm.c +$(OUTL)sf-worm.o: $(SRC)worm.c $(HACK_H) $(Q)$(CC) $(CFLAGS) $(SFFLAGS) -Fo$@ -c $(SRC)worm.c -$(OUTL)sf-nhlua.o: $(SRC)nhlua.c +$(OUTL)sf-nhlua.o: $(SRC)nhlua.c $(HACK_H) $(Q)$(CC) $(CFLAGS) $(SFFLAGS) -Fo$@ -c $(SRC)nhlua.c -$(OUTL)sf-track.o: $(SRC)track.c +$(OUTL)sf-track.o: $(SRC)track.c $(HACK_H) $(Q)$(CC) $(CFLAGS) $(SFFLAGS) -Fo$@ -c $(SRC)track.c -$(OUTL)sf-sys.o: $(SRC)sys.c +$(OUTL)sf-sys.o: $(SRC)sys.c $(HACK_H) $(Q)$(CC) $(CFLAGS) $(SFFLAGS) -Fo$@ -c $(SRC)sys.c -$(OUTL)sf-windsys.o: $(MSWSYS)windsys.c +$(OUTL)sf-windsys.o: $(MSWSYS)windsys.c $(HACK_H) $(Q)$(CC) $(CFLAGS) $(SFFLAGS) -Fo$@ -c $(MSWSYS)windsys.c $(UTIL)sftags.exe: $(OUTL)sftags.o $(OUTLHACKLIB) From c85b3f87d1fe1247104acbdfb30680b0b06c70e4 Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 2 Jun 2025 21:33:05 -0400 Subject: [PATCH 708/791] GNUmakefile follow-up --- sys/windows/GNUmakefile | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/sys/windows/GNUmakefile b/sys/windows/GNUmakefile index 98d561c2b..c8f765025 100644 --- a/sys/windows/GNUmakefile +++ b/sys/windows/GNUmakefile @@ -760,7 +760,32 @@ CLEAN_FILE += $(UTARGETS) $(UOBJS) # pacman -S ctags # -.PHONY: sfctool +.PHONEY: sfctool + +CONFIG_H = ../include/color.h ../include/config.h ../include/config1.h \ + ../include/coord.h ../include/cstd.h ../include/fnamesiz.h \ + ../include/global.h ../include/integer.h ../include/micro.h \ + ../include/patchlevel.h ../include/pcconf.h \ + ../include/tradstdc.h ../include/unixconf.h \ + ../include/vmsconf.h ../include/warnings.h \ + ../include/windconf.h +HACK_H = $(CONFIG_H) ../include/align.h ../include/artilist.h \ + ../include/attrib.h ../include/botl.h ../include/context.h \ + ../include/decl.h ../include/defsym.h ../include/display.h \ + ../include/dungeon.h ../include/engrave.h ../include/flag.h \ + ../include/hack.h ../include/lint.h ../include/mextra.h \ + ../include/mkroom.h ../include/monattk.h ../include/mondata.h \ + ../include/monflag.h ../include/monst.h ../include/monsters.h \ + ../include/nhlua.h ../include/obj.h ../include/objclass.h \ + ../include/objects.h ../include/permonst.h ../include/prop.h \ + ../include/quest.h ../include/rect.h ../include/region.h \ + ../include/rm.h ../include/savefile.h ../include/sfprocs.h \ + ../include/seffects.h ../include/selvar.h \ + ../include/skills.h ../include/sndprocs.h ../include/spell.h \ + ../include/stairs.h ../include/sym.h ../include/sys.h \ + ../include/timeout.h ../include/trap.h ../include/vision.h \ + ../include/weight.h ../include/winprocs.h \ + ../include/wintype.h ../include/you.h ../include/youprop.h OSFC = $(O)sfctool SFCTARGETS = $(U)sftags.exe $(GAMEDIR)/sfctool.exe From d25e01614022b2d8b66dc9446aee468512540f63 Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 2 Jun 2025 21:38:21 -0400 Subject: [PATCH 709/791] typo fix again --- sys/windows/GNUmakefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/windows/GNUmakefile b/sys/windows/GNUmakefile index c8f765025..cc3206073 100644 --- a/sys/windows/GNUmakefile +++ b/sys/windows/GNUmakefile @@ -760,7 +760,7 @@ CLEAN_FILE += $(UTARGETS) $(UOBJS) # pacman -S ctags # -.PHONEY: sfctool +.PHONY: sfctool CONFIG_H = ../include/color.h ../include/config.h ../include/config1.h \ ../include/coord.h ../include/cstd.h ../include/fnamesiz.h \ From cb12423a2ee80551fca7de2d12e77827c610ea0b Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 2 Jun 2025 21:52:38 -0400 Subject: [PATCH 710/791] sys/unix/Makefile.utl update for sfctool --- sys/unix/Makefile.utl | 58 +++++++++++++++++++++---------------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/sys/unix/Makefile.utl b/sys/unix/Makefile.utl index bcd2c4da4..6e8aa0c71 100644 --- a/sys/unix/Makefile.utl +++ b/sys/unix/Makefile.utl @@ -325,69 +325,69 @@ $(SFCTOOLBIN): $(SFCTOOLOBJS) $(HACKLIB) $(TARGET_CLINK) $(TARGET_LFLAGS) -o $@ $(SFCTOOLOBJS) $(HACKLIB) $(TARGET_LIBS) $(TARGETPFX)sfctool.o: sfctool.c $(HACK_H) ../include/sfprocs.h $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c sfctool.c -$(TARGETPFX)sf-alloc.o: ../src/alloc.c +$(TARGETPFX)sf-alloc.o: ../src/alloc.c $(HACK_H) $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/alloc.c -$(TARGETPFX)sf-calendar.o: ../src/calendar.c +$(TARGETPFX)sf-calendar.o: ../src/calendar.c $(HACK_H) $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/calendar.c -$(TARGETPFX)sf-cfgfiles.o: ../src/cfgfiles.c +$(TARGETPFX)sf-cfgfiles.o: ../src/cfgfiles.c $(HACK_H) $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/cfgfiles.c -$(TARGETPFX)sf-date.o: ../src/date.c +$(TARGETPFX)sf-date.o: ../src/date.c $(HACK_H) $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/date.c -$(TARGETPFX)sf-decl.o: ../src/decl.c +$(TARGETPFX)sf-decl.o: ../src/decl.c $(HACK_H) $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/decl.c -$(TARGETPFX)sf-monst.o: ../src/monst.c +$(TARGETPFX)sf-monst.o: ../src/monst.c $(HACK_H) $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/monst.c -$(TARGETPFX)sf-objects.o: ../src/objects.c +$(TARGETPFX)sf-objects.o: ../src/objects.c $(HACK_H) $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/objects.c $(TARGETPFX)sf-panic.o: panic.c $(CONFIG_H) $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c panic.c -$(TARGETPFX)sf-artifact.o: ../src/artifact.c +$(TARGETPFX)sf-artifact.o: ../src/artifact.c $(HACK_H) $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/artifact.c -$(TARGETPFX)sf-dungeon.o: ../src/dungeon.c +$(TARGETPFX)sf-dungeon.o: ../src/dungeon.c $(HACK_H) $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/dungeon.c -$(TARGETPFX)sf-end.o: ../src/end.c +$(TARGETPFX)sf-end.o: ../src/end.c $(HACK_H) $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/end.c -$(TARGETPFX)sf-engrave.o: ../src/engrave.c +$(TARGETPFX)sf-engrave.o: ../src/engrave.c $(HACK_H) $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/engrave.c -$(TARGETPFX)sf-files.o: ../src/files.c +$(TARGETPFX)sf-files.o: ../src/files.c $(HACK_H) $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/files.c -$(TARGETPFX)sf-light.o: ../src/light.c +$(TARGETPFX)sf-light.o: ../src/light.c $(HACK_H) $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/light.c -$(TARGETPFX)sf-mdlib.o: ../src/mdlib.c +$(TARGETPFX)sf-mdlib.o: ../src/mdlib.c $(HACK_H) $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/mdlib.c -$(TARGETPFX)sf-mkmaze.o: ../src/mkmaze.c +$(TARGETPFX)sf-mkmaze.o: ../src/mkmaze.c $(HACK_H) $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/mkmaze.c -$(TARGETPFX)sf-mkroom.o: ../src/mkroom.c +$(TARGETPFX)sf-mkroom.o: ../src/mkroom.c $(HACK_H) $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/mkroom.c -$(TARGETPFX)sf-nhlua.o: ../src/nhlua.c +$(TARGETPFX)sf-nhlua.o: ../src/nhlua.c $(HACK_H) $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/nhlua.c -$(TARGETPFX)sf-o_init.o: ../src/o_init.c +$(TARGETPFX)sf-o_init.o: ../src/o_init.c $(HACK_H) $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/o_init.c -$(TARGETPFX)sf-region.o: ../src/region.c +$(TARGETPFX)sf-region.o: ../src/region.c $(HACK_H) $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/region.c -$(TARGETPFX)sf-restore.o: ../src/restore.c +$(TARGETPFX)sf-restore.o: ../src/restore.c $(HACK_H) $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/restore.c -$(TARGETPFX)sf-rumors.o: ../src/rumors.c +$(TARGETPFX)sf-rumors.o: ../src/rumors.c $(HACK_H) $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/rumors.c -$(TARGETPFX)sfbase.o: ../src/sfbase.c +$(TARGETPFX)sfbase.o: ../src/sfbase.c $(HACK_H) $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/sfbase.c $(TARGETPFX)sfdata.o: sfdata.c $(HACK_H) ../include/sfprocs.h ../include/sfproto.h $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c sfdata.c $(TARGETPFX)sfexpasc.o: sfexpasc.c $(HACK_H) ../include/sfprocs.h ../include/sfproto.h $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c sfexpasc.c -$(TARGETPFX)sf-struct.o: ../src/sfstruct.c +$(TARGETPFX)sf-struct.o: ../src/sfstruct.c $(HACK_H) $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/sfstruct.c -$(TARGETPFX)strutil.o: ../src/strutil.c +$(TARGETPFX)strutil.o: ../src/strutil.c $(HACK_H) $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/strutil.c -$(TARGETPFX)sf-sys.o: ../src/sys.c +$(TARGETPFX)sf-sys.o: ../src/sys.c $(HACK_H) $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/sys.c -$(TARGETPFX)sf-timeout.o: ../src/timeout.c +$(TARGETPFX)sf-timeout.o: ../src/timeout.c $(HACK_H) $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/timeout.c -$(TARGETPFX)sf-track.o: ../src/track.c +$(TARGETPFX)sf-track.o: ../src/track.c $(HACK_H) $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/track.c -$(TARGETPFX)sf-version.o: ../src/version.c +$(TARGETPFX)sf-version.o: ../src/version.c $(HACK_H) $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/version.c -$(TARGETPFX)sf-worm.o: ../src/worm.c +$(TARGETPFX)sf-worm.o: ../src/worm.c $(HACK_H) $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/worm.c sftags: sftags.o $(HACKLIB) From 6c6d8afb8f5fd479ff798a05e13874fe7b03b110 Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 2 Jun 2025 22:37:48 -0400 Subject: [PATCH 711/791] fix a warning during sfctool build --- src/restore.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/restore.c b/src/restore.c index 086f21d99..bf2376c4e 100644 --- a/src/restore.c +++ b/src/restore.c @@ -1385,7 +1385,9 @@ void restore_msghistory(NHFILE *nhfp) { int msgsize = 0; +#ifndef SFCTOOL int msgcount = 0; +#endif char msg[BUFSZ]; while (1) { @@ -1398,8 +1400,8 @@ restore_msghistory(NHFILE *nhfp) msg[msgsize] = '\0'; #ifndef SFCTOOL putmsghistory(msg, TRUE); -#endif /* !SFCTOOL */ ++msgcount; +#endif /* !SFCTOOL */ } #ifndef SFCTOOL if (msgcount) From 356f451b1b572fa31bf22a9bae03c4fc64476bda Mon Sep 17 00:00:00 2001 From: nhmall Date: Tue, 3 Jun 2025 07:35:34 -0400 Subject: [PATCH 712/791] prevent a double free() --- src/rumors.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/rumors.c b/src/rumors.c index 711d08516..5aac3bd40 100644 --- a/src/rumors.c +++ b/src/rumors.c @@ -613,6 +613,7 @@ save_oracles(NHFILE *nhfp) } if (svo.oracle_loc) { free((genericptr_t) svo.oracle_loc); + svo.oracle_loc = 0; } } } From 28af1d641068d6f47645127ce33585f91676e239 Mon Sep 17 00:00:00 2001 From: nhmall Date: Tue, 3 Jun 2025 20:45:08 -0400 Subject: [PATCH 713/791] whitespace cleanup in sfbase.c --- src/sfbase.c | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/src/sfbase.c b/src/sfbase.c index 8c722eeb4..07de09b3b 100644 --- a/src/sfbase.c +++ b/src/sfbase.c @@ -71,18 +71,18 @@ void sf_log(NHFILE *, const char *, size_t, int, char *); #else -#define sfvalue(x) \ - _Generic( (x), \ - anything *: sfvalue_any, \ +#define sfvalue(x) \ + _Generic( (x), \ + anything *: sfvalue_any, \ genericptr_t *: sfvalue_genericptr, \ - int16_t *: sfvalue_int16, \ - int32_t *: sfvalue_int32, \ - int64_t *: sfvalue_int64, \ - uchar *: sfvalue_uchar, \ - uint16_t *: sfvalue_uint16, \ - uint32_t *: sfvalue_uint32, \ - uint64_t *: sfvalue_uint64, \ - xint8 *: sfvalue_xint8 \ + int16_t *: sfvalue_int16, \ + int32_t *: sfvalue_int32, \ + int64_t *: sfvalue_int64, \ + uchar *: sfvalue_uchar, \ + uint16_t *: sfvalue_uint16, \ + uint32_t *: sfvalue_uint32, \ + uint64_t *: sfvalue_uint64, \ + xint8 *: sfvalue_xint8 \ )(x) #define Sfvalue_any(a) sfvalue(a) @@ -160,14 +160,14 @@ void sfo_##dtyp(NHFILE *nhfp, keyw dtyp *d_##dtyp, const char *myname) { \ if (nhfp->fplog) \ sf_log(nhfp, myname, sizeof *d_##dtyp, 1, \ - complex_dump((uchar *) d_##dtyp)); \ + complex_dump((uchar *) d_##dtyp)); \ if (nhfp->structlevel) { \ (*sfoprocs[nhfp->fnidx].fn.sf_##dtyp)(nhfp, d_##dtyp, myname); \ } else { \ FILE *save_fplog = nhfp->fplog; \ \ nhfp->fplog = 0; \ - (*sfoflprocs[nhfp->fnidx].fn_x.sf_##dtyp)(nhfp, d_##dtyp, myname); \ + (*sfoflprocs[nhfp->fnidx].fn_x.sf_##dtyp)(nhfp, d_##dtyp, myname); \ nhfp->fplog = save_fplog; \ } \ } \ @@ -181,7 +181,7 @@ void sfi_##dtyp(NHFILE *nhfp, keyw dtyp *d_##dtyp, const char *myname) \ nhfp->mode &= ~(CONVERTING | UNCONVERTING); \ nhfp->mode |= TURN_OFF_LOGGING; \ - (*sfiflprocs[nhfp->fnidx].fn_x.sf_##dtyp)(nhfp, d_##dtyp, myname); \ + (*sfiflprocs[nhfp->fnidx].fn_x.sf_##dtyp)(nhfp, d_##dtyp, myname); \ nhfp->mode = save_mode; \ } \ if (!nhfp->eof) { \ @@ -192,7 +192,7 @@ void sfi_##dtyp(NHFILE *nhfp, keyw dtyp *d_##dtyp, const char *myname) } \ if (nhfp->fplog) \ sf_log(nhfp, myname, sizeof *d_##dtyp, 1, \ - complex_dump((uchar *) d_##dtyp)); \ + complex_dump((uchar *) d_##dtyp)); \ } \ } @@ -208,7 +208,8 @@ void sfo_##dtyp(NHFILE *nhfp, xxx *d_##dtyp, const char *myname, int bfsz) FILE *save_fplog = nhfp->fplog; \ \ nhfp->fplog = 0; \ - (*sfoflprocs[nhfp->fnidx].fn_x.sf_##dtyp)(nhfp, d_##dtyp, myname, bfsz); \ + (*sfoflprocs[nhfp->fnidx].fn_x.sf_##dtyp)(nhfp, d_##dtyp, \ + myname, bfsz); \ nhfp->fplog = save_fplog; \ } \ if (nhfp->fplog && !nhfp->eof) \ @@ -224,7 +225,8 @@ void sfi_##dtyp(NHFILE *nhfp, xxx *d_##dtyp, const char *myname, int bfsz) \ nhfp->mode &= ~(CONVERTING | UNCONVERTING); \ nhfp->mode |= TURN_OFF_LOGGING; \ - (*sfiflprocs[nhfp->fnidx].fn_x.sf_##dtyp)(nhfp, d_##dtyp, myname, bfsz); \ + (*sfiflprocs[nhfp->fnidx].fn_x.sf_##dtyp)(nhfp, d_##dtyp, \ + myname, bfsz); \ nhfp->mode = save_mode; \ } \ if (!nhfp->eof) { \ From 45f751989af58a7f49db6cc66b143f2bf94db3a1 Mon Sep 17 00:00:00 2001 From: PatR Date: Tue, 3 Jun 2025 22:13:22 -0700 Subject: [PATCH 714/791] fix #K4331 - sticking from distance Stop attacking if target isn't there anymore. Already handled for two-weapon in normal form, not for multi-attacks in poly'd form and for multi-attack monster vs hero or monster vs other monster. I didn't attempt to reproduce the reported problem. This fix is based on code inspection. Also prevent monsters that have hug or engulf attacks from knocking target back with other attacks since that prohibits the grab/engulf from being able to hit. --- src/mhitm.c | 11 ++++++++++- src/mhitu.c | 2 ++ src/uhitm.c | 32 +++++++++++++++++++++++--------- 3 files changed, 35 insertions(+), 10 deletions(-) diff --git a/src/mhitm.c b/src/mhitm.c index 8892c0f59..39fe251a7 100644 --- a/src/mhitm.c +++ b/src/mhitm.c @@ -284,6 +284,9 @@ mdisplacem( * Each successive attack has a lower probability of hitting. Some rely on * success of previous attacks. ** this doesn't seem to be implemented -dl ** * + * Attacker has targeted rather than + * mx,mdef->my>; matters for long worms. + * * In the case of exploding monsters, the monster dies as well. */ int @@ -353,7 +356,7 @@ mattackm( /* Set up the visibility of action */ gv.vis = ((cansee(magr->mx, magr->my) && canspotmon(magr)) - || (cansee(mdef->mx, mdef->my) && canspotmon(mdef))); + || (cansee(mdef->mx, mdef->my) && canspotmon(mdef))); /* Set flag indicating monster has moved this turn. Necessary since a * monster might get an attack out of sequence (i.e. before its move) in @@ -371,6 +374,12 @@ mattackm( /* Now perform all attacks for the monster. */ for (i = 0; i < NATTK; i++) { res[i] = M_ATTK_MISS; + + /* target might no longer be there */ + if (i > 0 && (m_at(gb.bhitpos.x, gb.bhitpos.y) != mdef + || DEADMONSTER(magr) || DEADMONSTER(mdef))) + continue; + mattk = getmattk(magr, mdef, i, res, &alt_attk); /* reduce verbosity for mind flayer attacking creature without a head (or worm's tail); this is similar to monster with multiple diff --git a/src/mhitu.c b/src/mhitu.c index ed0b6e098..0357915e8 100644 --- a/src/mhitu.c +++ b/src/mhitu.c @@ -754,6 +754,8 @@ mattacku(struct monst *mtmp) /* if hero was found but isn't anymore, avoid wildmiss now */ if (firstfoundyou && !foundyou) continue; /* set sum[i] to 'miss' but skip other actions */ + if (!u_at(gb.bhitpos.x, gb.bhitpos.y)) + continue; } mon_currwep = (struct obj *) 0; mattk = getmattk(mtmp, &gy.youmonst, i, sum, &alt_attk); diff --git a/src/uhitm.c b/src/uhitm.c index 56a4079ce..90014bcd6 100644 --- a/src/uhitm.c +++ b/src/uhitm.c @@ -5203,7 +5203,7 @@ mhitm_knockback( boolean u_def = (mdef == &gy.youmonst); boolean was_u = FALSE, dismount = FALSE; struct obj *wep = weapon_used ? (u_agr ? uwep : MON_WEP(magr)) - : (struct obj *)0; + : (struct obj *) 0; if (wep && is_art(wep, ART_OGRESMASHER)) chance = 2; @@ -5211,6 +5211,20 @@ mhitm_knockback( if (rn2(chance)) return FALSE; + /* only certain attacks qualify for knockback */ + if (!((mattk->adtyp == AD_PHYS) + && (mattk->aatyp == AT_CLAW + || mattk->aatyp == AT_KICK + || mattk->aatyp == AT_BUTT + || mattk->aatyp == AT_WEAP))) + return FALSE; + + /* don't knockback if attacker also wants to grab or engulf */ + if (attacktype(magr->data, AT_ENGL) + || attacktype(magr->data, AT_HUGS) + || sticks(magr->data)) + return FALSE; + /* decide where the first step will place the target; not accurate for being knocked out of saddle but doesn't need to be; used for test_move() and for message before actual hurtle */ @@ -5257,14 +5271,6 @@ mhitm_knockback( if (wep && (is_flimsy(wep) || !is_blunt_weapon(wep))) return FALSE; - /* only certain attacks qualify for knockback */ - if (!((mattk->adtyp == AD_PHYS) - && (mattk->aatyp == AT_CLAW - || mattk->aatyp == AT_KICK - || mattk->aatyp == AT_BUTT - || mattk->aatyp == AT_WEAP))) - return FALSE; - /* needs a solid physical hit */ if (unsolid(magr->data)) return FALSE; @@ -5388,6 +5394,14 @@ hmonas(struct monst *mon) for (i = 0; i < NATTK; i++) { /* sum[i] = M_ATTK_MISS; -- now done above */ + + /* target might have been knocked back so no longer in range, or an + engulfing vampshifted fog cloud killed and reverted to vampire + that's placed at another spot (hero occupies mon's first spot) */ + if (i > 0 && (m_at(gb.bhitpos.x, gb.bhitpos.y) != mon + || DEADMONSTER(mon))) + continue; + mattk = getmattk(&gy.youmonst, mon, i, sum, &alt_attk); if (gs.skipdrin && mattk->aatyp == AT_TENT && mattk->adtyp == AD_DRIN) continue; From b8aa0a507c5d8538e569d527fbc0f21f805ec0ee Mon Sep 17 00:00:00 2001 From: nhmall Date: Wed, 4 Jun 2025 05:51:03 -0400 Subject: [PATCH 715/791] warning in cfgfiles.c while building sfctool ../src/cfgfiles.c:457:9: warning: variable 'nsep' set but not used [-Wunused-but-set-variable] 457 | int nsep = 1; | ^ 1 warning generated. --- src/cfgfiles.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/cfgfiles.c b/src/cfgfiles.c index 2fded6d51..3a3c0ff06 100644 --- a/src/cfgfiles.c +++ b/src/cfgfiles.c @@ -470,6 +470,7 @@ choose_random_part(char *str, char sep) #ifndef SFCTOOL csep = rn2(nsep); #else + nhUse(nsep); csep = 1; #endif str = begin; From 8d0b284dc606564da1a160828048ceb293486c57 Mon Sep 17 00:00:00 2001 From: nhmall Date: Wed, 4 Jun 2025 07:37:34 -0400 Subject: [PATCH 716/791] update tested versions of Visual Studio 2025-06-04 --- sys/windows/Makefile.nmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sys/windows/Makefile.nmake b/sys/windows/Makefile.nmake index 04dc2c59f..b06d6e915 100644 --- a/sys/windows/Makefile.nmake +++ b/sys/windows/Makefile.nmake @@ -9,7 +9,7 @@ # # Visual Studio Compilers Tested: # - Microsoft Visual Studio 2019 Community Edition v 16.11.42 -# - Microsoft Visual Studio 2022 Community Edition v 17.14.3 +# - Microsoft Visual Studio 2022 Community Edition v 17.14.4 # #============================================================================== # This is used for building two distinct executables of NetHack: @@ -1178,7 +1178,7 @@ rc=Rc.exe # # Recently tested versions: TESTEDVS2019 = 14.29.30157.0 -TESTEDVS2022 = 14.44.35208.0 +TESTEDVS2022 = 14.44.35209.0 VS2019CUR = $(TESTEDVS2019:.=) VS2022CUR = $(TESTEDVS2022:.=) From c384f6acb6d3bbc218999f85d16efbf8a9011f12 Mon Sep 17 00:00:00 2001 From: nhmall Date: Wed, 4 Jun 2025 07:39:12 -0400 Subject: [PATCH 717/791] macro whitespace cleanup in util/sfexpasc.c --- util/sfexpasc.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/util/sfexpasc.c b/util/sfexpasc.c index f129efe6c..ecd0e6919 100644 --- a/util/sfexpasc.c +++ b/util/sfexpasc.c @@ -85,55 +85,55 @@ void exportascii_sfi_cnt(NHFILE *nhfp, char *d_str, const char *myname UNUSED, i } #define SF_A(dtyp) \ -void exportascii_sfo_##dtyp(NHFILE *, dtyp *d_##dtyp, \ +void exportascii_sfo_##dtyp(NHFILE *, dtyp *d_##dtyp, \ const char *); \ -void exportascii_sfi_##dtyp(NHFILE *, dtyp *d_##dtyp, \ +void exportascii_sfi_##dtyp(NHFILE *, dtyp *d_##dtyp, \ const char *); /* -void exportascii_sfo_##dtyp(NHFILE *nhfp, dtyp *d_##dtyp, \ +void exportascii_sfo_##dtyp(NHFILE *nhfp, dtyp *d_##dtyp, \ const char *myname UNUSED) \ SFO_BODY(dtyp) \ \ -void exportascii_sfi_##dtyp(NHFILE *nhfp, dtyp *d_##dtyp, \ +void exportascii_sfi_##dtyp(NHFILE *nhfp, dtyp *d_##dtyp, \ const char *myname UNUSED) \ SFI_BODY(dtyp) */ #define SF_C(keyw, dtyp) \ -void exportascii_sfo_##dtyp(NHFILE * UNUSED, keyw dtyp *d_##dtyp UNUSED, \ +void exportascii_sfo_##dtyp(NHFILE * UNUSED, keyw dtyp *d_##dtyp UNUSED, \ const char *); \ -void exportascii_sfi_##dtyp(NHFILE *UNUSED, keyw dtyp *d_##dtyp, \ +void exportascii_sfi_##dtyp(NHFILE *UNUSED, keyw dtyp *d_##dtyp, \ const char *); \ \ -void exportascii_sfo_##dtyp(NHFILE *nhfp UNUSED, keyw dtyp *d_##dtyp UNUSED, \ +void exportascii_sfo_##dtyp(NHFILE *nhfp UNUSED, keyw dtyp *d_##dtyp UNUSED, \ const char *myname UNUSED) \ SFO_BODY(dtyp) \ \ -void exportascii_sfi_##dtyp(NHFILE *nhfp UNUSED, keyw dtyp *d_##dtyp UNUSED, \ +void exportascii_sfi_##dtyp(NHFILE *nhfp UNUSED, keyw dtyp *d_##dtyp UNUSED, \ const char *myname UNUSED) \ SFI_BODY(dtyp) #define SF_X(xxx, dtyp) \ -void exportascii_sfo_##dtyp(NHFILE * UNUSED, xxx *d_##dtyp UNUSED, \ +void exportascii_sfo_##dtyp(NHFILE * UNUSED, xxx *d_##dtyp UNUSED, \ const char * UNUSED); \ -void exportascii_sfi_##dtyp(NHFILE *, xxx *d_##dtyp, \ +void exportascii_sfi_##dtyp(NHFILE *, xxx *d_##dtyp, \ const char *); \ \ -void exportascii_sfo_##dtyp(NHFILE *nhfp UNUSED, xxx *d_##dtyp UNUSED, \ +void exportascii_sfo_##dtyp(NHFILE *nhfp UNUSED, xxx *d_##dtyp UNUSED, \ const char *myname UNUSED) \ SFO_BODY(dtyp) \ \ -void exportascii_sfi_##dtyp(NHFILE *nhfp, xxx *d_##dtyp, \ +void exportascii_sfi_##dtyp(NHFILE *nhfp, xxx *d_##dtyp, \ const char *myname UNUSED) \ SFI_BODY(dtyp) #define SF_BF(xxx, dtyp) \ -void exportascii_sfo_##dtyp(NHFILE *, xxx *d_##dtyp, \ +void exportascii_sfo_##dtyp(NHFILE *, xxx *d_##dtyp, \ const char *, int); \ -void exportascii_sfi_##dtyp(NHFILE *, xxx *d_##dtyp, \ +void exportascii_sfi_##dtyp(NHFILE *, xxx *d_##dtyp, \ const char *, int); SF_C(struct, arti_info) From 92f02d73a4d8bd26a89ca7e6566803206f2fcfb1 Mon Sep 17 00:00:00 2001 From: PatR Date: Wed, 4 Jun 2025 13:27:24 -0700 Subject: [PATCH 718/791] github issue #1416 - regression of towel's weight The blindness overhaul branch was created before towel weight got changed, then unintentionally put the old weight back when it was finally merged. Increase weight to towel from 2 to 5 again. Fixes #1416 --- include/objects.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/objects.h b/include/objects.h index e7783a2d2..1108f14b0 100644 --- a/include/objects.h +++ b/include/objects.h @@ -1,4 +1,4 @@ -/* NetHack 3.7 objects.h $NHDT-Date: 1725653011 2024/09/06 20:03:31 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.26 $ */ +/* NetHack 3.7 objects.h $NHDT-Date: 1749097644 2025/06/04 20:27:24 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.30 $ */ /* Copyright (c) Mike Threepoint, 1989. */ /* NetHack may be freely redistributed. See license for details. */ @@ -935,7 +935,7 @@ EYEWEAR("lenses", NoDes, 1, 0, 5, 3, 80, GLASS, HI_GLASS, LENSES), EYEWEAR("blindfold", NoDes, 1, BLINDED, 50, 2, 20, CLOTH, CLR_BLACK, BLINDFOLD), -EYEWEAR("towel", NoDes, 1, BLINDED, 50, 2, 50, CLOTH, CLR_MAGENTA, +EYEWEAR("towel", NoDes, 1, BLINDED, 50, 5, 50, CLOTH, CLR_MAGENTA, TOWEL), #undef EYEWEAR From 7122c0cb0aae4fe3c2af6371a8903b7e96819906 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Thu, 19 Jun 2025 12:00:56 +0300 Subject: [PATCH 719/791] Add a literary reference to genetic engineer database entry --- dat/data.base | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/dat/data.base b/dat/data.base index df3fd0f73..ed42fca25 100644 --- a/dat/data.base +++ b/dat/data.base @@ -2056,6 +2056,16 @@ genetic engineer immediate mutations in the subject. Far from needing an elaborate laboratory to accomplish such abominations, a mere touch seems to be all that is necessary. + [] + + "I thought the whole point of genetic engineering was to avoid + the random waste of natural evolution, and replace it with + the efficiency of reason," Miles piped up. All three haut- + women turned to stare at him in astonishment, as if a potted + plant had suddenly offered a critique of its fertilization + routine. "Or ... so it seems to me," Miles trailed off in + a much smaller voice. + [ Cetaganda, Lois McMaster Bujold ] geryon Forthwith that image vile of fraud appear'd, His head and upper part expos'd on land, From 1e5a132fa16bdceb9e9d4a35d1cd57d31c691069 Mon Sep 17 00:00:00 2001 From: nhmall Date: Thu, 19 Jun 2025 13:44:06 -0400 Subject: [PATCH 720/791] update tested versions of Visual Studio 2025-06-19 --- sys/windows/Makefile.nmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sys/windows/Makefile.nmake b/sys/windows/Makefile.nmake index b06d6e915..cf95dc141 100644 --- a/sys/windows/Makefile.nmake +++ b/sys/windows/Makefile.nmake @@ -9,7 +9,7 @@ # # Visual Studio Compilers Tested: # - Microsoft Visual Studio 2019 Community Edition v 16.11.42 -# - Microsoft Visual Studio 2022 Community Edition v 17.14.4 +# - Microsoft Visual Studio 2022 Community Edition v 17.14.6 # #============================================================================== # This is used for building two distinct executables of NetHack: @@ -1178,7 +1178,7 @@ rc=Rc.exe # # Recently tested versions: TESTEDVS2019 = 14.29.30157.0 -TESTEDVS2022 = 14.44.35209.0 +TESTEDVS2022 = 14.44.35211.0 VS2019CUR = $(TESTEDVS2019:.=) VS2022CUR = $(TESTEDVS2022:.=) From 02885dfccfeaf4bbc7189e3d77701a16ad4c146e Mon Sep 17 00:00:00 2001 From: PatR Date: Sat, 21 Jun 2025 22:16:35 -0700 Subject: [PATCH 721/791] X11 xrdb complaints Three instances of "'s" were triggering warnings due to unmatched apostrophe in the X11 application defaults file. Reword the affected comments. --- win/X11/NetHack.ad | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/win/X11/NetHack.ad b/win/X11/NetHack.ad index 22e2c6bae..4c5f9b191 100644 --- a/win/X11/NetHack.ad +++ b/win/X11/NetHack.ad @@ -1,4 +1,4 @@ -! $NHDT-Date: 1542244983 2018/11/15 01:23:03 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.20 $ +! $NHDT-Date: 1750598195 2025/06/22 05:16:35 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.27 $ ! Copyright (c) 2017 by Pasi Kallinen ! NetHack may be freely redistributed. See license for details. @@ -56,7 +56,7 @@ NetHack.tile_file: x11tiles !NetHack.tombtext_y: 78 !NetHack.tombtext_dx: 0 !NetHack.tombtext_dy: 13 -! The color to use for the text on the hero's tombstone +! The color to use for the text on the tombstone of the hero (end of game). NetHack*rip*foreground: black ! The icon to use; supported values are nh72, nh56, and nh32; nh72 is the @@ -80,7 +80,7 @@ NetHack*rip*foreground: black !NetHack*autofocus: True ! If 'slow' is True, setting 'highlight_prompt' to True will cause the line -! between map and message display that's used for prompting to be "hidden" +! between map and message display that is used for prompting to be "hidden" ! as part of the map when no prompt is active, then invert foreground and ! background to stand out when a prompt is issued and waiting for a response. ! If 'slow' is False, 'highlight_prompt' will have no effect. @@ -116,8 +116,8 @@ NetHack*message*translations: : input() ! !Down: input(j) ! Specify the number of rows and columns of the map window. The default -! is the standard 80x21 window. Note: this _does_not_ change nethack's -! level size, only what you see of it. +! is the standard 80x21 window. Note: this _does_not_ change the size of +! map levels, only what you see of them. !NetHack*map*rows: 21 !NetHack*map*columns: 80 From 8d8867007fdd9d1afad69405f1f04a7396b92ac7 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Fri, 27 Jun 2025 00:28:27 +0300 Subject: [PATCH 722/791] Typofix --- sys/unix/unixmain.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/unix/unixmain.c b/sys/unix/unixmain.c index 6e943d685..06bc853e6 100644 --- a/sys/unix/unixmain.c +++ b/sys/unix/unixmain.c @@ -555,7 +555,7 @@ process_options(int argc, char *argv[]) if (mx_ok) gl.locknum = mxplyrs; else - config_error_add("Invalid MAXPLATERS \"%s\"", argv[1]); + config_error_add("Invalid MAXPLAYERS \"%s\"", argv[1]); #endif } #ifdef MAX_NR_OF_PLAYERS From 34b42d2354f443b2678cb4c564e93dd8236665c3 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 29 Jun 2025 11:59:07 -0400 Subject: [PATCH 723/791] recent qt6 requires c++20 There are warnings within the qt6 header files if c++20 is not used, for example: usr/include/x86_64-linux-gnu/qt6/QtCore/qfuturesynchronizer.h:21:5: warning: use of the 'nodiscard' attribute is a C++20 extension [-Wc++20-attribute-extensions] 21 | Q_NODISCARD_CTOR_X("Use future.waitForFinished() instead.") | ^ /usr/include/x86_64-linux-gnu/qt6/QtCore/qcompilerdetection.h:972:43: note: expanded from macro 'Q_NODISCARD_CTOR_X' 972 | # define Q_NODISCARD_CTOR_X(message) [[nodiscard(message)]] | ^ 1 warning generated. qmake6 --version QMake version 3.1 Using Qt version 6.8.3 in /usr/lib/x86_64-linux-gnu --- sys/unix/hints/include/compiler.370 | 14 ++++++++++++++ sys/unix/hints/include/multiw-2.370 | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/sys/unix/hints/include/compiler.370 b/sys/unix/hints/include/compiler.370 index 62486d3ad..5ef6f801e 100755 --- a/sys/unix/hints/include/compiler.370 +++ b/sys/unix/hints/include/compiler.370 @@ -26,6 +26,7 @@ CCFLAGS = -g # If these are set on entry, preparation for C++ compiles is affected. # CPLUSPLUS_NEEDED = 1 C++ compile bits included # CPLUSPLUS_NEED17 = 1 C++ -std=c++17 (at least) +# CPLUSPLUS_NEED20 = 1 C++ -std=c++20 (at least) # CPLUSPLUS_NEED_DEPSUPPRESS = 1 C++ -Wno-deprecated-copy, # -Wno-deprecated-declarations @@ -149,6 +150,14 @@ else # g++ version greater than or equal to 12? (no follows) CCXX=g++ -std=c++17 endif # g++ version greater than or equal to 12 endif # CPLUSPLUS_NEED17 +ifdef CPLUSPLUS_NEED20 +ifeq "$(GPPGTEQ9)" "1" +CCXX=g++ -std=c++20 +else # g++ version greater than or equal to 9? (no follows) +CCXX=g++ -std=c++17 +endif # g++ version greater than or equal to 9 +endif # CPLUSPLUS_NEED20 + else # g++ or clang++ ? @@ -183,6 +192,11 @@ ifeq "$(CLANGPPGTEQ17)" "1" CCXX=clang++ -std=c++17 endif # clang++ greater than or equal to 17 endif # CPLUSPLUS_NEED17 +ifdef CPLUSPLUS_NEED20 +ifeq "$(CLANGPPGTEQ17)" "1" +CCXX=clang++ -std=c++20 +endif # clang++ greater than or equal to 17 +endif # CPLUSPLUS_NEED20 endif # end of clang++-specific section CXX=$(CCXX) endif # CPLUSPLUS_NEEDED diff --git a/sys/unix/hints/include/multiw-2.370 b/sys/unix/hints/include/multiw-2.370 index 073cc9c20..c580063b6 100644 --- a/sys/unix/hints/include/multiw-2.370 +++ b/sys/unix/hints/include/multiw-2.370 @@ -163,7 +163,7 @@ ifndef CPLUSPLUS_NEEDED CPLUSPLUS_NEEDED = 1 endif # CPLUSPLUS_NEEDED ifdef WANT_WIN_QT6 -CPLUSPLUS_NEED17 = 1 +CPLUSPLUS_NEED20 = 1 CPLUSPLUS_NEED_DEPSUPPRESS = 1 endif # WANT_WIN_QT6 endif # WANT_WIN_QT From 459a339a9507027bfe1fd3b621b9692f308dab0c Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 29 Jun 2025 13:31:02 -0400 Subject: [PATCH 724/791] X11: strip extra bits off color when used as index --- win/X11/winmap.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/win/X11/winmap.c b/win/X11/winmap.c index d27f0ac88..9445f8170 100644 --- a/win/X11/winmap.c +++ b/win/X11/winmap.c @@ -1567,8 +1567,8 @@ X11_make_gc( } ggc = (iflags.use_color ? (cur_inv - ? text_map->inv_color_gcs[color] - : text_map->color_gcs[color]) + ? text_map->inv_color_gcs[COLORVAL(color)] + : text_map->color_gcs[COLORVAL(color)]) : (cur_inv ? text_map->inv_copy_gc : text_map->copy_gc)); From a93397e286800b3734bae1dc09817e3c4acee7e6 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 29 Jun 2025 20:43:28 -0400 Subject: [PATCH 725/791] follow-up bit This may not be required, but it won't hurt. --- win/X11/winmap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/win/X11/winmap.c b/win/X11/winmap.c index 9445f8170..cb86685ce 100644 --- a/win/X11/winmap.c +++ b/win/X11/winmap.c @@ -1444,7 +1444,7 @@ map_update(struct xwindow *wp, int start_row, int stop_row, int start_col, int s BlackPixelOfScreen(screen)); } { - uint32_t fc = tile_map->glyphs[row][cur_col].framecolor; + uint32_t fc = COLORVAL(tile_map->glyphs[row][cur_col].framecolor); if (fc != NO_COLOR) XDrawRectangle(dpy, XtWindow(wp->w), From a89d6b3bae30632d4aadbc6207e0c16455adb79f Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Mon, 30 Jun 2025 12:34:40 +0300 Subject: [PATCH 726/791] Tutorial: fix non-alt keys shown as alt-combos Lua doesn't have regexes, and "-" has special meaning in match; escape the minus with "%", so it actually matches a minus sign. --- 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 f6a31cf82..9c7eb268d 100644 --- a/dat/tut-1.lua +++ b/dat/tut-1.lua @@ -10,7 +10,7 @@ function tut_key(command) return "Ctrl-" .. m; end - m = s:match("^M-([A-Z])$"); -- M-X is Alt-X + m = s:match("^M%-([A-Z])$"); -- M-X is Alt-X if (m ~= nil) then tut_alt_key = m; return "Alt-" .. m; From 2b0530a5edfe34687efb617aed600a8a34ff4165 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Mon, 30 Jun 2025 12:41:16 +0300 Subject: [PATCH 727/791] Tutorial: iron bars to show hidden stairs Seems like several new players did not find the "hidden" stairs. Add iron bars to show a glimpse of them - the hero still needs to find the secret door in to the room. --- 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 9c7eb268d..7f8dba5c5 100644 --- a/dat/tut-1.lua +++ b/dat/tut-1.lua @@ -41,7 +41,7 @@ des.map([[ |......| |.-------------------.......|...|....--S----............| |......| ###### |.........| |..S.......|...|....|.....|............| |----.-| -+- # |.....---.|######+..|.......S...|....|.....|............| -|----+----.----+---.|.--|.|.|# ------------...|....|.....|............| +|----+----.----+---.|.--|.|.|# ------------...|....|.....F............| |........|.|......|.|...F...|# ........|.....+...|....|.....|............| |.P......-S|......|------.---# .........|.....|...|....-------............| |..........|......+.|...|.|.S# ..--S-----.....|LLL|.......................| From 1ece615eb29fa25edbf2f71d89ccf107c357a313 Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 30 Jun 2025 09:04:41 -0400 Subject: [PATCH 728/791] fixes3-7-0.txt catch-up; also replace some magic hex numbers --- doc/fixes3-7-0.txt | 3 +++ win/X11/winmap.c | 15 +++++++++------ 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index cc3076cb2..9b36d3c3e 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -2228,6 +2228,9 @@ X11: when trying to lookup scrollbars in order to handle scrolling via keys, X11: enable horizontal scrollbar for persistent inventory window X11: if a group accelerator matched a menu command ('^' in menu for '/') it wouldn't work to select, just to manipulate the menu +X11: ascii_map could try to use a color value, with some added flag bits set, + as an index into the color_gcs[] and inv_color_gcs[] arrays leading + to a segfault; clear the flag bits before using the color as an index X11+macOS: after the "bad Atom" fix (below), the persistent inventory window crept downward every time it got updated diff --git a/win/X11/winmap.c b/win/X11/winmap.c index cb86685ce..53a094c34 100644 --- a/win/X11/winmap.c +++ b/win/X11/winmap.c @@ -56,6 +56,9 @@ extern int total_tiles_used, Tile_corr; #define COL0_OFFSET 1 /* change to 0 to revert to displaying unused column 0 */ +#define NH_INVERSE_COLOR 0x40000000 +#define NH_ENHANCED_COLOR 0x80000000 + static X11_map_symbol glyph_char(const glyph_info *glyphinfo); static GC X11_make_gc(struct xwindow *wp, struct text_map_info_t *text_map, X11_color color, boolean inverted); @@ -170,9 +173,9 @@ X11_print_glyph( ? CLR_MAX : 0; color += colordif; if (nhcolor != 0) - color = nhcolor | 0x80000000; + color = nhcolor | NH_ENHANCED_COLOR; if (colordif != 0) - color |= 0x40000000; + color |= NH_INVERSE_COLOR; if (*co_ptr != color) { *co_ptr = color; @@ -1528,9 +1531,9 @@ X11_make_gc( GC ggc; #ifdef ENHANCED_SYMBOLS - if ((color & 0x80000000) != 0) { + if ((color & NH_ENHANCED_COLOR) != 0) { /* We need a new GC */ - if ((color & 0x40000000) != 0) { + if ((color & NH_INVERSE_COLOR) != 0) { cur_inv = !cur_inv; } if (iflags.use_color) { @@ -1540,7 +1543,7 @@ X11_make_gc( /* FIXME: Does this still work when the display does not support true color? */ - fgpixel = color & 0xFFFFFF; + fgpixel = COLORVAL(color); XtSetArg(arg[0], XtNbackground, &bgpixel); XtGetValues(wp->w, arg, 1); if (cur_inv) { @@ -1580,7 +1583,7 @@ X11_make_gc( static void X11_free_gc(struct xwindow *wp, GC ggc, X11_color color) { - if ((color & 0x80000000) != 0 && iflags.use_color) { + if ((color & NH_ENHANCED_COLOR) != 0 && iflags.use_color) { /* X11_make_gc allocated a new GC */ XtReleaseGC(wp->w, ggc); } From fed5be69434264cb4d820374e8eed5bbb0323e9c Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 30 Jun 2025 09:21:17 -0400 Subject: [PATCH 729/791] another follow-up bit for X11 --- win/X11/winmap.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/win/X11/winmap.c b/win/X11/winmap.c index 53a094c34..39b980b28 100644 --- a/win/X11/winmap.c +++ b/win/X11/winmap.c @@ -1564,14 +1564,16 @@ X11_make_gc( } else #endif { - if (color >= CLR_MAX) { - color -= CLR_MAX; + uint32 nhcolor = COLORVAL(color); /* strip flag bits */ + + if (nhcolor >= CLR_MAX) { + nhcolor -= CLR_MAX; cur_inv = !cur_inv; } ggc = (iflags.use_color ? (cur_inv - ? text_map->inv_color_gcs[COLORVAL(color)] - : text_map->color_gcs[COLORVAL(color)]) + ? text_map->inv_color_gcs[nhcolor] + : text_map->color_gcs[nhcolor]) : (cur_inv ? text_map->inv_copy_gc : text_map->copy_gc)); From 20b03ec0c593b8560f38197e7db8c447cea4f3a2 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Mon, 30 Jun 2025 17:59:38 +0300 Subject: [PATCH 730/791] Fix wrong key code in binding keys --- src/cmd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cmd.c b/src/cmd.c index 68a8b1304..3eb8a634e 100644 --- a/src/cmd.c +++ b/src/cmd.c @@ -2140,7 +2140,7 @@ handler_rebind_keys_add(boolean keyfirst) pline("Bind which key? "); key = pgetchar(); - if (!key || key == '\027') + if (!key || key == '\033') return; } @@ -2205,7 +2205,7 @@ handler_rebind_keys_add(boolean keyfirst) pline("Bind which key? "); key = pgetchar(); - if (!key || key == '\027') + if (!key || key == '\033') return; } From 751b296e3b504e6394746a1b2b502d6fff98141b Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Mon, 30 Jun 2025 18:00:08 +0300 Subject: [PATCH 731/791] Tutorial: boulders and a trapdoor --- dat/tut-1.lua | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/dat/tut-1.lua b/dat/tut-1.lua index 7f8dba5c5..548fcaa7d 100644 --- a/dat/tut-1.lua +++ b/dat/tut-1.lua @@ -45,9 +45,9 @@ des.map([[ |........|.|......|.|...F...|# ........|.....+...|....|.....|............| |.P......-S|......|------.---# .........|.....|...|....-------............| |..........|......+.|...|.|.S# ..--S-----.....|LLL|.......................| -|.W......---......|.|.|.|.|.|# ..|......|.....|LLL|.......................| -|....Z.L.S.F......|.|.|.|.---# |......+.....|...|.......................| -|........|--......|...|.....|####+......|.....|...+.......................| +|.W......---......|.|.|.|.|.|# ..|......|.....|LLL|...................|.--| +|....Z.L.S.F......|.|.|.|.---# |......+.....|...|...................|.|.| +|........|--......|...|.....|####+......|.....|...+...................|...| --------------------------------------------------------------------------- ]]); @@ -287,6 +287,15 @@ des.engraving({ coord = { 65,3 }, type = "burn", text = "UNDER CONSTRUCTION", de des.trap({ type = "magic portal", coord = { 66,2 }, seen = true }); +-- + +-- try to squeeze over boulders, find a trap door + +des.object({ id = "boulder", coord = {71,16} }); +des.object({ id = "boulder", coord = {72,16} }); +des.object({ id = "boulder", coord = {73,16} }); +des.trap({ type = "trap door", coord = { 73,15 } }); + ---------------- -- entering and leaving tutorial _branch_ now handled by core From 47e95a126e871932e7c762f5770550e6718fd8b1 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Tue, 1 Jul 2025 16:18:58 +0300 Subject: [PATCH 732/791] Tutorial: wrong secret door Some first time players have gotten stuck here. Give them a hint. --- dat/tut-1.lua | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dat/tut-1.lua b/dat/tut-1.lua index 548fcaa7d..6c8b088a8 100644 --- a/dat/tut-1.lua +++ b/dat/tut-1.lua @@ -109,6 +109,8 @@ des.engraving({ coord = { 5,12 }, type = "engrave", text = "Look around the map des.engraving({ coord = { 10,13 }, type = "engrave", text = "Use '" .. tut_key("search") .. "' to search for secret doors", degrade = false }); +des.engraving({ coord = { 10,15 }, type = "engrave", text = "Wrong secret", degrade = false }); + -- des.engraving({ coord = { 10,10 }, type = "engrave", text = "Behind this door is a dark corridor", degrade = false }); From 79bbd336750c9bab216087f83b549632cb868130 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Tue, 1 Jul 2025 21:04:41 +0300 Subject: [PATCH 733/791] Add a false rumor ... but is it false? --- dat/rumors.fal | 1 + 1 file changed, 1 insertion(+) diff --git a/dat/rumors.fal b/dat/rumors.fal index 721e13d8c..43895f568 100644 --- a/dat/rumors.fal +++ b/dat/rumors.fal @@ -28,6 +28,7 @@ All monsters are created evil, but some are more evil than others. Always attack a floating eye from behind! An elven cloak is always the height of fashion. Any small object that is accidentally dropped will hide under a larger object. +Archeologists are very squishy, often found under boulders. Archeologists find more bones piles. Austin Powers says: My Mojo is back! Yeah, baby! Balrogs do not appear above level 20. From 04e651ca346fd1749945422c129e778a3753a961 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Wed, 2 Jul 2025 17:24:15 +0300 Subject: [PATCH 734/791] Allow kelp in walls of water --- src/mklev.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/mklev.c b/src/mklev.c index a455639c6..8c75cc1df 100644 --- a/src/mklev.c +++ b/src/mklev.c @@ -26,6 +26,7 @@ staticfn void themerooms_post_level_generate(void); staticfn boolean chk_okdoor(coordxy, coordxy); staticfn void mklev_sanity_check(void); staticfn void makelevel(void); +staticfn boolean water_has_kelp(coordxy, coordxy, int, int); staticfn boolean bydoor(coordxy, coordxy); staticfn void mktrap_victim(struct trap *); staticfn int traptype_rnd(unsigned); @@ -1423,6 +1424,18 @@ makelevel(void) } } +/* return TRUE if water location at (x,y) should have kelp. */ +staticfn boolean +water_has_kelp(coordxy x, coordxy y, int kelp_pool, int kelp_moat) +{ + if ((kelp_pool && (levl[x][y].typ == POOL + || (levl[x][y].typ == WATER && !Is_waterlevel(&u.uz))) + && !rn2(kelp_pool)) + || (kelp_moat && levl[x][y].typ == MOAT && !rn2(kelp_moat))) + return TRUE; + return FALSE; +} + /* * Place deposits of minerals (gold and misc gems) in the stone * surrounding the rooms on the map. @@ -1448,8 +1461,7 @@ mineralize(int kelp_pool, int kelp_moat, int goldprob, int gemprob, return; for (x = 2; x < (COLNO - 2); x++) for (y = 1; y < (ROWNO - 1); y++) - if ((kelp_pool && levl[x][y].typ == POOL && !rn2(kelp_pool)) - || (kelp_moat && levl[x][y].typ == MOAT && !rn2(kelp_moat))) + if (water_has_kelp(x, y, kelp_pool, kelp_moat)) (void) mksobj_at(KELP_FROND, x, y, TRUE, FALSE); /* determine if it is even allowed; From 76de716d2d28a909c62bc6854285ba61abcfa340 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Thu, 3 Jul 2025 10:09:51 +0300 Subject: [PATCH 735/791] Tutorial: squeezing through small gaps --- dat/tut-1.lua | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/dat/tut-1.lua b/dat/tut-1.lua index 6c8b088a8..22ae97c16 100644 --- a/dat/tut-1.lua +++ b/dat/tut-1.lua @@ -43,11 +43,11 @@ des.map([[ |----.-| -+- # |.....---.|######+..|.......S...|....|.....|............| |----+----.----+---.|.--|.|.|# ------------...|....|.....F............| |........|.|......|.|...F...|# ........|.....+...|....|.....|............| -|.P......-S|......|------.---# .........|.....|...|....-------............| -|..........|......+.|...|.|.S# ..--S-----.....|LLL|.......................| -|.W......---......|.|.|.|.|.|# ..|......|.....|LLL|...................|.--| -|....Z.L.S.F......|.|.|.|.---# |......+.....|...|...................|.|.| -|........|--......|...|.....|####+......|.....|...+...................|...| +|.P......-S|......|------.---# .........|.....|...|....-------........----| +|..........|......+.|...|.|.S# ..--S-----.....|LLL|..................|..| | +|.W......---......|.|.|.|.|.|# ..|......|.....|LLL|..................|..--| +|....Z.L.S.F......|.|.|.|.---# |......+.....|...|..................|..|.| +|........|--......|...|.....|####+......|.....|...+..................||...| --------------------------------------------------------------------------- ]]); @@ -291,6 +291,10 @@ des.trap({ type = "magic portal", coord = { 66,2 }, seen = true }); -- +-- squeezing through small gaps + +des.engraving({ coord = { 69,12 }, type = "burn", text = "Can't get through? You're carrying too much.", degrade = false }); + -- try to squeeze over boulders, find a trap door des.object({ id = "boulder", coord = {71,16} }); From b8664198da17583c4204b6511c25f4c0cbe7abc0 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Thu, 3 Jul 2025 21:07:05 +0300 Subject: [PATCH 736/791] Alchemy smock reduces chances of dipped potions exploding --- doc/fixes3-7-0.txt | 1 + src/potion.c | 43 +++++++++++++++++++++++++++---------------- 2 files changed, 28 insertions(+), 16 deletions(-) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index 9b36d3c3e..9d5bc44a8 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -1517,6 +1517,7 @@ hitting with Ogresmasher gives a higher chance of knockback Snickersnee can hit at a distance once per turn for free the engraving pristine text field was not being appropriately populated during level creation +worn alchemy smock reduces chances of dipped potions exploding Fixes to 3.7.0-x General Problems Exposed Via git Repository diff --git a/src/potion.c b/src/potion.c index 3ff57c360..d537daf5c 100644 --- a/src/potion.c +++ b/src/potion.c @@ -42,6 +42,7 @@ staticfn int dip_hands_ok(struct obj *); staticfn void hold_potion(struct obj *, const char *, const char *, const char *); staticfn void poof(struct obj *); +staticfn boolean dip_potion_explosion(struct obj *, int); staticfn int potion_dip(struct obj *obj, struct obj *potion); /* used to indicate whether quaff or dip has skipped an opportunity to @@ -2393,6 +2394,31 @@ poof(struct obj *potion) useup(potion); } +/* do dipped potion(s) explode? */ +staticfn boolean +dip_potion_explosion(struct obj *obj, int dmg) +{ + if (obj->cursed || obj->otyp == POT_ACID + || (obj->otyp == POT_OIL && obj->lamplit) + || !rn2((uarmc && uarmc->otyp == ALCHEMY_SMOCK) ? 30 : 10)) { + /* it would be better to use up the whole stack in advance + of the message, but we can't because we need to keep it + around for potionbreathe() [and we can't set obj->in_use + to 'amt' because that's not implemented] */ + obj->in_use = 1; + pline("%sThey explode!", !Deaf ? "BOOM! " : ""); + wake_nearto(u.ux, u.uy, (BOLT_LIM + 1) * (BOLT_LIM + 1)); + exercise(A_STR, FALSE); + if (!breathless(gy.youmonst.data) || haseyes(gy.youmonst.data)) + potionbreathe(obj); + useupall(obj); + losehp(dmg, /* not physical damage */ + "alchemic blast", KILLED_BY_AN); + return TRUE; + } + return FALSE; +} + /* called by dodip() or dip_into() after obj and potion have been chosen */ staticfn int potion_dip(struct obj *obj, struct obj *potion) @@ -2494,23 +2520,8 @@ potion_dip(struct obj *obj, struct obj *potion) useup(potion); /* now gone */ /* Mixing potions is dangerous... KMH, balance patch -- acid is particularly unstable */ - if (obj->cursed || obj->otyp == POT_ACID - || (obj->otyp == POT_OIL && obj->lamplit) || !rn2(10)) { - /* it would be better to use up the whole stack in advance - of the message, but we can't because we need to keep it - around for potionbreathe() [and we can't set obj->in_use - to 'amt' because that's not implemented] */ - obj->in_use = 1; - pline("%sThey explode!", !Deaf ? "BOOM! " : ""); - wake_nearto(u.ux, u.uy, (BOLT_LIM + 1) * (BOLT_LIM + 1)); - exercise(A_STR, FALSE); - if (!breathless(gy.youmonst.data) || haseyes(gy.youmonst.data)) - potionbreathe(obj); - useupall(obj); - losehp(amt + rnd(9), /* not physical damage */ - "alchemic blast", KILLED_BY_AN); + if (dip_potion_explosion(obj, amt + rnd(9))) return ECMD_TIME; - } obj->blessed = obj->cursed = obj->bknown = 0; if (Blind || Hallucination) From a0d9c94ece09e048d77625ae5d497fb2b0f4f5a5 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Fri, 4 Jul 2025 17:04:37 +0300 Subject: [PATCH 737/791] Dwarves can sense buried items under their feet --- doc/fixes3-7-0.txt | 1 + src/dungeon.c | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index 9d5bc44a8..e90d275e2 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -1518,6 +1518,7 @@ Snickersnee can hit at a distance once per turn for free the engraving pristine text field was not being appropriately populated during level creation worn alchemy smock reduces chances of dipped potions exploding +dwarves can sense buried items under their feet Fixes to 3.7.0-x General Problems Exposed Via git Repository diff --git a/src/dungeon.c b/src/dungeon.c index c3d9b8e43..5b172b815 100644 --- a/src/dungeon.c +++ b/src/dungeon.c @@ -60,6 +60,7 @@ staticfn void init_dungeon_set_depth(struct proto_dungeon *, int); staticfn void init_castle_tune(void); staticfn void fixup_level_locations(void); staticfn void free_proto_dungeon(struct proto_dungeon *); +staticfn void earth_sense(void); staticfn boolean init_dungeon_dungeons(lua_State *, struct proto_dungeon *, int); staticfn boolean unplaced_floater(struct dungeon *); @@ -1541,6 +1542,28 @@ prev_level(boolean at_stairs) } } +/* Dwarves have "earth sense", + able to sense if something is buried under their feet */ +staticfn void +earth_sense(void) +{ + struct obj *otmp; + + if (!Race_if(PM_DWARF)) + return; + if (u.usteed || Flying || Levitation || Upolyd) + return; + if (levl[u.ux][u.uy].typ != CORR + && levl[u.ux][u.uy].typ != ROOM) + return; + + for (otmp = svl.level.buriedobjlist; otmp; otmp = otmp->nobj) + if (u_at(otmp->ox, otmp->oy)) { + You("sense something below your %s.", makeplural(body_part(FOOT))); + return; + } +} + void u_on_newpos(coordxy x, coordxy y) { @@ -1568,6 +1591,7 @@ u_on_newpos(coordxy x, coordxy y) /* still on same level; might have come close enough to generic object(s) to redisplay them as specific objects */ see_nearby_objects(); + earth_sense(); } /* place you on a random location when arriving on a level */ From e2b80cd886cf9f2bda9bb25d131c8033d51dbbd0 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Fri, 4 Jul 2025 17:39:08 +0300 Subject: [PATCH 738/791] Monsters trapped in pits cannot kick --- doc/fixes3-7-0.txt | 1 + include/extern.h | 1 + src/mhitm.c | 2 ++ src/mhitu.c | 18 ++++++++++++++++++ src/uhitm.c | 3 +++ 5 files changed, 25 insertions(+) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index e90d275e2..56d72fe80 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -1519,6 +1519,7 @@ the engraving pristine text field was not being appropriately populated during level creation worn alchemy smock reduces chances of dipped potions exploding dwarves can sense buried items under their feet +monsters trapped in pits cannot kick Fixes to 3.7.0-x General Problems Exposed Via git Repository diff --git a/include/extern.h b/include/extern.h index e3375627f..7df8e2530 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1507,6 +1507,7 @@ extern struct monst *cloneu(void); extern void expels(struct monst *, struct permonst *, boolean) NONNULLARG12; extern struct attack *getmattk(struct monst *, struct monst *, int, int *, struct attack *) NONNULLARG12; +extern boolean mtrapped_in_pit(struct monst *) NONNULLARG1; extern int mattacku(struct monst *) NONNULLARG1; boolean diseasemu(struct permonst *) NONNULLARG1; boolean u_slip_free(struct monst *, struct attack *) NONNULLARG12; diff --git a/src/mhitm.c b/src/mhitm.c index 39fe251a7..078b7596c 100644 --- a/src/mhitm.c +++ b/src/mhitm.c @@ -423,6 +423,8 @@ mattackm( case AT_TUCH: case AT_BUTT: case AT_TENT: + if (mattk->aatyp == AT_KICK && mtrapped_in_pit(magr)) + continue; /* Nymph that teleported away on first attack? */ if (distmin(magr->mx, magr->my, mdef->mx, mdef->my) > 1) /* Continue because the monster may have a ranged attack. */ diff --git a/src/mhitu.c b/src/mhitu.c index 0357915e8..ff32445e8 100644 --- a/src/mhitu.c +++ b/src/mhitu.c @@ -453,6 +453,22 @@ calc_mattacku_vars( gn.notonhead = FALSE; } +/* return TRUE iff monster or hero is trapped in a (spiked) pit */ +boolean +mtrapped_in_pit(struct monst *mtmp) +{ + struct trap *ttmp = 0; + + if (mtmp == &gy.youmonst) + ttmp = (u.utrap && u.utraptype == TT_PIT) ? t_at(u.ux, u.uy) : 0; + else + ttmp = mtmp->mtrapped ? t_at(mtmp->mx, mtmp->my) : 0; + + if (ttmp && is_pit(ttmp->ttyp)) + return TRUE; + return FALSE; +} + /* * mattacku: monster attacks you * returns 1 if monster dies (e.g. "yellow light"), 0 otherwise @@ -773,6 +789,8 @@ mattacku(struct monst *mtmp) case AT_TUCH: case AT_BUTT: case AT_TENT: + if (mattk->aatyp == AT_KICK && mtrapped_in_pit(mtmp)) + continue; if (!range2 && (!MON_WEP(mtmp) || mtmp->mconf || Conflict || !touch_petrifies(gy.youmonst.data))) { if (foundyou) { diff --git a/src/uhitm.c b/src/uhitm.c index 90014bcd6..d43fe53be 100644 --- a/src/uhitm.c +++ b/src/uhitm.c @@ -5498,6 +5498,9 @@ hmonas(struct monst *mon) FALLTHROUGH; /*FALLTHRU*/ case AT_KICK: + if (mattk->aatyp == AT_KICK && mtrapped_in_pit(&gy.youmonst)) + continue; + /*FALLTHRU*/ case AT_BITE: case AT_STNG: case AT_BUTT: From 0da45c1e7420e886ba8bf8ddd107262f11af0961 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sat, 5 Jul 2025 19:59:23 +0300 Subject: [PATCH 739/791] Fix Snickersnee attack Adding the extra attack to Snickersnee made the weapon always attack from range, even when it was used in melee. --- src/uhitm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/uhitm.c b/src/uhitm.c index d43fe53be..65b311e4c 100644 --- a/src/uhitm.c +++ b/src/uhitm.c @@ -1055,7 +1055,8 @@ hmon_hitmon_weapon( /* or strike with a missile in your hand... */ || (!hmd->thrown && (is_missile(obj) || is_ammo(obj))) /* or use a pole at short range and not mounted... */ - || (!hmd->thrown && !u.usteed && is_pole(obj)) + || (!hmd->thrown && !u.usteed && is_pole(obj) + && !is_art(obj,ART_SNICKERSNEE)) /* or throw a missile without the proper bow... */ || (is_ammo(obj) && (hmd->thrown != HMON_THROWN || !ammo_and_launcher(obj, uwep)))) { From 079dca27f296086eac9676c2cf39262af370ba66 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Mon, 7 Jul 2025 13:08:07 +0300 Subject: [PATCH 740/791] Tutorial: clear user-given obj type names --- src/nhlua.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/nhlua.c b/src/nhlua.c index 3ed150392..11cc8d537 100644 --- a/src/nhlua.c +++ b/src/nhlua.c @@ -1652,6 +1652,7 @@ nhl_gamestate(lua_State *L) struct obj *otmp; int argc = lua_gettop(L); boolean reststate = (argc > 0) ? lua_toboolean(L, -1) : FALSE; + int otyp; debugpline4("gamestate: %d:%d (%c vs %c)", u.uz.dnum, u.uz.dlevel, reststate ? 'T' : 'F', gg.gmst_stored ? 't' : 'f'); @@ -1683,6 +1684,12 @@ nhl_gamestate(lua_State *L) assert(gg.gmst_mvitals != NULL); (void) memcpy((genericptr_t) &svm.mvitals, gg.gmst_mvitals, sizeof svm.mvitals); + /* clear user-given object type names */ + for (otyp = 0; otyp < NUM_OBJECTS; otyp++) + if (objects[otyp].oc_uname) { + free(objects[otyp].oc_uname); + objects[otyp].oc_uname = (char *) 0; + } /* some restored state would confuse the level change in progress */ u.uz = cur_uz, u.uz0 = cur_uz0; init_uhunger(); From da132e3bb09f7970fa3900e351bd5a2d2b87c712 Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 7 Jul 2025 10:00:25 -0400 Subject: [PATCH 741/791] Revert "remove extraneous script file (Windows)" This reverts commit 33652b82880abc1bd96059993b93fc71e4f54eb5. --- sys/windows/fetch.sh | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 sys/windows/fetch.sh diff --git a/sys/windows/fetch.sh b/sys/windows/fetch.sh new file mode 100644 index 000000000..4d9b36202 --- /dev/null +++ b/sys/windows/fetch.sh @@ -0,0 +1,36 @@ +#!/bin/sh + +if [ ! -d lib ]; then +mkdir -p lib +fi + +if [ $1 == "lua" ]; then + if [ -z "$LUA_VERSION" ]; then + export LUA_VERSION=5.4.6 + export LUASRC=../lib/lua + fi + + export CURLLUASRC=http://www.lua.org/ftp/lua-5.4.6.tar.gz + export CURLLUADST=lua-5.4.6.tar.gz + + if [ ! -f lib/lua.h ] ;then + cd lib + curl -L $CURLLUASRC -o $CURLLUADST + /c/Windows/System32/tar -xvf $CURLLUADST + cd .. + fi +fi + +if [ $1 == "pdcursesmod" ]; then + export CURLPDCSRC=https://github.com/Bill-Gray/PDCursesMod/archive/refs/tags/v4.4.0.zip + export CURLPDCDST=pdcursesmod.zip + + if [ ! -f lib/pdcursesmod/curses.h ] ; then + cd lib + curl -L $CURLPDCSRC -o $CURLPDCDST + /c/Windows/System32/tar -xvf $CURLPDCDST + mkdir -p pdcursesmod + /c/Windows/System32/tar -C pdcursesmod --strip-components=1 -xvf $CURLPDCDST + cd .. + fi +fi From ce8c4c3ca2ec0f02003c0140a0633c7efe62d4cd Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 7 Jul 2025 10:07:02 -0400 Subject: [PATCH 742/791] fix reported missing closing '%' in fetch.cmd Reported directly to devteam by email in K4336 (thank you). --- sys/windows/fetch.cmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/windows/fetch.cmd b/sys/windows/fetch.cmd index 7399ed31c..c484f9b13 100644 --- a/sys/windows/fetch.cmd +++ b/sys/windows/fetch.cmd @@ -5,7 +5,7 @@ if [%1] == [lua] ( set LUA_VERSION=5.4.6 set LUASRC=../lib/lua set CURLLUASRC=http://www.lua.org/ftp/lua-%LUA_VERSION%.tar.gz - set CURLLUADST=lua-%LUA_VERSION.tar.gz + set CURLLUADST=lua-%LUA_VERSION%.tar.gz if NOT exist lib/lua.h ( cd lib curl -L %CURLLUASRC% -o %CURLLUADST% From 69cf9ad689a17daab8238c52859d45b255e9cef9 Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 7 Jul 2025 10:32:47 -0400 Subject: [PATCH 743/791] aim for successful build even without using hints file --- sys/unix/Makefile.src | 2 ++ sys/unix/Makefile.utl | 2 ++ 2 files changed, 4 insertions(+) diff --git a/sys/unix/Makefile.src b/sys/unix/Makefile.src index 623d19c12..fac0403f7 100644 --- a/sys/unix/Makefile.src +++ b/sys/unix/Makefile.src @@ -188,6 +188,8 @@ SYSOBJ = $(TARGETPFX)ioctl.o $(TARGETPFX)unixmain.o $(TARGETPFX)unixtty.o \ #CFLAGS = -O -I../include #LFLAGS = +CFLAGS ?= -I../include + AR = ar ARFLAGS = rcs diff --git a/sys/unix/Makefile.utl b/sys/unix/Makefile.utl index 6e8aa0c71..9ae37bdec 100644 --- a/sys/unix/Makefile.utl +++ b/sys/unix/Makefile.utl @@ -106,6 +106,8 @@ NHSROOT=.. #CFLAGS = -O -I../include #LFLAGS = +CFLAGS ?= -I../include + # -lm required by lua LFLAGS += -lm From adef0707f742a0b684d153bb1d6b3b1f4aace0d4 Mon Sep 17 00:00:00 2001 From: nhw_cron Date: Mon, 7 Jul 2025 10:24:06 -0400 Subject: [PATCH 744/791] This is cron-daily v1-Apr-1-2024. 000files updated: Files --- Files | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Files b/Files index 07b39a821..786f0c06d 100644 --- a/Files +++ b/Files @@ -433,11 +433,11 @@ sys/windows: 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 +fetch.cmd fetch.sh 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) From b4f2ef853a566cb206da8c4f4700324bf84e8a51 Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 7 Jul 2025 12:43:27 -0400 Subject: [PATCH 745/791] add more fallback values to allow basic build to proceed --- sys/unix/Makefile.src | 6 ++++++ sys/unix/Makefile.utl | 1 + 2 files changed, 7 insertions(+) diff --git a/sys/unix/Makefile.src b/sys/unix/Makefile.src index fac0403f7..eaf5b1d47 100644 --- a/sys/unix/Makefile.src +++ b/sys/unix/Makefile.src @@ -188,7 +188,9 @@ SYSOBJ = $(TARGETPFX)ioctl.o $(TARGETPFX)unixmain.o $(TARGETPFX)unixtty.o \ #CFLAGS = -O -I../include #LFLAGS = +#fallback values, only if these are not already set CFLAGS ?= -I../include +LINK ?= $(CC) AR = ar ARFLAGS = rcs @@ -408,6 +410,10 @@ WINCURSESLIB = -lncurses # # LIBS = +#fallback values, only if these are not already set +WINOBJ ?= $(WINTTYOBJ) +WINLIB ?= $(WINTTYLIB) -lncurses + # make NetHack GAME = nethack # GAME = nethack.prg diff --git a/sys/unix/Makefile.utl b/sys/unix/Makefile.utl index 9ae37bdec..4df167f43 100644 --- a/sys/unix/Makefile.utl +++ b/sys/unix/Makefile.utl @@ -106,6 +106,7 @@ NHSROOT=.. #CFLAGS = -O -I../include #LFLAGS = +#fallback defaults if not set CFLAGS ?= -I../include # -lm required by lua From 3440193a5a835b0cd695e3ee2bea31c240ba1028 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Wed, 9 Jul 2025 18:30:54 +0300 Subject: [PATCH 746/791] Tutorial: spellcasting Add some basic spellcasting stuff to the tutorial: read a spellbook, cast a spell. If the hero doesn't have enough energy, just adds a note saying so. Remove/restore the known spells when entering/leaving the tutorial. --- dat/tut-1.lua | 21 ++++++++++++++++++--- include/decl.h | 1 + src/decl.c | 1 + src/nhlua.c | 3 +++ 4 files changed, 23 insertions(+), 3 deletions(-) diff --git a/dat/tut-1.lua b/dat/tut-1.lua index 22ae97c16..246dedefd 100644 --- a/dat/tut-1.lua +++ b/dat/tut-1.lua @@ -32,10 +32,10 @@ des.level_flags("mazelevel", "noflip", des.map([[ --------------------------------------------------------------------------- -|-.--|.......|......|..S....|.F.......|.............|.....................| +|-.--|.......|......|..S....|.F.......|.............|.......|.............| |.-..........|......|--|....|.F.....|.|S-------.....|.....................| -||.--|.......|..T......|....|.F.....|.|.......|.....|.....................| -||.|.|.......|......|-.|....|.F.....|.|.......|.....|.....................| +||.--|.......|..T......|....|.F.....|.|.......|.....|.......|.............| +||.|.|.......|......|-.|....|.F.....|.|.......|.....|--------.............| ||.|.|.......|......||.|-.-----------.-.......|-S----.....................| |-+-S---------..---.||........................|...|.......................| |......| |.-------------------.......|...|....--S----............| @@ -302,6 +302,21 @@ des.object({ id = "boulder", coord = {72,16} }); des.object({ id = "boulder", coord = {73,16} }); des.trap({ type = "trap door", coord = { 73,15 } }); +-- + +des.engraving({ coord = { 60,2 }, type = "engrave", text = "Spellcasting", degrade = false }); +if (u.uenmax < 5) then + -- TODO: make sure hero has enough Pw to cast the spell (5 pw) instead? + -- TODO: ensure the first cast of this spell succeeds? + des.engraving({ coord = { 59,2 }, type = "engrave", text = "Unfortunately you don't have enough energy to cast spells.", degrade = false }); +end +des.engraving({ coord = { 57,2 }, type = "engrave", text = "Pick up the spellbook with '" .. tut_key("pickup") .. "'", degrade = false }); +des.object({ coord = { 57,2 }, id = "spellbook of light", buc = "blessed" }); +des.engraving({ coord = { 55,2 }, type = "engrave", text = "Read the spellbook with '" .. tut_key("read") .. "'", degrade = false }); +des.engraving({ coord = { 53,2 }, type = "engrave", text = "Use '" .. tut_key("cast") .. "' to cast a spell", degrade = false }); +des.region(selection.area(53,01, 59, 3), "unlit"); + + ---------------- -- entering and leaving tutorial _branch_ now handled by core diff --git a/include/decl.h b/include/decl.h index 54cf2f390..d5186158b 100644 --- a/include/decl.h +++ b/include/decl.h @@ -423,6 +423,7 @@ struct instance_globals_g { long gmst_moves; struct obj *gmst_invent; genericptr_t *gmst_ubak, *gmst_disco, *gmst_mvitals; + struct spell gmst_spl_book[MAXSPELL + 1]; /* pline.c */ struct gamelog_line *gamelog; diff --git a/src/decl.c b/src/decl.c index 3430cd3a5..7d0a47cb4 100644 --- a/src/decl.c +++ b/src/decl.c @@ -372,6 +372,7 @@ static const struct instance_globals_g g_init_g = { 0L, /* gmst_moves */ NULL, /* gmst_invent */ NULL, NULL, NULL, /* gmst_ubak, gmst_disco, gmst_mvitals */ + { DUMMY }, /* gmst_spl_book */ /* pline.c */ UNDEFINED_PTR, /* gamelog */ /* region.c */ diff --git a/src/nhlua.c b/src/nhlua.c index 11cc8d537..b43e4c089 100644 --- a/src/nhlua.c +++ b/src/nhlua.c @@ -1695,6 +1695,7 @@ nhl_gamestate(lua_State *L) init_uhunger(); free_tutorial(); /* release gg.gmst_XYZ */ gg.gmst_stored = FALSE; + (void) memcpy(svs.spl_book, gg.gmst_spl_book, sizeof svs.spl_book); } else if (!reststate && !gg.gmst_stored) { /* store game state */ gg.gmst_moves = svm.moves; @@ -1715,6 +1716,8 @@ nhl_gamestate(lua_State *L) gg.gmst_mvitals = (genericptr_t) alloc(sizeof svm.mvitals); (void) memcpy(gg.gmst_mvitals, (genericptr_t) &svm.mvitals, sizeof svm.mvitals); + (void) memcpy(gg.gmst_spl_book, svs.spl_book, sizeof svs.spl_book); + (void) memset(svs.spl_book, 0, sizeof(svs.spl_book)); gg.gmst_stored = TRUE; } else { impossible("nhl_gamestate: inconsistent state (%s vs %s)", From 44b9ffe245036f80534bb0c2180bddc8be0bf5b4 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Thu, 10 Jul 2025 11:01:30 +0300 Subject: [PATCH 747/791] Tutorial: tip containers --- dat/tut-1.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dat/tut-1.lua b/dat/tut-1.lua index 246dedefd..511090b79 100644 --- a/dat/tut-1.lua +++ b/dat/tut-1.lua @@ -222,10 +222,11 @@ 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, trapped = false, +des.object({ coord = { 41,6 }, id = "large box", broken = true, trapped = false, contents = function(obj) des.object({ id = "secret door detection", class = "/", spe = 30 }); end }); +des.engraving({ coord = { 42,6 }, type = "engrave", text = "Containers can also be emptied with '" .. tut_key("tip") .. "'", degrade = false }); des.engraving({ coord = { 45,6 }, type = "engrave", text = "Magic wands are used with '" .. tut_key("zap") .. "'", degrade = false }); From 06ab2ce604cf492f8d650ca2a4d317c0a82c5bc5 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Thu, 10 Jul 2025 11:07:45 +0300 Subject: [PATCH 748/791] Tutorial: Knight jumping --- dat/tut-1.lua | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dat/tut-1.lua b/dat/tut-1.lua index 511090b79..f57f9119e 100644 --- a/dat/tut-1.lua +++ b/dat/tut-1.lua @@ -80,6 +80,10 @@ local diagmovekeys = tut_key("movesouthwest") .. " " .. 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 }); +if (u.role == "Knight") then + des.engraving({ coord = { 12,1 }, type = "engrave", text = "Knights can jump with '" .. tut_key("jump") .. "'", degrade = false }); +end + -- des.engraving({ coord = { 2,4 }, type = "engrave", text = "Some actions may require multiple tries before succeeding", degrade = false }); From 588dc6b73f71c3e4abd5083480db046c8ec5c63a Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Thu, 10 Jul 2025 13:40:04 +0300 Subject: [PATCH 749/791] Tutorial: quaffing potions --- dat/tut-1.lua | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/dat/tut-1.lua b/dat/tut-1.lua index f57f9119e..8640f3ad5 100644 --- a/dat/tut-1.lua +++ b/dat/tut-1.lua @@ -321,6 +321,11 @@ des.engraving({ coord = { 55,2 }, type = "engrave", text = "Read the spellbook w des.engraving({ coord = { 53,2 }, type = "engrave", text = "Use '" .. tut_key("cast") .. "' to cast a spell", degrade = false }); des.region(selection.area(53,01, 59, 3), "unlit"); +-- + +des.engraving({ coord = { 72,2 }, type = "engrave", text = "You \"quaff\" potions with '" .. tut_key("quaff") .. "'", degrade = false }); +des.object({ coord = { 72,2 }, id = "potion of object detection", buc = "blessed" }); + ---------------- From e5bd185ab5abac9dd3c9f7f2f43f20646612aa07 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Thu, 10 Jul 2025 13:48:16 +0300 Subject: [PATCH 750/791] Tutorial: untrapping traps --- dat/tut-1.lua | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dat/tut-1.lua b/dat/tut-1.lua index 8640f3ad5..b30e4edb2 100644 --- a/dat/tut-1.lua +++ b/dat/tut-1.lua @@ -133,6 +133,9 @@ for i = 1, 4 do coord = locs[i], victim = false }); end +des.engraving({ coord = { 15,15 }, type = "engrave", text = "Some traps can be disabled with '" .. tut_key("untrap") .. "'", degrade = false }); +des.trap({ coord = { 15,16 }, type = "web", spider_on_web = false }); + -- des.door({ coord = { 18,13 }, state = "closed" }); From 6c22e7af454c6c192f9f45bc4125336e87a7ec9b Mon Sep 17 00:00:00 2001 From: nhmall Date: Thu, 10 Jul 2025 22:44:56 -0400 Subject: [PATCH 751/791] attempt to ensure the correct curses.h is used on Linux OpenSUSE Tumbleweed ncurses 6.5 requires the one in /usr/include/ncursesw/curses.h, if ncursesw is being used. Otherwise, several needed function prototypes are not there. Fixes #1427 --- sys/unix/hints/linux.370 | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/sys/unix/hints/linux.370 b/sys/unix/hints/linux.370 index 2c4e460e8..3ce7d47d4 100755 --- a/sys/unix/hints/linux.370 +++ b/sys/unix/hints/linux.370 @@ -104,6 +104,7 @@ CURSESLIB = -lncurses -ltinfo ifdef MAKEFILE_SRC comma:=, NCURSES_LFLAGS = $(shell pkg-config ncursesw --libs) +NCURSES_CFLAGS = $(shell pkg-config ncursesw --cflags) ifeq (,$(findstring ncursesw, $(NCURSES_LFLAGS))) ifeq (,$(findstring ncurses, $(NCURSES_LFLAGS))) #this indicates that pkg-config itself was unavailable @@ -125,8 +126,33 @@ CURSESLIB = $(subst -Wl$(comma)-Bsymbolic-functions,,$(NCURSES_LFLAGS)) else CURSESLIB = $(NCURSES_LFLAGS) endif -#$(info $(CURSESLIB)) endif #HAVE_NCURSESW +#$(info $(CURSESLIB)) +ifeq (,$(findstring ncursesw, $(NCURSES_LFLAGS))) +ifeq (,$(findstring ncurses, $(NCURSES_LFLAGS))) +#this indicates that pkg-config itself was unavailable +NOPKGCONFIG = 1 +endif #ncurses not in NCURSES_LFLAGS? +endif #ncursesw not in NCURSES_LFLAGS? +# +ifeq "$(NOPKGCONFIG)" "1" +NCURSES_CFLAGS = -D_DEFAULT_SOURCE -D_XOPEN_SOURCE=600 +ifeq "$(HAVE_NCURSESW)" "1" +ifeq (,$(wildcard /usr/include/ncursesw/curses.h)) +NCURSES_CFLAGS += -I/usr/include +else +NCURSES_CFLAGS += -I/usr/include/ncursesw +endif +NCURSES_LFLAGS = -lncursesw -ltinfo +else #HAVE_NCURSESW +ifeq (,$(wildcard /usr/include/ncurses/curses.h)) +NCURSES_CFLAGS += -I/usr/include +else +NCURSES_CFLAGS += -I/usr/include/ncurses +endif +NCURSES_LFLAGS = -lncurses -ltinfo +endif #HAVE_NCURSESW +endif #NOPKGCONFIG endif #MAKEFILE_SRC endif #USE_CURSESLIB @@ -152,6 +178,7 @@ NHCFLAGS+=-DCOMPRESS=\"/bin/gzip\" -DCOMPRESS_EXTENSION=\".gz\" #NHCFLAGS+=-DCHANGE_COLOR NHCFLAGS+=-DSELF_RECOVER ifdef WANT_WIN_CURSES +NHCFLAGS+=$(NCURSES_CFLAGS) ifeq "$(HAVE_NCURSESW)" "1" NHCFLAGS+=-DCURSES_UNICODE else From 8570421449c612bc28bf68cfc2286464c850460b Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Fri, 11 Jul 2025 13:04:25 +0300 Subject: [PATCH 752/791] Create familiar spell can create harder creatures --- doc/fixes3-7-0.txt | 1 + src/dog.c | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index 56d72fe80..8bb097002 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -1520,6 +1520,7 @@ the engraving pristine text field was not being appropriately populated during worn alchemy smock reduces chances of dipped potions exploding dwarves can sense buried items under their feet monsters trapped in pits cannot kick +create familiar spell can create harder creatures Fixes to 3.7.0-x General Problems Exposed Via git Repository diff --git a/src/dog.c b/src/dog.c index d0d4e7f3c..0682cf610 100644 --- a/src/dog.c +++ b/src/dog.c @@ -124,7 +124,10 @@ pick_familiar_pm(struct obj *otmp, boolean quietly) } else if (!rn2(3)) { pm = &mons[pet_type()]; } else { - pm = rndmonst(); + int skill = spell_skilltype(SPE_CREATE_FAMILIAR); + int max = 3 * P_SKILL(skill); + + pm = rndmonst_adj(0, max); if (!pm && !quietly) There("seems to be nothing available for a familiar."); } From 03415bc595018ed107fc4eab9206115dfb016e01 Mon Sep 17 00:00:00 2001 From: nhkeni Date: Fri, 11 Jul 2025 15:44:23 -0400 Subject: [PATCH 753/791] fix typo --- sys/unix/README-hints | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/unix/README-hints b/sys/unix/README-hints index e564aafab..9c5f06934 100644 --- a/sys/unix/README-hints +++ b/sys/unix/README-hints @@ -26,7 +26,7 @@ cases to include support for multiple features. Some of the options require prerequisite packages to be available on your build machine. make WANT_WIN_TTY=1 Include support for the TTY interface (default). -make NANT_WIN_CURSES=1 Include support for the curses interface. +make WANT_WIN_CURSES=1 Include support for the curses interface. make WANT_WIN_X11=1 Include support for the X11 interface. make WANT_WIN_Qt=1 Include support for Qt interface, defaults to Qt5. make WANT_WIN_QT5=1 Include support for Qt5 interface. From e240efa10b63662509034901bfb02e973b3a22d0 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sat, 12 Jul 2025 18:21:09 +0300 Subject: [PATCH 754/791] Restoring a game can return to the wishing prompt In TTY or curses, if the terminal goes away while you're in the wishing prompt, return to the prompt when the game is restored. Breaks saves. --- doc/fixes3-7-0.txt | 2 ++ include/context.h | 1 + include/flag.h | 1 + include/patchlevel.h | 2 +- src/allmain.c | 3 +++ src/zap.c | 7 +++++++ win/curses/cursdial.c | 4 ++++ win/curses/cursmesg.c | 3 +++ win/curses/cursmisc.c | 1 + win/tty/getline.c | 2 ++ win/tty/wintty.c | 4 +++- 11 files changed, 28 insertions(+), 2 deletions(-) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index 8bb097002..5bd8ab8ca 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -2453,6 +2453,8 @@ tty: hide cursor unless waiting for user input; now extended to include tty platforms that define NO_TERMS, rather than just on those using termcap/terminfo, namely Windows console and msdos (text-mode implemented; vga and vesa just have stubs currently) +tty+curses: if terminal goes away while in the wishing prompt, return to the + wish prompt when game is restored Unix: when user name is used as default character name, keep hyphenated value intact instead stripping off dash and whatever follows as if that specified role/race/&c (worked once upon a time; broken since 3.3.0) diff --git a/include/context.h b/include/context.h index d98ada70e..73fee29bc 100644 --- a/include/context.h +++ b/include/context.h @@ -161,6 +161,7 @@ struct context_info { boolean mv; boolean bypasses; /* bypass flag is set on at least one fobj */ boolean door_opened; /* set to true if door was opened during test_move */ + boolean resume_wish; /* game was exited while in wish prompt */ boolean tips[NUM_TIPS]; struct dig_info digging; struct victual_info victual; diff --git a/include/flag.h b/include/flag.h index d586f3c5f..bd6a5dc58 100644 --- a/include/flag.h +++ b/include/flag.h @@ -246,6 +246,7 @@ struct instance_flags { boolean invis_goldsym; /* gold symbol is ' '? */ boolean in_lua; /* executing a lua script */ boolean lua_testing; /* doing lua tests */ + boolean term_gone; /* terminal is gone, abort abort abort */ boolean nofollowers; /* level change ignores pets (for tutorial) */ boolean partly_eaten_hack; /* extra flag for xname() used when it's called * indirectly so we can't use xname_flags() */ diff --git a/include/patchlevel.h b/include/patchlevel.h index 4992b7f3a..1de0380b0 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 127 +#define EDITLEVEL 128 /* * Development status possibilities. diff --git a/src/allmain.c b/src/allmain.c index d80e50a78..a1fad95c9 100644 --- a/src/allmain.c +++ b/src/allmain.c @@ -187,6 +187,9 @@ moveloop_core(void) if (iflags.sanity_check || iflags.debug_fuzzer) sanity_check(); + if (svc.context.resume_wish) + makewish(); /* clears resume_wish */ + if (svc.context.move) { /* actual time passed */ u.umovement -= NORMAL_SPEED; diff --git a/src/zap.c b/src/zap.c index 67eac9bbe..efd60f1fe 100644 --- a/src/zap.c +++ b/src/zap.c @@ -6186,6 +6186,7 @@ makewish(void) int tries = 0; long oldwisharti = u.uconduct.wisharti; + svc.context.resume_wish = 0; promptbuf[0] = '\0'; nothing = cg.zeroobj; /* lint suppression; only its address matters */ if (flags.verbose) @@ -6196,6 +6197,12 @@ makewish(void) Strcat(promptbuf, " (enter 'help' for assistance)"); Strcat(promptbuf, "?"); getlin(promptbuf, buf); + + if (iflags.term_gone) { + svc.context.resume_wish = 1; + return; + } + (void) mungspaces(buf); if (buf[0] == '\033') { buf[0] = '\0'; diff --git a/win/curses/cursdial.c b/win/curses/cursdial.c index 85803a5a8..b6a51eb2a 100644 --- a/win/curses/cursdial.c +++ b/win/curses/cursdial.c @@ -308,6 +308,7 @@ curses_character_input_dialog( answer = curses_read_char(); #endif if (answer == ERR) { + iflags.term_gone = 1; answer = def; break; } @@ -451,6 +452,8 @@ curses_ext_cmd(void) curs_set(0); prompt_width = (int) strlen(cur_choice); + if (letter == ERR) + iflags.term_gone = 1; if (letter == '\033' || letter == ERR) { ret = -1; break; @@ -1518,6 +1521,7 @@ menu_get_selections(WINDOW *win, nhmenu *menu, int how) curletter = curses_getch(); if (curletter == ERR) { + iflags.term_gone = 1; num_selected = -1; dismiss = TRUE; } diff --git a/win/curses/cursmesg.c b/win/curses/cursmesg.c index 9608c1158..adc039f52 100644 --- a/win/curses/cursmesg.c +++ b/win/curses/cursmesg.c @@ -348,6 +348,8 @@ curses_block( ret = '\n'; else ret = curses_read_char(); + if (ret == ERR) + iflags.term_gone = 1; if (ret == ERR || ret == '\0') ret = '\n'; /* msgtype=stop should require space/enter rather than any key, @@ -775,6 +777,7 @@ curses_message_win_getline(const char *prompt, char *answer, int buffer) switch (ch) { case ERR: /* should not happen */ + iflags.term_gone = 1; *answer = '\0'; goto alldone; case '\033': /* DOESCAPE */ diff --git a/win/curses/cursmisc.c b/win/curses/cursmisc.c index ce02ca435..4b4fe97c1 100644 --- a/win/curses/cursmisc.c +++ b/win/curses/cursmisc.c @@ -1026,6 +1026,7 @@ parse_escape_sequence(int key, boolean *keypadnum) ret = getch(); if (ret == ERR) { + iflags.term_gone = 1; /* there was no additional char; treat as M-O or M-^O below */ ret = (key == '\033') ? 'O' : C('O'); } else if (ret >= 112 && ret <= 121) { /* 'p'..'y' */ diff --git a/win/tty/getline.c b/win/tty/getline.c index 1a8215c06..acb3f7f14 100644 --- a/win/tty/getline.c +++ b/win/tty/getline.c @@ -83,6 +83,8 @@ hooked_tty_getlin( c = pgetchar(); term_curs_set(0); if (c == '\033' || c == EOF) { + if (c == EOF) + iflags.term_gone = 1; if (c == '\033' && obufp[0] != '\0') { obufp[0] = '\0'; bufp = obufp; diff --git a/win/tty/wintty.c b/win/tty/wintty.c index 4c7a107dc..61338542b 100644 --- a/win/tty/wintty.c +++ b/win/tty/wintty.c @@ -4090,8 +4090,10 @@ tty_nhgetch(void) term_curs_set(0); if (!i) i = '\033'; /* map NUL to ESC since nethack doesn't expect NUL */ - else if (i == EOF) + else if (i == EOF) { + iflags.term_gone = 1; i = '\033'; /* same for EOF */ + } /* topline has been seen - we can clear the need for --More-- */ if (ttyDisplay && ttyDisplay->toplin == TOPLINE_NEED_MORE) ttyDisplay->toplin = TOPLINE_NON_EMPTY; From 0db013c08e84403a3911f31d36c327025a5ed893 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 13 Jul 2025 21:37:35 -0400 Subject: [PATCH 755/791] adjust levitation wand engraving wording slightly --- include/extern.h | 2 +- src/apply.c | 2 +- src/dig.c | 4 ++-- src/engrave.c | 35 +++++++++++++++++++++++------------ src/lock.c | 2 +- src/pickup.c | 2 +- 6 files changed, 29 insertions(+), 18 deletions(-) diff --git a/include/extern.h b/include/extern.h index 7df8e2530..1d3e5ade1 100644 --- a/include/extern.h +++ b/include/extern.h @@ -978,7 +978,7 @@ extern char *build_english_list(char *) NONNULLARG1; extern char *random_engraving(char *, char *) NONNULLARG12; extern void wipeout_text(char *, int, unsigned) NONNULLARG1; extern boolean can_reach_floor(boolean); -extern void cant_reach_floor(coordxy, coordxy, boolean, boolean); +extern void cant_reach_floor(coordxy, coordxy, boolean, boolean, boolean); extern struct engr *engr_at(coordxy, coordxy); extern struct engr *sengr_at(const char *, coordxy, coordxy, boolean) NONNULLARG1; extern void u_wipe_engr(int); diff --git a/src/apply.c b/src/apply.c index 61219a716..3e7370c4a 100644 --- a/src/apply.c +++ b/src/apply.c @@ -360,7 +360,7 @@ use_stethoscope(struct obj *obj) Soundeffect(se_faint_splashing, 35); You_hear("faint splashing."); } else if (u.dz < 0 || !can_reach_floor(TRUE)) { - cant_reach_floor(u.ux, u.uy, (u.dz < 0), TRUE); + cant_reach_floor(u.ux, u.uy, (u.dz < 0), TRUE, FALSE); } else if (its_dead(u.ux, u.uy, &res)) { ; /* message already given */ } else if (Is_stronghold(&u.uz)) { diff --git a/src/dig.c b/src/dig.c index e8a89888f..579a97013 100644 --- a/src/dig.c +++ b/src/dig.c @@ -1314,7 +1314,7 @@ use_pick_axe2(struct obj *obj) /* it must be air -- water checked above */ You("swing %s through thin air.", yobjnam(obj, (char *) 0)); } else if (!can_reach_floor(FALSE)) { - cant_reach_floor(u.ux, u.uy, FALSE, FALSE); + cant_reach_floor(u.ux, u.uy, FALSE, FALSE, FALSE); } else if (is_pool_or_lava(u.ux, u.uy)) { /* Monsters which swim also happen not to be able to dig */ You("cannot stay under%s long enough.", @@ -1324,7 +1324,7 @@ use_pick_axe2(struct obj *obj) dotrap(trap, FORCEBUNGLE); /* might escape trap and still be teetering at brink */ if (!u.utrap) - cant_reach_floor(u.ux, u.uy, FALSE, TRUE); + cant_reach_floor(u.ux, u.uy, FALSE, TRUE, FALSE); } else if (!ispick /* can only dig down with an axe when doing so will trigger or disarm a trap here */ diff --git a/src/engrave.c b/src/engrave.c index 226f6b30b..e029e87dc 100644 --- a/src/engrave.c +++ b/src/engrave.c @@ -215,13 +215,16 @@ can_reach_floor(boolean check_pit) /* give a message after caller has determined that hero can't reach */ void -cant_reach_floor(coordxy x, coordxy y, boolean up, boolean check_pit) +cant_reach_floor(coordxy x, coordxy y, boolean up, + boolean check_pit, boolean wand_engraving) { - You("can't reach the %s.", - up ? ceiling(x, y) - : (check_pit && can_reach_floor(FALSE)) - ? "bottom of the pit" - : surface(x, y)); + pline("%s can't reach the %s.", + wand_engraving + ? "The wand does nothing more, and the tip of the wand" + : "You", + up ? ceiling(x, y) + : (check_pit && can_reach_floor(FALSE)) ? "bottom of the pit" + : surface(x, y)); } struct engr * @@ -493,7 +496,7 @@ u_can_engrave(void) pline("What would you write? \"Jonah was here\"?"); return FALSE; } else if (is_whirly(u.ustuck->data)) { - cant_reach_floor(u.ux, u.uy, FALSE, FALSE); + cant_reach_floor(u.ux, u.uy, FALSE, FALSE, FALSE); return FALSE; } /* Note: for amorphous engulfers, writing attempt is allowed here @@ -941,6 +944,7 @@ doengrave(void) char *sp; /* Place holder for space count of engr text */ struct _doengrave_ctx *de; int retval; + boolean initial_msg_given = FALSE; /* Can the adventurer engrave at all? */ if (!u_can_engrave()) @@ -982,12 +986,19 @@ doengrave(void) Your("message dissolves..."); goto doengr_exit; } - if (de->otmp->oclass != WAND_CLASS && !can_reach_floor(TRUE)) { - cant_reach_floor(u.ux, u.uy, FALSE, TRUE); - goto doengr_exit; + if (!can_reach_floor(TRUE)) { + if (de->otmp->oclass != WAND_CLASS) { + cant_reach_floor(u.ux, u.uy, FALSE, TRUE, FALSE); + goto doengr_exit; + } else { + You("gesture, with your wand, towards the %s below you.", + surface(u.ux, u.uy)); + initial_msg_given = TRUE; + } } if (IS_ALTAR(levl[u.ux][u.uy].typ)) { - You("make a motion towards the altar with %s.", de->writer); + if (!initial_msg_given) + You("make a motion towards the altar with %s.", de->writer); altar_wrath(u.ux, u.uy); goto doengr_exit; } @@ -1074,7 +1085,7 @@ doengrave(void) if (!de->ptext) { if (de->otmp && de->otmp->oclass == WAND_CLASS && !can_reach_floor(TRUE)) - cant_reach_floor(u.ux, u.uy, FALSE, TRUE); + cant_reach_floor(u.ux, u.uy, FALSE, TRUE, TRUE); de->ret = ECMD_TIME; goto doengr_exit; } diff --git a/src/lock.c b/src/lock.c index 2fe2a198a..2e8851754 100644 --- a/src/lock.c +++ b/src/lock.c @@ -700,7 +700,7 @@ doforce(void) return ECMD_OK; } if (!can_reach_floor(TRUE)) { - cant_reach_floor(u.ux, u.uy, FALSE, TRUE); + cant_reach_floor(u.ux, u.uy, FALSE, TRUE, FALSE); return ECMD_OK; } diff --git a/src/pickup.c b/src/pickup.c index a01283cde..b74119402 100644 --- a/src/pickup.c +++ b/src/pickup.c @@ -2051,7 +2051,7 @@ able_to_loot( if (u.usteed && P_SKILL(P_RIDING) < P_BASIC) rider_cant_reach(); /* not skilled enough to reach */ else - cant_reach_floor(x, y, FALSE, TRUE); + cant_reach_floor(x, y, FALSE, TRUE, FALSE); return FALSE; } else if ((is_pool(x, y) && (looting || !Underwater)) || is_lava(x, y)) { /* at present, can't loot in water even when Underwater; From dcef128290e15537de37a1c17ea1a88aed50281e Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 13 Jul 2025 23:46:50 -0400 Subject: [PATCH 756/791] control-v on curses using pdcursesmod --- win/curses/cursmain.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/win/curses/cursmain.c b/win/curses/cursmain.c index 89491434e..326f7999b 100644 --- a/win/curses/cursmain.c +++ b/win/curses/cursmain.c @@ -267,6 +267,8 @@ curses_init_nhwindows( # endif/* DEF_GAME_NAME */ PDC_set_title(window_title); PDC_set_blink(TRUE); /* Only if the user asks for it! */ + /* disable the default paste function so control-V works as expected */ + PDC_set_function_key(FUNCTION_KEY_PASTE, 0); timeout(1); (void) getch(); timeout(-1); From f58b7a8269d1a113163e46a8f2a54b67e2fb2b89 Mon Sep 17 00:00:00 2001 From: nhmall Date: Wed, 16 Jul 2025 21:04:04 -0400 Subject: [PATCH 757/791] update tested versions of Visual Studio 2025-07-16 --- sys/windows/Makefile.nmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sys/windows/Makefile.nmake b/sys/windows/Makefile.nmake index cf95dc141..05df018c4 100644 --- a/sys/windows/Makefile.nmake +++ b/sys/windows/Makefile.nmake @@ -9,7 +9,7 @@ # # Visual Studio Compilers Tested: # - Microsoft Visual Studio 2019 Community Edition v 16.11.42 -# - Microsoft Visual Studio 2022 Community Edition v 17.14.6 +# - Microsoft Visual Studio 2022 Community Edition v 17.14.9 # #============================================================================== # This is used for building two distinct executables of NetHack: @@ -1178,7 +1178,7 @@ rc=Rc.exe # # Recently tested versions: TESTEDVS2019 = 14.29.30157.0 -TESTEDVS2022 = 14.44.35211.0 +TESTEDVS2022 = 14.44.35213.0 VS2019CUR = $(TESTEDVS2019:.=) VS2022CUR = $(TESTEDVS2022:.=) From 58d377e81e23cb78710d0fbe27c807a4cbf5507e Mon Sep 17 00:00:00 2001 From: PatR Date: Thu, 17 Jul 2025 16:29:27 -0700 Subject: [PATCH 758/791] uhitm.c warning fix From "Monsters trapped in pits cannot kick" two weeks ago. Avoid uhitm.c:5505:9: warning: unannotated fall-through between switch labels [-Wimplicit-fallthrough] Recent clang wants C23's [[fallthrough]] attribute rather than just the lint '/*FALLTHRU*/' comment. --- src/uhitm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/uhitm.c b/src/uhitm.c index 65b311e4c..cb85c63e3 100644 --- a/src/uhitm.c +++ b/src/uhitm.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 uhitm.c $NHDT-Date: 1736575153 2025/01/10 21:59:13 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.461 $ */ +/* NetHack 3.7 uhitm.c $NHDT-Date: 1752823766 2025/07/17 23:29:26 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.477 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -5501,6 +5501,7 @@ hmonas(struct monst *mon) case AT_KICK: if (mattk->aatyp == AT_KICK && mtrapped_in_pit(&gy.youmonst)) continue; + FALLTHROUGH; /*FALLTHRU*/ case AT_BITE: case AT_STNG: From 36dcb92288f0066aefbce01c9d7d4f197f937b6b Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 19 Jul 2025 18:22:35 -0400 Subject: [PATCH 759/791] MSYS2 package fix: include lua-5.4.6.dll in zip --- sys/windows/GNUmakefile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sys/windows/GNUmakefile b/sys/windows/GNUmakefile index cc3206073..1d2868c05 100644 --- a/sys/windows/GNUmakefile +++ b/sys/windows/GNUmakefile @@ -1360,12 +1360,13 @@ $(ONH)/%.o: $(SRC)/%.c $(NHLUAH) | $(ONH) TARGET_CPU = x64 NHV=370 PKGFILES = nethackrc.template Guidebook.txt license NetHack.exe NetHack.txt \ - NetHackW.exe opthelp nhdat370 record symbols sysconf.template + NetHackW.exe opthelp nhdat370 record symbols sysconf.template $(notdir $(LUADLL)) + FILESTOZIP = $(addprefix $(GAMEDIR)/, $(PKGFILES)) MAINZIP = $(PkgDir)/nethack-$(NHV)-win-$(TARGET_CPU)-msys2.zip package: binary $(FILESTOZIP) $(MAINZIP) - @echo NetHack Windows package created: $(MAINZIP) + @echo NetHack Windows package created: $(MAINZIP) $(MAINZIP): $(FILESTOZIP) | $(PkgDir) /c/Windows/System32/tar -a -cf $(MAINZIP) -C $(GAMEDIR) $(PKGFILES) From f145cc02f4eab11dacac08feb60a5d1fa062f868 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 26 Jul 2025 11:03:20 -0400 Subject: [PATCH 760/791] photograph experience gains often counted only prior to first move More details in https://github.com/NetHack/NetHack/issues/1430 track photographed monsters using a distinct bit also adds a pair of new context fields to track the total number of monsters seen up close, and the total number of monsters photographed. So, if somebody wants to add unique end-of-game disclosure statements for tourists that relate to those, the groundwork should be there. NOTE: This increments EDITLEVEL, so existing save and bones files will become outdated. Fixes #1430 --- include/context.h | 6 ++++++ include/extern.h | 2 +- include/hack.h | 1 + include/patchlevel.h | 2 +- src/apply.c | 2 +- src/mon.c | 16 ++++++++++++---- 6 files changed, 22 insertions(+), 7 deletions(-) diff --git a/include/context.h b/include/context.h index 73fee29bc..f2105f147 100644 --- a/include/context.h +++ b/include/context.h @@ -135,6 +135,11 @@ struct achievement_tracking { boolean minetn_reached; /* avoid redundant checking for town entry */ }; +struct lifelists { + long total_seen_upclose; /* count of critters seen up close */ + long total_photographed; /* count of critters photographed (tourists) */ +}; + struct context_info { unsigned ident; /* social security number for each monster */ unsigned no_of_wizards; /* 0, 1 or 2 (wizard and his shadow) */ @@ -175,6 +180,7 @@ struct context_info { struct tribute_info tribute; struct novel_tracking novel; struct achievement_tracking achieveo; + struct lifelists lifelist; char jingle[5 + 1]; }; diff --git a/include/extern.h b/include/extern.h index 1d3e5ade1..c8180ec44 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1812,7 +1812,7 @@ extern void dealloc_mextra(struct monst *); extern boolean usmellmon(struct permonst *); extern void mimic_hit_msg(struct monst *, short); extern void adj_erinys(unsigned); -extern void see_monster_closeup(struct monst *) NONNULLARG1; +extern void see_monster_closeup(struct monst *, boolean) NONNULLARG1; extern void see_nearby_monsters(void); extern void shieldeff_mon(struct monst *) NONNULLARG1; extern void flash_mon(struct monst *) NONNULLARG1; diff --git a/include/hack.h b/include/hack.h index fcb669d10..99eaca753 100644 --- a/include/hack.h +++ b/include/hack.h @@ -670,6 +670,7 @@ struct mvitals { uchar died; uchar mvflags; Bitfield(seen_close, 1); + Bitfield(photographed, 1); }; diff --git a/include/patchlevel.h b/include/patchlevel.h index 1de0380b0..27a7ac520 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 128 +#define EDITLEVEL 129 /* * Development status possibilities. diff --git a/src/apply.c b/src/apply.c index 3e7370c4a..a4d64bd23 100644 --- a/src/apply.c +++ b/src/apply.c @@ -68,7 +68,7 @@ do_blinding_ray(struct obj *obj) if (mtmp) { (void) flash_hits_mon(mtmp, obj); if (obj->otyp == EXPENSIVE_CAMERA) - see_monster_closeup(mtmp); + see_monster_closeup(mtmp, TRUE); /* TRUE for photo */ } /* normally bhit() would do this but for FLASHED_LIGHT we want it to be deferred until after flash_hits_mon() */ diff --git a/src/mon.c b/src/mon.c index ade679695..891c744f6 100644 --- a/src/mon.c +++ b/src/mon.c @@ -5896,13 +5896,18 @@ adj_erinys(unsigned abuse) pm->difficulty = min(10 + (u.ualign.abuse / 3), 25); } -/* mark monster type as seen from close-up, +/* mark individual monster type as seen from close-up, if we haven't seen it nearby before */ void -see_monster_closeup(struct monst *mtmp) +see_monster_closeup(struct monst *mtmp, boolean photo) { if (!svm.mvitals[monsndx(mtmp->data)].seen_close) { svm.mvitals[monsndx(mtmp->data)].seen_close = TRUE; + svc.context.lifelist.total_seen_upclose++; + } + if (photo && !svm.mvitals[monsndx(mtmp->data)].photographed) { + svm.mvitals[monsndx(mtmp->data)].photographed = 1; + svc.context.lifelist.total_photographed++; if (Role_if(PM_TOURIST)) { more_experienced(experience(mtmp, 0), 0); newexplevel(); @@ -5921,8 +5926,11 @@ see_nearby_monsters(void) if (isok(x, y) && MON_AT(x, y)) { struct monst *mtmp = m_at(x, y); - if (canspotmon(mtmp) && !mtmp->mundetected && !M_AP_TYPE(mtmp)) - svm.mvitals[monsndx(mtmp->data)].seen_close = TRUE; + if (canspotmon(mtmp) && !mtmp->mundetected && !M_AP_TYPE(mtmp) + && !svm.mvitals[monsndx(mtmp->data)].seen_close) { + svm.mvitals[monsndx(mtmp->data)].seen_close = 1; + svc.context.lifelist.total_seen_upclose++; + } } } From c08f79b26ebe7da2f68ec5008fd2cb6cef0a864a Mon Sep 17 00:00:00 2001 From: PatR Date: Tue, 29 Jul 2025 15:45:11 -0700 Subject: [PATCH 761/791] more photographing monsters Don't record hallucinated monsters as having been seen up close or as photographed. Treat a tourist's starting pet has having been photographed prior to bringing the camera and dog or cat into the dungeon. No extra points to tourist when first long worm tail is photographed. EDITLEVEL is incremented again, for extra context to track starting pet. --- include/context.h | 3 +- include/patchlevel.h | 4 +-- src/apply.c | 7 ++-- src/dog.c | 16 ++++++--- src/mon.c | 85 ++++++++++++++++++++++++++++++++++---------- 5 files changed, 87 insertions(+), 28 deletions(-) diff --git a/include/context.h b/include/context.h index f2105f147..589a80691 100644 --- a/include/context.h +++ b/include/context.h @@ -1,4 +1,4 @@ -/* NetHack 3.7 context.h $NHDT-Date: 1646428003 2022/03/04 21:06:43 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.45 $ */ +/* NetHack 3.7 context.h $NHDT-Date: 1753856387 2025/07/29 22:19:47 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.58 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2006. */ /* NetHack may be freely redistributed. See license for details. */ @@ -150,6 +150,7 @@ struct context_info { int current_fruit; /* fruit->fid corresponding to svp.pl_fruit[] */ int mysteryforce; /* adjusts how often "mysterious force" kicks in */ int rndencode; /* randomized escape sequence introducer */ + int startingpet_typ; /* monster type for initial pet */ int warnlevel; /* threshold (digit) to warn about unseen mons */ long next_attrib_check; /* next attribute check */ long seer_turn; /* when random clairvoyance will next kick in */ diff --git a/include/patchlevel.h b/include/patchlevel.h index 27a7ac520..ff02f26bc 100644 --- a/include/patchlevel.h +++ b/include/patchlevel.h @@ -1,4 +1,4 @@ -/* NetHack 3.7 patchlevel.h $NHDT-Date: 1725653013 2024/09/06 20:03:33 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.264 $ */ +/* NetHack 3.7 patchlevel.h $NHDT-Date: 1753856387 2025/07/29 22:19:47 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.288 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -17,7 +17,7 @@ * Incrementing EDITLEVEL can be used to force invalidation of old bones * and save files. */ -#define EDITLEVEL 129 +#define EDITLEVEL 130 /* * Development status possibilities. diff --git a/src/apply.c b/src/apply.c index a4d64bd23..4e3788dd4 100644 --- a/src/apply.c +++ b/src/apply.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 apply.c $NHDT-Date: 1737275719 2025/01/19 00:35:19 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.464 $ */ +/* NetHack 3.7 apply.c $NHDT-Date: 1753856387 2025/07/29 22:19:47 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.472 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -61,8 +61,8 @@ void do_blinding_ray(struct obj *obj) { struct monst *mtmp = bhit(u.dx, u.dy, COLNO, FLASHED_LIGHT, - (int (*) (MONST_P, OBJ_P)) 0, - (int (*) (OBJ_P, OBJ_P)) 0, &obj); + (int (*) (MONST_P, OBJ_P)) 0, + (int (*) (OBJ_P, OBJ_P)) 0, &obj); obj->ox = u.ux, obj->oy = u.uy; /* flash_hits_mon() wants this */ if (mtmp) { @@ -100,6 +100,7 @@ use_camera(struct obj *obj) You("take a picture of the %s.", (u.dz > 0) ? surface(u.ux, u.uy) : ceiling(u.ux, u.uy)); } else if (!u.dx && !u.dy) { + /* TODO: we ought to have a "selfie" joke here... */ (void) zapyourself(obj, TRUE); } else { do_blinding_ray(obj); diff --git a/src/dog.c b/src/dog.c index 0682cf610..a583de705 100644 --- a/src/dog.c +++ b/src/dog.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 dog.c $NHDT-Date: 1737287993 2025/01/19 03:59:53 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.178 $ */ +/* NetHack 3.7 dog.c $NHDT-Date: 1753856387 2025/07/29 22:19:47 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.190 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2011. */ /* NetHack may be freely redistributed. See license for details. */ @@ -214,7 +214,7 @@ make_familiar(struct obj *otmp, coordxy x, coordxy y, boolean quietly) return mtmp; } -/* used exclusively for hero's starting pet */ +/* despite rather general name, used exclusively for hero's starting pet */ struct monst * makedog(void) { @@ -222,10 +222,13 @@ makedog(void) const char *petname; int pettype; - if (gp.preferred_pet == 'n') + if (gp.preferred_pet == 'n') { + /* static init yields 0 (PM_GIANT_ANT); fix that up now */ + svc.context.startingpet_typ = NON_PM; return ((struct monst *) 0); + } - pettype = pet_type(); + pettype = svc.context.startingpet_typ = pet_type(); petname = (pettype == PM_LITTLE_DOG) ? gd.dogname : (pettype == PM_KITTEN) ? gc.catname : (pettype == PM_PONY) ? gh.horsename @@ -264,6 +267,11 @@ makedog(void) put_saddle_on_mon((struct obj *) 0, mtmp); } } + /* starting pet's type has been seen up close (unless PermaBlind) + and for tourist treat it as having already been photographed */ + gb.bhitpos.x = mtmp->mx, gb.bhitpos.y = mtmp->my; + gn.notonhead = FALSE; + see_monster_closeup(mtmp, carrying(EXPENSIVE_CAMERA) ? TRUE : FALSE); } else { impossible("makedog() when startingpet_mid is already non-zero?"); } diff --git a/src/mon.c b/src/mon.c index 891c744f6..a84bb364b 100644 --- a/src/mon.c +++ b/src/mon.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 mon.c $NHDT-Date: 1722365546 2024/07/30 18:52:26 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.584 $ */ +/* NetHack 3.7 mon.c $NHDT-Date: 1753856387 2025/07/29 22:19:47 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.611 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Derek S. Ray, 2015. */ /* NetHack may be freely redistributed. See license for details. */ @@ -5901,16 +5901,52 @@ adj_erinys(unsigned abuse) void see_monster_closeup(struct monst *mtmp, boolean photo) { - if (!svm.mvitals[monsndx(mtmp->data)].seen_close) { - svm.mvitals[monsndx(mtmp->data)].seen_close = TRUE; + int mndx; + + if (Hallucination || (Blind && !Blind_telepat)) + return; + + mndx = monsndx(mtmp->data); + if (M_AP_TYPE(mtmp) == M_AP_MONSTER && !sensemon(mtmp)) + mndx = mtmp->mappearance; + if (mndx == PM_LONG_WORM && gn.notonhead) + mndx = PM_LONG_WORM_TAIL; + + if (!svm.mvitals[mndx].seen_close) { + svm.mvitals[mndx].seen_close = 1; svc.context.lifelist.total_seen_upclose++; } - if (photo && !svm.mvitals[monsndx(mtmp->data)].photographed) { - svm.mvitals[monsndx(mtmp->data)].photographed = 1; - svc.context.lifelist.total_photographed++; - if (Role_if(PM_TOURIST)) { - more_experienced(experience(mtmp, 0), 0); - newexplevel(); + + /* hallucinatory monsters don't reach here--they're not recorded; + being able to see invisible doesn't make invisible monsters show up + on photos; likewise, telepathy allows hero to see hidden monsters + but doesn't cause them to appear on photos */ + if (photo && !mtmp->minvis && !mtmp->mundetected + && (M_AP_TYPE(mtmp) == M_AP_NOTHING + || M_AP_TYPE(mtmp) == M_AP_MONSTER)) { + if (M_AP_TYPE(mtmp) == M_AP_MONSTER) /* cloned Wizard of Yendor */ + mndx = mtmp->mappearance; + + if (!svm.mvitals[mndx].photographed) { + svm.mvitals[mndx].photographed = 1; + svc.context.lifelist.total_photographed++; + + /* tourist earns points (toward EXP but not final score) for + the first instance of each type of monster photographed; + worm tail can be photographed but yields no EXP bonus */ + if (Role_if(PM_TOURIST) + /* suppress extra points for photographing the pet that hero + started with (unless it has changed shape due to growing + up or being polymorphed) */ + && (mtmp->m_id != svc.context.startingpet_mid + || mndx != svc.context.startingpet_typ) + /* monsndx() check covers worm tail and also disguised + Wizard of Yendor; experienced() won't yield a reasonable + value for those */ + && mndx == monsndx(mtmp->data)) { + more_experienced(experience(mtmp, 0), 0); + newexplevel(); + } } } } @@ -5919,19 +5955,32 @@ see_monster_closeup(struct monst *mtmp, boolean photo) void see_nearby_monsters(void) { + struct monst *mtmp; + int mndx; coordxy x, y; - 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 (Hallucination || (Blind && !Blind_telepat)) + return; - if (canspotmon(mtmp) && !mtmp->mundetected && !M_AP_TYPE(mtmp) - && !svm.mvitals[monsndx(mtmp->data)].seen_close) { - svm.mvitals[monsndx(mtmp->data)].seen_close = 1; - svc.context.lifelist.total_seen_upclose++; - } + for (x = u.ux - 1; x <= u.ux + 1; x++) + for (y = u.uy - 1; y <= u.uy + 1; y++) { + if (!isok(x, y)) + continue; + if (!(mtmp = m_at(x, y))) + continue; + mndx = monsndx(mtmp->data); + if (M_AP_TYPE(mtmp) == M_AP_MONSTER) + mndx = mtmp->mappearance; + /* skip closeup handling if this mon type has already been done */ + if (svm.mvitals[mndx].seen_close) + continue; + /* disguised mimics pass canseemon(); undetected hiders don't */ + if (canseemon(mtmp) || (mtmp->mundetected && sensemon(mtmp))) { + gb.bhitpos.x = x, gb.bhitpos.y = y; + gn.notonhead = (x != mtmp->mx || y != mtmp->my); + see_monster_closeup(mtmp, FALSE); } + } } /* monster resists something. From 5fe746a0d6b8314340b670c5b2a3861f14c167e2 Mon Sep 17 00:00:00 2001 From: PatR Date: Mon, 4 Aug 2025 19:56:51 -0700 Subject: [PATCH 762/791] fix issue #1435 - vampire leaders as wolves Issue reported by by vultur-cadens: a vampire lord or lady might change to wolf form while flying over water or lava, ending flight and dropping into that water or lava. It would then drown or burn up, revert to vampire leader form and resume flying, then be teleported since it was past the check for being in flight. The fix is pretty staightforward. It is still possible to force wolf form with the monpolycontrol option, leaving the wolf standing on water (didn't test for lava) and then drowning on its next move, where it will revert to vampire form but no longer teleport away. There's no need for a wizard mode hack to behave more stringently. Fixes #1435 --- doc/fixes3-7-0.txt | 2 ++ src/mon.c | 36 ++++++++++++++++++++++++++---------- 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index 5bd8ab8ca..8a37c1f5c 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -1521,6 +1521,8 @@ worn alchemy smock reduces chances of dipped potions exploding dwarves can sense buried items under their feet monsters trapped in pits cannot kick create familiar spell can create harder creatures +a vampire lord could choose to take on wolf form while flying over water or + lava, then revert to vampire lord form and teleport unnecessarily Fixes to 3.7.0-x General Problems Exposed Via git Repository diff --git a/src/mon.c b/src/mon.c index a84bb364b..40a005440 100644 --- a/src/mon.c +++ b/src/mon.c @@ -1022,14 +1022,22 @@ minliquid_core(struct monst *mtmp) pline_mon(mtmp, "%s surrenders to the fire.", Monnam(mtmp)); mondead(mtmp); /* no corpse */ - } else if (cansee(mtmp->mx, mtmp->my)) - pline_mon(mtmp, "%s burns slightly.", - Monnam(mtmp)); + } else if (cansee(mtmp->mx, mtmp->my)) { + pline_mon(mtmp, "%s burns slightly.", Monnam(mtmp)); + } } if (!DEADMONSTER(mtmp)) { - (void) fire_damage_chain(mtmp->minvent, FALSE, FALSE, - mtmp->mx, mtmp->my); - (void) rloc(mtmp, RLOC_MSG); + if (m_in_air(mtmp)) { + ; /* vampshifter in wolf form can revert to vampire lord + * and become a flyer so not need to teleport */ + } else if (likes_lava(mtmp->data)) { + ; /* likes_lava case is hypothetical */ + } else { + (void) fire_damage_chain(mtmp->minvent, FALSE, FALSE, + mtmp->mx, mtmp->my); + if (!rloc(mtmp, RLOC_MSG)) + deal_with_overcrowding(mtmp); + } return 0; } return 1; @@ -1065,9 +1073,14 @@ minliquid_core(struct monst *mtmp) else xkilled(mtmp, XKILL_NOMSG); if (!DEADMONSTER(mtmp)) { - water_damage_chain(mtmp->minvent, FALSE); - if (!rloc(mtmp, RLOC_NOMSG)) - deal_with_overcrowding(mtmp); + if (m_in_air(mtmp)) { + ; /* vampshifter in wolf form can revert to vampire lord + * and become a flyer so not need to teleport */ + } else { + water_damage_chain(mtmp->minvent, FALSE); + if (!rloc(mtmp, RLOC_NOMSG)) + deal_with_overcrowding(mtmp); + } return 0; } return 1; @@ -4888,7 +4901,10 @@ pickvampshape(struct monst *mon) FALLTHROUGH; /*FALLTHRU*/ case PM_VAMPIRE_LEADER: /* vampire lord or Vlad can become wolf */ - if (!rn2(wolfchance) && !uppercase_only) { + if (!rn2(wolfchance) && !uppercase_only + /* don't pick a walking form if that would lead to immediate + drowning or immolation and reversion to vampire form */ + && !is_pool_or_lava(mon->mx, mon->my)) { mndx = PM_WOLF; break; } From 695c6ef3ac6b73e2dacbc8f3224232338423efdc Mon Sep 17 00:00:00 2001 From: PatR Date: Tue, 5 Aug 2025 13:30:17 -0700 Subject: [PATCH 763/791] fix issue #1434 - engulfed gas spore explosion Issue reported by Umbire: a gas spore that got swallowed and killed didn't die but exploded anyway, with the explosion affecting the map instead of being contained in the swallower. There was code to handle that but it wasn't being executed. This fix feels unclean but seems to work. I couldn't reproduce the survival of the gas spore but since that isn't wanted I won't worry about it. Fixes #1434 --- doc/fixes3-7-0.txt | 2 ++ include/decl.h | 3 +++ src/decl.c | 2 ++ src/mhitm.c | 2 ++ src/mhitu.c | 4 +++- src/mon.c | 32 ++++++++++++++++++++++++-------- src/uhitm.c | 2 ++ 7 files changed, 38 insertions(+), 9 deletions(-) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index 8a37c1f5c..d19a70a6e 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -1523,6 +1523,8 @@ monsters trapped in pits cannot kick create familiar spell can create harder creatures a vampire lord could choose to take on wolf form while flying over water or lava, then revert to vampire lord form and teleport unnecessarily +a gas spore that was killed when an engulfer swallowed it produced an explosion + on the map rather than inside the engulfer Fixes to 3.7.0-x General Problems Exposed Via git Repository diff --git a/include/decl.h b/include/decl.h index d5186158b..72f85eb90 100644 --- a/include/decl.h +++ b/include/decl.h @@ -604,6 +604,9 @@ struct instance_globals_m { /* dokick.c */ struct rm *maploc; + /* mhitm.c */ + struct monst *mswallower; /* for gas spore explosion when it's swallowed*/ + /* mhitu.c */ int mhitu_dieroll; diff --git a/src/decl.c b/src/decl.c index 7d0a47cb4..a7e52dd80 100644 --- a/src/decl.c +++ b/src/decl.c @@ -508,6 +508,8 @@ static const struct instance_globals_m g_init_m = { UNDEFINED_PTR, /* migrating_mons */ /* dokick.c */ UNDEFINED_PTR, /* maploc */ + /* mhitm.c */ + UNDEFINED_PTR, /* mswallower */ /* mhitu.c */ UNDEFINED_VALUE, /* mhitu_dieroll */ /* mklev.c */ diff --git a/src/mhitm.c b/src/mhitm.c index 078b7596c..322b65b22 100644 --- a/src/mhitm.c +++ b/src/mhitm.c @@ -906,7 +906,9 @@ gulpmm( newsym(ax, ay); /* erase old position */ newsym(dx, dy); /* update new position */ + gm.mswallower = magr; /* corpse_chance() wants this */ status = mdamagem(magr, mdef, mattk, (struct obj *) 0, 0); + gm.mswallower = (struct monst *) 0; /* reset */ if ((status & (M_ATTK_AGR_DIED | M_ATTK_DEF_DIED)) == (M_ATTK_AGR_DIED | M_ATTK_DEF_DIED)) { diff --git a/src/mhitu.c b/src/mhitu.c index ff32445e8..d6332c18d 100644 --- a/src/mhitu.c +++ b/src/mhitu.c @@ -1271,7 +1271,7 @@ gulp_blnd_check(void) return FALSE; } -/* monster swallows you, or damage if u.uswallow */ +/* monster swallows you, or damage if already swallowed (u.uswallow != 0) */ staticfn int gulpmu(struct monst *mtmp, struct attack *mattk) { @@ -1537,7 +1537,9 @@ gulpmu(struct monst *mtmp, struct attack *mattk) if (physical_damage) tmp = Maybe_Half_Phys(tmp); + gm.mswallower = mtmp; /* match gulpmm() */ mdamageu(mtmp, tmp); + gm.mswallower = 0; if (tmp) stop_occupation(); diff --git a/src/mon.c b/src/mon.c index 40a005440..dce75521c 100644 --- a/src/mon.c +++ b/src/mon.c @@ -2204,8 +2204,7 @@ mfndpos( if (IS_DOOR(ntyp) /* an amorphous creature can only move under/through a closed door if it doesn't currently have hero engulfed */ - && !((amorphous(mdat) || can_fog(mon)) - && (mon != u.ustuck || !u.uswallow)) + && !((amorphous(mdat) || can_fog(mon)) && !engulfing_u(mon)) && (((levl[nx][ny].doormask & D_CLOSED) && !(flag & OPENDOOR)) || ((levl[nx][ny].doormask & D_LOCKED) && !(flag & UNLOCKDOOR))) && !thrudoor) @@ -2670,11 +2669,25 @@ mon_leaving_level(struct monst *mon) remove_monster(mx, my); #if 0 /* mustn't do this; too many places assume that the stale - monst->mx,my values are still valid */ + * monst->mx,my values are still valid */ mon->mx = mon->my = 0; /* off normal map */ #endif } if (onmap) { + /* gulpmm() tries to deal with this, but without this extra + place_monster() the messages for exploding engulfed gas spore + are delivered without the engulfer being shown on the map */ + if (gm.mswallower && gm.mswallower != mon) { + if (gm.mswallower != &gy.youmonst) { + place_monster(gm.mswallower, + gm.mswallower->mx, gm.mswallower->my); + } else { + u_on_newpos(u.ux, u.uy); + if (canspotself()) + display_self(); + } + } + mon->mundetected = 0; /* for migration; doesn't matter for death */ /* unhide mimic in case its shape has been blocking line of sight or it is accompanying the hero to another level */ @@ -3146,6 +3159,9 @@ corpse_chance( struct permonst *mdat = mon->data; int i, tmp; + if (!magr && gm.mswallower && attacktype(gm.mswallower->data, AT_ENGL)) + magr = gm.mswallower, was_swallowed = TRUE; /* for gas spore boom */ + if (mdat == &mons[PM_VLAD_THE_IMPALER] || mdat->mlet == S_LICH) { if (cansee(mon->mx, mon->my) && !was_swallowed) pline_mon(mon, "%s body crumbles into dust.", @@ -3162,7 +3178,10 @@ corpse_chance( tmp = d((int) mdat->mlevel + 1, (int) mdat->mattk[i].damd); else tmp = 0; + if (was_swallowed && magr) { + /* mdef is a gas spore (AT_BOOM) that is exploding inside an + engulfer; suppress usual explosion since it's contained */ if (magr == &gy.youmonst) { There("is an explosion in your %s!", body_part(STOMACH)); Sprintf(svk.killer.name, "%s explosion", @@ -3176,14 +3195,11 @@ corpse_chance( mondied(magr); if (DEADMONSTER(magr)) { /* maybe lifesaved */ if (canspotmon(magr)) - pline_mon(magr, "%s rips open!", - Monnam(magr)); + pline_mon(magr, "%s rips open!", Monnam(magr)); } else if (canseemon(magr)) - pline_mon(magr, - "%s seems to have indigestion.", + pline_mon(magr, "%s seems to have indigestion.", Monnam(magr)); } - return FALSE; } diff --git a/src/uhitm.c b/src/uhitm.c index cb85c63e3..cbf797e8e 100644 --- a/src/uhitm.c +++ b/src/uhitm.c @@ -5005,6 +5005,7 @@ gulpum(struct monst *mdef, struct attack *mattk) "you totally digest " will be coming soon (after several turns) but the level-gain message seems out of order if the kill message is left implicit */ + gm.mswallower = &gy.youmonst; xkilled(mdef, XKILL_GIVEMSG | XKILL_NOCORPSE); if (!DEADMONSTER(mdef)) { /* monster lifesaved */ You("hurriedly regurgitate the sizzling in your %s.", @@ -5045,6 +5046,7 @@ gulpum(struct monst *mdef, struct attack *mattk) } else exercise(A_CON, TRUE); } + gm.mswallower = (struct monst *) 0; end_engulf(); return M_ATTK_DEF_DIED; case AD_PHYS: From 6607b48dd1e20a4cc47782c3de4e5047e8ca38f6 Mon Sep 17 00:00:00 2001 From: nhmall Date: Wed, 6 Aug 2025 12:52:55 -0400 Subject: [PATCH 764/791] sfctool build bit --- util/sftags.c | 1 + 1 file changed, 1 insertion(+) diff --git a/util/sftags.c b/util/sftags.c index db1d9b870..5f055a60e 100644 --- a/util/sftags.c +++ b/util/sftags.c @@ -211,6 +211,7 @@ struct nhdatatypes_t readtagstypes[] = { { NHTYPE_COMPLEX, (char *) "dig_info", sizeof(struct dig_info) }, /* context */ { NHTYPE_COMPLEX, (char *) "engrave_info", sizeof(struct engrave_info) }, + { NHTYPE_COMPLEX, (char *) "lifelists", sizeof(struct lifelists) }, { NHTYPE_COMPLEX, (char *) "obj_split", sizeof(struct obj_split) }, { NHTYPE_COMPLEX, (char *) "polearm_info", sizeof(struct polearm_info) }, { NHTYPE_COMPLEX, (char *) "takeoff_info", sizeof(struct takeoff_info) }, From a0275e26968507906b363fda7582395056dcfefe Mon Sep 17 00:00:00 2001 From: nhmall Date: Wed, 6 Aug 2025 12:56:07 -0400 Subject: [PATCH 765/791] consolidate some duplication into sfmacros.h : #include "sfmacros.h" : from sfstruct.c and sfbase.c --- include/sfmacros.h | 81 ++++++++++++++++++++++++++++++++++++++++++++++ src/sfbase.c | 66 +------------------------------------ src/sfstruct.c | 68 ++------------------------------------ 3 files changed, 84 insertions(+), 131 deletions(-) create mode 100644 include/sfmacros.h diff --git a/include/sfmacros.h b/include/sfmacros.h new file mode 100644 index 000000000..752b74978 --- /dev/null +++ b/include/sfmacros.h @@ -0,0 +1,81 @@ +/* NetHack 3.7 sfmacros.h $NHDT-Date$ $NHDT-Branch$:$NHDT-Revision$ */ +/* Copyright (c) Michael Allison, 2025. */ +/* NetHack may be freely redistributed. See license for details. */ + +/* This file is included by sfbase.c, sfstruct.c */ + +#if defined(SF_C) && defined(SF_A) + +SF_C(struct, arti_info) +SF_C(struct, nhrect) +SF_C(struct, branch) +SF_C(struct, bubble) +SF_C(struct, cemetery) +SF_C(struct, context_info) +SF_C(struct, nhcoord) +SF_C(struct, damage) +SF_C(struct, dest_area) +SF_C(struct, dgn_topology) +SF_C(struct, dungeon) +SF_C(struct, d_level) +SF_C(struct, ebones) +SF_C(struct, edog) +SF_C(struct, egd) +SF_C(struct, emin) +SF_C(struct, engr) +SF_C(struct, epri) +SF_C(struct, eshk) +SF_C(struct, fe) +SF_C(struct, flag) +SF_C(struct, fruit) +SF_C(struct, gamelog_line) +SF_C(struct, kinfo) +SF_C(struct, levelflags) +SF_C(struct, ls_t) +SF_C(struct, linfo) +SF_C(struct, mapseen_feat) +SF_C(struct, mapseen_flags) +SF_C(struct, mapseen_rooms) +SF_C(struct, mkroom) +SF_C(struct, monst) +SF_C(struct, mvitals) +SF_C(struct, obj) +SF_C(struct, objclass) +SF_C(struct, q_score) +SF_C(struct, rm) +SF_C(struct, spell) +SF_C(struct, stairway) +SF_C(struct, s_level) +SF_C(struct, trap) +SF_C(struct, you) +SF_C(union, any) + +SF_A(aligntyp) +SF_A(boolean) +SF_A(coordxy) +//SF_A(genericptr) +SF_A(int) +SF_A(int16) +SF_A(int32) +SF_A(int64) +SF_A(long) +SF_A(schar) +SF_A(short) +SF_A(size_t) +SF_A(time_t) +SF_A(uchar) +SF_A(uint16) +SF_A(uint32) +SF_A(uint64) +SF_A(ulong) +SF_A(unsigned) +SF_A(ushort) +SF_A(xint16) +SF_A(xint8) + +#else + +#error Non-productive inclusion of sfmacros.h + +#endif /* SF_C && SF_A */ + diff --git a/src/sfbase.c b/src/sfbase.c index 07de09b3b..c1f4308a3 100644 --- a/src/sfbase.c +++ b/src/sfbase.c @@ -241,72 +241,8 @@ void sfi_##dtyp(NHFILE *nhfp, xxx *d_##dtyp, const char *myname, int bfsz) } \ } -SF_C(struct, arti_info) -SF_C(struct, nhrect) -SF_C(struct, branch) -SF_C(struct, bubble) -SF_C(struct, cemetery) -SF_C(struct, context_info) -SF_C(struct, nhcoord) -SF_C(struct, damage) -SF_C(struct, dest_area) -SF_C(struct, dgn_topology) -SF_C(struct, dungeon) -SF_C(struct, d_level) -SF_C(struct, ebones) -SF_C(struct, edog) -SF_C(struct, egd) -SF_C(struct, emin) -SF_C(struct, engr) -SF_C(struct, epri) -SF_C(struct, eshk) -SF_C(struct, fe) -SF_C(struct, flag) -SF_C(struct, fruit) -SF_C(struct, gamelog_line) -SF_C(struct, kinfo) -SF_C(struct, levelflags) -SF_C(struct, ls_t) -SF_C(struct, linfo) -SF_C(struct, mapseen_feat) -SF_C(struct, mapseen_flags) -SF_C(struct, mapseen_rooms) -SF_C(struct, mkroom) -SF_C(struct, monst) -SF_C(struct, mvitals) -SF_C(struct, obj) -SF_C(struct, objclass) -SF_C(struct, q_score) -SF_C(struct, rm) -SF_C(struct, spell) -SF_C(struct, stairway) -SF_C(struct, s_level) -SF_C(struct, trap) -SF_C(struct, you) -SF_C(union, any) +#include "sfmacros.h" -SF_A(aligntyp) -SF_A(boolean) -SF_A(coordxy) -//SF_A(genericptr) -SF_A(int) -SF_A(int16) -SF_A(int32) -SF_A(int64) -SF_A(long) -SF_A(schar) -SF_A(short) -SF_A(size_t) -SF_A(time_t) -SF_A(uchar) -SF_A(uint16) -SF_A(uint32) -SF_A(uint64) -SF_A(ulong) -SF_A(unsigned) -SF_A(ushort) -SF_A(xint16) -SF_A(xint8) SF_X(uint8_t, bitfield) void diff --git a/src/sfstruct.c b/src/sfstruct.c index ef9dbdf37..c62b46405 100644 --- a/src/sfstruct.c +++ b/src/sfstruct.c @@ -95,73 +95,9 @@ void historical_sfi_##dtyp(NHFILE *nhfp, xxx *d_##dtyp, const char *myname UNUSED, int bflen UNUSED) \ SFI_BODY(dtyp) -SF_C(struct, arti_info) -SF_C(struct, nhrect) -SF_C(struct, branch) -SF_C(struct, bubble) -SF_C(struct, cemetery) -SF_C(struct, context_info) -SF_C(struct, nhcoord) -SF_C(struct, damage) -SF_C(struct, dest_area) -SF_C(struct, dgn_topology) -SF_C(struct, dungeon) -SF_C(struct, d_level) -SF_C(struct, ebones) -SF_C(struct, edog) -SF_C(struct, egd) -SF_C(struct, emin) -SF_C(struct, engr) -SF_C(struct, epri) -SF_C(struct, eshk) -SF_C(struct, fe) -SF_C(struct, flag) -SF_C(struct, fruit) -SF_C(struct, gamelog_line) -SF_C(struct, kinfo) -SF_C(struct, levelflags) -SF_C(struct, ls_t) -SF_C(struct, linfo) -SF_C(struct, mapseen_feat) -SF_C(struct, mapseen_flags) -SF_C(struct, mapseen_rooms) -SF_C(struct, mkroom) -SF_C(struct, monst) -SF_C(struct, mvitals) -SF_C(struct, obj) -SF_C(struct, objclass) -SF_C(struct, q_score) -SF_C(struct, rm) -SF_C(struct, spell) -SF_C(struct, stairway) -SF_C(struct, s_level) -SF_C(struct, trap) -SF_C(struct, version_info) -SF_C(struct, you) -SF_C(union, any) -SF_A(aligntyp) -SF_A(boolean) -SF_A(coordxy) -//SF_A(genericptr_t) -SF_A(int) -SF_A(int16) -SF_A(int32) -SF_A(int64) -SF_A(long) -SF_A(schar) -SF_A(short) -SF_A(size_t) -SF_A(time_t) -SF_A(uchar) -SF_A(uint16) -SF_A(uint32) -SF_A(uint64) -SF_A(ulong) -SF_A(unsigned) -SF_A(ushort) -SF_A(xint16) -SF_A(xint8) +#include "sfmacros.h" +SF_C(struct, version_info) void historical_sfo_char(NHFILE *, char *d_char, const char *, int); void historical_sfi_char(NHFILE *, char *d_char, const char *, int); From 52573394f0e67c4ef8025af0a6c63f38e79f9e26 Mon Sep 17 00:00:00 2001 From: nhw_cron Date: Wed, 6 Aug 2025 13:24:07 -0400 Subject: [PATCH 766/791] This is cron-daily v1-Apr-1-2024. 000files updated: Files --- Files | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Files b/Files index 786f0c06d..e4f4e096b 100644 --- a/Files +++ b/Files @@ -98,11 +98,12 @@ monflag.h monst.h monsters.h nhmd4.h nhregex.h obj.h objclass.h objects.h optlist.h patchlevel.h pcconf.h permonst.h prop.h quest.h rect.h region.h rm.h savefile.h seffects.h selvar.h -sfprocs.h skills.h sndprocs.h sp_lev.h spell.h -stairs.h sym.h sys.h tcap.h tileset.h -timeout.h tradstdc.h trap.h unixconf.h vision.h -vmsconf.h warnings.h weight.h winami.h wincurs.h -windconf.h winprocs.h wintype.h you.h youprop.h +sfmacros.h sfprocs.h skills.h sndprocs.h sp_lev.h +spell.h stairs.h sym.h sys.h tcap.h +tileset.h timeout.h tradstdc.h trap.h unixconf.h +vision.h vmsconf.h warnings.h weight.h winami.h +wincurs.h windconf.h winprocs.h wintype.h you.h +youprop.h (file for tty versions) wintty.h From 75a2a61653c015ba8305029b3029ab3879981bb3 Mon Sep 17 00:00:00 2001 From: nhmall Date: Wed, 6 Aug 2025 13:51:22 -0400 Subject: [PATCH 767/791] some Makefile follow-up --- sys/unix/Makefile.src | 4 ++-- sys/unix/Makefile.utl | 7 ++++--- sys/vms/Makefile_src.vms | 5 +++-- sys/windows/GNUmakefile | 6 +++--- sys/windows/Makefile.nmake | 17 +++++++++-------- 5 files changed, 21 insertions(+), 18 deletions(-) diff --git a/sys/unix/Makefile.src b/sys/unix/Makefile.src index eaf5b1d47..57bd4b1db 100644 --- a/sys/unix/Makefile.src +++ b/sys/unix/Makefile.src @@ -769,7 +769,7 @@ hacklib.a: hacklib.o ../win/gnome/gn_rip.h: ../win/X11/rip.xpm cp ../win/X11/rip.xpm ../win/gnome/gn_rip.h -$(TARGETPFX)sfbase.o: sfbase.c $(HACK_H) ../include/sfprocs.h +$(TARGETPFX)sfbase.o: sfbase.c $(HACK_H) ../include/sfprocs.h ../include/sfmacros.h # date.c should be recompiled any time any of the source or include code # is modified. @@ -1242,7 +1242,7 @@ $(TARGETPFX)role.o: role.c $(HACK_H) $(TARGETPFX)rumors.o: rumors.c $(HACK_H) ../include/dlb.h $(TARGETPFX)save.o: save.c $(HACK_H) $(TARGETPFX)selvar.o: selvar.c $(HACK_H) ../include/sp_lev.h -$(TARGETPFX)sfstruct.o: sfstruct.c $(HACK_H) ../include/sfprocs.h +$(TARGETPFX)sfstruct.o: sfstruct.c $(HACK_H) ../include/sfprocs.h ../include/sfmacros.h $(TARGETPFX)shk.o: shk.c $(HACK_H) $(TARGETPFX)shknam.o: shknam.c $(HACK_H) $(TARGETPFX)sit.o: sit.c $(HACK_H) ../include/artifact.h diff --git a/sys/unix/Makefile.utl b/sys/unix/Makefile.utl index 4df167f43..84f73b4f6 100644 --- a/sys/unix/Makefile.utl +++ b/sys/unix/Makefile.utl @@ -372,13 +372,14 @@ $(TARGETPFX)sf-restore.o: ../src/restore.c $(HACK_H) $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/restore.c $(TARGETPFX)sf-rumors.o: ../src/rumors.c $(HACK_H) $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/rumors.c -$(TARGETPFX)sfbase.o: ../src/sfbase.c $(HACK_H) +$(TARGETPFX)sfbase.o: ../src/sfbase.c $(HACK_H) ../include/sfmacros.h $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/sfbase.c $(TARGETPFX)sfdata.o: sfdata.c $(HACK_H) ../include/sfprocs.h ../include/sfproto.h $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c sfdata.c -$(TARGETPFX)sfexpasc.o: sfexpasc.c $(HACK_H) ../include/sfprocs.h ../include/sfproto.h +$(TARGETPFX)sfexpasc.o: sfexpasc.c $(HACK_H) ../include/sfprocs.h \ + ../include/sfproto.h ../include/sfmacros.h $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c sfexpasc.c -$(TARGETPFX)sf-struct.o: ../src/sfstruct.c $(HACK_H) +$(TARGETPFX)sf-struct.o: ../src/sfstruct.c $(HACK_H) ../include/sfmacros.h $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/sfstruct.c $(TARGETPFX)strutil.o: ../src/strutil.c $(HACK_H) $(TARGET_CC) $(TARGET_CFLAGS) $(SFFLAGS) -o $@ -c ../src/strutil.c diff --git a/sys/vms/Makefile_src.vms b/sys/vms/Makefile_src.vms index 334145b22..af841394d 100644 --- a/sys/vms/Makefile_src.vms +++ b/sys/vms/Makefile_src.vms @@ -125,7 +125,7 @@ HACKFILES := allmain alloc apply artifact attrib ball bones \ nhlua nhlsel nhlobj objnam o_init objects \ options pager pickup pline polyself potion pray \ priest quest questpgr read rect region report restore \ - rip rnd role rumors save selvar sfstruct \ + rip rnd role rumors save selvar sfbase sfstruct \ shk shknam sit sounds \ sp_lev spell stairs steal steed strutil symbols sys teleport \ timeout topten track trap u_init utf8map \ @@ -805,7 +805,8 @@ $(TARGETPFX)role.obj: role.c $(HACK_H) $(TARGETPFX)rumors.obj: rumors.c $(HACK_H) $(INCL)dlb.h $(TARGETPFX)save.obj: save.c $(HACK_H) $(TARGETPFX)selvar.obj: selvar.c $(HACK_H) -$(TARGETPFX)sfstruct.obj: sfstruct.c $(HACK_H) +$(TARGETPFX)sfbase.obj: sfbase.c $(HACK_H) $(INCL)sfprocs.h $(INCL)sfmacros.h +$(TARGETPFX)sfstruct.obj: sfstruct.c $(HACK_H) $(INCL)sfprocs.h $(INCL)sfmacros.h $(TARGETPFX)shk.obj: shk.c $(HACK_H) $(TARGETPFX)shknam.obj: shknam.c $(HACK_H) $(TARGETPFX)sit.obj: sit.c $(HACK_H) $(INCL)artifact.h diff --git a/sys/windows/GNUmakefile b/sys/windows/GNUmakefile index 1d2868c05..aac5608d4 100644 --- a/sys/windows/GNUmakefile +++ b/sys/windows/GNUmakefile @@ -855,11 +855,11 @@ $(OSFC)/sf-restore.o: $(SRC)/restore.c $(HACK_H) | $(OSFC) $(cc) $(CFLAGSU) $(SFFLAGS) -c $(SRC)/restore.c -o$@ $(OSFC)/sf-rumors.o: $(SRC)/\rumors.c $(HACK_H) | $(OSFC) $(cc) $(CFLAGSU) $(SFFLAGS) -c $(SRC)/rumors.c -o$@ -$(OSFC)/sfbase.o: $(SRC)/sfbase.c $(HACK_H) | $(OSFC) +$(OSFC)/sfbase.o: $(SRC)/sfbase.c $(HACK_H) $(INCL)/sfprocs.h $(INCL)/sfmacros.h | $(OSFC) $(cc) $(CFLAGSU) $(SFFLAGS) -c $(SRC)/sfbase.c -o$@ -$(OSFC)/sfexpasc.o: $(U)sfexpasc.c $(HACK_H) $(INCL)/sfprocs.h $(INCL)/sfproto.h | $(OSFC) +$(OSFC)/sfexpasc.o: $(U)sfexpasc.c $(HACK_H) $(INCL)/sfprocs.h $(INCL)/sfproto.h $(INCL)/sfmacros.h | $(OSFC) $(cc) $(CFLAGSU) $(SFFLAGS) -c $(U)sfexpasc.c -o$@ -$(OSFC)/sf-struct.o: $(SRC)/sfstruct.c $(HACK_H) | $(OSFC) +$(OSFC)/sf-struct.o: $(SRC)/sfstruct.c $(HACK_H) $(INCL)/sfprocs.h $(INCL)/sfmacros.h | $(OSFC) $(cc) $(CFLAGSU) $(SFFLAGS) -c $(SRC)/sfstruct.c -o$@ $(OSFC)/strutil.o: $(SRC)/strutil.c $(HACK_H) | $(OSFC) $(cc) $(CFLAGSU) $(SFFLAGS) -c $(SRC)/strutil.c -o$@ diff --git a/sys/windows/Makefile.nmake b/sys/windows/Makefile.nmake index 05df018c4..7aac1a3bf 100644 --- a/sys/windows/Makefile.nmake +++ b/sys/windows/Makefile.nmake @@ -665,7 +665,8 @@ HACKCSRC = \ $(SRC)potion.c $(SRC)pray.c $(SRC)priest.c $(SRC)quest.c \ $(SRC)questpgr.c $(SRC)read.c $(SRC)rect.c $(SRC)region.c \ $(SRC)restore.c $(SRC)rip.c $(SRC)rnd.c $(SRC)role.c \ - $(SRC)rumors.c $(SRC)save.c $(SRC)selvar.c $(SRC)sfstruct.c sfbase.c \ + $(SRC)rumors.c $(SRC)save.c $(SRC)selvar.c\ + $(SRC)sfbase.c $(SRC)sfstruct.c \ $(SRC)shk.c $(SRC)shknam.c $(SRC)sit.c $(SRC)sounds.c \ $(SRC)sp_lev.c $(SRC)spell.c $(SRC)stairs.c $(SRC)steal.c \ $(SRC)steed.c $(SRC)symbols.c $(SRC)sys.c $(SRC)teleport.c \ @@ -1868,11 +1869,11 @@ $(OGUI)date.o: $(HACKINCL) $(HACKSRC) $(HACKOBJ) $(ALLOBJGUI) @$(MAKE) /NOLOGO /A -f date.nmk !ENDIF -$(OGUI)sfbase.o: sfbase.c $(HACK_H) +$(OGUI)sfbase.o: sfbase.c $(HACK_H) $(INCL)sfmacros.h $(Q)$(CC) $(CFLAGS) /EP $(@B).c > $(OGUI)$(@B).c.preproc $(Q)$(CC) $(CFLAGS) -Fo$@ $(@B).c -$(OTTY)sfbase.o: sfbase.c $(HACK_H) +$(OTTY)sfbase.o: sfbase.c $(HACK_H) $(INCL)sfmacros.h $(Q)$(CC) $(CFLAGS) /EP $(@B).c > $(OTTY)$(@B).c.preproc $(Q)$(CC) $(CFLAGS) -Fo$@ $(@B).c @@ -2513,7 +2514,7 @@ $(OUTL)sfctool.o: $(UTIL)sfctool.c $(HACK_H) $(INCL)sfprocs.h $(Q)$(CC) $(CFLAGS) $(SFFLAGS) -Fo$@ -c $(UTIL)sfctool.c $(OUTL)sfdata.o: $(UTIL)sfdata.c $(HACK_H) $(INCL)sfprocs.h $(INCL)sfproto.h $(Q)$(CC) $(CFLAGS) $(SFFLAGS) -Fo$@ -c $(UTIL)sfdata.c -$(OUTL)sfexpasc.o: $(UTIL)sfexpasc.c $(HACK_H) $(INCL)sfprocs.h $(INCL)sfproto.h +$(OUTL)sfexpasc.o: $(UTIL)sfexpasc.c $(HACK_H) $(INCL)sfprocs.h $(INCL)sfproto.h $(INCL)sfmacros.h $(Q)$(CC) $(CFLAGS) $(SFFLAGS) -Fo$@ -c $(UTIL)sfexpasc.c $(OUTL)sf-alloc.o: $(SRC)alloc.c $(HACK_H) $(Q)$(CC) $(CFLAGS) $(SFFLAGS) -Fo$@ -c $(SRC)alloc.c @@ -2525,9 +2526,9 @@ $(OUTL)sf-monst.o: $(SRC)monst.c $(HACK_H) $(Q)$(CC) $(CFLAGS) $(SFFLAGS) -Fo$@ -c $(SRC)monst.c $(OUTL)sf-objects.o: $(SRC)objects.c $(HACK_H) $(Q)$(CC) $(CFLAGS) $(SFFLAGS) -Fo$@ -c $(SRC)objects.c -$(OUTL)sfbase.o: $(SRC)sfbase.c $(HACK_H) +$(OUTL)sfbase.o: $(SRC)sfbase.c $(HACK_H) $(INCL)sfmacros.h $(Q)$(CC) $(CFLAGS) $(SFFLAGS) -Fo$@ -c $(SRC)sfbase.c -$(OUTL)sf-struct.o: $(SRC)sfstruct.c $(HACK_H) +$(OUTL)sf-struct.o: $(SRC)sfstruct.c $(HACK_H) $(INCL)sfmacros.h $(Q)$(CC) $(CFLAGS) $(SFFLAGS) -Fo$@ -c $(SRC)sfstruct.c $(OUTL)sf-artifact.o: $(SRC)artifact.c $(HACK_H) $(Q)$(CC) $(CFLAGS) $(SFFLAGS) -Fo$@ -c $(SRC)artifact.c @@ -3249,7 +3250,7 @@ $(OTTY)role.o: role.c $(HACK_H) $(OTTY)rumors.o: rumors.c $(HACK_H) $(INCL)dlb.h $(OTTY)save.o: save.c $(HACK_H) $(OTTY)selvar.o: selvar.c $(HACK_H) $(INCL)sp_lev.h -$(OTTY)sfstruct.o: sfstruct.c $(HACK_H) +$(OTTY)sfstruct.o: sfstruct.c $(HACK_H) $(INCL)sfmacros.h $(Q)$(CC) $(CFLAGS) /EP $(@B).c > $(OTTY)$(@B).c.preproc $(Q)$(CC) $(CFLAGS) -Fo$@ $(@B).c $(OTTY)shk.o: shk.c $(HACK_H) @@ -3627,7 +3628,7 @@ $(OGUI)role.o: role.c $(HACK_H) $(OGUI)rumors.o: rumors.c $(HACK_H) $(INCL)dlb.h $(OGUI)save.o: save.c $(HACK_H) $(OGUI)selvar.o: selvar.c $(HACK_H) $(INCL)sp_lev.h -$(OGUI)sfstruct.o: sfstruct.c $(HACK_H) +$(OGUI)sfstruct.o: sfstruct.c $(HACK_H) $(INCL)sfmacros.h $(Q)$(CC) $(CFLAGS) /EP $(@B).c > $(OGUI)$(@B).c.preproc $(Q)$(CC) $(CFLAGS) -Fo$@ $(@B).c $(OGUI)shk.o: shk.c $(HACK_H) From 80e11c287d9b635fe75656f399d94f9e24e4779b Mon Sep 17 00:00:00 2001 From: nhmall Date: Wed, 6 Aug 2025 13:55:41 -0400 Subject: [PATCH 768/791] more follow-up (for visual studio) --- sys/windows/vs/NetHack/NetHack.vcxproj | 1 + sys/windows/vs/NetHackW/NetHackW.vcxproj | 1 + 2 files changed, 2 insertions(+) diff --git a/sys/windows/vs/NetHack/NetHack.vcxproj b/sys/windows/vs/NetHack/NetHack.vcxproj index 002d5c9be..48ba1d27e 100644 --- a/sys/windows/vs/NetHack/NetHack.vcxproj +++ b/sys/windows/vs/NetHack/NetHack.vcxproj @@ -297,6 +297,7 @@ + diff --git a/sys/windows/vs/NetHackW/NetHackW.vcxproj b/sys/windows/vs/NetHackW/NetHackW.vcxproj index 8db832c65..0fb4f77e3 100644 --- a/sys/windows/vs/NetHackW/NetHackW.vcxproj +++ b/sys/windows/vs/NetHackW/NetHackW.vcxproj @@ -356,6 +356,7 @@ + From 2b399d1739a43bc9dc3648e8300c3b2ddf2e2212 Mon Sep 17 00:00:00 2001 From: Michael Allison Date: Wed, 6 Aug 2025 14:12:10 -0400 Subject: [PATCH 769/791] more follow-up (for Xcode) --- sys/unix/NetHack.xcodeproj/project.pbxproj | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sys/unix/NetHack.xcodeproj/project.pbxproj b/sys/unix/NetHack.xcodeproj/project.pbxproj index 39863734e..044752f5f 100644 --- a/sys/unix/NetHack.xcodeproj/project.pbxproj +++ b/sys/unix/NetHack.xcodeproj/project.pbxproj @@ -626,6 +626,10 @@ F515A73B2DED0B47006E1F63 /* hacklib.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = hacklib.c; path = ../../src/hacklib.c; sourceTree = ""; }; F5457B1C2DED143E00039D83 /* libhacklib.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libhacklib.a; sourceTree = BUILT_PRODUCTS_DIR; }; F5457B202DED146B00039D83 /* hacklib.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = hacklib.c; path = ../../src/hacklib.c; sourceTree = ""; }; + F54C1AE12E43D22A006CAA8E /* nhmd4.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = nhmd4.h; path = /Volumes/T7/git/NHsource/include/nhmd4.h; sourceTree = ""; }; + F54C1AE22E43D22A006CAA8E /* savefile.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = savefile.h; path = /Volumes/T7/git/NHsource/include/savefile.h; sourceTree = ""; }; + F54C1AE32E43D22A006CAA8E /* sfmacros.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = sfmacros.h; path = /Volumes/T7/git/NHsource/include/sfmacros.h; sourceTree = ""; }; + F54C1AE42E43D22A006CAA8E /* sfprocs.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = sfprocs.h; path = /Volumes/T7/git/NHsource/include/sfprocs.h; sourceTree = ""; }; F5857AA32DED032C00A8CB4F /* cfgfiles.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = cfgfiles.c; path = ../../src/cfgfiles.c; sourceTree = ""; }; F5857AA52DED03BB00A8CB4F /* sfbase.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = sfbase.c; path = ../../src/sfbase.c; sourceTree = ""; }; /* End PBXFileReference section */ @@ -896,6 +900,10 @@ 3189579621A2046700FB2ABE /* include */ = { isa = PBXGroup; children = ( + F54C1AE12E43D22A006CAA8E /* nhmd4.h */, + F54C1AE22E43D22A006CAA8E /* savefile.h */, + F54C1AE32E43D22A006CAA8E /* sfmacros.h */, + F54C1AE42E43D22A006CAA8E /* sfprocs.h */, 3186A3B721A4B0FD0052BF02 /* align.h */, 3186A38821A4B0FB0052BF02 /* artifact.h */, 3186A3AB21A4B0FD0052BF02 /* artilist.h */, From b0076decae87c0c1ac11667776b03b6dca97caf5 Mon Sep 17 00:00:00 2001 From: Michael Allison Date: Wed, 6 Aug 2025 14:25:50 -0400 Subject: [PATCH 770/791] more Xcode follow-up --- sys/unix/NetHack.xcodeproj/project.pbxproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sys/unix/NetHack.xcodeproj/project.pbxproj b/sys/unix/NetHack.xcodeproj/project.pbxproj index 044752f5f..0ba3338fb 100644 --- a/sys/unix/NetHack.xcodeproj/project.pbxproj +++ b/sys/unix/NetHack.xcodeproj/project.pbxproj @@ -626,10 +626,10 @@ F515A73B2DED0B47006E1F63 /* hacklib.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = hacklib.c; path = ../../src/hacklib.c; sourceTree = ""; }; F5457B1C2DED143E00039D83 /* libhacklib.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libhacklib.a; sourceTree = BUILT_PRODUCTS_DIR; }; F5457B202DED146B00039D83 /* hacklib.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = hacklib.c; path = ../../src/hacklib.c; sourceTree = ""; }; - F54C1AE12E43D22A006CAA8E /* nhmd4.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = nhmd4.h; path = /Volumes/T7/git/NHsource/include/nhmd4.h; sourceTree = ""; }; - F54C1AE22E43D22A006CAA8E /* savefile.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = savefile.h; path = /Volumes/T7/git/NHsource/include/savefile.h; sourceTree = ""; }; - F54C1AE32E43D22A006CAA8E /* sfmacros.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = sfmacros.h; path = /Volumes/T7/git/NHsource/include/sfmacros.h; sourceTree = ""; }; - F54C1AE42E43D22A006CAA8E /* sfprocs.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = sfprocs.h; path = /Volumes/T7/git/NHsource/include/sfprocs.h; sourceTree = ""; }; + F54C1AE12E43D22A006CAA8E /* nhmd4.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = nhmd4.h; path = ../../include/include/nhmd4.h; sourceTree = ""; }; + F54C1AE22E43D22A006CAA8E /* savefile.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = savefile.h; path = ../../include/include/savefile.h; sourceTree = ""; }; + F54C1AE32E43D22A006CAA8E /* sfmacros.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = sfmacros.h; path = ../../include/include/sfmacros.h; sourceTree = ""; }; + F54C1AE42E43D22A006CAA8E /* sfprocs.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = sfprocs.h; path = ../../include/include/sfprocs.h; sourceTree = ""; }; F5857AA32DED032C00A8CB4F /* cfgfiles.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = cfgfiles.c; path = ../../src/cfgfiles.c; sourceTree = ""; }; F5857AA52DED03BB00A8CB4F /* sfbase.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = sfbase.c; path = ../../src/sfbase.c; sourceTree = ""; }; /* End PBXFileReference section */ From 2d6f0d74f2a4c52edfa8569d394d13ab74c2b223 Mon Sep 17 00:00:00 2001 From: PatR Date: Wed, 6 Aug 2025 15:33:57 -0700 Subject: [PATCH 771/791] fix pull request #1433 - silver mace Pull request from Umbire: starting gear for angelic beings should use recently added silver mace instead of old ordinary mace. It's simpler to just type in the change than to merge the commit. Fixes #1433 --- src/makemon.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/makemon.c b/src/makemon.c index f9578b586..c95fe8439 100644 --- a/src/makemon.c +++ b/src/makemon.c @@ -331,7 +331,7 @@ m_initweap(struct monst *mtmp) case S_ANGEL: if (humanoid(ptr)) { /* create minion stuff; bypass mongets */ - int typ = rn2(3) ? LONG_SWORD : MACE; + int typ = rn2(3) ? LONG_SWORD : SILVER_MACE; const char *nam = (typ == LONG_SWORD) ? "Sunsword" : "Demonbane"; otmp = mksobj(typ, FALSE, FALSE); @@ -346,7 +346,7 @@ m_initweap(struct monst *mtmp) /* make long sword be +0 to +3, mace be +3 to +6 to compensate for being significantly weaker against large opponents */ otmp->spe = rn2(4); - if (typ == MACE) + if (typ == SILVER_MACE) otmp->spe += 3; (void) mpickobj(mtmp, otmp); From 5fe7c4d12e4c5687ed4448b1c6a872291a7de60d Mon Sep 17 00:00:00 2001 From: nhmall Date: Wed, 6 Aug 2025 21:27:25 -0400 Subject: [PATCH 772/791] update tested versions of Visual Studio 2025-08-06 --- sys/windows/Makefile.nmake | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sys/windows/Makefile.nmake b/sys/windows/Makefile.nmake index 7aac1a3bf..53ad84616 100644 --- a/sys/windows/Makefile.nmake +++ b/sys/windows/Makefile.nmake @@ -9,7 +9,7 @@ # # Visual Studio Compilers Tested: # - Microsoft Visual Studio 2019 Community Edition v 16.11.42 -# - Microsoft Visual Studio 2022 Community Edition v 17.14.9 +# - Microsoft Visual Studio 2022 Community Edition v 17.14.11 # #============================================================================== # This is used for building two distinct executables of NetHack: @@ -1180,6 +1180,7 @@ rc=Rc.exe # Recently tested versions: TESTEDVS2019 = 14.29.30157.0 TESTEDVS2022 = 14.44.35213.0 +TESTEDVS2022 = 14.44.35214.0 VS2019CUR = $(TESTEDVS2019:.=) VS2022CUR = $(TESTEDVS2022:.=) From 70510f1dbc2a258f500777a1fe80c7c2db4fb897 Mon Sep 17 00:00:00 2001 From: nhmall Date: Wed, 6 Aug 2025 21:27:54 -0400 Subject: [PATCH 773/791] update visual studio sys/windows/vs/cpp.hint --- sys/windows/vs/cpp.hint | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/sys/windows/vs/cpp.hint b/sys/windows/vs/cpp.hint index 4f77429fe..3be7cc99a 100644 --- a/sys/windows/vs/cpp.hint +++ b/sys/windows/vs/cpp.hint @@ -4,3 +4,28 @@ #define E #define NDECL(x) x #define FDECL(x, y) x y +#define staticfn +#define NONNULL +#define NONNULLPTRS +#define NONNULLARG1 +#define NONNULLARG2 +#define NONNULLARG3 +#define NONNULLARG4 +#define NONNULLARG5 +#define NONNULLARG6 +#define NONNULLARG7 +#define NONNULLARG12 +#define NONNULLARG23 +#define NONNULLARG123 +#define NONNULLARG13 +#define NONNULLARG14 +#define NONNULLARG134 +#define NONNULLARG145 +#define NONNULLARG17 +#define NONNULLARG24 +#define NONNULLARG45 +#define NO_NNARGS +#define ATTRNORETURN +#define NORETURN +#define PRINTF_F + From dc48ff9f1e995856bb974f3aaef0ca010a12433e Mon Sep 17 00:00:00 2001 From: nhmall Date: Thu, 7 Aug 2025 20:05:38 -0400 Subject: [PATCH 774/791] remove UNUSED from prototype in util/sfexpasc.c --- util/sfexpasc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/util/sfexpasc.c b/util/sfexpasc.c index ecd0e6919..9f390633f 100644 --- a/util/sfexpasc.c +++ b/util/sfexpasc.c @@ -101,9 +101,9 @@ void exportascii_sfi_##dtyp(NHFILE *nhfp, dtyp *d_##dtyp, \ */ #define SF_C(keyw, dtyp) \ -void exportascii_sfo_##dtyp(NHFILE * UNUSED, keyw dtyp *d_##dtyp UNUSED, \ +void exportascii_sfo_##dtyp(NHFILE *, keyw dtyp *d_##dtyp UNUSED, \ const char *); \ -void exportascii_sfi_##dtyp(NHFILE *UNUSED, keyw dtyp *d_##dtyp, \ +void exportascii_sfi_##dtyp(NHFILE *, keyw dtyp *d_##dtyp, \ const char *); \ \ void exportascii_sfo_##dtyp(NHFILE *nhfp UNUSED, keyw dtyp *d_##dtyp UNUSED, \ @@ -116,8 +116,8 @@ void exportascii_sfi_##dtyp(NHFILE *nhfp UNUSED, keyw dtyp *d_##dtyp UNUSED, \ #define SF_X(xxx, dtyp) \ -void exportascii_sfo_##dtyp(NHFILE * UNUSED, xxx *d_##dtyp UNUSED, \ - const char * UNUSED); \ +void exportascii_sfo_##dtyp(NHFILE *, xxx *d_##dtyp, \ + const char *); \ void exportascii_sfi_##dtyp(NHFILE *, xxx *d_##dtyp, \ const char *); \ \ From 93803de4138ea282b171712b5bbf3dc0a5cae4df Mon Sep 17 00:00:00 2001 From: nhmall Date: Thu, 7 Aug 2025 21:41:25 -0400 Subject: [PATCH 775/791] work around an X11 build issue under C23 --- win/X11/winX.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/win/X11/winX.c b/win/X11/winX.c index 54c3579f6..1021c6ce3 100644 --- a/win/X11/winX.c +++ b/win/X11/winX.c @@ -100,7 +100,18 @@ int click_x, click_y, click_button; /* Click position on a map window int updated_inventory; /* used to indicate perm_invent updating */ color_attr X11_menu_promptstyle = { NO_COLOR, ATR_NONE }; -ATTRNORETURN static void X11_error_handler(String) NORETURN; +/* X11/Intrinsic.h prototype has an issue if [[NORETURN]] is used + * rather than the old __attribute((noreturn)) under c23 */ +#if defined(__GNUC__) || defined(__clang__) +#define USE_GNUC_PROTO +#endif + +#ifdef USE_GNUC_PROTO +static void X11_error_handler(String) __attribute__((noreturn)); +#else +ATTRNORETURN static XtErrorHandler X11_error_handler(String); +#endif + static int X11_io_error_handler(Display *); static int (*old_error_handler)(Display *, XErrorEvent *); From b876381b72ba11667a1d54a097c400334275247e Mon Sep 17 00:00:00 2001 From: nhmall Date: Thu, 7 Aug 2025 21:47:40 -0400 Subject: [PATCH 776/791] add support for [[maybe_unused]] if available --- include/tradstdc.h | 16 ++++++++++++++++ src/report.c | 4 +++- win/share/tilemap.c | 7 +++++-- 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/include/tradstdc.h b/include/tradstdc.h index adcfa0619..4c304b625 100644 --- a/include/tradstdc.h +++ b/include/tradstdc.h @@ -389,6 +389,14 @@ typedef genericptr genericptr_t; /* (void *) or (char *) */ #define FALLTHROUGH [[fallthrough]] /* #warning [[fallthrough]] from C23 */ #endif /* __has_c_attribute(fallthrough) */ +/* + * maybe_unused + */ +#if __has_c_attribute(maybe_unused) +#ifndef ATTRUNUSED +#define ATTRUNUSED [[maybe_unused]] +#endif +#endif /* __has_c_attribute(maybe_unused) */ #endif /* NH_C >= 202300L */ /* @@ -416,7 +424,9 @@ typedef genericptr genericptr_t; /* (void *) or (char *) */ #define PRINTF_F_PTR(f, v) PRINTF_F(f, v) #endif #if __GNUC__ >= 3 +#ifndef ATTRUNUSED #define UNUSED __attribute__((unused)) +#endif #ifndef ATTRNORETURN #ifndef NORETURN #define NORETURN __attribute__((noreturn)) @@ -496,6 +506,9 @@ typedef genericptr genericptr_t; /* (void *) or (char *) */ #define NH_PRAGMA_MESSAGE 1 #endif /* _MSC_VER */ +#if !defined(UNUSED) && defined(ATTRUNUSED) +#define UNUSED ATTRUNUSED +#endif /* Fallback implementations */ #ifndef PRINTF_F @@ -507,6 +520,9 @@ typedef genericptr genericptr_t; /* (void *) or (char *) */ #ifndef UNUSED #define UNUSED #endif +#ifndef ATTRUNUSED +#define ATTRUNUSED +#endif #ifndef FALLTHROUGH #define FALLTHROUGH #endif diff --git a/src/report.c b/src/report.c index 3eb8fd5aa..ecfa0ad17 100644 --- a/src/report.c +++ b/src/report.c @@ -110,7 +110,7 @@ static char bid[40]; /* ARGSUSED */ void -crashreport_init(int argc UNUSED, char *argv[] UNUSED) +crashreport_init(int argc, char *argv[]) { static int once = 0; if (once++) /* NetHackW.exe calls us twice */ @@ -169,6 +169,8 @@ crashreport_init(int argc UNUSED, char *argv[] UNUSED) Strcpy(bid, "unknown"); HASH_CLEANUP(ctxp); HASH_PRAGMA_END + nhUse(argc); + nhUse(argv); } #undef HASH_CONTEXTPTR diff --git a/win/share/tilemap.c b/win/share/tilemap.c index a28cd8c76..832bae769 100644 --- a/win/share/tilemap.c +++ b/win/share/tilemap.c @@ -1311,7 +1311,7 @@ extern void objects_globals_init(void); DISABLE_WARNING_UNREACHABLE_CODE int -main(int argc UNUSED, char *argv[] UNUSED) +main(int argc, char *argv[]) { int i, tilenum; char filename[30]; @@ -1395,6 +1395,8 @@ main(int argc UNUSED, char *argv[] UNUSED) free_tilerefs(); exit(EXIT_SUCCESS); /*NOTREACHED*/ + nhUse(argc); + nhUse(argv); return 0; } @@ -1491,7 +1493,7 @@ add_tileref( const char *prefix) { struct tiles_used temp = { 0 }; - static const char ellipsis[] UNUSED = "..."; + static const char ellipsis[] = "..."; char buf[BUFSZ]; if (!tilelist[n]) { @@ -1519,6 +1521,7 @@ add_tileref( (strlen(temp.references) >= (sizeof temp.references - 7) - 1) ? buf : ""); + nhUse(ellipsis); } void From 4bde4b439d3bf24fe5e88b7d0be8575e8fdd75af Mon Sep 17 00:00:00 2001 From: PatR Date: Fri, 8 Aug 2025 13:41:27 -0700 Subject: [PATCH 777/791] 'opthelp' tidbit Data typo affecting '?' command's "longer explanation of game options". Change the indication of menu_objsym's default value from [5] to [4] since 4 is the actual default value in the code and the Guidebook. --- dat/opthelp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dat/opthelp b/dat/opthelp index 16106b16c..d36e5228b 100644 --- a/dat/opthelp +++ b/dat/opthelp @@ -189,7 +189,7 @@ menustyle user interface for selection of multiple objects: [Full] only the first letter ('T','C','F','P') matters (With Traditional, many actions allow pseudo-class 'm' to request a menu for choosing items: one-shot Combination.) -menu_objsyms whether to include object class symbols in menus: [5] +menu_objsyms whether to include object class symbols in menus: [4] 0 - none -- don't add object symbols to menus; 1 - headers -- append object class symbol to menu header lines; 2 - entries -- show object glyphs (same as class symbol From 407a2e0ea8d0ccf7f0d575d8567abeebf73e14cb Mon Sep 17 00:00:00 2001 From: PatR Date: Sun, 10 Aug 2025 12:45:29 -0700 Subject: [PATCH 778/791] fix issue #1436 - object_from_map() vs Hallu Issue reported by janne-hmp: examining an object on the map while halluicinating might operate on an object whose name is Null since the random object could be one that holds an extra description for item shuffling at game start. Attempting to format the object led to a crash. I wasn't able to reproduce the crash, possibly because MacOS produces the string "(null)" for sprintf("%s",NULL) instead of dereferencing the Null pointer. Perhaps random object selection for display should reject the extra description objects in some classes. This susbstitutes a different object if examining the map encounters one of those. Fixes #1436 --- doc/fixes3-7-0.txt | 3 +++ src/pager.c | 15 ++++++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index d19a70a6e..fb87d1121 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -1525,6 +1525,9 @@ a vampire lord could choose to take on wolf form while flying over water or lava, then revert to vampire lord form and teleport unnecessarily a gas spore that was killed when an engulfer swallowed it produced an explosion on the map rather than inside the engulfer +hallucination can display objects on the map that have a description (for + shuffling into play at game start) but no name; examining those might + trigger a crash Fixes to 3.7.0-x General Problems Exposed Via git Repository diff --git a/src/pager.c b/src/pager.c index e2e0c06a9..061937687 100644 --- a/src/pager.c +++ b/src/pager.c @@ -312,7 +312,20 @@ object_from_map( if (!otmp || otmp->otyp != glyphotyp) { /* this used to exclude STRANGE_OBJECT; now caller deals with it */ - otmp = mksobj(glyphotyp, FALSE, FALSE); + if (OBJ_NAME(objects[glyphotyp])) { + /* map shows a regular object, but one that's not actually here */ + otmp = mksobj(glyphotyp, FALSE, FALSE); + } else { + /* map shows a non-item that holds an extra object type (shown + on map due to hallucination) for a name which might have been + shuffled into play but wasn't (or was shuffled out of play); + pick another item that is a regular one in same object class */ + otmp = mkobj(objects[glyphotyp].oc_class, FALSE); + /* mkobj() doesn't provide any no-init option; however, there + aren't any extra tool items (or statues) so we won't get here + for tools and don't need to check for and delete container + contents or extinguish lights on the temporary object */ + } /* even though we pass False for mksobj()'s 'init' arg, corpse-rot, egg-hatch, and figurine-transform timers get initialized */ if (otmp->timed) From 351ed094b4e499435847f9ef21e145061a0c67fd Mon Sep 17 00:00:00 2001 From: PatR Date: Mon, 11 Aug 2025 15:28:11 -0700 Subject: [PATCH 779/791] fix? github issue #1431 - init_role_redist() Issue reported by vultur-cadens: 3.7's revised handling for initial characteristic allocation included an unintended change from 3.6's. I don't pretend to understand how characteristic allocation really works. This should restore handling for values which are too low. Fixes #1431 --- src/attrib.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/attrib.c b/src/attrib.c index 079607c1b..fc6a7aebf 100644 --- a/src/attrib.c +++ b/src/attrib.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 attrib.c $NHDT-Date: 1726168587 2024/09/12 19:16:27 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.129 $ */ +/* NetHack 3.7 attrib.c $NHDT-Date: 1754979443 2025/08/11 22:17:23 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.134 $ */ /* Copyright 1988, 1989, 1990, 1992, M. Stephenson */ /* NetHack may be freely redistributed. See license for details. */ @@ -701,7 +701,9 @@ init_attr_role_redist(int np, boolean addition) while ((addition ? (np > 0) : (np < 0)) && tryct < 100) { int i = rnd_attr(); - if (i >= A_MAX || ABASE(i) >= ATTRMAX(i)) { + if (i >= A_MAX + || (addition ? (ABASE(i) >= ATTRMAX(i)) + : (ABASE(i) <= ATTRMIN(i)))) { tryct++; continue; } From 8f4c0f22159da2db6219e6c2eb23e7241e0647b2 Mon Sep 17 00:00:00 2001 From: Alex Smith Date: Sat, 16 Aug 2025 01:24:58 +0100 Subject: [PATCH 780/791] You can throw objects at mimics if you know there's a monster there Part of the reasoning behind thrown objects not hitting mimics is that a character who doesn't know there's a mimic there wouldn't aim at it. But if you know there's a monster there (e.g. via telepathy or monster detection), you would aim at it. Pushing a boulder at it and hearing a monster works too (which is important in cases where a mimic is trapped behind a boulder in the Sokoban corridors). --- src/zap.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/zap.c b/src/zap.c index efd60f1fe..a1a5c3380 100644 --- a/src/zap.c +++ b/src/zap.c @@ -3854,6 +3854,7 @@ bhit( while (range-- > 0) { coordxy x, y; + int xyglyph; gb.bhitpos.x += ddx; gb.bhitpos.y += ddy; @@ -3962,10 +3963,15 @@ bhit( because the hero is likely aiming to throw over what seems to be an object rather than at it, and for balance because otherwise mimics are too easy to identify by throwing gold at - them) */ + them); exception: if the hero knows there is a monster there, + they will be aiming at the monster */ + xyglyph = glyph_at(x, y); if (mtmp && (((weapon == THROWN_WEAPON || weapon == KICKED_WEAPON) && (shade_miss(&gy.youmonst, mtmp, obj, TRUE, TRUE) - || M_AP_TYPE(mtmp) == M_AP_OBJECT)) + || (M_AP_TYPE(mtmp) == M_AP_OBJECT + && !glyph_is_monster(xyglyph) + && !glyph_is_warning(xyglyph) + && !glyph_is_invisible(xyglyph)))) || (weapon == FLASHED_LIGHT && M_AP_TYPE(mtmp) == M_AP_OBJECT))) mtmp = (struct monst *) 0; From 16716c2d3ae529297f6a18b609910d1128fef1d8 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 16 Aug 2025 12:38:58 -0400 Subject: [PATCH 781/791] update tested versions of Visual Studio 2025-08-16 --- sys/windows/Makefile.nmake | 17 +- sys/windows/vs/NetHack/NetHack.vcxproj | 26 +- sys/windows/vs/NetHackW/NetHackW.vcxproj | 33 +-- sys/windows/vs/lualib/lualib.vcxproj | 363 +++-------------------- 4 files changed, 71 insertions(+), 368 deletions(-) diff --git a/sys/windows/Makefile.nmake b/sys/windows/Makefile.nmake index 53ad84616..c76201a4f 100644 --- a/sys/windows/Makefile.nmake +++ b/sys/windows/Makefile.nmake @@ -9,7 +9,7 @@ # # Visual Studio Compilers Tested: # - Microsoft Visual Studio 2019 Community Edition v 16.11.42 -# - Microsoft Visual Studio 2022 Community Edition v 17.14.11 +# - Microsoft Visual Studio 2022 Community Edition v 17.14.12 # #============================================================================== # This is used for building two distinct executables of NetHack: @@ -1293,25 +1293,34 @@ scall = !IF ($(VSVER) >= 2012) # # 4100 unreferenced formal parameter +# 4101 'identifier': unreferenced local variable +# 4102 'label': unreferenced label # 4131 old-style declarator +# 4201 'nonstandard extension used : nameless struct/union' # 4244 conversion possible loss of data # 4245 conversion from 'char' to 'uchar', signed/unsigned mismatch # 4310 a constant value is cast to a smaller type +# 4324 'structname': structure was padded due to alignment specifier +# 4431 missing type specifier - int assumed. Note: C no longer supports default-int # 4706 assignment within conditional # 4774 format string is not a string literal (default is off at W4) # 4777 format string requires an argument of type 'type', # but variadic argument 'position' has type 'type' # 4820 padding in struct # 5262 enable fallthrough warnings that lack [[fallthrough]] +# 5264 'variable-name': 'const' variable is not used +# 5266 'const' qualifier on return type has no effect +# 6001 'Using uninitialized memory' # -ctmpflags = $(ctmpflags:-W3=-W4) -wd4100 -wd4244 -wd4245 -wd4310 -wd4706 -w44777 -wd4820 +#ctmpflags = $(ctmpflags:-W3=-W4) -wd4100 -wd4244 -wd4245 -wd4310 -wd4706 +ctmpflags = $(ctmpflags:-W3=-W4) -wd4244 -wd4245 -wd4310 -wd4706 -w44101 -w44102 !IF ($(VSVER) >= 2019) ctmpflags = $(ctmpflags) -w44774 !ENDIF !IF ($(VSVER) >= 2022) !IF ($(MAKEVERSION) >= 1440338120) # warning 5262 became available starting in Visual Studio 2022 version 17.4. -ctmpflags = $(ctmpflags) -w45262 /std:clatest +ctmpflags = $(ctmpflags) -w45262 -w45264 -w45266 -w44431 -w44777 -wd4820 /std:clatest !ENDIF !ENDIF !ENDIF @@ -2475,7 +2484,7 @@ $(DAT)bogusmon: $(U)makedefs.exe $(DAT)bogusmon.txt $(U)makedefs -3 # This is the universal ctags utility which produces the tags in the -# format that util/readtags requires. +# format that util/readtags requires. # https://github.com/universal-ctags/ctags.git #=============================================================================== diff --git a/sys/windows/vs/NetHack/NetHack.vcxproj b/sys/windows/vs/NetHack/NetHack.vcxproj index 48ba1d27e..7b28b0837 100644 --- a/sys/windows/vs/NetHack/NetHack.vcxproj +++ b/sys/windows/vs/NetHack/NetHack.vcxproj @@ -41,35 +41,20 @@ /Gs /Oi- /w44774 /w45262 %(AdditionalOptions) + 4100;4244;4245;4310;4706;4820;4324 Disabled Default Speed true $(WinWin32Dir);$(IncDir);$(SysWindDir);$(SysShareDir);$(WinShareDir);$(LuaDir);%(AdditionalIncludeDirectories) WIN32CON;NO_TILE_C;DLB;SAFEPROCS;SND_LIB_WINDSOUND;USER_SOUNDS;_LIB;HAS_STDINT_H;%(PreprocessorDefinitions) - stdclatest - stdclatest - stdclatest - stdclatest - /Gs /Oi- /w44774 /w45262 %(AdditionalOptions) - /Gs /Oi- /w44774 /w45262 %(AdditionalOptions) - /Gs /Oi- /w44774 /w45262 %(AdditionalOptions) - /Gs /Oi- /w44774 /w45262 %(AdditionalOptions) + stdclatest hacklib.lib;lualib.lib;kernel32.lib;dbghelp.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;winmm.lib;Winmm.lib;UserEnv.lib;bcrypt.lib;%(AdditionalDependencies) - $(SndWavDir);%(AdditionalIncludeDirectories) - - - $(SndWavDir);%(AdditionalIncludeDirectories) - - - $(SndWavDir);%(AdditionalIncludeDirectories) - - - $(SndWavDir);%(AdditionalIncludeDirectories) + $(SndWavDir);%(AdditionalIncludeDirectories) @@ -139,10 +124,7 @@ - - 4820;4706;4244;4245;4100;4310;4324 - 4820;4706;4244;4245;4100;4310;4324 - + diff --git a/sys/windows/vs/NetHackW/NetHackW.vcxproj b/sys/windows/vs/NetHackW/NetHackW.vcxproj index 0fb4f77e3..11e6baa99 100644 --- a/sys/windows/vs/NetHackW/NetHackW.vcxproj +++ b/sys/windows/vs/NetHackW/NetHackW.vcxproj @@ -48,7 +48,8 @@ - /Gs /Oi- /w44774 %(AdditionalOptions) + /Gs /Oi- /w44774 /w45262 %(AdditionalOptions) + 4100;4244;4245;4310;4706;4820;4324 Disabled true $(WinWin32Dir);$(IncDir);$(SysWindDir);$(SysShareDir);$(WinShareDir);$(LuaDir);%(AdditionalIncludeDirectories) @@ -57,12 +58,6 @@ stdclatest stdclatest stdclatest - /Gs /Oi- /w44774 /w45262 %(AdditionalOptions) - /Gs /Oi- /w44774 /w45262 %(AdditionalOptions) - /Gs /Oi- /w44774 /w45262 %(AdditionalOptions) - /Gs /Oi- /w44774 /w45262 %(AdditionalOptions) - 4820;4706;4244;4245;4100;4310;6001 - 4820;4706;4244;4245;4100;4310 NDEBUG;%(PreprocessorDefinitions) @@ -148,17 +143,15 @@ - 4820;4706;4244;4245;4100;4310;4324 - 4820;4706;4244;4245;4100;4310;4324 + 4100;4244;4245;4310;4706;4820;4324 + 4100;4244;4245;4310;4706;4820;4324 - - 4820;4706;4244;4245;4100;4310;6001 - + @@ -192,9 +185,7 @@ - - 4820;4706;4244;4245;4100;4310;6001 - + @@ -218,17 +209,15 @@ - - 4820;4706;4244;4245;4100;4310;6001 - + - 4820;4706;4244;4245;4100;4310;4201 - 4820;4706;4244;4245;4100;4310;4201 - 4820;4706;4244;4245;4100;4310;4201 - 4820;4706;4244;4245;4100;4310;4201 + 4100;4201;4244;4245;4310;4706;4820;4324 + 4100;4201;4244;4245;4310;4706;4820;4324 + 4100;4201;4244;4245;4310;4706;4820;4324 + 4100;4201;4244;4245;4310;4706;4820 diff --git a/sys/windows/vs/lualib/lualib.vcxproj b/sys/windows/vs/lualib/lualib.vcxproj index 13c01453e..48cbb9f35 100644 --- a/sys/windows/vs/lualib/lualib.vcxproj +++ b/sys/windows/vs/lualib/lualib.vcxproj @@ -24,327 +24,50 @@ x64 + + + /Gs /Oi- /w44774 /w45262 %(AdditionalOptions) + 4100;4244;4245;4310;4706;4820;4324 + Disabled + true + $(WinWin32Dir);$(IncDir);$(SysWindDir);$(SysShareDir);$(WinShareDir);$(LuaDir);%(AdditionalIncludeDirectories) + TILES;_WINDOWS;DLB;MSWIN_GRAPHICS;SAFEPROCS;NOTTYGRAPHICS;SND_LIB_WINDSOUND;USER_SOUNDS;HAS_STDINT_H;PDC_WIDE;%(PreprocessorDefinitions) + stdclatest + + - - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - - - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - - - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - - - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - - - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - - - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - - - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - - - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - - - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - - - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - - - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - - - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - - - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - - - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - - - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - - - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - - - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - - - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - - - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - - - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - - - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - - - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - - - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - - - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - - - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - - - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - - - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - - - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - - - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - - - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - - - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - - - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - 4701;4702;4244;4310;4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - %(AdditionalOptions) /wd4774 - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 17.0 From 070730d8459ab7286ce10be9be9557490b8d73be Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 17 Aug 2025 01:33:24 -0400 Subject: [PATCH 782/791] Qt6 wasn't exiting as expected after saving the game Reported by email to devteam on Feb 1, 2025. --- include/hack.h | 1 + src/save.c | 1 + win/Qt/qt_bind.cpp | 4 ++++ 3 files changed, 6 insertions(+) diff --git a/include/hack.h b/include/hack.h index 99eaca753..361b95cd3 100644 --- a/include/hack.h +++ b/include/hack.h @@ -801,6 +801,7 @@ struct sinfo { int in_sanity_check; /* for impossible() during sanity checking */ int config_error_ready; /* config_error_add is ready, available */ int beyond_savefile_load; /* set when past savefile loading */ + int savefile_completed; /* savefile has completed writing */ #ifdef PANICLOG int in_paniclog; /* writing a panicloc entry */ #endif diff --git a/src/save.c b/src/save.c index aa9e32c3d..9dc8a3f7b 100644 --- a/src/save.c +++ b/src/save.c @@ -54,6 +54,7 @@ dosave(void) program_state.done_hup = 0; #endif if (dosave0()) { + program_state.savefile_completed++; u.uhp = -1; /* universal game's over indicator */ if (soundprocs.sound_exit_nhsound) (*soundprocs.sound_exit_nhsound)("dosave"); diff --git a/win/Qt/qt_bind.cpp b/win/Qt/qt_bind.cpp index 75a3620c1..58dc96476 100644 --- a/win/Qt/qt_bind.cpp +++ b/win/Qt/qt_bind.cpp @@ -724,6 +724,10 @@ char NetHackQtBind::qt_more() int complain = 0; do { ch = NetHackQtBind::qt_nhgetch(); + if (::program_state.savefile_completed) { + retry = false; + break; + } switch (ch) { case '\0': // hypothetical ch = '\033'; From 6c3e70ad777aaf0d4279b34233e1092bf5ea8536 Mon Sep 17 00:00:00 2001 From: nhmall Date: Tue, 19 Aug 2025 08:35:39 -0400 Subject: [PATCH 783/791] remove stray tabs from *.c files and config.h --- include/config.h | 2 +- src/bones.c | 2 +- src/files.c | 2 +- src/restore.c | 2 +- src/save.c | 4 ++-- src/sfstruct.c | 4 ++-- sys/msdos/vidtxt.c | 10 +++++----- sys/unix/unixmain.c | 6 +++--- sys/vms/vmsmain.c | 2 +- util/dlb_main.c | 14 +++++++------- util/recover.c | 2 +- util/sfctool.c | 18 +++++++++--------- util/sftags.c | 16 ++++++++-------- util/stripbs.c | 14 +++++++------- win/curses/cursmain.c | 8 ++++---- win/win32/mhmap.c | 2 +- win/win32/mhsplash.c | 2 +- win/win32/mswproc.c | 4 ++-- 18 files changed, 57 insertions(+), 57 deletions(-) diff --git a/include/config.h b/include/config.h index f14273810..7069b268d 100644 --- a/include/config.h +++ b/include/config.h @@ -273,7 +273,7 @@ # endif # ifdef __linux__ # define PANICTRACE -# ifndef NOSTATICFN // may be defined on command line +# ifndef NOSTATICFN // may be defined on command line # define NOSTATICFN # endif # endif diff --git a/src/bones.c b/src/bones.c index 922737fe1..5afb0cbcd 100644 --- a/src/bones.c +++ b/src/bones.c @@ -614,7 +614,7 @@ savebones(int how, time_t when, struct obj *corpse) /* if a bones pool digit is in use, it precedes the bonesid string and isn't recorded in the file */ Sfo_char(nhfp, &c, "bones_count", 1); - Sfo_char(nhfp, bonesid, "bonesid", (int) c); /* DD.nnn */ + Sfo_char(nhfp, bonesid, "bonesid", (int) c); /* DD.nnn */ savefruitchn(nhfp); update_mlstmv(); /* update monsters for eventual restoration */ savelev(nhfp, ledger_no(&u.uz)); diff --git a/src/files.c b/src/files.c index ab4ba9ed8..c984c673e 100644 --- a/src/files.c +++ b/src/files.c @@ -2106,7 +2106,7 @@ make_converted_name(const char *filename) #endif /* UNIX || WIN32 */ if (dir) { finaldirchar = c_eos(dir); - finaldirchar--; + finaldirchar--; if (!(*finaldirchar == '/' || *finaldirchar == '\\' || *finaldirchar == ':')) { needsep = TRUE; diff --git a/src/restore.c b/src/restore.c index bf2376c4e..59bc231ad 100644 --- a/src/restore.c +++ b/src/restore.c @@ -860,7 +860,7 @@ dorecover(NHFILE *nhfp) restoreinfo.mread_flags = 1; /* return despite error */ while (1) { Sfi_xint8(nhfp, <mp, "gamestate-level_number"); - if (nhfp->eof) + if (nhfp->eof) break; getlev(nhfp, 0, ltmp); #ifdef MICRO diff --git a/src/save.c b/src/save.c index 9dc8a3f7b..57c8bfb41 100644 --- a/src/save.c +++ b/src/save.c @@ -54,7 +54,7 @@ dosave(void) program_state.done_hup = 0; #endif if (dosave0()) { - program_state.savefile_completed++; + program_state.savefile_completed++; u.uhp = -1; /* universal game's over indicator */ if (soundprocs.sound_exit_nhsound) (*soundprocs.sound_exit_nhsound)("dosave"); @@ -564,7 +564,7 @@ savelevl(NHFILE *nhfp) for (x = 0; x < COLNO; x++) { for (y = 0; y < ROWNO; y++) { Sfo_rm(nhfp, &levl[x][y], "location-rm"); - } + } } return; } diff --git a/src/sfstruct.c b/src/sfstruct.c index c62b46405..6014d97b2 100644 --- a/src/sfstruct.c +++ b/src/sfstruct.c @@ -506,7 +506,7 @@ bwrite(int fd, const genericptr_t loc, unsigned num) fprintf(ofp[fd], "%08ld, %08ld, %d\n", ocnt, ftell(ofp[fd]), num); ocnt++; - } + } } #endif @@ -559,7 +559,7 @@ mread(int fd, genericptr_t buf, unsigned len) fprintf(ifp[fd], "%08ld, %08ld, %d\n", icnt, ftell(ifp[fd]), (int) len); icnt++; - } + } } #endif diff --git a/sys/msdos/vidtxt.c b/sys/msdos/vidtxt.c index 680f23e3c..990d6d064 100644 --- a/sys/msdos/vidtxt.c +++ b/sys/msdos/vidtxt.c @@ -40,10 +40,10 @@ extern int attrib_gr_intense; /* graphics mode intense attribute */ #if defined(SCREEN_BIOS) && !defined(PC9800) static unsigned char cursor_info = 0, - cursor_start_scanline = 6, cursor_end_scanline = 7; + cursor_start_scanline = 6, cursor_end_scanline = 7; static void get_cursinfo(unsigned char *start, unsigned char *end, - unsigned char *flg); + unsigned char *flg); #endif void @@ -414,8 +414,8 @@ void txt_get_cursor(int *x, int *y) *y = regs.h.dh; if (!cursor_info) { cursor_start_scanline = regs.h.ch; - cursor_end_scanline = regs.h.cl; - cursor_info = 1; + cursor_end_scanline = regs.h.cl; + cursor_info = 1; } } @@ -464,7 +464,7 @@ get_cursinfo(uchar *start, uchar *end, uchar *flg) *end = regs.h.cl; } else { *start = 6; - *end = 7; + *end = 7; } *flg = 1; } diff --git a/sys/unix/unixmain.c b/sys/unix/unixmain.c index 06bc853e6..e74cfc8c5 100644 --- a/sys/unix/unixmain.c +++ b/sys/unix/unixmain.c @@ -707,10 +707,10 @@ early_options(int *argc_p, char ***argv_p, char **hackdir_p) break; case 's': if (argcheck(argc, argv, ARG_SHOWPATHS) == 2) { - gd.deferred_showpaths = TRUE; - gd.deferred_showpaths_dir = *hackdir_p; + gd.deferred_showpaths = TRUE; + gd.deferred_showpaths_dir = *hackdir_p; config_error_done(); - return; + return; } /* check for "-s" request to show scores */ if (lopt(arg, ((ArgValDisallowed | ArgErrComplain) diff --git a/sys/vms/vmsmain.c b/sys/vms/vmsmain.c index 25c40b842..7b52691ea 100644 --- a/sys/vms/vmsmain.c +++ b/sys/vms/vmsmain.c @@ -82,7 +82,7 @@ main(int argc, char *argv[]) if (argcheck(argc, argv, ARG_SHOWPATHS) == 2) { gd.deferred_showpaths = TRUE; return; - } + } if (argcheck(argc, argv, ARG_DEBUG) == 1) { argc--; argv++; diff --git a/util/dlb_main.c b/util/dlb_main.c index 27310b303..1926b871d 100644 --- a/util/dlb_main.c +++ b/util/dlb_main.c @@ -67,14 +67,14 @@ static char origdir[255] = ""; * * dlb COMMANDoptions arg... files... * commands: - * dlb x extract all files - * dlb c build the archive - * dlb t list the archive + * dlb x extract all files + * dlb c build the archive + * dlb t list the archive * options: - * v verbose - * f file specify archive file (default DLBFILE) - * I file specify file for list of files (default LIBLISTFILE) - * C dir chdir to dir (used ONCE, not like tar's -C) + * v verbose + * f file specify archive file (default DLBFILE) + * I file specify file for list of files (default LIBLISTFILE) + * C dir chdir to dir (used ONCE, not like tar's -C) */ ATTRNORETURN static void diff --git a/util/recover.c b/util/recover.c index f43d1132c..508263675 100644 --- a/util/recover.c +++ b/util/recover.c @@ -1,5 +1,5 @@ /* NetHack 3.7 recover.c $NHDT-Date: 1687547437 2023/06/23 19:10:37 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.33 $ */ -/* Copyright (c) Janet Walz, 1992. */ +/* Copyright (c) Janet Walz, 1992. */ /* NetHack may be freely redistributed. See license for details. */ /* diff --git a/util/sfctool.c b/util/sfctool.c index d1ecaaceb..8bfc3ccde 100644 --- a/util/sfctool.c +++ b/util/sfctool.c @@ -1,5 +1,5 @@ /* NetHack 3.7 sfctool.c */ -/* Copyright (c) Michael Allison, 2025. */ +/* Copyright (c) Michael Allison, 2025. */ /* NetHack may be freely redistributed. See license for details. */ /* @@ -318,18 +318,18 @@ process_savefile(const char *srcfnam, enum saveformats srcstyle, cscbuf[5]); /* ptr */ if (sfstatus > SF_UPTODATE && ((sfstatus <= SF_CRITICAL_BYTE_COUNT_MISMATCH) || !unconvert)) { - if (sfstatus == SF_OUTDATED) { + if (sfstatus == SF_OUTDATED) { fprintf(stderr, "The %s savefile is outdated with respect to this %d.%d.%d EDITLEVEL %ld " - "%s%s%s.\n", + "%s%s%s.\n", briefname(srcfnam), - VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL, - (long) EDITLEVEL, + VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL, + (long) EDITLEVEL, thisdatamodel ? thisdatamodel : "", thisdatamodel ? " " : "", - "sfctool"); + "sfctool"); return 0; - } else { + } else { fprintf(stderr, "The %s savefile %s%s%s not compatible with this %s%s %s utility.\n", briefname(srcfnam), @@ -338,9 +338,9 @@ process_savefile(const char *srcfnam, enum saveformats srcstyle, dmfile ? " savefile, thus" : " is", thisdatamodel ? thisdatamodel : "", thisdatamodel ? " " : "", - "sfctool"); + "sfctool"); return 0; - } + } } if (sfstatus >= SF_DM_IL32LLP64_ON_ILP32LL64) { renidx = sfstatus - SF_DM_IL32LLP64_ON_ILP32LL64; diff --git a/util/sftags.c b/util/sftags.c index 5f055a60e..3a04cb94d 100644 --- a/util/sftags.c +++ b/util/sftags.c @@ -1,9 +1,9 @@ /* NetHack 3.6 sftags.c $Date$ $Revision$ */ -/* Copyright (c) Michael Allison, 2025 */ +/* Copyright (c) Michael Allison, 2025 */ /* NetHack may be freely redistributed. See license for details. */ /* - * Read the given ctags file and generate: + * Read the given ctags file and generate: * Intermediate temp files: * include/sfo_proto.tmp * include/sfi_proto.tmp @@ -45,12 +45,12 @@ #endif #endif -#define NHTYPE_SIMPLE 1 -#define NHTYPE_COMPLEX 2 +#define NHTYPE_SIMPLE 1 +#define NHTYPE_COMPLEX 2 struct nhdatatypes_t { - uint dtclass; - char *dtype; - size_t dtsize; + uint dtclass; + char *dtype; + size_t dtsize; }; struct tagstruct { @@ -867,7 +867,7 @@ findtype(char *st, char *tag) /* comma or semicolon immediately following tag */ else { volatile int y = 0; - nhUse(y); + nhUse(y); y = 1; } if (strncmpi(ftbuf, "struct ", 7) == 0) diff --git a/util/stripbs.c b/util/stripbs.c index fbe8316c6..15d319566 100644 --- a/util/stripbs.c +++ b/util/stripbs.c @@ -28,16 +28,16 @@ int main(int argc UNUSED, char *argv[] UNUSED) while (!stop) { if ((fread(buf, 1, 1, stdin)) > 0) { if (*cp == 8) { - *prev = 0; - } else { - if (*prev) + *prev = 0; + } else { + if (*prev) fputc(*prev, stdout); - *prev = *cp; - } + *prev = *cp; + } } else { - if (errno != EOF) + if (errno != EOF) trouble = 1; - if (*prev) + if (*prev) fputc(*prev, stdout); stop = 1; } diff --git a/win/curses/cursmain.c b/win/curses/cursmain.c index 326f7999b..77d1013f6 100644 --- a/win/curses/cursmain.c +++ b/win/curses/cursmain.c @@ -622,7 +622,7 @@ curses_putmixed(winid window, int attr, const char *str) /* now send buf to the normal putstr */ curses_putstr(window, attr, buf); done_output = TRUE; - } + } } if (!done_output) { @@ -824,11 +824,11 @@ curses_ctrl_nhwindow( case request_settings: break; case set_menu_promptstyle: - curses_menu_promptstyle.color = wri->fromcore.menu_promptstyle.color; + curses_menu_promptstyle.color = wri->fromcore.menu_promptstyle.color; if (curses_menu_promptstyle.color == NO_COLOR) curses_menu_promptstyle.color = NONE; - attr = wri->fromcore.menu_promptstyle.attr; - curses_menu_promptstyle.attr = curses_convert_attr(attr);; + attr = wri->fromcore.menu_promptstyle.attr; + curses_menu_promptstyle.attr = curses_convert_attr(attr);; break; default: break; diff --git a/win/win32/mhmap.c b/win/win32/mhmap.c index a3f46c39d..d5e6b116e 100644 --- a/win/win32/mhmap.c +++ b/win/win32/mhmap.c @@ -764,7 +764,7 @@ onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) msg_data->buffer[index++] = '\r'; msg_data->buffer[index++] = '\n'; } - nhUse(mgch); + nhUse(mgch); } break; #ifdef ENHANCED_SYMBOLS diff --git a/win/win32/mhsplash.c b/win/win32/mhsplash.c index 5c5ef6328..5609bab89 100644 --- a/win/win32/mhsplash.c +++ b/win/win32/mhsplash.c @@ -259,7 +259,7 @@ NHSplashWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) DrawText(hdc, VersionString, strlen(VersionString), &rt, DT_LEFT | DT_NOPREFIX); EndPaint(hWnd, &ps); - nhUse(OldFont); + nhUse(OldFont); } break; case WM_COMMAND: diff --git a/win/win32/mswproc.c b/win/win32/mswproc.c index 8f5c4cc45..06464c6de 100644 --- a/win/win32/mswproc.c +++ b/win/win32/mswproc.c @@ -379,8 +379,8 @@ prompt_for_player_selection(void) * bottom of the window. */ /* tty_clear_nhwindow(BASE_WINDOW) */ - ; - } + ; + } if (pick4u != 'y' && pick4u != 'n') { give_up: /* Quit */ if (selected) From 16c723f0be86e4a8648d4e5d974c944a5556cd29 Mon Sep 17 00:00:00 2001 From: nhmall Date: Tue, 19 Aug 2025 13:21:56 -0400 Subject: [PATCH 784/791] update tested versions of Visual Studio 2025-08-19 --- sys/windows/Makefile.nmake | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sys/windows/Makefile.nmake b/sys/windows/Makefile.nmake index c76201a4f..2d92eb582 100644 --- a/sys/windows/Makefile.nmake +++ b/sys/windows/Makefile.nmake @@ -9,7 +9,7 @@ # # Visual Studio Compilers Tested: # - Microsoft Visual Studio 2019 Community Edition v 16.11.42 -# - Microsoft Visual Studio 2022 Community Edition v 17.14.12 +# - Microsoft Visual Studio 2022 Community Edition v 17.14.13 # #============================================================================== # This is used for building two distinct executables of NetHack: @@ -1179,8 +1179,7 @@ rc=Rc.exe # # Recently tested versions: TESTEDVS2019 = 14.29.30157.0 -TESTEDVS2022 = 14.44.35213.0 -TESTEDVS2022 = 14.44.35214.0 +TESTEDVS2022 = 14.44.35215.0 VS2019CUR = $(TESTEDVS2019:.=) VS2022CUR = $(TESTEDVS2022:.=) From ab26a2e851d535c05ecf48bede6058e528b8e953 Mon Sep 17 00:00:00 2001 From: nhmall Date: Tue, 19 Aug 2025 20:37:43 -0400 Subject: [PATCH 785/791] strip some outdated info from sys/windows/porthelp --- sys/windows/porthelp | 181 ++++++++++++++++++------------------------- 1 file changed, 75 insertions(+), 106 deletions(-) diff --git a/sys/windows/porthelp b/sys/windows/porthelp index a251e14b5..7861b4062 100644 --- a/sys/windows/porthelp +++ b/sys/windows/porthelp @@ -1,38 +1,35 @@ Microsoft Windows specific help file for NetHack 3.7 - Copyright (c) NetHack PC Development Team 1993-2020. + Copyright (c) NetHack PC Development Team 1993-2025. NetHack may be freely distributed. See license for details. - (Last Revision: August 8, 2020) + (Last Revision: August 19, 2025) -This file details specifics for NetHack built for Windows 95, 98, NT, -Me, 2000, and XP. Users of really early 16-bit Windows versions should -use the MSDOS NetHack. +This file details some specifics for NetHack built for Windows. -Please note that "NetHack for Windows - Graphical Interface" requires -an installation of Internet Explorer 4 or an installation of -version 4.71 of the common controls. See the following internet page: - http://www.nethack.org/v340/ports/download-win.html#cc -for more information. If the game runs for you, you are not affected. - -New players should be sure to read GuideBook.txt which contains +New players should be sure to read GuideBook.txt which contains essential information about playing NetHack. It can be found in the same directory as your NetHack executable. -The NetHack for Windows port supports some additional or enhanced -commands as well as some defaults.nh file options specific to -configuration choices used during the building of NetHack for -Windows. Listed below are those commands and defaults.nh file -options. +The NetHack for Windows port supports some additional or enhanced +commands as well as some NetHack config file options. -Some options are applicable only to the "Graphical Interface." -These are discussed separately in their own section. +The active NetHack config file is stored in the nethack subfolder of the +user's User Profile Folder. The config file can be referenced +in the legacy CMD command prompt as: + %USERPROFILE%\nethack\.nethackrc + +Under powershell, the User's config file can be referenced +as: + $env:USERPROFILE\nethack\.nethackrc + +Some options are applicable only to the "Graphical Interface." +These are discussed separately in their own section. Contents 1. ALT Key Combinations -2. Boolean options - Option that you can toggle on or off -3. Graphical Interface - Options you can assign a value to -4. Graphical Interface - Additional/Enhanced Commands -5. Graphical Interface - Menus -6. Numeric Keypad (for number_pad mode) +2. Graphical Interface - Options you can assign a value to +3. Graphical Interface - Additional/Enhanced Commands +4. Graphical Interface - Menus +5. Numeric Keypad (for number_pad mode) 1. ALT Key Combinations @@ -42,7 +39,7 @@ while the "NetHack for Windows - Graphical Interface" lets you toggle the mode. In non-NetHack mode, all ALT-key combinations are sent to the Windows itself, rather than to NetHack. -While playing in NetHack mode you can press the ALT key in +While playing in NetHack mode you can press the ALT key in combination with another key to execute an extended command as an alternative method to pressing a # key sequence. The available commands are: @@ -57,7 +54,7 @@ The available commands are: Alt-i #invoke - invoke an object's powers. Alt-j #jump - jump to a location. Alt-l #loot - loot a box on the floor. - Alt-m #monster - use a monster's special ability. + Alt-m #monster - use a monster's special ability. Alt-n #name - name an item or type of object. Alt-o #offer - offer a sacrifice to the gods. Alt-p #pray - pray to the gods for help. @@ -71,41 +68,14 @@ The available commands are: Alt-w #wipe - wipe off your face. Alt-? #? - display list of extended menu commands -2. Boolean Options (Options that can be toggled on or off) ----------------------------------------------------------- - -Listed here are any options not discussed in the main help, options -which may be slightly different from the main help file, and options -which may need a slightly more explanatory note: - - color Use color when displaying non-tiled maps. Tiled - maps (available in the graphical port) are always - rendered in color. Default: [TRUE] - - hilite_pet Using tiled graphics, displays a small heart symbol - next to your pet. Using ascii graphics, the pet is - hilited in a white background. - Default: [TRUE] - - IBMgraphics Use IBM extended characters for the dungeon - Default: [TRUE] - - msg_window When ^P is pressed, it shows menu in a full window. - Available only in the non-graphical (tty) version. - Default: [FALSE] - - toptenwin Write top ten list to a window, as opposed to stdout. - Default in tty interface: [FALSE] - Default in graphical interface: [TRUE] (and cannot be changed) - -3. Options that you assign a value to (Graphical Interface only) +2. Options that you assign a value to (Graphical Interface only) ---------------------------------------------------------------- -"NetHack for Windows - Graphical Interface" recognizes the following +"NetHack for Windows - Graphical Interface" recognizes the following additional options, which the non-graphical (tty) version will silently ignore. These are options that specify attributes of various -windows. The windows that you can tailor include menu windows (such -as the inventory list), text windows (such as "It is written in the +windows. The windows that you can tailor include menu windows (such +as the inventory list), text windows (such as "It is written in the book of ..." screens), the message window (where events of the game are displayed), the status window (where your character name and attributes are displayed), and the map window (where the map @@ -113,47 +83,47 @@ is drawn). Window Alignment options: - align_message Specifies at which side of the NetHack screen the - message window is aligned. This option can be used + align_message Specifies at which side of the NetHack screen the + message window is aligned. This option can be used to align the window to "top" or "bottom". - Default: [TOP] + Default: [TOP] - align_status Specifies at which side of the NetHack screen the + align_status Specifies at which side of the NetHack screen the status window is aligned. This option can be used to align the window to "top" or "bottom". - Default: [BOTTOM] + Default: [BOTTOM] Map Window options: - map_mode Specifies which map mode to use. - The following map modes are available: - tiles (display things on the map with colored tiles), + map_mode Specifies which map mode to use. + The following map modes are available: + tiles (display things on the map with colored tiles), ascii4x6, ascii6x8, ascii8x8, ascii16x8, ascii7x12, ascii8x12, ascii16x12, ascii12x16, ascii10x18 - (which use that size font to display things on + (which use that size font to display things on the map), or fit_to_screen (an ascii mode which forces things to fit on a single screen). Default: [tiles] scroll_margin Specifies the number of map cells from the edge of the map window where scrolling will take place. - Default: [5] + Default: [5] - tile_file An alternative file containing bitmap to use for - tiles. This file should be a .bmp file and should - be organized as 40 rectangular tiles wide. It is - beyond the scope of this document to describe the + tile_file An alternative file containing bitmap to use for + tiles. This file should be a .bmp file and should + be organized as 40 rectangular tiles wide. It is + beyond the scope of this document to describe the exact contents of each tile in the .bmp, which must match the object lists used when building NetHack. - tile_height Used with tile_file to specify the height of each + tile_height Used with tile_file to specify the height of each tile in pixels. This option may only be specified in the defaults.nh config file. - Default: [16] + Default: [16] - tile_width Used with tile_file to specify the width of each + tile_width Used with tile_file to specify the width of each tile in pixels. This option may only be specified - in the defaults.nh config file. + in the defaults.nh config file. Default: [16] Other Window options: @@ -177,12 +147,12 @@ Other Window options: cyan, gray (or grey), orange, brightgreen, yellow, brightblue, brightmagenta, brightcyan, white, trueblack, purple, silver, maroon, fuchsia, - lime, olive, navy, teal, aqua. In addition, you - can use the following names to refer to default - Windows settings: activeborder, activecaption, - appworkspace, background, btnface, btnshadow, btntext, - captiontext, graytext, highlight, highlighttext, - inactiveborder, inactivecaption, menu, menutext, + lime, olive, navy, teal, aqua. In addition, you + can use the following names to refer to default + Windows settings: activeborder, activecaption, \ + appworkspace, background, btnface, btnshadow, btntext, + captiontext, graytext, highlight, highlighttext, + inactiveborder, inactivecaption, menu, menutext, scrollbar, window, windowframe, windowtext. Example: @@ -203,56 +173,56 @@ Other Window options: font_size_text Specifies the size of the text font. -Miscellaneous options: +Miscellaneous options: - vary_msgcount Number of lines to display in message window. + vary_msgcount Number of lines to display in message window. -4. NetHack for Windows - Graphical Interface, Additional/Enhanced Commands +3. NetHack for Windows - Graphical Interface, Additional/Enhanced Commands ------------------------------------------------------------------------- The following function keys are active in -the "NetHack for Windows - Graphical Interface": +the "NetHack for Windows - Graphical Interface": - F4 Toggle level overview mode on/off - This key will toggle the map between a view that - is mapped to fit exactly to the window, and the - view that shows the various symbols in their - normal size. This is useful for getting an idea - of where you are in a level. + F4 Toggle level overview mode on/off + This key will toggle the map between a view that + is mapped to fit exactly to the window, and the + view that shows the various symbols in their + normal size. This is useful for getting an idea + of where you are in a level. - F5 Toggle tiled display on/off. - This key switches between the tiled and the - traditional ASCII display. This is equivalent to - using the "map_mode" option. + F5 Toggle tiled display on/off. + This key switches between the tiled and the + traditional ASCII display. This is equivalent to + using the "map_mode" option. - F10 Activate menu bar. - This key will activate the menu bar, allowing you - to select between the menus: File, Map, - Window Settings, and Help. + F10 Activate menu bar. + This key will activate the menu bar, allowing you + to select between the menus: File, Map, + Window Settings, and Help. -5. Graphical Port Menus +4. Graphical Port Menus ----------------------- File Save - Allows you to save and exit the game Quit - Allows you to quit the game -Map - Provides for selection of map mode. Equivalent to using -the map_mode option. +Map - Provides for selection of map mode. Equivalent to using +the map_mode option. Window Settings - Changes your logged-on user's settings for NetHack. -In 3.5.0, only one setting is available: NetHack mode, which can be +Only one setting is available: NetHack mode, which can be checked or unchecked. NetHack mode allows you to use the ALT key for game key commands [see list above]. You can use F10 to access the menu bar while in NetHack mode. You can also clear your logged-on user's settings for NetHack. Settings in this window are saved in -your logged-on user's registry. +your logged-on user's registry. Help - Provides help about various portions of NetHack. -6. Numeric Keypad (for "OPTION=number_pad" mode) +5. Numeric Keypad (for "OPTION=number_pad" mode) ------------------------------------------------ The numeric keypad and surrounding characters act as macros for different @@ -297,4 +267,3 @@ most of these keys: Ctrl-Shift-PgDn (3) Scroll (Pan) map left to lowermost corner - From 91f973d4548f809e28ec5401ecab82581eeb3013 Mon Sep 17 00:00:00 2001 From: George Huebner Date: Sat, 23 Aug 2025 13:45:21 -0500 Subject: [PATCH 786/791] config.nh: fix example MENUCOLOR regex Matching literal parentheses requires escaping them with `\` --- doc/config.nh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/config.nh b/doc/config.nh index 695534110..920074b3e 100644 --- a/doc/config.nh +++ b/doc/config.nh @@ -498,7 +498,7 @@ # Show all unholy water in red #MENUCOLOR=" unholy " = red # Show all cursed worn items in orange and underlined -#MENUCOLOR=" cursed .* (being worn)" = orange&underline +#MENUCOLOR=" cursed .* \(being worn\)" = orange&underline # Use the IBM character set rather than just plain ascii characters From f110db02fce3c4049897175ef95434683fbcf892 Mon Sep 17 00:00:00 2001 From: nhmall Date: Thu, 28 Aug 2025 11:43:47 -0400 Subject: [PATCH 787/791] updates for build on OpenVMS --- src/sfbase.c | 292 +++++++++++++++++++-------------------- src/sfstruct.c | 6 +- sys/vms/Makefile_src.vms | 8 +- sys/vms/Makefile_utl.vms | 21 +-- sys/vms/vmsmain.c | 2 +- sys/vms/vmstty.c | 2 +- 6 files changed, 168 insertions(+), 163 deletions(-) diff --git a/src/sfbase.c b/src/sfbase.c index c1f4308a3..9260b5a9d 100644 --- a/src/sfbase.c +++ b/src/sfbase.c @@ -658,442 +658,442 @@ sf_setflprocs(int idx, struct sf_fieldlevel_procs *flsfi, } #ifndef SFCTOOL -void normalize_pointers_any(union any *d_any); -void normalize_pointers_align(struct align *d_align); -void normalize_pointers_arti_info(struct arti_info *d_arti_info); -void normalize_pointers_attribs(struct attribs *d_attribs); -void normalize_pointers_bill_x(struct bill_x *d_bill_x); -void normalize_pointers_branch(struct branch *d_branch); -void normalize_pointers_bubble(struct bubble *d_bubble); -void normalize_pointers_cemetery(struct cemetery *d_cemetery); -void normalize_pointers_context_info(struct context_info *d_context_info); -void normalize_pointers_achievement_tracking( +void norm_ptrs_any(union any *d_any); +void norm_ptrs_align(struct align *d_align); +void norm_ptrs_arti_info(struct arti_info *d_arti_info); +void norm_ptrs_attribs(struct attribs *d_attribs); +void norm_ptrs_bill_x(struct bill_x *d_bill_x); +void norm_ptrs_branch(struct branch *d_branch); +void norm_ptrs_bubble(struct bubble *d_bubble); +void norm_ptrs_cemetery(struct cemetery *d_cemetery); +void norm_ptrs_context_info(struct context_info *d_context_info); +void norm_ptrs_achievement_tracking( struct achievement_tracking *d_achievement_tracking); -void normalize_pointers_book_info(struct book_info *d_book_info); -void normalize_pointers_dig_info(struct dig_info *d_dig_info); -void normalize_pointers_engrave_info(struct engrave_info *d_engrave_info); -void normalize_pointers_obj_split(struct obj_split *d_obj_split); -void normalize_pointers_polearm_info(struct polearm_info *d_polearm_info); -void normalize_pointers_takeoff_info(struct takeoff_info *d_takeoff_info); -void normalize_pointers_tin_info(struct tin_info *d_tin_info); -void normalize_pointers_tribute_info(struct tribute_info *d_tribute_info); -void normalize_pointers_victual_info(struct victual_info *d_victual_info); -void normalize_pointers_warntype_info(struct warntype_info *d_warntype_info); -void normalize_pointers_d_flags(struct d_flags *d_d_flags); -void normalize_pointers_d_level(struct d_level *d_d_level); -void normalize_pointers_damage(struct damage *d_damage); -void normalize_pointers_dest_area(struct dest_area *d_dest_area); -void normalize_pointers_dgn_topology(struct dgn_topology *d_dgn_topology); -void normalize_pointers_dungeon(struct dungeon *d_dungeon); -void normalize_pointers_ebones(struct ebones *d_ebones); -void normalize_pointers_edog(struct edog *d_edog); -void normalize_pointers_egd(struct egd *d_egd); -void normalize_pointers_emin(struct emin *d_emin); -void normalize_pointers_engr(struct engr *d_engr); -void normalize_pointers_epri(struct epri *d_epri); -void normalize_pointers_eshk(struct eshk *d_eshk); -void normalize_pointers_fakecorridor(struct fakecorridor *d_fakecorridor); -void normalize_pointers_fe(struct fe *d_fe); -void normalize_pointers_flag(struct flag *d_flag); -void normalize_pointers_fruit(struct fruit *d_fruit); -void normalize_pointers_gamelog_line(struct gamelog_line *d_gamelog_line); -void normalize_pointers_kinfo(struct kinfo *d_kinfo); -void normalize_pointers_levelflags(struct levelflags *d_levelflags); -void normalize_pointers_linfo(struct linfo *d_linfo); -void normalize_pointers_ls_t(struct ls_t *d_ls_t); -void normalize_pointers_mapseen_feat(struct mapseen_feat *d_mapseen_feat); -void normalize_pointers_mapseen_flags(struct mapseen_flags *d_mapseen_flags); -void normalize_pointers_mapseen_rooms(struct mapseen_rooms *d_mapseen_rooms); -void normalize_pointers_mapseen(struct mapseen *d_mapseen); -void normalize_pointers_mextra(struct mextra *d_mextra); -void normalize_pointers_mkroom(struct mkroom *d_mkroom); -void normalize_pointers_monst(struct monst *d_monst); -void normalize_pointers_mvitals(struct mvitals *d_mvitals); -void normalize_pointers_nhcoord(struct nhcoord *d_nhcoord); -void normalize_pointers_nhrect(struct nhrect *d_nhrect); -void normalize_pointers_novel_tracking(struct novel_tracking *d_novel_tracking); -void normalize_pointers_obj(struct obj *d_obj); -void normalize_pointers_objclass(struct objclass *d_objclass); -void normalize_pointers_oextra(struct oextra *d_oextra); -void normalize_pointers_prop(struct prop *d_prop); -void normalize_pointers_q_score(struct q_score *d_q_score); -void normalize_pointers_rm(struct rm *d_rm); -void normalize_pointers_s_level(struct s_level *d_s_level); -void normalize_pointers_skills(struct skills *d_skills); -void normalize_pointers_spell(struct spell *d_spell); -void normalize_pointers_stairway(struct stairway *d_stairway); -void normalize_pointers_trap(struct trap *d_trap); -void normalize_pointers_u_conduct(struct u_conduct *d_u_conduct); -void normalize_pointers_u_event(struct u_event *d_u_event); -void normalize_pointers_u_have(struct u_have *d_u_have); -void normalize_pointers_u_realtime(struct u_realtime *d_u_realtime); -void normalize_pointers_u_roleplay(struct u_roleplay *d_u_roleplay); -void normalize_pointers_version_info(struct version_info *d_version_info); -void normalize_pointers_vlaunchinfo(union vlaunchinfo *d_vlaunchinfo); -void normalize_pointers_vptrs(union vptrs *d_vptrs); -void normalize_pointers_you(struct you *d_you); +void norm_ptrs_book_info(struct book_info *d_book_info); +void norm_ptrs_dig_info(struct dig_info *d_dig_info); +void norm_ptrs_engrave_info(struct engrave_info *d_engrave_info); +void norm_ptrs_obj_split(struct obj_split *d_obj_split); +void norm_ptrs_polearm_info(struct polearm_info *d_polearm_info); +void norm_ptrs_takeoff_info(struct takeoff_info *d_takeoff_info); +void norm_ptrs_tin_info(struct tin_info *d_tin_info); +void norm_ptrs_tribute_info(struct tribute_info *d_tribute_info); +void norm_ptrs_victual_info(struct victual_info *d_victual_info); +void norm_ptrs_warntype_info(struct warntype_info *d_warntype_info); +void norm_ptrs_d_flags(struct d_flags *d_d_flags); +void norm_ptrs_d_level(struct d_level *d_d_level); +void norm_ptrs_damage(struct damage *d_damage); +void norm_ptrs_dest_area(struct dest_area *d_dest_area); +void norm_ptrs_dgn_topology(struct dgn_topology *d_dgn_topology); +void norm_ptrs_dungeon(struct dungeon *d_dungeon); +void norm_ptrs_ebones(struct ebones *d_ebones); +void norm_ptrs_edog(struct edog *d_edog); +void norm_ptrs_egd(struct egd *d_egd); +void norm_ptrs_emin(struct emin *d_emin); +void norm_ptrs_engr(struct engr *d_engr); +void norm_ptrs_epri(struct epri *d_epri); +void norm_ptrs_eshk(struct eshk *d_eshk); +void norm_ptrs_fakecorridor(struct fakecorridor *d_fakecorridor); +void norm_ptrs_fe(struct fe *d_fe); +void norm_ptrs_flag(struct flag *d_flag); +void norm_ptrs_fruit(struct fruit *d_fruit); +void norm_ptrs_gamelog_line(struct gamelog_line *d_gamelog_line); +void norm_ptrs_kinfo(struct kinfo *d_kinfo); +void norm_ptrs_levelflags(struct levelflags *d_levelflags); +void norm_ptrs_linfo(struct linfo *d_linfo); +void norm_ptrs_ls_t(struct ls_t *d_ls_t); +void norm_ptrs_mapseen_feat(struct mapseen_feat *d_mapseen_feat); +void norm_ptrs_mapseen_flags(struct mapseen_flags *d_mapseen_flags); +void norm_ptrs_mapseen_rooms(struct mapseen_rooms *d_mapseen_rooms); +void norm_ptrs_mapseen(struct mapseen *d_mapseen); +void norm_ptrs_mextra(struct mextra *d_mextra); +void norm_ptrs_mkroom(struct mkroom *d_mkroom); +void norm_ptrs_monst(struct monst *d_monst); +void norm_ptrs_mvitals(struct mvitals *d_mvitals); +void norm_ptrs_nhcoord(struct nhcoord *d_nhcoord); +void norm_ptrs_nhrect(struct nhrect *d_nhrect); +void norm_ptrs_novel_tracking(struct novel_tracking *d_novel_tracking); +void norm_ptrs_obj(struct obj *d_obj); +void norm_ptrs_objclass(struct objclass *d_objclass); +void norm_ptrs_oextra(struct oextra *d_oextra); +void norm_ptrs_prop(struct prop *d_prop); +void norm_ptrs_q_score(struct q_score *d_q_score); +void norm_ptrs_rm(struct rm *d_rm); +void norm_ptrs_s_level(struct s_level *d_s_level); +void norm_ptrs_skills(struct skills *d_skills); +void norm_ptrs_spell(struct spell *d_spell); +void norm_ptrs_stairway(struct stairway *d_stairway); +void norm_ptrs_trap(struct trap *d_trap); +void norm_ptrs_u_conduct(struct u_conduct *d_u_conduct); +void norm_ptrs_u_event(struct u_event *d_u_event); +void norm_ptrs_u_have(struct u_have *d_u_have); +void norm_ptrs_u_realtime(struct u_realtime *d_u_realtime); +void norm_ptrs_u_roleplay(struct u_roleplay *d_u_roleplay); +void norm_ptrs_version_info(struct version_info *d_version_info); +void norm_ptrs_vlaunchinfo(union vlaunchinfo *d_vlaunchinfo); +void norm_ptrs_vptrs(union vptrs *d_vptrs); +void norm_ptrs_you(struct you *d_you); void -normalize_pointers_any(union any *d_any UNUSED) +norm_ptrs_any(union any *d_any UNUSED) { } void -normalize_pointers_align(struct align *d_align UNUSED) +norm_ptrs_align(struct align *d_align UNUSED) { } void -normalize_pointers_arti_info(struct arti_info *d_arti_info UNUSED) +norm_ptrs_arti_info(struct arti_info *d_arti_info UNUSED) { } void -normalize_pointers_attribs(struct attribs *d_attribs UNUSED) +norm_ptrs_attribs(struct attribs *d_attribs UNUSED) { } void -normalize_pointers_bill_x(struct bill_x *d_bill_x UNUSED) +norm_ptrs_bill_x(struct bill_x *d_bill_x UNUSED) { } void -normalize_pointers_branch(struct branch *d_branch UNUSED) +norm_ptrs_branch(struct branch *d_branch UNUSED) { } void -normalize_pointers_bubble(struct bubble *d_bubble UNUSED) +norm_ptrs_bubble(struct bubble *d_bubble UNUSED) { } void -normalize_pointers_cemetery(struct cemetery *d_cemetery UNUSED) +norm_ptrs_cemetery(struct cemetery *d_cemetery UNUSED) { } void -normalize_pointers_context_info(struct context_info *d_context_info UNUSED) +norm_ptrs_context_info(struct context_info *d_context_info UNUSED) { } void -normalize_pointers_achievement_tracking(struct achievement_tracking *d_achievement_tracking UNUSED) +norm_ptrs_achievement_tracking(struct achievement_tracking *d_achievement_tracking UNUSED) { } void -normalize_pointers_book_info(struct book_info *d_book_info UNUSED) +norm_ptrs_book_info(struct book_info *d_book_info UNUSED) { } void -normalize_pointers_dig_info(struct dig_info *d_dig_info UNUSED) +norm_ptrs_dig_info(struct dig_info *d_dig_info UNUSED) { } void -normalize_pointers_engrave_info(struct engrave_info *d_engrave_info UNUSED) +norm_ptrs_engrave_info(struct engrave_info *d_engrave_info UNUSED) { } void -normalize_pointers_obj_split(struct obj_split *d_obj_split UNUSED) +norm_ptrs_obj_split(struct obj_split *d_obj_split UNUSED) { } void -normalize_pointers_polearm_info(struct polearm_info *d_polearm_info UNUSED) +norm_ptrs_polearm_info(struct polearm_info *d_polearm_info UNUSED) { } void -normalize_pointers_takeoff_info(struct takeoff_info *d_takeoff_info UNUSED) +norm_ptrs_takeoff_info(struct takeoff_info *d_takeoff_info UNUSED) { } void -normalize_pointers_tin_info(struct tin_info *d_tin_info UNUSED) +norm_ptrs_tin_info(struct tin_info *d_tin_info UNUSED) { } void -normalize_pointers_tribute_info(struct tribute_info *d_tribute_info UNUSED) +norm_ptrs_tribute_info(struct tribute_info *d_tribute_info UNUSED) { } void -normalize_pointers_victual_info(struct victual_info *d_victual_info UNUSED) +norm_ptrs_victual_info(struct victual_info *d_victual_info UNUSED) { } void -normalize_pointers_warntype_info(struct warntype_info *d_warntype_info UNUSED) +norm_ptrs_warntype_info(struct warntype_info *d_warntype_info UNUSED) { } void -normalize_pointers_d_flags(struct d_flags *d_d_flags UNUSED) +norm_ptrs_d_flags(struct d_flags *d_d_flags UNUSED) { } void -normalize_pointers_d_level(struct d_level *d_d_level UNUSED) +norm_ptrs_d_level(struct d_level *d_d_level UNUSED) { } void -normalize_pointers_damage(struct damage *d_damage UNUSED) +norm_ptrs_damage(struct damage *d_damage UNUSED) { } void -normalize_pointers_dest_area(struct dest_area *d_dest_area UNUSED) +norm_ptrs_dest_area(struct dest_area *d_dest_area UNUSED) { } void -normalize_pointers_dgn_topology(struct dgn_topology *d_dgn_topology UNUSED) +norm_ptrs_dgn_topology(struct dgn_topology *d_dgn_topology UNUSED) { } void -normalize_pointers_dungeon(struct dungeon *d_dungeon UNUSED) +norm_ptrs_dungeon(struct dungeon *d_dungeon UNUSED) { } void -normalize_pointers_ebones(struct ebones *d_ebones UNUSED) +norm_ptrs_ebones(struct ebones *d_ebones UNUSED) { } void -normalize_pointers_edog(struct edog *d_edog UNUSED) +norm_ptrs_edog(struct edog *d_edog UNUSED) { } void -normalize_pointers_egd(struct egd *d_egd UNUSED) +norm_ptrs_egd(struct egd *d_egd UNUSED) { } void -normalize_pointers_emin(struct emin *d_emin UNUSED) +norm_ptrs_emin(struct emin *d_emin UNUSED) { } void -normalize_pointers_engr(struct engr *d_engr UNUSED) +norm_ptrs_engr(struct engr *d_engr UNUSED) { } void -normalize_pointers_epri(struct epri *d_epri UNUSED) +norm_ptrs_epri(struct epri *d_epri UNUSED) { } void -normalize_pointers_eshk(struct eshk *d_eshk UNUSED) +norm_ptrs_eshk(struct eshk *d_eshk UNUSED) { } void -normalize_pointers_fakecorridor(struct fakecorridor *d_fakecorridor UNUSED) +norm_ptrs_fakecorridor(struct fakecorridor *d_fakecorridor UNUSED) { } void -normalize_pointers_fe(struct fe *d_fe UNUSED) +norm_ptrs_fe(struct fe *d_fe UNUSED) { } void -normalize_pointers_flag(struct flag *d_flag UNUSED) +norm_ptrs_flag(struct flag *d_flag UNUSED) { } void -normalize_pointers_fruit(struct fruit *d_fruit UNUSED) +norm_ptrs_fruit(struct fruit *d_fruit UNUSED) { } void -normalize_pointers_gamelog_line(struct gamelog_line *d_gamelog_line UNUSED) +norm_ptrs_gamelog_line(struct gamelog_line *d_gamelog_line UNUSED) { } void -normalize_pointers_kinfo(struct kinfo *d_kinfo UNUSED) +norm_ptrs_kinfo(struct kinfo *d_kinfo UNUSED) { } void -normalize_pointers_levelflags(struct levelflags *d_levelflags UNUSED) +norm_ptrs_levelflags(struct levelflags *d_levelflags UNUSED) { } void -normalize_pointers_linfo(struct linfo *d_linfo UNUSED) +norm_ptrs_linfo(struct linfo *d_linfo UNUSED) { } void -normalize_pointers_ls_t(struct ls_t *d_ls_t UNUSED) +norm_ptrs_ls_t(struct ls_t *d_ls_t UNUSED) { } void -normalize_pointers_mapseen_feat(struct mapseen_feat *d_mapseen_feat UNUSED) +norm_ptrs_mapseen_feat(struct mapseen_feat *d_mapseen_feat UNUSED) { } void -normalize_pointers_mapseen_flags(struct mapseen_flags *d_mapseen_flags UNUSED) +norm_ptrs_mapseen_flags(struct mapseen_flags *d_mapseen_flags UNUSED) { } void -normalize_pointers_mapseen_rooms(struct mapseen_rooms *d_mapseen_rooms UNUSED) +norm_ptrs_mapseen_rooms(struct mapseen_rooms *d_mapseen_rooms UNUSED) { } void -normalize_pointers_mapseen(struct mapseen *d_mapseen UNUSED) +norm_ptrs_mapseen(struct mapseen *d_mapseen UNUSED) { } void -normalize_pointers_mextra(struct mextra *d_mextra UNUSED) +norm_ptrs_mextra(struct mextra *d_mextra UNUSED) { } void -normalize_pointers_mkroom(struct mkroom *d_mkroom UNUSED) +norm_ptrs_mkroom(struct mkroom *d_mkroom UNUSED) { } void -normalize_pointers_monst(struct monst *d_monst UNUSED) +norm_ptrs_monst(struct monst *d_monst UNUSED) { } void -normalize_pointers_mvitals(struct mvitals *d_mvitals UNUSED) +norm_ptrs_mvitals(struct mvitals *d_mvitals UNUSED) { } void -normalize_pointers_nhcoord(struct nhcoord *d_nhcoord UNUSED) +norm_ptrs_nhcoord(struct nhcoord *d_nhcoord UNUSED) { } void -normalize_pointers_nhrect(struct nhrect *d_nhrect UNUSED) +norm_ptrs_nhrect(struct nhrect *d_nhrect UNUSED) { } void -normalize_pointers_novel_tracking(struct novel_tracking *d_novel_tracking UNUSED) +norm_ptrs_novel_tracking(struct novel_tracking *d_novel_tracking UNUSED) { } void -normalize_pointers_obj(struct obj *d_obj UNUSED) +norm_ptrs_obj(struct obj *d_obj UNUSED) { } void -normalize_pointers_objclass(struct objclass *d_objclass UNUSED) +norm_ptrs_objclass(struct objclass *d_objclass UNUSED) { } void -normalize_pointers_oextra(struct oextra *d_oextra UNUSED) +norm_ptrs_oextra(struct oextra *d_oextra UNUSED) { } void -normalize_pointers_prop(struct prop *d_prop UNUSED) +norm_ptrs_prop(struct prop *d_prop UNUSED) { } void -normalize_pointers_q_score(struct q_score *d_q_score UNUSED) +norm_ptrs_q_score(struct q_score *d_q_score UNUSED) { } void -normalize_pointers_rm(struct rm *d_rm UNUSED) +norm_ptrs_rm(struct rm *d_rm UNUSED) { } void -normalize_pointers_s_level(struct s_level *d_s_level UNUSED) +norm_ptrs_s_level(struct s_level *d_s_level UNUSED) { } void -normalize_pointers_skills(struct skills *d_skills UNUSED) +norm_ptrs_skills(struct skills *d_skills UNUSED) { } void -normalize_pointers_spell(struct spell *d_spell UNUSED) +norm_ptrs_spell(struct spell *d_spell UNUSED) { } void -normalize_pointers_stairway(struct stairway *d_stairway UNUSED) +norm_ptrs_stairway(struct stairway *d_stairway UNUSED) { } void -normalize_pointers_trap(struct trap *d_trap UNUSED) +norm_ptrs_trap(struct trap *d_trap UNUSED) { } void -normalize_pointers_u_conduct(struct u_conduct *d_u_conduct UNUSED) +norm_ptrs_u_conduct(struct u_conduct *d_u_conduct UNUSED) { } void -normalize_pointers_u_event(struct u_event *d_u_event UNUSED) +norm_ptrs_u_event(struct u_event *d_u_event UNUSED) { } void -normalize_pointers_u_have(struct u_have *d_u_have UNUSED) +norm_ptrs_u_have(struct u_have *d_u_have UNUSED) { } void -normalize_pointers_u_realtime(struct u_realtime *d_u_realtime UNUSED) +norm_ptrs_u_realtime(struct u_realtime *d_u_realtime UNUSED) { } void -normalize_pointers_u_roleplay(struct u_roleplay *d_u_roleplay UNUSED) +norm_ptrs_u_roleplay(struct u_roleplay *d_u_roleplay UNUSED) { } void -normalize_pointers_version_info(struct version_info *d_version_info UNUSED) +norm_ptrs_version_info(struct version_info *d_version_info UNUSED) { } void -normalize_pointers_vlaunchinfo(union vlaunchinfo *d_vlaunchinfo UNUSED) +norm_ptrs_vlaunchinfo(union vlaunchinfo *d_vlaunchinfo UNUSED) { } void -normalize_pointers_vptrs(union vptrs *d_vptrs UNUSED) +norm_ptrs_vptrs(union vptrs *d_vptrs UNUSED) { } void -normalize_pointers_you(struct you *d_you UNUSED) +norm_ptrs_you(struct you *d_you UNUSED) { } #endif /* SFCTOOL */ diff --git a/src/sfstruct.c b/src/sfstruct.c index 6014d97b2..8a15a0c17 100644 --- a/src/sfstruct.c +++ b/src/sfstruct.c @@ -53,7 +53,7 @@ void historical_sfi_##dtyp(NHFILE *nhfp, dtyp *d_##dtyp, #define SFO_CBODY(dt) \ { \ - normalize_pointers_##dt(d_##dt); \ + norm_ptrs_##dt(d_##dt); \ bwrite(nhfp->fd, (genericptr_t) d_##dt, sizeof *d_##dt); \ } @@ -63,7 +63,7 @@ void historical_sfi_##dtyp(NHFILE *nhfp, dtyp *d_##dtyp, sfstruct_read_error(); \ } \ mread(nhfp->fd, (genericptr_t) d_##dt, sizeof *d_##dt); \ - normalize_pointers_##dt(d_##dt); \ + norm_ptrs_##dt(d_##dt); \ if (restoreinfo.mread_flags == -1) \ nhfp->eof = TRUE; \ } @@ -73,7 +73,7 @@ void historical_sfo_##dtyp(NHFILE *, keyw dtyp *d_##dtyp, const char *); \ void historical_sfi_##dtyp(NHFILE *, keyw dtyp *d_##dtyp, \ const char *); \ -extern void normalize_pointers_##dtyp(keyw dtyp *d_##dtyp); \ +extern void norm_ptrs_##dtyp(keyw dtyp *d_##dtyp); \ \ void historical_sfo_##dtyp(NHFILE *nhfp, keyw dtyp *d_##dtyp, \ const char *myname UNUSED) \ diff --git a/sys/vms/Makefile_src.vms b/sys/vms/Makefile_src.vms index af841394d..bf7355722 100644 --- a/sys/vms/Makefile_src.vms +++ b/sys/vms/Makefile_src.vms @@ -114,10 +114,10 @@ HACK_H = $(addsuffix .h, $(addprefix $(INCL), $(CONFIGBASEH) $(HACKBASEH))) # all .c that are part of the main NetHack program and are not # operating-system or windowing-system specific. # Do not include date.c in this list. -HACKFILES := allmain alloc apply artifact attrib ball bones \ - botl calendar cmd coloratt dbridge decl detect dig display dlb do \ - do_name do_wear dog dogmove dokick dothrow drawing \ - dungeon eat end engrave exper explode extralev \ +HACKFILES := allmain alloc apply artifact attrib ball bones botl \ + calendar cfgfiles cmd coloratt dbridge decl detect \ + dig display dlb do do_name do_wear dog dogmove dokick \ + dothrow drawing dungeon eat end engrave exper explode extralev \ files fountain getpos glyphs hack hacklib insight invent isaac64 \ light lock mail makemon mcastu mdlib mhitm mhitu minion mklev \ mkmap mkmaze mkobj mkroom mon \ diff --git a/sys/vms/Makefile_utl.vms b/sys/vms/Makefile_utl.vms index 4c845194a..83c112c95 100644 --- a/sys/vms/Makefile_utl.vms +++ b/sys/vms/Makefile_utl.vms @@ -113,7 +113,7 @@ ODATE = $(OBJDIR)date.obj MAKEOBJS = []makedefs.obj $(OMONOBJ) $(ODATE) $(OALLOC) $(OPANIC) # object files for recovery utility -RECOVOBJS = $(TARGETPFX)recover.obj +RECOVOBJS = $(TARGETPFX)recover.obj $(TARGETPFX)recover_ver.obj # object files for the data librarian DLBOBJS = dlb_main.obj $(OBJDIR)dlb.obj $(OALLOC) $(OPANIC) @@ -140,9 +140,9 @@ $(HACKLIB): $(HACKLIBOBJS) [-.util]panic.obj # dependencies for makedefs # -makedefs.exe: $(HACKLIB) $(MAKEOBJS) placeholder.obj mdgrep.h +makedefs.exe: $(HACKLIB) $(MAKEOBJS) uplaceholder.obj mdgrep.h $(CLINK) $(LFLAGS) /EXE=$@ \ - $(addsuffix $(comma),$(MAKEOBJS)) placeholder.obj, \ + $(addsuffix $(comma),$(MAKEOBJS)) uplaceholder.obj, \ $(HACKLIB)/lib # note: the headers listed here are maintained manually rather than via @@ -158,10 +158,10 @@ makedefs.obj: makedefs.c $(SRC)mdlib.c $(CONFIG_H) \ $(INCL)dlb.h $(INCL)patchlevel.h mdgrep.h $(CC) $(CFLAGS) $(CSTD) makedefs.c /OBJ=$@ -placeholder.c: - echo int makedefs_placeholder = 1; >$@ +uplaceholder.c: + echo int uplaceholder = 1; >$@ -placeholder.obj: placeholder.c +uplaceholder.obj: uplaceholder.c # Don't require perl to build; that is why mdgrep.h is spelled wrong below. @@ -193,13 +193,18 @@ panic.obj: panic.c $(CONFIG_H) # # dependencies for recover # -$(TARGETPFX)recover.exe: $(HACKLIB) $(RECOVOBJS) +$(TARGETPFX)recover.exe: $(HACKLIB) $(RECOVOBJS) uplaceholder.obj $(TARGET_CLINK) $(TARGET_LFLAGS) /EXE=$@ \ - $(RECOVOBJS),$(HACKLIB)/lib $(LIBS) + $(addsuffix $(comma),$(RECOVOBJS)) uplaceholder.obj, \ + $(HACKLIB)/lib $(LIBS) $(TARGETPFX)recover.obj: recover.c $(CONFIG_H) $(TARGET_CC) $(TARGET_CFLAGS) $(CSTD) recover.c /OBJ=$@ +$(TARGETPFX)recover_ver.obj: [-.src]version.c $(HACK_H) + $(TARGET_CC) $(TARGET_CFLAGS) $(CSTD) \ + /DEFINE=(MINIMAL_FOR_RECOVER) \ + [-.src]version.c /OBJ=$@ # dependencies for dlb # diff --git a/sys/vms/vmsmain.c b/sys/vms/vmsmain.c index 7b52691ea..f540d3190 100644 --- a/sys/vms/vmsmain.c +++ b/sys/vms/vmsmain.c @@ -81,7 +81,7 @@ main(int argc, char *argv[]) if (argcheck(argc, argv, ARG_SHOWPATHS) == 2) { gd.deferred_showpaths = TRUE; - return; + return 0; } if (argcheck(argc, argv, ARG_DEBUG) == 1) { argc--; diff --git a/sys/vms/vmstty.c b/sys/vms/vmstty.c index b6dd2013e..9b0051c0a 100644 --- a/sys/vms/vmstty.c +++ b/sys/vms/vmstty.c @@ -459,7 +459,7 @@ void settty(const char *s) { if (!bombing) - end_screen(); + term_end_screen(); if (s) raw_print(s); if (settty_needed) { From b576ead25ab1f4d8e31c8dba63c0993eb7f93ae9 Mon Sep 17 00:00:00 2001 From: nhmall Date: Thu, 28 Aug 2025 11:53:50 -0400 Subject: [PATCH 788/791] follow-up after changing normalize_pointers_ to norm_ptrs_ --- util/sftags.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/util/sftags.c b/util/sftags.c index 3a04cb94d..39bfe24f9 100644 --- a/util/sftags.c +++ b/util/sftags.c @@ -1108,10 +1108,10 @@ static void generate_c_files(void) /* begin sfnormptrs.tmp */ Fprintf(SF_NORMALIZE_POINTERS, - "void normalize_pointers_any(union any *d_any);\n\n"); + "void norm_ptrs_any(union any *d_any);\n\n"); Fprintf(SF_NORMALIZE_POINTERS, "void\n" - "normalize_pointers_any(union any *d_any UNUSED)\n" + "norm_ptrs_any(union any *d_any UNUSED)\n" "{\n" "}\n"); @@ -1225,11 +1225,11 @@ static void generate_c_files(void) Fprintf(SF_NORMALIZE_POINTERS, - "\nvoid normalize_pointers_%s(%s " + "\nvoid norm_ptrs_%s(%s " "*d_%s);\n", readtagstypes[k].dtype, sfparent, readtagstypes[k].dtype); Fprintf(SF_NORMALIZE_POINTERS, - "\nvoid\nnormalize_pointers_%s(%s " + "\nvoid\nnorm_ptrs_%s(%s " "*d_%s)\n{\n", readtagstypes[k].dtype, sfparent, readtagstypes[k].dtype); Snprintf(norm_param_buf, sizeof norm_param_buf, "d_%s", From 506e9cdd8fca6a85c0bceedee6b7521dc7702404 Mon Sep 17 00:00:00 2001 From: nhmall Date: Thu, 28 Aug 2025 12:13:12 -0400 Subject: [PATCH 789/791] follow-up build bit for OpenVMS --- src/sfbase.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/sfbase.c b/src/sfbase.c index 9260b5a9d..0922839d1 100644 --- a/src/sfbase.c +++ b/src/sfbase.c @@ -382,9 +382,20 @@ sf_log(NHFILE *nhfp, const char *t1, size_t sz, int cnt, char *txtvalue) if (fp && dolog) { iocount = ((nhfp->mode & WRITING) == 0) ? &nhfp->rcount : &nhfp->wcount; - (void) fprintf(fp, "%08ld %s sz=%zu cnt=%d |%s|\n", - *iocount, - t1, sz, cnt, txtvalue); + (void) fprintf(fp, +#ifndef VMS + "%08ld %s sz=%zu cnt=%d |%s|\n", +#else + "%08ld %s sz=%lu cnt=%d |%s|\n", +#endif + *iocount, + t1, +#ifndef VMS + sz, +#else + (unsigned long) sz, +#endif + cnt, txtvalue); // (*iocount)++; // if (*iocount == 87) // __debugbreak(); From bfff247462a60ad81801a1fa66fa7e4d877834db Mon Sep 17 00:00:00 2001 From: PatR Date: Fri, 29 Aug 2025 11:14:01 -0700 Subject: [PATCH 790/791] suppress a static analyzer complaint for o_init.c This should fix one of the three new complaints. It compiles but has not actually been through the analyzer. --- src/o_init.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/o_init.c b/src/o_init.c index c62ca0a0c..1185c177f 100644 --- a/src/o_init.c +++ b/src/o_init.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 o_init.c $NHDT-Date: 1720391455 2024/07/07 22:30:55 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.87 $ */ +/* NetHack 3.7 o_init.c $NHDT-Date: 1756520041 2025/08/29 18:14:01 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.96 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2011. */ /* NetHack may be freely redistributed. See license for details. */ @@ -692,9 +692,10 @@ disco_append_typename(char *buf, int dis) /* sort and output sorted_lines to window and free the lines */ staticfn void -disco_output_sorted(winid tmpwin, - char **sorted_lines, int sorted_ct, - boolean lootsort) +disco_output_sorted( + winid tmpwin, + char **sorted_lines, int sorted_ct, + boolean lootsort) { char *p; int j; @@ -702,6 +703,7 @@ disco_output_sorted(winid tmpwin, qsort(sorted_lines, sorted_ct, sizeof (char *), discovered_cmp); for (j = 0; j < sorted_ct; ++j) { p = sorted_lines[j]; + assert(p != NULL); /* pacify static analyzer */ if (lootsort) { p[6] = p[0]; /* '*' or ' ' */ p += 6; From 6f5aba00cdd3e0b8faa745843dd113dc7bffb369 Mon Sep 17 00:00:00 2001 From: PatR Date: Fri, 29 Aug 2025 14:20:49 -0700 Subject: [PATCH 791/791] fix issue #1440 - spurious sanity check warning Issue reported by NullCGT: if the spot in front of a drawbridge held water and got frozen, sanity checking for ice-melt timer would issue complaints about melt timer for non-ice whenever the bridge was open. Ice in front of closed bridge was handled ok, but ice beneath an open bridge issued a spurious warning each turn if the sanity_check option (wizard mode-only) was on. Fixes #1440 --- src/timeout.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/timeout.c b/src/timeout.c index 248dde41f..1b85d5398 100644 --- a/src/timeout.c +++ b/src/timeout.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 timeout.c $NHDT-Date: 1727251273 2024/09/25 08:01:13 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.193 $ */ +/* NetHack 3.7 timeout.c $NHDT-Date: 1756531249 2025/08/29 21:20:49 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.205 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2018. */ /* NetHack may be freely redistributed. See license for details. */ @@ -2179,7 +2179,13 @@ timer_sanity_check(void) the analyzer isn't aware that isok() filters such things */ assert(x > 0 && x < COLNO && y >= 0 && y < ROWNO); - if (curr->func_index == MELT_ICE_AWAY && !is_ice(x, y)) + if (curr->func_index == MELT_ICE_AWAY && !is_ice(x, y) + /* the terrain under the span of an open drawbridge might + be frozen moat; is_ice() only checks for that when + the drawbridge is closed (and terrain here would be + DRAWBRIGE_UP) */ + && !(levl[x][y].typ == DRAWBRIDGE_DOWN + && (levl[x][y].drawbridgemask & DB_UNDER) == DB_ICE)) impossible( "timer sanity: melt timer %lu on non-ice %d <%d,%d>", t_id, levl[x][y].typ, x, y);