diff --git a/.gitignore b/.gitignore index 5c64716a3..366cf938f 100644 --- a/.gitignore +++ b/.gitignore @@ -37,7 +37,7 @@ Release/ binary/ build/ ipch/ -lib/ +lib/* Nethack.sln Nethack.sdf Nethack.opensdf @@ -81,3 +81,9 @@ win/share/monthin.txt win/share/objthin.txt win/share/oththin.txt # end of ms-dos + +#libnethack +targets/* +#test.js +#sys/lib/npm-package/build/nethack.js +#sys/lib/npm-package/build/nethack.wasm diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..ef732d5c0 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,6 @@ +[submodule "submodules/lua"] + path = submodules/lua + url = https://github.com/lua/lua.git +[submodule "submodules/pdcurses"] + path = submodules/pdcurses + url = https://github.com/wmcbrine/PDCurses.git diff --git a/Cross-compiling b/Cross-compiling index b7fc4b58b..f09be14b7 100644 --- a/Cross-compiling +++ b/Cross-compiling @@ -1,4 +1,4 @@ -Cross-compiling NetHack 3.7 Last edit: May 31, 2020 +Cross-compiling NetHack 3.7 Last edit: December 7, 2020 The NetHack 3.7 build process differs from the build process of previous versions in some important ways that make it possible to use a cross-compiler @@ -17,6 +17,8 @@ Part B Contents: B2. What needs to be built and executed on the HOST? B3. What needs to be built for the TARGET? B4. Case sample: msdos + B5. Case sample: amiga (started but incomplete) + B6. Case sample: Web Assembly, libnh -------------------------------------------------------------------------------- Part A - Cross-compiling NetHack @@ -45,7 +47,7 @@ may include, but not necessarily be limited to, any of the following: o Compilers: Some of the native compilers on historical platforms may only support the particular dialect of C that was popular when the platform and - compiler were in their prime. + compiler were in their prime. Another useful potential result of cross-compiling, is that it paves the way for carrying out test and production builds of NetHack for multiple target @@ -65,27 +67,27 @@ steps to be carried out: (a) additional build steps to follow, including some header files: pm.h, onames.h, date.h. (b) creation of files, containing information required by, - or about the game during its execution, that are stored in a + or about the game during its execution, that are stored in a portable, platform-independent way, that need to be inserted into the game package. (c) creation of files containing information required by, or about the game during its execution, that are stored in an architecture and/or platform and/or operating system dependent way, that need - to be inserted into the game package (the quest text format is + to be inserted into the game package (the quest text format is one example). - 3. Compile and link the level compiler. This step needs to execute + 3. Compile and link the level compiler. This step needs to execute work-alike tools to lex and yacc, or needs to build pre-built lex and yacc output (.c, .h files) that are provided in the sys/share part of the NetHack source code tree. 4. Execute the level compiler to read dat/*.des files and create - a set of binary output files that are architecture and/or operating + a set of binary output files that are architecture and/or operating system dependent on the build platform, for use by the game during its execution. 5. Compile and link the dungeon compiler. Like the level compiler, this - step needs to execute work-alike tools to lex and yacc, or needs to + step needs to execute work-alike tools to lex and yacc, or needs to build pre-built lex and yacc output (.c, .h files) that are provided in the sys/share part of the NetHack source code tree. - 6. Execute the dungeon compiler to read dat/dungeon.def and create + 6. Execute the dungeon compiler to read dat/dungeon.def and create a set of binary output files that are architecture and/or operating system dependent on the build platform, for use by the game during its execution. @@ -126,7 +128,7 @@ steps to be carried out: (a) additional build steps to follow, including some header files: pm.h, onames.h, date.h. (b) creation of files, containing information required by, - or about the game during its execution, that are stored in a + or about the game during its execution, that are stored in a portable, platform-independent way, that need to be inserted into the game package. 3. Compile and link several less critical utilities such as uudecode, @@ -143,7 +145,7 @@ steps to be carried out: previous steps 2b, 3 and 4 above. Step 4 is now the only impediment to cross-compiling NetHack, and is resolved -by executing step 4 using a cross-compiler that runs on the build (host) +by executing step 4 using a cross-compiler that runs on the build (host) platform to produce a resulting binary for the target platform, instead of executing the native compiler. @@ -158,18 +160,15 @@ cross-compiling possible: o There is no creation of platform-dependent files, such as the quest text files, by makedefs during the build process. Instead, the quest text files have been converted to Lua and are inserted into the game - package for processing by the embedded Lua - during execution of NetHack. + package for processing by the embedded Lua during execution of NetHack. o There is no build-time level compiler involved. Instead, the level descriptions have been converted to Lua and are inserted into the game - package for processing by the embeded Lua - during execution of NetHack. + package for processing by the embeded Lua during execution of NetHack. o There is no build-time dungeon compiler involved. Instead, the dungeon description has been converted to Lua and is inserted into the game - package for processing by the embeded Lua - during execution of NetHack. + package for processing by the embeded Lua during execution of NetHack. o Some of the build and option information that was formerly produced during build time by makedefs, and contained information about the @@ -182,7 +181,7 @@ cross-compiling possible: +------------------------------------------------------------+ o If you have a favourite target platform (let's call it XX-Platform for - example purposes) that you'd like to see NetHack be able to run on, do + example purposes) that you'd like to see NetHack be able to run on, do some research to find out if a cross-compiler exists that: - produces output for XX-Platform. - executes on a platform that you use and love (Linux, Windows, @@ -191,9 +190,9 @@ cross-compiling possible: o Then, make the community, devteam, and others aware that you're starting a cross-compile of NetHack for XX-Platform. You might need to ask some - "starting out" questions initially, and as you get deeper into it, you + "starting out" questions initially, and as you get deeper into it, you might need to ask some tougher questions. - + o Perhaps consider forking from NetHack on GitHub, and do the cross-compiler work there in your fork. Strive to get it to a point where it's ready to play-test on XX-Platform, or perhaps even use an emulator @@ -205,9 +204,9 @@ cross-compiling possible: - It will make it possible and straightforward to merge upstream NetHack changes into your work for the XX-Platform cross-compile so that it stays current with the game as it evolves. - - You may get help from others in the form of suggestions, or + - You may get help from others in the form of suggestions, or pull-requests, or offers to join the development. Chances are, - you aren't the only person out there that would like to + you aren't the only person out there that would like to establish/resurrect/maintain NetHack on XX-Platform. Have fun! @@ -258,7 +257,7 @@ On the HOST, here are the mandatory things that have to be built. a) Using the HOST native compiler, build HOST native utility makedefs Compile and link the following with these compiler switches: - -DCROSSCOMPILE and -DCROSSCOMPILE_HOST + -DCROSSCOMPILE from sources: util/makedefs.c, src/mdlib.c, src/monst.c, src/objects.c b) Execute HOST native makedefs utility, util/makedefs, as follows: @@ -307,7 +306,7 @@ On the HOST, here are the mandatory things that have to be built. util/uudecode from sources: sys/share/uudecode.c - purpose: convert some binary files, that are + purpose: convert some binary files, that are distributed in the NetHack sources in uuencoded format, back into their original binary state @@ -452,67 +451,240 @@ Using the cross-compiler, build the following targets: Cross-compiler used: Andrew Wu's djgpp cross-compiler Cross-compiler url: https://github.com/andrewwutw/build-djgpp Cross-compiler pre-built binary downloads: - https://github.com/andrewwutw/build-djgpp/releases/download/v2.9/ - Mac OS X pre-built binary: djgpp-osx-gcc550.tar.bz2 (tested) - Linux pre-built binary : djgpp-linux64-gcc550.tar.bz2 (tested) - mingw pre-built binary : djgpp-mingw-gcc550-standalone.zip (untested) + https://github.com/andrewwutw/build-djgpp/releases/download/v3.0/ + Cross-compiler bits tested: + https://github.com/andrewwutw/build-djgpp + and the pre-built binary for your platform from: + https://github.com/andrewwutw/build-djgpp/releases/download/v3.0/ + and a DOS-extender (for including in msdos packaging) from + http://sandmann.dotster.com/cwsdpmi/csdpmi7b.zip + and pdcurses from: + https://github.com/wmcbrine/PDCurses.git -The msdos cross-compile for NetHack 3.7 uses two phases of compiles: -Phase1 is the host-side prerequisite stuff that needs to be done first. -Phase2 is the cross-compile pieces using the djgpp cross-compiler hosted on -Linux, Mac OS X, or Windows mingw. + - A shell script to download that djgpp cross-compiler and associated + pieces for either linux or macOS is available: -First, on the host platform, you need to set up for a native Unix NetHack -build in the usual way. For example, on linux: - cd sys/unix - sh setup.sh hints/linux - cd ../.. - make fetch-lua + sh sys/msdos/fetch-cross-compiler.sh -Now, you could proceed to go ahead and issue - make all -to build a native NetHack at that point if you wish, but it is not needed -for the msdos cross-compile. + That script won't install anything, it just does file fetches and stores + them in subfolders of lib. The linux.2020 and macOS.2020 hints files are + configured to find the cross-compiler there if you add + CROSS_TO_MSDOS=1 + on your make command line. -Instead, a test shell script has been put together that will next accomplish -each of the following tasks when it is executed. The shell script can be -invoked by: - sh sys/msdos/msdos-cross-compile.sh -but before you do that, please read the paragraphs below. + Note: Both the fetch-cross-compiler.sh script and and the msdos + cross-compile and package procedures require unzip and zip to be available + on your host build system. -The shell script is meant to accomplish the following things: + On your linux host: - Prep : the script downloads the djgpp cross-compiler for the host - platform into lib/djgpp (it doesn't install anything on the - system, nor does it need to, it just downloads them into the - identified directories), it downloads a copy of the msdos - dos-extender into lib/djgpp/cwsdpmi for later packaging up with - the msdos game, and it downloads pdcurses into lib/pdcurses - for cross-compiling during the TARGET build. + cd sys/unix ; sh setup.sh hints/linux.2020 ; cd ../.. + make fetch-lua - Be certain to ensure the right products are at the url's - identified above *before* you execute the Case sample msdos - cross-compile script. The correct products were at those url's - at the time this was written in Dec 2019, but we don't assume - any responsibility for what is at those url's now or in the - future. You need to check before executing the script. + On your macOS host: - Phase1 : the script uses the Makefile sys/msdos/Makefile1.cross - to complete the host-side build steps using the native gcc - compiler for the host platform. During phase1 the host obj - files are put in subfolder src/host_o to keep them separated - and distinguishable from the target obj files that will be - built in phase2. + cd sys/unix ; sh setup.sh hints/macOS.2020 ; cd ../.. + make fetch-lua - Phase2 : the script uses the Makefile sys/msdos/Makefile2.cross - to complete the target-side build steps using the - cross-compiler that was obtained during the prep step of the - script described above. During phase2 the target obj files - are put in src/msdos_o to keep them separated and - distinguishable from the host obj files + The MSDOS cross-compile can then be carried out by specifying + CROSS_TO_MSDOS=1 on the make command line: - Package: the script then packages up the results that reside in - msdos-binary into a zip file which it places in lib called - nh370dos.zip. + make CROSS_TO_MSDOS=1 all + make CROSS_TO_MSDOS=1 package + You can explicitly include tty and curses support if desired. The default + you'll end up with is a tty-only cross-compile build: + + make WANT_WIN_TTY=1 WANT_WIN_CURSES=1 CROSS_TO_MSDOS=1 all + make WANT_WIN_TTY=1 WANT_WIN_CURSES=1 CROSS_TO_MSDOS=1 package + + Result: The "make package" target will bundle all of the necessary + components to run NetHack on msdos into a folder: + targets/msdos/pkg + and then it zips the contents of that folder into: + targets/msdos/nh370dos.zip + + Also note that building the msdos targets using the make command + above, does not preclude you from building local linux or macOS + targets as well. Just drop the CROSS_TO_MSDOS=1 from the make + command line. That's because the cross-compiler hints additions are + enclosed inside ifdef sections and won't interfere with the + non-cross-compile build in that case. + + +-------------------------+ + | B5. Case sample: amiga | + +-------------------------+ + +Disclaimer: This is a minimal recipe, just to help someone else get + started if they have a desire to get a full cross-compile of + NetHack going for the Amiga. + See CAVEATS below. + +Cross-compiler used: bebbo's amiga-gcc +Cross-compiler url: https://github.com/bebbo/amiga-gcc + + To our knowledge, a pre-built copy of the cross-compiler isn't available, + so you will likely have to obtain the cross-compiler sources via git and + build it on your system. + + The build prerequisite packages for building the compiler on Ubuntu can be + easily obtained: + + sudo apt install make wget git gcc g++ lhasa libgmp-dev \ + libmpfr-dev libmpc-dev flex bison gettext texinfo ncurses-dev \ + autoconf rsync + + The build prerequisite packages for macOS via homebrew are documented but + not tested by us any of us to date. + + brew install bash wget make lhasa gmp mpfr libmpc flex gettext \ + texinfo gcc make autoconf + + After installing the prerequite packages and the cross-compiler + it was a straightforward build: + + git clone https://github.com/bebbo/amiga-gcc.git + cd amiga-gcc + make update + + [Note that you may have to take ownership of the files in the bebbo + repo via chown before succesfully carrying out the next steps] + + make clean + make clean-prefix + date; make all -j3 >&b.log; date + + The compiler pieces are installed in /opt/amiga by default. If you prefer, + you can alter the prefix before you build if you want. The instructions + for doing so were spelled out at the time of this writing at: + + https://github.com/bebbo/amiga-gcc + + On your linux host: + + cd sys/unix ; sh setup.sh hints/linux.2020 ; cd ../.. + make fetch-lua + + On your macOS host: + + cd sys/unix ; sh setup.sh hints/macOS.2020 ; cd ../.. + make fetch-lua + + The Amiga cross-compile can then be carried out by specifying + CROSS_TO_AMIGA=1 on the make command line: + + make CROSS_TO_AMIGA=1 all + make CROSS_TO_AMIGA=1 package + + You can explicitly include tty and curses support if desired, otherwise + you'll end up with a tty-only cross-compile build. The SDL1 pdcurses + support has not been tested. + + make WANT_WIN_TTY=1 WANT_WIN_CURSES=1 CROSS_TO_AMIGA=1 all + + Result: The "make package" target will bundle the (hopefully) necessary + components to run NetHack on msdos into a folder: + targets/amiga/pkg + and then it zips the contents of that folder into: + targets/amiga/nh370ami.zip + + Also note that building the amiga targets using the make command + above, does not preclude you from building local linux or macOS + targets as well. Just drop the CROSS_TO_AMIGA=1 from the make + command line. + + The cross-compiler hints additions are enclosed inside ifdef sections + and won't interfere with the non-cross-compile build in that case. + + CAVEATS: The original NetHack Amiga build steps included the source for + some utilities that were built and executed on the amiga: + txt2iff and xpm2iff + as part of the NetHack build procedure on amiga. + Those did not compile out-of-the-box on the linux host. They + will either have to be: + - ported to build and run on the linux or macOS cross-compile + host + or + + - their functionality will have to be rolled into amiga NetHack + itself and executed on the target Amiga the first time the game + is run, perhaps. + + If you make headway, or are successful getting a working copy of + NetHack going on the amiga, drop us a note at devteam@nethack.org. + + +--------------------------------+ + | B6. Case sample: Web Assembly | + +--------------------------------+ + +Credit: The initial Web Assembly cross compile was found in a pull request: + https://github.com/NetHack/NetHack/pull/385 + by apowers313. The pull request was merged with some accompanying + NetHack source tree integration changes in early October 2020. + +Cross-compiler used: emscripten +Cross-compiler url: https://emscripten.org/docs/getting_started/downloads.html + + Here's a brief guide to obtaining the cross-compiler sources via git and + building it on your system. + + For Ubuntu, the build prerequisite packages for building the compiler can + be easily obtained: + + sudo apt-get install python3 cmake default-jre + + For macOS, you will need to install Xcode, git, cmake, Python 3.5 or new + (at time of this writing). + + After installing the prerequite packages above, obtain the cross-compiler + via git and build it from the directory of your choice using steps similar + to these: + + git clone https://github.com/emscripten-core/emsdk.git + cd emsdk + git pull + ./emsdk install latest + ./emsdk activate latest + source ./emsdk_env.sh + + The steps above reflect what was outlined at this url at the time + of writing: + + https://emscripten.org/docs/getting_started/downloads.html + + That is the definitive source and trumps anything documented here. + + On your linux host, prepare to cross-compile NetHack as follows: + + cd sys/unix ; sh setup.sh hints/linux.2020 ; cd ../.. + make fetch-lua + + On your macOS host, prepare to cross-compile NetHack as follows: + + cd sys/unix ; sh setup.sh hints/macOS.2020 ; cd ../.. + make fetch-lua + + Then, cross-compile to targets/wasm as follows: + + make CROSS_TO_WASM=1 + + You can build src/libnh.a from pull request 385 as follows: + + make WANT_LIBNH=1 + + Do not add any additional windowport interfaces to your build + (such as WANT_WIN_TTY=1 WANT_WIN_CURSES=1 WANT_WIN_X11=1 or + WANT_WIN_QT=1) as those aren't applicable to the Web Assembly + or nethacklib builds. A "shim" pseudo-windowport is included + from pull request 385. + + Result: As mentioned, the wasm cross-compile will end up in + targets/wasm and the nethacklib.a will end up in + src. + + The cross-compiler hints additions are enclosed inside ifdef sections + and shouldn't interfere with the non-cross-compile builds using + hints/linux.2020 or hints/macOS.2020. + +--- diff --git a/DEVEL/Developer.txt b/DEVEL/Developer.txt index 7a588c203..ad4262bb6 100644 --- a/DEVEL/Developer.txt +++ b/DEVEL/Developer.txt @@ -4,7 +4,7 @@ |___/\___|\_/\___|_\___/ .__/\___|_| |_| -# NetHack 3.6 Developer.txt $NHDT-Date: 1524689668 2018/04/25 20:54:28 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.13 $ +# NetHack 3.7 Developer.txt $NHDT-Date: 1596498265 2020/08/03 23:44:25 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.19 $ # Copyright (c) 2015 by Kenneth Lorber, Kensington, Maryland # NetHack may be freely redistributed. See license for details. diff --git a/DEVEL/code_features.txt b/DEVEL/code_features.txt index 4e89df7f5..25859a5f1 100644 --- a/DEVEL/code_features.txt +++ b/DEVEL/code_features.txt @@ -1,4 +1,4 @@ -# NetHack 3.6 code_features.txt $NHDT-Date: 1524689669 2018/04/25 20:54:29 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.3 $ +# NetHack 3.7 code_features.txt $NHDT-Date: 1596498264 2020/08/03 23:44:24 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.6 $ # Copyright (c) 2015 by Michael Allison # NetHack may be freely redistributed. See license for details. diff --git a/DEVEL/code_style.txt b/DEVEL/code_style.txt index 6946604e1..a62e1f9e9 100644 --- a/DEVEL/code_style.txt +++ b/DEVEL/code_style.txt @@ -1,4 +1,4 @@ -# NetHack 3.6 code_style.txt $NHDT-Date: 1524689669 2018/04/25 20:54:29 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.2 $ +# NetHack 3.7 code_style.txt $NHDT-Date: 1596498264 2020/08/03 23:44:24 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.5 $ # Copyright (c) 2015 by Derek S. Ray # NetHack may be freely redistributed. See license for details. diff --git a/DEVEL/git_recipes.txt b/DEVEL/git_recipes.txt index 09f2344e3..e4ca94925 100644 --- a/DEVEL/git_recipes.txt +++ b/DEVEL/git_recipes.txt @@ -1,4 +1,4 @@ -# NetHack 3.6 git_recipes.txt $NHDT-Date: 1524689669 2018/04/25 20:54:29 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.9 $ +# NetHack 3.7 git_recipes.txt $NHDT-Date: 1596498266 2020/08/03 23:44:26 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.11 $ # Copyright (c) 2015 by Derek S. Ray # NetHack may be freely redistributed. See license for details. diff --git a/DEVEL/gitinfo.pl b/DEVEL/gitinfo.pl index 91f71e65e..f348f8e6e 100644 --- a/DEVEL/gitinfo.pl +++ b/DEVEL/gitinfo.pl @@ -1,5 +1,5 @@ #!/usr/bin/perl -# NetHack 3.6 getinfo.pl $NHDT-Date: 1524689669 2018/04/25 20:54:29 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.2 $ +# NetHack 3.7 getinfo.pl $NHDT-Date: 1596498266 2020/08/03 23:44:26 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.3 $ # Copyright (c) 2018 by Michael Allison # NetHack may be freely redistributed. See license for details. diff --git a/DEVEL/hooksdir/NHadd b/DEVEL/hooksdir/NHadd index 3e4b24b85..c4d6e547d 100644 --- a/DEVEL/hooksdir/NHadd +++ b/DEVEL/hooksdir/NHadd @@ -1,5 +1,5 @@ #!/usr/bin/perl -# NetHack 3.6 NHadd $NHDT-Date: 1524689631 2018/04/25 20:53:51 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.1 $ +# NetHack 3.7 NHadd $NHDT-Date: 1596498406 2020/08/03 23:46:46 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.2 $ # Copyright (c) 2015 by Kenneth Lorber, Kensington, Maryland # NetHack may be freely redistributed. See license for details. diff --git a/DEVEL/hooksdir/NHgithook.pm b/DEVEL/hooksdir/NHgithook.pm index 0c64ab12f..c7c3456f5 100644 --- a/DEVEL/hooksdir/NHgithook.pm +++ b/DEVEL/hooksdir/NHgithook.pm @@ -1,5 +1,5 @@ # -# NetHack 3.6 NHgithook.pm $NHDT-Date: 1524689631 2018/04/25 20:53:51 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.6 $ +# NetHack 3.7 NHgithook.pm $NHDT-Date: 1596498406 2020/08/03 23:46:46 $ $NHDT-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. diff --git a/DEVEL/hooksdir/NHsubst b/DEVEL/hooksdir/NHsubst index 45e8297e1..99621fc57 100755 --- a/DEVEL/hooksdir/NHsubst +++ b/DEVEL/hooksdir/NHsubst @@ -1,5 +1,5 @@ #!/usr/bin/perl -# NetHack 3.6 NHsubst $NHDT-Date: 1524689631 2018/04/25 20:53:51 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.4 $ +# NetHack 3.7 NHsubst $NHDT-Date: 1596498407 2020/08/03 23:46:47 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.5 $ # Copyright (c) 2015 by Kenneth Lorber, Kensington, Maryland # NetHack may be freely redistributed. See license for details. @@ -392,7 +392,7 @@ $TEST-Branch: theirs $ TEST 8: <<< d1 -/* NetHack 3.6 objnam.c $TEST-Date$ $TEST-Branch$:$TEST-Revision$ */ +/* NetHack 3.7 objnam.c $TEST-Date$ $TEST-Branch$:$TEST-Revision$ */ === -/* NetHack 3.6 objnam.c $TEST-Date: 1426977394 2015/03/21 22:36:34 $ $TEST-Branch: master $:$TEST-Revision: 1.108 $ */ +/* NetHack 3.7 objnam.c $TEST-Date: 1426977394 2015/03/21 22:36:34 $ $TEST-Branch: master $:$TEST-Revision: 1.108 $ */ >>> d3 diff --git a/DEVEL/hooksdir/NHtext b/DEVEL/hooksdir/NHtext index 44a70db42..8e0d9a9c2 100755 --- a/DEVEL/hooksdir/NHtext +++ b/DEVEL/hooksdir/NHtext @@ -1,5 +1,5 @@ #!/usr/bin/perl -# NetHack 3.6 NHtext $NHDT-Date: 1524689631 2018/04/25 20:53:51 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.8 $ +# NetHack 3.7 NHtext $NHDT-Date: 1596498408 2020/08/03 23:46:48 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.9 $ # Copyright (c) 2015 by Kenneth Lorber, Kensington, Maryland # NetHack may be freely redistributed. See license for details. diff --git a/DEVEL/hooksdir/applypatch-msg b/DEVEL/hooksdir/applypatch-msg index 4432174ab..2318186ed 100755 --- a/DEVEL/hooksdir/applypatch-msg +++ b/DEVEL/hooksdir/applypatch-msg @@ -1,5 +1,5 @@ #!/usr/bin/perl -# NetHack 3.6 applypatch-msg $NHDT-Date: 1524689646 2018/04/25 20:54:06 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.1 $ +# NetHack 3.7 applypatch-msg $NHDT-Date: 1596498405 2020/08/03 23:46:45 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.2 $ # Copyright (c) 2015 by Kenneth Lorber, Kensington, Maryland # NetHack may be freely redistributed. See license for details. diff --git a/DEVEL/hooksdir/commit-msg b/DEVEL/hooksdir/commit-msg index 1f2ad49a2..e4befa0e5 100755 --- a/DEVEL/hooksdir/commit-msg +++ b/DEVEL/hooksdir/commit-msg @@ -1,5 +1,5 @@ #!/usr/bin/perl -# NetHack 3.6 commit-msg $NHDT-Date: 1524689646 2018/04/25 20:54:06 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.1 $ +# NetHack 3.7 commit-msg $NHDT-Date: 1596498405 2020/08/03 23:46:45 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.2 $ # Copyright (c) 2015 by Kenneth Lorber, Kensington, Maryland # NetHack may be freely redistributed. See license for details. diff --git a/DEVEL/hooksdir/post-checkout b/DEVEL/hooksdir/post-checkout index c7fde4f18..d7e6c5724 100755 --- a/DEVEL/hooksdir/post-checkout +++ b/DEVEL/hooksdir/post-checkout @@ -1,5 +1,5 @@ #!/usr/bin/perl -# NetHack 3.6 post-checkout $NHDT-Date: 1524689632 2018/04/25 20:53:52 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.2 $ +# NetHack 3.7 post-checkout $NHDT-Date: 1596498409 2020/08/03 23:46:49 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.3 $ # Copyright (c) 2015 by Kenneth Lorber, Kensington, Maryland # NetHack may be freely redistributed. See license for details. diff --git a/DEVEL/hooksdir/post-commit b/DEVEL/hooksdir/post-commit index 309eec4ce..cb37b3800 100755 --- a/DEVEL/hooksdir/post-commit +++ b/DEVEL/hooksdir/post-commit @@ -1,5 +1,5 @@ #!/usr/bin/perl -# NetHack 3.6 post-commit $NHDT-Date: 1524689632 2018/04/25 20:53:52 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.2 $ +# NetHack 3.7 post-commit $NHDT-Date: 1596498409 2020/08/03 23:46:49 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.3 $ # Copyright (c) 2015 by Kenneth Lorber, Kensington, Maryland # NetHack may be freely redistributed. See license for details. diff --git a/DEVEL/hooksdir/post-merge b/DEVEL/hooksdir/post-merge index 6ca8dc532..a634f51ef 100755 --- a/DEVEL/hooksdir/post-merge +++ b/DEVEL/hooksdir/post-merge @@ -1,5 +1,5 @@ #!/usr/bin/perl -# NetHack 3.6 post-merge $NHDT-Date: 1524689632 2018/04/25 20:53:52 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.2 $ +# NetHack 3.7 post-merge $NHDT-Date: 1596498410 2020/08/03 23:46:50 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.3 $ # Copyright (c) 2015 by Kenneth Lorber, Kensington, Maryland # NetHack may be freely redistributed. See license for details. diff --git a/DEVEL/hooksdir/post-rewrite b/DEVEL/hooksdir/post-rewrite index 317eddea0..655c1a0cd 100755 --- a/DEVEL/hooksdir/post-rewrite +++ b/DEVEL/hooksdir/post-rewrite @@ -1,5 +1,5 @@ #!/usr/bin/perl -# NetHack 3.6 post-rewrite $NHDT-Date: 1524689632 2018/04/25 20:53:52 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.1 $ +# NetHack 3.7 post-rewrite $NHDT-Date: 1596498411 2020/08/03 23:46:51 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.2 $ # Copyright (c) 2015 by Kenneth Lorber, Kensington, Maryland # NetHack may be freely redistributed. See license for details. diff --git a/DEVEL/hooksdir/pre-applypatch b/DEVEL/hooksdir/pre-applypatch index f71d1fda3..3b57a6f53 100755 --- a/DEVEL/hooksdir/pre-applypatch +++ b/DEVEL/hooksdir/pre-applypatch @@ -1,5 +1,5 @@ #!/usr/bin/perl -# NetHack 3.6 pre-applypatch $NHDT-Date: 1524689632 2018/04/25 20:53:52 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.1 $ +# NetHack 3.7 pre-applypatch $NHDT-Date: 1596498411 2020/08/03 23:46:51 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.2 $ # Copyright (c) 2015 by Kenneth Lorber, Kensington, Maryland # NetHack may be freely redistributed. See license for details. diff --git a/DEVEL/hooksdir/pre-auto-gc b/DEVEL/hooksdir/pre-auto-gc index e1c39bebd..d1ab9b005 100755 --- a/DEVEL/hooksdir/pre-auto-gc +++ b/DEVEL/hooksdir/pre-auto-gc @@ -1,5 +1,5 @@ #!/usr/bin/perl -# NetHack 3.6 pre-auto-gc $NHDT-Date: 1524689632 2018/04/25 20:53:52 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.1 $ +# NetHack 3.7 pre-auto-gc $NHDT-Date: 1596498412 2020/08/03 23:46:52 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.2 $ # Copyright (c) 2015 by Kenneth Lorber, Kensington, Maryland # NetHack may be freely redistributed. See license for details. diff --git a/DEVEL/hooksdir/pre-commit b/DEVEL/hooksdir/pre-commit index 83dacdd41..bb5dbfe84 100755 --- a/DEVEL/hooksdir/pre-commit +++ b/DEVEL/hooksdir/pre-commit @@ -1,5 +1,5 @@ #!/usr/bin/perl -# NetHack 3.6 pre-commit $NHDT-Date: 1524689632 2018/04/25 20:53:52 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.1 $ +# NetHack 3.7 pre-commit $NHDT-Date: 1596498413 2020/08/03 23:46:53 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.2 $ # Copyright (c) 2015 by Kenneth Lorber, Kensington, Maryland # NetHack may be freely redistributed. See license for details. diff --git a/DEVEL/hooksdir/pre-push b/DEVEL/hooksdir/pre-push index d65dcbecb..c2639fa2e 100755 --- a/DEVEL/hooksdir/pre-push +++ b/DEVEL/hooksdir/pre-push @@ -1,5 +1,5 @@ #!/usr/bin/perl -# NetHack 3.6 pre-push $NHDT-Date: 1524689632 2018/04/25 20:53:52 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.1 $ +# NetHack 3.7 pre-push $NHDT-Date: 1596498413 2020/08/03 23:46:53 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.2 $ # Copyright (c) 2015 by Kenneth Lorber, Kensington, Maryland # NetHack may be freely redistributed. See license for details. diff --git a/DEVEL/hooksdir/pre-rebase b/DEVEL/hooksdir/pre-rebase index e25f41cac..7f447a082 100755 --- a/DEVEL/hooksdir/pre-rebase +++ b/DEVEL/hooksdir/pre-rebase @@ -1,5 +1,5 @@ #!/usr/bin/perl -# NetHack 3.6 pre-rebase $NHDT-Date: 1524689633 2018/04/25 20:53:53 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.1 $ +# NetHack 3.7 pre-rebase $NHDT-Date: 1596498414 2020/08/03 23:46:54 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.2 $ # Copyright (c) 2015 by Kenneth Lorber, Kensington, Maryland # NetHack may be freely redistributed. See license for details. diff --git a/Files b/Files index a4bac931f..7972c7373 100644 --- a/Files +++ b/Files @@ -1,4 +1,4 @@ -This is a listing of all files in a full NetHack 3.6 distribution, organized +This is a listing of all files in a full NetHack 3.7 distribution, organized in their standard manner on a UNIX system. It indicates which files are necessary for which versions, so that you can tell which files may be deleted from or not transferred to your system if you wish. @@ -7,8 +7,8 @@ from or not transferred to your system if you wish. .: (files in top directory) -.clang-format .travis.yml Cross-compiling Files -Porting README +.clang-format Cross-compiling Files +Porting README azure-pipelines.yml DEVEL: (files for people developing changes to NetHack) @@ -102,20 +102,22 @@ ntconf.h obj.h objclass.h optlist.h patchlevel.h pcconf.h permonst.h prop.h quest.h rect.h region.h rm.h skills.h sp_lev.h spell.h sys.h system.h tcap.h tileset.h timeout.h -tradstdc.h trampoli.h trap.h unixconf.h vision.h -vmsconf.h winami.h wincurs.h winprocs.h wintype.h -you.h youprop.h +tradstdc.h trap.h unixconf.h vision.h vmsconf.h +winami.h wincurs.h winprocs.h wintype.h you.h +youprop.h (file for tty versions) wintty.h -(files for various Macintosh versions) -mac-carbon.h mac-qt.h mac-term.h macpopup.h mactty.h -macwin.h mttypriv.h +outdated: +(files that are no longer maintained for current game code) +.travis.yml outdated/include: (files that are no longer maintained for current game code) -amiconf.h beconf.h def_os2.h macconf.h os2conf.h tosconf.h wceconf.h +amiconf.h beconf.h def_os2.h mac-carbon.h mac-qt.h +mac-term.h macconf.h macpopup.h mactty.h macwin.h +mttypriv.h os2conf.h tosconf.h trampoli.h wceconf.h outdated/sys/amiga: (files for Amiga versions - untested for 3.7) @@ -123,9 +125,9 @@ Build.ami Install.ami Makefile.agc Makefile.ami NetHack.cnf amidos.c amidos.p amifont.uu amifont8.uu amigst.c amii.hlp amimenu.c amirip.c amistack.c amitty.c amiwind.c amiwind.p clipwin.c colorwin.c grave16.xpm -ifchange mkdmake txt2iff.c winami.c winami.p -winchar.c windefs.h winext.h winfuncs.c winkey.c -winmenu.c winproto.h winreq.c winstr.c xpm2iff.c +ifchange mkdmake txt2iff.c winamenu.c winami.c +winami.p winchar.c windefs.h winext.h winfuncs.c +winkey.c winproto.h winreq.c winstr.c xpm2iff.c outdated/sys/atari: (files for Atari version - untested for 3.7) @@ -153,6 +155,10 @@ outdated/sys/os2: (files for OS/2 version - untested for 3.7) Install.os2 Makefile.os2 nhpmico.uu os2.c +outdated/sys/unix: +(files that are no longer maintained for current game code) +README.linux + outdated/sys/wince: (files for Windows CE and PocketPC - untested for 3.7) Install.ce bootstrp.mak celib.c cesetup.bat cesound.c @@ -220,15 +226,27 @@ uhitm.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 +submodules: +(files in top directory) +lua pdcurses + +sys/libnh: +(files in top directory) +README.md libnhmain.c sysconf + +sys/libnh/test: +(files in top directory) +README.md libtest.c run.sh + sys/msdos: (files for MSDOS version) -Install.dos Makefile.GCC Makefile1.cross -Makefile2.cross msdos-cross-compile.sh msdos.c -msdoshlp.txt nhlua.h pckeys.c -pctiles.c pctiles.h pcvideo.h -portio.h setup.bat sysconf -tile2bin.c vesa.h video.c -vidtxt.c vidvesa.c vidvga.c +Install.dos Makefile.GCC fetch-cross-compiler.sh +msdos.c msdoshlp.txt nhlua.h +pckeys.c pctiles.c pctiles.h +pcvideo.h portio.h setup.bat +sysconf tile2bin.c vesa.h +video.c vidtxt.c vidvesa.c +vidvga.c (files for running MSDOS binary under Windows) nhico.uu nhpif.uu @@ -276,10 +294,10 @@ pmatchregex.c sys/unix: (files for UNIX versions) Install.unx Makefile.dat Makefile.doc Makefile.src -Makefile.top Makefile.utl NewInstall.unx README.linux -README.xcode XCode.xcconfig depend.awk gitinfo.sh -mkmkfile.sh nethack.sh setup.sh sysconf -unixmain.c unixres.c unixunix.c +Makefile.top Makefile.utl NewInstall.unx README.xcode +XCode.xcconfig depend.awk gitinfo.sh mkmkfile.sh +nethack.sh setup.sh sysconf unixmain.c +unixres.c unixunix.c (files for replacement cpp, only needed by some ancient UNIX systems) cpp1.shr cpp2.shr cpp3.shr @@ -304,10 +322,15 @@ sys/unix/hints: (files for configuring UNIX NetHack versions) linux linux-chroot linux-minimal linux-qt4 linux-qt5 linux-x11 -macosx macosx.sh macosx10.5 -macosx10.7 macosx10.8 macosx10.10 -macosx10.10-qt macosx10.14 solaris -solaris-playground unix +linux.2020 macOS.2020 macosx +macosx.sh macosx10.5 macosx10.7 +macosx10.8 macosx10.10 macosx10.10-qt +macosx10.14 solaris solaris-playground +unix + +sys/unix/hints/include: +(files for configuring UNIX NetHack versions) +cross-post.2020 cross-pre.2020 multiw-1.2020 multiw-2.2020 sys/vms: (files for VMS version) @@ -338,16 +361,17 @@ dlb_main.c makedefs.c mdgrep.h mdgrep.pl panic.c recover.c win/Qt: (files for the Qt 4 or 5 widget library - X11, Windows, Mac OS X) -qt_bind.cpp qt_bind.h qt_click.cpp qt_click.h qt_clust.cpp -qt_clust.h qt_delay.cpp qt_delay.h qt_glyph.cpp qt_glyph.h -qt_icon.cpp qt_icon.h qt_inv.cpp qt_inv.h qt_kde0.h -qt_key.cpp qt_key.h qt_line.cpp qt_line.h qt_main.cpp -qt_main.h qt_map.cpp qt_map.h qt_menu.cpp qt_menu.h -qt_msg.cpp qt_msg.h qt_plsel.cpp qt_plsel.h qt_rip.cpp -qt_rip.h qt_set.cpp qt_set.h qt_stat.cpp qt_stat.h -qt_str.cpp qt_str.h qt_streq.cpp qt_streq.h qt_svsel.cpp -qt_svsel.h qt_win.cpp qt_win.h qt_xcmd.cpp qt_xcmd.h -qt_xpms.h qt_yndlg.cpp qt_yndlg.h +Qt-issues.txt qt_bind.cpp qt_bind.h qt_click.cpp qt_click.h +qt_clust.cpp qt_clust.h qt_delay.cpp qt_delay.h qt_glyph.cpp +qt_glyph.h qt_icon.cpp qt_icon.h qt_inv.cpp qt_inv.h +qt_kde0.h qt_key.cpp qt_key.h qt_line.cpp qt_line.h +qt_main.cpp qt_main.h qt_map.cpp qt_map.h qt_menu.cpp +qt_menu.h qt_msg.cpp qt_msg.h qt_plsel.cpp qt_plsel.h +qt_post.h qt_pre.h qt_rip.cpp qt_rip.h qt_set.cpp +qt_set.h qt_stat.cpp qt_stat.h qt_str.cpp qt_str.h +qt_streq.cpp qt_streq.h qt_svsel.cpp qt_svsel.h qt_win.cpp +qt_win.h qt_xcmd.cpp qt_xcmd.h qt_xpms.h qt_yndlg.cpp +qt_yndlg.h win/X11: (files for X versions) @@ -379,6 +403,10 @@ nhsplash.xpm objects.txt other.txt ppmwrite.c renumtiles.pl safeproc.c thintile.c tile.doc tile.h tile2bmp.c tilemap.c tileset.c tiletext.c +win/shim: +(file in top directory) +winshim.c + win/tty: (files for tty versions) getline.c termcap.c topl.c wintty.c @@ -401,8 +429,8 @@ record.uu resource.h rip.uu splash.uu tiles-mingw32.mak tiles.mak winMS.h -win/win32/vs2017: -(files for Visual Studio 2017 Community Edition builds) +win/win32/vs: +(files for Visual Studio 2017 or 2019 Community Edition builds) NetHack.sln NetHack.vcxproj NetHackPackage.appxmanifest NetHackPackage.wapproj NetHackProperties.props NetHackW.vcxproj @@ -413,19 +441,20 @@ afterrecover.proj aftertile2bmp.proj aftertilemap.proj afteruudecode.proj build.bat common.props config.props console.props -default.props default_dll.props -default_lib.props dirs.props -dlb.vcxproj dll.props -files.props makedefs.vcxproj -nh340key.def nh340key.vcxproj -nhdefkey.def nhdefkey.vcxproj -nhraykey.def nhraykey.vcxproj -recover.vcxproj tile2bmp.vcxproj -tilemap.vcxproj tiles.vcxproj -travisci.sh uudecode.vcxproj +cpp.hint default.props +default_dll.props default_lib.props +dirs.props dlb.vcxproj +dll.props files.props +makedefs.vcxproj nh340key.def +nh340key.vcxproj nhdefkey.def +nhdefkey.vcxproj nhraykey.def +nhraykey.vcxproj recover.vcxproj +tile2bmp.vcxproj tilemap.vcxproj +tiles.vcxproj travisci.sh +uudecode.vcxproj -win/win32/vs2017/Images: -(files for Visual Studio 2017 Community Edition builds) +win/win32/vs/Images: +(files for Visual Studio 2017 or 2019 Community Edition builds) BadgeLogo.scale-100.png BadgeLogo.scale-125.png BadgeLogo.scale-150.png diff --git a/Porting b/Porting index 7d4d5153a..da8d74594 100644 --- a/Porting +++ b/Porting @@ -14,7 +14,7 @@ new machine. The basic steps in porting the program are: have the files in the top directory since you're reading this one. :-) - If you will be cross-compiling for your target platform on + If you will be cross-compiling for your target platform on a different platform, you may want to read Cross-compiling in the Top folder as well. @@ -185,14 +185,13 @@ line options to produce several output files that are required for: (a) additional build steps to follow, including some header files: pm.h, onames.h, date.h. (b) creation of files, containing information required by, - or about the game during its execution, that are stored in a + or about the game during its execution, that are stored in a portable, platform-independent way, that need to be inserted into the final game package. util/makedefs -v util/makedefs -o util/makedefs -p - util/makedefs -z util/makedefs -d util/makedefs -r util/makedefs -h @@ -205,9 +204,9 @@ utilities, and so forth. Those produce output files for use during the game and need to be included in the packaging of the game. 4.3. Lua - + Compile and link into a library, or obtain a prebuilt Lua library for -your platform. Place the Lua source into lib/lua-5.4.0 (or other folder +your platform. Place the Lua source into lib/lua-5.4.2 (or other folder representing an appropriate Lua version); place the compiled Lua library into lib. @@ -244,7 +243,7 @@ text by makedefs during the build process, have been replaced by Lua versions and are inserted into the game package for processing by the embedded Lua interpreter during game execution. - 5.2 Level Compiler + 5.2 Level Compiler There is no longer a build-time level compiler. Instead, the level descriptions have been converted to Lua and are inserted into the game package @@ -266,6 +265,6 @@ by code within the game itself. That was done to facilitate cross-compiling of NetHack on one platform for game execution on another. -# NetHack 3.6 Porting $NHDT-Date: 1594155866 2020/07/07 21:04:26 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.8 $ +# NetHack 3.7 Porting $NHDT-Date: 1596498144 2020/08/03 23:42:24 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.9 $ # Copyright (c) 2005 by Michael Allison # NetHack may be freely redistributed. See license for details. diff --git a/README b/README index 8ca02f15c..1e99c8c26 100644 --- a/README +++ b/README @@ -11,7 +11,7 @@ The file doc/fixes37.0 in the source distribution will be updated with a list of fixes as they are committed. In short -- there are likely to be bugs. Don't treat NetHack-3.7 branch as -released code, and if stability is paramount, then the most recent +released code, and if stability is paramount, then the most recent NetHack 3.6.6 release is safest for you. We're making the .0 work-in-progress available so that you can observe, test @@ -22,11 +22,11 @@ The file doc/fixes37.0 in the source distribution has a full list of bug-fixes included so far, as well as brief mentions of some of the other code changes. The text in there was written for the development team's own use and is provided "as is", so please do not ask us to further explain the entries in -that file. Some entries might be considered "spoilers", particularly in the +that file. Some entries might be considered "spoilers", particularly in the "new features" section. Along with the game improvements and bug fixes, NetHack 3.7 strives to make -some general architectural improvements to the game or to its building +some general architectural improvements to the game or to its building process. Among them: * Remove barriers to building NetHack on one platform and operating system, @@ -35,9 +35,9 @@ process. Among them: See the file "Cross-compiling" in the top-level folder for more information on that. - * Replace the build-time "yacc and lex"-based level compiler, the "yacc and + * Replace the build-time "yacc and lex"-based level compiler, the "yacc and lex"-based dungeon compiler, and the quest text file processing done - by NetHack's "makedefs" utility, with Lua text alternatives that are + by NetHack's "makedefs" utility, with Lua text alternatives that are loaded and processed by the game during play. * Write game savefiles and bonesfiles in a more portable and consistent way @@ -60,7 +60,7 @@ considered spoilers: their individual fields and save those fields instead of the entire struct - savefile: use little-endian format for fields where that makes a difference - + - - - - - - - - - - - Please read items (1), (2) and (3) BEFORE doing anything with your new code. @@ -113,7 +113,7 @@ Please read items (1), (2) and (3) BEFORE doing anything with your new code. OpenVMS (aka VMS) V8.4 on Alpha and on Integrity/Itanium/IA64 Instructions have been provided by way of community contribution on: - msdos protected mode using djgpp including a Linux-host djgpp + msdos protected mode using djgpp including a Linux-host djgpp cross-compile Previous versions of NetHack were tested and known to run on the diff --git a/azure-pipelines.yml b/azure-pipelines.yml new file mode 100644 index 000000000..188c39bbc --- /dev/null +++ b/azure-pipelines.yml @@ -0,0 +1,214 @@ +strategy: + matrix: + linux_focal_gcc8_minimal: + imageName: 'ubuntu-20.04' + toolchainName: gcc8 + buildTargetName: minimal + linux_focal_clang_all: + imageName: 'ubuntu-20.04' + toolchainName: clang + buildTargetName: all + linux_focal_gcc8_all: + imageName: 'ubuntu-20.04' + toolchainName: gcc8 + buildTargetName: all + linux_focal_gcc9_all: + imageName: 'ubuntu-20.04' + toolchainName: gcc9 + buildTargetName: all + linux_bionic_gcc7_all: + imageName: 'ubuntu-18.04' + toolchainName: gcc7 + buildTargetName: all +# build is currently broken +# mac_catalina_gcc8_all: +# imageName: 'macOS-10.15' +# ccName: gcc-8 +# cxxName: g++-8 +# buildSetting: 'all' + mac_catalina_clang_all: + imageName: 'macOS-10.15' + toolchainName: clang + buildTargetName: all + windows-visualstudio: + imageName: 'windows-2019' + toolchainName: vs + buildTargetName: all + windows-mingw: + imageName: 'windows-2019' + toolchainName: mingw + buildTargetName: all + linux_focal_cross_msdos: + imageName: 'ubuntu-20.04' + toolchainName: cross + buildTargetName: msdos + +pool: + vmImage: $(imageName) + +# resources: +# repositories: +# - repository: pdcursesrepo +# type: github +# name: wmcbrine/PDCurses +# ref: refs/heads/master +# endpoint: github.com_barthouse + +variables: + toolchain: $(toolchainName) + buildTarget: $(buildTargetName) + netHackPath: s/NetHack + +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)" == "gcc8" ] + then + echo "##vso[task.setvariable variable=CC]gcc-8" + echo "##vso[task.setvariable variable=CXX]g++-8" + fi + if [ "$(toolchain)" == "gcc9" ] + then + echo "##vso[task.setvariable variable=CC]gcc-9" + echo "##vso[task.setvariable variable=CXX]g++-9" + fi + if [ "$(toolchain)" == "gcc10" ] + then + echo "##vso[task.setvariable variable=CC]gcc-10" + echo "##vso[task.setvariable variable=CXX]g++-10" + fi + if [ "$(toolchain)" == "clang" ] + then + echo "##vso[task.setvariable variable=CC]clang" + echo "##vso[task.setvariable variable=CXX]clang++" + fi + if [ "$(toolchain)" == "cross" ] + then + echo "##vso[task.setvariable variable=CC]gcc-8" + echo "##vso[task.setvariable variable=CXX]g++-8" + fi + displayName: 'Setting variables' + +- bash: | + echo "toolchain: $(toolchain)" + echo "buildTarget: $(buildTarget)" + echo "netHackPath: $NETHACKPATH" + echo "CC: $CC" + echo "CXX: $CXX" + displayName: 'Echoing variables' + +- checkout: git://NetHack/NetHackTest@pipeline-test + submodules: true + path: $(netHackPath) # $(Agent.BuildDirectory)/$(netHackPath) + +- task: DownloadSecureFile@1 + name: storeKey + inputs: + secureFile: 'NetHackPackage_StoreKey.pfx' + condition: eq( variables.toolchain, 'vs' ) + displayName: 'Store Key Download' + +- task: CopyFiles@2 + inputs: + contents: NetHackPackage_StoreKey.pfx + SourceFolder: $(Agent.TempDirectory) + TargetFolder: $(Agent.BuildDirectory)/$(netHackPath)/win/win32/vs + condition: eq( variables.toolchain, 'vs' ) + displayName: 'Copying store key' + +- task: MSBuild@1 + inputs: + solution: $(Agent.BuildDirectory)/$(netHackPath)/win/win32/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 + export LUATOP=../submodules/lua + export LUASRC=../submodules/lua + export ADD_CURSES=Y + export PDCURSES_TOP=../submodules/pdcurses + export LUA_VERSION=5.4.2 + export TRAVIS_COMPILER=1 + cp ../sys/winnt/Makefile.gcc ./Makefile + mingw32-make LUA_VERSION=$LUA_VERSION install + condition: eq( variables.toolchain, 'mingw' ) + workingDirectory: $(Agent.BuildDirectory)/$(netHackPath)/src + displayName: 'MinGW Build' + +- bash: | + sudo apt-get -qq -y update + sudo apt-get -qq -y install libncurses5-dev + sudo apt-get -qq -y install libx11-dev libxaw7-dev xfonts-utils qtbase5-dev qtmultimedia5-dev qtbase5-dev-tools + condition: eq( variables['Agent.OS'], 'Linux' ) + workingDirectory: $(Agent.BuildDirectory)/$(netHackPath) + displayName: 'Getting linux build dependencies' + +- bash: | + cd sys/unix + sh setup.sh hints/linux.2020 + cd ../.. + make fetch-lua + make WANT_WIN_ALL=1 QT_SELECT=5 MOC=moc all + condition: and(eq( variables['Agent.OS'], 'Linux' ), eq( variables.buildTarget, 'all')) + workingDirectory: $(Agent.BuildDirectory)/$(netHackPath) + displayName: 'Building linux full build' + +- bash: | + cd sys/unix + sh setup.sh hints/linux-minimal + cd ../.. + sed -i '/^#define CLIPPING/d' include/config.h + sed -i '/^#define COMPRESS/d' include/config.h + #sed -i '/^#define DOAGAIN/d' include/config.h + sed -i '/^#define DUMPLOG/d' include/config.h + #sed -i '/^#define GDBPATH/d' include/config.h + #sed -i '/^#define GREPPATH/d' include/config.h + sed -i '/^#define INSURANCE/d' include/config.h + sed -i '/^#define LOGFILE/d' include/config.h + sed -i '/^#define NEWS/d' include/config.h + sed -i '/^#define PANICLOG/d' include/config.h + #sed -i '/^#define STATUS_HILITES/d' include/config.h + sed -i '/^#define SYSCF/d' include/config.h + sed -i '/^#define USER_SOUNDS/d' include/config.h + sed -i '/^#define XLOGFILE/d' include/config.h + + sed -i '/^#define MAIL/d' include/unixconf.h + sed -i '/^#define SHELL/d' include/unixconf.h + sed -i '/^#define SUSPEND/d' include/unixconf.h + sed -i 's/^#define TEXTCOLOR//' include/unixconf.h + make fetch-lua + make WANT_WIN_ALL=1 all + condition: and(eq( variables['Agent.OS'], 'Linux' ), eq( variables.buildTarget, 'minimal')) + displayName: 'Building linux minimal build' + workingDirectory: $(Agent.BuildDirectory)/$(netHackPath) + +- bash: | + cd sys/unix + sh setup.sh hints/macos.2020 + cd ../.. + make fetch-lua + make all + condition: eq( variables['Agent.OS'], 'Darwin' ) + workingDirectory: $(Agent.BuildDirectory)/$(netHackPath) + displayName: 'Building mac full build' + +- bash: | + export GCCVER=gcc1010 + cd sys/unix + sh setup.sh hints/linux.2020 + cd ../.. + make fetch-lua + sh sys/msdos/fetch-cross-compiler.sh + make LUA_VERSION=5.4.2 WANT_WIN_TTY=1 WANT_WIN_CURSES=1 CROSS_TO_MSDOS=1 all + make LUA_VERSION=5.4.2 WANT_WIN_TTY=1 WANT_WIN_CURSES=1 CROSS_TO_MSDOS=1 package + condition: and(eq( variables['Agent.OS'], 'Linux' ), eq( variables.toolchain, 'cross')) + workingDirectory: $(Agent.BuildDirectory)/$(netHackPath) + displayName: 'Building MSDOS build' diff --git a/dat/Arc-fila.lua b/dat/Arc-fila.lua index 2e2dc1578..786d37e86 100644 --- a/dat/Arc-fila.lua +++ b/dat/Arc-fila.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 Arch.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ +-- NetHack 3.7 Arch.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- Copyright (c) 1991 by M. Stephenson -- NetHack may be freely redistributed. See license for details. diff --git a/dat/Arc-filb.lua b/dat/Arc-filb.lua index 8b3f1d257..d4ec17464 100644 --- a/dat/Arc-filb.lua +++ b/dat/Arc-filb.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 Arch.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ +-- NetHack 3.7 Arch.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- Copyright (c) 1991 by M. Stephenson -- NetHack may be freely redistributed. See license for details. diff --git a/dat/Arc-goal.lua b/dat/Arc-goal.lua index 4f48ec516..8cdf65e8c 100644 --- a/dat/Arc-goal.lua +++ b/dat/Arc-goal.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 Arch.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ +-- NetHack 3.7 Arch.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- Copyright (c) 1991 by M. Stephenson -- NetHack may be freely redistributed. See license for details. @@ -52,7 +52,7 @@ des.region(selection.area(35,16,36,17), "unlit") des.region(selection.area(38,13,38,17), "unlit") des.region(selection.area(40,13,41,14), "unlit") des.region(selection.area(40,16,41,17), "unlit") -des.region({ region={43,13, 50,15}, lit=0, type="temple", prefilled=0 }) +des.region({ region={43,13, 50,15}, lit=0, type="temple", filled=2 }) des.region(selection.area(52,13,52,15), "unlit") -- Stairs des.stair("up", 38,10) diff --git a/dat/Arc-loca.lua b/dat/Arc-loca.lua index 374deb595..93ab61fee 100644 --- a/dat/Arc-loca.lua +++ b/dat/Arc-loca.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 Arch.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ +-- NetHack 3.7 Arch.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- Copyright (c) 1991 by M. Stephenson -- NetHack may be freely redistributed. See license for details. @@ -31,18 +31,18 @@ des.map([[ ]]); -- Dungeon Description des.region(selection.area(00,00,75,19), "lit") -des.region({ region={25,04, 28,07}, lit=1, type="temple", prefilled=0 }) -des.region({ region={25,09, 28,11}, lit=0, type="temple", prefilled=0 }) -des.region({ region={25,13, 28,16}, lit=1, type="temple", prefilled=0 }) +des.region({ region={25,04, 28,07}, lit=1, type="temple", filled=2 }) +des.region({ region={25,09, 28,11}, lit=0, type="temple", filled=2 }) +des.region({ region={25,13, 28,16}, lit=1, type="temple", filled=2 }) des.region(selection.area(30,04,30,16), "lit") des.region(selection.area(32,04,32,16), "unlit") -des.region({ region={33,04, 53,04}, lit=0, type="ordinary", prefilled=0, irregular=1 }) +des.region({ region={33,04, 53,04}, lit=0, type="ordinary", irregular=1 }) des.region(selection.area(36,10,37,10), "unlit") des.region(selection.area(39,09,39,11), "unlit") -des.region({ region={36,06, 42,08}, lit=0, type="ordinary", prefilled=0, irregular=1 }) -des.region({ region={36,12, 42,14}, lit=0, type="ordinary", prefilled=0, irregular=1 }) +des.region({ region={36,06, 42,08}, lit=0, type="ordinary", irregular=1 }) +des.region({ region={36,12, 42,14}, lit=0, type="ordinary", irregular=1 }) des.region(selection.area(46,06,51,09), "unlit") -des.region({ region={46,11, 49,11}, lit=0, type="ordinary", prefilled=0, irregular=1 }) +des.region({ region={46,11, 49,11}, lit=0, type="ordinary", irregular=1 }) des.region(selection.area(48,13,51,14), "unlit") -- Doors des.door("closed",31,04) diff --git a/dat/Arc-strt.lua b/dat/Arc-strt.lua index 9292d40ca..5f759b575 100644 --- a/dat/Arc-strt.lua +++ b/dat/Arc-strt.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 Arch.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ +-- NetHack 3.7 Arch.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- Copyright (c) 1991 by M. Stephenson -- NetHack may be freely redistributed. See license for details. diff --git a/dat/Bar-fila.lua b/dat/Bar-fila.lua index dda6d9ca7..dca44c6cf 100644 --- a/dat/Bar-fila.lua +++ b/dat/Bar-fila.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 Barb.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ +-- NetHack 3.7 Barb.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- Copyright (c) 1991 by M. Stephenson -- NetHack may be freely redistributed. See license for details. diff --git a/dat/Bar-filb.lua b/dat/Bar-filb.lua index 6978f32a3..4da533632 100644 --- a/dat/Bar-filb.lua +++ b/dat/Bar-filb.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 Barb.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ +-- NetHack 3.7 Barb.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- Copyright (c) 1991 by M. Stephenson -- NetHack may be freely redistributed. See license for details. diff --git a/dat/Bar-goal.lua b/dat/Bar-goal.lua index 31754a4c0..79b9b587e 100644 --- a/dat/Bar-goal.lua +++ b/dat/Bar-goal.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 Barb.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ +-- NetHack 3.7 Barb.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- Copyright (c) 1991 by M. Stephenson -- NetHack may be freely redistributed. See license for details. diff --git a/dat/Bar-loca.lua b/dat/Bar-loca.lua index df1e7d8aa..41680ca28 100644 --- a/dat/Bar-loca.lua +++ b/dat/Bar-loca.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 Barb.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ +-- NetHack 3.7 Barb.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- Copyright (c) 1991 by M. Stephenson -- NetHack may be freely redistributed. See license for details. diff --git a/dat/Bar-strt.lua b/dat/Bar-strt.lua index 17be92208..79df053e7 100644 --- a/dat/Bar-strt.lua +++ b/dat/Bar-strt.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 Barb.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ +-- NetHack 3.7 Barb.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- Copyright (c) 1991 by M. Stephenson -- NetHack may be freely redistributed. See license for details. diff --git a/dat/Cav-fila.lua b/dat/Cav-fila.lua index 5220b4eb3..50b518833 100644 --- a/dat/Cav-fila.lua +++ b/dat/Cav-fila.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 Caveman.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ +-- NetHack 3.7 Caveman.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- Copyright (c) 1991 by M. Stephenson -- NetHack may be freely redistributed. See license for details. diff --git a/dat/Cav-filb.lua b/dat/Cav-filb.lua index 5bc5ad4ac..812b6b786 100644 --- a/dat/Cav-filb.lua +++ b/dat/Cav-filb.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 Caveman.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ +-- NetHack 3.7 Caveman.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- Copyright (c) 1991 by M. Stephenson -- NetHack may be freely redistributed. See license for details. diff --git a/dat/Cav-goal.lua b/dat/Cav-goal.lua index 98919b04f..698147fd2 100644 --- a/dat/Cav-goal.lua +++ b/dat/Cav-goal.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 Caveman.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ +-- NetHack 3.7 Caveman.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- Copyright (c) 1991 by M. Stephenson -- NetHack may be freely redistributed. See license for details. diff --git a/dat/Cav-loca.lua b/dat/Cav-loca.lua index e3b970948..a9dfe1a07 100644 --- a/dat/Cav-loca.lua +++ b/dat/Cav-loca.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 Caveman.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ +-- NetHack 3.7 Caveman.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- Copyright (c) 1991 by M. Stephenson -- NetHack may be freely redistributed. See license for details. @@ -31,7 +31,7 @@ des.map([[ ]]); -- Dungeon Description des.region(selection.area(00,00,75,19), "unlit") -des.region({ region={52,06, 73,15}, lit=1, type="ordinary", prefilled=0, irregular=1 }) +des.region({ region={52,06, 73,15}, lit=1, type="ordinary", irregular=1 }) -- Doors des.door("locked",28,11) -- Stairs diff --git a/dat/Cav-strt.lua b/dat/Cav-strt.lua index eae5c35d1..83c071d0c 100644 --- a/dat/Cav-strt.lua +++ b/dat/Cav-strt.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 Caveman.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ +-- NetHack 3.7 Caveman.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- Copyright (c) 1991 by M. Stephenson -- NetHack may be freely redistributed. See license for details. @@ -37,14 +37,14 @@ des.map([[ ]]); -- Dungeon Description des.region(selection.area(00,00,75,19), "unlit") -des.region({ region={13,01, 40,05}, lit=1, type="temple", prefilled=0, irregular=1 }) +des.region({ region={13,01, 40,05}, lit=1, type="temple", filled=1, irregular=1 }) -- The occupied rooms. -des.region({ region={02,01, 08,03}, lit=1, type="ordinary", prefilled=0, irregular=1 }) -des.region({ region={01,11, 06,14}, lit=1, type="ordinary", prefilled=0, irregular=1 }) -des.region({ region={13,08, 18,10}, lit=1, type="ordinary", prefilled=0, irregular=1 }) -des.region({ region={05,17, 14,18}, lit=1, type="ordinary", prefilled=0, irregular=1 }) -des.region({ region={17,16, 23,18}, lit=1, type="ordinary", prefilled=0, irregular=1 }) -des.region({ region={35,16, 44,18}, lit=1, type="ordinary", prefilled=0, irregular=1 }) +des.region({ region={02,01, 08,03}, lit=1, type="ordinary", irregular=1 }) +des.region({ region={01,11, 06,14}, lit=1, type="ordinary", irregular=1 }) +des.region({ region={13,08, 18,10}, lit=1, type="ordinary", irregular=1 }) +des.region({ region={05,17, 14,18}, lit=1, type="ordinary", irregular=1 }) +des.region({ region={17,16, 23,18}, lit=1, type="ordinary", irregular=1 }) +des.region({ region={35,16, 44,18}, lit=1, type="ordinary", irregular=1 }) -- Stairs des.stair("down", 02,03) -- Portal arrival point diff --git a/dat/GENFILES b/dat/GENFILES index 1a49c97a2..eaf994740 100755 --- a/dat/GENFILES +++ b/dat/GENFILES @@ -1,5 +1,5 @@ #!/usr/bin/perl -# NetHack 3.6 GENFILES $NHDT-Date: 1550799147 2019/02/22 01:32:27 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.0 $ +# NetHack 3.7 GENFILES $NHDT-Date: 1596498242 2020/08/03 23:44:02 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.2 $ # Copyright (c) 2018 by Kenneth Lorber # NetHack may be freely redistributed. See license for details. diff --git a/dat/Hea-fila.lua b/dat/Hea-fila.lua index 03f52245f..5046818d0 100644 --- a/dat/Hea-fila.lua +++ b/dat/Hea-fila.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 Healer.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ +-- NetHack 3.7 Healer.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- Copyright (c) 1991, 1993 by M. Stephenson, P. Winner -- NetHack may be freely redistributed. See license for details. diff --git a/dat/Hea-filb.lua b/dat/Hea-filb.lua index 293437006..5d67d817e 100644 --- a/dat/Hea-filb.lua +++ b/dat/Hea-filb.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 Healer.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ +-- NetHack 3.7 Healer.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- Copyright (c) 1991, 1993 by M. Stephenson, P. Winner -- NetHack may be freely redistributed. See license for details. diff --git a/dat/Hea-goal.lua b/dat/Hea-goal.lua index 48d6fbae4..fd0203908 100644 --- a/dat/Hea-goal.lua +++ b/dat/Hea-goal.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 Healer.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ +-- NetHack 3.7 Healer.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- Copyright (c) 1991, 1993 by M. Stephenson, P. Winner -- NetHack may be freely redistributed. See license for details. diff --git a/dat/Hea-loca.lua b/dat/Hea-loca.lua index fdc432471..e79666897 100644 --- a/dat/Hea-loca.lua +++ b/dat/Hea-loca.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 Healer.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ +-- NetHack 3.7 Healer.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- Copyright (c) 1991, 1993 by M. Stephenson, P. Winner -- NetHack may be freely redistributed. See license for details. @@ -23,7 +23,7 @@ PPPPPPPPPPP........PPPPPPPPPPPP ]]); -- Dungeon Description des.region(selection.area(00,00,30,09), "lit") -des.region({ region={12,03, 20,06}, lit=1, type="temple" }) +des.region({ region={12,03, 20,06}, lit=1, type="temple", filled=1 }) -- Doors des.door("closed",09,04) des.door("closed",09,05) diff --git a/dat/Hea-strt.lua b/dat/Hea-strt.lua index 665c73097..1a2f64acc 100644 --- a/dat/Hea-strt.lua +++ b/dat/Hea-strt.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 Healer.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ +-- NetHack 3.7 Healer.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- Copyright (c) 1991, 1993 by M. Stephenson, P. Winner -- NetHack may be freely redistributed. See license for details. diff --git a/dat/Kni-fila.lua b/dat/Kni-fila.lua index 79866a692..b02df405e 100644 --- a/dat/Kni-fila.lua +++ b/dat/Kni-fila.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 Knight.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ +-- NetHack 3.7 Knight.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- Copyright (c) 1991,92 by M. Stephenson -- NetHack may be freely redistributed. See license for details. diff --git a/dat/Kni-filb.lua b/dat/Kni-filb.lua index 49d14e661..31afecf30 100644 --- a/dat/Kni-filb.lua +++ b/dat/Kni-filb.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 Knight.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ +-- NetHack 3.7 Knight.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- Copyright (c) 1991,92 by M. Stephenson -- NetHack may be freely redistributed. See license for details. diff --git a/dat/Kni-goal.lua b/dat/Kni-goal.lua index 577355937..70709e9ce 100644 --- a/dat/Kni-goal.lua +++ b/dat/Kni-goal.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 Knight.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ +-- NetHack 3.7 Knight.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- Copyright (c) 1991,92 by M. Stephenson -- NetHack may be freely redistributed. See license for details. diff --git a/dat/Kni-loca.lua b/dat/Kni-loca.lua index 20aed41f5..7d77598e6 100644 --- a/dat/Kni-loca.lua +++ b/dat/Kni-loca.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 Knight.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ +-- NetHack 3.7 Knight.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- Copyright (c) 1991,92 by M. Stephenson -- NetHack may be freely redistributed. See license for details. @@ -27,7 +27,7 @@ xxxxxxxxx.......xxxxxx.....xxxxxxxxxxxxx -- The Isle of Glass is a Tor rising out of the swamps surrounding it. des.region(selection.area(00,00,39,11), "lit") -- The top area of the Tor is a holy site. -des.region({ region={09,02, 27,09}, lit=1, type="temple" }) +des.region({ region={09,02, 27,09}, lit=1, type="temple", filled=2 }) -- Stairs des.stair("up", 38,0) des.stair("down", 18,05) diff --git a/dat/Kni-strt.lua b/dat/Kni-strt.lua index 8feba3489..4442d93a7 100644 --- a/dat/Kni-strt.lua +++ b/dat/Kni-strt.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 Knight.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ +-- NetHack 3.7 Knight.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- Copyright (c) 1991,92 by M. Stephenson -- NetHack may be freely redistributed. See license for details. @@ -36,7 +36,7 @@ des.map([[ -- Dungeon Description des.region(selection.area(00,00,49,15), "lit") des.region(selection.area(04,04,45,11), "unlit") -des.region({ region={06,06,22,09}, lit=1, type="throne", prefilled=1 }) +des.region({ region={06,06,22,09}, lit=1, type="throne", filled=2 }) des.region(selection.area(27,06,43,09), "lit") -- Portal arrival point des.levregion({ region = {20,14,20,14}, type="branch" }) diff --git a/dat/Mon-fila.lua b/dat/Mon-fila.lua index d0e36ad2c..9a2129ee5 100644 --- a/dat/Mon-fila.lua +++ b/dat/Mon-fila.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 Monk.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.12 $ +-- NetHack 3.7 Monk.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.12 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- Copyright (c) 1991-2 by M. Stephenson -- NetHack may be freely redistributed. See license for details. diff --git a/dat/Mon-filb.lua b/dat/Mon-filb.lua index a6fbdd5b1..4c5f7d23c 100644 --- a/dat/Mon-filb.lua +++ b/dat/Mon-filb.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 Monk.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.12 $ +-- NetHack 3.7 Monk.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.12 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- Copyright (c) 1991-2 by M. Stephenson -- NetHack may be freely redistributed. See license for details. diff --git a/dat/Mon-goal.lua b/dat/Mon-goal.lua index d339e323d..26a715238 100644 --- a/dat/Mon-goal.lua +++ b/dat/Mon-goal.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 Monk.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.12 $ +-- NetHack 3.7 Monk.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.12 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- Copyright (c) 1991-2 by M. Stephenson -- NetHack may be freely redistributed. See license for details. diff --git a/dat/Mon-loca.lua b/dat/Mon-loca.lua index 2436a33da..927b770ec 100644 --- a/dat/Mon-loca.lua +++ b/dat/Mon-loca.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 Monk.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.12 $ +-- NetHack 3.7 Monk.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.12 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- Copyright (c) 1991-2 by M. Stephenson -- NetHack may be freely redistributed. See license for details. diff --git a/dat/Mon-strt.lua b/dat/Mon-strt.lua index a71975d5f..ae1ad77d0 100644 --- a/dat/Mon-strt.lua +++ b/dat/Mon-strt.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 Monk.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.12 $ +-- NetHack 3.7 Monk.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.12 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- Copyright (c) 1991-2 by M. Stephenson -- NetHack may be freely redistributed. See license for details. diff --git a/dat/Pri-fila.lua b/dat/Pri-fila.lua index 6df964f60..65bd61ee2 100644 --- a/dat/Pri-fila.lua +++ b/dat/Pri-fila.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 Priest.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ +-- NetHack 3.7 Priest.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- Copyright (c) 1991-2 by M. Stephenson -- NetHack may be freely redistributed. See license for details. diff --git a/dat/Pri-filb.lua b/dat/Pri-filb.lua index 060afd246..b3bc7e33d 100644 --- a/dat/Pri-filb.lua +++ b/dat/Pri-filb.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 Priest.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ +-- NetHack 3.7 Priest.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- Copyright (c) 1991-2 by M. Stephenson -- NetHack may be freely redistributed. See license for details. diff --git a/dat/Pri-goal.lua b/dat/Pri-goal.lua index 5de237d20..ba47c03f0 100644 --- a/dat/Pri-goal.lua +++ b/dat/Pri-goal.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 Priest.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ +-- NetHack 3.7 Priest.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- Copyright (c) 1991-2 by M. Stephenson -- NetHack may be freely redistributed. See license for details. diff --git a/dat/Pri-loca.lua b/dat/Pri-loca.lua index ab2cc2f3d..5583ac270 100644 --- a/dat/Pri-loca.lua +++ b/dat/Pri-loca.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 Priest.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ +-- NetHack 3.7 Priest.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- Copyright (c) 1991-2 by M. Stephenson -- NetHack may be freely redistributed. See license for details. @@ -26,11 +26,11 @@ des.map([[ ........................................ ]]); -- Dungeon Description -des.region({ region={00,00, 09,13}, lit=0, type="morgue", prefilled=0 }) -des.region({ region={09,00, 30,01}, lit=0, type="morgue", prefilled=0 }) -des.region({ region={09,12, 30,13}, lit=0, type="morgue", prefilled=0 }) -des.region({ region={31,00, 39,13}, lit=0, type="morgue", prefilled=0 }) -des.region({ region={11,03, 29,10}, lit=1, type="temple", prefilled=0, irregular=1 }) +des.region({ region={00,00, 09,13}, lit=0, type="morgue", filled=1 }) +des.region({ region={09,00, 30,01}, lit=0, type="morgue", filled=1 }) +des.region({ region={09,12, 30,13}, lit=0, type="morgue", filled=1 }) +des.region({ region={31,00, 39,13}, lit=0, type="morgue", filled=1 }) +des.region({ region={11,03, 29,10}, lit=1, type="temple", filled=1, irregular=1 }) -- The altar inside the temple des.altar({ x=20,y=07, align="noalign", type="shrine" }) des.monster({ id = "aligned priest", x=20, y=07, align="noalign", peaceful = 0 }) diff --git a/dat/Pri-strt.lua b/dat/Pri-strt.lua index 70d8444e6..480a6276d 100644 --- a/dat/Pri-strt.lua +++ b/dat/Pri-strt.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 Priest.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ +-- NetHack 3.7 Priest.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- Copyright (c) 1991-2 by M. Stephenson -- NetHack may be freely redistributed. See license for details. @@ -37,7 +37,7 @@ des.map([[ ]]); -- Dungeon Description des.region(selection.area(00,00,75,19), "lit") -des.region({ region={24,06, 33,13}, lit=1, type="temple" }) +des.region({ region={24,06, 33,13}, lit=1, type="temple", filled=2 }) des.replace_terrain({ region={00,00, 10,19}, fromterrain=".", toterrain="T", chance=10 }) des.replace_terrain({ region={65,00, 75,19}, fromterrain=".", toterrain="T", chance=10 }) diff --git a/dat/Ran-fila.lua b/dat/Ran-fila.lua index 2ef3e476c..e604310c3 100644 --- a/dat/Ran-fila.lua +++ b/dat/Ran-fila.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 Ranger.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ +-- NetHack 3.7 Ranger.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- Copyright (c) 1991 by M. Stephenson -- NetHack may be freely redistributed. See license for details. diff --git a/dat/Ran-filb.lua b/dat/Ran-filb.lua index 8f19cd06f..a91bfd579 100644 --- a/dat/Ran-filb.lua +++ b/dat/Ran-filb.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 Ranger.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ +-- NetHack 3.7 Ranger.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- Copyright (c) 1991 by M. Stephenson -- NetHack may be freely redistributed. See license for details. diff --git a/dat/Ran-goal.lua b/dat/Ran-goal.lua index b32c5add4..9e9215a18 100644 --- a/dat/Ran-goal.lua +++ b/dat/Ran-goal.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 Ranger.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ +-- NetHack 3.7 Ranger.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- Copyright (c) 1991 by M. Stephenson -- NetHack may be freely redistributed. See license for details. diff --git a/dat/Ran-loca.lua b/dat/Ran-loca.lua index c9af3f1f3..4aec9449c 100644 --- a/dat/Ran-loca.lua +++ b/dat/Ran-loca.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 Ranger.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ +-- NetHack 3.7 Ranger.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- Copyright (c) 1991 by M. Stephenson -- NetHack may be freely redistributed. See license for details. diff --git a/dat/Ran-strt.lua b/dat/Ran-strt.lua index 66ea5028a..69004ebb6 100644 --- a/dat/Ran-strt.lua +++ b/dat/Ran-strt.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 Ranger.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ +-- NetHack 3.7 Ranger.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- Copyright (c) 1991 by M. Stephenson -- NetHack may be freely redistributed. See license for details. diff --git a/dat/Rog-fila.lua b/dat/Rog-fila.lua index b21be7db9..d89bbaf98 100644 --- a/dat/Rog-fila.lua +++ b/dat/Rog-fila.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 Rogue.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ +-- NetHack 3.7 Rogue.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ -- Copyright (c) 1992 by Dean Luick -- NetHack may be freely redistributed. See license for details. -- diff --git a/dat/Rog-filb.lua b/dat/Rog-filb.lua index b21be7db9..d89bbaf98 100644 --- a/dat/Rog-filb.lua +++ b/dat/Rog-filb.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 Rogue.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ +-- NetHack 3.7 Rogue.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ -- Copyright (c) 1992 by Dean Luick -- NetHack may be freely redistributed. See license for details. -- diff --git a/dat/Rog-goal.lua b/dat/Rog-goal.lua index 3fa505c25..351ec307a 100644 --- a/dat/Rog-goal.lua +++ b/dat/Rog-goal.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 Rogue.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ +-- NetHack 3.7 Rogue.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ -- Copyright (c) 1992 by Dean Luick -- NetHack may be freely redistributed. See license for details. -- diff --git a/dat/Rog-loca.lua b/dat/Rog-loca.lua index ef5b399ea..fa151dbb2 100644 --- a/dat/Rog-loca.lua +++ b/dat/Rog-loca.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 Rogue.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ +-- NetHack 3.7 Rogue.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ -- Copyright (c) 1992 by Dean Luick -- NetHack may be freely redistributed. See license for details. -- diff --git a/dat/Rog-strt.lua b/dat/Rog-strt.lua index b7e97e63a..58f27f696 100644 --- a/dat/Rog-strt.lua +++ b/dat/Rog-strt.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 Rogue.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ +-- NetHack 3.7 Rogue.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ -- Copyright (c) 1992 by Dean Luick -- NetHack may be freely redistributed. See license for details. -- diff --git a/dat/Sam-fila.lua b/dat/Sam-fila.lua index 642b79fa1..e93278391 100644 --- a/dat/Sam-fila.lua +++ b/dat/Sam-fila.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 Samurai.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ +-- NetHack 3.7 Samurai.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- Copyright (c) 1991-92 by M. Stephenson, P. Winner -- NetHack may be freely redistributed. See license for details. diff --git a/dat/Sam-filb.lua b/dat/Sam-filb.lua index 640f4b17b..60611d4c3 100644 --- a/dat/Sam-filb.lua +++ b/dat/Sam-filb.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 Samurai.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ +-- NetHack 3.7 Samurai.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- Copyright (c) 1991-92 by M. Stephenson, P. Winner -- NetHack may be freely redistributed. See license for details. diff --git a/dat/Sam-goal.lua b/dat/Sam-goal.lua index ce7215a0a..ce766f80b 100644 --- a/dat/Sam-goal.lua +++ b/dat/Sam-goal.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 Samurai.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ +-- NetHack 3.7 Samurai.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- Copyright (c) 1991-92 by M. Stephenson, P. Winner -- NetHack may be freely redistributed. See license for details. diff --git a/dat/Sam-loca.lua b/dat/Sam-loca.lua index ccad8e260..45ccd7ece 100644 --- a/dat/Sam-loca.lua +++ b/dat/Sam-loca.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 Samurai.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ +-- NetHack 3.7 Samurai.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- Copyright (c) 1991-92 by M. Stephenson, P. Winner -- NetHack may be freely redistributed. See license for details. diff --git a/dat/Sam-strt.lua b/dat/Sam-strt.lua index 108f28f61..8186c3cb4 100644 --- a/dat/Sam-strt.lua +++ b/dat/Sam-strt.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 Samurai.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ +-- NetHack 3.7 Samurai.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- Copyright (c) 1991-92 by M. Stephenson, P. Winner -- NetHack may be freely redistributed. See license for details. @@ -37,7 +37,7 @@ des.map([[ ]]); -- Dungeon Description des.region(selection.area(00,00,75,19), "lit") -des.region({ region={18,03, 26,07}, lit=1, type="throne", prefilled=1 }) +des.region({ region={18,03, 26,07}, lit=1, type="throne", filled=2 }) -- Portal arrival zone des.levregion({ region = {62,12,70,17}, type="branch" }) -- Stairs diff --git a/dat/Tou-fila.lua b/dat/Tou-fila.lua index 112caf4ed..8a8af769c 100644 --- a/dat/Tou-fila.lua +++ b/dat/Tou-fila.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 Tourist.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ +-- NetHack 3.7 Tourist.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- Copyright (c) 1991,92 by M. Stephenson, P. Winner -- NetHack may be freely redistributed. See license for details. diff --git a/dat/Tou-filb.lua b/dat/Tou-filb.lua index 4dccad5b0..ad2a8ae9f 100644 --- a/dat/Tou-filb.lua +++ b/dat/Tou-filb.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 Tourist.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ +-- NetHack 3.7 Tourist.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- Copyright (c) 1991,92 by M. Stephenson, P. Winner -- NetHack may be freely redistributed. See license for details. diff --git a/dat/Tou-goal.lua b/dat/Tou-goal.lua index b1fb941ed..2fc3de33c 100644 --- a/dat/Tou-goal.lua +++ b/dat/Tou-goal.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 Tourist.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ +-- NetHack 3.7 Tourist.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- Copyright (c) 1991,92 by M. Stephenson, P. Winner -- NetHack may be freely redistributed. See license for details. @@ -33,7 +33,7 @@ des.map([[ des.region(selection.area(00,00,75,19), "lit") -- The Inn des.region(selection.area(01,01,09,02), "lit") -des.region({ region = {01,04,09,05}, lit=1, type = "barracks" }) +des.region({ region = {01,04,09,05}, lit=1, type = "barracks", filled = 1 }) des.region(selection.area(01,07,02,10), "unlit") des.region(selection.area(07,07,09,10), "unlit") des.region(selection.area(01,14,02,15), "unlit") @@ -41,9 +41,9 @@ des.region(selection.area(07,14,09,15), "unlit") des.region(selection.area(01,17,02,18), "unlit") des.region(selection.area(07,17,09,18), "unlit") -- -des.region({ region = {11,01,19,02}, lit = 0, type = "barracks" }) +des.region({ region = {11,01,19,02}, lit = 0, type = "barracks", filled = 1 }) des.region(selection.area(21,01,30,02), "unlit") -des.region({ region = {11,17,19,18}, lit = 0, type = "barracks" }) +des.region({ region = {11,17,19,18}, lit = 0, type = "barracks", filled = 1 }) des.region(selection.area(21,17,30,18), "unlit") -- Police Station des.region(selection.area(18,07,25,11), "lit") @@ -53,12 +53,12 @@ des.region(selection.area(24,13,25,13), "unlit") -- The town itself des.region(selection.area(42,03,47,06), "unlit") des.region(selection.area(42,08,50,11), "unlit") -des.region({ region = {37,16,41,18}, lit = 0, type = "morgue" }) +des.region({ region = {37,16,41,18}, lit = 0, type = "morgue", filled = 1 }) des.region(selection.area(47,16,55,18), "unlit") des.region(selection.area(55,01,62,03), "unlit") des.region(selection.area(64,01,71,03), "unlit") -des.region({ region = {60,14,71,15}, lit = 1, type = "shop" }) -des.region({ region = {60,17,71,18}, lit = 1, type = "shop" }) +des.region({ region = {60,14,71,15}, lit = 1, type = "shop", filled = 1 }) +des.region({ region = {60,17,71,18}, lit = 1, type = "shop", filled = 1 }) -- Non diggable walls des.non_diggable(selection.area(00,00,75,19)) -- Stairs diff --git a/dat/Tou-loca.lua b/dat/Tou-loca.lua index f82f5072f..808d45faa 100644 --- a/dat/Tou-loca.lua +++ b/dat/Tou-loca.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 Tourist.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ +-- NetHack 3.7 Tourist.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- Copyright (c) 1991,92 by M. Stephenson, P. Winner -- NetHack may be freely redistributed. See license for details. @@ -32,14 +32,14 @@ des.map([[ des.region(selection.area(00,00,75,19), "lit") des.non_diggable(selection.area(00,00,75,19)) -- -des.region({ region={01,01, 04,05}, lit=0, type="morgue", prefilled = 0 }) -des.region({ region={15,03, 20,05}, lit=1, type="shop", prefilled = 0 }) -des.region({ region={62,03, 71,04}, lit=1, type="shop", prefilled = 0 }) -des.region({ region={01,17, 11,18}, lit=1, type="barracks", prefilled = 0 }) -des.region({ region={12,09, 20,10}, lit=1, type="barracks", prefilled = 0 }) -des.region({ region={53,11, 59,14}, lit=1, type="zoo", prefilled = 0 }) -des.region({ region={63,14, 72,16}, lit=1, type="barracks", prefilled = 0 }) -des.region({ region={32,14, 40,16}, lit=1, type="temple", prefilled = 0 }) +des.region({ region={01,01, 04,05}, lit=0, type="morgue", filled=1 }) +des.region({ region={15,03, 20,05}, lit=1, type="shop", filled=1 }) +des.region({ region={62,03, 71,04}, lit=1, type="shop", filled=1 }) +des.region({ region={01,17, 11,18}, lit=1, type="barracks", filled=1 }) +des.region({ region={12,09, 20,10}, lit=1, type="barracks", filled=1 }) +des.region({ region={53,11, 59,14}, lit=1, type="zoo", filled=1 }) +des.region({ region={63,14, 72,16}, lit=1, type="barracks", filled=1 }) +des.region({ region={32,14, 40,16}, lit=1, type="temple", filled=1 }) -- des.region({ region = {06,01,11,02}, type = "ordinary" }) des.region({ region = {24,01,29,02}, type = "ordinary" }) diff --git a/dat/Tou-strt.lua b/dat/Tou-strt.lua index 8ca3f6a76..c5efa0d29 100644 --- a/dat/Tou-strt.lua +++ b/dat/Tou-strt.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 Tourist.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ +-- NetHack 3.7 Tourist.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- Copyright (c) 1991,92 by M. Stephenson, P. Winner -- NetHack may be freely redistributed. See license for details. @@ -36,7 +36,7 @@ des.map([[ ]]); -- Dungeon Description des.region(selection.area(00,00,75,19), "lit") -des.region({ region={14,01, 20,03}, lit=0, type="morgue", prefilled=0 }) +des.region({ region={14,01, 20,03}, lit=0, type="morgue", filled=1 }) des.region(selection.area(07,10,11,12), "unlit") des.region(selection.area(04,16,08,18), "unlit") des.region(selection.area(17,16,21,18), "unlit") diff --git a/dat/Val-fila.lua b/dat/Val-fila.lua index bf7cb2e86..ad3dc282d 100644 --- a/dat/Val-fila.lua +++ b/dat/Val-fila.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 Valkyrie.des $NHDT-Date: 1553807172 2019/03/28 21:06:12 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.15 $ +-- NetHack 3.7 Valkyrie.des $NHDT-Date: 1553807172 2019/03/28 21:06:12 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.15 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- Copyright (c) 1991-2 by M. Stephenson -- NetHack may be freely redistributed. See license for details. diff --git a/dat/Val-filb.lua b/dat/Val-filb.lua index e779ed564..84bb73987 100644 --- a/dat/Val-filb.lua +++ b/dat/Val-filb.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 Valkyrie.des $NHDT-Date: 1553807172 2019/03/28 21:06:12 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.15 $ +-- NetHack 3.7 Valkyrie.des $NHDT-Date: 1553807172 2019/03/28 21:06:12 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.15 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- Copyright (c) 1991-2 by M. Stephenson -- NetHack may be freely redistributed. See license for details. diff --git a/dat/Val-goal.lua b/dat/Val-goal.lua index d92917039..4971822cf 100644 --- a/dat/Val-goal.lua +++ b/dat/Val-goal.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 Valkyrie.des $NHDT-Date: 1553807172 2019/03/28 21:06:12 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.15 $ +-- NetHack 3.7 Valkyrie.des $NHDT-Date: 1553807172 2019/03/28 21:06:12 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.15 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- Copyright (c) 1991-2 by M. Stephenson -- NetHack may be freely redistributed. See license for details. diff --git a/dat/Val-loca.lua b/dat/Val-loca.lua index a5817ebea..ab0f15181 100644 --- a/dat/Val-loca.lua +++ b/dat/Val-loca.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 Valkyrie.des $NHDT-Date: 1553807172 2019/03/28 21:06:12 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.15 $ +-- NetHack 3.7 Valkyrie.des $NHDT-Date: 1553807172 2019/03/28 21:06:12 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.15 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- Copyright (c) 1991-2 by M. Stephenson -- NetHack may be freely redistributed. See license for details. diff --git a/dat/Val-strt.lua b/dat/Val-strt.lua index 5bb9fce57..dbce2280d 100644 --- a/dat/Val-strt.lua +++ b/dat/Val-strt.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 Valkyrie.des $NHDT-Date: 1553807172 2019/03/28 21:06:12 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.15 $ +-- NetHack 3.7 Valkyrie.des $NHDT-Date: 1553807172 2019/03/28 21:06:12 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.15 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- Copyright (c) 1991-2 by M. Stephenson -- NetHack may be freely redistributed. See license for details. diff --git a/dat/Wiz-fila.lua b/dat/Wiz-fila.lua index 61c78d75b..e11b50340 100644 --- a/dat/Wiz-fila.lua +++ b/dat/Wiz-fila.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 Wizard.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ +-- NetHack 3.7 Wizard.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ -- Copyright (c) 1992 by David Cohrs -- NetHack may be freely redistributed. See license for details. -- diff --git a/dat/Wiz-filb.lua b/dat/Wiz-filb.lua index 41eae6c47..2fff8cba5 100644 --- a/dat/Wiz-filb.lua +++ b/dat/Wiz-filb.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 Wizard.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ +-- NetHack 3.7 Wizard.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ -- Copyright (c) 1992 by David Cohrs -- NetHack may be freely redistributed. See license for details. -- diff --git a/dat/Wiz-goal.lua b/dat/Wiz-goal.lua index 5673410c6..3620c42e4 100644 --- a/dat/Wiz-goal.lua +++ b/dat/Wiz-goal.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 Wizard.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ +-- NetHack 3.7 Wizard.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ -- Copyright (c) 1992 by David Cohrs -- NetHack may be freely redistributed. See license for details. -- @@ -29,7 +29,7 @@ des.map([[ ]]); -- Dungeon Description -des.region({ region={13,10,18,12}, lit=0, type="temple" }) +des.region({ region={13,10,18,12}, lit=0, type="temple", filled=2 }) des.region(selection.area(13,06,18,08), "lit") des.region(selection.area(20,04,30,14), "unlit") des.region(selection.area(32,06,33,07), "unlit") diff --git a/dat/Wiz-loca.lua b/dat/Wiz-loca.lua index 288660ca7..7197f1856 100644 --- a/dat/Wiz-loca.lua +++ b/dat/Wiz-loca.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 Wizard.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ +-- NetHack 3.7 Wizard.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ -- Copyright (c) 1992 by David Cohrs -- NetHack may be freely redistributed. See license for details. -- @@ -36,18 +36,18 @@ des.replace_terrain({ region = {34, 1,68,19}, fromterrain="}", toterrain=".", ch -- Dungeon Description des.region(selection.area(00,00,75,20), "lit") -des.region({ region={37,04,65,16}, lit=0, type="ordinary", prefilled=1, irregular=1, +des.region({ region={37,04,65,16}, lit=0, type="ordinary", irregular=1, contents = function() des.door({ state="secret", wall="random" }) end }) -des.region({ region={39,06,63,14}, lit=0, type="ordinary", prefilled=1, irregular=1, +des.region({ region={39,06,63,14}, lit=0, type="ordinary", irregular=1, contents = function() des.door({ state="secret", wall="random" }) end }) -des.region({ region={41,08,46,12}, lit=1, type="ordinary", prefilled=1, irregular=1, +des.region({ region={41,08,46,12}, lit=1, type="ordinary", irregular=1, contents = function() local walls = { "north", "south", "west" } local widx = math.random(1, #walls) @@ -55,7 +55,7 @@ des.region({ region={41,08,46,12}, lit=1, type="ordinary", prefilled=1, irregula end }) -des.region({ region={56,08,61,12}, lit=1, type="ordinary", prefilled=1, irregular=1, +des.region({ region={56,08,61,12}, lit=1, type="ordinary", irregular=1, contents = function() local walls = { "north", "south", "east" } local widx = math.random(1, #walls) @@ -66,7 +66,7 @@ des.region({ region={56,08,61,12}, lit=1, type="ordinary", prefilled=1, irregula des.region(selection.area(48,08,54,08), "unlit") des.region(selection.area(48,12,54,12), "unlit") -des.region({ region={48,10,54,10}, lit=0, type="ordinary", prefilled=1, irregular=1, +des.region({ region={48,10,54,10}, lit=0, type="ordinary", irregular=1, contents = function() des.door({ state="secret", wall="random" }) end diff --git a/dat/Wiz-strt.lua b/dat/Wiz-strt.lua index 19478b249..715cb5744 100644 --- a/dat/Wiz-strt.lua +++ b/dat/Wiz-strt.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 Wizard.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ +-- NetHack 3.7 Wizard.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ -- Copyright (c) 1992 by David Cohrs -- NetHack may be freely redistributed. See license for details. -- @@ -44,7 +44,7 @@ des.replace_terrain({ region={13,5, 33,15}, fromterrain="C", toterrain=".", chan des.region(selection.area(00,00,75,19), "lit") des.region(selection.area(35,00,49,03), "unlit") des.region(selection.area(43,12,49,16), "unlit") -des.region({ region={19,11,33,15}, lit=0, type="ordinary", prefilled=0, irregular=1 }) +des.region({ region={19,11,33,15}, lit=0, type="ordinary", irregular=1 }) des.region(selection.area(30,10,31,10), "unlit") -- Stairs des.stair("down", 30,10) diff --git a/dat/air.lua b/dat/air.lua index ba925c86a..b8e0fd936 100644 --- a/dat/air.lua +++ b/dat/air.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 endgame.des $NHDT-Date: 1546303680 2019/01/01 00:48:00 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.14 $ +-- NetHack 3.7 endgame.des $NHDT-Date: 1546303680 2019/01/01 00:48:00 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.14 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- Copyright (c) 1992,1993 by Izchak Miller, David Cohrs, -- and Timo Hakulinen diff --git a/dat/asmodeus.lua b/dat/asmodeus.lua index a8b73b8a4..e8f1ffaf6 100644 --- a/dat/asmodeus.lua +++ b/dat/asmodeus.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 gehennom.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.13 $ +-- NetHack 3.7 gehennom.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.13 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- Copyright (c) 1992 by M. Stephenson and Izchak Miller -- NetHack may be freely redistributed. See license for details. diff --git a/dat/astral.lua b/dat/astral.lua index 5a3a70286..398ffe2ba 100644 --- a/dat/astral.lua +++ b/dat/astral.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 endgame.des $NHDT-Date: 1546303680 2019/01/01 00:48:00 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.14 $ +-- NetHack 3.7 endgame.des $NHDT-Date: 1546303680 2019/01/01 00:48:00 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.14 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- Copyright (c) 1992,1993 by Izchak Miller, David Cohrs, -- and Timo Hakulinen @@ -76,15 +76,15 @@ place:set(51,9); -- Where the player will land on arrival des.teleport_region({ region = {29,15,45,15}, exclude = {30,15,44,15} }) -- Lit courts -des.region({ region={01,05,16,14},lit=1,type="ordinary",prefilled=1,irregular=1 }) -des.region({ region={31,01,44,10},lit=1,type="ordinary",prefilled=1,irregular=1 }) -des.region({ region={61,05,74,14},lit=1,type="ordinary",prefilled=1,irregular=1 }) +des.region({ region={01,05,16,14},lit=1,type="ordinary",irregular=1 }) +des.region({ region={31,01,44,10},lit=1,type="ordinary",irregular=1 }) +des.region({ region={61,05,74,14},lit=1,type="ordinary",irregular=1 }) -- A Sanctum for each alignment -- The shrines' alignments are shuffled for -- each game -des.region({ region={04,07,10,11},lit=1,type="temple" }) -des.region({ region={34,03,40,07},lit=1,type="temple" }) -des.region({ region={64,07,70,11},lit=1,type="temple" }) +des.region({ region={04,07,10,11},lit=1,type="temple",filled=2 }) +des.region({ region={34,03,40,07},lit=1,type="temple",filled=2 }) +des.region({ region={64,07,70,11},lit=1,type="temple",filled=2 }) des.altar({ x=07, y=09, align=align[1],type="sanctum" }) des.altar({ x=37, y=05, align=align[2],type="sanctum" }) diff --git a/dat/baalz.lua b/dat/baalz.lua index 107c98719..d75e6e3a2 100644 --- a/dat/baalz.lua +++ b/dat/baalz.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 gehennom.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.13 $ +-- NetHack 3.7 gehennom.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.13 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- Copyright (c) 1992 by M. Stephenson and Izchak Miller -- NetHack may be freely redistributed. See license for details. diff --git a/dat/bogusmon.txt b/dat/bogusmon.txt index 7179c8b11..40f7a507e 100644 --- a/dat/bogusmon.txt +++ b/dat/bogusmon.txt @@ -1,4 +1,4 @@ -# NetHack 3.6 bogusmon.txt $NHDT-Date: 1574387024 2019/11/22 01:43:44 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.8 $ +# NetHack 3.7 bogusmon.txt $NHDT-Date: 1596498237 2020/08/03 23:43:57 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.10 $ # Copyright (c) 2016 by Pasi Kallinen # NetHack may be freely redistributed. See license for details. # diff --git a/dat/castle.lua b/dat/castle.lua index fa798f3f9..c2f05f02f 100644 --- a/dat/castle.lua +++ b/dat/castle.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 castle.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ +-- NetHack 3.7 castle.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- NetHack may be freely redistributed. See license for details. -- @@ -230,7 +230,7 @@ des.region(selection.area(00,00,62,16),"unlit") des.region(selection.area(00,05,05,11),"lit") des.region(selection.area(57,05,62,11),"lit") -- Throne room -des.region({ region={27,05, 37,11},lit=1,type="throne", prefilled=1 }) +des.region({ region={27,05, 37,11},lit=1,type="throne", filled=2 }) -- Antechamber des.region(selection.area(07,05,14,11),"lit") -- Storerooms @@ -244,8 +244,8 @@ des.region(selection.area(56,02,60,03),"lit") des.region(selection.area(02,13,06,14),"lit") des.region(selection.area(56,13,60,14),"lit") -- Barracks -des.region({ region={16,05, 25,06},lit=1,type="barracks", prefilled=0 }) -des.region({ region={16,10, 25,11},lit=1,type="barracks", prefilled=0 }) +des.region({ region={16,05, 25,06},lit=1,type="barracks", filled=1 }) +des.region({ region={16,10, 25,11},lit=1,type="barracks", filled=1 }) -- Hallways des.region(selection.area(08,03,54,03),"unlit") des.region(selection.area(08,13,54,13),"unlit") diff --git a/dat/cmdhelp b/dat/cmdhelp index cd0944d2d..134866d01 100644 --- a/dat/cmdhelp +++ b/dat/cmdhelp @@ -1,4 +1,4 @@ -&# cmdhelp +&# cmdhelp - became obsolete when 'BINDINGS=key:command' got added & Tell what command a keystroke invokes ^ Show the type of an adjacent trap ^[ Cancel command (same as ESCape key) @@ -145,6 +145,7 @@ _ Travel via a shortest-path algorithm to a point on the map * Show all equipment in use (combination of the ),[,=,",( commands) $ Count your gold + List known spells +Del Display map without monsters or objects obstructing the view. # Perform an extended command (use '#?' to list choices) &# number_pad: &# -1 = numpad off, swap y with z (including Y with Z, ^Y with ^Z, M-y &c) @@ -222,3 +223,4 @@ M-T Tip: empty a container M-u Untrap something (trap, door, or chest) M-v Print compile time options for this version of NetHack M-w Wipe off your face +M-X Switch from normal play to explore mode diff --git a/dat/data.base b/dat/data.base index b4ada5b50..a23ba5449 100644 --- a/dat/data.base +++ b/dat/data.base @@ -1,5 +1,5 @@ -# NetHack 3.6 data.base -# $NHDT-Date: 1590711596 2020/05/29 00:19:56 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.96 $ +# NetHack 3.7 data.base +# $NHDT-Date: 1608767189 2020/12/23 23:46:29 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.99 $ # 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. @@ -1064,13 +1064,14 @@ cream pie And welcomes little fishes in, With gently smiling jaws! [ How Doth The Little Crocodile, by Lewis Carroll ] +# Creosote is the Discworld analogue of Croesus croesus kroisos creosote Croesus (in Greek: Kroisos), the wealthy last king of Lydia; - his empire was destroyed when he attacked Cyrus in 549, after - the Oracle of Delphi (q.v.) had told him: "if you attack the - Persians, you will destroy a mighty empire". Herodotus + his empire was destroyed when he attacked Cyrus in 549 BC, + after the Oracle of Delphi (q.v.) had told him: "if you attack + the Persians, you will destroy a mighty empire". Herodotus relates of his legendary conversation with Solon of Athens, who impressed upon him that being rich does not imply being happy and that no one should be considered fortunate before @@ -2699,10 +2700,11 @@ kelp* specimens in their native setting. [ 20,000 Leagues Under the Sea, by Jules Verne ] ki-rin - The ki-rin is a strange-looking flying creature. It has - scales, a mane like a lion, a tail, hooves, and a horn. It - is brightly colored, and can usually be found flying in the - sky looking for good deeds to reward. + The ki-rin is a strange-looking wingless flying creature. + It has scales, a mane like a lion, a tail, four legs with + hooves, and a horn like a unicorn's. It is brightly colored, + and can usually be found flying in the sky looking for good + deeds to reward. king arthur *arthur Ector took both his sons to the church before which the diff --git a/dat/earth.lua b/dat/earth.lua index 62cb6da32..521da3d10 100644 --- a/dat/earth.lua +++ b/dat/earth.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 endgame.des $NHDT-Date: 1546303680 2019/01/01 00:48:00 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.14 $ +-- NetHack 3.7 endgame.des $NHDT-Date: 1546303680 2019/01/01 00:48:00 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.14 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- Copyright (c) 1992,1993 by Izchak Miller, David Cohrs, -- and Timo Hakulinen diff --git a/dat/engrave.txt b/dat/engrave.txt index 222d1e5a9..ff473b610 100644 --- a/dat/engrave.txt +++ b/dat/engrave.txt @@ -1,4 +1,4 @@ -# NetHack 3.6 engrave.txt $NHDT-Date: 1581206725 2020/02/09 00:05:25 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.4 $ +# NetHack 3.7 engrave.txt $NHDT-Date: 1596498240 2020/08/03 23:44:00 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.5 $ # Copyright (c) 2015 by Pasi Kallinen # NetHack may be freely redistributed. See license for details. # Random engravings on the floor diff --git a/dat/epitaph.txt b/dat/epitaph.txt index d35ba5441..a8fbb3266 100644 --- a/dat/epitaph.txt +++ b/dat/epitaph.txt @@ -1,4 +1,4 @@ -# NetHack 3.6 epitaph.txt $NHDT-Date: 1524689580 2018/04/25 20:53:00 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.3 $ +# NetHack 3.7 epitaph.txt $NHDT-Date: 1596498241 2020/08/03 23:44:01 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.4 $ # Copyright (c) 2015 by Pasi Kallinen # NetHack may be freely redistributed. See license for details. # Epitaphs for random headstones diff --git a/dat/fakewiz1.lua b/dat/fakewiz1.lua index 856ac3161..906d7f97c 100644 --- a/dat/fakewiz1.lua +++ b/dat/fakewiz1.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 yendor.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ +-- NetHack 3.7 yendor.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- Copyright (c) 1992 by M. Stephenson and Izchak Miller -- NetHack may be freely redistributed. See license for details. @@ -23,7 +23,7 @@ des.levregion({ region={01,00,79,20}, region_islev=1, exclude={0,0,8,7}, type="b des.teleport_region({ region={01,00,79,20}, region_islev=1,exclude={2,2,6,6} }) des.levregion({ region={4,4,4,4}, type="portal", name="wizard3" }) des.mazewalk(08,05,"east") -des.region({ region={04,03,06,06},lit=0,type="ordinary",prefilled=0,irregular=1 }) +des.region({ region={04,03,06,06},lit=0,type="ordinary",irregular=1,arrival_room=true }) des.monster("L",04,04) des.monster("vampire lord",03,04) des.monster("kraken",06,06) diff --git a/dat/fakewiz2.lua b/dat/fakewiz2.lua index d8f73abb3..ae14a6966 100644 --- a/dat/fakewiz2.lua +++ b/dat/fakewiz2.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 yendor.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ +-- NetHack 3.7 yendor.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- Copyright (c) 1992 by M. Stephenson and Izchak Miller -- NetHack may be freely redistributed. See license for details. @@ -22,7 +22,6 @@ des.levregion({ region={01,00,79,20}, region_islev=1, exclude={0,0,8,7}, type="s des.levregion({ region={01,00,79,20}, region_islev=1, exclude={0,0,8,7}, type="branch" }); des.teleport_region({ region={01,00,79,20}, region_islev=1,exclude={2,2,6,6} }) des.mazewalk(08,05,"east") -des.region({ region={04,03,06,06},lit=0,type="ordinary",prefilled=0,irregular=1 }) des.monster("L",04,04) des.monster("vampire lord",03,04) des.monster("kraken",06,06) diff --git a/dat/fire.lua b/dat/fire.lua index 105ca0fd0..babe6e15f 100644 --- a/dat/fire.lua +++ b/dat/fire.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 endgame.des $NHDT-Date: 1546303680 2019/01/01 00:48:00 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.14 $ +-- NetHack 3.7 endgame.des $NHDT-Date: 1546303680 2019/01/01 00:48:00 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.14 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- Copyright (c) 1992,1993 by Izchak Miller, David Cohrs, -- and Timo Hakulinen diff --git a/dat/history b/dat/history index d1d6dd084..1651f7d3b 100644 --- a/dat/history +++ b/dat/history @@ -5,9 +5,14 @@ Behold, mortal, the origins of NetHack... Jay Fenlason wrote the original Hack, with help from Kenny Woodland, Mike Thome, and Jon Payne. -Andries Brouwer did a major re-write, transforming Hack into a very different -game, and published (at least) three versions (1.0.1, 1.0.2, and 1.0.3) for -UNIX(tm) machines to the Usenet. +Andries Brouwer did a major re-write while at Stichting Mathematisch Centrum +(now Centrum Wiskunde & Informatica), transforming Hack into a very different +game. He published the Hack source code for use on UNIX(tm) 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(tm) C and MS-DOS(tm), producing PC HACK 1.01e, added support for DEC Rainbow graphics in version 1.03g, and @@ -20,7 +25,9 @@ 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. +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, @@ -183,11 +190,11 @@ resurrected it for 3.3.1. The release of NetHack 3.4.3 in December 2003 marked the beginning 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 continued 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 +NetHack Development Team slowly and quietly continued 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. diff --git a/dat/juiblex.lua b/dat/juiblex.lua index 588290cc1..2eff9ec79 100644 --- a/dat/juiblex.lua +++ b/dat/juiblex.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 gehennom.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.13 $ +-- NetHack 3.7 gehennom.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.13 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- Copyright (c) 1992 by M. Stephenson and Izchak Miller -- NetHack may be freely redistributed. See license for details. @@ -56,7 +56,7 @@ place:set(04,15); place:set(46,15); -- Dungeon description -des.region({ region={00,00,50,17}, lit=0, type="swamp" }) +des.region({ region={00,00,50,17}, lit=0, type="swamp", filled=2 }) des.levregion({ region = {01,00,11,20}, region_islev=1, exclude={0,0,50,17}, type="stair-down" }); des.levregion({ region = {69,00,79,20}, region_islev=1, exclude={0,0,50,17}, type="stair-up" }); des.levregion({ region = {01,00,11,20}, region_islev=1, exclude={0,0,50,17}, type="branch" }); diff --git a/dat/knox.lua b/dat/knox.lua index aa5ca4888..e9603e866 100644 --- a/dat/knox.lua +++ b/dat/knox.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 knox.des $NHDT-Date: 1547343821 2019/01/13 01:43:41 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.13 $ +-- NetHack 3.7 knox.des $NHDT-Date: 1547343821 2019/01/13 01:43:41 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.13 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- Copyright (c) 1992 by Izchak Miller -- NetHack may be freely redistributed. See license for details. @@ -39,7 +39,7 @@ des.levregion({ region = {08,16,08,16}, type="branch" }); des.teleport_region({ region = {06,15,09,16}, dir="up" }) des.teleport_region({ region = {06,15,09,16}, dir="down" }) -- Throne room, with Croesus on the throne -des.region({ x1=37,y1=08,x2=46,y2=11, lit=1, type="throne", prefilled=0 }) +des.region({ x1=37,y1=08,x2=46,y2=11, lit=1, type="throne", filled=1 }) -- 50% chance each to move throne and/or fort's entry secret door up one row if percent(50) then des.monster({ id = "Croesus", x=43, y=10, peaceful = 0 }) @@ -80,10 +80,10 @@ des.region(selection.area(46,06,48,06),"lit") des.region(selection.area(19,13,21,13),"lit") des.region(selection.area(46,13,48,13),"lit") -- A welcoming committee -des.region({ region={03,10,07,13},lit=1,type="zoo",prefilled=0,irregular=1 }) +des.region({ region={03,10,07,13},lit=1,type="zoo",filled=1,irregular=1 }) -- arrival chamber; needs to be a real room to control migrating monsters, -- and `unfilled' is a kludge to force an ordinary room to remain a room -des.region({ region={06,15,09,16},lit=0,type="ordinary",prefilled=0 }) +des.region({ region={06,15,09,16},lit=0,type="ordinary",arrival_room=true }) -- 3.6.2: Entering level carrying a lit candle would show the whole entry -- chamber except for its top right corner even though some of the revealed @@ -109,7 +109,7 @@ des.region(selection.area(05,14,09,14),"unlit") -- it is expected to work.) -- Barracks -des.region({ region={62,03,71,04},lit=1,type="barracks",prefilled=0,irregular=1 }) +des.region({ region={62,03,71,04},lit=1,type="barracks",filled=1,irregular=1 }) -- Doors des.door("closed",06,14) des.door("closed",09,03) diff --git a/dat/medusa-1.lua b/dat/medusa-1.lua index 591e404d2..85f053a06 100644 --- a/dat/medusa-1.lua +++ b/dat/medusa-1.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 medusa.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ +-- NetHack 3.7 medusa.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- Copyright (c) 1990, 1991 by M. Stephenson -- NetHack may be freely redistributed. See license for details. @@ -36,8 +36,10 @@ des.map([[ -- Dungeon Description des.region(selection.area(00,00,74,19),"lit") des.region(selection.area(31,07,45,07),"unlit") --- (must maintain one room definition; `filled=0' forces its room to be kept) -des.region({ region={35,09, 41,10}, lit = 0, type="ordinary", prefilled = 1 }) +-- make the downstairs room a real room to control arriving monsters, +-- and also as a fixup_special hack; the first room defined on Medusa's level +-- receives some statues +des.region({ region={35,09, 41,10}, lit = 0, type="ordinary", arrival_room=true }) des.region(selection.area(31,12,45,12),"unlit") -- Teleport: down to up stairs island, up to Medusa's island des.teleport_region({ region = {01,01,05,17}, dir="down" }) diff --git a/dat/medusa-2.lua b/dat/medusa-2.lua index 17c2893ff..5fc0886ea 100644 --- a/dat/medusa-2.lua +++ b/dat/medusa-2.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 medusa.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ +-- NetHack 3.7 medusa.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- Copyright (c) 1990, 1991 by M. Stephenson -- NetHack may be freely redistributed. See license for details. @@ -32,9 +32,12 @@ des.map([[ -- Dungeon Description des.region(selection.area(00,00,74,19),"lit") des.region(selection.area(02,03,05,16),"unlit") -des.region({ region={61,03, 72,16}, lit=0, type="ordinary", prefilled = 1,irregular = 1 }) +-- fixup_special hack: the first room defined on a Medusa level gets some +-- leaderboard statues; setting the region as irregular makes it a room +des.region({ region={61,03, 72,16}, lit=0, type="ordinary",irregular = 1 }) des.region(selection.area(71,08,72,11),"unlit") -des.region(selection.area(67,08,69,11),"lit") +-- make the downstairs area a real room to control arriving monsters +des.region({ region={67,08,69,11}, lit=1, type="ordinary", arrival_room=true }) -- Teleport: down to up stairs island, up to Medusa's island des.teleport_region({ region = {02,03,05,16}, dir="down" }) des.teleport_region({ region = {61,03,72,16}, dir="up" }) diff --git a/dat/medusa-3.lua b/dat/medusa-3.lua index efc860ae5..65da48b76 100644 --- a/dat/medusa-3.lua +++ b/dat/medusa-3.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 medusa.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ +-- NetHack 3.7 medusa.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- Copyright (c) 1990, 1991 by M. Stephenson -- NetHack may be freely redistributed. See license for details. @@ -37,7 +37,10 @@ place:set(66,05); place:set(46,15); des.region(selection.area(00,00,74,19),"lit") -des.region({ region={49,14, 51,16}, lit=-1, type="ordinary", prefilled = 1 }); +-- fixup_special hack: the first room defined on a Medusa level gets some +-- leaderboard statues, use arrival_room to force it to be a room even though +-- monsters won't arrive within it +des.region({ region={49,14, 51,16}, lit=-1, type="ordinary", arrival_room=true }); des.region(selection.area(07,05,09,07),"unlit") des.region(selection.area(65,04,67,06),"unlit") des.region(selection.area(45,14,47,16),"unlit") diff --git a/dat/medusa-4.lua b/dat/medusa-4.lua index 73f6df286..75e910bf5 100644 --- a/dat/medusa-4.lua +++ b/dat/medusa-4.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 medusa.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ +-- NetHack 3.7 medusa.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- Copyright (c) 1990, 1991 by M. Stephenson -- NetHack may be freely redistributed. See license for details. @@ -40,7 +40,10 @@ place:set(10,08); place:set(10,12); -- des.region(selection.area(00,00,74,19),"lit") -des.region({ region={13,03, 18,13}, lit=1, type="ordinary", prefilled=1 }) +-- fixup_special hack: The first "room" region in Medusa levels gets filled with +-- some leaderboard statues, so this needs to be a room; setting irregular=1 +-- will force this +des.region({ region={13,03, 18,13}, lit=1, type="ordinary", irregular=1 }) -- des.teleport_region({ region = {64,01,74,17}, dir="down" }); des.teleport_region({ region = {02,02,18,13}, dir="up" }); diff --git a/dat/minefill.lua b/dat/minefill.lua index ca23a8da6..74911c39d 100644 --- a/dat/minefill.lua +++ b/dat/minefill.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 mines.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.25 $ +-- NetHack 3.7 mines.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.25 $ -- Copyright (c) 1989-95 by Jean-Christophe Collet -- Copyright (c) 1991-95 by M. Stephenson -- NetHack may be freely redistributed. See license for details. diff --git a/dat/minend-1.lua b/dat/minend-1.lua index 7fce31a28..f86140518 100644 --- a/dat/minend-1.lua +++ b/dat/minend-1.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 mines.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.25 $ +-- NetHack 3.7 mines.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.25 $ -- Copyright (c) 1989-95 by Jean-Christophe Collet -- Copyright (c) 1991-95 by M. Stephenson -- NetHack may be freely redistributed. See license for details. @@ -35,8 +35,8 @@ des.map([[ local place = { {08,16},{13,07},{21,08},{41,14},{50,04},{50,16},{66,01} } shuffle(place) -des.region({ region={26,01,32,01}, lit=0, type="ordinary", - prefilled=0, irregular=1 }) +-- make the entry chamber a real room; it affects monster arrival +des.region({ region={26,01,32,01}, lit=0, type="ordinary", irregular=1, arrival_room=true }) des.region(selection.area(20,08,21,08),"unlit") des.region(selection.area(23,08,25,08),"unlit"); -- Secret doors diff --git a/dat/minend-2.lua b/dat/minend-2.lua index ced2b11f6..469310d19 100644 --- a/dat/minend-2.lua +++ b/dat/minend-2.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 mines.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.25 $ +-- NetHack 3.7 mines.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.25 $ -- Copyright (c) 1989-95 by Jean-Christophe Collet -- Copyright (c) 1991-95 by M. Stephenson -- NetHack may be freely redistributed. See license for details. diff --git a/dat/minend-3.lua b/dat/minend-3.lua index 92be571b1..b5d7abfda 100644 --- a/dat/minend-3.lua +++ b/dat/minend-3.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 mines.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.25 $ +-- NetHack 3.7 mines.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.25 $ -- Copyright (c) 1989-95 by Jean-Christophe Collet -- Copyright (c) 1991-95 by M. Stephenson -- NetHack may be freely redistributed. See license for details. diff --git a/dat/minetn-1.lua b/dat/minetn-1.lua index 39460ead3..8558662b9 100644 --- a/dat/minetn-1.lua +++ b/dat/minetn-1.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 mines.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.25 $ +-- NetHack 3.7 mines.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.25 $ -- Copyright (c) 1989-95 by Jean-Christophe Collet -- Copyright (c) 1991-95 by M. Stephenson -- NetHack may be freely redistributed. See license for details. diff --git a/dat/minetn-2.lua b/dat/minetn-2.lua index 7081021e6..258f62a57 100644 --- a/dat/minetn-2.lua +++ b/dat/minetn-2.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 mines.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.25 $ +-- NetHack 3.7 mines.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.25 $ -- Copyright (c) 1989-95 by Jean-Christophe Collet -- Copyright (c) 1991-95 by M. Stephenson -- NetHack may be freely redistributed. See license for details. diff --git a/dat/minetn-3.lua b/dat/minetn-3.lua index b4ff7fb06..cd979739f 100644 --- a/dat/minetn-3.lua +++ b/dat/minetn-3.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 mines.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.25 $ +-- NetHack 3.7 mines.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.25 $ -- Copyright (c) 1989-95 by Jean-Christophe Collet -- Copyright (c) 1991-95 by M. Stephenson -- NetHack may be freely redistributed. See license for details. diff --git a/dat/minetn-4.lua b/dat/minetn-4.lua index cc4dc7611..49325239d 100644 --- a/dat/minetn-4.lua +++ b/dat/minetn-4.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 mines.des $NHDT-Date: 1548631704 2019/01/27 23:28:24 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.30 $ +-- NetHack 3.7 mines.des $NHDT-Date: 1548631704 2019/01/27 23:28:24 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.30 $ -- Copyright (c) 1989-95 by Jean-Christophe Collet -- Copyright (c) 1991-95 by M. Stephenson -- NetHack may be freely redistributed. See license for details. diff --git a/dat/minetn-5.lua b/dat/minetn-5.lua index baade6a41..f08a19007 100644 --- a/dat/minetn-5.lua +++ b/dat/minetn-5.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 mines.des $NHDT-Date: 1548631704 2019/01/27 23:28:24 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.30 $ +-- NetHack 3.7 mines.des $NHDT-Date: 1548631704 2019/01/27 23:28:24 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.30 $ -- Copyright (c) 1989-95 by Jean-Christophe Collet -- Copyright (c) 1991-95 by M. Stephenson -- NetHack may be freely redistributed. See license for details. @@ -95,13 +95,13 @@ des.monster("dwarf") des.monster("dwarf") -- The shops -des.region({ region={25,17, 28,19}, lit=1, type="candle shop", prefilled=0 }) +des.region({ region={25,17, 28,19}, lit=1, type="candle shop", filled=1 }) des.door("closed",24,18) -des.region({ region={59, 9, 67,10}, lit=1, type="shop", prefilled=0 }) +des.region({ region={59, 9, 67,10}, lit=1, type="shop", filled=1 }) des.door("closed",66,08) -des.region({ region={57,13, 60,15}, lit=1, type="tool shop", prefilled=0 }) +des.region({ region={57,13, 60,15}, lit=1, type="tool shop", filled=1 }) des.door("closed",56,14) -des.region({ region={05,09, 08,10}, lit=1, type=monkfoodshop(), prefilled=0 }) +des.region({ region={05,09, 08,10}, lit=1, type=monkfoodshop(), filled=1 }) des.door("closed",07,11) -- Gnome homes des.door("closed",04,14) @@ -132,6 +132,6 @@ des.door("locked",50,06) des.object("(", 50, 03) des.object({ id = "statue", x=38, y=15, montype="gnome king", historic=1 }) -- Temple -des.region({ region={29,02, 33,04}, lit=1, type="temple" }) +des.region({ region={29,02, 33,04}, lit=1, type="temple", filled=1 }) des.door("closed",31,05) des.altar({ x=31,y=03, align=align[1], type="shrine" }) diff --git a/dat/minetn-6.lua b/dat/minetn-6.lua index 6de06d11a..ba642c625 100644 --- a/dat/minetn-6.lua +++ b/dat/minetn-6.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 mines.des $NHDT-Date: 1548631704 2019/01/27 23:28:24 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.30 $ +-- NetHack 3.7 mines.des $NHDT-Date: 1548631704 2019/01/27 23:28:24 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.30 $ -- Copyright (c) 1989-95 by Jean-Christophe Collet -- Copyright (c) 1991-95 by M. Stephenson -- NetHack may be freely redistributed. See license for details. @@ -36,11 +36,11 @@ des.levregion({ type="stair-down", region={61,03,75,19}, region_islev=1, exclude des.feature("fountain" ,22,07) des.feature("fountain", 09,13) des.region(selection.area(13,5,14,6),"unlit") -des.region({ region={09,07, 11,09}, lit=1, type="candle shop", prefilled=0 }) -des.region({ region={16,04, 18,06}, lit=1, type="tool shop", prefilled=0 }) -des.region({ region={23,01, 25,03}, lit=1, type="shop", prefilled=0 }) -des.region({ region={22,12, 24,13}, lit=1, type=monkfoodshop(), prefilled=0 }) -des.region({ region={31,12, 36,14}, lit=1, type="temple", prefilled=0 }) +des.region({ region={09,07, 11,09}, lit=1, type="candle shop", filled=1 }) +des.region({ region={16,04, 18,06}, lit=1, type="tool shop", filled=1 }) +des.region({ region={23,01, 25,03}, lit=1, type="shop", filled=1 }) +des.region({ region={22,12, 24,13}, lit=1, type=monkfoodshop(), filled=1 }) +des.region({ region={31,12, 36,14}, lit=1, type="temple", filled=1 }) des.altar({ x=35,y=13,align=align[1],type="shrine"}) des.door("closed",5,2) diff --git a/dat/minetn-7.lua b/dat/minetn-7.lua index 16bca3ae1..4526b9225 100644 --- a/dat/minetn-7.lua +++ b/dat/minetn-7.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 mines.des $NHDT-Date: 1548631704 2019/01/27 23:28:24 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.30 $ +-- NetHack 3.7 mines.des $NHDT-Date: 1548631704 2019/01/27 23:28:24 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.30 $ -- Copyright (c) 1989-95 by Jean-Christophe Collet -- Copyright (c) 1991-95 by M. Stephenson -- NetHack may be freely redistributed. See license for details. diff --git a/dat/opthelp b/dat/opthelp index 5a9049cac..2d82a4e85 100644 --- a/dat/opthelp +++ b/dat/opthelp @@ -2,120 +2,150 @@ Boolean options not under specific compile flags (with default values in []): (You can learn which options exist in your version by checking your current option setting, which is reached via the 'O' command.) -acoustics can your character hear anything [TRUE] -autodescribe describe the terrain under cursor [FALSE] -autodig dig if moving and wielding digging tool [FALSE] -autoopen walking into a door attempts to open it [TRUE] -autopickup automatically pick up objects you move over [TRUE] -autoquiver when firing with an empty quiver, select some [FALSE] +acoustics can your character hear anything [True] +autodescribe describe the terrain under cursor [False] +autodig dig if moving and wielding digging tool [False] +autoopen walking into a door attempts to open it [True] +autopickup automatically pick up objects you move over [True] +autoquiver when firing with an empty quiver, select some [False] suitable inventory weapon to fill the quiver -autounlock when opening a locked door or looting a locked [TRUE] +autounlock when opening a locked door or looting a locked [True] container while carrying a key, offer to use it -BIOS allow the use of IBM ROM BIOS calls [FALSE] -blind your character is permanently blind [FALSE] -bones allow loading bones files [TRUE] -clicklook look at map by clicking right mouse button [FALSE] -cmdassist give help for errors on direction & other commands [TRUE] -confirm ask before hitting tame or peaceful monsters [TRUE] -dark_room show floor not in sight in different color [TRUE] -eight_bit_tty send 8-bit characters straight to terminal [FALSE] -extmenu tty, curses: use menu for # (extended commands) [FALSE] +BIOS allow the use of IBM ROM BIOS calls [False] +blind your character is permanently blind [False] +bones allow loading bones files [True] +clicklook look at map by clicking right mouse button [False] +cmdassist give help for errors on direction & other commands [True] +confirm ask before hitting tame or peaceful monsters [True] +dark_room show floor not in sight in different color [True] +eight_bit_tty send 8-bit characters straight to terminal [False] +extmenu tty, curses: use menu for # (extended commands) [False] X11: menu has all commands (T) or traditional subset (F) -fixinv try to retain the same letter for the same object [TRUE] -force_invmenu commands asking for inventory item show a menu [FALSE] -goldX when filtering objects by bless/curse state, [FALSE] +female deprecated; use compound option gender:female [False] +fixinv try to retain the same letter for the same object [True] +force_invmenu commands asking for inventory item show a menu [False] +goldX when filtering objects by bless/curse state, [False] whether to classify gold as X (unknown) or U (uncursed) -help print all available info when using the / command [TRUE] +help print all available info when using the / command [True] herecmd_menu show menu of some possible commands when clicking - on yourself or next to you with mouse [FALSE] -ignintr ignore interrupt signal, including breaks [FALSE] -implicit_uncursed omit "uncursed" from inventory, if possible [TRUE] -legacy print introductory message [TRUE] -lit_corridor show a dark corridor as lit if in sight [FALSE] -lootabc use a/b/c rather than o/i/b when looting [FALSE] -mail enable the mail daemon [TRUE] -mention_decor give feedback when walking across stairs, altars, [FALSE] + on yourself or next to you with mouse [False] +ignintr ignore interrupt signal, including breaks [False] +implicit_uncursed omit "uncursed" from inventory, if possible [True] +legacy print introductory message [True] +lit_corridor show a dark corridor as lit if in sight [False] +lootabc use a/b/c rather than o/i/b when looting [False] +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] -nudist start your character without armor [FALSE] -null allow nulls to be sent to your terminal [TRUE] +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 + bold, inverse, &c even when color is unavailable or toggled off +nudist start your character without armor [False] +null allow nulls to be sent to your terminal [True] try turning this option off (forcing NetHack to use its own delay code) if moving objects seem to teleport across rooms -perm_invent keep inventory in a permanent window [FALSE] -pickup_thrown override pickup_types for thrown objects [TRUE] -pushweapon when wielding a new weapon, put your previously [FALSE] +perm_invent keep inventory in a permanent window [False] +pickup_thrown override pickup_types for thrown objects [True] +pushweapon when wielding a new weapon, put your previously [False] wielded weapon into the secondary weapon slot -quick_farsight usually skip the chance to browse the map when [FALSE] +quick_farsight usually skip the chance to browse the map when [False] randomly triggered clairvoyance takes place -rawio allow the use of raw I/O [FALSE] -rest_on_space count the space bar as a rest character [FALSE] -safe_pet prevent you from (knowingly) attacking your pet(s) [TRUE] -sanity_check perform data sanity checks [FALSE] -showexp display your accumulated experience points [FALSE] -showrace show yourself by your race rather than by role [FALSE] -silent don't use your terminal's bell sound [TRUE] -sortpack group similar kinds of objects in inventory [TRUE] -sparkle display sparkly effect for resisted magical [TRUE] +rawio allow the use of raw I/O [False] +rest_on_space count the space bar as a rest character [False] +safe_pet prevent you from (knowingly) attacking your pet(s) [True] +safe_wait require use of 'm' prefix before '.' or 's' to [True] + wait or search when adjacent to a hostile monster +sanity_check perform data sanity checks [False] +showexp display your accumulated experience points [False] +showrace show yourself by your race rather than by role [False] +silent don't use your terminal's bell sound [True] +sortpack group similar kinds of objects in inventory [True] +sparkle display sparkly effect for resisted magical [True] attacks (e.g. fire attack on fire-resistant monster) -standout use standout mode for --More-- on messages [FALSE] -status_updates update the status lines [TRUE] -time display elapsed game time, in moves [FALSE] -tombstone print tombstone when you die [TRUE] -toptenwin print topten in a window rather than stdout [FALSE] -travel enables travelling via mouse click if supported; [TRUE] +standout use standout mode for --More-- on messages [False] +status_updates update the status lines [True] +time display elapsed game time, in moves [False] +tombstone print tombstone when you die [True] +toptenwin print topten in a window rather than stdout [False] +travel enables travelling via mouse click if supported; [True] can be toggled off to prevent mouse clicks on the map from 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] -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] +use_darkgray use bold black instead of blue for black glyphs. [True] +use_inverse display detected monsters in highlighted manner [False] +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] There are further boolean options controlled by compilation flags. Boolean option if INSURANCE was set at compile time: -checkpoint save game state after each level change, for [TRUE] +checkpoint save game state after each level change, for [True] possible recovery after program crash Boolean option if NEWS was set at compile time: -news print any news from game administrator on startup [TRUE] +news print any news from game administrator on startup [True] Boolean option if SCORE_ON_BOTL was set at compile time: -showscore display your approximate accumulated score [FALSE] +showscore display your approximate accumulated score [False] Boolean options if TEXTCOLOR was set at compile time: -color use different colors for objects on screen [TRUE for micros] -hilite_pet display pets in a highlighted manner [FALSE] -hilite_pile display item piles in a highlighted manner [FALSE] +color use different colors for objects on screen [True for micros] +hilite_pet display pets in a highlighted manner [False] +hilite_pile display item piles in a highlighted manner [False] Boolean option if TIMED_DELAY was set at compile time (tty interface only): -timed_delay on unix and VMS, use a timer instead of sending [TRUE] +timed_delay on unix and VMS, use a timer instead of sending [True] extra screen output when attempting to pause for display effect. on MSDOS without the termcap lib, whether or not to pause for visual effect. Boolean option for Amiga, or for others if ALTMETA was set at compile time: -altmeta For Amiga, treat Alt+key as Meta+key. [TRUE] +altmeta For Amiga, treat Alt+key as Meta+key. [True] altmeta For unix and VMS, treat two character sequence - "ESC c" as M-c (Meta+c, 8th bit set) when nethack [FALSE] + "ESC c" as M-c (Meta+c, 8th bit set) when nethack [False] obtains a command from player's keyboard. Boolean option if USE_TILES was set at compile time (MSDOS protected mode): -preload_tiles control whether tiles get pre-loaded into RAM at [TRUE] +preload_tiles control whether tiles get pre-loaded into RAM at [True] the start of the game. Doing so enhances performance of the tile graphics, but uses more memory. Boolean option if TTY_TILES_ESCCODES was set at compile time (tty only): -vt_tiledata insert extra data escape code markers into output [FALSE] +vt_tiledata insert extra data escape code markers into output [False] Boolean option if TTY_SOUND_ESCCODES was set at compile time (tty only): -vt_sounddata insert sound data escape code markers into output [FALSE] +vt_sounddata insert sound data escape code markers into output [False] -Any Boolean option can be negated by prefixing it with a '!' or 'no'. +Boolean options which may be available depending upon which interfaces +the program has been built to support. If it supports multiple such, +some of these may show as available for setting but not do anything if +you happen to be using a different interface than the one(s) they're for: +ascii_map show map as text, forces tiles_map Off; Qt, X11 +guicolor curses +hitpointbar curses, tty, Windows GUI if statushilites enabled; + Qt without statushilites; X11 if 'fancy_status' disabled + (via X application defaults) and statushilities enabled +popup_dialog curses, Qt, Windows GUI +selectsaved tty (Qt and Windows GUI do this unconditionally) +splash_screen curses, Qt, Windows GUI +tiled_map show map as tiles, forces ascii_map Off; Qt, X11 +Boolean options available when running in debug mode (aka wizard mode): +menu_tab_sep menu formatting--do not touch +monpolycontrol have player choose shape-changing monsters' new shapes +travel_debug not implemented? +wizweight include item weights in inventory display + +Any Boolean option can be set to True by including it among options being +set, or negated (set to False) by prefixing its name with a '!' or 'no'. +Alternatively, the compound option syntax can be used: 'optname:true' and +'optname:false'. + + - - - - - Compound options are written as option_name:option_value. @@ -129,10 +159,12 @@ disclose the types of information you want [ni na nv ng nc no] 'n' prompt with default "no", 'y' prompt with default "yes", 'a' prompt to select sorting order (for suffix 'v' only); suffix: 'i' inventory, 'a' attributes, 'v' vanquished - monsters, 'g' genocided and extinct monsters, 'c' conduct, - 'o' dungeon overview) + monsters, 'g' genocided and extinct monsters, 'c' conduct + and achievements, 'o' dungeon overview) fruit the name of a fruit you enjoy eating [slime mold] (basically a whimsy which NetHack uses from time to time). +hilite_status specifies a rule for highlighting a status field [] + (multiple instances are allowed) menustyle user interface for selection of multiple objects: [Full] Traditional -- prompt for classes of interest, then prompt item-by-item for those classes; @@ -143,13 +175,24 @@ 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.) +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 + reverse -- full with messages printed most-recent-first + combination -- first two of consecutive ^P commands show + single messages, third yields full set +msg_window behavior of ^P message recall for curses interface: [r] + reverse -- full window, most recent first + full -- full with messages printed least recent first, + initially positioned on last page to start + with most recent messages in view number_pad alphabetic versus numeric control over movement: [0] 0 -- traditional hjkl + yubn movement (default); 1 -- digits control movement, for use with numeric keypad; 2 -- same as 1, but '5' works as 'g' prefix rather than 'G'; 3 -- numeric for phone keypad (1,2,3 above, 7,8,9 below); 4 -- phone keypad (3) combined with '5' preference (2); - -1 -- alphabetic movement but 'z' swapped with 'y'. + -1 -- "qwertz"; alphabetic movement but 'z' swapped with 'y'. Setting number_pad (to a positive value) affects how all digit keys are handled, not just those on numeric keypad. packorder a list of default symbols for kinds of [")[%?+!=/(*`0_] @@ -190,6 +233,21 @@ scores the parts of the score list you wish [!own/3 top/2 around] to see when the game ends. You choose a combination of top scores, scores around the top scores, and all of your own scores. +sortdiscoveries preferred order when viewing list of discovered objects [o] + o -- in order of discovery within each class + s -- sortloot's "loot" order + c -- alphabetized within each class + a -- alphabetized across all classes +sortloot preferred order when examining a set of objects [n] + none -- no sorting + loot -- sort piles of objects on floor and in containers + full -- 'loot' plus objects in inventory +statushilites whether to display status highlights (when non-zero) and [0] + also how many turns to display temporary highlights (for + 'up', 'down', and 'changed' hilite_status rules) +statuslines whether to use expanded (3) or condensed (2) status [2] + (for tty and curses; 2 is traditional, 3 is recommended; + also for Qt, where 3 is traditional and 2 is recommended) suppress_alert disable various version-specific warnings about changes [] in game play or the user interface, such as notification given for the 'Q' command that quitting is now done via #quit @@ -215,8 +273,8 @@ Compound options which may be set only on startup are: align Your starting alignment (lawful, neutral, chaotic, [random] or random). Many roles restrict the choice to a subset. You may specify just the first letter. -catname the name of your first cat [none] -dogname the name of your first dog [none] +catname name of your starting pet if it is a kitten [none] +dogname name of your starting pet if it is a little dog [none] Several roles who start with a dog have one whose name is pre-set (for example, "Hachi" for Samurai), but that name will be overridden if you specify dogname. @@ -224,7 +282,7 @@ gender Your starting gender (male, female, or random). [random] You may specify just the first letter. Although you can still denote your gender using the old "male" and "female" boolean options, the "gender" option will take precedence. -horsename the name of your first horse [none] +horsename name of your starting pet if it is a pony [none] menu_* specify single character accelerators for menu commands. Here is a list of all commands with their default keystroke followed by a list of window-ports that implement them: @@ -266,21 +324,13 @@ role Your starting role (e.g., role:Barbarian, role:Valk). [random] the "role" option will take precedence. windowtype windowing system to be used [depends on operating system and compile-time setup] if more than one choice is available. - Most instances of the program support only one window-type; + Some instances of the program support only one window-type; when that is the case, you don't need to specify anything. The list of supported window-types in your program can be seen while the program is running by using the #version command or from outside the program by examining the text file named 'options' which is generated when building it. -Compound option if TTY_GRAPHICS was set at compile time: -msg_window the type of message window to use: [single] - single -- One message at a time - full -- Full window with all saved top line messages - reverse -- Same as full, but messages printed most-recent-first - combination -- Two single messages, then as full - - Some sample options lists are: !autopickup,!tombstone,name:Gandalf,scores:own/3 top/2 around female,nonews,dogname:Rover,rest_on_space,!verbose,menustyle:traditional diff --git a/dat/orcus.lua b/dat/orcus.lua index ac5b940bf..109053c3d 100644 --- a/dat/orcus.lua +++ b/dat/orcus.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 gehennom.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.13 $ +-- NetHack 3.7 gehennom.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.13 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- Copyright (c) 1992 by M. Stephenson and Izchak Miller -- NetHack may be freely redistributed. See license for details. @@ -77,9 +77,9 @@ des.door("open",26,14) des.door("closed",06,15) -- Special rooms des.altar({ x=24,y=07,align="noalign",type="sanctum" }) -des.region({ region={22,12,25,16},lit=0,type="morgue", prefilled=0 }) -des.region({ region={32,09,37,12},lit=1,type="shop",prefilled=0 }) -des.region({ region={12,00,15,04},lit=1,type="shop",prefilled=0 }) +des.region({ region={22,12,25,16},lit=0,type="morgue",filled=1 }) +des.region({ region={32,09,37,12},lit=1,type="shop",filled=1 }) +des.region({ region={12,00,15,04},lit=1,type="shop",filled=1 }) -- Some traps. des.trap("spiked pit") des.trap("sleep gas") diff --git a/dat/quest.lua b/dat/quest.lua index d23208b36..4a9f275bf 100644 --- a/dat/quest.lua +++ b/dat/quest.lua @@ -82,6 +82,10 @@ questtext = { "\"Thou art but a godless void.\"", "\"Thou art not worthy to seek the Amulet.\"", "\"No one expects the Spanish Inquisition!\"", + "\"Judgment hath been passed upon thee, %p.\"", + "\"Thy reckoning is at hand, %p.\"", + "\"Thou shalt be brought before %D for thy crimes!\"", + "\"With %D as my witness, I shall strike thee down.\"", }, banished = { synopsis = "[You are banished from %H for betraying your allegiance to %d.]", @@ -118,6 +122,13 @@ Go now! You are banished from this place.]], "\"Verily, thy corpse could not smell worse!\"", "\"Wait! I shall polymorph into a grid bug to give thee a fighting chance!\"", "\"Why search for the Amulet? Thou wouldst but lose it, cretin.\"", + "\"Thou ought to be a comedian, thy skills are so laughable!\"", + "\"Thy gaze is so vacant, I thought thee a floating eye!\"", + "\"Thy head is unfit for a mind flayer to munch upon!\"", + "\"Only thy reflection could love thee!\"", + "\"Hast thou considered masking thy odor?\"", + "\"Hold! Thy face is a most exquisite torture!\"", + "\"I wouldst fart in thy direction, but it might improve thy smell!\"", }, legacy = { synopsis = "[%dC has chosen you to recover the Amulet of Yendor for %dI.]", diff --git a/dat/sanctum.lua b/dat/sanctum.lua index 45aa0b361..d4594fe40 100644 --- a/dat/sanctum.lua +++ b/dat/sanctum.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 gehennom.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.13 $ +-- NetHack 3.7 gehennom.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.13 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- Copyright (c) 1992 by M. Stephenson and Izchak Miller -- NetHack may be freely redistributed. See license for details. @@ -32,11 +32,11 @@ des.map([[ | ------------- ----- ------- | ---------------------------------------------------------------------------- ]]); -des.region({ region={15,07, 21,10}, lit=1, type="temple", contents = function() +des.region({ region={15,07, 21,10}, lit=1, type="temple", filled=2, contents = function() des.door({ wall = "random", state = "secret" }); end }) des.altar({ x=18, y=08, align="noalign", type="sanctum" }) -des.region({ region={41,06, 48,11}, lit=0, type="morgue", prefilled=0, irregular=1 }) +des.region({ region={41,06, 48,11}, lit=0, type="morgue", filled=1, irregular=1 }) -- Non diggable walls des.non_diggable(selection.area(00,00,75,19)) -- Invisible barrier separating the left & right halves of the level diff --git a/dat/soko1-1.lua b/dat/soko1-1.lua index b281975b5..1d6b7c09b 100644 --- a/dat/soko1-1.lua +++ b/dat/soko1-1.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 sokoban.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.13 $ +-- NetHack 3.7 sokoban.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.13 $ -- Copyright (c) 1998-1999 by Kevin Hugo -- NetHack may be freely redistributed. See license for details. -- @@ -94,8 +94,7 @@ des.door("closed", 17, 11); des.door("closed", 17, 13); des.door("closed", 17, 15); -des.region({ region={18,10, 22,16}, lit = 1, type = "zoo", - prefilled = 0, irregular = 1 }); +des.region({ region={18,10, 22,16}, lit = 1, type = "zoo", filled = 1, irregular = 1 }); px, py = selection.rndcoord(place); if percent(75) then diff --git a/dat/soko1-2.lua b/dat/soko1-2.lua index 9a8002852..3b54a231e 100644 --- a/dat/soko1-2.lua +++ b/dat/soko1-2.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 sokoban.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.13 $ +-- NetHack 3.7 sokoban.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.13 $ -- Copyright (c) 1998-1999 by Kevin Hugo -- NetHack may be freely redistributed. See license for details. -- @@ -96,8 +96,7 @@ des.door("locked",23,12) des.door("closed",17,10) des.door("closed",17,12) des.door("closed",17,14) -des.region({ region={18,09, 22,15}, lit = 1, type = "zoo", - prefilled = 0, irregular = 1 }); +des.region({ region={18,09, 22,15}, lit = 1, type = "zoo", filled = 1, irregular = 1 }); px, py = selection.rndcoord(place); if percent(25) then diff --git a/dat/soko2-1.lua b/dat/soko2-1.lua index 9934819f7..b9d043853 100644 --- a/dat/soko2-1.lua +++ b/dat/soko2-1.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 sokoban.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.13 $ +-- NetHack 3.7 sokoban.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.13 $ -- Copyright (c) 1998-1999 by Kevin Hugo -- NetHack may be freely redistributed. See license for details. -- diff --git a/dat/soko2-2.lua b/dat/soko2-2.lua index bb931c15f..ed64954d8 100644 --- a/dat/soko2-2.lua +++ b/dat/soko2-2.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 sokoban.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.13 $ +-- NetHack 3.7 sokoban.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.13 $ -- Copyright (c) 1998-1999 by Kevin Hugo -- NetHack may be freely redistributed. See license for details. -- diff --git a/dat/soko3-1.lua b/dat/soko3-1.lua index cec5eec8b..2a0826e0f 100644 --- a/dat/soko3-1.lua +++ b/dat/soko3-1.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 sokoban.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.13 $ +-- NetHack 3.7 sokoban.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.13 $ -- Copyright (c) 1998-1999 by Kevin Hugo -- NetHack may be freely redistributed. See license for details. -- diff --git a/dat/soko3-2.lua b/dat/soko3-2.lua index fa15d8ba6..461635d8d 100644 --- a/dat/soko3-2.lua +++ b/dat/soko3-2.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 sokoban.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.13 $ +-- NetHack 3.7 sokoban.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.13 $ -- Copyright (c) 1998-1999 by Kevin Hugo -- NetHack may be freely redistributed. See license for details. -- diff --git a/dat/soko4-1.lua b/dat/soko4-1.lua index 3257986de..5629a7a5d 100644 --- a/dat/soko4-1.lua +++ b/dat/soko4-1.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 sokoban.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.13 $ +-- NetHack 3.7 sokoban.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.13 $ -- Copyright (c) 1998-1999 by Kevin Hugo -- NetHack may be freely redistributed. See license for details. -- diff --git a/dat/soko4-2.lua b/dat/soko4-2.lua index e9df5c050..2cea6235f 100644 --- a/dat/soko4-2.lua +++ b/dat/soko4-2.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 sokoban.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.13 $ +-- NetHack 3.7 sokoban.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.13 $ -- Copyright (c) 1998-1999 by Kevin Hugo -- NetHack may be freely redistributed. See license for details. -- diff --git a/dat/symbols b/dat/symbols index 06aa31f66..9b9f9c72e 100644 --- a/dat/symbols +++ b/dat/symbols @@ -1,4 +1,4 @@ -# NetHack 3.6 symbols $NHDT-Date: 1572892906 2019/11/04 18:41:46 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.21 $ +# NetHack 3.7 symbols $NHDT-Date: 1596498253 2020/08/03 23:44:13 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.22 $ # Copyright (c) 2006 by Michael Allison # NetHack may be freely redistributed. See license for details. # diff --git a/dat/themerms.lua b/dat/themerms.lua index acb826cee..fa85a44df 100644 --- a/dat/themerms.lua +++ b/dat/themerms.lua @@ -1,7 +1,10 @@ -- themerooms is an array of tables and/or functions. --- the tables define "frequency" and "contents", --- a plain function has frequency of 1 +-- 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. -- 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 @@ -12,9 +15,8 @@ -- core calls themerooms_generate() multiple times per level -- to generate a single themed room. - themerooms = { - { + { -- the "default" room frequency = 1000, contents = function() @@ -77,38 +79,44 @@ themerooms = { end, -- Boulder room - function() - des.room({ type = "themed", - contents = function(rm) - for x = 0, rm.width do - for y = 0, rm.height do - if (percent(30)) then - if (percent(50)) then - des.object("boulder"); - else - des.trap("rolling boulder"); - end - end - end - end - end - }); - end, + { + mindiff = 4, + contents = function() + des.room({ type = "themed", + contents = function(rm) + for x = 0, rm.width - 1 do + for y = 0, rm.height - 1 do + if (percent(30)) then + if (percent(50)) then + des.object("boulder"); + else + des.trap("rolling boulder"); + end + end + end + end + end + }); + end + }, -- Spider nest - function() - des.room({ type = "themed", - contents = function(rm) - for x = 0, rm.width do - for y = 0, rm.height do - if (percent(30)) then - des.trap("web", x, y); - end - end - end - end - }); - end, + { + mindiff = 10, + contents = function() + des.room({ type = "themed", + contents = function(rm) + for x = 0, rm.width - 1 do + for y = 0, rm.height - 1 do + if (percent(30)) then + des.trap("web", x, y); + end + end + end + end + }); + end + }, -- Trap room function() @@ -118,8 +126,8 @@ themerooms = { "land mine", "sleep gas", "rust", "anti magic" }; shuffle(traps); - for x = 0, rm.width do - for y = 0, rm.height do + for x = 0, rm.width - 1 do + for y = 0, rm.height - 1 do if (percent(30)) then des.trap(traps[1], x, y); end @@ -169,8 +177,8 @@ themerooms = { contents = function(rm) local terr = { "-", "-", "-", "-", "L", "P", "T" }; shuffle(terr); - for x = 0, (rm.width - 3) / 4 do - for y = 0, (rm.height - 3) / 4 do + 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 }); @@ -219,7 +227,9 @@ themerooms = { 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 / 2), y = (rm.height / 2), w = 1, h = 1, joined = 0, + des.room({ type = "themed", + x = (rm.width - 1) / 2, y = (rm.height - 1) / 2, + w = 1, h = 1, joined = 0, contents = function() if (percent(50)) then local mons = { "M", "V", "L", "Z" }; @@ -245,7 +255,8 @@ themerooms = { contents = function(rm) local feature = { "C", "L", "I", "P", "T" }; shuffle(feature); - des.terrain(rm.width / 2, rm.height / 2, feature[1]); + des.terrain((rm.width - 1) / 2, (rm.height - 1) / 2, + feature[1]); end }); end, @@ -260,7 +271,7 @@ themerooms = { |......| |......| |......| ---------]], contents = function(m) des.region({ region={1,1,3,3}, type="ordinary", irregular=true, prefilled=true }); end }); +--------]], contents = function(m) des.region({ region={1,1,3,3}, type="ordinary", irregular=true, filled=1 }); end }); end, -- L-shaped, rot 1 @@ -273,7 +284,7 @@ xxx|...| |......| |......| |......| ---------]], contents = function(m) des.region({ region={5,1,5,3}, type="ordinary", irregular=true, prefilled=true }); end }); +--------]], contents = function(m) des.region({ region={5,1,5,3}, type="ordinary", irregular=true, filled=1 }); end }); end, -- L-shaped, rot 2 @@ -286,7 +297,7 @@ xxx|...| ----...| xxx|...| xxx|...| -xxx-----]], contents = function(m) des.region({ region={1,1,2,2}, type="ordinary", irregular=true, prefilled=true }); end }); +xxx-----]], contents = function(m) des.region({ region={1,1,2,2}, type="ordinary", irregular=true, filled=1 }); end }); end, -- L-shaped, rot 3 @@ -299,7 +310,7 @@ xxx-----]], contents = function(m) des.region({ region={1,1,2,2}, type="ordinary |...---- |...|xxx |...|xxx ------xxx]], contents = function(m) des.region({ region={1,1,2,2}, type="ordinary", irregular=true, prefilled=true }); end }); +-----xxx]], contents = function(m) des.region({ region={1,1,2,2}, type="ordinary", irregular=true, filled=1 }); end }); end, -- Blocked center @@ -321,7 +332,7 @@ if (percent(30)) then shuffle(terr); des.replace_terrain({ region = {1,1, 9,9}, fromterrain = "L", toterrain = terr[1] }); end -des.region({ region={1,1,2,2}, type="ordinary", irregular=true, prefilled=true }); +des.region({ region={1,1,2,2}, type="ordinary", irregular=true, filled=1 }); end }); end, @@ -334,7 +345,7 @@ x--.--x |.....| --...-- x--.--x -xx---xx]], contents = function(m) des.region({ region={3,3,3,3}, type="ordinary", irregular=true, prefilled=true }); end }); +xx---xx]], contents = function(m) des.region({ region={3,3,3,3}, type="ordinary", irregular=true, filled=1 }); end }); end, -- Circular, medium @@ -348,7 +359,7 @@ x--...--x |.......| --.....-- x--...--x -xx-----xx]], contents = function(m) des.region({ region={4,4,4,4}, type="ordinary", irregular=true, prefilled=true }); end }); +xx-----xx]], contents = function(m) des.region({ region={4,4,4,4}, type="ordinary", irregular=true, filled=1 }); end }); end, -- Circular, big @@ -364,7 +375,7 @@ x-.......-x --.......-- x-.......-x x---...---x -xxx-----xxx]], contents = function(m) des.region({ region={5,5,5,5}, type="ordinary", irregular=true, prefilled=true }); end }); +xxx-----xxx]], contents = function(m) des.region({ region={5,5,5,5}, type="ordinary", irregular=true, filled=1 }); end }); end, -- T-shaped @@ -377,7 +388,7 @@ xxx|...|xxx |.........| |.........| |.........| ------------]], contents = function(m) des.region({ region={5,5,5,5}, type="ordinary", irregular=true, prefilled=true }); end }); +-----------]], contents = function(m) des.region({ region={5,5,5,5}, type="ordinary", irregular=true, filled=1 }); end }); end, -- T-shaped, rot 1 @@ -393,7 +404,7 @@ xxx|...|xxx |...---- |...|xxx |...|xxx ------xxx]], contents = function(m) des.region({ region={2,2,2,2}, type="ordinary", irregular=true, prefilled=true }); end }); +-----xxx]], contents = function(m) des.region({ region={2,2,2,2}, type="ordinary", irregular=true, filled=1 }); end }); end, -- T-shaped, rot 2 @@ -406,7 +417,7 @@ xxx|...|xxx ----...---- xxx|...|xxx xxx|...|xxx -xxx-----xxx]], contents = function(m) des.region({ region={2,2,2,2}, type="ordinary", irregular=true, prefilled=true }); end }); +xxx-----xxx]], contents = function(m) des.region({ region={2,2,2,2}, type="ordinary", irregular=true, filled=1 }); end }); end, -- T-shaped, rot 3 @@ -422,7 +433,7 @@ xxx|...| ----...| xxx|...| xxx|...| -xxx-----]], contents = function(m) des.region({ region={5,5,5,5}, type="ordinary", irregular=true, prefilled=true }); end }); +xxx-----]], contents = function(m) des.region({ region={5,5,5,5}, type="ordinary", irregular=true, filled=1 }); end }); end, -- S-shaped @@ -438,7 +449,7 @@ xxx-----]], contents = function(m) des.region({ region={5,5,5,5}, type="ordinary ----...| xxx|...| xxx|...| -xxx-----]], contents = function(m) des.region({ region={2,2,2,2}, type="ordinary", irregular=true, prefilled=true }); end }); +xxx-----]], contents = function(m) des.region({ region={2,2,2,2}, type="ordinary", irregular=true, filled=1 }); end }); end, -- S-shaped, rot 1 @@ -451,7 +462,7 @@ xxx|......| |......---- |......|xxx |......|xxx ---------xxx]], contents = function(m) des.region({ region={5,5,5,5}, type="ordinary", irregular=true, prefilled=true }); end }); +--------xxx]], contents = function(m) des.region({ region={5,5,5,5}, type="ordinary", irregular=true, filled=1 }); end }); end, -- Z-shaped @@ -467,7 +478,7 @@ xxx|...| |...---- |...|xxx |...|xxx ------xxx]], contents = function(m) des.region({ region={5,5,5,5}, type="ordinary", irregular=true, prefilled=true }); end }); +-----xxx]], contents = function(m) des.region({ region={5,5,5,5}, type="ordinary", irregular=true, filled=1 }); end }); end, -- Z-shaped, rot 1 @@ -480,7 +491,7 @@ xxx|...| ----......| xxx|......| xxx|......| -xxx--------]], contents = function(m) des.region({ region={2,2,2,2}, type="ordinary", irregular=true, prefilled=true }); end }); +xxx--------]], contents = function(m) des.region({ region={2,2,2,2}, type="ordinary", irregular=true, filled=1 }); end }); end, -- Cross @@ -496,7 +507,7 @@ xxx|...|xxx ----...---- xxx|...|xxx xxx|...|xxx -xxx-----xxx]], contents = function(m) des.region({ region={6,6,6,6}, type="ordinary", irregular=true, prefilled=true }); end }); +xxx-----xxx]], contents = function(m) des.region({ region={6,6,6,6}, type="ordinary", irregular=true, filled=1 }); end }); end, -- Four-leaf clover @@ -512,7 +523,7 @@ xx|.....|xx |.........| |...---...| |...|x|...| ------x-----]], contents = function(m) des.region({ region={6,6,6,6}, type="ordinary", irregular=true, prefilled=true }); end }); +-----x-----]], contents = function(m) des.region({ region={6,6,6,6}, type="ordinary", irregular=true, filled=1 }); end }); end, -- Water-surrounded vault @@ -523,7 +534,7 @@ xx|.....|xx }|..|} }|..|} }----} -}}}}}}]], contents = function(m) des.region({ region={3,3,3,3}, type="themed", irregular=true, prefilled=false, 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" }; des.object("chest", 2, 2); des.object("chest", 3, 2); @@ -534,38 +545,101 @@ xx|.....|xx end }); end, + -- 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 + -- 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" + end + end + p = placements[d(#placements)] + des.room({ type=ltype, x=p["lx"], y=p["ly"], w=3, h=3, filled=1, joined=0, + 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=0, + contents = function() + des.door({ state=shopdoorstate(), wall=p["rwall"] }) + end + }); + end + }); + end + }, + }; -local total_frequency = 0; -for i = 1, #themerooms do - local t = type(themerooms[i]); +function is_eligible(room) + local t = type(room); + local diff = nh.level_difficulty(); if (t == "table") then - total_frequency = total_frequency + themerooms[i].frequency; + if (room.mindiff ~= nil and diff < room.mindiff) then + return false + elseif (room.maxdiff ~= nil and diff > room.maxdiff) then + return false + end elseif (t == "function") then - total_frequency = total_frequency + 1; + -- functions currently have no constraints end -end - -if (total_frequency == 0) then - error("Theme rooms total_frequency == 0"); + return true end function themerooms_generate() - local pick = nh.rn2(total_frequency); + local pick = 1; + local total_frequency = 0; for i = 1, #themerooms do - local t = type(themerooms[i]); - if (t == "table") then - pick = pick - themerooms[i].frequency; - if (pick < 0) then - themerooms[i].contents(); - return; + -- 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]) then + local this_frequency; + if (type(themerooms[i]) == "table" and themerooms[i].frequency ~= nil) then + this_frequency = themerooms[i].frequency; + else + this_frequency = 1; end - elseif (t == "function") then - pick = pick - 1; - if (pick < 0) then - themerooms[i](); - return; + 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 + pick = i; end end end + + local t = type(themerooms[pick]); + if (t == "table") then + themerooms[pick].contents(); + elseif (t == "function") then + themerooms[pick](); + end end diff --git a/dat/tower1.lua b/dat/tower1.lua index dcd84f1f6..a5ee95f55 100644 --- a/dat/tower1.lua +++ b/dat/tower1.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 tower.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ +-- NetHack 3.7 tower.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- NetHack may be freely redistributed. See license for details. -- diff --git a/dat/tower2.lua b/dat/tower2.lua index 0376ec51c..793257844 100644 --- a/dat/tower2.lua +++ b/dat/tower2.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 tower.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ +-- NetHack 3.7 tower.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- NetHack may be freely redistributed. See license for details. -- diff --git a/dat/tower3.lua b/dat/tower3.lua index 345c5a9c2..6a601908a 100644 --- a/dat/tower3.lua +++ b/dat/tower3.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 tower.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ +-- NetHack 3.7 tower.des $NHDT-Date: 1432512784 2015/05/25 00:13:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- NetHack may be freely redistributed. See license for details. -- diff --git a/dat/tribute b/dat/tribute index e1596bc49..67fbd93d8 100644 --- a/dat/tribute +++ b/dat/tribute @@ -1,4 +1,4 @@ -# NetHack 3.6 tribute $NHDT-Date: 1590695417 2020/05/28 19:50:17 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.88 $ +# NetHack 3.7 tribute $NHDT-Date: 1596498255 2020/08/03 23:44:15 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.89 $ # Copyright (c) 2017 by Robert Patrick Rankin # NetHack may be freely redistributed. See license for details. # A tribute introduced in NetHack 3.6.0 to: diff --git a/dat/valley.lua b/dat/valley.lua index adcd4e80f..47f6c44df 100644 --- a/dat/valley.lua +++ b/dat/valley.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 gehennom.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.13 $ +-- NetHack 3.7 gehennom.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.13 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- Copyright (c) 1992 by M. Stephenson and Izchak Miller -- NetHack may be freely redistributed. See license for details. @@ -51,11 +51,11 @@ end -- Dungeon Description -- The shrine to Moloch. -des.region({ region={01,06, 05,14},lit=1,type="temple" }) +des.region({ region={01,06, 05,14},lit=1,type="temple",filled=2 }) -- The Morgues -des.region({ region={19,01, 24,08},lit=0,type="morgue",prefilled=0,irregular=1 }) -des.region({ region={09,14, 16,18},lit=0,type="morgue",prefilled=0,irregular=1 }) -des.region({ region={37,09, 43,14},lit=0,type="morgue",prefilled=0,irregular=1 }) +des.region({ region={19,01, 24,08},lit=0,type="morgue",filled=1,irregular=1 }) +des.region({ region={09,14, 16,18},lit=0,type="morgue",filled=1,irregular=1 }) +des.region({ region={37,09, 43,14},lit=0,type="morgue",filled=1,irregular=1 }) -- Stairs des.stair("down", 01,01) -- Branch location diff --git a/dat/water.lua b/dat/water.lua index fdf6a5586..8b1ba9365 100644 --- a/dat/water.lua +++ b/dat/water.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 endgame.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.13 $ +-- NetHack 3.7 endgame.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.13 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- Copyright (c) 1992,1993 by Izchak Miller, David Cohrs, -- and Timo Hakulinen diff --git a/dat/wizard1.lua b/dat/wizard1.lua index 26dfd5839..2e4a0af79 100644 --- a/dat/wizard1.lua +++ b/dat/wizard1.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 yendor.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ +-- NetHack 3.7 yendor.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- Copyright (c) 1992 by M. Stephenson and Izchak Miller -- NetHack may be freely redistributed. See license for details. @@ -28,12 +28,12 @@ des.levregion({ type="stair-up", region={01,00,79,20}, region_islev=1, exclude={ des.levregion({ type="stair-down", region={01,00,79,20}, region_islev=1, exclude={0,0,28,12} }) des.levregion({ type="branch", region={01,00,79,20}, region_islev=1, exclude={0,0,28,12} }) des.teleport_region({ region={01,00,79,20}, region_islev=1, exclude={0,0,27,12} }) -des.region({ region={12,01, 20,09}, lit=0, type="morgue", prefilled=1, contents=function() +des.region({ region={12,01, 20,09}, lit=0, type="morgue", filled=2, contents=function() local sdwall = { "south", "west", "east" }; des.door({ wall = sdwall[math.random(1, #sdwall)], state = "secret" }); end }) -- another region to constrain monster arrival -des.region({ region={01,01, 10,11}, lit=0, type="ordinary", prefilled=0 }) +des.region({ region={01,01, 10,11}, lit=0, type="ordinary", arrival_room=true }) des.mazewalk(28,05,"east") des.ladder("down", 06,05) -- Non diggable walls diff --git a/dat/wizard2.lua b/dat/wizard2.lua index 9bcd4ab3b..825f2f342 100644 --- a/dat/wizard2.lua +++ b/dat/wizard2.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 yendor.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ +-- NetHack 3.7 yendor.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- Copyright (c) 1992 by M. Stephenson and Izchak Miller -- NetHack may be freely redistributed. See license for details. @@ -26,8 +26,8 @@ des.levregion({ type="stair-down", region={01,00,79,20}, region_islev=1, exclude des.levregion({ type="branch", region={01,00,79,20}, region_islev=1, exclude={0,0,28,12} }) des.teleport_region({ region={01,00,79,20}, region_islev=1, exclude={0,0,27,12} }) -- entire tower in a region, constrains monster migration -des.region({ region={01,01, 26,11}, lit=0, type="ordinary", prefilled=1 }) -des.region({ region={09,03, 17,09}, lit=0, type="zoo", prefilled=0 }) +des.region({ region={01,01, 26,11}, lit=0, type="ordinary", arrival_room=true }) +des.region({ region={09,03, 17,09}, lit=0, type="zoo", filled=1 }) des.door("closed",15,02) des.door("closed",11,10) des.mazewalk(28,05,"east") diff --git a/dat/wizard3.lua b/dat/wizard3.lua index a7b53a340..6c439c190 100644 --- a/dat/wizard3.lua +++ b/dat/wizard3.lua @@ -1,4 +1,4 @@ --- NetHack 3.6 yendor.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ +-- NetHack 3.7 yendor.des $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ -- Copyright (c) 1989 by Jean-Christophe Collet -- Copyright (c) 1992 by M. Stephenson and Izchak Miller -- NetHack may be freely redistributed. See license for details. @@ -27,11 +27,10 @@ des.levregion({ type="branch", region={01,00,79,20}, region_islev=1, exclude={0, des.teleport_region({ region={01,00,79,20}, region_islev=1, exclude={0,0,27,12} }) des.levregion({ region={25,11,25,11}, type="portal", name="fakewiz1" }); des.mazewalk(28,09,"east") -des.region({ region={07,03, 15,11}, lit=0 ,type="morgue",prefilled=1 }) -des.region({ region={17,06, 18,11}, lit=0, type="beehive" }) --- make the entry chamber a real room; it affects monster arrival; --- `unfilled' is a kludge to force an ordinary room to remain a room -des.region({ region={20,06,26,11},lit=0,type="ordinary",prefilled=1, +des.region({ region={07,03, 15,11}, lit=0 ,type="morgue", filled=2 }) +des.region({ region={17,06, 18,11}, lit=0, type="beehive", filled=1 }) +-- make the entry chamber a real room; it affects monster arrival +des.region({ region={20,06,26,11},lit=0,type="ordinary",arrival_room=true, contents = function() local w = "north"; if percent(50) then w = "west" end diff --git a/dat/wizhelp b/dat/wizhelp index bc8a4715c..0237b1a3c 100644 --- a/dat/wizhelp +++ b/dat/wizhelp @@ -13,16 +13,18 @@ Debug-Mode Quick Reference: #lightsources == show mobile light sources #panic == panic test (warning: current game will be terminated) #polyself == polymorph self -#seenv == show seen vectors #stats == show memory statistics #terrain == show current level (more options than in normal play) #timeout == look at timeout queue and hero's timed intrinsics #vanquished == disclose counts of dead monsters sorted in various ways #vision == show vision array #wizborn == show monster birth/death/geno/extinct stats +#wizfliplevel == transpose the current dungeon level #wizintrinsic == set selected intrinsic timeouts #wizmakemap == recreate the current dungeon level -#wizrumorcheck == validate first and last rumor for true and false set +#wizrumorcheck == validate rumor indexing; also show first, second, and last + random engravings, epitaphs, and hallucinatory monsters +#wizseenv == show map locations' seen vectors #wizsmell == smell a monster #wizwhere == show dungeon placement of all special levels #wmode == show wall modes diff --git a/doc/Guidebook.mn b/doc/Guidebook.mn index 855c7974b..451376619 100644 --- a/doc/Guidebook.mn +++ b/doc/Guidebook.mn @@ -1,4 +1,4 @@ -.\" $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.391 $ $NHDT-Date: 1594377460 2020/07/10 10:37:40 $ +.\" $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.410 $ $NHDT-Date: 1608664223 2020/12/22 19:10:23 $ .\" .\" This is an excerpt from the 'roff' man page from the 'groff' package. .\" Guidebook.mn currently does *not* fully adhere to these guidelines. @@ -35,7 +35,7 @@ .ds vr "NetHack 3.7 .ds f0 "\*(vr .ds f1 -.ds f2 "July 9, 2020 +.ds f2 "December 19, 2020 . .\" A note on some special characters: .\" \(lq = left double quote @@ -103,7 +103,7 @@ travel, you see the ancient ruins that mark the entrance to the Mazes of Menace. It is late at night, so you make camp at the entrance and spend the night sleeping under the open skies. In the morning, you gather your gear, eat what may be your last meal outside, and enter the -dungeon... +dungeon.... . .hn 1 What is going on here? @@ -675,7 +675,9 @@ support, the command is also invoked when a mouse-click takes place on a location other than the current position. .lp . Wait or rest, do nothing for one turn. Precede with the \(oqm\(cq prefix -to wait for a turn even next to a hostile monster. +to wait for a turn even next to a hostile monster, if +.op safe_wait +is on. .lp a Apply (use) a tool (pick-axe, key, lamp...). .lp "" @@ -884,7 +886,9 @@ Redraw the screen. Search for secret doors and traps around you. It usually takes several tries to find something. Precede with the \(oqm\(cq prefix to search for a turn -even next to a hostile monster. +even next to a hostile monster, if +.op safe_wait +is on. .lp "" Can also be used to figure out whether there is still a monster at an adjacent \(lqremembered, unseen monster\(rq marker. @@ -965,9 +969,9 @@ the exchange still takes place. Toggle two-weapon combat, if your character can do it. Also available via the \(lq#twoweapon\(rq extended command. .lp "" -(In versions prior to 3.6 this was the command to switch from normal +(In versions prior to 3.6 this keystroke ran the command to switch from normal play to \(lqexplore mode\(rq, also known as \(lqdiscovery mode\(rq, -which has now been moved to \(lq#exploremode\(rq.) +which has now been moved to \(lq#exploremode\(rq and M-X.) .lp \(haX Display basic information about your character. .lp "" @@ -1001,6 +1005,7 @@ Suspend the game .\" .UX: print "UNIX" now and a trademark footnote at bottom of current page; .\" 2nd arg (literal '(') _precedes_ it, 1st arg (quoted string) follows it .UX " versions with job control only)." ( +See \(lq#suspend\(rq below for more details. .lp : Look at what is here. .lp ; @@ -1031,7 +1036,7 @@ Tell what equipment you are using. Combines the preceding five type-specific commands into one. .lp $ -Count your gold pieces. +Report the gold you're carrying, possibly shop credit and/or debt too. .lp + List the spells you know. .lp "" @@ -1050,10 +1055,29 @@ be added to the end of the list rather than be inserted into the sorted ordering.) .lp \\\\ Show what types of objects have been discovered. +.lp "" +May be preceded by \(oq\f(CRm\fP\(cq to select preferred display order. .lp \` Show discovered types for one class of objects. +.lp "" +May be preceded by \(oq\f(CRm\fP\(cq to select preferred display order. .lp ! Escape to a shell. +See \(lq#shell\(rq below for more details. +.lp Del +Show map without obstructions. +You can view the explored portion of the current level's map without +monsters; without monsters and objects; or without monsters, objects, +and traps. +.lp "" +The key is also shown as on some keyboards or +on others. +It is sometimes displayed as \(ha? even though that is not an actual +control character. +.lp "" +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 \(lq#terrain\(rq instead. .lp # Perform an extended command. .lp "" @@ -1179,7 +1203,8 @@ Advance or check weapon and spell skills. Autocompletes. Default key is \(oqM-e\(cq. .lp #exploremode -Enter the explore mode. +Switch from normal play to non-scoring explore mode. +Default key is \(oqM-X\(cq. .lp "" Requires confirmation; default response is \f(CRn\fP (no). To really switch to explore mode, respond with \f(CRy\fP. @@ -1202,7 +1227,15 @@ Default key is \(oq?\(cq, and also \(oqh\(cq if .op number_pad is on. .lp #herecmdmenu -Show a menu of possible actions in your current location. +Show a menu of possible actions directed at your current location. +The menu is limited to a subset of the likeliest actions, not an +exhaustive set of all possibilities. +Autocompletes. +.lp "" +If mouse support is enabled and the +.op herecmd_menu +option is On, clicking on the hero (or steed when mounted) will +execute this command. .lp "#history " Show long version and game history. Default key is \(oqV\(cq. @@ -1229,10 +1262,16 @@ Default key is \(oq\(haD\(cq, and \(oqk\(cq if is on. .lp "#known " Show what object types have been discovered. -Default key is \(oq\\\(cq. +Default key is \(oq\f(CR\\\fP\(cq. +.lp "" +The \(oq\f(CRm\fP\(cq prefix allows assigning a new value to the +.op sortdiscoveries +option to control the order in which the discoveries are displayed. .lp #knownclass Show discovered types for one class of objects. -Default key is \(oq\`\(cq. +Default key is \(oq\f(CR\`\fP\(cq. +.lp "" +The \(oq\f(CRm\fP\(cq prefix operates the same as for \(lq#known\(rq. .lp #levelchange Change your experience level. Autocompletes. @@ -1381,31 +1420,37 @@ Default key is \(oq\(dq\(cq. \" double quote .lp #seearmor Show the armor currently worn. Default key is \(oq[\(cq. -.lp "#seegold " -Count your gold. -Default key is \(oq$\(cq. -.lp "#seenv " -Show seen vectors. -Autocompletes. -Debug mode only. .lp #seerings Show the ring(s) currently worn. Default key is \(oq=\(cq. -.lp #seespells -List and reorder known spells. -Default key is \(oq+\(cq. .lp #seetools Show the tools currently in use. Default key is \(oq(\(cq. -.lp "#seetrap " -Show the type of an adjacent trap. -Default key is \(oq\(ha\(cq. \" 'hat' (circumflex character) .lp #seeweapon Show the weapon currently wielded. Default key is \(oq)\(cq. .lp "#shell " -Do a shell escape. +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 +configuration file. +Use the shell command \(oq\f(CRexit\fP\(cq to return to the game. Default key is \(oq!\(cq. +.lp "#showgold" +Report the gold in your inventory and if you are inside a shop, +report any credit or debt you have in that shop. +Does not report on any gold inside containers you're carrying. +Default key is \(oq$\(cq. +.lp #showspells +List and reorder known spells. +Default key is \(oq+\(cq. +.lp "#showtrap" +Describe an adjacent trap, possibly covered by objects or a monster. +To be eligible, the trap must already be discovered. +(The \(lq#terrain\(rq command can display your map with all objects and +monsters temporarily removed, making it possible to see all discovered +traps.) +Default key is \(oq\(ha\(cq. \" 'hat' (circumflex character) .lp "#sit " Sit down. Autocompletes. @@ -1415,7 +1460,12 @@ Show memory usage statistics. Autocompletes. Debug mode only. .lp "#suspend " -Suspend the game. +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 \fItty\fP and \fIcurses\fP interfaces on +.UX \. \" yields "UNIX." +Use the shell command \(oq\f(CRfg\fP\(cq to return to the game. Default key is \(oq\(haZ\(cq. .lp "#swap " Swap wielded and secondary weapons. @@ -1430,10 +1480,27 @@ Default key is \(oqA\(cq. Teleport around the level. Default key is \(oq\(haT\(cq. .lp "#terrain " -Show bare map without displaying monsters, objects, or traps. +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. +.lp "" +In explore mode, you can choose to view the full map rather than just +its explored portion. +In debug mode there are additional choices. +.lp "" Autocompletes. +Default key is \(oq\(cq or \(oq\(cq (see \fIDel\fP above). .lp #therecmdmenu -Show a menu of possible actions in a location next to you. +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. +.\"--invoking it by mouse seems to be broken +.\" .lp "" +.\" If mouse support is enabled and the +.\" .op herecmd_menu +.\" option is On, clicking on an adjacent location will execute this command. .lp "#throw " Throw something. Default key is \(oqt\(cq. @@ -1485,10 +1552,17 @@ Autocompletes. Debug mode only. .lp "#version " Print compile time options for this version of NetHack. +.lp "" +The second paragraph lists the user interface(s) that are included. +If there are more than one, you can use the +.op windowtype +option in your run-time configuration file to select the one you want. +.lp "" Autocompletes. Default key is \(oqM-v\(cq. .lp #versionshort -Show version string. +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 \(oqv\(cq. .lp "#vision " Show vision array. @@ -1562,6 +1636,10 @@ and hallucinatory monsters. .lp "" Autocompletes. Debug mode only. +.lp #wizseenv +Show map locations' seen vectors. +Autocompletes. +Debug mode only. .lp #wizsmell Smell monster. Autocompletes. @@ -1591,16 +1669,27 @@ with another key, modifies it by setting the \(lqmeta\(rq [8th, or \(lqhigh\(rq] bit), you can invoke many extended commands by meta-ing the first letter of the command. .pg -In \fIWindows\fP, \fIOS/2\fP, \fIPC\fP and \fIST\fP \fINetHack\fP, -the \(lqAlt\(rq key can be used in this fashion; -on the \fIAmiga\fP, set the -.op altmeta -option to get this behavior. +On \fIWindows\fP and \fIMS-DOS\fP, +the \(lqAlt\(rq key can be used in this fashion. +.\" On the \fIAmiga\fP, set the +.\" .op altmeta +.\" option to get this behavior. On other systems, if typing \(lqAlt\(rq plus another key transmits a two character sequence consisting of an \fBEscape\fP followed by the other key, you may set the .op altmeta option to have NetHack combine them into meta+key. +(This combining action only takes place when NetHack is expecting a +command to execute, not when accepting input to name something or to +make a wish.) +.pg +Unlike control characters, where \(hax and \(haX 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 used for +another command, so the three key combination meta+shift+letter is needed. +.BR 1 +. .lp M-? #? (not supported by all platforms) .lp M-2 @@ -1655,6 +1744,8 @@ option is enabled) #version .lp M-w #wipe +.lp M-X +#exploremode .lp "" .pg If the @@ -1813,7 +1904,7 @@ 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. +with a \fIscroll of earth\fP. However, doing such things will lower your luck without any specific message given about that. See the \fIConduct\fP section for information about getting feedback for @@ -1876,10 +1967,12 @@ 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. .pg -Shopkeepers sometimes 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 shop where -it was obtained; other shopkeepers won't honor it. (If you happen to +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 shop +where it was obtained; other shopkeepers won't honor it. +(If you happen to find a \(lqcredit card\(rq in the dungeon, don't bother trying to use it in shops; shopkeepers will not accept it.) .pg @@ -1901,7 +1994,7 @@ 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 were outside the shop. .lp * 2 -While the shopkeeper watches you like a hawk, he will generally ignore +While the shopkeeper watches you like a hawk, he or she will generally ignore any other customers. .lp * 2 If a shop is \(lqclosed for inventory,\(rq it will not open of its own accord. @@ -1985,6 +2078,23 @@ The .op 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). +.hn 2 +Rogue level +.pg +One dungeon level (occurring in mid to late teens of the main dungeon) +is a tribute to the ancestor game \fIhack\fP's inspiration \fIrogue\fP. +.pg +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 \f(CR*\fP rather than \f(CR$\fP +and stairs are shown as \f(CR%\fP rather than \f(CR<\fP and \f(CR>\fP. +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 radius around your character. +And monsters represented by lower-case letters aren't randomly +generated on the rogue level. +.pg +The slight strangeness of this level is a feature, not a bug.... . .hn 1 Monsters @@ -2140,8 +2250,8 @@ to discard some of what you're carrying or collapse under its weight. .pg NetHack will tell you how badly you have loaded yourself. If you are encumbered, one of the conditions -\(lq\fIBurdened\fP\(rq, \(lq\fIStressed\fP\(rq, \(lq\fIStrained\fP\(rq, -\(lq\fIOvertaxed\fP\(rq or \(lq\fIOverloaded\fP\(rq will be +\f(CRBurdened\fP, \f(CRStressed\fP, \f(CRStrained\fP, +\f(CROvertaxed\fP, or \f(CROverloaded\fP will be shown on the bottom line status display. .pg When you pick up an object, it is assigned an inventory letter. Many @@ -2177,9 +2287,10 @@ 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. .pg -Objects can also be blessed. Blessed items usually work better or -more beneficially than normal uncursed items. For example, a blessed -weapon will do more damage against demons. +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. .pg Objects which are neither cursed nor blessed are referred to as uncursed. They could just as easily have been described as unblessed, but the @@ -2189,20 +2300,28 @@ that what you will. .pg 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 +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. .pg An item with unknown status will be reported in your inventory with no prefix. An item which you know the state of will be distinguished in your inventory -by the presence of the word \(lqcursed\(rq, \(lquncursed\(rq or -\(lqblessed\(rq in the description of the item. -In some cases \(lquncursed\(rq will be omitted as being redundant when +by the presence of the word \f(CRcursed\fP, \f(CRuncursed\fP, or +\f(CRblessed\fP in the description of the item. +In some cases \f(CRuncursed\fP will be omitted as being redundant when enough other information is displayed. The .op implicit_uncursed -option can be used to control this; toggle it off to have \(lquncursed\(rq +option can be used to control this; toggle it off to have \f(CRuncursed\fP be displayed even when that can be deduced from other attributes. +.pg +Sometimes the bless or curse state of objects is referred to as their +\(lq\f(CRBUC\fP\(rq attribute, for Blessed, Uncursed, or Cursed state, +or \(lq\f(CRBUCX\fP\(rq for Blessed, Uncursed, Cursed, or unknown. +(The term \fIbeatitude\fP is occasionally used as well.) .hn 2 Weapons (\(oq)\(cq) .pg @@ -2426,7 +2545,7 @@ NetHack. Here is a list of the armor class values provided by suits of armor: . .\" Replace the old one suit per line table with a more condensed one. -.\" AC4 and AC7 have been split into two lines to accomodate plain text +.\" AC4 and AC7 have been split into two lines to accommodate plain text .\" output (Guidebook.txt). AC4 needs it to reduce overall width; after .\" that, AC7 became the longest and the table looks better by shortening .\" it to get the second column (number) closer to the text on most lines. @@ -3119,24 +3238,28 @@ the configuration file for you using the default template file. .pg On MS-DOS, it is \(lqdefaults.nh\(rq in the same folder as nethack.exe. .pg -Any line in the configuration file starting with \(oq#\(cq is treated -as a comment. +Any line in the configuration file starting with \(oq\f(CR#\fP\(cq is treated +as a comment and ignored. Empty lines are ignored. .pg -Any line beginning with \(oq[\(cq and ending in \(oq]\(cq is considered -a section marker. +Any line beginning with \(oq\f(CR[\fP\(cq and ending in \(oq\f(CR]\fP\(cq +is a section marker (the closing \(oq\f(CR]\fP\(cq can be followed +by whitespace and then an arbitrary comment beginning with \(oq\f(CR#\fP\(cq). The text between the square brackets is the section name. -Lines after a section marker belong to that section, and are -ignored unless a CHOOSE statement was used to select that section. -Section names are case insensitive. +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 section. .pg -You can use different configuration statements in the file, some +You can use different configuration directives in the file, some of which can be used multiple times. -In general, the statements are +In general, the directives are written in capital letters, followed by an equals sign, followed by -settings particular to that statement. +settings particular to that directive. .pg -Here is a list of allowed statements: +Here is a list of allowed directives: .lp OPTIONS There are two types of options, boolean and compound options. Boolean options toggle a setting on or off, while compound options @@ -3144,8 +3267,8 @@ take more diverse values. Prefix a boolean option with \(lqno\(rq or \(oq!\(cq 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 statements, and multiple options -separated by commas in a single OPTIONS statement. +You can specify multiple OPTIONS directives, and multiple options +separated by commas in a single OPTIONS directive. (Comma separated options are processed from right to left.) .lp "" Example: @@ -3209,7 +3332,8 @@ Example: .ed .lp CHOOSE Chooses at random one of the comma-separated parameters as an active -section name. Lines in other sections are ignored. +section name. +Lines in other sections are ignored. .lp "" Example: .sd @@ -3220,8 +3344,14 @@ CHOOSE=char A,char B OPTIONS=role:arc,race:dwa,align:law,gender:fem [char B] OPTIONS=role:wiz,race:elf,align:cha,gender:mal +[] #end of CHOOSE +OPTIONS=!rest_on_space .ft \" revert to previous font .ed +.lp "" +If \f(CR[]\fP is present, the preceding section is closed and no new +section begins; whatever follows will be common to all sections. +Otherwise the last section extends to the end of the options file. .lp MENUCOLOR Highlight menu lines with different colors. See the \(lqConfiguring Menu Colors\(rq section. @@ -3331,10 +3461,10 @@ to that shell), or the pair of commands in \fIsh\fP, \fIksh\fP, or \fIbash\fP. .pg The NETHACKOPTIONS value is effectively the same as a single OPTIONS -statement in a configuration file. +directive in a configuration file. The \(lqOPTIONS=\(rq prefix is implied and comma separated options are processed from right to left. -Other types of configuration statements such as BIND or MSGTYPE are +Other types of configuration directives such as BIND or MSGTYPE are not allowed. .pg Instead of a comma-separated list of options, @@ -3965,6 +4095,9 @@ Persistent. .lp safe_pet Prevent you from (knowingly) attacking your pets (default on). Persistent. +.lp safe_wait +Prevents you from waiting or searching when next to a hostile monster +(default on). Persistent. .lp sanity_check Evaluate monsters, objects, and map prior to each turn (default off). Debug mode only. @@ -3986,19 +4119,47 @@ Persistent. Show your approximate accumulated score on bottom line (default off). Persistent. .lp "silent " -Suppress terminal beeps (default on). Persistent. +Suppress terminal beeps (default on). +Persistent. +.lp sortdiscoveries +Controls the sorting behavior for the output of the \(oq\f(CR\\\fP\(cq +and \(oq\f(CR\`\fP\(cq commands. +Persistent. +.lp "" +The possible values are: +.PS o +.PL o +list object types by class, in discovery order within each class; +default; +.PL s +list object types by +.op 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; +.PL c +list by class, alphabetically within each class; +.PL a +list alphabetically across all classes. +.PE +Can be interactively set via the \(oq\f(CRO\fP\(cq command or via using +the \(oq\f(CRm\fP\(cq prefix before the \(oq\f(CR\\\fP\(cq +or \(oq\f(CR\`\fP\(cq command. .lp sortloot Controls the sorting behavior of the pickup lists for inventory and #loot commands and some others. Persistent. +.lp "" The possible values are: -.PS full +.PS none \" note: with proportional font, "none" is wider than "full" or "loot" .PL full always sort the lists; .PL loot only sort the lists that don't use inventory letters, like with the #loot and pickup commands; .PL none -show lists the traditional way without sorting. +show lists the traditional way without sorting; +default. .PE .lp sortpack Sort the pack contents by type when displaying inventory (default on). @@ -4143,7 +4304,19 @@ Where to align or place the message window (top, bottom, left, or right) .lp align_status Where to align or place the status window (top, bottom, left, or right). .lp ascii_map -If NetHack can, it should display an ascii character map if it can. +.hw DECgraphics IBMgraphics \" don't hyphenate these +If NetHack can, it should display the map using simple +characters (letters and punctuation) rather than \fItiles\fP graphics. +In some cases, characters can be augmented with line-drawing symbols; +use the +.op symset +option to select a symbol set such as \fIDECgraphics\fP +or \fIIBMgraphics\fP if your display supports them. +Setting +.op ascii_map +to \fITrue\fP forces +.op tiled_map +to be \fIFalse\fP. .lp color If NetHack can, it should display color if it can for different monsters, objects, and dungeon features. @@ -4212,8 +4385,29 @@ If NetHack can, it should display an opening splash screen when it starts up (default yes). .lp statuslines Number of lines for traditional below-the-map status display. -Acceptable values are 2 and 3 (default is 2). -Curses and tty interfaces only. +Acceptable values are \f(CR2\fP and \f(CR3\fP (default is \f(CR2\fP). +.lp "" +When set to \f(CR3\fP, the \f(CRtty\fP 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 \(oqO\(cq +command. +.lp "" +The \f(CRcurses\fP interface does likewise if the +.op align_status +option is set to \fItop\fP or \fIbottom\fP but ignores +.op statuslines +when set to \fIleft\fP or \fIright\fP. +.lp "" +The \f(CRQt\fP interface already displays more than 3 lines for status +so uses the +.op statuslines +value differently. +A value of \f(CR3\fP renders status in the \f(CRQt\fP interface's +original format, with the status window spread out vertically. +A value of \f(CR2\fP makes status be slightly condensed, moving some +fields to different lines to eliminate one whole line, reducing the +height needed. .lp "term_cols\ \ \fIand\fP" .lp term_rows Curses interface only. @@ -4221,14 +4415,21 @@ 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. -.lp tiled_map -If NetHack can, it should display a tiled map if it can. .lp tile_file Specify the name of an alternative tile file to override the default. .lp tile_height Specify the preferred height of each tile in a tile capable port. .lp tile_width Specify the preferred width of each tile in a tile capable port +.lp tiled_map +If NetHack can, it should display the map using \fItiles\fP graphics +rather than simple characters (letters and punctuation, possibly +augmented by line-drawing symbols). +Setting +.op tiled_map +to \fITrue\fP forces +.op ascii_map +to be \fIFalse\fP. .lp use_darkgray Use bold black instead of blue for black glyphs (TTY only). .lp use_inverse @@ -4327,7 +4528,7 @@ May be used to alter the value of keystrokes that the operating system returns to NetHack to help compensate 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 statements in the configuration file +You can use multiple subkeyvalue assignments in the configuration file if needed. Cannot be set with the \(oqO\(cq command. .lp video @@ -4599,10 +4800,20 @@ Prefix key to run towards a direction. With .op number_pad only. -Default is \(oq5\(cq. +.lp "" +Default is \(oq5\(cq when number_pad is set to 1 or 3, +otherwise \(oqM-5\(cq when it is set to 2 or 4. .lp rush Prefix key to rush towards a direction. Default is \(oqg\(cq. +.lp rush.numpad +Prefix key to rush towards a direction. +With +.op number_pad +only. +.lp "" +Default is \(oqM-5\(cq when number_pad is set to 1 or 3, +otherwise \(oq5\(cq when it is set to 2 or 4. .hn 2 Configuring Message Types .pg @@ -5428,11 +5639,19 @@ Main events in the course of the game development are described below: \fBJay Fenlason\fP wrote the original Hack, with help from \fBKenny Woodland\fP, \fBMike Thome\fP, and \fBJon Payne\fP. .pg -\fBAndries Brouwer\fP did a major re-write, transforming Hack into a -very different game, and published (at least) three versions (1.0.1, -1.0.2, and 1.0.3) for +\fBAndries Brouwer\fP did a major re-write while at +Stichting Mathematisch Centrum (now Centrum Wiskunde & Informatica), +transforming Hack into a very different game. +He published the Hack source code for use on .UX -machines to the Usenet. +systems by posting that to Usenet +newsgroup \fInet.sources\fP (later renamed \fIcomp.sources\fP) +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 \fInet.games.hack\fP (later +renamed \fIrec.games.hack\fP, eventually replaced +by \fIrec.games.roguelike.nethack\fP) +was created for discussing it. .pg \fBDon G. Kneller\fP ported Hack 1.0.3 to Microsoft C and MS-DOS, producing PC HACK 1.01e, added support for DEC Rainbow graphics in version 1.03g, and went @@ -5447,6 +5666,9 @@ 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 \fIftp\fP and \fIuucp\fP after expiring from the newsgroup. .pg Later, Mike coordinated a major re-write of the game, heading a team which included \fBKen Arromdee\fP, \fBJean-Christophe Collet\fP, diff --git a/doc/Guidebook.tex b/doc/Guidebook.tex index 429fdbb4c..e55152a06 100644 --- a/doc/Guidebook.tex +++ b/doc/Guidebook.tex @@ -1,5 +1,5 @@ \documentstyle[titlepage,longtable]{article} -% NetHack 3.6 Guidebook.tex $NHDT-Date: 1431192762 2015/12/16 17:32:42 $ $NHDT-Branch: master $:$NHDT-Revision: 1.60 $ */ +% NetHack 3.7 Guidebook.tex $NHDT-Date: 1431192762 2015/12/16 17:32:42 $ $NHDT-Branch: master $:$NHDT-Revision: 1.60 $ */ %+% we're still limping along in LaTeX 2.09 compatibility mode %-%\documentclass{article} %-%\usepackage{hyperref} % before longtable @@ -45,7 +45,7 @@ %.au \author{Original version - Eric S. Raymond\\ (Edited and expanded for 3.7 by Mike Stephenson and others)} -\date{July 9, 2020} +\date{December 19, 2020} \maketitle @@ -769,7 +769,8 @@ location other than the current position. %.lp \item[\tb{.}] Wait or rest, do nothing for one turn. Precede with the `{\tt m}' prefix -to wait for a turn even next to a hostile monster. +to wait for a turn even next to a hostile monster, if {\it safe\verb+_+wait\/} +is on. %.lp \item[\tb{a}] Apply (use) a tool (pick-axe, key, lamp \ldots).\\ @@ -968,7 +969,8 @@ Redraw the screen. Search for secret doors and traps around you. It usually takes several tries to find something. Precede with the `{\tt m}' prefix to wait for a turn -even next to a hostile monster.\\ +even next to a hostile monster, if {\it safe\verb+_+wait\/} +is on.\\ %.lp "" Can also be used to figure out whether there is still a monster at an adjacent ``remembered, unseen monster'' marker. @@ -1057,9 +1059,9 @@ the exchange still takes place. Toggle two-weapon combat, if your character can do it. Also available via the ``{\tt \#twoweapon}'' extended command.\\ %.lp "" -(In versions prior to 3.6 this was the command to switch from normal +(In versions prior to 3.6 this keystroke ran the command to switch from normal play to ``explore mode'', also known as ``discovery mode'', which has now -been moved to ``{\tt \#exploremode}''.) +been moved to ``{\tt \#exploremode}'' and M-X.) %.lp \item[\tb{\^{}X}] Display basic information about your character.\\ @@ -1093,6 +1095,7 @@ Zap (cast) a spell.\\ %.lp \item[\tb{\^{}Z}] Suspend the game (UNIX versions with job control only). +See ``\#suspend'' below for more details. %.lp \item[\tb{:}] Look at what is here. @@ -1133,7 +1136,7 @@ Combines the preceding five type-specific commands into one. %.lp \item[\tb{\$}] -Count your gold pieces. +Report the gold you're carrying, possibly shop credit and/or debt too. %.lp \item[\tb{+}] List the spells you know.\\ @@ -1151,12 +1154,34 @@ ordering.) %.lp \item[\tb{$\backslash$}] Show what types of objects have been discovered. +\\ +%.lp "" +May be preceded by `{\tt m}' to select preferred display order. %.lp \item[\tb{\`}] Show discovered types for one class of objects. +\\ +.lp "" +May be preceded by `{\tt m}' to select preferred display order. %.lp \item[\tb{!}] Escape to a shell. +See ``\#shell'' below for more details. +%.lp +\item[\tb{Del}] +Show map without obstructions. +You can view the explored portion of the current level's map without +monsters; without monsters and objects; or without monsters, objects, +and traps.\\ +%.lp "" +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.\\ +%.lp "" +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. %.lp \item[\tb{\#}] Perform an extended command.\\ @@ -1263,7 +1288,8 @@ Advance or check weapon and spell skills. Autocompletes. Default key is `{\tt M-e}'. %.lp \item[\tb{\#exploremode}] -Enter the explore mode.\\ +Switch from normal play to non-scoring explore mode. +Default key is `{\tt M-X}'.\\ %.lp "" Requires confirmation; default response is `{\tt n}' (no). To really switch to explore mode, respond with `{\tt y}'. @@ -1286,7 +1312,14 @@ Default key is `{\tt ?}', and also `{\tt h}' if {\it number\verb+_+pad\/} is on. %.lp \item[\tb{\#herecmdmenu}] -Show a menu of possible actions in your current location. +Show a menu of possible actions directed at your current location. +The menu is limited to a subset of the likeliest actions, not an +exhaustive set of all possibilities. +Autocompletes.\\ +%.lp "" +If mouse support is enabled and the {\it herecmd\verb+_+menu\/} +option is On, clicking on the hero (or steed when mounted) will +execute this command. %.lp \item[\tb{\#history}] Show long version and game history. Default key is `{\tt V}'. @@ -1313,10 +1346,18 @@ and also `{\tt k}' if {\it number\verb+_+pad\/} is on. \item[\tb{\#known}] Show what object types have been discovered. Default key is `{\tt $\backslash$}'. +\\ +%.lp "" +The `{\tt m}' prefix allows assigning a new value to the +{\it sortdiscoveries\/} +option to control the order in which the discoveries are displayed. %.lp \item[\tb{\#knownclass}] Show discovered types for one class of objects. Default key is `{\tt `}'. +\\ +%.lp "" +The `{\tt m}' prefix operates the same as for \(lq#known\(rq. %.lp \item[\tb{\#levelchange}] Change your experience level. @@ -1467,31 +1508,40 @@ Show the amulet currently worn. Default key is `{\tt "}'. \item[\tb{\#seearmor}] Show the armor currently worn. Default key is `{\tt [}'. %.lp -\item[\tb{\#seegold}] -Count your gold. Default key is `{\tt \$}'. -%.lp -\item[\tb{\#seenv}] -Show seen vectors. -Autocompletes. -Debug mode only. -%.lp \item[\tb{\#seerings}] Show the ring(s) currently worn. Default key is `{\tt =}'. %.lp -\item[\tb{\#seespells}] -List and reorder known spells. Default key is `{\tt +}'. -%.lp \item[\tb{\#seetools}] Show the tools currently in use. Default key is `{\tt (}'. %.lp -\item[\tb{\#seetrap}] -Show the type of an adjacent trap. Default key is `{\tt \^{}}'. -%.lp \item[\tb{\#seeweapon}] Show the weapon currently wielded. Default key is `{\tt )}'. %.lp \item[\tb{\#shell}] -Do a shell escape. Default key is `{\tt !}'. +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 +configuration file. +Use the shell command `{\tt exit}' to return to the game. +Default key is `{\tt !}'. +%.lp +\item[\tb{\#showgold}] +Report the gold in your inventory and if you are inside a shop, +report any credit or debt you have in that shop. +Does not report on any gold inside containers you're carrying. +Default key is `{\tt \$}'. +%.lp +\item[\tb{\#showspells}] +List and reorder known spells. +Default key is `{\tt +}'. +%.lp +\item[\tb{\#showtrap}] +Describe an adjacent trap, possibly covered by objects or a monster. +To be eligible, the trap must already be discovered. +(The ``{\tt \#terrain}'' command can display your map with all objects and +monsters temporarily removed, making it possible to see all discovered +traps.) +Default key is `{\tt \^{}}'. %.lp \item[\tb{\#sit}] Sit down. Autocompletes. Default key is `{\tt M-s}'. @@ -1502,7 +1552,14 @@ Autocompletes. Debug mode only. %.lp \item[\tb{\#suspend}] -Suspend the game. Default key is `{\tt \^{}Z}'. +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 {\it tty\/} and {\it curses\/} interfaces on +%.UX \. \" yields "UNIX." +UNIX. +Use the shell command `{\tt fg}' to return to the game. +Default key is `{\tt \^{}Z}'. %.lp \item[\tb{\#swap}] Swap wielded and secondary weapons. Default key is `{\tt x}'. @@ -1517,11 +1574,28 @@ Remove all armor. Default key is `{\tt A}'. Teleport around the level. Default key is `{\tt \^{}T}'. %.lp \item[\tb{\#terrain}] -Show bare map without displaying monsters, objects, or traps. +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.\\ +%.lp "" +In explore mode, you can choose to view the full map rather than just +its explored portion. +In debug mode there are additional choices.\\ +%.lp "" Autocompletes. +Default key is `' or `' (see {\it Del\/} above). %.lp \item[\tb{\#therecmdmenu}] -Show a menu of possible actions in a location next to you. +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. +%%--invoking it by mouse seems to be broken +%% \\ +%% .lp "" +%% If mouse support is enabled and the {\it herecmd\verb+_+menu\/} +%% option is On, clicking on an adjacent location will execute this command. %.lp \item[\tb{\#throw}] Throw something. Default key is `{\tt t}'. @@ -1573,10 +1647,19 @@ Debug mode only. %.lp \item[\tb{\#version}] Print compile time options for this version of {\it NetHack\/}. + +%.lp +The second paragraph lists the user interface(s) that are included. +If there are more than one, you can use the {\it windowtype\/} +option in your run-time configuration file to select the one you want. + +%.lp Autocompletes. Default key is `{\tt M-v}'. %.lp \item[\tb{\#versionshort}] -Show version string. Default key is `{\tt 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 `{\tt v}'. %.lp \item[\tb{\#vision}] Show vision array. @@ -1659,6 +1742,11 @@ and hallucinatory monsters.\\ Autocompletes. Debug mode only. %.lp +\item[\tb{\#wizseenv}] +Show map locations' seen vectors. +Autocompletes. +Debug mode only. +%.lp \item[\tb{\#wizsmell}] Smell monster. Autocompletes. @@ -1692,13 +1780,26 @@ Help menu: get the list of available extended commands. with another key, modifies it by setting the `meta' [8th, or `high'] bit), you can invoke many extended commands by meta-ing the first letter of the command. -In {\it Windows, OS/2, PC\/ {\rm and} ST NetHack}, -the `Alt' key can be used in this fashion; -on the {\it Amiga}, set the {\it altmeta\/} option to get this behavior. + +On {\it Windows\/} and {\it MS-DOS\/}, +the `Alt' key can be used in this fashion. +%% On the {\it Amiga}, set the {\it altmeta\/} option to get this behavior. On other systems, if typing `Alt' plus another key transmits a two character sequence consisting of an {\tt Escape} followed by the other key, you may set the {\it altmeta\/} option to have {\it NetHack\/} combine them into meta\+key. +(This combining action only takes place when NetHack is expecting a +command to execute, not when accepting input to name something or to +make a wish.) + +%.pg +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 used for +another command, so the three key combination meta+shift+letter is needed. + +%.BR 1 \blist{} %.lp \item[\tb{M-?}] @@ -1778,6 +1879,9 @@ option to have {\it NetHack\/} combine them into meta\+key. %.lp \item[\tb{M-w}] {\tt\#wipe} +%.lp +\item[\tb{M-X}] +{\tt\#exploremode} \elist %.pg @@ -1959,7 +2063,7 @@ 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. +with a {\it scroll of earth}. However, doing such things will lower your luck without any specific message given about that. See the {\it Conduct\/} section for information about getting feedback for @@ -2028,10 +2132,12 @@ claim ownership without offering any compensation. You'll have to buy it back if you want to reclaim it. %.pg -Shopkeepers sometimes 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 shop where -it was obtained; other shopkeepers won't honor it. (If you happen to +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 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 use it in shops; shopkeepers will not accept it.) @@ -2060,7 +2166,7 @@ A shopkeeper treats the spot immediately inside the door as if it were outside the shop. %.lp \(bu 2 \item[$\bullet$] -While the shopkeeper watches you like a hawk, he will generally ignore +While the shopkeeper watches you like a hawk, he or she will generally ignore any other customers. %.lp \(bu 2 \item[$\bullet$] @@ -2071,7 +2177,7 @@ Shops do not get restocked with new items, regardless of inventory depletion. \end{itemize} %.hn 2 -\subsubsection*{Movement feedback} +\subsection*{Movement feedback} %.pg Moving around the map usually provides no @@ -2157,6 +2263,27 @@ The option controls how frequently the map gets redrawn when moving more than one step in a single command (so when rushing, running, or traveling). +%.hn 2 +\subsection*{Rogue level} + +%.pg +One dungeon level (occurring in mid to late teens of the main dungeon) +is a tribute to the ancestor game {\it hack}'s inspiration {\it rogue}. + +%.pg +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 {\tt *} rather than {\tt \verb+$+} +and stairs are shown as {\tt \verb+%+} rather than {\tt <} and {\tt >}. +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 radius around your character. +And monsters represented by lower-case letters aren't randomly +generated on the rogue level. + +%.pg +The slight strangeness of this level is a feature, not a bug.... + %.hn 1 \section{Monsters} @@ -2324,8 +2451,8 @@ to discard some of what you're carrying or collapse under its weight. %.pg {\it NetHack\/} will tell you how badly you have loaded yourself. If you are encumbered, one of the conditions -``{\it Burdened\/}'', ``{\it Stressed\/}'', ``{\it Strained\/}'', -``{\it Overtaxed\/}'' or ``{\it Overloaded\/}'' will be +{\tt Burdened}, {\tt Stressed}, {\tt Strained}, +{\tt Overtaxed}, or {\tt Overloaded} will be shown on the bottom line status display. %.pg @@ -2366,9 +2493,10 @@ less effective in combat. Other cursed objects may act poorly or detrimentally in other ways. %.pg -Objects can also be blessed. Blessed items usually work better or -more beneficially than normal uncursed items. For example, a blessed -weapon will do more damage against demons. +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. %.pg Objects which are neither cursed nor blessed are referred to as uncursed. @@ -2379,22 +2507,31 @@ half full versus glass half empty'' situation; make of that what you will. %.pg 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 +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. %.pg An item with unknown status will be reported in your inventory with no prefix. An item which you know the state of will be distinguished 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 +by the presence of the word {\tt cursed}, {\tt uncursed} or +{\tt blessed} in the description of the item. +In some cases {\tt uncursed} will be omitted as being redundant when enough other information is displayed. The {\it implicit\verb+_+uncursed\/} -option can be used to control this; toggle it off to have ``uncursed'' +option can be used to control this; toggle it off to have {\tt uncursed} be displayed even when that can be deduced from other attributes. +%.pg +Sometimes the bless or curse state of objects is referred to as their +``{\tt BUC}'' attribute, for Blessed, Uncursed, or Cursed state, +or ``{\tt BUCX}'' for Blessed, Uncursed, Cursed, or unknown. +(The term {\it beatitude\/} is occasionally used as well.) + %.hn 2 \subsection*{Weapons (`{\tt )}')} @@ -2826,7 +2963,7 @@ That's done implicitly to avoid unnecessary tedium. %.pg The commands to use rings are `{\tt P}' (put on) and `{\tt R}' (remove). -`{\tt A|', `{\tt W}', and `{\tt T}' can also be used; see {\it Amulets\/}. +`{\tt A}', `{\tt W}', and `{\tt T}' can also be used; see {\it Amulets\/}. %.hn 2 \subsection*{Spellbooks (`{\tt +}')} @@ -3159,7 +3296,7 @@ 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 time, but it is tracked as a conduct. -The #conduct command and end of game disclosure will report whether +The {\tt \#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, providing you with a way to discover which actions incur bad luck so that you can be better informed about whether @@ -3276,7 +3413,7 @@ Losing enough levels to revert to lower rank(s) does not discard the corresponding achievement(s). %.pg -The ``special items'' hidden in {\it Mines'~End\/} and (\it Sokoban\/} +The ``special items'' hidden in {\it Mines'~End\/} and {\it 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. @@ -3323,7 +3460,7 @@ The default name and location of the configuration file varies on different operating systems.\\ %.lp "" -On Unix, Linux and Mac OS X it is \mbox{``.nethackrc''} in the user's home +On UNIX, Linux and Mac OS X it is \mbox{``.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.\\ @@ -3343,22 +3480,30 @@ On MS-DOS it is \mbox{``defaults.nh''} in the same folder as \mbox{{\it nethack.exe\/}}.\\ %.lp "" -Any line in the configuration file starting with `{\tt \#}' is treated as a comment. -Empty lines are ignored. Any line beginning with `{\tt [}' and ending in `{\tt ]}' is considered a section -marker. The text between the square brackets is the section name. -Lines after a section marker belong to that section, and are -ignored unless a CHOOSE -statement was used to select that section. -Section names are case insensitive. +Any line in the configuration file starting with `{\tt \#}' is treated +as a comment and ignored. +Empty lines are ignored. + +Any line beginning with `{\tt [}' and ending in `{\tt ]}' +is a section marker (the closing `{\tt ]}' can be followed +by whitespace and then an arbitrary comment beginning with `{\tt \#}'). +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 section. %.pg -You can use different configuration statements in the file, some +You can use different configuration directives in the file, some of which can be used multiple times. -In general, the statements are +In general, the directives are written in capital letters, followed by an equals sign, followed by -settings particular to that statement. +settings particular to that directive. %.pg -Here is a list of allowed statements: +Here is a list of allowed directives: %.lp \blist{} @@ -3369,8 +3514,8 @@ 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 statements, and multiple options -separated by commas in a single OPTIONS statement. +You can specify multiple OPTIONS directives, and multiple options +separated by commas in a single OPTIONS directive. (Comma separated options are processed from right to left.) %.lp "" @@ -3449,7 +3594,8 @@ Example: %.lp \item[\bb{CHOOSE}] Chooses at random one of the comma-separated parameters as an active -section name. Lines in other sections are ignored. +section name. +Lines in other sections are ignored. %.lp "" Example: @@ -3461,9 +3607,16 @@ Example: OPTIONS=role:arc,race:dwa,align:law,gender:fem [char B] OPTIONS=role:wiz,race:elf,align:cha,gender:mal + [] #end of CHOOSE + OPTIONS=!rest_on_space \end{verbatim} %.ed +%.lp "" +If {\tt []} is present, the preceding section is closed and no new +section begins; whatever follows will be common to all sections. +Otherwise the last section extends to the end of the options file. + %.lp \item[\bb{MENUCOLOR}] Highlight menu lines with different colors. @@ -3580,10 +3733,10 @@ to that shell), or the pair of commands %.pg The NETHACKOPTIONS value is effectively the same as a single OPTIONS -statement in a configuration file. +directive in a configuration file. The ``OPTIONS='' prefix is implied and comma separated options are processed from right to left. -Other types of configuration statements such as BIND or MSGTYPE are +Other types of configuration directives such as BIND or MSGTYPE are not allowed. %.pg @@ -4279,6 +4432,10 @@ depend upon the window port used or on the type of terminal. Persistent. %.lp \item[\ib{safe\verb+_+pet}] Prevent you from (knowingly) attacking your pets (default on). Persistent. +%.lp +\item[\ib{safe\verb+_+wait}] +Prevents you from waiting or searching when next to a hostile monster +(default on). Persistent. %+.lp \item[\ib{sanity\verb+_+check}] Evaluate monsters, objects, and map prior to each turn (default off). @@ -4307,17 +4464,44 @@ Persistent. \item[\ib{silent}] Suppress terminal beeps (default on). Persistent. %.lp +\item[\ib{sortdiscoveries}] +Controls the sorting behavior for the output of the `{\tt $\backslash$}' +and `{\tt \`}' commands. +Persistent. +\\ +%.lp "" +The possible values are: +%.PS o +%.PL o +(\tt o} --- list object types by class, in discovery order within each class; +default; +%.PL s +{\tt s} --- list object types by {\it 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; +\\ +%.PL c +{\tt c} --- list by class, alphabetically within each class;\\ +%.PL a +{\tt a} --- list alphabetically across all classes.\\ +%.PE +Can be interactively set via the `{\tt O}' command or via using +the `{\tt m}' prefix before the `{\tt $\backslash$}' +or `{\tt \`}' command. +%.lp \item[\ib{sortloot}] Controls the sorting behavior of pickup lists for inventory and \#loot commands and some others. Persistent. - +\\ The possible values are: %.sd %.si {\tt full} --- always sort the lists;\\ {\tt loot} --- only sort the lists that don't use inventory letters, like with the \#loot and pickup commands;\\ -{\tt none} --- show lists the traditional way without sorting. +{\tt none} --- show lists the traditional way without sorting; default. %.ei %.ed %.lp @@ -4495,7 +4679,16 @@ with the `{\tt O}' command. Where to align or place the status window (top, bottom, left, or right). %.lp \item[\ib{ascii\verb+_+map}] -If {\it NetHack\/} can, it should display an ascii map. +%.hw DECgraphics IBMgraphics \% don't hyphenate these +\hyphenation{DECgraphics IBMgraphics} +If {\it NetHack\/} can, it should display the map using simple +characters (letters and punctuation) rather than {\it tiles\/} graphics. +In some cases, characters can be augmented with line-drawing symbols; +use the {\tt symset} +option to select a symbol set such as {\it DECgraphics\/} +or {\it IBMgraphics\/} if your display supports them. +Setting {\tt ascii\verb+_+map} to {\it True\/} forces +{\tt tiled\verb+_+map} to be {\it False}. %.lp \item[\ib{color}] If {\it NetHack\/} can, it should display color for different monsters, @@ -4587,8 +4780,32 @@ it starts up (default yes). %.lp \item[\ib{statuslines}] Number of lines for traditional below-the-map status display. -Acceptable values are 2 and 3 (default is 2). -Curses and tty interfaces only. +Acceptable values are {\tt 2} and {\tt 3} (default is {\tt 2}). + +%.lp "" +When set to {\tt 3}, the {\tt 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. + +%.lp "" +The {\tt curses} interface does likewise if the +{\it align\verb+_+status\/} +option is set to {\it top\/} or {\it bottom\/} but ignores +{\it statuslines\/} +when set to {\it left\/} or {\it right}. + +%.lp "" +The {\tt Qt} interface already displays more than 3 lines for status +so uses the +{\it statuslines\/} +value differently. +A value of {\tt 3} renders status in the {\tt Qt} interface's +original format, with the status window spread out vertically. +A value of {\tt 2} makes status be slightly condensed, moving some +fields to different lines to eliminate one whole line, reducing the +height needed. %.lp \item[\ib{term\verb+_+cols} {\normalfont and}] %.lp @@ -4599,9 +4816,6 @@ 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. %.lp -\item[\ib{tiled\verb+_+map}] -If {\it NetHack\/} can, it should display a tiled map if it can. -%.lp \item[\ib{tile\verb+_+file}] Specify the name of an alternative tile file to override the default. %.lp @@ -4611,6 +4825,13 @@ Specify the preferred height of each tile in a tile capable port. \item[\ib{tile\verb+_+width}] Specify the preferred width of each tile in a tile capable port %.lp +\item[\ib{tiled\verb+_+map}] +If {\it NetHack\/} can, it should display the map using \fItiles\fP graphics +rather than simple characters (letters and punctuation, possibly +augmented by line-drawing symbols). +Setting {\tt tiled\verb+_+map} to {\it True\/} forces +{\tt ascii\verb+_+map} to be {\it False}. +%.lp \item[\ib{use\verb+_+darkgray}] Use bold black instead of blue for black glyphs (TTY only). %.lp @@ -4733,7 +4954,7 @@ returns to {\it NetHack\/} to help compensate for international keyboard issues. OPTIONS=subkeyvalue:171/92 will return 92 to {\it NetHack\/}, if 171 was originally going to be returned. -You can use multiple subkeyvalue statements in the configuration file +You can use multiple subkeyvalue assignments in the configuration file if needed. Cannot be set with the `{\tt O}' command. %.lp @@ -4773,7 +4994,7 @@ if this does not correct the problem, try {\tt !color}. Cannot be set with the `{\tt O}' command. \elist -%.nh 2 +%.hn 2 \subsection*{Regular Expressions} %.pg @@ -5027,11 +5248,23 @@ Prefix key to run towards a direction without picking up items on the way. Default is~`{\tt M}'. %.lp \item[{\bb{run.numpad}}] -Prefix key to run towards a direction. With {\it number\verb+_+pad\/} only. -Default is~`{\tt 5}'. +Prefix key to run towards a direction. +With {\it number\verb+_+pad\/} only. + +%.lp "" +Default is `{\tt 5}' when number_pad is set to 1~or~3, +otherwise `{\tt M-5}' when it is set to 2~or~4. %.lp \item[{\bb{rush}}] Prefix key to rush towards a direction. Default is~`{\tt g}'. +%.lp +\item[{\bb{rush.numpad}}] +Prefix key to rush towards a direction. +With {\it number\verb+_+pad\/} only. + +.lp "" +Default is `{\tt M-5}' when number_pad is set to 1~or~3, +otherwise `{\tt 5}' when it is set to 2~or~4. \elist @@ -5922,9 +6155,18 @@ Kenny Woodland}, {\it Mike Thome}, and {\it Jon Payne}. %.pg \medskip -\nd {\it Andries Brouwer\/} did a major re-write, transforming {\it Hack\/} -into a very different game, and published (at least) three versions (1.0.1, -1.0.2, and 1.0.3) for UNIX machines to the Usenet. +\nd {\it Andries Brouwer\/} did a major re-write while at +Stichting Mathematisch 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 {\it net.sources\/} (later renamed {\it 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 {\it net.games.hack\/} (later +renamed {\it rec.games.hack}, eventually replaced +by {\it rec.games.roguelike.nethack}) +was created for discussing it. %.pg \medskip @@ -5947,6 +6189,9 @@ incorporating many of the added features, and produced {\it NetHack\/} version 1.4 in 1987. He then coordinated a cast of thousands in enhancing and debugging {\it NetHack\/} 1.4 and released {\it 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 {\it ftp\/} and {\it uucp\/} after expiring from the newsgroup. %.pg \medskip @@ -6238,8 +6483,8 @@ In January 2015, preparation began for the release of NetHack 3.6. %.pg \medskip -At the beginning of development for what would eventually get released -as 3.6.0, the {\it NetHack Development Team} consisted of {\it Warwick Allison}, +At the beginning of development for what would eventually get released as +3.6.0, the {\it NetHack Development Team} consisted of {\it Warwick Allison}, {\it Michael Allison}, {\it Ken Arromdee}, {\it David Cohrs}, {\it Jessie Collet}, {\it Ken Lorber}, {\it Dean Luick}, {\it Pat Rankin}, @@ -6265,7 +6510,7 @@ patches. Many bugs were fixed and some code was restructured. \medskip The {\it NetHack Development Team}, as well as {\it Steve VanDevender} and {\it Kevin Smolkowski}, ensured that {\it NetHack\/} 3.6 continued to -operate on various Unix flavors and maintained the X11 interface. +operate on various UNIX flavors and maintained the X11 interface. %.pg \medskip diff --git a/doc/Guidebook.txt b/doc/Guidebook.txt index ad9ddff17..e31cd4137 100644 --- a/doc/Guidebook.txt +++ b/doc/Guidebook.txt @@ -15,7 +15,7 @@ Original version - Eric S. Raymond (Edited and expanded for 3.7 by Mike Stephenson and others) - July 9, 2020 + December 19, 2020 @@ -76,7 +76,7 @@ Menace. It is late at night, so you make camp at the entrance and spend the night sleeping under the open skies. In the morn- ing, you gather your gear, eat what may be your last meal out- - side, and enter the dungeon... + side, and enter the dungeon.... 2. What is going on here? @@ -126,7 +126,7 @@ - NetHack 3.7 July 9, 2020 + NetHack 3.7 December 19, 2020 @@ -192,7 +192,7 @@ you have seen on the current dungeon level; as you explore more - NetHack 3.7 July 9, 2020 + NetHack 3.7 December 19, 2020 @@ -258,7 +258,7 @@ - NetHack 3.7 July 9, 2020 + NetHack 3.7 December 19, 2020 @@ -324,7 +324,7 @@ - NetHack 3.7 July 9, 2020 + NetHack 3.7 December 19, 2020 @@ -390,7 +390,7 @@ you have available for spell casting. Again, resting will - NetHack 3.7 July 9, 2020 + NetHack 3.7 December 19, 2020 @@ -456,7 +456,7 @@ scribe things that are impossible to represent visually. If you - NetHack 3.7 July 9, 2020 + NetHack 3.7 December 19, 2020 @@ -522,7 +522,7 @@ - NetHack 3.7 July 9, 2020 + NetHack 3.7 December 19, 2020 @@ -588,7 +588,7 @@ - NetHack 3.7 July 9, 2020 + NetHack 3.7 December 19, 2020 @@ -654,7 +654,7 @@ - NetHack 3.7 July 9, 2020 + NetHack 3.7 December 19, 2020 @@ -720,7 +720,7 @@ - NetHack 3.7 July 9, 2020 + NetHack 3.7 December 19, 2020 @@ -740,23 +740,24 @@ tion. . Wait or rest, do nothing for one turn. Precede with the `m' - prefix to wait for a turn even next to a hostile monster. + prefix 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 + 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 + Use `T' (take off) to take off only one piece of armor or `R' (remove) to take off only one accessory. ^A Redo the previous command. c Close a door. - C Call (name) a monster, an individual object, or a type of + C Call (name) a monster, an individual object, or a type of object. Same as extended command "#name". @@ -773,9 +774,9 @@ "What kinds of things do you want to drop? [!%= BUCXaium]" - you should type zero or more object symbols possibly fol- + you should type zero or more object symbols possibly fol- lowed by `a' and/or `i' and/or `u' and/or `m'. In addition, - one or more of the blessed/uncursed/cursed groups may be + one or more of the blessed/uncursed/cursed groups may be typed. DB - drop all objects known to be blessed. @@ -783,10 +784,9 @@ DC - drop all objects known to be cursed. DX - drop all objects of unknown B/U/C status. Da - drop all objects, without asking for confirmation. - Di - examine your inventory before dropping anything. - NetHack 3.7 July 9, 2020 + NetHack 3.7 December 19, 2020 @@ -796,38 +796,39 @@ + Di - examine your inventory before dropping anything. Du - drop only unpaid objects (when in a shop). 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 three cate- - gories of object filtering: class (`!' for potions, `?' for - scrolls, and so on), shop status (`u' for unpaid, in other - words, owned by the shop), and bless/curse state (`B', `U', - `C', and `X' as shown above). If you specify more than one + gories of object filtering: class (`!' for potions, `?' for + scrolls, and so on), shop status (`u' for unpaid, in other + words, owned by the shop), and bless/curse state (`B', `U', + `C', and `X' as shown above). 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 + "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 category - 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, fil- + 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, fil- ter combinations behaved differently.) ^D Kick something (usually a door). e Eat food. - Normally checks for edible item(s) on the floor, then if + 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 at- tempting to eat anything 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 + 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 paranoid_confirmation:eating option to require a response of yes instead of just y. @@ -835,14 +836,14 @@ E- - write in the dust with your fingers. - Engraving the word "Elbereth" will cause most monsters to + 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 + 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 + may select ammunition with a previous `Q' command, or let + the computer pick something appropriate if autoquiver is true. See also `t' (throw) for more general throwing and shooting. @@ -851,8 +852,7 @@ - - NetHack 3.7 July 9, 2020 + NetHack 3.7 December 19, 2020 @@ -863,7 +863,7 @@ I List selected parts of your inventory, usually be specifying - the character for a particular set of objects, like `[' for + the character for a particular set of objects, like `[' for armor or `!' for potions. I* - list all gems in inventory; @@ -879,22 +879,22 @@ O Set options. - A menu showing the current option values will be displayed. - You can change most values simply by selecting the menu en- + A menu showing the current option values will be displayed. + You can change most values simply by selecting the menu en- try for the given option (ie, by typing its letter or click- - ing 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 + ing 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 be- fore the game rather than with the `O' command; see the sec- tion on options below. ^O Show overview. - Shortcut for "#overview": list interesting dungeon levels + Shortcut for "#overview": list interesting dungeon levels visited. - (Prior to 3.6.0, `^O' was a debug mode command which listed + (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.) @@ -903,22 +903,22 @@ 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 - choosing an unlisted item of armor will attempt to wear it. + 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 but will accept an accessory and attempt to put that on.) ^P Repeat previous message. - Subsequent `^P's repeat earlier messages. For some inter- + Subsequent `^P's repeat earlier messages. For some inter- faces, the behavior can be varied via the msg_window option. q Quaff (drink) something (potion, water, etc). - NetHack 3.7 July 9, 2020 + NetHack 3.7 December 19, 2020 @@ -928,34 +928,35 @@ - Q Select an object for your quiver, quiver sack, or just gen- - erally at the ready (only one of these is available at a - time). You can then throw this (or one of these) using the + Q Select an object for your quiver, quiver sack, or just gen- + erally 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. - (In versions prior to 3.3 this was the command to quit the + (In versions prior to 3.3 this was the command to quit the game, which has been moved to "#quit".) r Read a scroll or spellbook. R Remove a worn accessory (ring, amulet, or blindfold). - If you're wearing more than one, you'll be prompted for - which one to remove. When you're only wearing one, then by - default it will be removed without asking, but you can set + If you're wearing more than one, you'll be prompted for + which one to remove. When you're only wearing one, then by + default it will be removed without asking, but you can set the paranoid_confirmation 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 acces- - sories, but an item of worn armor can be chosen. (See the - `T' command below. It lists armor as the inventory choices + for which inventory item to remove only lists worn acces- + sories, 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 accessory and attempt to remove it.) ^R Redraw the screen. - s Search for secret doors and traps around you. It usually + 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. + 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 mon- ster at an adjacent "remembered, unseen monster" marker. @@ -981,10 +982,9 @@ 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 generally be less effective than when shot. - NetHack 3.7 July 9, 2020 + NetHack 3.7 December 19, 2020 @@ -994,6 +994,8 @@ + hand and it will generally be less effective than when shot. + See also `f' (fire) for throwing or shooting an item pre-se- lected via the `Q' (quiver) command. @@ -1046,11 +1048,9 @@ 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 was the command to switch - from normal play to "explore mode", also known as "discovery - NetHack 3.7 July 9, 2020 + NetHack 3.7 December 19, 2020 @@ -1060,20 +1060,23 @@ - mode", which has now been moved to "#exploremode".) + (In versions prior to 3.6 this keystroke ran the command to + switch from normal play to "explore mode", also known as + "discovery 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 align- - ment, along with your patron deity and his or her opposi- - tion. It also shows most of the various items of informa- + Displays name, role, race, gender (unless role name makes + that redundant, such as Caveman or Priestess), and align- + ment, along with your patron deity and his or her opposi- + tion. It also shows most of the various items of informa- tion from the status line(s) in a less terse form, including - several additional things which don't appear in the normal + several additional things which don't appear in the normal status display due to space considerations. - In normal play, that's all that `^X' displays. In explore - mode, the role and status feedback is augmented by the in- + In normal play, that's all that `^X' displays. In explore + mode, the role and status feedback is augmented by the in- formation provided by enlightenment magic. z Zap a wand. @@ -1084,7 +1087,8 @@ Z. - to cast at yourself, use `.' for the direction. - ^Z Suspend the game (UNIX(R) versions with job control only). + ^Z Suspend the game (UNIX(R) versions with job control only). + See "#suspend" below for more details. : Look at what is here. @@ -1106,17 +1110,13 @@ " Tell what amulet you are wearing. - ( Tell what tools you are using. - - * Tell what equipment you are using. - __________ (R)UNIX is a registered trademark of The Open Group. - NetHack 3.7 July 9, 2020 + NetHack 3.7 December 19, 2020 @@ -1126,63 +1126,63 @@ + ( Tell what tools you are using. + + * Tell what equipment you are using. + Combines the preceding five type-specific commands into one. - $ Count your gold pieces. + $ Report the gold you're carrying, possibly shop credit and/or + debt too. + 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 an- - other to swap places with it. Swapping pairs of spells + 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 an- + other to swap places with it. Swapping pairs of spells changes their casting letters, so the change lasts after the - current `+' command finishes. Sorting the whole list is - temporary. To make the most recent sort order persist be- - yond 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 + current `+' command finishes. Sorting the whole list is + temporary. To make the most recent sort order persist be- + yond 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. + May be preceded by `m' to select preferred display order. + ` Show discovered types for one class of objects. - ! Escape to a shell. + May be preceded by `m' to select preferred display order. + + ! Escape to a shell. See "#shell" below for more details. + + Del Show map without obstructions. You can view the explored + portion 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 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 "#terrain" instead. # Perform an extended command. - As you can see, the authors of NetHack used up all the let- + As you can see, the authors of NetHack used up all the let- ters, so this is a way to introduce the less frequently used com- - mands. What extended commands are available depends on what fea- - tures the game was compiled with. - - #adjust - 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 - inventory slot to another so that it has a letter which is - more meaningful for you or that it will appear in a particu- - lar location when inventory listings are displayed. You can - move to a currently empty slot, or if the destination is oc- - cupied--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 letter. - - 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 + mands. What extended commands are available depends on what - NetHack 3.7 July 9, 2020 + NetHack 3.7 December 19, 2020 @@ -1192,29 +1192,52 @@ - eligible. In either case, otherwise compatible stacks with - a different name will not be merged. This contrasts with - using "#adjust" to move from one slot to a different slot. - In that situation, moving (no count given) a compatible - stack will merge if either stack has a name when the other - doesn't and give that name to the result, while splitting - (count given) will ignore the source stack's name when de- - ciding whether to merge with the destination stack. + features the game was compiled with. + + #adjust + 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 + inventory slot to another so that it has a letter which is + more meaningful for you or that it will appear in a particu- + lar location when inventory listings are displayed. You can + move to a currently empty slot, or if the destination is oc- + cupied--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 letter. + + 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 eligi- + ble. In either case, otherwise compatible stacks with a + different name will not be merged. This contrasts with us- + ing "#adjust" to move from one slot to a different slot. In + that situation, moving (no count given) a compatible stack + will merge if either stack has a name when the other doesn't + and give that name to the result, while splitting (count + 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 current dungeon level. All levels with annotations are dis- - played by the "#overview" command. Autocompletes. Default + played by the "#overview" command. Autocompletes. Default key is `M-A', and also `^N' if number_pad is on. #apply - Apply (use) a tool such as a pick-axe, a key, or a lamp. + Apply (use) a tool such as a pick-axe, a key, or a lamp. Default key is `a'. - If the tool used acts on items on the floor, using the `m' + 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 + If used on a wand, that wand will be broken, releasing its magic in the process. Confirmation is required. #attributes @@ -1223,10 +1246,22 @@ #autopickup Toggle the autopickup option on/off. Default key is `@'. + + + NetHack 3.7 December 19, 2020 + + + + + + NetHack Guidebook 20 + + + #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 level (same as "#annotate"). Default key is + 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 @@ -1239,25 +1274,13 @@ Close a door. Default key is `c'. #conduct - List voluntary challenges you have maintained. Autocom- + List voluntary challenges you have maintained. Autocom- pletes. Default key is `M-C'. See the section below entitled "Conduct" for details. #dip - Dip an object into something. Autocompletes. Default key - - - NetHack 3.7 July 9, 2020 - - - - - - NetHack Guidebook 20 - - - + Dip an object into something. Autocompletes. Default key is `M-d'. #down @@ -1270,24 +1293,37 @@ Drop specific item types. Default key is `D'. #eat - Eat something. Default key is `e'. The `m' prefix skips + 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. + Advance or check weapon and spell skills. Autocompletes. Default key is `M-e'. #exploremode - Enter the explore mode. + Switch from normal play to non-scoring explore mode. De- + fault key is `M-X'. Requires confirmation; default response is n (no). To real- ly switch to explore mode, respond with y. You can set the paranoid_confirmation:quit option to require a response of yes instead. + + + NetHack 3.7 December 19, 2020 + + + + + + NetHack Guidebook 21 + + + #fire Fire ammunition from quiver. Default key is `f'. @@ -1303,7 +1339,14 @@ number_pad is on. #herecmdmenu - Show a menu of possible actions in your current location. + Show a menu of possible actions directed at your current lo- + cation. The menu is limited to a subset of the likeliest + actions, not an exhaustive set of all possibilities. Auto- + completes. + + If mouse support is enabled and the herecmd_menu option is + On, clicking on the hero (or steed when mounted) will exe- + cute this command. #history Show long version and game history. Default key is `V'. @@ -1311,76 +1354,33 @@ #inventory Show your inventory. Default key is `i'. - - - - NetHack 3.7 July 9, 2020 - - - - - - NetHack Guidebook 21 - - - #inventtype Inventory specific item types. Default key is `I'. #invoke - Invoke an object's special powers. Autocompletes. Default + Invoke an object's special powers. Autocompletes. Default key is `M-i'. #jump - Jump to another location. Autocompletes. Default key is + 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 + Kick something. Default key is `^D', and `k' if number_pad is on. #known Show what object types have been discovered. Default key is `\'. - #knownclass - Show discovered types for one class of objects. Default key - is ``'. - - #levelchange - Change your experience level. Autocompletes. Debug mode - only. - - #lightsources - Show mobile light sources. Autocompletes. Debug mode only. - - #look - Look at what is here, under you. Default key is `:'. - - #loot - 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 removing a saddle. Default key is `M-l', and - also `l' if number_pad is on. - - #monster - Use a monster's special ability (when polymorphed into mon- - ster form). Autocompletes. Default key is `M-m'. - - #name - 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 `M-o'. + The `m' prefix allows assigning a new value to the sortdis- + coveries option to control the order in which the discover- + ies are displayed. - NetHack 3.7 July 9, 2020 + NetHack 3.7 December 19, 2020 @@ -1390,8 +1390,44 @@ - You'll need to find an altar to have any chance at success. - Corpses of recently killed monsters are the fodder of + #knownclass + Show discovered types for one class of objects. Default key + is ``'. + + The `m' prefix operates the same as for "#known". + + #levelchange + Change your experience level. Autocompletes. Debug mode + only. + + #lightsources + Show mobile light sources. Autocompletes. Debug mode only. + + #look + Look at what is here, under you. Default key is `:'. + + #loot + 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 removing a saddle. Default key is `M-l', and + also `l' if number_pad is on. + + #monster + Use a monster's special ability (when polymorphed into mon- + ster form). Autocompletes. Default key is `M-m'. + + #name + 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 `M-o'. + + 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 al- @@ -1404,22 +1440,34 @@ Show and change option settings. Default key is `O'. #overview - Display information you've discovered about the dungeon. - Any visited level (unless forgotten due to amnesia) with an - annotation is included, and many things (altars, thrones, - fountains, and so on; extra stairs leading to another dun- - geon branch) trigger an automatic annotation. If dungeon + Display information you've discovered about the dungeon. + Any visited level (unless forgotten due to amnesia) with an + annotation is included, and many things (altars, thrones, + fountains, and so on; extra stairs leading to another + + + NetHack 3.7 December 19, 2020 + + + + + + NetHack Guidebook 23 + + + + dungeon branch) trigger an automatic annotation. If dungeon overview is chosen during end-of-game disclosure, every vis- - ited level will be included regardless of annotations. Au- + ited level will be included regardless of annotations. Au- tocompletes. Default keys are `^O', and `M-O'. #panic Test the panic routine. Terminates the current game. Auto- completes. Debug mode only. - Asks for confirmation; default is n (no); continue playing. - To really panic, respond with y. You can set the para- - noid_confirmation:quit option to require a response of yes + Asks for confirmation; default is n (no); continue playing. + To really panic, respond with y. You can set the para- + noid_confirmation:quit option to require a response of yes instead. #pay @@ -1433,86 +1481,38 @@ Polymorph self. Autocompletes. Debug mode only. #pray - Pray to the gods for help. Autocompletes. Default key is + 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 re- + Praying too soon after receiving prior help is a bad idea. + (Hint: entering the dungeon alive is treated as having re- ceived help. You probably shouldn't start off a new game by - praying right away.) Since using this command by accident - can cause 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 + praying right away.) Since using this command by accident + can cause 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. - - NetHack 3.7 July 9, 2020 - - - - - - NetHack Guidebook 23 - - - #prevmsg - Show previously displayed game messages. Default key is + Show previously displayed game messages. Default key is `^P'. #puton - Put on an accessory (ring, amulet, etc). Default key is + Put on an accessory (ring, amulet, etc). Default key is `P'. #quaff Quaff (drink) something. Default key is `q'. #quit - Quit the program without saving your game. Autocompletes. + Quit the program without saving your game. Autocompletes. Default key is `M-q'. - Since using this command by accident would throw away the - current 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_con- - firmation: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 `r'. - - #redraw - Redraw the screen. Default key is `^R', and also `^L' if - number_pad is on. - - #remove - Remove an accessory (ring, amulet, etc). Default key is - `R'. - - #ride - Ride (or stop riding) a saddled creature. Autocompletes. - Default key is `M-R'. - - #rub - Rub a lamp or a stone. Autocompletes. Default key is `M- - r'. - - #save - Save the game and exit the program. Default key is `S'. - - #search - Search for traps and secret doors around you. Default key - is `s'. - - #seeall - Show all equipment in use. Default key is `*'. + Since using this command by accident would throw away the + current game, you are asked to confirm your intent before - - NetHack 3.7 July 9, 2020 + NetHack 3.7 December 19, 2020 @@ -1522,35 +1522,92 @@ + quitting. Default response is n (no); continue playing. To + really quit, respond with y. You can set the paranoid_con- + firmation: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 `r'. + + #redraw + Redraw the screen. Default key is `^R', and also `^L' if + number_pad is on. + + #remove + Remove an accessory (ring, amulet, etc). Default key is + `R'. + + #ride + Ride (or stop riding) a saddled creature. Autocompletes. + Default key is `M-R'. + + #rub + Rub a lamp or a stone. Autocompletes. Default key is `M- + r'. + + #save + Save the game and exit the program. Default key is `S'. + + #search + Search for traps and secret doors around you. Default key + is `s'. + + #seeall + Show all equipment in use. Default key is `*'. + #seeamulet Show the amulet currently worn. Default key is `"'. #seearmor Show the armor currently worn. Default key is `['. - #seegold - Count your gold. Default key is `$'. - - #seenv - Show seen vectors. Autocompletes. Debug mode only. - #seerings Show the ring(s) currently worn. Default key is `='. - #seespells - List and reorder known spells. Default key is `+'. - #seetools Show the tools currently in use. Default key is `('. - #seetrap - Show the type of an adjacent trap. Default key is `^'. - #seeweapon Show the weapon currently wielded. Default key is `)'. #shell - Do a shell escape. Default key is `!'. + Do a shell escape, switching from NetHack to a subprocess. + + + NetHack 3.7 December 19, 2020 + + + + + + NetHack Guidebook 25 + + + + Can be disabled at the time the program is built. When en- + abled, access for specific users can be controlled by the + system configuration file. Use the shell command `exit' to + return to the game. Default key is `!'. + + #showgold + Report the gold in your inventory and if you are inside a + shop, report any credit or debt you have in that shop. Does + not report on any gold inside containers you're carrying. + Default key is `$'. + + #showspells + List and reorder known spells. Default key is `+'. + + #showtrap + Describe an adjacent trap, possibly covered by objects or a + monster. To be eligible, the trap must already be discov- + ered. (The "#terrain" command can display your map with all + objects and monsters temporarily removed, making it possible + to see all discovered traps.) Default key is `^'. #sit Sit down. Autocompletes. Default key is `M-s'. @@ -1560,7 +1617,12 @@ only. #suspend - Suspend the game. Default key is `^Z'. + 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 Swap wielded and secondary weapons. Default key is `x'. @@ -1575,76 +1637,14 @@ Teleport around the level. Default key is `^T'. #terrain - Show bare map without displaying monsters, objects, or - - - NetHack 3.7 July 9, 2020 + Show map without obstructions. In normal play you can view + the explored portion of the current level's map without mon- + sters; without monsters and objects; or without monsters, + objects, and traps. - - - NetHack Guidebook 25 - - - - traps. Autocompletes. - - #therecmdmenu - Show a menu of possible actions in a location next to you. - - #throw - Throw something. Default key is `t'. - - #timeout - Look at the timeout queue. Autocompletes. Debug mode only. - - #tip - Tip over a container (bag or box) to pour out its contents. - Autocompletes. Default key is `M-T'. The `m' prefix makes - the command use a menu. - - #travel - Travel to a specific location on the map. Default key is - `_'. Using the "request menu" prefix shows a menu of inter- - esting targets in sight without asking to move the cursor. - When picking a target with cursor and the autodescribe op- - tion is on, the top line will show "(no travel path)" if - your character does not know of a path to that location. - - #turn - Turn undead away. Autocompletes. Default key is `M-t'. - - #twoweapon - 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, or it will be automatically turned off. - - #untrap - 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 - monsters. - - #up - Go up a staircase. Default key is `<'. - - #vanquished - List vanquished monsters. Autocompletes. Debug mode only. - - #version - Print compile time options for this version of NetHack. Au- - tocompletes. Default key is `M-v'. - - #versionshort - Show version string. Default key is `v'. - - - - NetHack 3.7 July 9, 2020 + NetHack 3.7 December 19, 2020 @@ -1654,11 +1654,92 @@ + In explore mode, you can choose to view the full map rather + than just its explored portion. In debug mode there are ad- + ditional choices. + + 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, not an exhaustive set of all possibilities. Auto- + completes. + + #throw + Throw something. Default key is `t'. + + #timeout + Look at the timeout queue. Autocompletes. Debug mode only. + + #tip + Tip over a container (bag or box) to pour out its contents. + Autocompletes. Default key is `M-T'. The `m' prefix makes + the command use a menu. + + #travel + Travel to a specific location on the map. Default key is + `_'. Using the "request menu" prefix shows a menu of inter- + esting targets in sight without asking to move the cursor. + When picking a target with cursor and the autodescribe op- + tion is on, the top line will show "(no travel path)" if + your character does not know of a path to that location. + + #turn + Turn undead away. Autocompletes. Default key is `M-t'. + + #twoweapon + 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, or it will be automatically turned off. + + #untrap + 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 + monsters. + + #up + Go up a staircase. Default key is `<'. + + #vanquished + List vanquished monsters. Autocompletes. Debug mode only. + + + NetHack 3.7 December 19, 2020 + + + + + + NetHack Guidebook 27 + + + + #version + Print compile time options for this version of NetHack. + + The second paragraph lists the user interface(s) that are + included. If there are more than one, you can use the win- + dowtype option in your run-time configuration file to select + the one you want. + + Autocompletes. Default key is `M-v'. + + #versionshort + Show the program's version number, plus the date and time + that the running copy was built from sources (not the ver- + sion'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 + Rest one move while doing nothing. Default key is `.', and also ` ' if rest_on_space is on. #wear @@ -1668,7 +1749,7 @@ Tell what a key does. Default key is `&'. #whatis - Show what type of thing a symbol corresponds to. Default + Show what type of thing a symbol corresponds to. Default key is `/'. #wield @@ -1682,17 +1763,29 @@ Debug mode only. #wizbury - Bury objects under and around you. Autocompletes. Debug + Bury objects under and around you. Autocompletes. Debug mode only. #wizdetect - Search for hidden things (secret doors or traps or unseen - monsters) within a modest radius. Autocompletes. Debug + Search for hidden things (secret doors or traps or unseen + monsters) within a modest radius. Autocompletes. Debug mode only. Default key is `^E'. #wizgenesis Create a monster. May be prefixed by a count to create more - than one. Autocompletes. Debug mode only. Default key is + than one. Autocompletes. Debug mode only. Default key is + + + NetHack 3.7 December 19, 2020 + + + + + + NetHack Guidebook 28 + + + `^G'. #wizidentify @@ -1707,32 +1800,23 @@ Teleport to another level. Autocompletes. Debug mode only. Default key is `^V'. - - - - NetHack 3.7 July 9, 2020 - - - - - - NetHack Guidebook 27 - - - #wizmap - Map the level. Autocompletes. Debug mode only. Default + Map the level. Autocompletes. Debug mode only. Default key is `^F'. #wizrumorcheck - Verify rumor boundaries by displaying first and last true + Verify rumor boundaries by displaying first and last true rumors and first and last false rumors. - Also displays first, second, and last random engravings, + Also displays first, second, and last random engravings, epitaphs, and hallucinatory monsters. Autocompletes. Debug mode only. + #wizseenv + Show map locations' seen vectors. Autocompletes. Debug + mode only. + #wizsmell Smell monster. Autocompletes. Debug mode only. @@ -1755,17 +1839,39 @@ + + + + NetHack 3.7 December 19, 2020 + + + + + + NetHack Guidebook 29 + + + If your keyboard has a meta key (which, when pressed in com- bination with another key, modifies it by setting the "meta" [8th, or "high"] bit), you can invoke many extended commands by meta-ing the first letter of the command. - In Windows, OS/2, PC and ST NetHack, the "Alt" key can be - used in this fashion; on the Amiga, set the altmeta option to get - this behavior. 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+key. + 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 fol- + lowed by the other key, you may set the altmeta option to have + NetHack combine them into meta+key. (This combining action only + takes place when NetHack is expecting a command to execute, not + when accepting input to name something 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 low- + er-case equivalent is used for another command, so the three key + combination meta+shift+letter is needed. + M-? #? (not supported by all platforms) @@ -1773,19 +1879,6 @@ M-a #adjust - - - - NetHack 3.7 July 9, 2020 - - - - - - NetHack Guidebook 28 - - - M-A #annotate M-c #chat @@ -1812,6 +1905,19 @@ M-O #overview + + + + NetHack 3.7 December 19, 2020 + + + + + + NetHack Guidebook 30 + + + M-p #pray M-q #quit @@ -1832,6 +1938,8 @@ M-w #wipe + M-X #exploremode + If the number_pad option is on, some additional letter com- @@ -1839,19 +1947,6 @@ h #help - - - - NetHack 3.7 July 9, 2020 - - - - - - NetHack Guidebook 29 - - - j #jump k #kick @@ -1876,6 +1971,19 @@ tions. Mapping magic reveals secret corridors, so converts them into ordinary corridors and shows them as such. + + + + NetHack 3.7 December 19, 2020 + + + + + + NetHack Guidebook 31 + + + 5.1. Doorways Doorways connect rooms and corridors. Some doorways have no @@ -1906,18 +2014,6 @@ Some closed doors are booby-trapped and will explode if an attempt is made to open (when unlocked) or unlock (when locked) - - - NetHack 3.7 July 9, 2020 - - - - - - NetHack Guidebook 30 - - - 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 @@ -1939,6 +2035,21 @@ in all ways equivalent to normal doors. Mapping magic does not reveal secret doors. + + + + + + NetHack 3.7 December 19, 2020 + + + + + + NetHack Guidebook 32 + + + 5.2. Traps (`^') There are traps throughout the dungeon to snare the unwary @@ -1971,23 +2082,11 @@ always below the current level. Usually that will be the next level down but it can be farther. All of these traps choose a new destination each time they're activated. Magic portals also - send you to a different level but behave differently. Some - - - NetHack 3.7 July 9, 2020 - - - - - - NetHack Guidebook 31 - - - - 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 necessarily - to a specific location there. + send you to a different level but behave differently. Some por- + tals 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 necessarily 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." @@ -2005,6 +2104,18 @@ access to that spot. With careful foresight, it is possible to complete all of the levels according to the traditional rules of Sokoban. (Hint: to solve Sokoban puzzles, you often need to move + + + NetHack 3.7 December 19, 2020 + + + + + + NetHack Guidebook 33 + + + 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. @@ -2038,18 +2149,6 @@ levels, from a template for some "special" levels, or loaded from the remains of an earlier game for a "bones" level as briefly de- scribed below). Monsters are only active on the current level; - - - NetHack 3.7 July 9, 2020 - - - - - - NetHack Guidebook 32 - - - those on other levels are essentially placed into stasis. Ordinarily when you climb a set of stairs, you will arrive @@ -2070,109 +2169,10 @@ 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 us- - ing the "#chat" command while standing on it. Using an item pri- - or 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 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 shopkeeper 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 have to buy it back if you want to reclaim it. - - Shopkeepers sometimes 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 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 use it in shops; shopkeepers will - not accept it.) - - The `$' command, which reports the amount of gold you are - carrying (in inventory, not inside bags or boxes), will also show - current shop debt or credit, if any. The "Iu" command lists un- - paid items (those which still belong to the shop) if you are car- - rying any. The "Ix" command shows an inventory-like display of - any unpaid items which have been used up, along with other shop - fees, if any. + ing the "#chat" command while standing on it. Using an item - - - - - NetHack 3.7 July 9, 2020 - - - - - - NetHack Guidebook 33 - - - - 5.4.1. Shop idiosyncrasies - - Several aspects of shop behavior might be unexpected. - - * 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 were outside the shop. - - * While the shopkeeper watches you like a hawk, he will generally - ignore any other customers. - - * 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 inven- - tory depletion. - - 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 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 no matter how big a pile is. Note that the num- - ber refers to the count of separate stacks of objects present - rather than the sum of the quantities of those stacks (so 7 ar- - rows 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 loca- - tion). - - The "nopickup" command prefix (default `m') can be used be- - fore 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 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 any- - thing unless it is covered by one or more objects so is obscured - on the map. Setting this option to true will describe such - - - NetHack 3.7 July 9, 2020 + NetHack 3.7 December 19, 2020 @@ -2182,34 +2182,161 @@ - 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 + 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 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 shopkeeper 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 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 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 use it in shops; shopkeepers will + not accept it.) + + The `$' command, which reports the amount of gold you are + carrying (in inventory, not inside bags or boxes), will also show + current shop debt or credit, if any. The "Iu" command lists un- + paid items (those which still belong to the shop) if you are car- + rying any. The "Ix" command shows an inventory-like display of + any unpaid items which have been used up, along with other shop + fees, if any. + + 5.4.1. Shop idiosyncrasies + + Several aspects of shop behavior might be unexpected. + + * 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 were outside the shop. + + * While the shopkeeper watches you like a hawk, he or she will + generally ignore any other customers. + + * 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 inven- + tory depletion. + + 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 + + + NetHack 3.7 December 19, 2020 + + + + + + NetHack Guidebook 35 + + + + 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 no matter how big a pile is. Note that the num- + ber refers to the count of separate stacks of objects present + rather than the sum of the quantities of those stacks (so 7 ar- + rows 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 loca- + tion). + + The "nopickup" command prefix (default `m') can be used be- + fore 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 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 any- + thing 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 ob- + Moving off of any of those back onto "normal" terrain will give + one message too, unless there is feedback about one or more ob- jects, in which case the back on land circumstance is implied. - 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 + 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 + 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 at- - tack (see the Fighting subsection of Monsters below). The - "fight" command prefix (default `F'; also `-' if number_pad is + tack (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 attacking a peaceful or tame + monster is or when deliberately attacking a peaceful or tame creature. + + NetHack 3.7 December 19, 2020 + + + + + + NetHack Guidebook 36 + + + The run_mode option controls how frequently the map gets re- drawn 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 dungeon) is a tribute to the ancestor game hack's inspira- + tion rogue. + + It is usually displayed differently from other levels: pos- + sibly 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 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 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. @@ -2237,21 +2364,22 @@ business unless you attack them. Some of them are very dangerous when angered. Remember: discretion is the better part of valor. - - NetHack 3.7 July 9, 2020 - - - - - - NetHack Guidebook 35 - - - In most circumstances, if you attempt to attack a peaceful monster by moving into its location, you'll be asked to confirm your intent. By default an answer of `y' acknowledges that in- tent, which can be error prone if you're using `y' to move. You + + + NetHack 3.7 December 19, 2020 + + + + + + NetHack Guidebook 37 + + + can set the paranoid_confirmation option to require a response of "yes" instead. @@ -2302,21 +2430,22 @@ riding, in the same manner as you would move yourself. It is the beast that you will see displayed on the map. - - - NetHack 3.7 July 9, 2020 - - - - - - NetHack Guidebook 36 - - - Riding skill is managed by the "#enhance" command. See the section on Weapon proficiency for more information about that. + + + + NetHack 3.7 December 19, 2020 + + + + + + NetHack Guidebook 38 + + + Use the `a' (apply) command and pick a saddle in your inven- tory to attempt to put that saddle on an adjacent creature. If successful, it will be transferred to that creature's inventory. @@ -2368,141 +2497,12 @@ As you add items to your inventory, you also add the weight of that object to your load. The amount that you can carry de- pends on your strength and your constitution. The stronger and - - - NetHack 3.7 July 9, 2020 - - - - - - NetHack Guidebook 37 - - - sturdier you are, the less the additional load will affect you. There comes a point, though, when the weight of all of that stuff - you are carrying around with you through the dungeon will encum- - ber you. Your reactions will get slower and you'll burn calories - faster, requiring food more frequently to cope with it. Eventu- - ally, you'll be so overloaded that you'll either have to discard - some of what you're carrying or collapse under its weight. - - 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 display. - - When you pick up an object, it is assigned an inventory let- - ter. 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 pre- - sented with a list of inventory letters to choose from (see Com- - mands, above). - - Some objects, such as weapons, are easily differentiated. - Others, 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 - 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 in- - stead 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 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 en- - chantments that make them less effective in combat. Other cursed - objects may act poorly or detrimentally in other ways. - - Objects can also be blessed. Blessed items usually work - better or more beneficially than normal uncursed items. For ex- - ample, a blessed weapon will do more damage against demons. - - 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 + you are carrying around with you through the dungeon will - NetHack 3.7 July 9, 2020 - - - - - - NetHack Guidebook 38 - - - - 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 - 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. - - An item with unknown status will be reported in your inven- - tory with no prefix. An item which you know the state of will be - distinguished 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 information is displayed. The implicit_uncursed op- - tion can be used to control this; toggle it off to have "un- - cursed" be displayed even when that can be deduced from other at- - tributes. - - 7.2. Weapons (`)') - - Given a chance, most monsters in the Mazes of Menace will - gratuitously 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 normally 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 cross- - bow 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 weapon's enchantment is to have it magically iden- - tified somehow. Most 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 (en- - chantment and/or erosion), experience level, strength, dexterity, - encumbrance, and proficiency (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 - - - NetHack 3.7 July 9, 2020 + NetHack 3.7 December 19, 2020 @@ -2512,63 +2512,63 @@ - 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 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 simul- - taneously as primary and secondary; use the `X' command to engage - or disengage that. Only some types of characters (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. + encumber you. Your reactions will get slower and you'll burn + calories faster, requiring food more frequently to cope with it. + Eventually, you'll be so overloaded that you'll either have to + discard some of what you're carrying or collapse under its + weight. - There might be times when you'd rather not wield any weapon - at all. To accomplish that, wield `-', or else use the `A' com- - mand which allows you to unwield the current weapon in addition - to taking off other worn items. + 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 display. - 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 dam- - age to monsters 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. + When you pick up an object, it is assigned an inventory let- + ter. 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 pre- + sented with a list of inventory letters to choose from (see Com- + mands, above). - The commands to use weapons are `w' (wield), `t' (throw), - `f' (fire, an alternate way of throwing), `Q' (quiver), `x' (ex- - change), `X' (twoweapon), and "#enhance" (see below). + Some objects, such as weapons, are easily differentiated. + Others, 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. - 7.2.1. Throwing and shooting + 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 + 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 in- + stead of assigning a new one. - 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 target. The distance something can be thrown de- - pends 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. + 7.1. Curses and Blessings - 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. + 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 en- + chantments that make them less effective in combat. Other cursed + objects may act poorly or detrimentally in other ways. - Some characters have the ability to fire a volley of multi- - ple items in a single turn. 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 + 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 uncursed. They could just as easily have been described as + unblessed, but the uncursed designation is what you will see + within the game. A "glass half full versus glass half empty" - NetHack 3.7 July 9, 2020 + NetHack 3.7 December 19, 2020 @@ -2578,63 +2578,63 @@ - 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 example, "2f" (or "n2f" if using num- - ber_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 speci- - fied. Once the volley is in motion, all of the items will travel - in the same direction; if the first ones kill a monster, the oth- - ers can still continue beyond that spot. + situation; make of that what you will. - 7.2.2. Weapon proficiency + 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. - You will have varying degrees of skill in the weapons avail- - able. Weapon proficiency, or weapon skills, affect how well you - can use particular types of weapons, and you'll be able to im- - prove your skills as you progress through a game, depending on - your role, your experience level, and use of the weapons. + An item with unknown status will be reported in your inven- + tory with no prefix. An item which you know the state of will be + distinguished 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 information is displayed. The implicit_uncursed op- + tion can be used to control this; toggle it off to have uncursed + be displayed even when that can be deduced from other attributes. - 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. + 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.) - 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" (some- - times also referred to as "restricted", because you won't be able - to advance), "unskilled", "basic", "skilled", and "expert". Re- - stricted skills simply will not appear in the list shown by "#en- - hance". (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". + 7.2. Weapons (`)') - 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 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 to- - tal overall skills, so you need to actively choose which skills - to enhance and which to ignore. + Given a chance, most monsters in the Mazes of Menace will + gratuitously 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 normally 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 cross- + bow 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 weapon's enchantment is to have it magically iden- + tified somehow. Most 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 (en- + chantment and/or erosion), experience level, strength, dexterity, + encumbrance, and proficiency (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 - NetHack 3.7 July 9, 2020 + NetHack 3.7 December 19, 2020 @@ -2644,63 +2644,63 @@ - 7.2.3. Two-Weapon combat + vulnerable to certain types of weapons. - 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" com- - mand. 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 sec- - ondary is just an item in your inventory that's been designated - as alternate weapon.) + 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 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 simul- + taneously as primary and secondary; use the `X' command to engage + or disengage that. Only some types of characters (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. - 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 secondary, swap it to off hand, and then - wield the primary. + There might be times when you'd rather not wield any weapon + at all. To accomplish that, wield `-', or else use the `A' com- + mand which allows you to unwield the current weapon in addition + to taking off other worn items. - The whole process can be simplified via use of the push- - weapon option. When it is enabled, then using `w' to wield some- - thing causes the currently wielded weapon to become your alter- - nate 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 posi- - tion. + 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 dam- + age to monsters 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. - When in two-weapon combat mode, using the `X' command tog- - gles back to single-weapon mode. Throwing or dropping either of - the weapons or having one of them be stolen or destroyed will al- - so make you revert to single-weapon combat. + The commands to use weapons are `w' (wield), `t' (throw), + `f' (fire, an alternate way of throwing), `Q' (quiver), `x' (ex- + change), `X' (twoweapon), and "#enhance" (see below). - 7.3. Armor (`[') + 7.2.1. Throwing and shooting - Lots of unfriendly things lurk about; you need armor to pro- - tect yourself from their blows. Some types of armor offer better - protection than others. Your armor class is a measure of this - protection. Armor class (AC) is measured as in AD&D, with 10 be- - ing 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. + 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 target. The distance something can be thrown de- + pends 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. - 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 + 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. + + Some characters have the ability to fire a volley of multi- + ple items in a single turn. Knowing how to load several rounds + of ammunition at once--or hold several missiles in your hand--and - - NetHack 3.7 July 9, 2020 + NetHack 3.7 December 19, 2020 @@ -2710,63 +2710,63 @@ - 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 + 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 wield- + ing 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 lim- + it 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 shoot- + ing 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. - 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 corrosion to suits worn un- - der them and against some monster touch attacks. + 7.2.2. Weapon proficiency - 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 immediately find out the armor class and any - "plusses" it provides. Cursed pieces of armor usually have nega- - tive enchantments (minuses) in addition to being unremovable. + You will have varying degrees of skill in the weapons avail- + able. Weapon proficiency, or weapon skills, affect how well you + can use particular types of weapons, and you'll be able to im- + prove your skills as you progress through a game, depending on + your role, your experience level, and use of the weapons. - Many types of armor are subject to some kind of damage like - rust. Such damage can be repaired. Some types of armor may in- - hibit spell casting. + 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 nudist option can be set (prior to game start) to at- - tempt to play the entire game without wearing any armor (a self- - imposed challenge which is extremely difficult to accomplish). + 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" (some- + times also referred to as "restricted", because you won't be able + to advance), "unskilled", "basic", "skilled", and "expert". Re- + stricted skills simply will not appear in the list shown by "#en- + hance". (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". - 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 nor- - mally for accessories 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 usual- - ly 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 + 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 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 - NetHack 3.7 July 9, 2020 + NetHack 3.7 December 19, 2020 @@ -2776,63 +2776,63 @@ - is "you are what you eat." + use "#enhance" to increase one or more skills. Such skills are + not increased automatically because there is a limit to your to- + tal overall skills, so you need to actively choose which skills + to enhance and which to ignore. - Some character roles and some monsters are vegetarian. Veg- - etarian monsters will typically never eat animal corpses, while - vegetarian players can, but with some rather unpleasant side-ef- - fects. + 7.2.3. Two-Weapon combat - You can name one food item after something you like to eat - with the fruit option. + 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" com- + mand. 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 sec- + ondary is just an item in your inventory that's been designated + as alternate weapon.) - The command to eat food is `e'. + 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 secondary, swap it to off hand, and then + wield the primary. - 7.5. Scrolls (`?') + The whole process can be simplified via use of the push- + weapon option. When it is enabled, then using `w' to wield some- + thing causes the currently wielded weapon to become your alter- + nate 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 posi- + tion. - 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). + When in two-weapon combat mode, using the `X' command tog- + gles back to single-weapon mode. Throwing or dropping either of + the weapons or having one of them be stolen or destroyed will al- + so make you revert to single-weapon combat. - 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 ob- - jects of subtle enchantment are difficult to identify without - these. + 7.3. Armor (`[') - 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" en- - vironment variable to the file name of your mailbox. You may al- - so 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. + Lots of unfriendly things lurk about; you need armor to pro- + tect yourself from their blows. Some types of armor offer better + protection than others. Your armor class is a measure of this + protection. Armor class (AC) is measured as in AD&D, with 10 be- + ing 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. - The command to read a scroll is `r'. - - 7.6. Potions (`!') - - 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 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 into a potion. - - The command to drink a potion is `q' (quaff). + Here is a list of the armor class values provided by suits + of armor: - - - NetHack 3.7 July 9, 2020 + NetHack 3.7 December 19, 2020 @@ -2842,63 +2842,63 @@ - 7.7. Wands (`/') + 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 + Leather armor, Orcish ring mail 8 + Leather jacket 9 + none 10 - 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, however, 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. + 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 corrosion to suits worn un- + der them and against some monster touch attacks. - When the number of charges left in a wand becomes zero, at- - tempts to use the wand will usually result in nothing happening. - Occasionally, 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. + 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 immediately find out the armor class and any + "plusses" it provides. Cursed pieces of armor usually have nega- + tive enchantments (minuses) in addition to being unremovable. - 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 cer- - tainly cause a catastrophic release of magical energies. + Many types of armor are subject to some kind of damage like + rust. Such damage can be repaired. Some types of armor may in- + hibit spell casting. - When you have fully identified a particular wand, inventory - display will include additional information in parentheses: the - number of times it has been recharged followed by a colon and - then by its current number of charges. A current charge count of - -1 is a special case indicating that the wand has been cancelled. + The nudist option can be set (prior to game start) to at- + tempt to play the entire game without wearing any armor (a self- + imposed challenge which is extremely difficult to accomplish). - The command to use a wand is `z' (zap). To break one, use - the `a' (apply) command. + 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 nor- + mally for accessories 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.8. Rings (`=') + 7.4. Food (`%') - Rings are very useful items, since they are relatively per- - manent magic, unlike the usually fleeting effects of potions, - scrolls, and wands. - - 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 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 manually take them off before putting on or remov- - ing 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). - `A', `W', and `T' can also be used; see Amulets. + 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 usual- + ly stay fresh, but ice boxes are heavy, and tins take a while to + open. - - NetHack 3.7 July 9, 2020 + NetHack 3.7 December 19, 2020 @@ -2908,63 +2908,63 @@ - 7.9. Spellbooks (`+') + 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 what you eat." - 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 backfires. Reading a cursed spellbook or one with mystic - runes beyond your ken can be harmful to your health! + Some character roles and some monsters are vegetarian. Veg- + etarian monsters will typically never eat animal corpses, while + vegetarian players can, but with some rather unpleasant side-ef- + fects. - 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. + You can name one food item after something you like to eat + with the fruit option. - 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 ad- - ditional food. Casting of spells also requires practice. With - practice, your skill in each category of spell casting will im- - prove. Over time, however, your memory of each spell will dim, - and you will need to relearn it. + The command to eat food is `e'. - Some spells require a direction in which to cast them, simi- - lar to wands. To cast one at yourself, just give a `.' or `s' - for the direction. A few spells require you to pick a target lo- - cation rather than just specify a particular direction. Other - spells don't require any direction or target. + 7.5. Scrolls (`?') - 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".) + 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). - Casting a spell also requires flexible movement, and wearing - various types of armor may interfere with that. + 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 ob- + jects of subtle enchantment are difficult to identify without + these. - 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) com- - mand casts a spell. + 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" en- + vironment variable to the file name of your mailbox. You may al- + so 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. - 7.10. Tools (`(') + The command to read a scroll is `r'. - Tools are miscellaneous objects with various purposes. Some - tools have a limited number of uses, akin to wand charges. For + 7.6. Potions (`!') + + 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 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 into a potion. - NetHack 3.7 July 9, 2020 + + NetHack 3.7 December 19, 2020 @@ -2974,14 +2974,150 @@ - example, lamps burn out after a while. Other tools are contain- + 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, however, 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. + + When the number of charges left in a wand becomes zero, at- + tempts to use the wand will usually result in nothing happening. + Occasionally, 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 cer- + tainly cause a catastrophic release of magical energies. + + When you have fully identified a particular wand, inventory + display will include additional information in parentheses: the + number of times it has been recharged followed by a colon and + then by its current 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 `a' (apply) command. + + 7.8. Rings (`=') + + Rings are very useful items, since they are relatively per- + manent magic, unlike the usually fleeting effects of potions, + scrolls, and wands. + + 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 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 manually take them off before putting on or remov- + ing a ring and then re-wear them after. That's done implicitly + to avoid unnecessary tedium. + + + + + NetHack 3.7 December 19, 2020 + + + + + + NetHack Guidebook 47 + + + + 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 backfires. 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 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 within you. Casting temporarily drains your magical + power, which will slowly be recovered, and causes you to need ad- + ditional food. Casting of spells also requires practice. With + practice, your skill in each category of spell casting will im- + prove. Over time, however, your memory of each spell will dim, + and you will need to relearn it. + + Some spells require a direction in which to cast them, simi- + lar to wands. To cast one at yourself, just give a `.' or `s' + for the direction. A few spells require you to pick a target lo- + cation 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 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 + various 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 level, skill category, chance of failure when casting, and an + estimate of how strongly it is remembered. The `Z' (cast) com- + mand casts a spell. + + + + + NetHack 3.7 December 19, 2020 + + + + + + NetHack Guidebook 48 + + + + 7.10. Tools (`(') + + Tools are miscellaneous objects with various purposes. Some + tools have a limited number of uses, akin to wand charges. For + example, lamps burn out after a while. Other tools are contain- ers, 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 + 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 + 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 @@ -2992,14 +3128,14 @@ 7.10.1. Containers - You may encounter bags, boxes, and chests in your travels. - A tool of this sort can be opened with the "#loot" extended com- - mand when you are standing on top of it (that is, on the same - floor spot), or with the `a' (apply) command when you are carry- - ing it. However, chests are often locked, and are in any case - unwieldy objects. You must set one down before unlocking it by + You may encounter bags, boxes, and chests in your travels. + A tool of this sort can be opened with the "#loot" extended com- + mand when you are standing on top of it (that is, on the same + floor spot), or with the `a' (apply) command when you are carry- + ing 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' command, or by using a weapon to force + kicking it with the `^D' command, or by using a weapon to force the lock with the "#force" extended command. Some chests are trapped, causing nasty things to happen when @@ -3008,161 +3144,25 @@ 7.11. Amulets (`"') - Amulets are very similar to rings, and often more powerful. + Amulets are very similar to rings, and often more powerful. Like rings, amulets have various magical properties, some benefi- cial, 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, + 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 normally 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 + 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 normally 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. - NetHack 3.7 July 9, 2020 - - - - - - NetHack Guidebook 47 - - - - 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 projec- - tile 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 - generally heavy. It is rumored that some statues are not what - they seem. - - 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 pick-axe. 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 though. - - 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 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 de- - scribed 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 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 lo- - cation 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 ex- - ception is that if the object gets covered by the "remembered, - unseen monster" marker. When that marker is later removed after - - - NetHack 3.7 July 9, 2020 - - - - - - NetHack Guidebook 48 - - - - 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-discov- - er 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 op- - tion 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 challenges, 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 most difficult of these is the foodless challenge. Although - creatures can survive long periods of time without food, there is - a physiological need for water; thus there is no restriction on - drinking beverages, even if they provide some minor food bene- - fits. 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 animals. The primary source of nutrition is fruits and veg- - etables. 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 con- - sidered vegan food. Note however that eating such items still - counts against foodless conduct. - - Vegetarians do not eat animals; however, they are less se- - lective 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 - foodless conducts. This includes tripe rations, the corpses or - - - NetHack 3.7 July 9, 2020 + NetHack 3.7 December 19, 2020 @@ -3172,63 +3172,63 @@ - tins of any monsters not mentioned above, and the various other - chunks of meat found in the dungeon. Swallowing and digesting a - monster while polymorphed is treated as if you ate the creature's - corpse. Eating leather, dragon hide, or bone items while poly- - morphed 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. + 7.12. Gems (`*') - Regardless of conduct, there will be some items which are - indigestible, and others which are hazardous to eat. Using a - swallow-and-digest attack against a monster is equivalent to eat- - ing 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 contain milk, so they are - compatible with a vegan diet. Slime molds or player-defined - "fruits", although they could be anything from "cherries" to - "pork chops", are also assumed to be vegan. + 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. - An atheist is one who rejects religion. This means that you - cannot #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 con- - duct; 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 be- - ing 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. + Other small rocks are also categorized as gems, but they are + much less valuable. All rocks, however, can be used as projec- + tile weapons (if you have a sling). In the most desperate of + cases, you can still throw them by hand. - 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. + 7.13. Large rocks (``') - 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. + Statues and boulders are not particularly useful, and are + generally heavy. It is rumored that some statues are not what + they seem. - An illiterate character does not read or write. This in- - cludes reading a scroll, spellbook, fortune cookie message, or t- - shirt; writing 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 assumed to be learned from your - teachers prior to the start of the game and isn't counted. + 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 pick-axe. 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 though. + + 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 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 de- + scribed 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 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 lo- + cation 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 - - - NetHack 3.7 July 9, 2020 + NetHack 3.7 December 19, 2020 @@ -3238,63 +3238,63 @@ - There is a side-branch to the main dungeon called "Sokoban," - briefly described in the earlier section about Traps. As men- - tioned 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 diago- - nally. 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 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, providing 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 those ac- - tions 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 disclosed conduct even if you haven't done anything interest- - ing there. Ending the game with "never broke the Sokoban rules" - conduct is most meaningful if you also manage to perform the "ob- - tained the Sokoban prize" achievement (see Achievements below).) + more--perhaps a monster has picked it up or it has rotted away-- + until you can see or feel that location again. One notable ex- + ception is that if the object gets covered 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-discov- + er the object and resume remembering it. - There are several other challenges tracked by the game. It - is possible to eliminate one or more species of monsters by geno- - cide; 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, spell, or potion of polymorph; - avoiding these effects are each considered challenges. Polymor- - phing 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 challenge, as is a - game without wishing for an artifact (even if the artifact imme- - diately disappears). When the game offers you an opportunity to - make a wish for an item, you may choose "nothing" if you want to - decline. + The situation is the same for a pile of objects, except that + only the top item of the pile is displayed. The hilite_pile op- + tion can be enabled in order to show an item differently when it + is the top one of a pile. - 8.1. Achievements + 8. Conduct - End of game disclosure will also display various achieve- - ments 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. + 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 challenges, 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. - - Attained rank title . - Shop - Entered a shop. - Temple - Entered a temple. - Mines - Entered the Gnomish Mines. + 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 physiological need for water; thus there is no restriction on + drinking beverages, even if they provide some minor food bene- + fits. 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 animals. The primary source of nutrition is fruits and veg- + etables. 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 con- + sidered vegan food. Note however that eating such items still + counts against foodless conduct. + + Vegetarians do not eat animals; however, they are less se- + lective 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 - NetHack 3.7 July 9, 2020 + NetHack 3.7 December 19, 2020 @@ -3304,6 +3304,141 @@ + observe a vegetarian diet. + + Eating any kind of meat violates the vegetarian, vegan, and + foodless 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 polymorphed is treated as if you ate the creature's + corpse. Eating leather, dragon hide, or bone items while poly- + morphed 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 + indigestible, and others which are hazardous to eat. Using a + swallow-and-digest attack against a monster is equivalent to eat- + ing 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 contain milk, so they are + compatible with a vegan diet. Slime molds or player-defined + "fruits", although they could be anything from "cherries" to + "pork chops", are also assumed to be vegan. + + An atheist is one who rejects religion. This means that you + cannot #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 con- + duct; 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 be- + ing 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 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 in- + cludes reading a scroll, spellbook, fortune cookie message, or t- + shirt; writing 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) + + + NetHack 3.7 December 19, 2020 + + + + + + NetHack Guidebook 52 + + + + 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 men- + tioned 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 diago- + nally. 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 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, providing 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 those ac- + tions 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 disclosed conduct even if you haven't done anything interest- + ing there. Ending the game with "never broke the Sokoban rules" + conduct is most meaningful if you also manage to perform the "ob- + tained 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 geno- + cide; 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, spell, or potion of polymorph; + avoiding these effects are each considered challenges. Polymor- + phing 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 challenge, as is a + game without wishing for an artifact (even if the artifact imme- + diately disappears). When the game offers you an opportunity 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 achieve- + ments 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. + + - Attained rank title . + + + NetHack 3.7 December 19, 2020 + + + + + + NetHack Guidebook 53 + + + + Shop - Entered a shop. + Temple - Entered a temple. + Mines - Entered the Gnomish Mines. Town - Entered Mine Town. Oracle - Consulted the Oracle of Delphi. Novel - Read a passage from a Discworld Novel. @@ -3328,171 +3463,36 @@ Notes: - Achievements are recorded and subsequently reported in the - order in which they happen during your current game rather than + 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 ex- + There are nine titles for each role, bestowed at ex- perience levels 1, 3, 6, 10, 14, 18, 22, 26, and 30. The one for - experience level 1 is not recorded as an achievement. Losing - enough levels to revert to lower rank(s) does not discard the + experience level 1 is not recorded as an achievement. Losing + enough levels to revert to lower rank(s) does not discard the corresponding achievement(s). - There's no guaranteed Novel so the achievement to read one + There's no guaranteed Novel so the achievement to read one might not always be attainable (except perhaps by wishing). Sim- - ilarly, the Big Room level is not always present. Unlike with + ilarly, 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 + 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. - The Medusa achievement is recorded if she dies for any rea- - son, even if you are not directly responsible, and only if she + The Medusa achievement is recorded if she dies for any rea- + son, even if you are not directly responsible, and only if she dies. Blind and Nudist are also conducts, and they can only be en- - abled by setting the correspondingly named option in NETHACKOP- - TIONS or run-time configuration file prior to game start. In the - case of Blind, the option also enforces the conduct. They aren't - really significant accomplishments unless/until you make + abled by setting the correspondingly named option in - NetHack 3.7 July 9, 2020 - - - - - - NetHack Guidebook 52 - - - - 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 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 file, or in the NETHACKOPTIONS environment vari- - able. Some versions of NetHack also have front-end programs that - allow you to set options before starting the game or a global - configuration for system administrators. - - 9.2. Using a configuration file - - The default name of the configuration file varies on differ- - ent operating systems. - - On UNIX, Linux, and Mac OS X it is ".nethackrc" in the us- - er'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, it is ".nethackrc" in the folder "\%USERPRO- - FILE%\NetHack\3.6". The file may not exist, but it is a normal - ASCII text file can can be created with any text editor. After - running NetHack for the first time, you should find a default - template for the configuration file named ".nethackrc.template" - in "\%USERPROFILE%\NetHack\3.6". If you had not created the con- - figuration file, NetHack will create the configuration file 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 as a comment. Empty lines are ignored. - - Any line beginning with `[' and ending in `]' is considered - a section marker. The text between the square brackets is the - section name. Lines after a section marker belong to that sec- - tion, and are ignored unless a CHOOSE statement was used to se- - lect that section. Section names are case insensitive. - - You can use different configuration statements in the file, - some of which can be used multiple times. In general, the state- - ments are written in capital letters, followed by an equals sign, - followed by settings particular to that statement. - - - - - NetHack 3.7 July 9, 2020 - - - - - - NetHack Guidebook 53 - - - - Here is a list of allowed statements: - - OPTIONS - There are two types of options, boolean and compound options. - Boolean options toggle a setting on or off, while compound op- - tions 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 per- - sistent, and apply only to new games. You can specify multiple - OPTIONS statements, and multiple options separated by commas in - a single OPTIONS statement. (Comma separated options are pro- - cessed from right to left.) - - Example: - - OPTIONS=dogname:Fido - OPTIONS=!legacy,autopickup,pickup_types:$"=/!?+ - - HACKDIR - Default location of files NetHack needs. On Windows HACKDIR - defaults to the location of the NetHack.exe or NetHackw.exe - file so setting HACKDIR to override that is not usually neces- - sary or recommended. - - LEVELDIR - 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 be writable. - - BONESDIR - The location that bones files are kept. Defaults to HACKDIR, - must be writable. - - LOCKDIR - The location that file synchronization locks are stored. - Defaults to HACKDIR, must be writable. - - TROUBLEDIR - The location that a record of game aborts and self-diagnosed - game problems is kept. Defaults to HACKDIR, must be writable. - - AUTOCOMPLETE - Enable or disable an extended command autocompletion. Autocom- - pletion has no effect for the X11 windowport. You can specify - multiple autocompletions. To enable autocompletion, list the - extended command. Prefix the command with "!" to disable the - autocompletion for that command. - - Example: - - AUTOCOMPLETE=zap,!annotate - - - NetHack 3.7 July 9, 2020 + NetHack 3.7 December 19, 2020 @@ -3502,14 +3502,152 @@ + NETHACKOPTIONS or run-time configuration file prior to game + start. In the case of Blind, the option also enforces the con- + duct. They aren't really significant accomplishments unless/un- + til 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 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 file, or in the NETHACKOPTIONS environment vari- + able. Some versions of NetHack also have front-end programs that + allow you to set options before starting the game or a global + configuration for system administrators. + + 9.2. Using a configuration file + + The default name of the configuration file varies on differ- + ent operating systems. + + On UNIX, Linux, and Mac OS X it is ".nethackrc" in the us- + er'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, it is ".nethackrc" in the folder "\%USERPRO- + FILE%\NetHack\3.6". The file may not exist, but it is a normal + ASCII text file can can be created with any text editor. After + running NetHack for the first time, you should find a default + template for the configuration file named ".nethackrc.template" + in "\%USERPROFILE%\NetHack\3.6". If you had not created the con- + figuration file, NetHack will create the configuration file 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 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 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 insensi- + tive. Lines after a section marker belong to that section up un- + til another section starts or a marker without a name is encoun- + tered or the file ends. Lines within sections are ignored unless + a CHOOSE directive has selected that section. + + + NetHack 3.7 December 19, 2020 + + + + + + NetHack Guidebook 55 + + + + You can use different configuration directives in the file, + some of which can be used multiple times. In general, the direc- + tives 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. + Boolean options toggle a setting on or off, while compound op- + tions 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 per- + sistent, and apply only to new games. You can specify multiple + OPTIONS directives, and multiple options separated by commas in + a single OPTIONS directive. (Comma separated options are pro- + cessed from right to left.) + + Example: + + OPTIONS=dogname:Fido + OPTIONS=!legacy,autopickup,pickup_types:$"=/!?+ + + HACKDIR + Default location of files NetHack needs. On Windows HACKDIR + defaults to the location of the NetHack.exe or NetHackw.exe + file so setting HACKDIR to override that is not usually neces- + sary or recommended. + + LEVELDIR + 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 be writable. + + BONESDIR + The location that bones files are kept. Defaults to HACKDIR, + must be writable. + + LOCKDIR + The location that file synchronization locks are stored. + Defaults to HACKDIR, must be writable. + + TROUBLEDIR + The location that a record of game aborts and self-diagnosed + game problems is kept. Defaults to HACKDIR, must be writable. + + AUTOCOMPLETE + Enable or disable an extended command autocompletion. Autocom- + pletion has no effect for the X11 windowport. You can specify + multiple autocompletions. To enable autocompletion, list the + extended command. Prefix the command with "!" to disable the + + + NetHack 3.7 December 19, 2020 + + + + + + NetHack Guidebook 56 + + + + autocompletion for that command. + + Example: + + AUTOCOMPLETE=zap,!annotate + AUTOPICKUP_EXCEPTION - Set exceptions to the pickup_types option. See the "Configur- + Set exceptions to the pickup_types option. See the "Configur- ing Autopickup Exceptions" section. BINDINGS - Change the key bindings of some special keys, menu accelera- + Change the key bindings of some special keys, menu accelera- tors, or extended commands. You can specify multiple bindings. - Format is key followed by the command, separated by a colon. + Format is key followed by the command, separated by a colon. See the "Changing Key Bindings" section for more information. Example: @@ -3517,8 +3655,8 @@ BIND=^X:getpos.autodescribe CHOOSE - Chooses at random one of the comma-separated parameters as an - active section name. Lines in other sections are ignored. + Chooses at random one of the comma-separated parameters as an + active section name. Lines in other sections are ignored. Example: @@ -3528,6 +3666,13 @@ OPTIONS=role:arc,race:dwa,align:law,gender:fem [char B] OPTIONS=role:wiz,race:elf,align:cha,gender:mal + [] #end of CHOOSE + OPTIONS=!rest_on_space + + If [] is present, the preceding section is closed and no new + section begins; whatever follows will be common to all sec- + tions. Otherwise the last section extends to the end of the + options file. MENUCOLOR Highlight menu lines with different colors. See the "Configur- @@ -3542,8 +3687,20 @@ BOLS below. SOUND - Define a sound mapping. See the "Configuring User Sounds" sec- - tion. + Define a sound mapping. See the "Configuring User Sounds" + + + NetHack 3.7 December 19, 2020 + + + + + + NetHack Guidebook 57 + + + + section. SOUNDDIR Define the directory that contains the sound files. See the @@ -3556,18 +3713,6 @@ Example: - - - NetHack 3.7 July 9, 2020 - - - - - - NetHack Guidebook 55 - - - # replace small punctuation (tick marks) with digits SYMBOLS=S_boulder:0,S_golem:7 @@ -3608,8 +3753,20 @@ 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, and turn it off by typing a `!' or "no" be- - fore the name. Others take a character string as a value. You + option to the list, and turn it off by typing a `!' or "no" + + + NetHack 3.7 December 19, 2020 + + + + + + NetHack Guidebook 58 + + + + 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 ter- minated by the next comma or the end of string. @@ -3623,26 +3780,15 @@ in csh (note the need to escape the `!' since it's special to that shell), or the pair of commands - - NetHack 3.7 July 9, 2020 - - - - - - NetHack Guidebook 56 - - - $ NETHACKOPTIONS="color,!leg,name:Blue Meanie,fruit:lime" $ export NETHACKOPTIONS in sh, ksh, or bash. The NETHACKOPTIONS value is effectively the same as a single - OPTIONS statement in a configuration file. The "OPTIONS=" prefix + 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 statements such as BIND or + to left. Other types of configuration directives such as BIND or MSGTYPE are not allowed. Instead of a comma-separated list of options, NETHACKOPTIONS @@ -3675,6 +3821,17 @@ ment from being picked randomly. Cannot be set with the `O' command. Persistent. + + NetHack 3.7 December 19, 2020 + + + + + + NetHack Guidebook 59 + + + autodescribe Automatically describe the terrain under cursor when asked to get a location on the map (default true). The whatis_coord op- @@ -3688,18 +3845,6 @@ Walking into a closed door attempts to open it (default true). Persistent. - - - NetHack 3.7 July 9, 2020 - - - - - - NetHack Guidebook 57 - - - autopickup Automatically pick up things onto which you move (default on). Persistent. See pickup_types to refine the behavior. @@ -3741,6 +3886,18 @@ Synonym for "role" to pick the type of your character (for ex- ample "character:Monk"). See role for more details. + + + NetHack 3.7 December 19, 2020 + + + + + + NetHack Guidebook 60 + + + checkpoint Save game state after each level change, for possible recovery after program crash (default on). Persistent. @@ -3754,18 +3911,6 @@ new players if it detects some anticipated mistakes (default on). - - - NetHack 3.7 July 9, 2020 - - - - - - NetHack Guidebook 58 - - - confirm Have user confirm attacks on pets, shopkeepers, and other peaceable creatures (default on). Persistent. @@ -3807,6 +3952,18 @@ answering `y' rather than `a', will default to showing monsters in the traditional order, from high level to low level. + + + NetHack 3.7 December 19, 2020 + + + + + + NetHack Guidebook 61 + + + Omitted categories are implicitly added with `n' prefix. Spec- ified categories with omitted prefix implicitly use `+' prefix. Order of the disclosure categories does not matter, program @@ -3819,21 +3976,9 @@ and default to no, and overview to disclose without prompting. Note that the vanquished monsters list includes all monsters - killed by traps and each other as well as by you. And the - - - NetHack 3.7 July 9, 2020 - - - - - - NetHack Guidebook 59 - - - - dungeon overview shows all levels you had visited but does not - reveal things about them that you hadn't discovered. + killed by traps and each other as well as by you. And the dun- + geon overview shows all levels you had visited but does not re- + veal things about them that you hadn't discovered. dogname Name your starting dog (for example "dogname:Fang"). Cannot be @@ -3873,6 +4018,18 @@ gender Your starting gender (gender:male or gender:female). You may + + + NetHack 3.7 December 19, 2020 + + + + + + NetHack Guidebook 62 + + + specify just the first letter. Although you can still denote your gender using the "male" and "female" options, the "gender" option will take precedence. The default is to randomly pick @@ -3886,18 +4043,6 @@ when "on") or U (known to be uncursed, when "off", the de- fault). Gold is never blessed or cursed, but it is not de- scribed as "uncursed" even when the implicit_uncursed option is - - - NetHack 3.7 July 9, 2020 - - - - - - NetHack Guidebook 60 - - - "off". help @@ -3939,6 +4084,18 @@ horsename Name your starting horse (for example "horsename:Trigger"). + + + NetHack 3.7 December 19, 2020 + + + + + + NetHack Guidebook 63 + + + Cannot be set with the `O' command. ignintr @@ -3952,18 +4109,6 @@ If you use menu coloring, you may want to turn this off. - - - NetHack 3.7 July 9, 2020 - - - - - - NetHack Guidebook 61 - - - legacy Display an introductory message when starting the game (default on). Persistent. @@ -4005,6 +4150,18 @@ lowing: traditional, combination, full, or partial. Tradi- tional was the only interface available for early versions; it consists of a prompt for object class characters, followed by + + + NetHack 3.7 December 19, 2020 + + + + + + NetHack Guidebook 64 + + + 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 ob- @@ -4018,18 +4175,6 @@ Menu character accelerator to deselect all items in a menu. Implemented by the Amiga, Gem, X11 and tty ports. Default `-'. - - - NetHack 3.7 July 9, 2020 - - - - - - NetHack Guidebook 62 - - - menu_deselect_page Menu character accelerator to deselect all items on this page of a menu. Implemented by the Amiga, Gem and tty ports. De- @@ -4070,6 +4215,19 @@ to the right edge of the screen. Only for the tty port. (de- fault on) + + + + NetHack 3.7 December 19, 2020 + + + + + + NetHack Guidebook 65 + + + menu_previous_page Menu character accelerator to goto the previous menu page. Im- plemented by the Amiga, Gem and tty ports. Default `<'. @@ -4084,18 +4242,6 @@ menu_select_page Menu character accelerator to select all items on this page of - - - NetHack 3.7 July 9, 2020 - - - - - - NetHack Guidebook 63 - - - a menu. Implemented by the Amiga, Gem and tty ports. Default `,'. @@ -4136,6 +4282,18 @@ 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 + + + NetHack 3.7 December 19, 2020 + + + + + + NetHack Guidebook 66 + + + 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 @@ -4149,19 +4307,6 @@ nudist Start the character with no armor (default false). Persistent. - - - - NetHack 3.7 July 9, 2020 - - - - - - NetHack Guidebook 64 - - - null Send padding nulls to the terminal (default on). Persistent. @@ -4203,6 +4348,18 @@ stead of accepting any non-yes response as no quit - require "yes" rather than `y' to confirm quitting the game or switching into non-scoring explore + + + NetHack 3.7 December 19, 2020 + + + + + + NetHack Guidebook 67 + + + mode; die - require "yes" rather than `y' to confirm dying (not useful in normal play; applies to explore @@ -4216,18 +4373,6 @@ eating - require "yes" rather than `y' to confirm whether to continue eating; Were-change - require "yes" rather than `y' to confirm changing - - - NetHack 3.7 July 9, 2020 - - - - - - NetHack Guidebook 65 - - - form due to lycanthropy when hero has polymorph control; pray - require `y' to confirm an attempt to pray rather @@ -4268,6 +4413,19 @@ three, depending upon terminal hardware or terminal emulation software. + + + + NetHack 3.7 December 19, 2020 + + + + + + NetHack Guidebook 68 + + + Currently multiple highlight-style letters can be combined by simply stringing them together (for example, "bk"), but in the future they might require being separated by plus signs (such @@ -4282,18 +4440,6 @@ "horse", and "none". If the choice is not allowed for the role you are currently playing, it will be silently ignored. For example, "horse" will only be honored when playing a knight. - - - NetHack 3.7 July 9, 2020 - - - - - - NetHack Guidebook 66 - - - Cannot be set with the `O' command. pickup_burden @@ -4334,6 +4480,18 @@ pushweapon Using the `w' (wield) command when already wielding something + + + NetHack 3.7 December 19, 2020 + + + + + + NetHack Guidebook 69 + + + pushes the old item into your alternate weapon slot (default off). Likewise for the `a' (apply) command if it causes the applied item to become wielded. Persistent. @@ -4347,19 +4505,6 @@ objects or monsters is less intrusive. Default is off. Per- sistent. - - - - NetHack 3.7 July 9, 2020 - - - - - - NetHack Guidebook 67 - - - race Selects your race (for example, "race:human"). Default is ran- dom. If you prefix the value with `!' or "no", you will ex- @@ -4400,8 +4545,20 @@ 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 ac- - tual results of moving. The default is "run"; versions prior + This option only affects the game's screen display, not the + + + NetHack 3.7 December 19, 2020 + + + + + + NetHack Guidebook 70 + + + + 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. Persistent. @@ -4410,25 +4567,17 @@ Prevent you from (knowingly) attacking your pets (default on). Persistent. + safe_wait + Prevents you from waiting or searching when next to a hostile + monster (default on). Persistent. + sanity_check Evaluate monsters, objects, and map prior to each turn (default off). Debug mode only. - - - NetHack 3.7 July 9, 2020 - - - - - - NetHack Guidebook 68 - - - 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 + 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. @@ -4437,9 +4586,9 @@ off). Persistent. showrace - Display yourself as the glyph for your race, rather than the - glyph for your role (default off). Note that this setting af- - fects only the appearance of the display, not the way the game + Display yourself as the glyph for your race, rather than the + glyph for your role (default off). Note that this setting af- + fects only the appearance of the display, not the way the game treats you. Persistent. showscore @@ -4449,68 +4598,100 @@ silent Suppress terminal beeps (default on). Persistent. + sortdiscoveries + Controls the sorting behavior for the output of the `\' and ``' + commands. Persistent. + + The possible values are: + + 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 fully identified types; + c - list by class, alphabetically within each class; + + + NetHack 3.7 December 19, 2020 + + + + + + NetHack Guidebook 71 + + + + a - list alphabetically across all classes. + + 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 #loot commands and some others. Persistent. The possible - values are: + 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, + 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. + none - show lists the traditional way without sorting; default. sortpack - Sort the pack contents by type when displaying inventory (de- + Sort the pack contents by type when displaying inventory (de- fault on). Persistent. sparkle Display a sparkly effect when a monster (including yourself) is - hit by an attack to which it is resistant (default on). Per- + hit by an attack to which it is resistant (default on). Per- sistent. standout Boldface monsters and "--More--" (default off). Persistent. statushilites - Controls how many turns status hilite behaviors highlight the - field. If negated or set to zero, disables status hiliting. + Controls how many turns status hilite behaviors highlight the + field. If negated or set to zero, disables status hiliting. See "Configuring 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). - - - NetHack 3.7 July 9, 2020 - - - - - - NetHack Guidebook 69 - - - suppress_alert - This option may be set to a NetHack version level to suppress - alert notification messages about feature changes for that and + This option may be set to a NetHack version level to suppress + alert notification messages about feature changes for that and prior versions (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 "symset:default" to explicitly select the default + 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 "symset:default" to explicitly select the default symbols. time - Show the elapsed game time in turns on bottom line (default + Show the elapsed game time in turns on bottom line (default off). Persistent. timed_delay - When pausing momentarily for display effect, such as with ex- - plosions and moving objects, use a timer rather than sending - extra characters to the screen. (Applies to "tty" interface + When pausing momentarily for display effect, such as with + + + NetHack 3.7 December 19, 2020 + + + + + + NetHack Guidebook 72 + + + + explosions and moving objects, use a timer rather than sending + extra characters to the screen. (Applies to "tty" interface only; "X11" interface always uses a timer based delay. The de- fault is on if configured into the program.) Persistent. @@ -4520,44 +4701,30 @@ toptenwin Put the ending display in a NetHack window instead of on stdout - (default off). Setting this option makes the score list visi- - ble when a windowing version of NetHack is started without a - parent window, but it no longer leaves the score list around + (default off). Setting this option makes the score list visi- + ble 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 terminal or emulating window. travel Allow the travel command via mouse click (default on). Turning this option off will prevent the game from attempting unintend- - ed moves if you make inadvertent mouse clicks on the map win- - dow. Does not affect traveling via the `_' ("#travel") com- + ed moves if you make inadvertent mouse clicks on the map win- + dow. Does not affect traveling via the `_' ("#travel") com- mand. Persistent. verbose - Provide more commentary during the game (default on). Persis- + Provide more commentary during the game (default on). Persis- tent. whatis_coord - When using the `/' or `;' commands to look around on the map - with autodescribe on, display coordinates after the descrip- - tion. Also works in other situations where you are asked to + When using the `/' or `;' commands to look around on the map + with autodescribe on, display coordinates after the descrip- + tion. Also works in other situations where you are asked to pick a location. The possible settings are: - - - - - NetHack 3.7 July 9, 2020 - - - - - - NetHack Guidebook 70 - - - c - compass ("east" or "3s" or "2n,4w"); f - full compass ("east" or "3south" or "2north,4west"); m - map (map column x=0 is not used); @@ -4570,183 +4737,16 @@ whatis_filter When getting a location on the map, and using the keys to cycle - through next and previous targets, allows filtering the possi- + through next and previous targets, allows filtering the possi- ble 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 were last moving towards. - - Filtering can also be changed when getting a location with the - "getpos.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 de- - pends 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 op- - tions. 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. - - - NetHack 3.7 July 9, 2020 - - - - - - NetHack Guidebook 71 - - - - 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 adjust- - ing 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 right). - - ascii_map - If NetHack can, it should display an ascii character map if it - can. - - color - If NetHack can, it should display color if it can for different - monsters, objects, and dungeon features. - - eight_bit_tty - If NetHack can, it should pass eight-bit character values (for - example, specified with the traps option) straight through to - your terminal (default off). - - font_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 windows. - - font_message - If NetHack can, it should use a font by the chosen name for the - message window. - - - - - NetHack 3.7 July 9, 2020 - - - - - - NetHack Guidebook 72 - - - - font_status - If NetHack can, it should use a font by the chosen name for the - status window. - - font_text - If NetHack can, it should use a font by the chosen name for - text windows. - - font_size_map - If NetHack can, it should use this size font for the map win- - dow. - - font_size_menu - If NetHack can, it should use this size font for menu windows. - - font_size_message - If NetHack can, it should use this size font for the message - window. - - font_size_status - If NetHack can, it should use this size font for the status - window. - - font_size_text - If NetHack can, it should use this size font for text windows. - - fullscreen - If NetHack can, it should try and display on the entire screen - rather than in a window. - - guicolor - Use color text and/or highlighting attributes when displaying - some non-map data (such as menu selector letters). Curses in- - terface only; default is on. - - large_font - If NetHack can, it should use a large font. - - map_mode - If NetHack can, it should display the map in the manner speci- - fied. - - player_selection - 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 exam- - ple, in the protected mode MS-DOS version, control whether - tiles get pre-loaded into RAM at the start of the game. Doing - so enhances performance of the tile graphics, but uses more - - - NetHack 3.7 July 9, 2020 + NetHack 3.7 December 19, 2020 @@ -4756,24 +4756,206 @@ + 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 + "getpos.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 de- + pends 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 op- + tions. 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 adjust- + ing 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. + + + + NetHack 3.7 December 19, 2020 + + + + + + NetHack Guidebook 74 + + + + 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 right). + + ascii_map + If NetHack can, it should display the map using simple charac- + ters (letters and punctuation) rather than tiles graphics. In + some cases, characters can be augmented with line-drawing sym- + bols; use the symset option to select a symbol set such as + DECgraphics or IBMgraphics if your display supports them. Set- + ting ascii_map to True forces tiled_map to be False. + + color + If NetHack can, it should display color if it can for different + monsters, objects, and dungeon features. + + eight_bit_tty + If NetHack can, it should pass eight-bit character values (for + example, specified with the traps option) straight through to + your terminal (default off). + + font_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 windows. + + font_message + If NetHack can, it should use a font by the chosen name for the + message window. + + font_status + If NetHack can, it should use a font by the chosen name for the + status window. + + font_text + If NetHack can, it should use a font by the chosen name for + text windows. + + font_size_map + If NetHack can, it should use this size font for the map win- + dow. + + font_size_menu + If NetHack can, it should use this size font for menu windows. + + font_size_message + If NetHack can, it should use this size font for the message + + + NetHack 3.7 December 19, 2020 + + + + + + NetHack Guidebook 75 + + + + window. + + font_size_status + If NetHack can, it should use this size font for the status + window. + + font_size_text + If NetHack can, it should use this size font for text windows. + + fullscreen + If NetHack can, it should try and display on the entire screen + rather than in a window. + + guicolor + Use color text and/or highlighting attributes when displaying + some non-map data (such as menu selector letters). Curses in- + terface only; default is on. + + large_font + If NetHack can, it should use a large font. + + map_mode + If NetHack can, it should display the map in the manner speci- + fied. + + player_selection + 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 exam- + ple, in the protected mode MS-DOS version, control whether + tiles get pre-loaded into RAM at the start of the game. Doing + so enhances performance of the tile graphics, but uses more memory. (default on). Cannot be set with the `O' command. scroll_amount - If NetHack can, it should scroll the display by this number of + If NetHack can, it should scroll the display by this number of cells when the hero reaches the scroll_margin. scroll_margin - If NetHack can, it should scroll the display when the hero or - cursor is this number of cells away from the edge of the win- + If NetHack can, it should scroll the display when the hero or + cursor is this number of cells away from the edge of the win- dow. selectsaved - If NetHack can, it should display a menu of existing saved + If NetHack can, it should display a menu of existing saved games for the player to choose from at game startup, if it can. Not all ports support this option. + + + + NetHack 3.7 December 19, 2020 + + + + + + NetHack Guidebook 76 + + + softkeyboard - Display an onscreen keyboard. Handhelds are most likely to + Display an onscreen keyboard. Handhelds are most likely to support this option. splash_screen @@ -4781,9 +4963,26 @@ it starts up (default yes). statuslines - Number of lines for traditional below-the-map status display. - Acceptable values are 2 and 3 (default is 2). Curses and tty - interfaces only. + Number of lines for traditional below-the-map status display. + Acceptable values are 2 and 3 (default is 2). + + For 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 ren- + ders 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. For Qt, + statuslines can only be set in the configuration file or via + NETHACKOPTIONS, not with the `O' command. term_cols and @@ -4793,9 +4992,6 @@ ified but will settle for smaller sizes if they are too big. Default is the current window size. - tiled_map - If NetHack can, it should display a tiled map if it can. - tile_file Specify the name of an alternative tile file to override the default. @@ -4807,58 +5003,63 @@ 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, possi- + bly augmented by line-drawing symbols). Setting tiled_map to + True forces ascii_map to be False. + + + NetHack 3.7 December 19, 2020 + + + + + + NetHack Guidebook 77 + + + use_darkgray Use bold black instead of blue for black glyphs (TTY only). - - - NetHack 3.7 July 9, 2020 - - - - - - NetHack Guidebook 74 - - - use_inverse - If NetHack can, it should display inverse when the game speci- + If NetHack can, it should display inverse when the game speci- fies it. vary_msgcount - If NetHack can, it should display this number of messages at a + 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 in- + Whether to draw boxes around the map, status area, message + area, and persistent inventory window if enabled. Curses in- terface 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) - (The 26x82 size threshold for `2' refers to number of rows and - columns of the display. A width of at least 110 columns + (The 26x82 size threshold for `2' refers to number of rows and + columns of the display. A width of at least 110 columns (80+2+26+2) is needed for align_status set to left or right.) windowcolors - If NetHack can, it should display windows with the specified + If NetHack can, it should display windows with the specified foreground/background colors. Windows GUI only. The format is OPTION=windowcolors:wintype foreground/background - where wintype is one of "menu", "message", "status", or - "text", and foreground and background are colors, either a hexa- - decimal \'#rrggbb', one of the named colors (black, red, green, - brown, blue, magenta, cyan, orange, brightgreen, yellow, bright- - blue, brightmagenta, brightcyan, white, trueblack, gray, purple, - silver, maroon, fuchsia, lime, olive, navy, teal, aqua), or one - of Windows UI colors (activeborder, activecaption, appworkspace, - background, btnface, btnshadow, btntext, captiontext, graytext, - greytext, highlight, highlighttext, inactiveborder, inactivecap- - tion, menu, menutext, scrollbar, window, windowframe, window- + where wintype is one of "menu", "message", "status", or + "text", and foreground and background are colors, either a hexa- + decimal \'#rrggbb', one of the named colors (black, red, green, + brown, blue, magenta, cyan, orange, brightgreen, yellow, bright- + blue, brightmagenta, brightcyan, white, trueblack, gray, purple, + silver, maroon, fuchsia, lime, olive, navy, teal, aqua), or one + of Windows UI colors (activeborder, activecaption, appworkspace, + background, btnface, btnshadow, btntext, captiontext, graytext, + greytext, highlight, highlighttext, inactiveborder, inactivecap- + tion, menu, menutext, scrollbar, window, windowframe, window- text). wraptext @@ -4867,50 +5068,50 @@ 9.6. Platform-specific Customization options - Here are explanations of options that are used by specific + Here are explanations of options that are used by specific platforms or ports to customize and change the port behavior. altkeyhandler - Select an alternate keystroke handler dll to load (Win32 tty - NetHack only). The name of the handler is specified without + Select an alternate keystroke handler dll to load (Win32 tty + NetHack only). The name of the handler is specified without + + + NetHack 3.7 December 19, 2020 + + + + + + NetHack Guidebook 78 + + + the .dll extension and without any path information. Cannot be set with the `O' command. - - - NetHack 3.7 July 9, 2020 - - - - - - NetHack Guidebook 75 - - - altmeta On Amiga, this option controls whether typing "Alt" plus anoth- er key functions as a meta-shift for that key (default on). altmeta On other (non-Amiga) 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 + 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 + 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 + 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 sec- - ond ESC to finish cancelling such a count. At other prompts a + the count by typing ESC will leave NetHack waiting for another + character to complete the two character sequence. Type a sec- + ond 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 ma- - chines with an IBM PC compatible BIOS ROM (default off, OS/2, + the keyboard (allowing the use of arrow keys to move) on ma- + chines with an IBM PC compatible BIOS ROM (default off, OS/2, PC, and ST NetHack only). flush @@ -4923,74 +5124,75 @@ (default on, Mac NetHack only). rawio - Force raw (non-cbreak) mode for faster output and more bullet- - proof 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 + Force raw (non-cbreak) mode for faster output and more bullet- + proof 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 + (Win32 tty NetHack only). May be used to alter the value of keystrokes that the operating system returns to NetHack to help - 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 state- - ments in the configuration file if needed. Cannot be set with + 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 assign- + ments in the configuration file if needed. Cannot be set with the `O' command. + + + + NetHack 3.7 December 19, 2020 + + + + + + NetHack Guidebook 79 + + + video Set the video mode used (PC NetHack only). Values are "autode- - tect", "default", "vga", or "vesa". Setting "vesa" will cause + tect", "default", "vga", or "vesa". Setting "vesa" will cause the game to display tiles, using the full capability of the VGA - - - NetHack 3.7 July 9, 2020 - - - - - - NetHack Guidebook 76 - - - - hardware. Setting "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 + hardware. Setting "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 + Set the VGA mode resolution height (MS-DOS only, with video:vesa) video_width - Set the VGA mode resolution width (MS-DOS only, with + 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' + 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 (de- fault dark normal light, PC NetHack only). If the game display - is difficult to read, try adjusting these scales; if this does - not correct the problem, try !color. Cannot be set with the + is difficult to read, try adjusting these scales; if this does + not correct the problem, try !color. Cannot be set with the `O' command. 9.7. Regular Expressions - Regular expressions are normally POSIX extended regular ex- - pressions. It is possible to compile NetHack without regular ex- - pression support on a platform where there is no regular expres- - sion library. While this is not true of any modern platform, if - your NetHack was built this way, patterns are instead glob pat- + Regular expressions are normally POSIX extended regular ex- + pressions. It is possible to compile NetHack without regular ex- + pression support on a platform where there is no regular expres- + sion library. While this is not true of any modern platform, if + your NetHack was built this way, patterns are instead glob pat- terns. This applies to Autopickup exceptions, Message types, Menu colors, and User sounds. @@ -4999,40 +5201,42 @@ 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 + 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 December 19, 2020 + + + + + + NetHack Guidebook 80 + + + autopickup_exception - Sets an exception to the pickup_types option. The autopick- - up_exception option should be followed by a regular expression - to be used as a pattern to match against the singular form of + Sets an exception to the pickup_types option. The autopick- + up_exception option should be followed by a regular expression + to be used as a pattern to match against the singular form of the description of an object at your location. - - NetHack 3.7 July 9, 2020 - - - - - - NetHack Guidebook 77 - - - - In addition, some characters are treated specially if they oc- + In addition, some characters are treated specially if they oc- cur 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 + 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_ex- + 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_ex- ception rules and not saved with the game. Here are some examples: @@ -5041,17 +5245,17 @@ 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 ex- + 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 ex- clusion of items known to be cursed from autopickup. 9.9. 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 + 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"), or a three-digit decimal ASCII code. @@ -5062,37 +5266,38 @@ BIND=v:loot Extended command keys - You can bind multiple keys to the same extended command. Un- - bind a key by using "nothing" as the extended command to bind - to. You can also bind the "", "", and "" + You can bind multiple keys to the same extended command. Un- + bind a key by using "nothing" as the extended command to bind + to. You can also bind the "", "", and "" keys. + + + + NetHack 3.7 December 19, 2020 + + + + + + NetHack Guidebook 81 + + + Menu accelerator keys - The menu control or accelerator keys can also be rebound via - OPTIONS lines in the configuration file. You cannot bind ob- + The menu control or accelerator keys can also be rebound via + OPTIONS lines in the configuration file. You cannot bind ob- ject symbols into menu accelerators. Special command keys - Below are the special commands you can rebind. Some of them - - - NetHack 3.7 July 9, 2020 - - - - - - NetHack Guidebook 78 - - - - can be bound to same keys with no problems, others are in the - same "context", and if bound to same keys, only one of those - commands will be available. Special command can only be bound + 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 "context", 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 + Prefix key to start a count, to repeat a command this many times. With number_pad only. Default is `n'. doinv @@ -5102,19 +5307,19 @@ Prefix key to force fight a direction. Default is `F'. fight.numpad - Prefix key to force fight a direction. With number_pad only. + Prefix key to force fight a direction. With number_pad only. Default is `-'. getdir.help - When asked for a direction, the key to show the help. Default + When asked for a direction, the key to show the help. Default is `?'. getdir.self - When asked for a direction, the key to target yourself. De- + When asked for a direction, the key to target yourself. De- fault is `.'. getdir.self2 - When asked for a direction, the key to target yourself. De- + When asked for a direction, the key to target yourself. De- fault is `s'. getpos.autodescribe @@ -5126,116 +5331,117 @@ esting thing. Default is `a'. getpos.all.prev - When asked for a location, the key to go to previous closest + When asked for a location, the key to go to previous closest interesting thing. Default is `A'. getpos.door.next - When asked for a location, the key to go to next closest door + When asked for a location, the key to go to next closest door or doorway. Default is `d'. + + + NetHack 3.7 December 19, 2020 + + + + + + NetHack Guidebook 82 + + + getpos.door.prev - When asked for a location, the key to go to previous closest + When asked for a location, the key to go to previous closest door or doorway. Default is `D'. getpos.help - When asked for a location, the key to show help. Default is + When asked for a location, the key to show help. Default is `?'. - - NetHack 3.7 July 9, 2020 - - - - - - NetHack Guidebook 79 - - - getpos.mon.next - When asked for a location, the key to go to next closest mon- + When asked for a location, the key to go to next closest mon- ster. Default is `m'. getpos.mon.prev - When asked for a location, the key to go to previous closest + When asked for a location, the key to go to previous closest monster. Default is `M'. getpos.obj.next - When asked for a location, the key to go to next closest ob- + When asked for a location, the key to go to next closest ob- ject. Default is `o'. getpos.obj.prev - When asked for a location, the key to go to previous closest + 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 previ- - ous keys to cycle through targets, toggle showing a menu in- + When asked for a location, and using one of the next or previ- + ous keys to cycle through targets, toggle showing a menu in- stead. 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 + 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 + 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 + When asked for a location, the key to choose the location, and possibly ask for more info. Default is `.'. getpos.pick.once - When asked for a location, the key to choose the location, and + When asked for a location, the key to choose the location, and skip asking for more info. Default is `,'. getpos.pick.quick When asked for a location, the key to choose the location, skip - asking for more info, and exit the location asking loop. De- + asking for more info, and exit the location asking loop. De- fault is `;'. + + + + NetHack 3.7 December 19, 2020 + + + + + + NetHack Guidebook 83 + + + getpos.pick.verbose - When asked for a location, the key to choose the location, and + When asked for a location, the key to choose the location, and show more info without asking. Default is `:'. getpos.self When asked for a location, the key to go to your location. De- fault is `@'. - - - - NetHack 3.7 July 9, 2020 - - - - - - NetHack Guidebook 80 - - - getpos.unexplored.next - When asked for a location, the key to go to next closest unex- + When asked for a location, the key to go to next closest unex- plored location. Default is `x'. getpos.unexplored.prev - When asked for a location, the key to go to previous closest + When asked for a location, the key to go to previous closest unexplored location. Default is `X'. getpos.valid - When asked for a location, the key to go to show valid target + When asked for a location, the key to go to show valid target locations. Default is `$'. getpos.valid.next - When asked for a location, the key to go to next closest valid + When asked for a location, the key to go to next closest valid location. Default is `z'. getpos.valid.prev - When asked for a location, the key to go to previous closest + When asked for a location, the key to go to previous closest valid location. Default is `Z'. nopickup @@ -5245,7 +5451,7 @@ Key to redraw the screen. Default is `^R'. redraw.numpad - Key to redraw the screen. With number_pad only. Default is + Key to redraw the screen. With number_pad only. Default is `^L'. repeat @@ -5258,32 +5464,41 @@ Prefix key to run towards a direction. Default is `G'. run.nopickup - Prefix key to run towards a direction without picking up items + Prefix key to run towards a direction without picking up items on the way. Default is `M'. run.numpad - Prefix key to run towards a direction. With number_pad only. - Default is `5'. + Prefix key to run towards a direction. With number_pad only. + + + + NetHack 3.7 December 19, 2020 + + + + + + NetHack Guidebook 84 + + + + Default is `5' when number_pad is set to 1 or 3, otherwise + `M-5' when it is set to 2 or 4. rush Prefix key to rush towards a direction. Default is `g'. + rush.numpad + Prefix key to rush towards a direction. With number_pad only. + + Default is `M-5' when number_pad is set to 1 or 3, otherwise + `5' when it is set to 2 or 4. + 9.10. Configuring Message Types You can change the way the messages are shown in the message area, when the message matches a user-defined pattern. - - NetHack 3.7 July 9, 2020 - - - - - - NetHack Guidebook 81 - - - In general, the configuration file entries to describe the message types look like this: MSGTYPE=type "pattern" @@ -5320,6 +5535,19 @@ when the line matches a user-defined pattern. At this time the tty, curses, win32tty and win32gui interfaces support this. + + + + NetHack 3.7 December 19, 2020 + + + + + + NetHack Guidebook 85 + + + In general, the configuration file entries to describe the menu color mappings look like this: @@ -5337,22 +5565,10 @@ 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- - - - NetHack 3.7 July 9, 2020 - - - - - - NetHack Guidebook 82 - - - - magenta, light-cyan, and white. And no-color, the default - foreground color, which isn't necessarily the same as any of - the other colors. + cyan, gray, orange, light-green, yellow, light-blue, light-ma- + genta, light-cyan, and white. And no-color, the default fore- + ground color, which isn't necessarily the same as any of the + other colors. Allowed attributes are none, bold, dim, underline, blink, and inverse. "Normal" is a synonym for "none". Note that the @@ -5385,6 +5601,19 @@ to the message window. At this time the Qt port and the win32tty and win32gui ports support the use of user sounds. + + + + NetHack 3.7 December 19, 2020 + + + + + + NetHack Guidebook 86 + + + The following configuration file entries are relevant to mapping user sounds to messages: @@ -5405,17 +5634,6 @@ sound index - optional; the index corresponding to a sound file. - - NetHack 3.7 July 9, 2020 - - - - - - NetHack Guidebook 83 - - - The pattern should be a POSIX extended regular expression. 9.13. Configuring Status Hilites @@ -5450,6 +5668,18 @@ ground color on the display, which is not necessarily the same as black or white or any of the other colors. + + + NetHack 3.7 December 19, 2020 + + + + + + NetHack Guidebook 87 + + + Allowed attributes are none, bold, dim, underline, blink, and inverse. "Normal" is a synonym for "none"; they should not be used in combination with any of the other attributes. @@ -5469,19 +5699,6 @@ the only way a situation like that can be controlled is to speci- fy just one attribute. - - - - NetHack 3.7 July 9, 2020 - - - - - - NetHack Guidebook 84 - - - You can adjust the appearance of the following status fields: title dungeon-level experience-level @@ -5517,6 +5734,18 @@ * "changed" sets the field attribute for when the field val- ue changes. This attribute times out after statushilites + + + NetHack 3.7 December 19, 2020 + + + + + + NetHack Guidebook 88 + + + turns. (If a field has both a "changed" rule and an "up" or "down" rule which matches a change in the field's val- ue, the "up" or "down" one takes precedence.) @@ -5535,26 +5764,14 @@ 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 ex- - perience level to the start of the next level. So if - - - NetHack 3.7 July 9, 2020 - - - - - - NetHack Guidebook 85 - - - - 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 lev- - el, but a rule for =100% is allowed and matches the spe- - cial case of being exactly 1 experience point short of the - next level. + perience level to the start of the next level. So if lev- + el 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 experience point short of the next lev- + el. * absolute value sets the attribute when the field value matches that number. The number must be 0 or higher, ex- @@ -5578,6 +5795,23 @@ Example hilites: + + + + + + + + NetHack 3.7 December 19, 2020 + + + + + + NetHack Guidebook 89 + + + OPTION=hilite_status: gold/up/yellow/down/brown OPTION=hilite_status: characteristics/up/green/down/red OPTION=hilite_status: hitpoints/100%/gray&normal @@ -5603,17 +5837,6 @@ Set the name of the symbol set that you want to load for dis- play on the rogue level. - - NetHack 3.7 July 9, 2020 - - - - - - NetHack Guidebook 86 - - - You can also override one or more symbols using the SYMBOLS and ROGUESYMBOLS configuration file options. Symbols are speci- fied as name:value pairs. Note that NetHack escape-processes the @@ -5642,6 +5865,19 @@ - S_blcorn (bottom left corner) b S_blob (blob) + S_book (spellbook) + + + + NetHack 3.7 December 19, 2020 + + + + + + NetHack Guidebook 90 + + + ) S_boomleft (boomerang open left) ( S_boomright (boomerang open right) ` S_boulder (boulder) @@ -5667,19 +5903,6 @@ - S_explode2 (explosion top center) \ S_explode3 (explosion top right) | S_explode4 (explosion middle left) - - - - NetHack 3.7 July 9, 2020 - - - - - - NetHack Guidebook 87 - - - S_explode5 (explosion middle center) | S_explode6 (explosion middle right) \ S_explode7 (explosion bottom left) @@ -5708,6 +5931,19 @@ ^ S_hole (hole) @ S_human (human or elf) h S_humanoid (humanoid) + + + + NetHack 3.7 December 19, 2020 + + + + + + NetHack Guidebook 91 + + + - S_hwall (horizontal wall) . S_ice (ice) i S_imp (imp or minor demon) @@ -5733,19 +5969,6 @@ N S_naga (naga) . S_ndoor (doorway without door) n S_nymph (nymph) - - - - NetHack 3.7 July 9, 2020 - - - - - - NetHack Guidebook 88 - - - O S_ogre (ogre) o S_orc (orc) p S_piercer (piercer) @@ -5774,6 +5997,19 @@ ^ S_squeaky_board (squeaky board) 0 S_ss1 (magic shield 1 of 4) # S_ss2 (magic shield 2 of 4) + + + + NetHack 3.7 December 19, 2020 + + + + + + NetHack Guidebook 92 + + + @ S_ss3 (magic shield 3 of 4) * S_ss4 (magic shield 4 of 4) ^ S_statue_trap (statue trap) @@ -5799,19 +6035,6 @@ # S_tree (tree) T S_troll (troll) | S_trwall (wall) - - - - NetHack 3.7 July 9, 2020 - - - - - - NetHack Guidebook 89 - - - - S_tuwall (wall) U S_umber (umber hulk) S_unexplored (unexplored terrain) @@ -5840,6 +6063,19 @@ Y S_yeti (apelike creature) Z S_zombie (zombie) z S_zruty (zruty) + + + + NetHack 3.7 December 19, 2020 + + + + + + NetHack Guidebook 93 + + + S_pet_override (any pet if ACCESSIBILITY=1 is set) S_hero_override (hero if ACCESSIBILITY=1 is set) @@ -5866,18 +6102,6 @@ will have to know how to navigate horizontally and vertically character by character. They will also find the search capabili- ties of their screen-readers to be quite valuable. Be certain to - - - NetHack 3.7 July 9, 2020 - - - - - - NetHack Guidebook 90 - - - 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. @@ -5906,6 +6130,18 @@ game to run in a manner accessible to the blind. After you have gained some experience with the game and with editing files, you may want to alter settings via SYMBOLS= and ROGUESYMBOLS= in your + + + NetHack 3.7 December 19, 2020 + + + + + + NetHack Guidebook 94 + + + configuration file to better suit your preferences. See the pre- vious section for the special symbols S_pet_override to force a consistent symbol for all pets and S_hero_override to force a @@ -5933,17 +6169,6 @@ the screen. If this is the case, disable the number_pad option and use the traditional Rogue-like commands. - - NetHack 3.7 July 9, 2020 - - - - - - NetHack Guidebook 91 - - - autodescribe Automatically describe the terrain under the cursor when tar- geting. @@ -5970,6 +6195,19 @@ screen, if your screen-reader reads those lines. The same in- formation can be seen via the "#attributes" command. + + + + NetHack 3.7 December 19, 2020 + + + + + + NetHack Guidebook 95 + + + 9.16. Global Configuration for System Administrators If NetHack is compiled with the SYSCF option, a system ad- @@ -5998,18 +6236,6 @@ 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 - - - NetHack 3.7 July 9, 2020 - - - - - - NetHack Guidebook 92 - - - the first format exists. Valid choices are "historical" for binary writing of entire structs, "lendian" for binary writing of each field in little-endian order, "ascii" for writing the @@ -6036,6 +6262,18 @@ ARDS, and SHELLERS check for the player name instead of the us- er's login name. + + + NetHack 3.7 December 19, 2020 + + + + + + NetHack Guidebook 96 + + + 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 @@ -6065,17 +6303,6 @@ output files in one place rather than at the standard loca- tions. - - NetHack 3.7 July 9, 2020 - - - - - - NetHack Guidebook 93 - - - DUMPLOGFILE = A filename where the end-of-game dumplog is saved. Not defining this will prevent dumplog from being cre- ated. Only available if your game is compiled with DUMPLOG. Al- @@ -6101,6 +6328,18 @@ proper place under your current name. How many scores are kept can also be set up when NetHack is compiled. + + + NetHack 3.7 December 19, 2020 + + + + + + NetHack Guidebook 97 + + + 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 @@ -6130,18 +6369,6 @@ extended command while already playing the game. Starting a new game in explore mode provides your character with a wand of wish- ing in initial inventory; switching during play does not. The - - - NetHack 3.7 July 9, 2020 - - - - - - NetHack Guidebook 94 - - - other benefits of explore mode are left for the trepid reader to discover. @@ -6164,6 +6391,21 @@ allowed or not available will result in falling back to explore mode instead. + + + + + + NetHack 3.7 December 19, 2020 + + + + + + NetHack Guidebook 98 + + + 12. Credits The original hack game was modeled on the Berkeley UNIX @@ -6179,9 +6421,15 @@ Jay Fenlason wrote the original Hack, with help from Kenny Woodland, Mike Thome, and Jon Payne. - Andries Brouwer did a major re-write, transforming Hack into - a very different game, and published (at least) three versions - (1.0.1, 1.0.2, and 1.0.3) for UNIX machines to the Usenet. + Andries Brouwer did a major re-write while at Stichting + Mathematisch Centrum (now Centrum Wiskunde & Informatica), trans- + forming 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 ver- + sion 1.0 in December of 1984, then versions 1.0.1, 1.0.2, and fi- + nally 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, producing PC HACK 1.01e, added support for DEC Rainbow graphics @@ -6196,273 +6444,25 @@ 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 July 9, 2020 - - - - - - NetHack Guidebook 95 - - - - 2.2 and 2.3. - - Later, Mike coordinated a major re-write of the game, head- - ing a team which included Ken Arromdee, Jean-Christophe Collet, - Steve Creps, Eric Hendrickson, Izchak Miller, Eric S. Raymond, - John Rupley, Mike Threepoint, and Janet Walz, to produce NetHack + Later, Mike coordinated a major re-write of the game, head- + ing a team which included Ken Arromdee, Jean-Christophe Collet, + Steve Creps, 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 + 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-structured 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 Sche- - lin, 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 - Engber, 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 de- - velopment, Bart House added a Think C port. - - Timo Hakulinen ported NetHack 3.1 to OS/2. Eric Smith port- - ed NetHack 3.1 to the Atari. Pat Rankin, with help from Joshua - NetHack 3.7 July 9, 2020 - - - - - - NetHack Guidebook 96 - - - - 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 don't extend to individual monster and ob- - ject types, just replacements for monster and object classes (so - one custom image for all "a" insects and another for all "[" ar- - mor 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 ob- - jects rather than just their classes. He contributed them to the - NetHack Development Team which rechristened them "tiles", origi- - nal usage which has subsequently been picked up by various other - games. NetHack's tiles support 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 Alli- - son, Ken Arromdee, David Cohrs, Jessie Collet, Steve Creps, Kevin - Darcy, Timo Hakulinen, Steve Linhart, Dean Luick, Pat Rankin, Er- - ic 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 enthusi- - asts 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 cast- - ing system with the Wizard Patch. Warwick Allison also ported - - - NetHack 3.7 July 9, 2020 - - - - - - NetHack Guidebook 97 - - - - NetHack to use the Qt interface. - - Warren Cheung combined SLASH with the Wizard Patch to pro- - duce Slash'EM, and with the help of Kevin Hugo, added more fea- - tures. Kevin later joined the NetHack Development Team and in- - corporated 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 intro- - duced an extra column in the file layout which prevented score - entries from being read back in correctly, interfering with in- - sertion 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 Al- - lison, Ken Arromdee, David Cohrs, Jessie Collet, Steve Creps, - Kevin Darcy, Timo Hakulinen, Kevin Hugo, Steve Linhart, Ken Lor- - ber, 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 - separate race and profession. The Elf class was removed in pref- - erence 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, Barbar- - ians, 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 listing 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: - - - - NetHack 3.7 July 9, 2020 - - - - - - NetHack Guidebook 98 - - - - Pat Rankin maintained 3.4 for VMS. - - Michael Allison maintained NetHack 3.4 for the MS-DOS plat- - form. Paul Winner and Yitzhak Sapir provided encouragement. - - Dean Luick, Mark Modrall, and Kevin Hugo maintained and en- - hanced 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 inter- - face for the Windows port. Alex Kompel also contributed a Win- - dows 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 alive on OS/2 all these years. - - 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 af- - ter he resurrected it for 3.3.1. - - The release of NetHack 3.4.3 in December 2003 marked the be- - ginning 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 continued 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 con- - tinue to be developed, maintained, and enjoyed by the community - to this day. - - In September 2014, an interim snapshot of the code under de- - velopment 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 Development 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 - - - NetHack 3.7 July 9, 2020 + NetHack 3.7 December 19, 2020 @@ -6472,63 +6472,63 @@ - Warwick Allison, Michael Allison, Ken Arromdee, David Cohrs, - Jessie Collet, Ken Lorber, Dean Luick, Pat Rankin, Mike Stephen- - son, 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 Development Team. + 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. - Near the end of the development of 3.6.0, one of the signif- - icant 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. + 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. - 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 - restructured. + 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-structured 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. - The NetHack Development Team, as well as Steve VanDevender - and Kevin Smolkowski, ensured that NetHack 3.6 continued to oper- - ate on various UNIX flavors and maintained the X11 interface. + Ken Lorber, Gregg Wonderly and Greg Olson, with help from + Richard Addison, Mike Passaretti, and Olaf Seibert, developed + NetHack 3.1 for the Amiga. - Ken Lorber, Haoyang Wang, Pat Rankin, and Dean Luick main- - tained the port of NetHack 3.6 for Mac OSX. + Norm Meluch and Kevin Smolkowski, with help from Carl Sche- + lin, Stephen Spackman, Steve VanDevender, and Paul Winner, ported + NetHack 3.1 to the PC. - Michael Allison, David Cohrs, Bart House, Pasi Kallinen, - Alex Kompel, Dion Nicolaas, Derek S. Ray and Yitzhak Sapir main- - tained the port of NetHack 3.6 for Microsoft Windows. + Jon W{tte and Hao-yang Wang, with help from Ross Brown, Mike + Engber, 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 de- + velopment, Bart House added a Think C port. - Pat Rankin attempted to keep the VMS port running for - NetHack 3.6, hindered by limited access. Kevin Smolkowski has up- - dated 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. + Timo Hakulinen ported NetHack 3.1 to OS/2. Eric Smith port- + ed 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. - Ray Chason resurrected the MS-DOS port for 3.6 and contrib- - uted 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 con- - sisted 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 en- - hancements 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. + 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 ob- + ject types, just replacements for monster and object classes (so + one custom image for all "a" insects and another for all "[" ar- + mor and so forth, not separate images for beetles and ants or for + cloaks and boots). - NetHack 3.7 July 9, 2020 + + NetHack 3.7 December 19, 2020 @@ -6538,10 +6538,249 @@ + 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 ob- + jects rather than just their classes. He contributed them to the + NetHack Development Team which rechristened them "tiles", origi- + nal usage which has subsequently been picked up by various other + games. NetHack's tiles support 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 Alli- + son, Ken Arromdee, David Cohrs, Jessie Collet, Steve Creps, Kevin + Darcy, Timo Hakulinen, Steve Linhart, Dean Luick, Pat Rankin, Er- + ic 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 enthusi- + asts 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 cast- + ing system with the Wizard Patch. Warwick Allison also ported + NetHack to use the Qt interface. + + Warren Cheung combined SLASH with the Wizard Patch to pro- + duce Slash'EM, and with the help of Kevin Hugo, added more fea- + tures. Kevin later joined the NetHack Development Team and in- + corporated 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. + + + + NetHack 3.7 December 19, 2020 + + + + + + NetHack Guidebook 101 + + + + (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 intro- + duced an extra column in the file layout which prevented score + entries from being read back in correctly, interfering with in- + sertion 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 Al- + lison, Ken Arromdee, David Cohrs, Jessie Collet, Steve Creps, + Kevin Darcy, Timo Hakulinen, Kevin Hugo, Steve Linhart, Ken Lor- + ber, 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 + separate race and profession. The Elf class was removed in pref- + erence 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, Barbar- + ians, 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 listing 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 plat- + form. Paul Winner and Yitzhak Sapir provided encouragement. + + Dean Luick, Mark Modrall, and Kevin Hugo maintained and en- + hanced 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 inter- + face for the Windows port. Alex Kompel also contributed a Win- + dows CE port for 3.4.1. + + + NetHack 3.7 December 19, 2020 + + + + + + NetHack Guidebook 102 + + + + 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 Amiga port of 3.4 after Janne Salmijarvi resurrected it for + 3.3.1. + + Christian "Marvin" Bressler maintained 3.4 for the Atari af- + ter he resurrected it for 3.3.1. + + The release of NetHack 3.4.3 in December 2003 marked the be- + ginning 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 continued 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 con- + tinue to be developed, maintained, and enjoyed by the community + to this day. + + In September 2014, an interim snapshot of the code under de- + velopment 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 Development 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 Stephen- + son, 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 Development Team. + + Near the end of the development of 3.6.0, one of the signif- + icant 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 + + + NetHack 3.7 December 19, 2020 + + + + + + NetHack Guidebook 103 + + + + restructured. + + The NetHack Development Team, as well as Steve VanDevender + and Kevin Smolkowski, ensured that NetHack 3.6 continued to oper- + ate on various UNIX flavors and maintained the X11 interface. + + Ken Lorber, Haoyang Wang, Pat Rankin, and Dean Luick main- + tained the port of NetHack 3.6 for Mac OSX. + + Michael Allison, David Cohrs, Bart House, Pasi Kallinen, + Alex Kompel, Dion Nicolaas, Derek S. Ray and Yitzhak Sapir main- + tained 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 up- + dated 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 contrib- + uted 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 con- + sisted 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 en- + hancements 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 + 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 se- @@ -6550,22 +6789,35 @@ The official NetHack web site is maintained by Ken Lorber at https://www.nethack.org/. + + + + NetHack 3.7 December 19, 2020 + + + + + + NetHack Guidebook 104 + + + 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 + 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 dun- - geoneers who invest their time and effort into annual NetHack - tournaments such as Junethack, The November NetHack Tournament, + geoneers 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). - - - - - - - - - - - From time to time, some depraved individual out there in - netland sends a particularly intriguing modification to help out + 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 the names of the worst of these miscreants in this, the list of Dungeoneers: Adam Aronow J. Ali Harlow Mikko Juola Alex Kompel Janet Walz Nathan Eady @@ -6591,19 +6843,6 @@ Dean Luick Kevin Hugo Ross Brown Del Lamb Kevin Sitze Sascha Wostmann Derek S. Ray Kevin Smolkowski Scott Bigham - - - - NetHack 3.7 July 9, 2020 - - - - - - NetHack Guidebook 101 - - - Deron Meranda Kevin Sweet Scott R. Turner Dion Nicolaas Lars Huttar Sean Hunt Dylan O'Donnell Leon Arnott Stephen Spackman @@ -6616,6 +6855,19 @@ Frederick Roeber Merlyn LeRoy Tim Lennan Gil Neiger Michael Allison Timo Hakulinen Greg Laskin Michael Feir Tom Almy + + + + NetHack 3.7 December 19, 2020 + + + + + + NetHack Guidebook 105 + + + Greg Olson Michael Hamel Tom West Gregg Wonderly Michael Sokolov Warren Cheung Hao-yang Wang Mike Engber Warwick Allison @@ -6623,7 +6875,7 @@ Irina Rempt-Drijfhout Mike Passaretti Izchak Miller Mike Stephenson - Brand and product names are trademarks or registered trade- + Brand and product names are trademarks or registered trade- marks of their respective holders. @@ -6660,7 +6912,19 @@ - NetHack 3.7 July 9, 2020 + + + + + + + + + + + + + NetHack 3.7 December 19, 2020 diff --git a/doc/config.nh b/doc/config.nh index 437158250..484a2930e 100644 --- a/doc/config.nh +++ b/doc/config.nh @@ -1,4 +1,4 @@ -# NetHack 3.6 config.nh $NHDT-Date: 1524689547 2018/04/25 20:52:27 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.1 $ +# NetHack 3.7 config.nh $NHDT-Date: 1596498144 2020/08/03 23:42:24 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.4 $ # Copyright (c) 2016 by Pasi Kallinen # NetHack may be freely redistributed. See license for details. # Sample config file for NetHack 3.6 diff --git a/doc/fixes36.1 b/doc/fixes36.1 index 5fda55113..3b0b27ddb 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -853,7 +853,7 @@ X11: new NetHack*highlight_prompt resource to control whether the persistent configuration will be highlighted when it's expecting input X11: NetHack*extcmd_height_delta resource can be used to adjust initial size of the extended commands menu -X11: status display split into three columns to accomodate Stone/Deaf/Lev/&c; +X11: status display split into three columns to accommodate Stone/Deaf/Lev/&c; NetHack*status_condition.foreground, .background, and .showGrip resources replaced by status_condition[1-3].* X11: more terminal-like default resources diff --git a/doc/fixes36.4 b/doc/fixes36.4 index a4b8991c4..912f80723 100644 --- a/doc/fixes36.4 +++ b/doc/fixes36.4 @@ -11,7 +11,7 @@ GDBPATH and GREPPATH from sysconf or -D... on compilation command line were at end of game when that was enabled fix the article used in the message when your steed encounters a polymorph trap allow teleporting onto the vibrating square -message "your knapsack can't accomodate any more items" when picking stuff up +message "your knapsack can't accommodate any more items" when picking stuff up or removing such from container was inaccurate if there was some gold pending; vary the message rather than add more convoluted pickup code dozen-ish assorted spelling/typo fixes in messages and source comments diff --git a/doc/fixes37.0 b/doc/fixes37.0 index 3589e3830..1e7d25d56 100644 --- a/doc/fixes37.0 +++ b/doc/fixes37.0 @@ -1,4 +1,4 @@ -$NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.245 $ $NHDT-Date: 1594395803 2020/07/10 15:43:23 $ +NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.410 $ $NHDT-Date: 1609281273 2020/12/29 22:34:33 $ General Fixes and Modified Features ----------------------------------- @@ -126,14 +126,16 @@ it's possible to wish for tins of the Riders in wizard mode; eating one is fatal but if you're life-saved or decline to die, the game crashed revival via undead turning of corpse carried by hero said "your corpse comes alive" even when revived monster was undead -prevent searching or waiting next to a hostile monster - override with 'm' +prevent searching or waiting next to a hostile monster if boolean option + safe_wait is on - override with 'm' allow random mimics to show up mimicing more furniture than just stairs scatter exploding bag of holding contents instead of outright deleting them male hero poly'd into nymph chooses charm vs seduce message based on being male rather than on all nymphs being female but charm message was using hardcoded pronouns She,her for target monster--wrong for male target and noticable if " finishes taking off his suit" is given -hostile monsters with launcher and ammo try to stay away from melee range +hostile monsters with a spit attack or launcher and ammo try to stay away + from melee range allow displacing peaceful creatures unicorn horns don't restore attribute loss anymore when a shop is changed from food to health food, change room type to match @@ -217,6 +219,141 @@ the default engraving, epitaph, and bogus monster inserted by 'makedefs -s' when the corresponding file wasn't actually empty its first line ended up concatenated; default portion of the bad combined entry would be decrypted properly but the portion from the file's first line wouldn't +if the Wizard of Yendor fled up the stairs on level 1, the game would behave + as if he was still in play, but he wouldn't be on migrating monsters + list so couldn't be brought back and wouldn't appear on Plane of Earth + (stale non-zero value for context.no_of_wizards) +if a mind flayer's psychic blast targetted a hidden monster, feedback named + the monster but it wasn't brought out of hiding +hero poly'd into a mind flayer who used #monster to emit a psychic blast was + able to harm mindless monsters with it +some hero attacks that should have gotten a skill bonus or penalty didn't +change internal name of " venom" to "splash of venom" +some operations that made sense to handle venom ('D', scroll of identify, no + doubt others) ignored it because venom is suppressed from packorder; + matters for wizard mode or for normal play that loads wizard bones +singularize "splashes" to "splash" instead of "splashe" +treat slinging gems and tossing or slinging stones at unicorns as attacks +give rot-away timer instead of revive timer to corpses of cancelled trolls +switch revive timer to rot-away timer if a troll corpse gets cancelled +uncancel an ice troll if its corpse is put into an ice box; give corpse a + revive timer if later taken out +splitting a stack of candy bars gave new wrapper text depending upon the + obj->o_id value assigned; keep existing text for both halves of stack + (side-effect: separate candy bars usually won't merge anymore) +describing tin variety (deep fried, pureed, &c) relied on the 'contents known' + flag but object identification wasn't setting obj->cknown for tins +wizard mode #wizintrinsic: setting Levitation wouldn't block Flying as + intended because the check for that was being made too soon +chatting to the quest leader in wizard mode with sufficient experience level + and insufficient piety, player is asked whether alignment should be + boosted; answering 'n' resulted in being prompted a second time +leashing or unleashing pets wasn't updating persistent inventory window +end of game inventory disclosure passed an inappropriate argument to the + inventory display routine; not noticeable for tty and curses, + noticeable but not harmful for X11, and slightly harmful for Qt +turning into slime rendered hero as slime one turn too soon +avoid potential infinite loop if hangup occurs at ring "right or left?" prompt +randomize the turns where accessories and extrinsics affect nutrition +handle being interrupted by approaching monsters more consistently +if hero attacked a peaceful monster, some other peaceful monsters with humanoid + shape (minotaur, zruty, perhaps others) that witnessed it but which + shouldn't be capable of normal speech expressed their surprise audibly +make gasp/exclamation message from peaceful monsters be more verbose to + indicate which monster is doing the gasping or exclaiming +when make was invoked with -j makedefs instances could end up running in + parallel and could trample on each other's temp files; default to + using mkstemp(); allow a port runtime library implementation that lacks + mkstemp() to define HAS_NO_MKSTEMP to revert to the old behaviour; + provide a work-alike mkstemp() implementation for windows visual studio + in mdlib.c so there is no requirement to define HAS_NO_MKSTEMP there +make piranhas faster and give them extra bite attack +fire sources can ignite candles, lamps, and potions of oil +for multiple drop ('D') with menustyle traditional or combination, if the only + object class player picked was '$' then it operated on all classes +small monsters could seep through their shirt +don't snuff brass lantern when it's hit by water unless it is submerged +when reporting that hero can't repair a chest's broken lock with key/pick/card + just describe the base item without BUC, user assigned name, &c since + "You can't repair a chest's lock with an uncursed key." implicitly + suggests that you might be able to do so with a blessed or cursed one +pre-populate teleport destination prompt with travel destination +ghosts cannot be renamed +tossed upwards objects got two times half physical damage reduction +monster xorns could pass through iron bars but not eat them; monster rock + moles could no neither; now they can eat bars when adjacent and will + do so if the bars are blocking their path +hero poly'd into rust monster could implicitly eat bars when adjacent by + trying to move there, now when in rock mole form too; in xorn form + can explicitly eat them via 'e' after moving onto their spot +monster hiding under an egg that hatched was kept hidden +restful sleep regenerates hit points +attacking non-adjacent concealed mimic by applying a polearm would make the + hero be stuck to that mimic +hero could break a wand ("raising the wand high over your head, you break it + in two") even if hands were welded to a two-handed weapon or to a + one-handed weapon and also to a shield +if a monster threw a cocktrice egg at the hero but hit and petrified another + monster, the hero would get credit/blame for killing it +update persistent inventory when putting on a helmet causes it to auto-curse +since ki-rin look quite a bit like unicorns, make them be more like one: + allow them to use their own horn to cure themselves; remove M1_ANIMAL, + change MS_NEIGH to MS_SPELL, add MR_POISON, use horse body parts; + they're still 'A' rather than 'u' and don't care about gems +wand/scroll of create monster or bag of tricks that makes a new monster which + can be seen or sensed becomes discovered, but was doing so even for a + concealed mimic seen as furniture or an object +'showscore' could be used to determine how much gold was inside a container + whose contents were unknown +wizard mode (only way to get timed flying): if levitation and flying time out + on same turn, player was told "You have stopped levitating and are + now flying."; status line wasn't updated to remove stale Fly condition +throwing or kicking a shop container (that's light enough to move) made the + hero pay for any gold inside, then didn't refund that amount if the + container landed inside the shop +try to fix message sequencing for tame golems that "roast/rot/rust in peace" +autodescribe when moving the cursor was erroneously honoring MSGTYPE=stop + and potentially delivering sounds +reduce the number of "seeXYZ" commands by renaming some: #seenv -> #wizseenv, + #seegold -> #showgold, #seespells -> #showspells, #seetrap -> #showtrap +when saving while punished or game ends while punished, handling for ball and + chain might access freed memory with unpredictable consequences +brown pudding monster hitting another monster with decay attack corroded armor + instead of rotting it + -> omitted 'n' prefix and M-digit for number_pad mode, + and ^A/re-do was suppressed due lack of obsolete '#define REDO' +add missing key binding support for rush.numpad; default is M-5 for numpad==1 + or plain 5 for numpad==2 where behavior of 5 and M-5 are swapped +allow monsters to use wand of undead turning to revive corpses on floor + in some situations +selling a container to a shop for gold leaves any contents that the shop + doesn't ordinarily buy and sell owned by the hero, but selling the + container for credit resulted in the shop taking poesession of such + contents without giving any additional credit; mark out of place + contents 'no_charge' so that hero can reclaim them without buying +add some new demonic and angelic maledictions +when fire damage dried a wet towel, it would never reduce the wetness to 0 +when water damage wet a towel, the new wetness might randomly become less +when the wetness of a towel in inventory changed, persistent inventory wasn't + updated to show that +make Death revive earlier, and all the Riders after 67 turns at latest +when protection from shape changers begins, force mimic out of concealment + even if hero can't see its location; for locations that can be seen, + don't make double-trouble Wizard concealed as another monster--or pet + temporarily mimicking something while eating mimic corpse--fall asleep +best possible armor class reduced from -127 to -99; worst from +127 to +99; + charged or enchanted individual items also capped at +/- 99 (affects + wizard mode wishing, negligible effect on normal play) +fix several inconsistencies for objects at hole locations +make repeat (^A) work when bound to some other keystroke +if a prefix key was bound to some character which ordinarily ran a regular + command and that command wasn't bound to another key, typing the + prefix followed by a non-movement key behaved strangely: instead + of reporting "invalid direction" it would run the other command + (actually depended upon relative order of prefix's new and old key) +reqmenu (the request-a-menu prefix supported by a handful of non-movement + commands) could be bound to some key other than 'm' but it only + worked if the new key was also a movement prefix Fixes to 3.7.0-x Problems that Were Exposed Via git Repository @@ -260,6 +397,7 @@ grammar for messages about a monster removing items from a container was bad some new status conditions didn't always update when they should fix flipping non-existent stairs and ladders (github #311) fix door created into random wall or position opening into solid wall +handle gone portal when going back in quest 'use_inverse' option was accidentally made Windows-only; change it back to being more general; change its default to True change inconsistent achievement spelling of "Mine Town" to "Minetown" @@ -279,11 +417,70 @@ only generate shop items on solid floor squares avoid gcc 10 warning by removing duplicate definition of 'head_engr' if a monster removed a corpse from an ice box, the corpse would never rot away monster creation on quest levels could make genocided creatures +enabling wizard mode 'sanity_check' option would complain about invalid mhpmax + value for level N monsters created with a d8 value of 1 for all N d8's +disable that extra check because gremlim HP split after cloning triggers it +some versions of tiles processing (not X11's) complained about the rename of + "{acid,blinding} venom" to "splash of {acid,blinding} venom" +wizard mode #timeout changed to show timed Displacement in 'can be timed in + normal play' section instead of 'timed via #wizintrinsic only' section +the fix to make worm visibility checks work as intended forced the coordinates + of the extra tail segment co-located with the worm monster to match + the worm instead of leaving it off the map; place_worm_tail_randomly() + reverses the segments and can throw some away if there isn't room, + but throwing away the extra segment removed the worm from the map +using 'O' to try to change 'symset' was a no-op; 'roguesymset' worked +change default for lit attribute in special level des.terrain directives to + 'unchanged' instead of 'unlit' +replace worm tail placement code that reportedly led to a sanity_check warning + [no actual code problem found; might be compiler bug for 'xchar'] +learn scroll of teleportation after reading even when random destination is + right by starting spot +fix off-by-one bug in dimensions of theme rooms +fire/frost horn feedback when zapped by monster was inaccurate (falsely + claimed that it was "directed at self" when attacking hero) +tins of spinach and 'dead' eggs could cause out of array bounds access + attempting to index into mons[] by polyfodder() macro +options help ('? g') listed all boolean options, then repeated them among + the compound options; on OSX they showed a description of "(null)" + but for other sprintf implementations they might cause a crash +change name of #wizlevelflip to #wizfliplevel +dwarves could sometimes pass through walls without digging their way +fix genetic engineers dropping Schroedinger's cat box +the checks and handling for fountains, sinks, and drawbridges were being + missed during liquid_flow +monster movement flags unification allowed displacer beasts to displace Riders +a long worm with no visible segments (but one internal segment) might trigger + warning: tail 'segement' at <0,some_y>, worm at if teleported +adding displacer beast inadvertently introduced a regression in swapping with + pets, allowing them to be pulled into water by hero on/over water +splitting #if MAIL into #if MAIL_STRUCTURES and #if MAIL made it possible to + wish for and write scrolls of mail with MAIL disabled, but attempting + to read such a scroll issued impossible "What weird effect is this?" +remove M2_MALE flag that was unintentionally left on dwarf lord/lady/leader + entry and was preventing female incarnations +tilemap.c wasn't building if STATUES_LOOK_LIKE_MONSTERS wasn't defined; also, + to match the code that should be defined so change the preprocessor + test to 'ifndef STATUES_DONT_LOOK_LIKE_MONSTERS' +ensure that monster female name variation ends up as a female during ^G +arbitrate when there is a conflict between gender term (male or female) and + a gender-tied monster name (cavewoman) during ^G; gender term wins +wizard mode sanity check complained about Wizard's clone mimicking a monster +new ^G gender-naming handling code required a guard against null permonst + pointer which could occur under some circumstances +curses: 'msg_window' option wasn't functional for curses unless the binary + also included tty support +Qt: at Xp levels above 20 with 'showexp' On, the combined status field + "Level:NN/nnnnnnnn" was too big and truncated by a char at each end +Qt: searching a text window for something that wasn't found and then searching + for some other target could crash 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 new level after level change when S_unexplored is +Unix: after lua changes to Makefiles, 'make spotless' for dat subdirectory + left some generated data files which should have been deleted X11: was still initializing map to 'stone' instead of 'unexplored' after they became separate glyphs X11: for text map without color, add support for black&white ice; draw it in @@ -300,9 +497,102 @@ curses: for vertical status, line up conditions in columns; usually two but used to align entries in their columns--that's a feature...] msdos: add -DSTATUES_LOOK_LIKE_MONSTERS to Makefile1.cross so the VESA mode can display statue glyphs +Qt: quit if can't load tiles file instead of continuing and then segfaulting +Qt: [later] tiles load failure at startup now continues using an ascii map +Qt: use more columns for extended command selection dialog so that the number + of rows needed doesn't result in some commands being unaccessible +Qt: suppress wizard mode commands from '#' handling when not in wizard mode +Qt: organize extended command selection grid by columns instead of by rows + (first N entries down left column, next N entries down 2nd column, &c) +Qt: when selecting an extended command by typing its name, support + (aka ) in addition to to go back a character +Qt: switch to fixed-width font for menus +Qt: don't disable [cancel] button when viewing inventory or other pick-none + menus; ESC works to dismiss those and [cancel] should be the same +Qt: clicking on the window's Close button brought up a dialog offering + choices of "Save" and "Cancel"; picking Cancel sent nethack into an + infinite loop with complaints about Qt's event loop already being + active; change dialog: offer "Save and exit" or "Quit without saving" + with no opportunity to try to back out of the Close operation +Qt: add 3.6 status fields Stone, Slime, Strngl, Deaf, Lev, Fly, Ride +Qt: add Attributes, Overview, and Annotate to the "Info" pull down menu +Qt: rename menu entries game->Save to game->Save-and-exit and game->Quit + to game->Quit-without-saving +Qt: menu commands are now working; commands invoked via M-c were having that + keystroke changed to '?', bringing up nethack's help menu; now those + send #abc with just enough letters to disambiguate from other commands + ("Compilation" is one remaining problem; it yields "#version" which + brings up '#' menu subset with choices of "version" and "versionshort") +Qt: "paper doll" subset of persistent inventory has undergone several changes: + show previously missing quiver below weapon instead of duplicating + gloves there; show secondary weapon in shield slot and blank out + alternate weapon slot when two-weapon combat is active; show wielded + two-handed weapon in both the shield and primary weapon slots; show + first active light source in a previously unused slot on lower right; + show first leash-in-use in a previously unused slot on lower left +Qt: paper doll inventory view was inconsistently updated during Hallucination +Qt: when hero died, gold on tombstone only included gold in inventory, not + any additional gold inside carried containers; also, inventory gold + will be zero if bones get created for all 3.6.x and for 3.4.x+GOLDOBJ +Qt: tombstone showed newly constructed date instead of the value set up at + time of death; it only shows year but that could be wrong if player + stared at or ignored prior --More-- for long enough on 31 December +Qt: menu choices All, None, Invert were setting, unsetting, or toggling menu + entry checkboxes internally but didn't redraw the menu to show that +Qt: fix the F1/F2/Tab macro keys to not require that number_pad be On +Qt: unhighlight highlighted message (last one issued) after player has seen it +Qt: update message window's last message with player's response if it's a + prompt string for a single-character of input (ynaq or invent letter) +Qt: for line input, display the prompt+response in the message window +Qt: enable the popup_dialog WC option (result is a bit flakey but usable) +Qt: 3.6 catchup - show unexplored locations as unexplored rather than as stone +Qt: tried to honor 'showexp' but the value was unintentionally suppressed by + [lack of definition for] obsolete conditional EXP_ON_BOTL +Qt: implement --More-- prompt to support MSGTYPE=stop +Qt: for menu search, don't require clicking on the search target popup before + typing target string (was using typed letters to make menu selections + if player didn't click on the popup first) +Qt: rest ("Zz") button on the toolbar only worked when 'rest_on_space' was On + (core issue, not Qt's fault) +Qt: rename toolbar button "Get" and action menu choice "Get" to "Pick up" +Qt: status icons for alignment|hunger|encumbrance which started out centered + relative to the label text below them would shift to being left + justified when status got updated +Qt: handle '&' properly if it occurs as part of yn_function popup dialog +Qt: fix the display side of saved game selection; character names for + available save files are shown in a column of push buttons instead + of each button overwriting all the ones before it +Qt: don't clobber an existing save file after choosing "new game" in the + saved game selection widget +Qt: don't get stuck in a loop after choosing "play" while the character name + field is empty in the character selection widget +Qt: when a new message is issued, pan the message window to its left edge if + player panned it horizontally then didn't manually scroll it back +Qt: there was no way to enter extended command "#version" by typing; command + name matching was waiting to disambiguate it from "#versionshort" + and the only way to that was to type #version but + explicitly triggered rejection, cancelling '#' processing +Qt: {maybe just Qt+OSX:} when viewing a text window ('V' to look at 'history' + for instance), clicking on [Search], entering a search target in the + resulting popup and clicking on [Okay] or typing , the text + window got pushed underneath the main window so seemed to go away +Qt+OSX: fix control key +Qt+OSX: rename menu entry "nethack->Preferences..." for invoking nethack's + 'O' command to "Game->Run-time options" and entry "Game->Qt settings" + for making persistent Qt customizations to "nethack->Preferences..." +Qt+OSX: prevent game->Quit-without-saving from being hijacked for the nethack + menu by renaming it game->_Quit-without-saving (OSX only) +Qt+OSX: add a separate nethack->Quit menu entry with different functionality; + Command+Q invokes it +Qt+OSX: since menu entry help->"About Qt NetHack" gets hijacked and becomes + "nethack->About nethack", add a separate help->_About_Qt_NetHack_ + which stays where intended and brings up the same information +Qt+OSX: suppress unwanted "Search [______]" action from being inserted as the + first entry in the menubar's "Help" dropdown menu tiles: add indicator of thonged portion to aklys tile tty: role and race selection menus weren't filtering out potential choices which got excluded by OPTIONS=align:!lawful or !neutral or !chaotic +tty: '$' can now select gold in a menu even when it isn't on current page 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) @@ -380,6 +670,7 @@ for !fixinv option where inventory letters normally don't stick, try to put thrown from; only works if it does return and is successfully caught wizard mode #wizborn command include more skill information in ^X output when dual-wielding +include monk's to-hit penalty for worn suit in the status section of ^X output 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 @@ -391,12 +682,47 @@ new monsters: displacer beast ('f') and genetic engineer ('Q') make camera flash which reveals previously unseen map features or objects or monsters record those on the hero's map; monsters revert to 'unseen' boolean options can optionally have the form "name:value" with value taken - from among "true", "yes", "on", or "false", "no", "off" + from among "true", "yes", "on", or 1 and "false", "no", "off", or 0 record number of wishes and artifact wishes in xlogfile give feedback for '#chat' directed at walls add 'Sokoban' conduct, tracking the number of times the special Sokoban rules which incur luck penalties have been violated; don't report it unless/until Sokoban branch has been entered +reduce verbosity when a mind flayer attacks a headless monster; when a + tentacle-to-head attack hits but fails to accomplish anything skip + remaining attacks (mind flayer has 3, master mind flayer has 5) +add section marker [] support to run-time config file; CHOOSE section1,section2 + followed by [section1] ... [section2] ... forced all the rest of the + file to be part of the last section; that still works the same, but [] + can be used to terminate the last section and revert to common options + for the remainder of the file +render the color names in the corresponding color when using the pick-a-color + menu for adding status highlights or menu colors via 'O' +reading blessed scroll of teleportation confers one-shot teleport control +mild zombie apocalypse +list lamps and lanterns in charging prompt +let tourists read conical hats +when "?i" (show key bindings) displays commands and their keys, also show + commands without any key (so ones useable via '#', or possibly menu, + only; the majority are debugging commands) +assign default key binding for or to execute #terrain +assign M-X to #exploremode +make #herecmdmenu and #therecmdmenu autocomplete +add 'sortdiscoveries' option to control output of '\' and '`' commands +include an indication of monsters' health during farlook feedback (including + /M and autodescribe); also include it in death reason when killed by + a monster: "killed by {an uninjured newt,a heavily injured mumak}" +make DOAGAIN (^A) become unconditional; commenting it out in config.h makes + it be bound to NUL, a no-op, but allows BIND=k:repeat to set it to k +add support for a single monster species to have distinct male, female, + and gender-neutral naming terms +add support for a single monster species to have distinct male and female + tiles +consolidate several monsters that differed only by their gender into their + single species +added wizmgender debugging command to display female monsters in red inverse; + helpful for debugging gender-related matters on tty; currently ignored + on other window ports Platform- and/or Interface-Specific New Features @@ -406,6 +732,29 @@ user_sounds: provide an experimental mechanism for terminal-side sounds similar requires compile-time definition of TTY_SOUND_ESCCODES (also requires terminal-side code external to NetHack to recognize the sequence and act on it) +Qt: the "paper doll" inventory subset can be controlled via the "Qt Settings" + dialog box ("Preferences..." on OSX) +Qt: draw a border around each tile in the paper doll inventory; when BUC is + known for a doll item, change the border's color and thicken it +Qt: letting the mouse hover over the paper doll shows a tool tip describing + the object--or lack of same--in the slot under the pointer +Qt: clicking on the paper doll runs the #seeall command (inventory of wielded + and worn items plus tools [lamps, leashes] actively in use; in other + words, same set of things whose tiles are used to populate the doll) +Qt: clicking on the status window runs the #attributes command (^X) +Qt: add a Search button to the toolbar +Qt: support the 'hitpointbar' option +Qt: add Filter, Layout, and Reset buttons to the extended command selector; + Filter is only useful in wizard mode, allowing changing the set of + extended commands between "all", "normal mode only", "extra wizard + mode only"; Layout redisplays the grid of command buttons, toggling + from down columns to across rows or vice versa; Reset puts both back + to their default settings and clears any pending typed input +tiles: male and female variations in monsters.txt; tested only with tile2bmp + conversion utility so far; also supported by tilemap utility to + generate tile.c +Unix: can define NOSUSPEND in config.h or src/Makefile's CFLAGS to prevent + unixconf.h from enabling SUSPEND without need to modify unixconf.h NetHack Community Patches (or Variation) Included @@ -432,10 +781,17 @@ always print a message when the hero level teleports (github #265) remove Sokoban luck penalties for actions you can't cheat with (github #260) sounds for minotaurs (github #298) 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 + state that they work with video:vesa; the video:vga setting that was described there forces the 640x480x16 mode where video_width and video_height don't operate (github #294) redo rndmonst() to operate in a single pass (github pull request #286) +fix the "stuck pets" issue (github #329) +allow themed room subrooms to be filled (github #347) +allow rereading spellbooks to refresh memory at any time (github #261) +allow themed rooms constrained by level difficulty (github #344) +add a varied form of LIBNH nethack library contribution (github #385, #403) +add cross-compile to WASM (github #385, #403, #412) +differentiating gendered monster tiles from NullCGT (#430) Code Cleanup and Reorganization @@ -472,10 +828,28 @@ resurrect 'makedefs -m' to be able to derive default mons[].diffculty values suitable for assigning to new or changed monsters convert obj->oextra->omid from pointer to scalar get rid of unused obj->oextra->olong -relocated unmaintained code to outdated folder, specifically sys/amiga, +relocated unmaintained code to outdated folder, specifically sys/amiga, sys/atari, sys/be, sys/mac, sys/os2, sys/wince, win/Qt3, win/gem, win/gnome, include/amiconf.h, include/beconf.h, include/def_os2.h, include/os2conf.h, include/macconf.h, include/tosconf.h, include/wceconf.h removed SYSFLAGS conditional code removed MFLOPPY conditional code +get rid of 3.6.1 workaround needed to retain compatibility with 3.6.0 bones + files after fix for 3.3.0 through 3.6.0 bug for invalid 'bonesid' + designation in bones of quest levels +add an additional note to mextra.h and obj.h comments that reminds people to + appropriately init new fields if they need to initialize to something + other than zero +rework stairs structure into a linked list +move 'restoring' to the program_state struct; add corresponding 'saving'; + both used to enforce no updating of status lines or of persistent + inventory when the relevant activity is in progress +unify special attack damages from separate you-hit-monster, monster-hits-you, + and monster-hits-monster into functions by damage type +unify trap effects for hero and monster stepping on the trap by trap type +replace the single permonst mname field with male, female, and gender-neutral + names pmnames[NUM_MGENDERS] fields +add a new glyphmod parameter to window interface *_print_glyph() to be used + to provide additional details to the window port beyond the glyph; + begin to phase out the mapglyph() calls from within windows ports diff --git a/doc/lua.adoc b/doc/lua.adoc index 27da21ed9..b19186003 100644 --- a/doc/lua.adoc +++ b/doc/lua.adoc @@ -111,6 +111,15 @@ Example: local str = nh.ing_suffix("foo"); +=== level_difficulty + +Returns an integer value describing the level difficulty. +Normally this is the level's physical depth from the surface. + +Example: + + local diff = nh.level_difficulty(); + === makeplural Pluralize the given string. @@ -304,13 +313,13 @@ Set flags for this level. | nommap | Prevents magic mapping | shortsighted | Prevents monsters from seeing the hero from far away | arboreal | Notionally an outdoor map; replaces solid stone with trees -| mazelevel | +| mazelevel | | shroud | Unseen locations on the level will not be remembered by the hero, instead of rendering as out-of-sight map, trap, and object glyphs like they normally do. | graveyard | Treats the level as a graveyard level (causes graveyard sounds and undead have a reduced chance of leaving corpses). | icedpools | Ice generated with the level will be treated as frozen pools instead of frozen moats. -| corrmaze | +| corrmaze | | premapped | Map, including traps and boulders, is revealed on entrance. -| solidify | Areas outside the specified level map are made undiggable and unphaseable. +| solidify | Areas outside the specified level map are made undiggable and unphaseable. | inaccessibles | If inaccessible areas are generated, generate ways for them to connect to the "accessible" area. | noflip | Prevent flipping the level. | noflipx | Prevent flipping the level horizontally. @@ -471,7 +480,7 @@ Example: Example: des.region(selection, lit); - des.region({ x1=NN, y1=NN, x2=NN, y2=NN, lit=BOOL, type=ROOMTYPE, joined=BOOL, irregular=BOOL, prefilled=BOOL [ , contents = FUNCTION ] }); + des.region({ x1=NN, y1=NN, x2=NN, y2=NN, lit=BOOL, type=ROOMTYPE, joined=BOOL, irregular=BOOL, filled=NN [ , contents = FUNCTION ] }); des.region({ region={x1,y1, x2,y2}, type="ordinary" }); === replace_terrain diff --git a/doc/tmac.nh b/doc/tmac.nh index 5a1bd0a60..473f33a38 100644 --- a/doc/tmac.nh +++ b/doc/tmac.nh @@ -1,4 +1,4 @@ -.\" NetHack 3.6 tmac.nh $NHDT-Date: $ $NHDT-Branch: $:$NHDT-Revision: $ +.\" NetHack 3.7 tmac.nh $NHDT-Date: $ $NHDT-Branch: $:$NHDT-Revision: $ . .\" Miscellaneous tmac.n-style macros specifically for nethack's Guidebook. .\" diff --git a/doc/window.doc b/doc/window.doc index 73caf9322..bd55a5ac0 100644 --- a/doc/window.doc +++ b/doc/window.doc @@ -1,4 +1,4 @@ -NetHack 3.6 window.doc $NHDT-Date: 1433901374 2015/06/10 01:56:14 $ $NHDT-Branch: master $:$NHDT-Revision: 1.42 $ +NetHack 3.7 window.doc $NHDT-Date: 1596498145 2020/08/03 23:42:25 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.58 $ Introduction @@ -192,7 +192,7 @@ int nh_poskey(int *x, int *y, int *mod) B. High-level routines: -print_glyph(window, x, y, glyph, bkglyph) +print_glyph(window, x, y, glyph, bkglyph, glyphmod[3]) -- Print the glyph at (x,y) on the given window. Glyphs are integers at the interface, mapped to whatever the window- port wants (symbol, font, color, attributes, ...there's @@ -202,7 +202,10 @@ print_glyph(window, x, y, glyph, bkglyph) to fall against a background consistent with the grid around x,y. If bkglyph is NO_GLYPH, then the parameter should be ignored (do nothing with it). - + -- glyphmod (glyphmod[NUM_GLYPHNOD]) provides extended + information about the glyph that window ports can use to + enhance the display in various ways. + char yn_function(const char *ques, const char *choices, char default) -- Print a prompt made up of ques, choices and default. Read a single character response that is contained in diff --git a/include/align.h b/include/align.h index 47ad97f5d..bd7b70cc1 100644 --- a/include/align.h +++ b/include/align.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 align.h $NHDT-Date: 1432512779 2015/05/25 00:12:59 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ +/* NetHack 3.7 align.h $NHDT-Date: 1604269810 2020/11/01 22:30:10 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.15 $ */ /* Copyright (c) Mike Stephenson, Izchak Miller 1991. */ /* NetHack may be freely redistributed. See license for details. */ @@ -30,15 +30,30 @@ typedef struct align { /* alignment & record */ #define AM_LAWFUL 4 #define AM_MASK 7 +/* Some altars are considered as shrines, so we need a flag for that + for the altarmask field of struct rm. */ +#define AM_SHRINE 8 -#define AM_SPLEV_CO 3 -#define AM_SPLEV_NONCO 7 +/* special level flags, gone by the time the level has been loaded */ +#define AM_SPLEV_CO 3 /* co-aligned: force alignment to match hero's */ +#define AM_SPLEV_NONCO 7 /* non-co-aligned: force alignment to not match */ #define AM_SPLEV_RANDOM 8 -#define Amask2align(x) \ - ((aligntyp)((!(x)) ? A_NONE : ((x) == AM_LAWFUL) ? A_LAWFUL \ - : ((int) x) - 2)) +#define Amask2align(x) \ + ((aligntyp) ((((x) & AM_MASK) == 0) ? A_NONE \ + : (((x) & AM_MASK) == AM_LAWFUL) ? A_LAWFUL \ + : ((int) ((x) & AM_MASK)) - 2)) /* 2 => 0, 1 => -1 */ #define Align2amask(x) \ - (((x) == A_NONE) ? AM_NONE : ((x) == A_LAWFUL) ? AM_LAWFUL : (x) + 2) + ((unsigned) (((x) == A_NONE) ? AM_NONE \ + : ((x) == A_LAWFUL) ? AM_LAWFUL \ + : ((x) + 2))) /* -1 => 1, 0 => 2 */ + +/* Because clearly Nethack needs more ways to specify alignment... + Amask2msa(): 1, 2, 4 converted to 1, 2, 3 to fit within a width 2 bitfield; + Msa2amask(): 1, 2, 3 converted back to 1, 2, 4; + For Amask2msa(), 'x' might have the shrine bit set so strip that off. */ +#define Amask2msa(x) ((((x) & AM_MASK) == 4) ? 3 : (x) & AM_MASK) +#define Msa2amask(x) (((x) == 3) ? 4 : (x)) +#define MSA_NONE 0 /* unaligned or multiple alignments */ #endif /* ALIGN_H */ diff --git a/include/artifact.h b/include/artifact.h index 4e5193f55..b91e3602e 100644 --- a/include/artifact.h +++ b/include/artifact.h @@ -1,43 +1,40 @@ -/* NetHack 3.6 artifact.h $NHDT-Date: 1433050871 2015/05/31 05:41:11 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ */ +/* NetHack 3.7 artifact.h $NHDT-Date: 1602692711 2020/10/14 16:25:11 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.15 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2011. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef ARTIFACT_H #define ARTIFACT_H +/* clang-format off */ -#define SPFX_NONE 0x00000000L /* no special effects, just a bonus */ -#define SPFX_NOGEN 0x00000001L /* item is special, bequeathed by gods */ -#define SPFX_RESTR 0x00000002L /* item is restricted - can't be named */ -#define SPFX_INTEL 0x00000004L /* item is self-willed - intelligent */ -#define SPFX_SPEAK 0x00000008L /* item can speak (not implemented) */ -#define SPFX_SEEK 0x00000010L /* item helps you search for things */ -#define SPFX_WARN 0x00000020L /* item warns you of danger */ -#define SPFX_ATTK 0x00000040L /* item has a special attack (attk) */ -#define SPFX_DEFN 0x00000080L /* item has a special defence (defn) */ -#define SPFX_DRLI 0x00000100L /* drains a level from monsters */ +#define SPFX_NONE 0x00000000L /* no special effects, just a bonus */ +#define SPFX_NOGEN 0x00000001L /* item is special, bequeathed by gods */ +#define SPFX_RESTR 0x00000002L /* item is restricted - can't be named */ +#define SPFX_INTEL 0x00000004L /* item is self-willed - intelligent */ +#define SPFX_SPEAK 0x00000008L /* item can speak (not implemented) */ +#define SPFX_SEEK 0x00000010L /* item helps you search for things */ +#define SPFX_WARN 0x00000020L /* item warns you of danger */ +#define SPFX_ATTK 0x00000040L /* item has a special attack (attk) */ +#define SPFX_DEFN 0x00000080L /* item has a special defence (defn) */ +#define SPFX_DRLI 0x00000100L /* drains a level from monsters */ #define SPFX_SEARCH 0x00000200L /* helps searching */ #define SPFX_BEHEAD 0x00000400L /* beheads monsters */ #define SPFX_HALRES 0x00000800L /* blocks hallucinations */ -#define SPFX_ESP 0x00001000L /* ESP (like amulet of ESP) */ -#define SPFX_STLTH 0x00002000L /* Stealth */ -#define SPFX_REGEN 0x00004000L /* Regeneration */ +#define SPFX_ESP 0x00001000L /* ESP (like amulet of ESP) */ +#define SPFX_STLTH 0x00002000L /* Stealth */ +#define SPFX_REGEN 0x00004000L /* Regeneration */ #define SPFX_EREGEN 0x00008000L /* Energy Regeneration */ #define SPFX_HSPDAM 0x00010000L /* 1/2 spell damage (on player) in combat */ -#define SPFX_HPHDAM \ - 0x00020000L /* 1/2 physical damage (on player) in combat */ -#define SPFX_TCTRL 0x00040000L /* Teleportation Control */ -#define SPFX_LUCK 0x00080000L /* Increase Luck (like Luckstone) */ -#define SPFX_DMONS 0x00100000L /* attack bonus on one monster type */ -#define SPFX_DCLAS 0x00200000L /* attack bonus on monsters w/ symbol mtype \ - */ -#define SPFX_DFLAG1 0x00400000L /* attack bonus on monsters w/ mflags1 flag \ - */ -#define SPFX_DFLAG2 0x00800000L /* attack bonus on monsters w/ mflags2 flag \ - */ -#define SPFX_DALIGN 0x01000000L /* attack bonus on non-aligned monsters */ -#define SPFX_DBONUS 0x01F00000L /* attack bonus mask */ -#define SPFX_XRAY 0x02000000L /* gives X-RAY vision to player */ +#define SPFX_HPHDAM 0x00020000L /* 1/2 physical damage (on player) in combat */ +#define SPFX_TCTRL 0x00040000L /* Teleportation Control */ +#define SPFX_LUCK 0x00080000L /* Increase Luck (like Luckstone) */ +#define SPFX_DMONS 0x00100000L /* attack bonus on one monster type */ +#define SPFX_DCLAS 0x00200000L /* attack bonus on monsters w/ symbol mtype */ +#define SPFX_DFLAG1 0x00400000L /* attack bonus on monsters w/ mflags1 flag */ +#define SPFX_DFLAG2 0x00800000L /* attack bonus on monsters w/ mflags2 flag */ +#define SPFX_DALIGN 0x01000000L /* attack bonus on non-aligned monsters */ +#define SPFX_DBONUS 0x01F00000L /* attack bonus mask */ +#define SPFX_XRAY 0x02000000L /* gives X-RAY vision to player */ #define SPFX_REFLECT 0x04000000L /* Reflection */ #define SPFX_PROTECT 0x08000000L /* Protection */ @@ -52,7 +49,7 @@ struct artifact { aligntyp alignment; /* alignment of bequeathing gods */ short role; /* character role associated with */ short race; /* character race associated with */ - long cost; /* price when sold to hero (default 100 x base cost) */ + long cost; /* price when sold to hero (default 100 x base cost) */ char acolor; /* color to use if artifact 'glows' */ }; @@ -69,4 +66,5 @@ enum invoke_prop_types { CREATE_AMMO }; +/* clang-format on */ #endif /* ARTIFACT_H */ diff --git a/include/artilist.h b/include/artilist.h index d7b8f250c..c95f41775 100644 --- a/include/artilist.h +++ b/include/artilist.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 artilist.h $NHDT-Date: 1564351548 2019/07/28 22:05:48 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.20 $ */ +/* NetHack 3.7 artilist.h $NHDT-Date: 1596498526 2020/08/03 23:48:46 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.23 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2017. */ /* NetHack may be freely redistributed. See license for details. */ @@ -180,7 +180,7 @@ static NEARDATA struct artifact artilist[] = { 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_CAVEMAN, NON_PM, 2500L, + DFNS(AD_MAGM), NO_CARY, CONFLICT, A_LAWFUL, PM_CAVE_DWELLER, NON_PM, 2500L, NO_COLOR), #if 0 /* OBSOLETE */ @@ -210,7 +210,7 @@ A("The Palantir of Westernesse", CRYSTAL_BALL, 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_PRIEST, NON_PM, 2000L, NO_COLOR), + PM_CLERIC, NON_PM, 2000L, NO_COLOR), A("The Longbow of Diana", BOW, (SPFX_NOGEN | SPFX_RESTR | SPFX_INTEL | SPFX_REFLECT), SPFX_ESP, 0, diff --git a/include/attrib.h b/include/attrib.h index ecd29ab38..b3a5d82e7 100644 --- a/include/attrib.h +++ b/include/attrib.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 attrib.h $NHDT-Date: 1432512779 2015/05/25 00:12:59 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ +/* NetHack 3.7 attrib.h $NHDT-Date: 1596498527 2020/08/03 23:48:47 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.12 $ */ /* Copyright 1988, Mike Stephenson */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/include/botl.h b/include/botl.h index c91d76db6..89ca4f2df 100644 --- a/include/botl.h +++ b/include/botl.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 botl.h $NHDT-Date: 1562187996 2019/07/03 21:06:36 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.27 $ */ +/* NetHack 3.7 botl.h $NHDT-Date: 1596498528 2020/08/03 23:48:48 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.34 $ */ /* Copyright (c) Michael Allison, 2003 */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/include/color.h b/include/color.h index b05ae6d73..4b9f8a1cf 100644 --- a/include/color.h +++ b/include/color.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 color.h $NHDT-Date: 1432512776 2015/05/25 00:12:56 $ $NHDT-Branch: master $:$NHDT-Revision: 1.13 $ */ +/* NetHack 3.7 color.h $NHDT-Date: 1596498528 2020/08/03 23:48:48 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.15 $ */ /* Copyright (c) Steve Linhart, Eric Raymond, 1989. */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/include/config.h b/include/config.h index 7083a09bf..d9e4fbb25 100644 --- a/include/config.h +++ b/include/config.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 config.h $NHDT-Date: 1594169990 2020/07/08 00:59:50 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.139 $ */ +/* NetHack 3.7 config.h $NHDT-Date: 1608933417 2020/12/25 21:56:57 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.146 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2016. */ /* NetHack may be freely redistributed. See license for details. */ @@ -58,14 +58,13 @@ /* #define CURSES_GRAPHICS *//* Curses interface - Karl Garrison*/ /* #define X11_GRAPHICS */ /* X11 interface */ /* #define QT_GRAPHICS */ /* Qt interface */ -/* #define GNOME_GRAPHICS */ /* Gnome interface */ /* #define MSWIN_GRAPHICS */ /* Windows NT, CE, Graphics */ /* * Define the default window system. This should be one that is compiled * into your system (see defines above). Known window systems are: * - * tty, X11, mac, amii, BeOS, Qt, Gem, Gnome + * tty, X11, mac, amii, BeOS, Qt, Gem, Gnome, shim */ /* MAC also means MAC windows */ @@ -103,16 +102,24 @@ #ifndef NOUSER_SOUNDS #define USER_SOUNDS /* Use sounds */ #endif +#ifndef USE_XPM #define USE_XPM /* Use XPM format for images (required) */ +#endif +#ifndef GRAPHIC_TOMBSTONE #define GRAPHIC_TOMBSTONE /* Use graphical tombstone (rip.ppm) */ +#endif #ifndef DEFAULT_WINDOW_SYS #define DEFAULT_WINDOW_SYS "Qt" #endif #endif #ifdef GNOME_GRAPHICS +#ifndef USE_XPM #define USE_XPM /* Use XPM format for images (required) */ +#endif +#ifndef GRAPHIC_TOMBSTONE #define GRAPHIC_TOMBSTONE /* Use graphical tombstone (rip.ppm) */ +#endif #ifndef DEFAULT_WINDOW_SYS #define DEFAULT_WINDOW_SYS "Gnome" #endif @@ -125,9 +132,11 @@ #define HACKDIR "\\nethack" #endif +#ifdef TTY_GRAPHICS #ifndef DEFAULT_WINDOW_SYS #define DEFAULT_WINDOW_SYS "tty" #endif +#endif #ifdef CURSES_GRAPHICS #ifndef DEFAULT_WINDOW_SYS @@ -135,6 +144,12 @@ #endif #endif +#ifdef SHIM_GRAPHICS +#ifndef DEFAULT_WINDOW_SYS +#define DEFAULT_WINDOW_SYS "shim" +#endif +#endif + #ifdef X11_GRAPHICS /* * There are two ways that X11 tiles may be defined. (1) using a custom @@ -146,8 +161,10 @@ */ /* # define USE_XPM */ /* Disable if you do not have the XPM library */ #ifdef USE_XPM +#ifndef GRAPHIC_TOMBSTONE #define GRAPHIC_TOMBSTONE /* Use graphical tombstone (rip.xpm) */ #endif +#endif #ifndef DEFAULT_WC_TILED_MAP #define DEFAULT_WC_TILED_MAP /* Default to tiles */ #endif @@ -440,24 +457,15 @@ typedef unsigned char uchar; /* #define STRNCMPI */ /* compiler/library has the strncmpi function */ /* - * There are various choices for the NetHack vision system. There is a - * choice of two algorithms with the same behavior. Defining VISION_TABLES - * creates huge (60K) tables at compile time, drastically increasing data - * size, but runs slightly faster than the alternate algorithm. (MSDOS in - * particular cannot tolerate the increase in data size; other systems can - * flip a coin weighted to local conditions.) + * Vision choices. * - * If VISION_TABLES is not defined, things will be faster if you can use - * MACRO_CPATH. Some cpps, however, cannot deal with the size of the - * functions that have been macroized. + * Things will be faster if you can use MACRO_CPATH. Some cpps, however, + * cannot deal with the size of the functions that have been macroized. */ -/* #define VISION_TABLES */ /* use vision tables generated at compile time */ -#ifndef VISION_TABLES #ifndef NO_MACRO_CPATH #define MACRO_CPATH /* use clear_path macros instead of functions */ #endif -#endif #if !defined(MAC) #if !defined(NOCLIPPING) @@ -465,7 +473,12 @@ typedef unsigned char uchar; #endif #endif -#define DOAGAIN '\001' /* ^A, the "redo" key used in cmd.c and getline.c */ +/* The "repeat" key used in cmd.c as NHKF_DOAGAIN; if commented out or the + * value is changed from C('A') to 0, it won't be bound to any keystroke + * unless you use the run-time configuration file's BIND directive for it. + * [Note: C() macro isn't defined yet but it will be before DOAGAIN is used.] + */ +#define DOAGAIN C('A') /* repeat previous command; default is ^A, '\001' */ /* CONFIG_ERROR_SECURE: If user makes NETHACKOPTIONS point to a file ... * TRUE: Show the first error, nothing else. diff --git a/include/config1.h b/include/config1.h index 172de10b1..e93b98d22 100644 --- a/include/config1.h +++ b/include/config1.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 config1.h $NHDT-Date: 1594169991 2020/07/08 00:59:51 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.22 $ */ +/* NetHack 3.7 config1.h $NHDT-Date: 1596498530 2020/08/03 23:48:50 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.23 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Kenneth Lorber, Kensington, Maryland, 2015. */ /* NetHack may be freely redistributed. See license for details. */ @@ -28,8 +28,10 @@ #ifdef MSDOS #undef UNIX +#ifndef CROSSCOMPILE #define SHORT_FILENAMES #endif +#endif /* * Mac Stuff. diff --git a/include/context.h b/include/context.h index e2bd9b49f..fe7b3ab72 100644 --- a/include/context.h +++ b/include/context.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 context.h $NHDT-Date: 1580434522 2020/01/31 01:35:22 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.39 $ */ +/* NetHack 3.7 context.h $NHDT-Date: 1596498530 2020/08/03 23:48:50 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.41 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2006. */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/include/coord.h b/include/coord.h index e800fb876..9c066db26 100644 --- a/include/coord.h +++ b/include/coord.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 coord.h $NHDT-Date: 1432512778 2015/05/25 00:12:58 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ */ +/* NetHack 3.7 coord.h $NHDT-Date: 1596498531 2020/08/03 23:48:51 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.11 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Kenneth Lorber, Kensington, Maryland, 2015. */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/include/decl.h b/include/decl.h index 94e4581d0..59f599866 100644 --- a/include/decl.h +++ b/include/decl.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 decl.h $NHDT-Date: 1593953331 2020/07/05 12:48:51 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.238 $ */ +/* NetHack 3.7 decl.h $NHDT-Date: 1607641577 2020/12/10 23:06:17 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.248 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2007. */ /* NetHack may be freely redistributed. See license for details. */ @@ -75,16 +75,6 @@ struct dgn_topology { /* special dungeon levels for speed */ #define sokoend_level (g.dungeon_topology.d_sokoend_level) /* clang-format on */ -#define xdnstair (g.dnstair.sx) -#define ydnstair (g.dnstair.sy) -#define xupstair (g.upstair.sx) -#define yupstair (g.upstair.sy) - -#define xdnladder (g.dnladder.sx) -#define ydnladder (g.dnladder.sy) -#define xupladder (g.upladder.sx) -#define yupladder (g.upladder.sy) - #define dunlev_reached(x) (g.dungeons[(x)->dnum].dunlev_ureached) #include "quest.h" @@ -104,6 +94,8 @@ struct sinfo { int something_worth_saving; /* in case of panic */ int panicking; /* `panic' is in progress */ int exiting; /* an exit handler is executing */ + int saving; + int restoring; int in_moveloop; int in_impossible; int in_self_recover; @@ -424,15 +416,16 @@ enum nh_keyfunc { NHKF_REQMENU, /* run ... clicklook need to be in a continuous block */ - NHKF_RUN, - NHKF_RUN2, - NHKF_RUSH, - NHKF_FIGHT, - NHKF_FIGHT2, - NHKF_NOPICKUP, - NHKF_RUN_NOPICKUP, - NHKF_DOINV, - NHKF_TRAVEL, + NHKF_RUN, /* 'G' */ + NHKF_RUN2, /* '5' or M-5 */ + NHKF_RUSH, /* 'g' */ + NHKF_RUSH2, /* M-5 or '5' */ + NHKF_FIGHT, /* 'F' */ + NHKF_FIGHT2, /* '-' */ + NHKF_NOPICKUP, /* 'm' */ + NHKF_RUN_NOPICKUP, /* 'M' */ + NHKF_DOINV, /* '0' */ + NHKF_TRAVEL, /* via mouse */ NHKF_CLICKLOOK, NHKF_REDRAW, @@ -531,6 +524,9 @@ struct trapinfo { typedef struct { xchar gnew; /* perhaps move this bit into the rm structure. */ int glyph; +#ifndef UNBUFFERED_GLYPHMOD + unsigned glyphmod[NUM_GLYPHMOD]; +#endif } gbuf_entry; enum vanq_order_modes { @@ -632,19 +628,15 @@ struct role_filter { struct _create_particular_data { int quan; int which; - int fem; + int fem; /* -1, MALE, FEMALE, NEUTRAL */ + int genderconf; /* conflicting gender */ char monclass; boolean randmonst; boolean maketame, makepeaceful, makehostile; boolean sleeping, saddled, invisible, hidden; }; -/* instance_globals holds engine state that does not need to be - * persisted upon game exit. The initialization state is well defined - * an set in decl.c during early early engine initialization. - * - * unlike instance_flags, values in the structure can be of any type. */ - +/* some array sizes for 'g' */ #define BSIZE 20 #define WIZKIT_MAX 128 #define CVT_BUF_SIZE 64 @@ -652,6 +644,16 @@ struct _create_particular_data { #define LUA_VER_BUFSIZ 20 #define LUA_COPYRIGHT_BUFSIZ 120 +/* + * 'g' -- instance_globals holds engine state that does not need to be + * persisted upon game exit. The initialization state is well defined + * and set in decl.c during early early engine initialization. + * + * Unlike instance_flags, values in the structure can be of any type. + * + * Pulled from other files to be grouped in one place. Some comments + * which came with them don't make much sense out of their original context. + */ struct instance_globals { /* apply.c */ @@ -684,12 +686,12 @@ struct instance_globals { /* cmd.c */ struct cmd Cmd; /* flag.h */ - /* Provide a means to redo the last command. The flag `in_doagain' is set - * to true while redoing the command. This flag is tested in commands that - * require additional input (like `throw' which requires a thing and a - * direction), and the input prompt is not shown. Also, while in_doagain is - * TRUE, no keystrokes can be saved into the saveq. - */ + /* Provide a means to redo the last command. The flag `in_doagain' + (decl.c below) is set to true while redoing the command. This flag + is tested in commands that require additional input (like `throw' + which requires a thing and a direction), and the input prompt is + not shown. Also, while in_doagain is TRUE, no keystrokes can be + saved into the saveq. */ char pushq[BSIZE]; char saveq[BSIZE]; int phead; @@ -721,10 +723,7 @@ struct instance_globals { int y_maze_max; int otg_temp; /* used by object_to_glyph() [otg] */ int in_doagain; - stairway dnstair; /* stairs down */ - stairway upstair; /* stairs up */ - stairway dnladder; /* ladder down */ - stairway upladder; /* ladder up */ + stairway *stairs; int smeq[MAXNROFROOMS + 1]; int doorindex; char *save_cm; @@ -749,7 +748,6 @@ struct instance_globals { number of shots, index of current one, validity check, shoot vs throw */ struct multishot m_shot; dungeon dungeons[MAXDUNGEON]; /* ini'ed by init_dungeon() */ - stairway sstairs; dest_area updest; dest_area dndest; coord inv_pos; @@ -760,9 +758,6 @@ struct instance_globals { boolean mrg_to_wielded; /* weapon picked is merged with wielded one */ struct plinemsg_type *plinemsg_types; char toplines[TBUFSZ]; - struct mkroom *upstairs_room; - struct mkroom *dnstairs_room; - struct mkroom *sstairs_room; coord bhitpos; /* place where throw or zap hits or stops */ boolean in_steed_dismounting; coord doors[DOORMAX]; @@ -815,8 +810,8 @@ struct instance_globals { /* display.c */ gbuf_entry gbuf[ROWNO][COLNO]; - char gbuf_start[ROWNO]; - char gbuf_stop[ROWNO]; + xchar gbuf_start[ROWNO]; + xchar gbuf_stop[ROWNO]; /* do.c */ @@ -840,7 +835,7 @@ struct instance_globals { int petname_used; /* user preferred pet name has been used */ xchar gtyp; /* type of dog's current goal */ xchar gx; /* x position of dog's current goal */ - char gy; /* y position of dog's current goal */ + xchar gy; /* y position of dog's current goal */ char dogname[PL_PSIZ]; char catname[PL_PSIZ]; char horsename[PL_PSIZ]; @@ -932,9 +927,10 @@ struct instance_globals { /* makemon.c */ /* mhitm.c */ - boolean vis; - boolean far_noise; long noisetime; + boolean far_noise; + boolean vis; + boolean skipdrin; /* mind flayer against headless target */ /* mhitu.c */ int mhitu_dieroll; @@ -966,6 +962,7 @@ struct instance_globals { /* mon.c */ boolean vamp_rise_msg; boolean disintegested; + boolean zombify; short *animal_list; /* list of PM values for animal monsters */ int animal_list_count; @@ -998,34 +995,35 @@ struct instance_globals { /* objname.c */ /* distantname used by distant_name() to pass extra information to xname_flags(); it would be much cleaner if this were a parameter, - but that would require all of the xname() and doname() calls to be - modified */ + but that would require all xname() and doname() calls to be modified */ int distantname; /* options.c */ struct symsetentry *symset_list; /* files.c will populate this with - list of available sets */ - /* - * Allow the user to map incoming characters to various menu commands. - * The accelerator list must be a valid C string. - */ + * list of available sets */ + /* Allow the user to map incoming characters to various menu commands. */ char mapped_menu_cmds[MAX_MENU_MAPPED_CMDS + 1]; /* exported */ char mapped_menu_op[MAX_MENU_MAPPED_CMDS + 1]; short n_menu_mapped; + /* options processing */ boolean opt_initial; boolean opt_from_file; boolean opt_need_redraw; /* for doset() */ + /* use menucolors to show colors in the pick-a-color menu */ + boolean save_menucolors; /* copy of iflags.use_menu_colors */ + struct menucoloring *save_colorings; /* copy of g.menu_colorings */ + struct menucoloring *color_colorings; /* alternate set of menu colors */ /* pickup.c */ int oldcap; /* last encumberance */ /* current_container is set in use_container(), to be used by the callback routines in_container() and out_container() from askchain() - and use_container(). Also used by menu_loot() and container_gone(). */ + and use_container(). Also used by menu_loot() and container_gone(). */ struct obj *current_container; boolean abort_looting; /* Value set by query_objlist() for n_or_more(). */ long val_for_n_or_more; - /* list of valid menu classes for query_objlist() and allow_category callback + /* list of menu classes for query_objlist() and allow_category callback (with room for all object classes, 'u'npaid, BUCX, and terminator) */ char valid_menu_classes[MAXOCLASSES + 1 + 4 + 1]; boolean class_filter; @@ -1110,6 +1108,8 @@ struct instance_globals { boolean havestate; unsigned ustuck_id; /* need to preserve during save */ unsigned usteed_id; /* need to preserve during save */ + struct obj *looseball; /* track uball during save and... */ + struct obj *loosechain; /* track uchain since saving might free it */ /* shk.c */ /* auto-response flag for/from "sell foo?" 'a' => 'y', 'q' => 'n' */ @@ -1140,7 +1140,6 @@ struct instance_globals { unsigned int stealmid; /* monster doing the stealing */ /* teleport.c */ - struct obj *telescroll; /* non-null when teleporting via this scroll */ /* timeout.c */ /* ordered timer list */ @@ -1179,9 +1178,9 @@ struct instance_globals { Stormbringer's maliciousness. */ /* vision.c */ - char **viz_array; /* used in cansee() and couldsee() macros */ - char *viz_rmin; /* min could see indices */ - char *viz_rmax; /* max could see indices */ + xchar **viz_array; /* used in cansee() and couldsee() macros */ + xchar *viz_rmin; /* min could see indices */ + xchar *viz_rmax; /* max could see indices */ boolean vision_full_recalc; /* weapon.c */ diff --git a/include/dgn_file.h b/include/dgn_file.h index 442905cfb..dc3422391 100644 --- a/include/dgn_file.h +++ b/include/dgn_file.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 dgn_file.h $NHDT-Date: 1432512780 2015/05/25 00:13:00 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ +/* NetHack 3.7 dgn_file.h $NHDT-Date: 1596498533 2020/08/03 23:48:53 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.10 $ */ /* Copyright (c) 1989 by M. Stephenson */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/include/display.h b/include/display.h index 7813c008a..1c944c276 100644 --- a/include/display.h +++ b/include/display.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 display.h $NHDT-Date: 1559994621 2019/06/08 11:50:21 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.32 $ */ +/* NetHack 3.7 display.h $NHDT-Date: 1605927391 2020/11/21 02:56:31 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.48 $ */ /* Copyright (c) Dean Luick, with acknowledgements to Kevin Darcy */ /* and Dave Cohrs, 1990. */ /* NetHack may be freely redistributed. See license for details. */ @@ -69,6 +69,15 @@ enum explosion_types { * hero can physically see the location of the monster. The function * vobj_at() returns a pointer to an object that the hero can see there. * Infravision is not taken into account. + * + * Note: not reliable for concealed mimics. They don't have + * 'mon->mundetected' set even when mimicking objects or furniture. + * [Fixing this with a pair of mon->m_ap_type checks here (via either + * 'typ!=object && typ!=furniture' or 'typ==nothing || typ==monster') + * will require reviewing every instance of mon_visible(), canseemon(), + * canspotmon(), is_safemon() and perhaps others. Fixing it by setting + * mon->mundetected when concealed would be better but also require + * reviewing all those instances and also existing mundetected instances.] */ #if 0 #define mon_visible(mon) \ @@ -328,18 +337,18 @@ enum explosion_types { /* This has the unfortunate side effect of needing a global variable */ /* to store a result. 'otg_temp' is defined and declared in decl.{ch}. */ -#define random_obj_to_glyph(rng) \ - ((g.otg_temp = random_object(rng)) == CORPSE \ - ? random_monster(rng) + GLYPH_BODY_OFF \ +#define random_obj_to_glyph(rng) \ + ((g.otg_temp = random_object(rng)) == CORPSE \ + ? random_monster(rng) + GLYPH_BODY_OFF \ : g.otg_temp + GLYPH_OBJ_OFF) -#define obj_to_glyph(obj, rng) \ - (((obj)->otyp == STATUE) \ - ? statue_to_glyph(obj, rng) \ - : Hallucination \ - ? random_obj_to_glyph(rng) \ - : ((obj)->otyp == CORPSE) \ - ? (int) (obj)->corpsenm + GLYPH_BODY_OFF \ +#define obj_to_glyph(obj, rng) \ + (((obj)->otyp == STATUE) \ + ? statue_to_glyph(obj, rng) \ + : Hallucination \ + ? random_obj_to_glyph(rng) \ + : ((obj)->otyp == CORPSE) \ + ? (int) (obj)->corpsenm + GLYPH_BODY_OFF \ : (int) (obj)->otyp + GLYPH_OBJ_OFF) /* MRKR: Statues now have glyphs corresponding to the monster they */ @@ -349,6 +358,16 @@ enum explosion_types { (Hallucination ? random_monster(rng) + GLYPH_MON_OFF \ : (int) (obj)->corpsenm + GLYPH_STATUE_OFF) +/* briefly used for Qt's "paper doll" inventory which shows map tiles for + equipped objects; those vary like floor items during hallucination now + so this isn't used anywhere */ +#define obj_to_true_glyph(obj) \ + (((obj)->otyp == STATUE) \ + ? ((int) (obj)->corpsenm + GLYPH_STATUE_OFF) \ + : ((obj)->otyp == CORPSE) \ + ? ((int) (obj)->corpsenm + GLYPH_BODY_OFF) \ + : ((int) (obj)->otyp + GLYPH_OBJ_OFF)) + #define cmap_to_glyph(cmap_idx) ((int) (cmap_idx) + GLYPH_CMAP_OFF) #define explosion_to_glyph(expltype, idx) \ ((((expltype) * MAXEXPCHARS) + ((idx) - S_explode1)) + GLYPH_EXPLODE_OFF) @@ -456,4 +475,27 @@ enum explosion_types { #define glyph_is_unexplored(glyph) ((glyph) == GLYPH_UNEXPLORED) #define glyph_is_nothing(glyph) ((glyph) == GLYPH_NOTHING) +/* flags for map_glyphmod */ + +/* mgflags for altering map_glyphmod() internal behaviour */ +#define MG_FLAG_NORMAL 0x00 +#define MG_FLAG_NOOVERRIDE 0x01 +#define MG_FLAG_RETURNIDX 0x02 + +/* Special mapped glyph flags encoded in glyphmod[GM_FLAGS] by map_glyphmod() */ +#define MG_CORPSE 0x0001 +#define MG_INVIS 0x0002 +#define MG_DETECT 0x0004 +#define MG_PET 0x0008 +#define MG_RIDDEN 0x0010 +#define MG_STATUE 0x0020 +#define MG_OBJPILE 0x0040 /* more than one stack of objects */ +#define MG_BW_LAVA 0x0080 /* 'black & white lava': highlight lava if it + can't be distringuished from water by color */ +#define MG_BW_ICE 0x0100 /* similar for ice vs floor */ +#define MG_NOTHING 0x0200 /* char represents GLYPH_NOTHING */ +#define MG_UNEXPL 0x0400 /* char represents GLYPH_UNEXPLORED */ +#define MG_FEMALE 0x0800 /* represents a female mon,detected mon,pet,ridden */ +#define MG_BADXY 0x1000 /* bad coordinates were passed */ + #endif /* DISPLAY_H */ diff --git a/include/dlb.h b/include/dlb.h index e8b9fd253..4c1e5e583 100644 --- a/include/dlb.h +++ b/include/dlb.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 dlb.h $NHDT-Date: 1432512780 2015/05/25 00:13:00 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ */ +/* NetHack 3.7 dlb.h $NHDT-Date: 1596498534 2020/08/03 23:48:54 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.12 $ */ /* Copyright (c) Kenneth Lorber, Bethesda, Maryland, 1993. */ /* NetHack may be freely redistributed. See license for details. */ @@ -9,7 +9,7 @@ #ifdef DLB /* implementations */ -#ifdef MAC +#if defined(MAC) && !defined(MAC_CROSS) #define DLBRSRC /* use Mac resources */ #else #define DLBLIB /* use a set of external files */ diff --git a/include/dungeon.h b/include/dungeon.h index 26508a184..7a07e58f4 100644 --- a/include/dungeon.h +++ b/include/dungeon.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 dungeon.h $NHDT-Date: 1593953333 2020/07/05 12:48:53 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.38 $ */ +/* NetHack 3.7 dungeon.h $NHDT-Date: 1596498535 2020/08/03 23:48:55 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.39 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2006. */ /* NetHack may be freely redistributed. See license for details. */ @@ -34,7 +34,9 @@ typedef struct s_level { /* special dungeon level element */ typedef struct stairway { /* basic stairway identifier */ xchar sx, sy; /* x / y location of the stair */ d_level tolev; /* where does it go */ - char up; /* what type of stairway (up/down) */ + boolean up; /* up or down? */ + boolean isladder; /* ladder or stairway? */ + struct stairway *next; } stairway; /* level region types */ @@ -182,14 +184,6 @@ struct linfo { * fountains"). This makes it also subject to player conditions (amnesia). */ -/* Because clearly Nethack needs more ways to specify alignment */ -#define Amask2msa(x) ((x) == 4 ? 3 : (x) &AM_MASK) -#define Msa2amask(x) ((x) == 3 ? 4 : (x)) -#define MSA_NONE 0 /* unaligned or multiple alignments */ -#define MSA_LAWFUL 1 -#define MSA_NEUTRAL 2 -#define MSA_CHAOTIC 3 - /* what the player knows about a single dungeon level */ /* initialized in mklev() */ typedef struct mapseen { diff --git a/include/engrave.h b/include/engrave.h index 86f6fcdb8..f16c66ec1 100644 --- a/include/engrave.h +++ b/include/engrave.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 engrave.h $NHDT-Date: 1432512777 2015/05/25 00:12:57 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ +/* NetHack 3.7 engrave.h $NHDT-Date: 1596498535 2020/08/03 23:48:55 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.10 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Kenneth Lorber, Kensington, Maryland, 2015. */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/include/extern.h b/include/extern.h index 663d42f65..3ddaaa6e2 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 extern.h $NHDT-Date: 1594168620 2020/07/08 00:37:00 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.851 $ */ +/* NetHack 3.7 extern.h $NHDT-Date: 1608749030 2020/12/23 18:43:50 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.934 $ */ /* Copyright (c) Steve Creps, 1988. */ /* NetHack may be freely redistributed. See license for details. */ @@ -47,6 +47,7 @@ E void FDECL(check_leash, (XCHAR_P, XCHAR_P)); E boolean FDECL(um_dist, (XCHAR_P, XCHAR_P, XCHAR_P)); E boolean FDECL(snuff_candle, (struct obj *)); E boolean FDECL(snuff_lit, (struct obj *)); +E boolean FDECL(splash_lit, (struct obj *)); E boolean FDECL(catch_lit, (struct obj *)); E void FDECL(use_unicorn_horn, (struct obj **)); E boolean FDECL(tinnable, (struct obj *)); @@ -205,22 +206,9 @@ E void FDECL(random_response, (char *, int)); E int NDECL(rnd_extcmd_idx); E int NDECL(domonability); E char FDECL(cmd_from_func, (int NDECL((*)))); +E const char *FDECL(cmdname_from_func, (int NDECL((*)), char *, BOOLEAN_P)); E boolean FDECL(redraw_cmd, (CHAR_P)); E const char *FDECL(levltyp_to_name, (int)); -#ifdef USE_TRAMPOLI -E int NDECL(doextcmd); -E int NDECL(domonability); -E int NDECL(doprev_message); -E int NDECL(timed_occupation); -E int NDECL(doattributes); -E int NDECL(wiz_detect); -E int NDECL(wiz_genesis); -E int NDECL(wiz_identify); -E int NDECL(wiz_level_tele); -E int NDECL(wiz_map); -E int NDECL(wiz_where); -E int NDECL(wiz_wish); -#endif /* USE_TRAMPOLI */ E void NDECL(reset_occupations); E void FDECL(set_occupation, (int (*)(void), const char *, int)); E char NDECL(pgetchar); @@ -228,7 +216,7 @@ E void FDECL(pushch, (CHAR_P)); E void FDECL(savech, (CHAR_P)); E const char *FDECL(key2extcmddesc, (UCHAR_P)); E boolean FDECL(bind_specialkey, (UCHAR_P, const char *)); -E char FDECL(txt2key, (char *)); +E uchar FDECL(txt2key, (char *)); E void FDECL(parseautocomplete, (char *, BOOLEAN_P)); E void FDECL(reset_commands, (BOOLEAN_P)); E void FDECL(rhack, (char *)); @@ -296,10 +284,6 @@ E void FDECL(use_crystal_ball, (struct obj **)); E void NDECL(do_mapping); E void FDECL(do_vicinity_map, (struct obj *)); E void FDECL(cvt_sdoor_to_door, (struct rm *)); -#ifdef USE_TRAMPOLI -E void FDECL(findone, (int, int, genericptr_t)); -E void FDECL(openone, (int, int, genericptr_t)); -#endif E int NDECL(findit); E int NDECL(openit); E boolean FDECL(detecting, (void (*)(int, int, genericptr))); @@ -312,14 +296,12 @@ E void NDECL(sokoban_detect); E void NDECL(dump_map); #endif E void FDECL(reveal_terrain, (int, int)); +E int NDECL(wiz_mgender); /* ### dig.c ### */ E int FDECL(dig_typ, (struct obj *, XCHAR_P, XCHAR_P)); E boolean NDECL(is_digging); -#ifdef USE_TRAMPOLI -E int NDECL(dig); -#endif E int NDECL(holetime); E boolean FDECL(dig_check, (struct monst *, BOOLEAN_P, int, int)); E void FDECL(digactualhole, (int, int, struct monst *, int)); @@ -394,13 +376,10 @@ E void NDECL(reglyph_darkroom); E void NDECL(set_wall_state); E void FDECL(unset_seenv, (struct rm *, int, int, int, int)); E int FDECL(warning_of, (struct monst *)); +E void FDECL(map_glyphmod, (XCHAR_P, XCHAR_P, int, unsigned, unsigned *)); /* ### do.c ### */ -#ifdef USE_TRAMPOLI -E int FDECL(drop, (struct obj *)); -E int NDECL(wipeoff); -#endif E int NDECL(dodrop); E boolean FDECL(boulder_hits_pool, (struct obj *, int, int, BOOLEAN_P)); E boolean FDECL(flooreffects, (struct obj *, int, int, const char *)); @@ -419,11 +398,13 @@ E void NDECL(save_currentstate); E void FDECL(u_collide_m, (struct monst *)); E void FDECL(goto_level, (d_level *, BOOLEAN_P, BOOLEAN_P, BOOLEAN_P)); E void NDECL(maybe_lvltport_feedback); -E void FDECL(schedule_goto, (d_level *, BOOLEAN_P, BOOLEAN_P, int, +E void FDECL(schedule_goto, (d_level *, int, const char *, const char *)); E void NDECL(deferred_goto); E boolean FDECL(revive_corpse, (struct obj *)); E void FDECL(revive_mon, (ANY_P *, long)); +E void FDECL(zombify_mon, (ANY_P *, long)); +E boolean FDECL(cmd_safety_prevention, (const char *, const char *, int *)); E int NDECL(donull); E int NDECL(dowipe); E void FDECL(legs_in_no_shape, (const char *, BOOLEAN_P)); @@ -437,8 +418,8 @@ E char *FDECL(coord_desc, (int, int, char *, CHAR_P)); E boolean FDECL(getpos_menu, (coord *, int)); E int FDECL(getpos, (coord *, BOOLEAN_P, const char *)); E void FDECL(getpos_sethilite, (void (*f)(int), boolean (*d)(int,int))); -E void FDECL(new_mname, (struct monst *, int)); -E void FDECL(free_mname, (struct monst *)); +E void FDECL(new_mgivenname, (struct monst *, int)); +E void FDECL(free_mgivenname, (struct monst *)); E void FDECL(new_oname, (struct obj *, int)); E void FDECL(free_oname, (struct obj *)); E const char *FDECL(safe_oname, (struct obj *)); @@ -479,17 +460,13 @@ E struct monst *FDECL(christen_orc, (struct monst *, const char *, const char *)); E const char *FDECL(noveltitle, (int *)); E const char *FDECL(lookup_novel, (const char *, int *)); +#ifndef PMNAME_MACROS +E int FDECL(Mgender, (struct monst *)); +E const char *FDECL(pmname, (struct permonst *, int)); +#endif /* PMNAME_MACROS */ /* ### do_wear.c ### */ -#ifdef USE_TRAMPOLI -E int NDECL(Armor_on); -E int NDECL(Boots_on); -E int NDECL(Gloves_on); -E int NDECL(Helmet_on); -E int FDECL(select_off, (struct obj *)); -E int NDECL(take_off); -#endif E const char *FDECL(fingers_or_gloves, (BOOLEAN_P)); E void FDECL(off_msg, (struct obj *)); E void FDECL(toggle_displacement, (struct obj *, long, BOOLEAN_P)); @@ -559,9 +536,6 @@ E struct obj *FDECL(droppables, (struct monst *)); E int FDECL(dog_nutrition, (struct monst *, struct obj *)); E int FDECL(dog_eat, (struct monst *, struct obj *, int, int, BOOLEAN_P)); E int FDECL(dog_move, (struct monst *, int)); -#ifdef USE_TRAMPOLI -E void FDECL(wantdoor, (int, int, genericptr_t)); -#endif E void FDECL(finish_meating, (struct monst *)); /* ### dokick.c ### */ @@ -627,6 +601,15 @@ E void FDECL(next_level, (BOOLEAN_P)); E void FDECL(prev_level, (BOOLEAN_P)); E void FDECL(u_on_newpos, (int, int)); E void FDECL(u_on_rndspot, (int)); +E void FDECL(stairway_add, (int,int, BOOLEAN_P, BOOLEAN_P, d_level *)); +E void NDECL(stairway_print); +E void NDECL(stairway_free_all); +E stairway *FDECL(stairway_at, (int, int)); +E stairway *FDECL(stairway_find, (d_level *)); +E stairway *FDECL(stairway_find_from, (d_level *, BOOLEAN_P)); +E stairway *FDECL(stairway_find_dir, (BOOLEAN_P)); +E stairway *FDECL(stairway_find_type_dir, (BOOLEAN_P, BOOLEAN_P)); +E stairway *FDECL(stairway_find_special_dir, (BOOLEAN_P)); E void FDECL(u_on_sstairs, (int)); E void NDECL(u_on_upstairs); E void NDECL(u_on_dnstairs); @@ -673,12 +656,6 @@ E const char *FDECL(endgamelevelname, (char *, int)); /* ### eat.c ### */ -#ifdef USE_TRAMPOLI -E int NDECL(eatmdone); -E int NDECL(eatfood); -E int NDECL(opentin); -E int NDECL(unfaint); -#endif E void NDECL(eatmupdate); E boolean FDECL(is_edible, (struct obj *)); E void NDECL(init_uhunger); @@ -712,9 +689,6 @@ E boolean FDECL(Popeye, (int)); E void FDECL(done1, (int)); E int NDECL(done2); -#ifdef USE_TRAMPOLI -E void FDECL(done_intr, (int)); -#endif E void FDECL(done_in_by, (struct monst *, int)); #endif /* !MAKEDEFS_C && MDLIB_C */ E void VDECL(panic, (const char *, ...)) PRINTF_F(1, 2) NORETURN; @@ -854,9 +828,6 @@ E boolean FDECL(Death_quote, (char *, int)); E void FDECL(floating_above, (const char *)); E void FDECL(dogushforth, (int)); -#ifdef USE_TRAMPOLI -E void FDECL(gush, (int, int, genericptr_t)); -#endif E void FDECL(dryup, (XCHAR_P, XCHAR_P, BOOLEAN_P)); E void NDECL(drinkfountain); E void FDECL(dipfountain, (struct obj *)); @@ -871,6 +842,7 @@ E anything *FDECL(long_to_any, (long)); E anything *FDECL(monst_to_any, (struct monst *)); E anything *FDECL(obj_to_any, (struct obj *)); E boolean FDECL(revive_nasty, (int, int, const char *)); +E int FDECL(still_chewing, (XCHAR_P, XCHAR_P)); E void FDECL(movobj, (struct obj *, XCHAR_P, XCHAR_P)); E boolean FDECL(may_dig, (XCHAR_P, XCHAR_P)); E boolean FDECL(may_passwall, (XCHAR_P, XCHAR_P)); @@ -883,6 +855,7 @@ E int NDECL(wiz_debug_cmd_traveldisplay); #endif E boolean NDECL(u_rooted); E void NDECL(domove); +E void NDECL(overexert_hp); E boolean NDECL(overexertion); E void NDECL(invocation_message); E void NDECL(switch_terrain); @@ -1006,15 +979,13 @@ E void NDECL(ustatusline); /* ### invent.c ### */ +E void FDECL(loot_classify, (Loot *, struct obj *)); E Loot *FDECL(sortloot, (struct obj **, unsigned, BOOLEAN_P, boolean (*)(OBJ_P))); E void FDECL(unsortloot, (Loot **)); E void FDECL(assigninvlet, (struct obj *)); E struct obj *FDECL(merge_choice, (struct obj *, struct obj *)); E int FDECL(merged, (struct obj **, struct obj **)); -#ifdef USE_TRAMPOLI -E int FDECL(ckunpaid, (struct obj *)); -#endif E void FDECL(addinv_core1, (struct obj *)); E void FDECL(addinv_core2, (struct obj *)); E struct obj *FDECL(addinv, (struct obj *)); @@ -1045,6 +1016,7 @@ E int FDECL(ggetobj, (const char *, int (*)(OBJ_P), int, BOOLEAN_P, unsigned *)); E int FDECL(askchain, (struct obj **, const char *, int, int (*)(OBJ_P), int (*)(OBJ_P), int, const char *)); +E void FDECL(set_cknown_lknown, (struct obj *)); E void FDECL(fully_identify_obj, (struct obj *)); E int FDECL(identify, (struct obj *)); E int FDECL(count_unidentified, (struct obj *)); @@ -1105,7 +1077,7 @@ E int NDECL(dosuspend); E void FDECL(new_light_source, (XCHAR_P, XCHAR_P, int, int, ANY_P *)); E void FDECL(del_light_source, (int, ANY_P *)); -E void FDECL(do_light_sources, (char **)); +E void FDECL(do_light_sources, (xchar **)); E void FDECL(show_transient_light, (struct obj *, int, int)); E void NDECL(transient_light_cleanup); E struct monst *FDECL(find_mid, (unsigned, unsigned)); @@ -1129,10 +1101,6 @@ E int NDECL(wiz_light_sources); /* ### lock.c ### */ -#ifdef USE_TRAMPOLI -E int NDECL(forcelock); -E int NDECL(picklock); -#endif E boolean FDECL(picking_lock, (int *, int *)); E boolean FDECL(picking_at, (int, int)); E void FDECL(breakchestlock, (struct obj *, BOOLEAN_P)); @@ -1267,6 +1235,7 @@ E void FDECL(rustm, (struct monst *, struct obj *)); /* ### mhitu.c ### */ +E void FDECL(hitmsg, (struct monst *, struct attack *)); E const char *FDECL(mpoisons_subj, (struct monst *, struct attack *)); E void NDECL(u_slow_down); E struct monst *NDECL(cloneu); @@ -1274,6 +1243,8 @@ E void FDECL(expels, (struct monst *, struct permonst *, BOOLEAN_P)); E struct attack *FDECL(getmattk, (struct monst *, struct monst *, int, int *, struct attack *)); E int FDECL(mattacku, (struct monst *)); +boolean FDECL(diseasemu, (struct permonst *)); +boolean FDECL(u_slip_free, (struct monst *, struct attack *)); E int FDECL(magic_negation, (struct monst *)); E boolean NDECL(gulp_blnd_check); E int FDECL(gazemu, (struct monst *, struct attack *)); @@ -1300,9 +1271,6 @@ E void NDECL(gain_guardian_angel); /* ### mklev.c ### */ -#ifdef USE_TRAMPOLI -E int FDECL(do_comp, (genericptr_t, genericptr_t)); -#endif E void NDECL(sort_rooms); E void FDECL(add_room, (int, int, int, int, BOOLEAN_P, SCHAR_P, BOOLEAN_P)); E void FDECL(add_subroom, (struct mkroom *, int, int, int, int, BOOLEAN_P, @@ -1397,6 +1365,7 @@ E struct obj *FDECL(mk_named_object, (int, struct permonst *, int, int, const char *)); E struct obj *FDECL(rnd_treefruit_at, (int, int)); E void FDECL(set_corpsenm, (struct obj *, int)); +E long FDECL(rider_revival_time, (struct obj *, BOOLEAN_P)); E void FDECL(start_corpse_timeout, (struct obj *)); E void FDECL(bless, (struct obj *)); E void FDECL(unbless, (struct obj *)); @@ -1451,6 +1420,8 @@ E int FDECL(cmap_to_type, (int)); /* ### mon.c ### */ E void NDECL(mon_sanity_check); +E boolean FDECL(zombie_maker, (struct permonst *)); +E int FDECL(zombie_form, (struct permonst *)); E int FDECL(m_poisongas_ok, (struct monst *)); E int FDECL(undead_to_corpse, (int)); E int FDECL(genus, (int, int)); @@ -1465,6 +1436,7 @@ E boolean FDECL(mpickstuff, (struct monst *, const char *)); E int FDECL(curr_mon_load, (struct monst *)); E int FDECL(max_mon_load, (struct monst *)); E int FDECL(can_carry, (struct monst *, struct obj *)); +E long FDECL(mon_allowflags, (struct monst *)); E int FDECL(mfndpos, (struct monst *, coord *, long *, long)); E boolean FDECL(monnear, (struct monst *, int, int)); E void NDECL(dmonsfree); @@ -1498,6 +1470,7 @@ E void FDECL(seemimic, (struct monst *)); E void NDECL(rescham); E void NDECL(restartcham); E void FDECL(restore_cham, (struct monst *)); +E void FDECL(maybe_unhide_at, (XCHAR_P, XCHAR_P)); E boolean FDECL(hideunder, (struct monst *)); E void FDECL(hide_monst, (struct monst *)); E void FDECL(mon_animal_list, (BOOLEAN_P)); @@ -1549,8 +1522,8 @@ E boolean FDECL(dmgtype, (struct permonst *, int)); E int FDECL(max_passive_dmg, (struct monst *, struct monst *)); E boolean FDECL(same_race, (struct permonst *, struct permonst *)); E int FDECL(monsndx, (struct permonst *)); -E int FDECL(name_to_mon, (const char *)); -E int FDECL(name_to_monplus, (const char *, const char **)); +E int FDECL(name_to_mon, (const char *, int *)); +E int FDECL(name_to_monplus, (const char *, const char **, int *)); E int FDECL(name_to_monclass, (const char *, int *)); E int FDECL(gender, (struct monst *)); E int FDECL(pronoun_gender, (struct monst *, unsigned)); @@ -1579,6 +1552,7 @@ E void FDECL(mon_yells, (struct monst *, const char *)); E int FDECL(dochug, (struct monst *)); E boolean FDECL(m_digweapon_check, (struct monst *, XCHAR_P, XCHAR_P)); E int FDECL(m_move, (struct monst *, int)); +E int FDECL(m_move_aggress, (struct monst *, XCHAR_P, XCHAR_P)); E void FDECL(dissolve_bars, (int, int)); E boolean FDECL(closed_door, (int, int)); E boolean FDECL(accessible, (int, int)); @@ -1659,6 +1633,7 @@ E int FDECL(ohitmon, (struct monst *, struct obj *, int, BOOLEAN_P)); E void FDECL(thrwmu, (struct monst *)); E int FDECL(spitmu, (struct monst *, struct attack *)); E int FDECL(breamu, (struct monst *, struct attack *)); +E boolean FDECL(linedup_callback, (XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P, boolean FDECL((*), (int,int)))); E boolean FDECL(linedup, (XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P, int)); E boolean FDECL(lined_up, (struct monst *)); E struct obj *FDECL(m_carrying, (struct monst *, int)); @@ -1678,9 +1653,6 @@ E boolean FDECL(find_defensive, (struct monst *)); E int FDECL(use_defensive, (struct monst *)); E int FDECL(rnd_defensive_item, (struct monst *)); E boolean FDECL(find_offensive, (struct monst *)); -#ifdef USE_TRAMPOLI -E int FDECL(mbhitm, (struct monst *, struct obj *)); -#endif E int FDECL(use_offensive, (struct monst *)); E int FDECL(rnd_offensive_item, (struct monst *)); E boolean FDECL(find_misc, (struct monst *)); @@ -1772,11 +1744,13 @@ E void NDECL(nttty_exit); E void NDECL(init_objects); E void FDECL(obj_shuffle_range, (int, int *, int *)); E int NDECL(find_skates); +E boolean FDECL(objdescr_is, (struct obj *, const char *)); E void NDECL(oinit); E void FDECL(savenames, (NHFILE *)); E void FDECL(restnames, (NHFILE *)); E void FDECL(discover_object, (int, BOOLEAN_P, BOOLEAN_P)); E void FDECL(undiscover_object, (int)); +E int FDECL(choose_disco_sort, (int)); E int NDECL(dodiscovered); E int NDECL(doclassdisco); E void NDECL(rename_disco); @@ -1898,6 +1872,7 @@ E void NDECL(msgtype_free); /* ### pager.c ### */ E char *FDECL(self_lookat, (char *)); +E char *FDECL(monhealthdescr, (struct monst *mon, BOOLEAN_P, char *)); E void FDECL(mhidden_description, (struct monst *, BOOLEAN_P, char *)); E boolean FDECL(object_from_map, (int,int,int,struct obj **)); E int FDECL(do_screen_description, (coord, BOOLEAN_P, int, char *, @@ -1971,10 +1946,6 @@ E boolean FDECL(allow_category, (struct obj *)); E boolean FDECL(is_worn_by_type, (struct obj *)); E int FDECL(ck_bag, (struct obj *)); E void FDECL(removed_from_icebox, (struct obj *)); -#ifdef USE_TRAMPOLI -E int FDECL(in_container, (struct obj *)); -E int FDECL(out_container, (struct obj *)); -#endif E int FDECL(pickup, (int)); E int FDECL(pickup_object, (struct obj *, long, BOOLEAN_P)); E int FDECL(query_category, (const char *, struct obj *, int, @@ -2016,6 +1987,7 @@ E void VDECL(verbalize, (const char *, ...)) PRINTF_F(1, 2); E void VDECL(raw_printf, (const char *, ...)) PRINTF_F(1, 2); E void VDECL(impossible, (const char *, ...)) PRINTF_F(1, 2); E void VDECL(config_error_add, (const char *, ...)) PRINTF_F(1, 2); +E void FDECL(nhassert_failed, (const char *, const char *, int)); /* ### polyself.c ### */ @@ -2076,9 +2048,6 @@ E const char *NDECL(bottlename); E boolean FDECL(critically_low_hp, (BOOLEAN_P)); E boolean NDECL(stuck_in_wall); -#ifdef USE_TRAMPOLI -E int NDECL(prayer_done); -#endif E int NDECL(dosacrifice); E boolean FDECL(can_pray, (BOOLEAN_P)); E int NDECL(dopray); @@ -2147,16 +2116,21 @@ E void NDECL(deliver_splev_message); /* ### random.c ### */ #if defined(RANDOM) && !defined(__GO32__) /* djgpp has its own random */ +#ifndef CROSS_TO_AMIGA E void FDECL(srandom, (unsigned)); E char *FDECL(initstate, (unsigned, char *, int)); E char *FDECL(setstate, (char *)); E long NDECL(random); +#endif #endif /* RANDOM */ /* ### read.c ### */ E void FDECL(learnscroll, (struct obj *)); E char *FDECL(tshirt_text, (struct obj *, char *)); +E char *FDECL(apron_text, (struct obj *, char *)); +E const char *FDECL(candy_wrapper_text, (struct obj *)); +E void FDECL(assign_candy_wrapper, (struct obj *)); E int NDECL(doread); E boolean FDECL(is_chargeable, (struct obj *)); E void FDECL(recharge, (struct obj *, int)); @@ -2165,9 +2139,6 @@ E void FDECL(drop_boulder_on_player, (BOOLEAN_P, BOOLEAN_P, BOOLEAN_P, BOOLEAN_P)); E boolean FDECL(drop_boulder_on_monster, (int, int, BOOLEAN_P, BOOLEAN_P)); E void FDECL(wand_explode, (struct obj *, int)); -#ifdef USE_TRAMPOLI -E void FDECL(set_lit, (int, int, genericptr_t)); -#endif E void FDECL(litroom, (BOOLEAN_P, struct obj *)); E void FDECL(do_genocide, (int)); E void FDECL(punish, (struct obj *)); @@ -2372,7 +2343,7 @@ E void NDECL(finish_paybill); E struct obj *FDECL(find_oid, (unsigned)); E long FDECL(contained_cost, (struct obj *, struct monst *, long, BOOLEAN_P, BOOLEAN_P)); -E long FDECL(contained_gold, (struct obj *)); +E long FDECL(contained_gold, (struct obj *, BOOLEAN_P)); E void FDECL(picked_container, (struct obj *)); E void FDECL(gem_learned, (int)); E void FDECL(alter_cost, (struct obj *, long)); @@ -2381,8 +2352,9 @@ E boolean FDECL(billable, (struct monst **, struct obj *, CHAR_P, BOOLEAN_P)); E void FDECL(addtobill, (struct obj *, BOOLEAN_P, BOOLEAN_P, BOOLEAN_P)); E void FDECL(splitbill, (struct obj *, struct obj *)); E void FDECL(subfrombill, (struct obj *, struct monst *)); -E long FDECL(stolen_value, - (struct obj *, XCHAR_P, XCHAR_P, BOOLEAN_P, BOOLEAN_P)); +E long FDECL(stolen_value, (struct obj *, XCHAR_P, XCHAR_P, + BOOLEAN_P, BOOLEAN_P)); +E void FDECL(donate_gold, (long, struct monst *, BOOLEAN_P)); E void FDECL(sellobj_state, (int)); E void FDECL(sellobj, (struct obj *, XCHAR_P, XCHAR_P)); E int FDECL(doinvbill, (int)); @@ -2438,6 +2410,7 @@ E void FDECL(growl, (struct monst *)); E void FDECL(yelp, (struct monst *)); E void FDECL(whimper, (struct monst *)); E void FDECL(beg, (struct monst *)); +E const char *FDECL(maybe_gasp, (struct monst *)); E int NDECL(dotalk); E int NDECL(tiphat); #ifdef USER_SOUNDS @@ -2462,7 +2435,8 @@ E boolean FDECL(create_room, (XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P)); E void FDECL(create_secret_door, (struct mkroom *, XCHAR_P)); E boolean FDECL(dig_corridor, (coord *, coord *, BOOLEAN_P, SCHAR_P, SCHAR_P)); -E void FDECL(fill_room, (struct mkroom *, BOOLEAN_P)); +E void FDECL(fill_special_room, (struct mkroom *)); +E void FDECL(wallify_map, (int, int, int, int)); E boolean FDECL(load_special, (const char *)); E xchar FDECL(selection_getpoint, (int, int, struct selectionvar *)); E struct selectionvar *NDECL(selection_new); @@ -2472,17 +2446,17 @@ E void FDECL(set_selection_floodfillchk, (int FDECL((*), (int,int)))); E void FDECL(selection_floodfill, (struct selectionvar *, int, int, BOOLEAN_P)); E boolean FDECL(pm_good_location, (int, int, struct permonst *)); -E void FDECL(get_location_coord, (schar *, schar *, int, struct mkroom *, +E void FDECL(get_location_coord, (xchar *, xchar *, int, struct mkroom *, long)); E void FDECL(selection_setpoint, (int, int, struct selectionvar *, XCHAR_P)); E struct selectionvar * FDECL(selection_not, (struct selectionvar *)); E void FDECL(selection_filter_percent, (struct selectionvar *, int)); -E int FDECL(selection_rndcoord, (struct selectionvar *, schar *, schar *, +E int FDECL(selection_rndcoord, (struct selectionvar *, xchar *, xchar *, BOOLEAN_P)); E void FDECL(selection_do_grow, (struct selectionvar *, int)); -E void FDECL(selection_do_line, (SCHAR_P, SCHAR_P, SCHAR_P, SCHAR_P, +E void FDECL(selection_do_line, (XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P, struct selectionvar *)); -E void FDECL(selection_do_randline, (SCHAR_P, SCHAR_P, SCHAR_P, SCHAR_P, +E void FDECL(selection_do_randline, (XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P, SCHAR_P, SCHAR_P, struct selectionvar *)); E struct selectionvar *FDECL(selection_filter_mapchar, (struct selectionvar *, XCHAR_P, int)); @@ -2499,9 +2473,6 @@ E void FDECL(l_register_des, (lua_State *)); /* ### spell.c ### */ E void FDECL(book_cursed, (struct obj *)); -#ifdef USE_TRAMPOLI -E int NDECL(learn); -#endif E int FDECL(study_book, (struct obj *)); E void FDECL(book_disappears, (struct obj *)); E void FDECL(book_substitution, (struct obj *, struct obj *)); @@ -2516,10 +2487,6 @@ E void FDECL(initialspell, (struct obj *)); /* ### steal.c ### */ -#ifdef USE_TRAMPOLI -E int NDECL(stealarm); -E void NDECL(unstolenarm); -#endif E long FDECL(somegold, (long)); E void FDECL(stealgold, (struct monst *)); E void NDECL(thiefdead); @@ -2582,7 +2549,7 @@ E void FDECL(teleds, (int, int, int)); E boolean FDECL(safe_teleds, (int)); E boolean FDECL(teleport_pet, (struct monst *, BOOLEAN_P)); E void NDECL(tele); -E boolean FDECL(scrolltele, (struct obj *)); +E void FDECL(scrolltele, (struct obj *)); E int NDECL(dotelecmd); E int FDECL(dotele, (BOOLEAN_P)); E void NDECL(level_tele); @@ -2708,6 +2675,7 @@ E boolean NDECL(lava_effects); E void NDECL(sink_into_lava); E void NDECL(sokoban_guilt); E const char * FDECL(trapname, (int, BOOLEAN_P)); +E void FDECL(ignite_items, (struct obj *)); /* ### u_init.c ### */ @@ -2724,9 +2692,51 @@ E boolean FDECL(attack, (struct monst *)); E boolean FDECL(hmon, (struct monst *, struct obj *, int, int)); E boolean FDECL(shade_miss, (struct monst *, struct monst *, struct obj *, BOOLEAN_P, BOOLEAN_P)); +E void FDECL(mhitm_ad_rust, (struct monst *, struct attack *, struct monst *, struct mhitm_data *)); +E void FDECL(mhitm_ad_corr, (struct monst *, struct attack *, struct monst *, struct mhitm_data *)); +E void FDECL(mhitm_ad_dcay, (struct monst *, struct attack *, struct monst *, struct mhitm_data *)); +E void FDECL(mhitm_ad_dren, (struct monst *, struct attack *, struct monst *, struct mhitm_data *)); +E void FDECL(mhitm_ad_drli, (struct monst *, struct attack *, struct monst *, struct mhitm_data *)); +E void FDECL(mhitm_ad_fire, (struct monst *, struct attack *, struct monst *, struct mhitm_data *)); +E void FDECL(mhitm_ad_cold, (struct monst *, struct attack *, struct monst *, struct mhitm_data *)); +E void FDECL(mhitm_ad_elec, (struct monst *, struct attack *, struct monst *, struct mhitm_data *)); +E void FDECL(mhitm_ad_acid, (struct monst *, struct attack *, struct monst *, struct mhitm_data *)); +E void FDECL(mhitm_ad_sgld, (struct monst *, struct attack *, struct monst *, struct mhitm_data *)); +E void FDECL(mhitm_ad_tlpt, (struct monst *, struct attack *, struct monst *, struct mhitm_data *)); +E void FDECL(mhitm_ad_blnd, (struct monst *, struct attack *, struct monst *, struct mhitm_data *)); +E void FDECL(mhitm_ad_curs, (struct monst *, struct attack *, struct monst *, struct mhitm_data *)); +E void FDECL(mhitm_ad_drst, (struct monst *, struct attack *, struct monst *, struct mhitm_data *)); +E void FDECL(mhitm_ad_drin, (struct monst *, struct attack *, struct monst *, struct mhitm_data *)); +E void FDECL(mhitm_ad_stck, (struct monst *, struct attack *, struct monst *, struct mhitm_data *)); +E void FDECL(mhitm_ad_wrap, (struct monst *, struct attack *, struct monst *, struct mhitm_data *)); +E void FDECL(mhitm_ad_plys, (struct monst *, struct attack *, struct monst *, struct mhitm_data *)); +E void FDECL(mhitm_ad_slee, (struct monst *, struct attack *, struct monst *, struct mhitm_data *)); +E void FDECL(mhitm_ad_slim, (struct monst *, struct attack *, struct monst *, struct mhitm_data *)); +E void FDECL(mhitm_ad_ench, (struct monst *, struct attack *, struct monst *, struct mhitm_data *)); +E void FDECL(mhitm_ad_slow, (struct monst *, struct attack *, struct monst *, struct mhitm_data *)); +E void FDECL(mhitm_ad_conf, (struct monst *, struct attack *, struct monst *, struct mhitm_data *)); +E void FDECL(mhitm_ad_poly, (struct monst *, struct attack *, struct monst *, struct mhitm_data *)); +E void FDECL(mhitm_ad_famn, (struct monst *, struct attack *, struct monst *, struct mhitm_data *)); +E void FDECL(mhitm_ad_pest, (struct monst *, struct attack *, struct monst *, struct mhitm_data *)); +E void FDECL(mhitm_ad_deth, (struct monst *, struct attack *, struct monst *, struct mhitm_data *)); +E void FDECL(mhitm_ad_halu, (struct monst *, struct attack *, struct monst *, struct mhitm_data *)); +E void FDECL(mhitm_ad_phys, (struct monst *, struct attack *, struct monst *, struct mhitm_data *)); +E void FDECL(mhitm_ad_ston, (struct monst *, struct attack *, struct monst *, struct mhitm_data *)); +E void FDECL(mhitm_ad_were, (struct monst *, struct attack *, struct monst *, struct mhitm_data *)); +E void FDECL(mhitm_ad_heal, (struct monst *, struct attack *, struct monst *, struct mhitm_data *)); +E void FDECL(mhitm_ad_stun, (struct monst *, struct attack *, struct monst *, struct mhitm_data *)); +E void FDECL(mhitm_ad_legs, (struct monst *, struct attack *, struct monst *, struct mhitm_data *)); +E void FDECL(mhitm_ad_dgst, (struct monst *, struct attack *, struct monst *, struct mhitm_data *)); +E void FDECL(mhitm_ad_samu, (struct monst *, struct attack *, struct monst *, struct mhitm_data *)); +E void FDECL(mhitm_ad_dise, (struct monst *, struct attack *, struct monst *, struct mhitm_data *)); +E void FDECL(mhitm_ad_sedu, (struct monst *, struct attack *, struct monst *, struct mhitm_data *)); +E void FDECL(mhitm_ad_ssex, (struct monst *, struct attack *, struct monst *, struct mhitm_data *)); +E void FDECL(mhitm_adtyping, (struct monst *, struct attack *, struct monst *, struct mhitm_data *)); +E boolean FDECL(do_stone_u, (struct monst *)); +E void FDECL(do_stone_mon, (struct monst *, struct attack *, struct monst *, struct mhitm_data *)); E int FDECL(damageum, (struct monst *, struct attack *, int)); E void FDECL(missum, (struct monst *, struct attack *, BOOLEAN_P)); -E int FDECL(passive, (struct monst *, struct obj *, BOOLEAN_P, int, +E int FDECL(passive, (struct monst *, struct obj *, BOOLEAN_P, BOOLEAN_P, UCHAR_P, BOOLEAN_P)); E void FDECL(passive_obj, (struct monst *, struct obj *, struct attack *)); E void FDECL(stumble_onto_mimic, (struct monst *)); @@ -2742,7 +2752,7 @@ E void NDECL(port_help); E void FDECL(sethanguphandler, (void (*)(int))); E boolean NDECL(authorize_wizard_mode); E void FDECL(append_slash, (char *)); -E boolean FDECL(check_user_string, (char *)); +E boolean FDECL(check_user_string, (const char *)); E char *NDECL(get_login_name); E unsigned long NDECL(sys_random_seed); #endif /* UNIX */ @@ -2797,7 +2807,7 @@ E void FDECL(uleftvault, (struct monst *)); E void NDECL(invault); E int FDECL(gd_move, (struct monst *)); E void FDECL(paygd, (BOOLEAN_P)); -E long NDECL(hidden_gold); +E long FDECL(hidden_gold, (BOOLEAN_P)); E boolean NDECL(gd_sound); E void FDECL(vault_gd_watching, (unsigned int)); @@ -2842,12 +2852,6 @@ E int FDECL(assign_videoshades, (char *)); E int FDECL(assign_videocolors, (char *)); #endif -/* ### vis_tab.c ### */ - -#ifdef VISION_TABLES -E void NDECL(vis_tab_init); -#endif - /* ### vision.c ### */ E void NDECL(vision_init); @@ -2926,6 +2930,9 @@ E char *NDECL(verify_termcap); E void NDECL(privoff); E void NDECL(privon); #endif +#ifdef SYSCF +E boolean FDECL(check_user_string, (const char *)); +#endif #ifdef SHELL E int NDECL(dosh); #endif @@ -3074,6 +3081,7 @@ E void FDECL(save_worm, (NHFILE *)); E void FDECL(rest_worm, (NHFILE *)); E void FDECL(place_wsegs, (struct monst *, struct monst *)); E void FDECL(sanity_check_worm, (struct monst *)); +E void NDECL(wormno_sanity_check); E void FDECL(remove_worm, (struct monst *)); E void FDECL(place_worm_tail_randomly, (struct monst *, XCHAR_P, XCHAR_P)); E int FDECL(size_wseg, (struct monst *)); @@ -3088,6 +3096,7 @@ E void FDECL(flip_worm_segs_horizontal, (struct monst *, int, int)); E void FDECL(setworn, (struct obj *, long)); E void FDECL(setnotworn, (struct obj *)); +E void NDECL(allunworn); E struct obj *FDECL(wearmask_to_obj, (long)); E long FDECL(wearslot, (struct obj *)); E void FDECL(mon_set_minvis, (struct monst *)); @@ -3124,6 +3133,7 @@ E int FDECL(unturn_dead, (struct monst *)); E void NDECL(unturn_you); E void FDECL(cancel_item, (struct obj *)); E boolean FDECL(drain_item, (struct obj *, BOOLEAN_P)); +E boolean FDECL(obj_unpolyable, (struct obj *)); E struct obj *FDECL(poly_obj, (struct obj *, int)); E boolean FDECL(obj_resists, (struct obj *, int, int)); E boolean FDECL(obj_shudders, (struct obj *)); @@ -3132,6 +3142,7 @@ E int FDECL(bhito, (struct obj *, struct obj *)); E int FDECL(bhitpile, (struct obj *, int (*)(OBJ_P, OBJ_P), int, int, SCHAR_P)); E int FDECL(zappable, (struct obj *)); +E void NDECL(do_enlightenment_effect); E void FDECL(zapnodir, (struct obj *)); E int NDECL(dozap); E int FDECL(zapyourself, (struct obj *, BOOLEAN_P)); diff --git a/include/flag.h b/include/flag.h index 3439cc5b1..1e45e948a 100644 --- a/include/flag.h +++ b/include/flag.h @@ -1,4 +1,4 @@ -/* NetHack 3.7 flag.h $NHDT-Date: 1593953335 2020/07/05 12:48:55 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.183 $ */ +/* NetHack 3.7 flag.h $NHDT-Date: 1600933440 2020/09/24 07:44:00 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.185 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2006. */ /* NetHack may be freely redistributed. See license for details. */ @@ -52,6 +52,7 @@ struct flag { * clairvoyance */ boolean rest_on_space; /* space means rest */ boolean safe_dog; /* give complete protection to the dog */ + boolean safe_wait; /* prevent wait or search next to hostile */ boolean showexp; /* show experience points */ boolean showscore; /* show score */ boolean silent; /* whether the bell rings or not */ @@ -79,6 +80,7 @@ struct flag { #define PARANOID_EATING 0x0200 int pickup_burden; /* maximum burden before prompt */ int pile_limit; /* controls feedback when walking over objects */ + char discosort; /* order of dodiscovery/doclassdisco output: o,s,c,a */ char sortloot; /* 'n'=none, 'l'=loot (pickup), 'f'=full ('l'+invent) */ char inv_order[MAXOCLASSES]; char pickup_types[MAXOCLASSES]; @@ -92,8 +94,7 @@ struct flag { char end_disclose[NUM_DISCLOSURE_OPTIONS + 1]; /* disclose various info upon exit */ char menu_style; /* User interface style setting */ - boolean made_fruit; /* don't easily let the user overflow the number of - fruits */ + boolean made_fruit; /* don't easily let user overflow fruit limit */ /* KMH, role patch -- Variables used during startup. * @@ -238,6 +239,7 @@ struct instance_flags { * disable to avoid excessive noise when using * a screen reader (use ^X to review status) */ boolean toptenwin; /* ending list in window instead of stdout */ + 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 */ #ifdef STATUS_HILITES @@ -292,6 +294,7 @@ struct instance_flags { boolean cmdassist; /* provide detailed assistance for some comnds */ boolean time_botl; /* context.botl for 'time' (moves) only */ boolean wizweight; /* display weight of everything in wizard mode */ + boolean wizmgender; /* test gender info from core in window port */ /* * Window capability support. */ @@ -407,6 +410,7 @@ enum plnmsg_types { PLNMSG_OBJNAM_ONLY, /* xname/doname only, for #tip */ PLNMSG_OK_DONT_DIE, /* overriding death in explore/wizard mode */ PLNMSG_BACK_ON_GROUND, /* leaving water */ + PLNMSG_GROWL, /* growl() gave some message */ PLNMSG_enum /* allows inserting new entries with unconditional trailing comma */ }; diff --git a/include/func_tab.h b/include/func_tab.h index 79daef1de..84539c559 100644 --- a/include/func_tab.h +++ b/include/func_tab.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 func_tab.h $NHDT-Date: 1543797823 2018/12/03 00:43:43 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.11 $ */ +/* NetHack 3.7 func_tab.h $NHDT-Date: 1596498537 2020/08/03 23:48:57 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.14 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Pasi Kallinen, 2016. */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/include/global.h b/include/global.h index 20939108d..c1b9ae14d 100644 --- a/include/global.h +++ b/include/global.h @@ -49,9 +49,8 @@ #endif /* DUMB */ /* - * type xchar: small integers in the range 0 - 127, usually coordinates - * although they are nonnegative they must not be declared unsigned - * since otherwise comparisons with signed quantities are done incorrectly + * type xchar: small integers (typedef'd as signed char, + * so in the range -127 - 127), usually coordinates. */ typedef schar xchar; @@ -166,6 +165,10 @@ extern struct cross_target_s cross_target; #include "ntconf.h" #endif +#ifdef AMIGA +#include "amiconf.h" +#endif + /* Displayable name of this port; don't redefine if defined in *conf.h */ #ifndef PORT_ID #ifdef AMIGA @@ -213,11 +216,13 @@ extern struct cross_target_s cross_target; #endif #endif +#if !defined(CROSSCOMPILE) #if defined(MICRO) #if !defined(AMIGA) && !defined(TOS) && !defined(OS2_HPFS) #define SHORT_FILENAMES /* filenames are 8.3 */ #endif #endif +#endif #ifdef VMS /* vms_exit() (sys/vms/vmsmisc.c) expects the non-VMS EXIT_xxx values below. @@ -365,6 +370,13 @@ struct savefile_info { #define TBUFSZ 300 /* g.toplines[] buffer max msg: 3 81char names */ /* plus longest prefix plus a few extra words */ +/* COLBUFSZ is the larger of BUFSZ and COLNO */ +#if BUFSZ > COLNO +#define COLBUFSZ BUFSZ +#else +#define COLBUFSZ COLNO +#endif + #define PL_NSIZ 32 /* name of player, ghost, shopkeeper */ #define PL_CSIZ 32 /* sizeof pl_character */ #define PL_FSIZ 32 /* fruit name */ @@ -393,11 +405,14 @@ struct savefile_info { #ifdef UNIX #if (NH_DEVEL_STATUS != NH_STATUS_RELEASED) /* see end.c */ +#if !defined(CROSS_TO_WASM) #ifndef PANICTRACE #define PANICTRACE -#endif -#endif -#endif +#endif /* PANICTRACE */ +#endif /* CROSS_TO_WASM */ +#endif /* NH_DEVEL_STATUS != NH_STATUS_RELEASED */ +#endif /* UNIX */ + /* The following are meaningless if PANICTRACE is not defined: */ #if defined(__linux__) && defined(__GLIBC__) && (__GLIBC__ >= 2) #define PANICTRACE_LIBC @@ -406,8 +421,10 @@ struct savefile_info { #define PANICTRACE_LIBC #endif #ifdef UNIX +#if !defined(CROSS_TO_WASM) /* no popen in WASM */ #define PANICTRACE_GDB #endif +#endif /* Supply nethack_enter macro if not supplied by port */ #ifndef nethack_enter @@ -416,8 +433,8 @@ struct savefile_info { /* Supply nhassert macro if not supplied by port */ #ifndef nhassert -#define nhassert(e) ((void)0) +#define nhassert(expression) (void)((!!(expression)) || \ + (nhassert_failed(#expression, __FILE__, __LINE__), 0)) #endif - #endif /* GLOBAL_H */ diff --git a/include/hack.h b/include/hack.h index 44ee8c4a5..aa9b57106 100644 --- a/include/hack.h +++ b/include/hack.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 hack.h $NHDT-Date: 1591178395 2020/06/03 09:59:55 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.138 $ */ +/* NetHack 3.7 hack.h $NHDT-Date: 1601595709 2020/10/01 23:41:49 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.141 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Pasi Kallinen, 2017. */ /* NetHack may be freely redistributed. See license for details. */ @@ -79,24 +79,6 @@ enum dismount_types { DISMOUNT_BYCHOICE = 6 }; -/* mgflags for mapglyph() */ -#define MG_FLAG_NORMAL 0x00 -#define MG_FLAG_NOOVERRIDE 0x01 - -/* Special returns from mapglyph() */ -#define MG_CORPSE 0x0001 -#define MG_INVIS 0x0002 -#define MG_DETECT 0x0004 -#define MG_PET 0x0008 -#define MG_RIDDEN 0x0010 -#define MG_STATUE 0x0020 -#define MG_OBJPILE 0x0040 /* more than one stack of objects */ -#define MG_BW_LAVA 0x0080 /* 'black & white lava': highlight lava if it - can't be distringuished from water by color */ -#define MG_BW_ICE 0x0100 /* similar for ice vs floor */ -#define MG_NOTHING 0x0200 /* char represents GLYPH_NOTHING */ -#define MG_UNEXPL 0x0400 /* char represents GLYPH_UNEXPLORED */ - /* sellobj_state() states */ #define SELL_NORMAL (0) #define SELL_DELIBERATE (1) @@ -216,6 +198,9 @@ typedef struct { #define SYM_OFF_X (SYM_OFF_W + WARNCOUNT) #define SYM_MAX (SYM_OFF_X + MAXOTHER) +/* glyphmod entries */ +enum { GM_FLAGS, GM_TTYCHAR, GM_COLOR, NUM_GLYPHMOD }; + #include "rect.h" #include "region.h" #include "decl.h" @@ -272,23 +257,10 @@ typedef struct sortloot_item Loot; #include "display.h" #include "engrave.h" -#ifdef USE_TRAMPOLI /* this doesn't belong here, but we have little choice */ -#undef NDECL -#define NDECL(f) f() -#endif - #include "extern.h" #include "winprocs.h" #include "sys.h" -#ifdef USE_TRAMPOLI -#include "wintty.h" -#undef WINTTY_H -#include "trampoli.h" -#undef EXTERN_H -#include "extern.h" -#endif /* USE_TRAMPOLI */ - /* flags to control makemon(); goodpos() uses some plus has some of its own*/ #define NO_MM_FLAGS 0x000000L /* use this rather than plain 0 */ #define NO_MINVENT 0x000001L /* suppress minvent when creating mon */ @@ -306,10 +278,12 @@ typedef struct sortloot_item Loot; #define MM_ASLEEP 0x002000L /* monsters should be generated asleep */ #define MM_NOGRP 0x004000L /* suppress creation of monster groups */ #define MM_NOTAIL 0x008000L /* if a long worm, don't give it a tail */ +#define MM_MALE 0x010000L /* male variation */ +#define MM_FEMALE 0x020000L /* female variation */ /* if more MM_ flag masks are added, skip or renumber the GP_ one(s) */ -#define GP_ALLOW_XY 0x010000L /* [actually used by enexto() to decide whether +#define GP_ALLOW_XY 0x040000L /* [actually used by enexto() to decide whether * to make an extra call to goodpos()] */ -#define GP_ALLOW_U 0x020000L /* don't reject hero's location */ +#define GP_ALLOW_U 0x080000L /* don't reject hero's location */ /* flags for make_corpse() and mkcorpstat() */ #define CORPSTAT_NONE 0x00 @@ -346,27 +320,29 @@ typedef struct sortloot_item Loot; #define ALL_FINISHED 0x01 /* called routine already finished the job */ /* flags to control query_objlist() */ -#define BY_NEXTHERE 0x01 /* follow objlist by nexthere field */ -#define AUTOSELECT_SINGLE 0x02 /* if only 1 object, don't ask */ -#define USE_INVLET 0x04 /* use object's invlet */ -#define INVORDER_SORT 0x08 /* sort objects by packorder */ -#define SIGNAL_NOMENU 0x10 /* return -1 rather than 0 if none allowed */ -#define SIGNAL_ESCAPE 0x20 /* return -2 rather than 0 for ESC */ -#define FEEL_COCKATRICE 0x40 /* engage cockatrice checks and react */ -#define INCLUDE_HERO 0x80 /* show hero among engulfer's inventory */ +#define BY_NEXTHERE 0x0001 /* follow objlist by nexthere field */ +#define INCLUDE_VENOM 0x0002 /* include venom objects if present */ +#define AUTOSELECT_SINGLE 0x0004 /* if only 1 object, don't ask */ +#define USE_INVLET 0x0008 /* use object's invlet */ +#define INVORDER_SORT 0x0010 /* sort objects by packorder */ +#define SIGNAL_NOMENU 0x0020 /* return -1 rather than 0 if none allowed */ +#define SIGNAL_ESCAPE 0x0040 /* return -2 rather than 0 for ESC */ +#define FEEL_COCKATRICE 0x0080 /* engage cockatrice checks and react */ +#define INCLUDE_HERO 0x0100 /* show hero among engulfer's inventory */ /* Flags to control query_category() */ -/* BY_NEXTHERE used by query_category() too, so skip 0x01 */ -#define UNPAID_TYPES 0x002 -#define GOLD_TYPES 0x004 -#define WORN_TYPES 0x008 -#define ALL_TYPES 0x010 -#define BILLED_TYPES 0x020 -#define CHOOSE_ALL 0x040 -#define BUC_BLESSED 0x080 -#define BUC_CURSED 0x100 -#define BUC_UNCURSED 0x200 -#define BUC_UNKNOWN 0x400 +/* BY_NEXTHERE and INCLUDE_VENOM are used by query_category() too, so + skip 0x0001 and 0x0002 */ +#define UNPAID_TYPES 0x0004 +#define GOLD_TYPES 0x0008 +#define WORN_TYPES 0x0010 +#define ALL_TYPES 0x0020 +#define BILLED_TYPES 0x0040 +#define CHOOSE_ALL 0x0080 +#define BUC_BLESSED 0x0100 +#define BUC_CURSED 0x0200 +#define BUC_UNCURSED 0x0400 +#define BUC_UNKNOWN 0x0800 #define BUC_ALLBKNOWN (BUC_BLESSED | BUC_CURSED | BUC_UNCURSED) #define BUCX_TYPES (BUC_ALLBKNOWN | BUC_UNKNOWN) #define ALL_TYPES_SELECTED -2 @@ -561,6 +537,6 @@ enum optset_restrictions { #endif #define DEVTEAM_EMAIL "devteam@nethack.org" -#define DEVTEAM_URL "http://www.nethack.org" +#define DEVTEAM_URL "https://www.nethack.org/" #endif /* HACK_H */ diff --git a/include/integer.h b/include/integer.h index 322c2f5e3..5aca4ca22 100644 --- a/include/integer.h +++ b/include/integer.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 integer.h $NHDT-Date: 1551901047 2019/03/06 19:37:27 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.7 $ */ +/* NetHack 3.7 integer.h $NHDT-Date: 1596498539 2020/08/03 23:48:59 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.8 $ */ /* Copyright (c) 2016 by Michael Allison */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/include/lint.h b/include/lint.h index 93a33776b..66ad73d72 100644 --- a/include/lint.h +++ b/include/lint.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 lint.h $NHDT-Date: 1524689514 2018/04/25 20:51:54 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.5 $ */ +/* NetHack 3.7 lint.h $NHDT-Date: 1596498539 2020/08/03 23:48:59 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.6 $ */ /* Copyright (c) 2016 by Robert Patrick Rankin */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/include/mail.h b/include/mail.h index 3b7772b8c..4b3ec2d05 100644 --- a/include/mail.h +++ b/include/mail.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 mail.h $NHDT-Date: 1524689515 2018/04/25 20:51:55 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.9 $ */ +/* NetHack 3.7 mail.h $NHDT-Date: 1596498544 2020/08/03 23:49:04 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.10 $ */ /* Copyright (c) 2015 by Kenneth Lorber */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/include/mextra.h b/include/mextra.h index 9ceee2fb2..cc4d715ae 100644 --- a/include/mextra.h +++ b/include/mextra.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 mextra.h $NHDT-Date: 1574722861 2019/11/25 23:01:01 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.24 $ */ +/* NetHack 3.7 mextra.h $NHDT-Date: 1596498545 2020/08/03 23:49:05 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.30 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2006. */ /* NetHack may be freely redistributed. See license for details. */ @@ -19,7 +19,9 @@ * file. * 3. Add a referencing macro at bottom of this file after the mextra * struct (see MNAME, EGD, EPRI, ESHK, EMIN, or EDOG for examples). - * 4. Create a newXX(mtmp) function and possibly a free_XX(mtmp) + * 4. If your new field isn't a pointer and requires a non-zero value + * on initialization, add code to init_mextra() in src/makemon.c + * 5. Create a newXX(mtmp) function and possibly a free_XX(mtmp) * function in an appropriate new or existing source file and add * a prototype for it to include/extern.h. * @@ -39,7 +41,7 @@ * } * } * - * 5. Consider adding a new makemon flag MM_XX flag to include/hack.h + * 6. Consider adding a new makemon flag MM_XX flag to include/hack.h * and a corresponding change to makemon() if you require your * structure to be added at monster creation time. Initialize your * struct after a successful return from makemon(). @@ -47,14 +49,14 @@ * src/makemon.c: if (mmflags & MM_XX) newXX(mtmp); * your new code: mon = makemon(&mons[mnum], x, y, MM_XX); * - * 6. Adjust size_monst() in src/cmd.c appropriately. - * 7. Adjust dealloc_mextra() in src/mon.c to clean up + * 7. Adjust size_monst() in src/cmd.c appropriately. + * 8. Adjust dealloc_mextra() in src/mon.c to clean up * properly during monst deallocation. - * 8. Adjust copy_mextra() in src/mon.c to make duplicate + * 9. Adjust copy_mextra() in src/mon.c to make duplicate * copies of your struct or data on another monst struct. - * 9. Adjust restmon() in src/restore.c to deal with your + * 10. Adjust restmon() in src/restore.c to deal with your * struct or data during a restore. - * 10. Adjust savemon() in src/save.c to deal with your + * 11. Adjust savemon() in src/save.c to deal with your * struct or data during a save. */ @@ -173,7 +175,7 @@ struct edog { ** mextra.h -- collection of all monster extensions */ struct mextra { - char *mname; + char *mgivenname; struct egd *egd; struct epri *epri; struct eshk *eshk; @@ -184,7 +186,7 @@ struct mextra { * or an alignment mask for one posing as an altar */ }; -#define MNAME(mon) ((mon)->mextra->mname) +#define MGIVENNAME(mon) ((mon)->mextra->mgivenname) #define EGD(mon) ((mon)->mextra->egd) #define EPRI(mon) ((mon)->mextra->epri) #define ESHK(mon) ((mon)->mextra->eshk) @@ -192,7 +194,7 @@ struct mextra { #define EDOG(mon) ((mon)->mextra->edog) #define MCORPSENM(mon) ((mon)->mextra->mcorpsenm) -#define has_mname(mon) ((mon)->mextra && MNAME(mon)) +#define has_mgivenname(mon) ((mon)->mextra && MGIVENNAME(mon)) #define has_egd(mon) ((mon)->mextra && EGD(mon)) #define has_epri(mon) ((mon)->mextra && EPRI(mon)) #define has_eshk(mon) ((mon)->mextra && ESHK(mon)) diff --git a/include/mfndpos.h b/include/mfndpos.h index 18259c70c..a49f13262 100644 --- a/include/mfndpos.h +++ b/include/mfndpos.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 mfndpos.h $NHDT-Date: 1432512776 2015/05/25 00:12:56 $ $NHDT-Branch: master $:$NHDT-Revision: 1.12 $ */ +/* NetHack 3.7 mfndpos.h $NHDT-Date: 1596498546 2020/08/03 23:49:06 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.14 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2005. */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/include/micro.h b/include/micro.h index ec512a5c9..fd10be51b 100644 --- a/include/micro.h +++ b/include/micro.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 micro.h $NHDT-Date: 1524689515 2018/04/25 20:51:55 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.10 $ */ +/* NetHack 3.7 micro.h $NHDT-Date: 1596498546 2020/08/03 23:49:06 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.12 $ */ /* Copyright (c) 2015 by Kenneth Lorber */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/include/mkroom.h b/include/mkroom.h index 6bc6204ef..07d2318aa 100644 --- a/include/mkroom.h +++ b/include/mkroom.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 mkroom.h $NHDT-Date: 1560851014 2019/06/18 09:43:34 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.16 $ */ +/* NetHack 3.7 mkroom.h $NHDT-Date: 1596498547 2020/08/03 23:49:07 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.22 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Pasi Kallinen, 2016. */ /* NetHack may be freely redistributed. See license for details. */ @@ -9,7 +9,7 @@ /* mkroom.h - types and structures for room and shop initialization */ struct mkroom { - schar lx, hx, ly, hy; /* usually xchar, but hx may be -1 */ + xchar lx, hx, ly, hy; /* usually xchar, but hx may be -1 */ schar rtype; /* type of room (zoo, throne, etc...) */ schar orig_rtype; /* same as rtype, but not zeroed later */ schar rlit; /* is the room lit ? */ @@ -90,6 +90,14 @@ enum roomtype_types { #define ROOMOFFSET 3 /* (levl[x][y].roomno - ROOMOFFSET) gives g.rooms[] index, * for inside-squares and non-shared boundaries */ +/* Values for needfill */ +#define FILL_NONE 0 /* do not fill this room with anything */ +#define FILL_NORMAL 1 /* fill the room normally (OROOM or THEMEROOM gets + fill_ordinary_room; any other room type gets stocked + with its usual monsters/objects/terrain) */ +#define FILL_LVFLAGS 2 /* special rooms only; set the room's rtype and level + flags as appropriate, but do not put anything in it */ + #define IS_ROOM_PTR(x) ((x) >= g.rooms && (x) < g.rooms + MAXNROFROOMS) #define IS_ROOM_INDEX(x) ((x) >= 0 && (x) < MAXNROFROOMS) #define IS_SUBROOM_PTR(x) ((x) >= g.subrooms && (x) < g.subrooms + MAXNROFROOMS) diff --git a/include/monattk.h b/include/monattk.h index 1eb848fe7..98975e5db 100644 --- a/include/monattk.h +++ b/include/monattk.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 monattk.h $NHDT-Date: 1432512775 2015/05/25 00:12:55 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ */ +/* NetHack 3.7 monattk.h $NHDT-Date: 1596498548 2020/08/03 23:49:08 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.13 $ */ /* NetHack may be freely redistributed. See license for details. */ /* Copyright 1988, M. Stephenson */ @@ -86,6 +86,15 @@ #define AD_SAMU 252 /* hits, may steal Amulet (Wizard) */ #define AD_CURS 253 /* random curse (ex. gremlin) */ +struct mhitm_data { + int damage; + int hitflags; /* MM_DEF_DIED | MM_AGR_DIED | ... */ + boolean done; + boolean permdmg; + int specialdmg; + int dieroll; +}; + /* * Monster to monster attacks. When a monster attacks another (mattackm), * any or all of the following can be returned. See mattackm() for more @@ -95,5 +104,6 @@ #define MM_HIT 0x1 /* aggressor hit defender */ #define MM_DEF_DIED 0x2 /* defender died */ #define MM_AGR_DIED 0x4 /* aggressor died */ +#define MM_AGR_DONE 0x8 /* aggressor is done with their turn */ #endif /* MONATTK_H */ diff --git a/include/mondata.h b/include/mondata.h index abff12a2c..1ab07c6e3 100644 --- a/include/mondata.h +++ b/include/mondata.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 mondata.h $NHDT-Date: 1586178708 2020/04/06 13:11:48 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.43 $ */ +/* NetHack 3.7 mondata.h $NHDT-Date: 1606473485 2020/11/27 10:38:05 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.45 $ */ /* Copyright (c) 1989 Mike Threepoint */ /* NetHack may be freely redistributed. See license for details. */ @@ -224,9 +224,12 @@ #define nonliving(ptr) \ (is_undead(ptr) || (ptr) == &mons[PM_MANES] || weirdnonliving(ptr)) -/* no corpse (ie, blank scrolls) if killed by fire */ +/* no corpse (ie, blank scrolls) if killed by fire; special case instakill */ #define completelyburns(ptr) \ ((ptr) == &mons[PM_PAPER_GOLEM] || (ptr) == &mons[PM_STRAW_GOLEM]) +#define completelyrots(ptr) \ + ((ptr) == &mons[PM_WOOD_GOLEM] || (ptr) == &mons[PM_LEATHER_GOLEM]) +#define completelyrusts(ptr) ((ptr) == &mons[PM_IRON_GOLEM]) /* Used for conduct with corpses, tins, and digestion attacks */ /* G_NOCORPSE monsters might still be swallowed as a purple worm */ diff --git a/include/monflag.h b/include/monflag.h index b343791b0..d7a1a88f5 100644 --- a/include/monflag.h +++ b/include/monflag.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 monflag.h $NHDT-Date: 1590879610 2020/05/30 23:00:10 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.20 $ */ +/* NetHack 3.7 monflag.h $NHDT-Date: 1596498549 2020/08/03 23:49:09 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.21 $ */ /* Copyright (c) 1989 Mike Threepoint */ /* NetHack may be freely redistributed. See license for details. */ @@ -205,6 +205,9 @@ enum ms_sounds { #define G_GONE (G_GENOD | G_EXTINCT) #define MV_KNOWS_EGG 0x08 /* player recognizes egg of this monster type */ +enum mgender { MALE, FEMALE, NEUTRAL, + NUM_MGENDERS }; + /* *INDENT-ON* */ /* clang-format on */ #endif /* MONFLAG_H */ diff --git a/include/monst.h b/include/monst.h index 722805680..66f51f469 100644 --- a/include/monst.h +++ b/include/monst.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 monst.h $NHDT-Date: 1559994623 2019/06/08 11:50:23 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.32 $ */ +/* NetHack 3.7 monst.h $NHDT-Date: 1596498550 2020/08/03 23:49:10 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.42 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2016. */ /* NetHack may be freely redistributed. See license for details. */ @@ -82,6 +82,7 @@ struct monst { xchar mx, my; xchar 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 */ int mhp, mhpmax; unsigned mappearance; /* for undetected mimics and the wiz */ @@ -183,7 +184,7 @@ struct monst { #define DEADMONSTER(mon) ((mon)->mhp < 1) #define is_starting_pet(mon) ((mon)->m_id == g.context.startingpet_mid) #define is_vampshifter(mon) \ - ((mon)->cham == PM_VAMPIRE || (mon)->cham == PM_VAMPIRE_LORD \ + ((mon)->cham == PM_VAMPIRE || (mon)->cham == PM_VAMPIRE_LEADER \ || (mon)->cham == PM_VLAD_THE_IMPALER) #define vampshifted(mon) (is_vampshifter((mon)) && !is_vampire((mon)->data)) @@ -219,4 +220,8 @@ struct monst { #define montoostrong(monindx, lev) (mons[monindx].difficulty > lev) #define montooweak(monindx, lev) (mons[monindx].difficulty < lev) +#ifdef PMNAME_MACROS +#define Mgender(mon) ((mon)->female ? FEMALE : MALE) +#endif + #endif /* MONST_H */ diff --git a/include/monsym.h b/include/monsym.h index 68737fd83..e09a0b55d 100644 --- a/include/monsym.h +++ b/include/monsym.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 monsym.h $NHDT-Date: 1547428769 2019/01/14 01:19:29 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.12 $ */ +/* NetHack 3.7 monsym.h $NHDT-Date: 1596498550 2020/08/03 23:49:10 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.13 $ */ /* Copyright (c) 2016 by Pasi Kallinen */ /* NetHack may be freely redistributed. See license for details. */ /* Monster symbols and creation information rev 1.0 */ diff --git a/include/ntconf.h b/include/ntconf.h index 7b7edb407..711c83914 100644 --- a/include/ntconf.h +++ b/include/ntconf.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 ntconf.h $NHDT-Date: 1447424077 2015/11/13 14:14:37 $ $NHDT-Branch: master $:$NHDT-Revision: 1.48 $ */ +/* NetHack 3.7 ntconf.h $NHDT-Date: 1596498552 2020/08/03 23:49:12 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.89 $ */ /* Copyright (c) NetHack PC Development Team 1993, 1994. */ /* NetHack may be freely redistributed. See license for details. */ @@ -144,6 +144,8 @@ extern void FDECL(interject, (int)); #ifndef HAS_STDINT_H #define HAS_STDINT_H /* force include of stdint.h in integer.h */ #endif +/* Turn on some additional warnings */ +#pragma warning(3:4389) #endif /* _MSC_VER */ /* The following is needed for prototypes of certain functions */ @@ -156,14 +158,6 @@ extern void FDECL(interject, (int)); #define strncmpi(a, b, c) strnicmp(a, b, c) #endif -#ifdef _MSC_VER -/* Visual Studio defines this in their own headers, which we don't use */ -#ifndef snprintf -#define snprintf _snprintf -#pragma warning( \ - disable : 4996) /* deprecation warning suggesting snprintf_s */ -#endif -#endif #include #include @@ -281,16 +275,6 @@ extern int FDECL(set_win32_option, (const char *, const char *)); extern int FDECL(alternative_palette, (char *)); #endif -#ifdef NDEBUG -#define nhassert(expression) ((void)0) -#else -extern void FDECL(nhassert_failed, (const char * exp, const char * file, - int line)); - -#define nhassert(expression) (void)((!!(expression)) || \ - (nhassert_failed(#expression, __FILE__, __LINE__), 0)) -#endif - #define nethack_enter(argc, argv) nethack_enter_winnt() extern void FDECL(nethack_exit, (int)) NORETURN; extern boolean FDECL(file_exists, (const char *)); @@ -299,4 +283,13 @@ extern boolean FDECL(file_newer, (const char *, const char *)); #include "system.h" #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. + * #x to turn x into its string form). + */ +extern void FDECL(nt_assert_failed, (const char *, const char *, int)); +#define nhassert(expression) (void)((!!(expression)) || \ + (nt_assert_failed(#expression, __FILE__, __LINE__), 0)) + #endif /* NTCONF_H */ diff --git a/include/obj.h b/include/obj.h index bdf7945cb..9205c8151 100644 --- a/include/obj.h +++ b/include/obj.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 obj.h $NHDT-Date: 1590870784 2020/05/30 20:33:04 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.69 $ */ +/* NetHack 3.7 obj.h $NHDT-Date: 1604620981 2020/11/06 00:03:01 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.79 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2006. */ /* NetHack may be freely redistributed. See license for details. */ @@ -40,15 +40,19 @@ struct obj { unsigned owt; long quan; /* number of items */ +#define SPE_LIM 99 /* abs(obj->spe) <= 99, cap for enchanted and charged + * objects (and others; named fruit index excepted) */ schar spe; /* quality of weapon, weptool, armor or ring (+ or -); - number of charges for wand or charged tool ( >= -1 ); - number of candles attached to candelabrum; - marks your eggs, tin variety and spinach tins; - Schroedinger's Box (1) or royal coffers for a court (2); - tells which fruit a fruit is; - special for uball and amulet; - scroll of mail (normal==0, bones or wishing==1, written==2); - historic and gender for statues */ + * number of charges for wand or charged tool ( >= -1 ); + * number of candles attached to candelabrum; + * marks your eggs, tin variety and spinach tins; + * candy bar wrapper index; + * Schroedinger's Box (1) or royal coffers for a court (2); + * tells which fruit a fruit is; + * special for uball and amulet; + * scroll of mail (normal==0, bones or wishing==1, written==2); + * splash of venom (normal==0, wishing==1); + * historic and gender for statues */ #define STATUE_HISTORIC 0x01 #define STATUE_MALE 0x02 #define STATUE_FEMALE 0x04 @@ -105,7 +109,8 @@ struct obj { 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); /* contents of container assumed to be known */ + Bitfield(cknown, 1); /* for containers (including statues): the contents + * are known; also applicable to tins */ Bitfield(lknown, 1); /* locked/unlocked status is known */ /* 4 free bits */ @@ -113,12 +118,15 @@ struct obj { #define leashmon corpsenm /* gets m_id of attached pet */ #define fromsink corpsenm /* a potion from a sink */ #define novelidx corpsenm /* 3.6 tribute - the index of the novel title */ +#define migr_species corpsenm /* species to endow for MIGR_TO_SPECIES */ int usecount; /* overloaded for various things that tally */ #define spestudied usecount /* # of times a spellbook has been studied */ unsigned oeaten; /* nutrition left in food, if partly eaten */ long age; /* creation date */ long owornmask; unsigned lua_ref_cnt; /* # of lua script references for this object */ + xchar omigr_from_dnum; /* where obj is migrating from */ + xchar omigr_from_dlevel; /* where obj is migrating from */ struct oextra *oextra; /* pointer to oextra struct */ }; @@ -244,13 +252,16 @@ struct obj { #define stale_egg(egg) \ ((g.monstermoves - (egg)->age) > (2 * MAX_EGG_HATCH_TIME)) #define ofood(o) ((o)->otyp == CORPSE || (o)->otyp == EGG || (o)->otyp == TIN) + /* note: sometimes eggs and tins have special corpsenm values that + shouldn't be used as an index into mons[] */ #define polyfodder(obj) \ - (ofood(obj) && (pm_to_cham((obj)->corpsenm) != NON_PM \ + (ofood(obj) && (obj)->corpsenm >= LOW_PM \ + && (pm_to_cham((obj)->corpsenm) != NON_PM \ || dmgtype(&mons[(obj)->corpsenm], AD_POLY))) #define mlevelgain(obj) (ofood(obj) && (obj)->corpsenm == PM_WRAITH) #define mhealup(obj) (ofood(obj) && (obj)->corpsenm == PM_NURSE) -#define Is_pudding(o) \ - (o->otyp == GLOB_OF_GRAY_OOZE || o->otyp == GLOB_OF_BROWN_PUDDING \ +#define Is_pudding(o) \ + (o->otyp == GLOB_OF_GRAY_OOZE || o->otyp == GLOB_OF_BROWN_PUDDING \ || o->otyp == GLOB_OF_GREEN_SLIME || o->otyp == GLOB_OF_BLACK_PUDDING) /* Containers */ @@ -305,22 +316,26 @@ struct obj { (otmp->otyp == TALLOW_CANDLE || otmp->otyp == WAX_CANDLE) #define MAX_OIL_IN_FLASK 400 /* maximum amount of oil in a potion of oil */ -/* MAGIC_LAMP intentionally excluded below */ -/* age field of this is relative age rather than absolute */ -#define age_is_relative(otmp) \ +/* age field of this is relative age rather than absolute; does not include + magic lamp */ +#define age_is_relative(otmp) \ ((otmp)->otyp == BRASS_LANTERN || (otmp)->otyp == OIL_LAMP \ || (otmp)->otyp == CANDELABRUM_OF_INVOCATION \ || (otmp)->otyp == TALLOW_CANDLE || (otmp)->otyp == WAX_CANDLE \ || (otmp)->otyp == POT_OIL) -/* object can be ignited */ -#define ignitable(otmp) \ +/* object can be ignited; magic lamp used to excluded here too but all + usage of this macro ended up testing + (ignitable(obj) || obj->otyp == MAGIC_LAMP) + so include it; brass lantern can be lit but not by fire */ +#define ignitable(otmp) \ ((otmp)->otyp == BRASS_LANTERN || (otmp)->otyp == OIL_LAMP \ + || ((otmp)->otyp == MAGIC_LAMP && (otmp)->spe > 0) \ || (otmp)->otyp == CANDELABRUM_OF_INVOCATION \ || (otmp)->otyp == TALLOW_CANDLE || (otmp)->otyp == WAX_CANDLE \ || (otmp)->otyp == POT_OIL) /* things that can be read */ -#define is_readable(otmp) \ +#define is_readable(otmp) \ ((otmp)->otyp == FORTUNE_COOKIE || (otmp)->otyp == T_SHIRT \ || (otmp)->otyp == ALCHEMY_SMOCK || (otmp)->otyp == CREDIT_CARD \ || (otmp)->otyp == CAN_OF_GREASE || (otmp)->otyp == MAGIC_MARKER \ @@ -344,6 +359,10 @@ struct obj { && !undiscovered_artifact(ART_EYES_OF_THE_OVERWORLD))) #define pair_of(o) ((o)->otyp == LENSES || is_gloves(o) || is_boots(o)) +#define unpolyable(o) ((o)->otyp == WAN_POLYMORPH \ + || (o)->otyp == SPE_POLYMORPH \ + || (o)->otyp == POT_POLYMORPH) + /* achievement tracking; 3.6.x did this differently */ #define is_mines_prize(o) ((o)->o_id == g.context.achieveo.mines_prize_oid) #define is_soko_prize(o) ((o)->o_id == g.context.achieveo.soko_prize_oid) @@ -388,7 +407,9 @@ struct obj { * 4. Add a testing macro after the set of referencing macros * (see has_oname(), has_omonst(), has_omailcmd(), and has_omin(), * for examples). - * 5. Create newXX(otmp) function and possibly free_XX(otmp) function + * 5. If your new field isn't a pointer and requires a non-zero value + * on initialization, add code to init_oextra() in src/mkobj.c. + * 6. Create newXX(otmp) function and possibly free_XX(otmp) function * in an appropriate new or existing source file and add a prototype * for it to include/extern.h. The majority of these are currently * located in mkobj.c for convenience. @@ -409,14 +430,14 @@ struct obj { * } * } * - * 6. Adjust size_obj() in src/cmd.c appropriately. - * 7. Adjust dealloc_oextra() in src/mkobj.c to clean up + * 7. Adjust size_obj() in src/cmd.c appropriately. + * 8. Adjust dealloc_oextra() in src/mkobj.c to clean up * properly during obj deallocation. - * 8. Adjust copy_oextra() in src/mkobj.c to make duplicate + * 9. Adjust copy_oextra() in src/mkobj.c to make duplicate * copies of your struct or data onto another obj struct. - * 9. Adjust restobj() in src/restore.c to deal with your + * 10. Adjust restobj() in src/restore.c to deal with your * struct or data during a restore. - * 10. Adjust saveobj() in src/save.c to deal with your + * 11. Adjust saveobj() in src/save.c to deal with your * struct or data during a save. */ diff --git a/include/objclass.h b/include/objclass.h index 031d8595e..cdfc9b625 100644 --- a/include/objclass.h +++ b/include/objclass.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 objclass.h $NHDT-Date: 1578895344 2020/01/13 06:02:24 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.21 $ */ +/* NetHack 3.7 objclass.h $NHDT-Date: 1596498553 2020/08/03 23:49:13 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.22 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Pasi Kallinen, 2018. */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/include/optlist.h b/include/optlist.h index 085b527b1..4dc6ae115 100644 --- a/include/optlist.h +++ b/include/optlist.h @@ -120,9 +120,9 @@ pfx_##a, "deprecated (use S_boulder in sym file instead)") #endif NHOPTC(catname, PL_PSIZ, opt_in, set_gameview, No, Yes, No, No, NoAlias, - "the name of your (first) cat (e.g., catname:Tabby)") + "name of your starting pet if it is a kitten") #ifdef INSURANCE - NHOPTB(checkpoint, 0, opt_out, set_in_game, Off, Yes, No, No, NoAlias, + NHOPTB(checkpoint, 0, opt_out, set_in_game, On, Yes, No, No, NoAlias, &flags.ins_chkpt) #else NHOPTB(checkpoint, 0, opt_out, set_in_game, Off, No, No, No, NoAlias, @@ -150,11 +150,11 @@ pfx_##a, opt_in, set_in_game, Yes, Yes, No, Yes, NoAlias, "the kinds of information to disclose at end of game") NHOPTC(dogname, PL_PSIZ, opt_in, set_gameview, No, Yes, No, No, NoAlias, - "the name of your (first) dog (e.g., dogname:Fang)") - NHOPTC(dungeon, MAXDCHARS + 1,opt_in, set_in_config, No, Yes, No, No, NoAlias, - "the symbols to use in drawing the dungeon map") - NHOPTC(effects, MAXECHARS + 1, opt_in, set_in_config, No, Yes, No, No, NoAlias, - "the symbols to use in drawing special effects") + "name of your starting pet if it is a little dog") + NHOPTC(dungeon, MAXDCHARS + 1,opt_in, set_in_config, No, Yes, No, No, + NoAlias, "list of symbols to use in drawing the dungeon map") + NHOPTC(effects, MAXECHARS + 1, opt_in, set_in_config, No, Yes, No, No, + NoAlias, "list of symbols to use in drawing special effects") NHOPTB(eight_bit_tty, 0, opt_in, set_in_game, Off, Yes, No, No, NoAlias, &iflags.wc_eight_bit_input) NHOPTB(extmenu, 0, opt_in, set_in_game, Off, Yes, No, No, NoAlias, @@ -164,29 +164,29 @@ pfx_##a, NHOPTB(fixinv, 0, opt_out, set_in_game, On, Yes, No, No, NoAlias, &flags.invlet_constant) NHOPTC(font_map, 40, opt_in, set_gameview, Yes, Yes, Yes, No, NoAlias, - "the font to use in the map window") + "font to use in the map window") NHOPTC(font_menu, 40, opt_in, set_gameview, Yes, Yes, Yes, No, NoAlias, - "the font to use in menus") + "font to use in menus") NHOPTC(font_message, 40, opt_in, set_gameview, Yes, Yes, Yes, No, NoAlias, - "the font to use in the message window") + "font to use in the message window") NHOPTC(font_size_map, 20, opt_in, set_gameview, Yes, Yes, Yes, No, NoAlias, - "the size of the map font") - NHOPTC(font_size_menu, 20, opt_in, set_gameview, Yes, Yes, Yes, No, NoAlias, - "the size of the menu font") - NHOPTC(font_size_message, 20, opt_in, set_gameview, Yes, Yes, Yes, No, NoAlias, - "the size of the message font") - NHOPTC(font_size_status, 20, opt_in, set_gameview, Yes, Yes, Yes, No, NoAlias, - "the size of the status font") - NHOPTC(font_size_text, 20, opt_in, set_gameview, Yes, Yes, Yes, No, NoAlias, - "the size of the text font") + "size of the map font") + NHOPTC(font_size_menu, 20, opt_in, set_gameview, Yes, Yes, Yes, No, + NoAlias, "size of the menu font") + NHOPTC(font_size_message, 20, opt_in, set_gameview, Yes, Yes, Yes, No, + NoAlias, "size of the message font") + NHOPTC(font_size_status, 20, opt_in, set_gameview, Yes, Yes, Yes, No, + NoAlias, "size of the status font") + NHOPTC(font_size_text, 20, opt_in, set_gameview, Yes, Yes, Yes, No, + NoAlias, "size of the text font") NHOPTC(font_status, 40, opt_in, set_gameview, Yes, Yes, Yes, No, NoAlias, - "the font to use in status window") + "font to use in status window") NHOPTC(font_text, 40, opt_in, set_gameview, Yes, Yes, Yes, No, NoAlias, - "the font to use in text windows") + "font to use in text windows") NHOPTB(force_invmenu, 0, opt_in, set_in_game, Off, Yes, No, No, NoAlias, &iflags.force_invmenu) NHOPTC(fruit, PL_FSIZ, opt_in, set_in_game, No, Yes, No, No, NoAlias, - "the name of a fruit you enjoy eating") + "name of a fruit you enjoy eating") NHOPTB(fullscreen, 0, opt_in, set_in_config, Off, Yes, No, No, NoAlias, &iflags.wc2_fullscreen) NHOPTC(gender, 8, opt_in, set_gameview, No, Yes, No, No, NoAlias, @@ -209,12 +209,12 @@ pfx_##a, &iflags.hilite_pile) #ifdef STATUS_HILITES NHOPTC(hilite_status, 13, opt_out, set_in_game, Yes, Yes, Yes, No, NoAlias, - "hilite_status") + "a status highlighting rule (can occur multiple times)") #endif NHOPTB(hitpointbar, 0, opt_in, set_in_game, Off, Yes, No, No, NoAlias, &iflags.wc2_hitpointbar) NHOPTC(horsename, PL_PSIZ, opt_in, set_gameview, No, Yes, No, No, NoAlias, - "the name of your (first) horse (e.g., horsename:Silver)") + "name of your starting pet if it is a pony") #ifdef BACKWARD_COMPAT NHOPTC(IBMgraphics, 70, opt_in, set_in_config, Yes, Yes, No, No, NoAlias, "load IBMGraphics display symbols") @@ -226,10 +226,12 @@ pfx_##a, NHOPTB(ignintr, 0, opt_in, set_in_config, Off, Yes, No, No, NoAlias, (boolean *) 0) #endif - NHOPTB(implicit_uncursed, 0, opt_out, set_in_game, On, Yes, No, No, NoAlias, - &flags.implicit_uncursed) + NHOPTB(implicit_uncursed, 0, opt_out, set_in_game, On, Yes, No, No, + NoAlias, &flags.implicit_uncursed) +#if 0 /* obsolete - pre-OSX Mac */ NHOPTB(large_font, 0, opt_in, set_in_config, Off, Yes, No, No, NoAlias, &iflags.obsolete) +#endif NHOPTB(legacy, 0, opt_out, set_in_config, On, Yes, No, No, NoAlias, &flags.legacy) NHOPTB(lit_corridor, 0, opt_in, set_in_game, Off, Yes, No, No, NoAlias, @@ -248,18 +250,18 @@ pfx_##a, &flags.mention_decor) NHOPTB(mention_walls, 0, opt_in, set_in_game, Off, Yes, No, No, NoAlias, &flags.mention_walls) - NHOPTC(menu_deselect_all, 4, opt_in, set_in_config, No, Yes, No, No, NoAlias, - "deselect all items in a menu") - NHOPTC(menu_deselect_page, 4, opt_in, set_in_config, No, Yes, No, No, NoAlias, - "deselect all items on this page of a menu") + NHOPTC(menu_deselect_all, 4, opt_in, set_in_config, No, Yes, No, No, + NoAlias, "deselect all items in a menu") + NHOPTC(menu_deselect_page, 4, opt_in, set_in_config, No, Yes, No, No, + NoAlias, "deselect all items on this page of a menu") NHOPTC(menu_first_page, 4, opt_in, set_in_config, No, No, Yes, No, NoAlias, "jump to the first page in a menu") NHOPTC(menu_headings, 4, opt_in, set_in_game, No, Yes, No, Yes, NoAlias, "display style for menu headings") NHOPTC(menu_invert_all, 4, opt_in, set_in_config, No, Yes, No, No, NoAlias, "invert all items in a menu") - NHOPTC(menu_invert_page, 4, opt_in, set_in_config, No, Yes, No, No, NoAlias, - "invert all items on this page of a menu") + NHOPTC(menu_invert_page, 4, opt_in, set_in_config, No, Yes, No, No, + NoAlias, "invert all items on this page of a menu") NHOPTC(menu_last_page, 4, opt_in, set_in_config, No, Yes, No, No, NoAlias, "jump to the last page in a menu") NHOPTC(menu_next_page, 4, opt_in, set_in_config, No, Yes, No, No, NoAlias, @@ -273,34 +275,34 @@ pfx_##a, NHOPTB(menu_overlay, 0, opt_in, set_in_config, Off, No, No, No, NoAlias, (boolean *) 0) #endif - NHOPTC(menu_previous_page, 4, opt_in, set_in_config, No, Yes, No, No, NoAlias, - "goto the previous menu page") + NHOPTC(menu_previous_page, 4, opt_in, set_in_config, No, Yes, No, No, + NoAlias, "goto the previous menu page") NHOPTC(menu_search, 4, opt_in, set_in_config, No, Yes, No, No, NoAlias, "search for a menu item") NHOPTC(menu_select_all, 4, opt_in, set_in_config, No, Yes, No, No, NoAlias, "select all items in a menu") - NHOPTC(menu_select_page, 4, opt_in, set_in_config, No, Yes, No, No, NoAlias, - "select all items on this page of a menu") + NHOPTC(menu_select_page, 4, opt_in, set_in_config, No, Yes, No, No, + NoAlias, "select all items on this page of a menu") NHOPTB(menu_tab_sep, 0, opt_in, set_wizonly, Off, Yes, No, No, NoAlias, &iflags.menu_tab_sep) NHOPTB(menucolors, 0, opt_in, set_in_game, Off, Yes, Yes, No, NoAlias, &iflags.use_menu_color) NHOPTC(menuinvertmode, 5, opt_in, set_in_game, No, Yes, No, No, NoAlias, "behaviour of menu iverts") - NHOPTC(menustyle, MENUTYPELEN, opt_in, set_in_game, Yes, Yes, No, Yes, NoAlias, - "user interface for object selection") + NHOPTC(menustyle, MENUTYPELEN, opt_in, set_in_game, Yes, Yes, No, Yes, + NoAlias, "user interface for object selection") NHOPTB(monpolycontrol, 0, opt_in, set_wizonly, Off, Yes, No, No, NoAlias, &iflags.mon_polycontrol) - NHOPTC(monsters, MAXMCLASSES, opt_in, set_in_config, No, Yes, No, No, NoAlias, - "the symbols to use for monsters") + NHOPTC(monsters, MAXMCLASSES, opt_in, set_in_config, No, Yes, No, No, + NoAlias, "list of symbols to use for monsters") NHOPTC(mouse_support, 0, opt_in, set_in_game, No, Yes, No, No, NoAlias, "game receives click info from mouse") #if defined(TTY_GRAPHICS) || defined(CURSES_GRAPHICS) NHOPTC(msg_window, 1, opt_in, set_in_game, Yes, Yes, No, Yes, NoAlias, - "the type of message window required") + "control of \"view previous message(s)\" (^P) behavior") #else NHOPTC(msg_window, 1, opt_in, set_in_config, Yes, Yes, No, Yes, NoAlias, - "the type of message window required") + "control of \"view previous message(s)\" (^P) behavior") #endif NHOPTC(msghistory, 5, opt_in, set_gameview, Yes, Yes, No, No, NoAlias, "number of top line messages to save") @@ -319,10 +321,10 @@ pfx_##a, &flags.null) NHOPTC(number_pad, 1, opt_in, set_in_game, No, Yes, No, Yes, NoAlias, "use the number pad for movement") - NHOPTC(objects, MAXOCLASSES, opt_in, set_in_config, No, Yes, No, No, NoAlias, - "the symbols to use for objects") - NHOPTC(packorder, MAXOCLASSES, opt_in, set_in_game, No, Yes, No, No, NoAlias, - "the inventory order of the items in your pack") + NHOPTC(objects, MAXOCLASSES, opt_in, set_in_config, No, Yes, No, No, + NoAlias, "list of symbols to use for objects") + NHOPTC(packorder, MAXOCLASSES, opt_in, set_in_game, No, Yes, No, No, + NoAlias, "the inventory order of the items in your pack") #ifdef CHANGE_COLOR #ifndef WIN32 NHOPTC(palette, 15, opt_in, set_in_game, No, Yes, No, No, "hicolor", @@ -344,12 +346,12 @@ pfx_##a, "maximum burden picked up before prompt") NHOPTB(pickup_thrown, 0, opt_out, set_in_game, On, Yes, No, No, NoAlias, &flags.pickup_thrown) - NHOPTC(pickup_types, MAXOCLASSES, opt_in, set_in_game, No, Yes, No, Yes, NoAlias, - "types of objects to pick up automatically") + NHOPTC(pickup_types, MAXOCLASSES, opt_in, set_in_game, No, Yes, No, Yes, + NoAlias, "types of objects to pick up automatically") NHOPTC(pile_limit, 24, opt_in, set_in_game, Yes, Yes, No, No, NoAlias, "threshold for \"there are many objects here\"") - NHOPTC(player_selection, 12, opt_in, set_gameview, No, Yes, No, No, NoAlias, - "choose character via dialog or prompts") + NHOPTC(player_selection, 12, opt_in, set_gameview, No, Yes, No, No, + NoAlias, "choose character via dialog or prompts") NHOPTC(playmode, 8, opt_in, set_gameview, No, Yes, No, No, NoAlias, "normal play, non-scoring explore mode, or debug mode") NHOPTB(popup_dialog, 0, opt_in, set_in_game, Off, Yes, No, No, NoAlias, @@ -372,13 +374,15 @@ pfx_##a, NHOPTB(rest_on_space, 0, opt_in, set_in_game, Off, Yes, No, No, NoAlias, &flags.rest_on_space) NHOPTC(roguesymset, 70, opt_in, set_in_game, No, Yes, No, Yes, NoAlias, - "load a set of rogue display symbols from the symbols file") + "load a set of rogue display symbols from symbols file") NHOPTC(role, PL_CSIZ, opt_in, set_gameview, No, Yes, No, No, "character", "your starting role (e.g., Barbarian, Valkyrie)") NHOPTC(runmode, sizeof "teleport", opt_in, set_in_game, Yes, Yes, No, Yes, NoAlias, "display frequency when `running' or `travelling'") NHOPTB(safe_pet, 0, opt_out, set_in_game, On, Yes, No, No, NoAlias, &flags.safe_dog) + NHOPTB(safe_wait, 0, opt_out, set_in_game, On, Yes, No, No, NoAlias, + &flags.safe_wait) NHOPTB(sanity_check, 0, opt_in, set_wizonly, Off, Yes, No, No, NoAlias, &iflags.sanity_check) NHOPTC(scores, 32, opt_in, set_in_game, No, Yes, No, No, NoAlias, @@ -404,6 +408,8 @@ pfx_##a, &flags.silent) NHOPTB(softkeyboard, 0, opt_in, set_in_config, Off, Yes, No, No, NoAlias, &iflags.wc2_softkeyboard) + NHOPTC(sortdiscoveries, 0, opt_in, set_in_game, Yes, Yes, No, Yes, + NoAlias, "preferred order when displaying discovered objects") NHOPTC(sortloot, 4, opt_in, set_in_game, No, Yes, No, Yes, NoAlias, "sort object selection lists by description") NHOPTB(sortpack, 0, opt_out, set_in_game, On, Yes, No, No, NoAlias, @@ -420,16 +426,11 @@ pfx_##a, NHOPTC(statushilites, 20, opt_in, set_in_game, Yes, Yes, Yes, No, NoAlias, "0=no status highlighting, N=show highlights for N turns") #else - NHOPTC(statushilites, 20, opt_in, set_in_config, Yes, Yes, Yes, No, NoAlias, - "highlight control") + NHOPTC(statushilites, 20, opt_in, set_in_config, Yes, Yes, Yes, No, + NoAlias, "highlight control") #endif -#ifdef CURSES_GRAPHICS NHOPTC(statuslines, 20, opt_in, set_in_game, No, Yes, No, No, NoAlias, - "2 or 3 lines for horizontal (bottom or top) status display") -#else - NHOPTC(statuslines, 20, opt_in, set_in_config, No, Yes, No, No, NoAlias, "2 or 3 lines for status display") -#endif #ifdef WIN32 NHOPTC(subkeyvalue, 7, opt_in, set_in_config, No, Yes, Yes, No, NoAlias, "override keystroke value") @@ -437,7 +438,7 @@ pfx_##a, NHOPTC(suppress_alert, 8, opt_in, set_in_game, No, Yes, Yes, No, NoAlias, "suppress alerts about version-specific features") NHOPTC(symset, 70, opt_in, set_in_game, No, Yes, No, Yes, NoAlias, - "load a set of display symbols from the symbols file") + "load a set of display symbols from symbols file") NHOPTC(term_cols, 6, opt_in, set_in_config, No, Yes, No, No, "termcolumns", "number of columns") NHOPTC(term_rows, 6, opt_in, set_in_config, No, Yes, No, No, NoAlias, @@ -463,8 +464,8 @@ pfx_##a, &flags.tombstone) NHOPTB(toptenwin, 0, opt_in, set_in_game, Off, Yes, No, No, NoAlias, &iflags.toptenwin) - NHOPTC(traps, MAXTCHARS + 1, opt_in, set_in_config, No, Yes, No, No, NoAlias, - "the symbols to use in drawing traps") + NHOPTC(traps, MAXTCHARS + 1, opt_in, set_in_config, No, Yes, No, No, + NoAlias, "list of symbols to use in drawing traps") NHOPTB(travel, 0, opt_out, set_in_game, On, Yes, No, No, NoAlias, &flags.travelcmd) #ifdef DEBUG @@ -487,8 +488,8 @@ pfx_##a, "method of video updating") #endif #ifdef VIDEOSHADES - NHOPTC(videocolors, 40, opt_in, set_gameview, No, Yes, No, No, "videocolours", - "color mappings for internal screen routines") + NHOPTC(videocolors, 40, opt_in, set_gameview, No, Yes, No, No, + "videocolours", "color mappings for internal screen routines") NHOPTC(videoshades, 32, opt_in, set_gameview, No, Yes, No, No, NoAlias, "gray shades to map to black/gray/white") #endif @@ -530,8 +531,8 @@ pfx_##a, #endif NHOPTC(windowcolors, 80, opt_in, set_gameview, No, Yes, No, No, NoAlias, "the foreground/background colors of windows") - NHOPTC(windowtype, WINTYPELEN, opt_in, set_gameview, No, Yes, No, No, NoAlias, - "windowing system to use") + NHOPTC(windowtype, WINTYPELEN, opt_in, set_gameview, No, Yes, No, No, + NoAlias, "windowing system to use (should be specified first)") NHOPTB(wizweight, 0, opt_in, set_wizonly, Off, Yes, No, No, NoAlias, &iflags.wizweight) NHOPTB(wraptext, 0, opt_in, set_in_game, Off, Yes, No, No, NoAlias, diff --git a/include/patchlevel.h b/include/patchlevel.h index b5cda35a8..a7b4c2da8 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 22 +#define EDITLEVEL 30 /* * Development status possibilities. @@ -98,7 +98,7 @@ * fix the article used in the message when your steed encounters a polymorph * trap * allow teleporting onto the vibrating square - * message "your knapsack can't accomodate any more items" when picking stuff + * message "your knapsack can't accommodate any more items" when picking stuff * up or removing such from container was inaccurate if there was some * gold pending; vary the message rather than add more convoluted pickup * code diff --git a/include/pcconf.h b/include/pcconf.h index 6f1ad2b48..e2e6eca8a 100644 --- a/include/pcconf.h +++ b/include/pcconf.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 pcconf.h $NHDT-Date: 1593953338 2020/07/05 12:48:58 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.27 $ */ +/* NetHack 3.7 pcconf.h $NHDT-Date: 1596498554 2020/08/03 23:49:14 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.28 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2006. */ /* NetHack may be freely redistributed. See license for details. */ @@ -35,7 +35,9 @@ /*#define OVERLAY */ /* Manual overlay definition (MSC 6.0ax only) */ +#ifndef CROSS_TO_AMIGA #define SHELL /* via exec of COMMAND.COM */ +#endif /* * Screen control options @@ -88,7 +90,9 @@ #define ANSI_DEFAULT #endif +#ifndef CROSS_TO_AMIGA #define RANDOM /* have Berkeley random(3) */ +#endif #define MAIL /* Allows for fake mail daemon to deliver mail */ /* in the MSDOS version. (For AMIGA MAIL see */ @@ -101,6 +105,10 @@ #include /* Provides prototypes of exit(), spawn() */ #endif +#ifdef CROSS_TO_AMIGA +#include +#endif + #if defined(_MSC_VER) && (_MSC_VER >= 7) #include #include @@ -155,7 +163,9 @@ #endif /* MSDOS configuration stuff */ +#ifndef PATHLEN #define PATHLEN 64 /* maximum pathlength */ +#endif #define FILENAME 80 /* maximum filename length (conservative) */ #ifndef MICRO_H #include "micro.h" /* contains necessary externs for [os_name].c */ @@ -249,22 +259,6 @@ /* Sanity check, do not modify these blocks. */ -/* OVERLAY must be defined with MOVERLAY or VROOMM */ -#if (defined(MOVERLAY) || defined(VROOMM)) -#ifndef OVERLAY -#define OVERLAY -#endif -#endif - -#if defined(FUNCTION_LEVEL_LINKING) -#define OVERLAY -#endif - -#if defined(OVERLAY) && !defined(MOVERLAY) && !defined(VROOMM) \ - && !defined(FUNCTION_LEVEL_LINKING) -#define USE_TRAMPOLI -#endif - #if defined(MSDOS) && defined(NO_TERMS) #ifdef TERMLIB #if defined(_MSC_VER) || defined(__SC__) diff --git a/include/permonst.h b/include/permonst.h index b22269e68..0a017c68a 100644 --- a/include/permonst.h +++ b/include/permonst.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 permonst.h $NHDT-Date: 1539804913 2018/10/17 19:35:13 $ $NHDT-Branch: keni-makedefsm $:$NHDT-Revision: 1.12 $ */ +/* NetHack 3.7 permonst.h $NHDT-Date: 1596498555 2020/08/03 23:49:15 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.14 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Kenneth Lorber, Kensington, Maryland, 2015. */ /* NetHack may be freely redistributed. See license for details. */ @@ -40,7 +40,7 @@ struct attack { #include "monflag.h" struct permonst { - const char *mname; /* full name */ + const char *pmnames[NUM_MGENDERS]; char mlet; /* symbol */ schar mlevel, /* base monster level */ mmove, /* move speed */ @@ -78,4 +78,8 @@ extern NEARDATA struct permonst mons[]; /* the master list of monster types */ /* mons[SPECIAL_PM] through mons[NUMMONS-1], inclusive, are never generated randomly and cannot be polymorphed into */ +#ifdef PMNAME_MACROS +#define pmname(pm,g) ((((g) == MALE || (g) == FEMALE) && (pm)->pmnames[g]) \ + ? (pm)->pmnames[g] : (pm)->pmnames[NEUTRAL]) +#endif #endif /* PERMONST_H */ diff --git a/include/prop.h b/include/prop.h index 570f3f2fa..889ada22f 100644 --- a/include/prop.h +++ b/include/prop.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 prop.h $NHDT-Date: 1570566360 2019/10/08 20:26:00 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.21 $ */ +/* NetHack 3.7 prop.h $NHDT-Date: 1596498555 2020/08/03 23:49:15 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.22 $ */ /* Copyright (c) 1989 Mike Threepoint */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/include/quest.h b/include/quest.h index 0042de7f0..710af02d9 100644 --- a/include/quest.h +++ b/include/quest.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 quest.h $NHDT-Date: 1432512779 2015/05/25 00:12:59 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ */ +/* NetHack 3.7 quest.h $NHDT-Date: 1596498556 2020/08/03 23:49:16 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.11 $ */ /* Copyright (c) Mike Stephenson 1991. */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/include/rect.h b/include/rect.h index efbf253d5..cd5cb3b63 100644 --- a/include/rect.h +++ b/include/rect.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 rect.h $NHDT-Date: 1432512778 2015/05/25 00:12:58 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ +/* NetHack 3.7 rect.h $NHDT-Date: 1596498557 2020/08/03 23:49:17 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.9 $ */ /* Copyright (c) 1990 by Jean-Christophe Collet */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/include/region.h b/include/region.h index dd1534fc2..1303c7099 100644 --- a/include/region.h +++ b/include/region.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 region.h $NHDT-Date: 1432512779 2015/05/25 00:12:59 $ $NHDT-Branch: master $:$NHDT-Revision: 1.13 $ */ +/* NetHack 3.7 region.h $NHDT-Date: 1596498557 2020/08/03 23:49:17 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.15 $ */ /* Copyright (c) 1996 by Jean-Christophe Collet */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/include/rm.h b/include/rm.h index e5322b2ee..3d303a5c4 100644 --- a/include/rm.h +++ b/include/rm.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 rm.h $NHDT-Date: 1589064684 2020/05/09 22:51:24 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.82 $ */ +/* NetHack 3.7 rm.h $NHDT-Date: 1599434249 2020/09/06 23:17:29 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.84 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Pasi Kallinen, 2017. */ /* NetHack may be freely redistributed. See license for details. */ @@ -243,6 +243,8 @@ enum screen_symbols { #define is_cmap_furniture(i) ((i) >= S_upstair && (i) <= S_fountain) #define is_cmap_water(i) ((i) == S_pool || (i) == S_water) #define is_cmap_lava(i) ((i) == S_lava) +#define is_cmap_stairs(i) ((i) == S_upstair || (i) == S_dnstair || \ + (i) == S_upladder || (i) == S_dnladder) struct symdef { @@ -335,11 +337,6 @@ extern const struct symdef def_warnsyms[WARNCOUNT]; #define D_TRAPPED 16 #define D_SECRET 32 /* only used by sp_lev.c, NOT in rm-struct */ -/* - * Some altars are considered as shrines, so we need a flag. - */ -#define AM_SHRINE 8 - /* * Thrones should only be looted once. */ @@ -436,22 +433,6 @@ struct rm { Bitfield(candig, 1); /* Exception to Can_dig_down; was a trapdoor */ }; -#define SET_TYPLIT(x, y, ttyp, llit) \ - { \ - if ((x) >= 0 && (y) >= 0 && (x) < COLNO && (y) < ROWNO) { \ - if ((ttyp) < MAX_TYPE) \ - levl[(x)][(y)].typ = (ttyp); \ - if ((ttyp) == LAVAPOOL) \ - levl[(x)][(y)].lit = 1; \ - else if ((schar)(llit) != -2) { \ - if ((schar)(llit) == -1) \ - levl[(x)][(y)].lit = rn2(2); \ - else \ - levl[(x)][(y)].lit = (llit); \ - } \ - } \ - } - /* * Add wall angle viewing by defining "modes" for each wall type. Each * mode describes which parts of a wall are finished (seen as as wall) @@ -563,7 +544,7 @@ struct cemetery { /* date+time in string of digits rather than binary */ char when[4 + 2 + 2 + 2 + 2 + 2 + 1]; /* "YYYYMMDDhhmmss\0" */ /* final resting place spot */ - schar frpx, frpy; + xchar frpx, frpy; boolean bonesknown; }; @@ -631,10 +612,10 @@ typedef struct { * Macros for encapsulation of level.monsters references. */ #if 0 -#define MON_AT(x, y) \ +#define MON_AT(x, y) \ (g.level.monsters[x][y] != (struct monst *) 0 \ && !(g.level.monsters[x][y])->mburied) -#define MON_BURIED_AT(x, y) \ +#define MON_BURIED_AT(x, y) \ (g.level.monsters[x][y] != (struct monst *) 0 \ && (g.level.monsters[x][y])->mburied) #else /* without 'mburied' */ @@ -642,15 +623,15 @@ typedef struct { #endif #ifdef EXTRA_SANITY_CHECKS #define place_worm_seg(m, x, y) \ - do { \ + do { \ if (g.level.monsters[x][y] && g.level.monsters[x][y] != m) \ - impossible("place_worm_seg over mon"); \ - g.level.monsters[x][y] = m; \ + impossible("place_worm_seg over mon"); \ + g.level.monsters[x][y] = m; \ } while(0) #define remove_monster(x, y) \ - do { \ + do { \ if (!g.level.monsters[x][y]) \ - impossible("no monster to remove"); \ + impossible("no monster to remove"); \ g.level.monsters[x][y] = (struct monst *) 0; \ } while(0) #else diff --git a/include/skills.h b/include/skills.h index a7cdb5256..1862238c6 100644 --- a/include/skills.h +++ b/include/skills.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 skills.h $NHDT-Date: 1547255911 2019/01/12 01:18:31 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.15 $ */ +/* NetHack 3.7 skills.h $NHDT-Date: 1596498559 2020/08/03 23:49:19 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.16 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985-1999. */ /*-Copyright (c) Pasi Kallinen, 2017. */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/include/sp_lev.h b/include/sp_lev.h index 4104d51c9..ed3e20381 100644 --- a/include/sp_lev.h +++ b/include/sp_lev.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 sp_lev.h $NHDT-Date: 1580434523 2020/01/31 01:35:23 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.33 $ */ +/* NetHack 3.7 sp_lev.h $NHDT-Date: 1599434249 2020/09/06 23:17:29 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.39 $ */ /* Copyright (c) 1989 by Jean-Christophe Collet */ /* NetHack may be freely redistributed. See license for details. */ @@ -62,6 +62,11 @@ enum lvlinit_types { #define SEL_GRADIENT_RADIAL 0 #define SEL_GRADIENT_SQUARE 1 +/* light states for terrain replacements, specifically for SET_TYPLIT + * (not used for init_level) */ +#define SET_LIT_RANDOM -1 +#define SET_LIT_NOCHANGE -2 + #define SP_COORD_IS_RANDOM 0x01000000L /* Humidity flags for get_location() and friends, used with * SP_COORD_PACK_RANDOM() */ @@ -180,7 +185,7 @@ typedef struct _room { Str_or_Len parent; xchar x, y, w, h; xchar xalign, yalign; - xchar rtype, chance, rlit, filled, joined; + xchar rtype, chance, rlit, needfill, joined; } room; struct mapfragment { @@ -188,4 +193,21 @@ struct mapfragment { char *data; }; +#define SET_TYPLIT(x, y, ttyp, llit) \ + { \ + if ((x) >= 1 && (y) >= 0 && (x) < COLNO && (y) < ROWNO) { \ + if ((ttyp) < MAX_TYPE && levl[(x)][(y)].typ != STAIRS \ + && levl[(x)][(y)].typ != LADDER) \ + levl[(x)][(y)].typ = (ttyp); \ + if ((ttyp) == LAVAPOOL) \ + levl[(x)][(y)].lit = 1; \ + else if ((schar)(llit) != SET_LIT_NOCHANGE) { \ + if ((schar)(llit) == SET_LIT_RANDOM) \ + levl[(x)][(y)].lit = rn2(2); \ + else \ + levl[(x)][(y)].lit = (llit); \ + } \ + } \ + } + #endif /* SP_LEV_H */ diff --git a/include/spell.h b/include/spell.h index 8bf50715e..479283458 100644 --- a/include/spell.h +++ b/include/spell.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 spell.h $NHDT-Date: 1432512780 2015/05/25 00:13:00 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ */ +/* NetHack 3.7 spell.h $NHDT-Date: 1596498560 2020/08/03 23:49:20 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.11 $ */ /* Copyright 1986, M. Stephenson */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/include/sys.h b/include/sys.h index afb1fc865..ef794e747 100644 --- a/include/sys.h +++ b/include/sys.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 sys.h $NHDT-Date: 1449296291 2015/12/05 06:18:11 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.27 $ */ +/* NetHack 3.7 sys.h $NHDT-Date: 1596498561 2020/08/03 23:49:21 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.36 $ */ /* Copyright (c) Kenneth Lorber, Kensington, Maryland, 2008. */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/include/system.h b/include/system.h index 3906e68e4..ead454d69 100644 --- a/include/system.h +++ b/include/system.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 system.h $NHDT-Date: 1574825213 2019/11/27 03:26:53 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.22 $ */ +/* NetHack 3.7 system.h $NHDT-Date: 1596498562 2020/08/03 23:49:22 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.24 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2017. */ /* NetHack may be freely redistributed. See license for details. */ @@ -339,7 +339,7 @@ E int FDECL(memcmp, (const void *, const void *, size_t)); E void *FDECL(memcpy, (void *, const void *, size_t)); E void *FDECL(memset, (void *, int, size_t)); #else -#if defined(AZTEC_50) || defined(NHSTDC)) +#if defined(AZTEC_50) || defined(NHSTDC) E int FDECL(memcmp, (const void *, const void *, size_t)); E void *FDECL(memcpy, (void *, const void *, size_t)); E void *FDECL(memset, (void *, int, size_t)); diff --git a/include/tcap.h b/include/tcap.h index f3f28a95e..508d9432e 100644 --- a/include/tcap.h +++ b/include/tcap.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 tcap.h $NHDT-Date: 1432512774 2015/05/25 00:12:54 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ */ +/* NetHack 3.7 tcap.h $NHDT-Date: 1596498562 2020/08/03 23:49:22 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.12 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1989. */ /*-Copyright (c) Kenneth Lorber, Kensington, Maryland, 2015. */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/include/tile2x11.h b/include/tile2x11.h index 802cbd853..2839e8946 100644 --- a/include/tile2x11.h +++ b/include/tile2x11.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 tile2x11.h $NHDT-Date: 1524689515 2018/04/25 20:51:55 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.10 $ */ +/* NetHack 3.7 tile2x11.h $NHDT-Date: 1597274123 2020/08/12 23:15:23 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.12 $ */ /* Copyright (c) 2002 by David Cohrs */ /* NetHack may be freely redistributed. See license for details. */ @@ -6,7 +6,10 @@ #define TILE2X11_H /* - * Header for the x11 tile map. + * Header for the X11 tile map. + * + * dat/x11tiles is used by Qt for fallback if nhtiles.bmp is inaccessible, + * so this header is used by Qt as well as by X11. */ typedef struct { unsigned long version; diff --git a/include/tileset.h b/include/tileset.h index 997766434..92f40be9d 100644 --- a/include/tileset.h +++ b/include/tileset.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 tileset.h $NHDT-Date: 1457207052 2016/03/05 19:44:12 $ $NHDT-Branch: chasonr $:$NHDT-Revision: 1.0 $ */ +/* NetHack 3.7 tileset.h $NHDT-Date: 1596498564 2020/08/03 23:49:24 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.2 $ */ /* Copyright (c) Ray Chason, 2016. */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/include/timeout.h b/include/timeout.h index 0ac85a3c8..3853c80d4 100644 --- a/include/timeout.h +++ b/include/timeout.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 timeout.h $NHDT-Date: 1564269131 2019/07/27 23:12:11 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.12 $ */ +/* NetHack 3.7 timeout.h $NHDT-Date: 1596498564 2020/08/03 23:49:24 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.13 $ */ /* Copyright 1994, Dean Luick */ /* NetHack may be freely redistributed. See license for details. */ @@ -29,6 +29,7 @@ enum timeout_types { ROT_ORGANIC = 0, /* for buried organics */ ROT_CORPSE, REVIVE_MON, + ZOMBIFY_MON, BURN_OBJECT, HATCH_EGG, FIG_TRANSFORM, diff --git a/include/tradstdc.h b/include/tradstdc.h index 12a0d4afe..3827195f5 100644 --- a/include/tradstdc.h +++ b/include/tradstdc.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 tradstdc.h $NHDT-Date: 1555361295 2019/04/15 20:48:15 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.36 $ */ +/* NetHack 3.7 tradstdc.h $NHDT-Date: 1596498565 2020/08/03 23:49:25 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.37 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2006. */ /* NetHack may be freely redistributed. See license for details. */ @@ -184,11 +184,10 @@ typedef const char *vA; * FDECL() is used for functions with a fixed number of arguments; * VDECL() is used for functions with a variable number of arguments. * Separate macros are needed because ANSI will mix old-style declarations - * with prototypes, except in the case of varargs, and the OVERLAY-specific - * trampoli.* mechanism conflicts with the ANSI <> syntax. - */ + * with prototypes, except in the case of varargs + */ -#define NDECL(f) f(void) /* overridden later if USE_TRAMPOLI set */ +#define NDECL(f) f(void) #define FDECL(f, p) f p diff --git a/include/trap.h b/include/trap.h index f422c7764..8d08143b2 100644 --- a/include/trap.h +++ b/include/trap.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 trap.h $NHDT-Date: 1547255912 2019/01/12 01:18:32 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.17 $ */ +/* NetHack 3.7 trap.h $NHDT-Date: 1596498566 2020/08/03 23:49:26 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.19 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Pasi Kallinen, 2016. */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/include/unixconf.h b/include/unixconf.h index 1d3d636b0..698adfc56 100644 --- a/include/unixconf.h +++ b/include/unixconf.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 unixconf.h $NHDT-Date: 1555361298 2019/04/15 20:48:18 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.42 $ */ +/* NetHack 3.7 unixconf.h $NHDT-Date: 1607461111 2020/12/08 20:58:31 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.49 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Pasi Kallinen, 2018. */ /* NetHack may be freely redistributed. See license for details. */ @@ -273,8 +273,11 @@ #endif #endif #endif + +#ifndef NOSUSPEND #if defined(BSD_JOB_CONTROL) || defined(POSIX_JOB_CONTROL) || defined(AUX) -#define SUSPEND /* let ^Z suspend the game */ +#define SUSPEND /* let ^Z suspend the game (push to background) */ +#endif #endif /* @@ -389,7 +392,7 @@ #endif /* LINUX */ #endif /* GNOME_GRAPHICS */ -#ifdef MACOSX +#if defined(MACOSX) && !defined(LIBNH) # define RUNTIME_PASTEBUF_SUPPORT #endif diff --git a/include/vision.h b/include/vision.h index 8b2b0090c..7d1f651b6 100644 --- a/include/vision.h +++ b/include/vision.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 vision.h $NHDT-Date: 1559994624 2019/06/08 11:50:24 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.10 $ */ +/* NetHack 3.7 vision.h $NHDT-Date: 1596498568 2020/08/03 23:49:28 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.13 $ */ /* Copyright (c) Dean Luick, with acknowledgements to Dave Cohrs, 1990. */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/include/vmsconf.h b/include/vmsconf.h index 4fc219c2e..4c17d6151 100644 --- a/include/vmsconf.h +++ b/include/vmsconf.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 vmsconf.h $NHDT-Date: 1555361299 2019/04/15 20:48:19 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.30 $ */ +/* NetHack 3.7 vmsconf.h $NHDT-Date: 1596498569 2020/08/03 23:49:29 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.33 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2011. */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/include/winGnome.h b/include/winGnome.h index 0c2483a78..93bbbeb13 100644 --- a/include/winGnome.h +++ b/include/winGnome.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 winGnome.h $NHDT-Date: 1432512782 2015/05/25 00:13:02 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ +/* NetHack 3.7 winGnome.h $NHDT-Date: 1596498571 2020/08/03 23:49:31 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.9 $ */ /* Copyright (C) 1998 by Erik Andersen */ /* Copyright (C) 1998 by Anthony Taylor */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/include/winX.h b/include/winX.h index 60c4e8d58..3f29dce75 100644 --- a/include/winX.h +++ b/include/winX.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 winX.h $NHDT-Date: 1457079196 2016/03/04 08:13:16 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.23 $ */ +/* NetHack 3.7 winX.h $NHDT-Date: 1596498574 2020/08/03 23:49:34 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.39 $ */ /* Copyright (c) Dean Luick, 1992 */ /* NetHack may be freely redistributed. See license for details. */ @@ -453,7 +453,8 @@ E void NDECL(X11_wait_synch); #ifdef CLIPPING E void FDECL(X11_cliparound, (int, int)); #endif -E void FDECL(X11_print_glyph, (winid, XCHAR_P, XCHAR_P, int, int)); +E void FDECL(X11_print_glyph, (winid, XCHAR_P, XCHAR_P, + int, int, unsigned *)); E void FDECL(X11_raw_print, (const char *)); E void FDECL(X11_raw_print_bold, (const char *)); E int NDECL(X11_nhgetch); diff --git a/include/winami.h b/include/winami.h index ccc3c1e16..77932cc67 100644 --- a/include/winami.h +++ b/include/winami.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 winami.h $NHDT-Date: 1432512780 2015/05/25 00:13:00 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ +/* NetHack 3.7 winami.h $NHDT-Date: 1596498569 2020/08/03 23:49:29 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.9 $ */ /* Copyright (c) Kenneth Lorber, Bethesda, Maryland, 1991. */ /* Copyright (c) Gregg Wonderly, Naperville, Illinois, 1992, 1993. */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/include/wincurs.h b/include/wincurs.h index 9ae069a22..001c813e6 100644 --- a/include/wincurs.h +++ b/include/wincurs.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 wincurs.h */ +/* NetHack 3.7 wincurs.h */ /* Copyright (c) Karl Garrison, 2010. */ /* NetHack may be freely redistributed. See license for details. */ @@ -90,7 +90,7 @@ extern void curses_mark_synch(void); extern void curses_wait_synch(void); extern void curses_cliparound(int x, int y); extern void curses_print_glyph(winid wid, XCHAR_P x, XCHAR_P y, - int glyph, int bkglyph); + int glyph, int bkglyph, unsigned *glyphmod); extern void curses_raw_print(const char *str); extern void curses_raw_print_bold(const char *str); extern int curses_nhgetch(void); @@ -105,7 +105,7 @@ 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); +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); extern void curs_reset_windows(boolean, boolean); diff --git a/include/wingem.h b/include/wingem.h index 8d1edf2be..f433e1cc6 100644 --- a/include/wingem.h +++ b/include/wingem.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 wingem.h $NHDT-Date: 1433806582 2015/06/08 23:36:22 $ $NHDT-Branch: master $:$NHDT-Revision: 1.12 $ */ +/* NetHack 3.7 wingem.h $NHDT-Date: 1596498570 2020/08/03 23:49:30 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.15 $ */ /* Copyright (c) Christian Bressler, 1999 */ /* NetHack may be freely redistributed. See license for details. */ @@ -84,7 +84,8 @@ E void FDECL(Gem_cliparound, (int, int)); #ifdef POSITIONBAR E void FDECL(Gem_update_positionbar, (char *)); #endif -E void FDECL(Gem_print_glyph, (winid, XCHAR_P, XCHAR_P, int, int)); +E void FDECL(Gem_print_glyph, (winid, XCHAR_P, XCHAR_P, + int, int, unsigned *)); E void FDECL(Gem_raw_print, (const char *)); E void FDECL(Gem_raw_print_bold, (const char *)); E int NDECL(Gem_nhgetch); diff --git a/include/winprocs.h b/include/winprocs.h index 6506c9af0..728e35067 100644 --- a/include/winprocs.h +++ b/include/winprocs.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 winprocs.h $NHDT-Date: 1567213890 2019/08/31 01:11:30 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.50 $ */ +/* NetHack 3.7 winprocs.h $NHDT-Date: 1596498572 2020/08/03 23:49:32 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.56 $ */ /* Copyright (c) David Cohrs, 1992 */ /* NetHack may be freely redistributed. See license for details. */ @@ -45,7 +45,8 @@ struct window_procs { #ifdef POSITIONBAR void FDECL((*win_update_positionbar), (char *)); #endif - void FDECL((*win_print_glyph), (winid, XCHAR_P, XCHAR_P, int, int)); + void FDECL((*win_print_glyph), (winid, XCHAR_P, XCHAR_P, + int, int, unsigned *)); void FDECL((*win_raw_print), (const char *)); void FDECL((*win_raw_print_bold), (const char *)); int NDECL((*win_nhgetch)); @@ -345,7 +346,8 @@ struct chain_procs { #ifdef POSITIONBAR void FDECL((*win_update_positionbar), (CARGS, char *)); #endif - void FDECL((*win_print_glyph), (CARGS, winid, XCHAR_P, XCHAR_P, int, int)); + void FDECL((*win_print_glyph), (CARGS, winid, XCHAR_P, XCHAR_P, + int, int, unsigned *)); void FDECL((*win_raw_print), (CARGS, const char *)); void FDECL((*win_raw_print_bold), (CARGS, const char *)); int FDECL((*win_nhgetch), (CARGS)); @@ -420,7 +422,8 @@ extern void FDECL(safe_cliparound, (int, int)); #ifdef POSITIONBAR extern void FDECL(safe_update_positionbar, (char *)); #endif -extern void FDECL(safe_print_glyph, (winid, XCHAR_P, XCHAR_P, int, int)); +extern void FDECL(safe_print_glyph, (winid, XCHAR_P, XCHAR_P, + int, int, unsigned *)); extern void FDECL(safe_raw_print, (const char *)); extern void FDECL(safe_raw_print_bold, (const char *)); extern int NDECL(safe_nhgetch); diff --git a/include/wintty.h b/include/wintty.h index a13fe5226..5d1d444d0 100644 --- a/include/wintty.h +++ b/include/wintty.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 wintty.h $NHDT-Date: 1594169998 2020/07/08 00:59:58 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.43 $ */ +/* NetHack 3.7 wintty.h $NHDT-Date: 1596498572 2020/08/03 23:49:32 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.44 $ */ /* Copyright (c) David Cohrs, 1991,1992 */ /* NetHack may be freely redistributed. See license for details. */ @@ -52,6 +52,12 @@ struct WinDesc { #define WIN_STOP 1 /* for NHW_MESSAGE; stops output */ #define WIN_LOCKHISTORY 2 /* for NHW_MESSAGE; suppress history updates */ +/* topline states */ +#define TOPLINE_EMPTY 0 /* empty */ +#define TOPLINE_NEED_MORE 1 /* non-empty, need --More-- */ +#define TOPLINE_NON_EMPTY 2 /* non-empty, no --More-- required */ +#define TOPLINE_SPECIAL_PROMPT 3 /* special prompt state */ + /* descriptor for tty-based displays -- all the per-display data */ struct DisplayDesc { short rows, cols; /* width and height of tty display */ @@ -205,7 +211,7 @@ E void FDECL(tty_cliparound, (int, int)); #ifdef POSITIONBAR E void FDECL(tty_update_positionbar, (char *)); #endif -E void FDECL(tty_print_glyph, (winid, XCHAR_P, XCHAR_P, int, int)); +E void FDECL(tty_print_glyph, (winid, XCHAR_P, XCHAR_P, int, int, unsigned *)); E void FDECL(tty_raw_print, (const char *)); E void FDECL(tty_raw_print_bold, (const char *)); E int NDECL(tty_nhgetch); diff --git a/include/wintype.h b/include/wintype.h index d85485aeb..534421f2c 100644 --- a/include/wintype.h +++ b/include/wintype.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 wintype.h $NHDT-Date: 1549327486 2019/02/05 00:44:46 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.19 $ */ +/* NetHack 3.7 wintype.h $NHDT-Date: 1596498573 2020/08/03 23:49:33 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.23 $ */ /* Copyright (c) David Cohrs, 1991 */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/include/xwindow.h b/include/xwindow.h index 8b9cfa0d3..e05e94ae3 100644 --- a/include/xwindow.h +++ b/include/xwindow.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 xwindow.h $NHDT-Date: 1432512775 2015/05/25 00:12:55 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ +/* NetHack 3.7 xwindow.h $NHDT-Date: 1596498574 2020/08/03 23:49:34 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.9 $ */ /* Copyright (c) Dean Luick, 1992 */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/include/xwindowp.h b/include/xwindowp.h index 74f8e4ac0..10ee0b815 100644 --- a/include/xwindowp.h +++ b/include/xwindowp.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 xwindowp.h $NHDT-Date: 1432512779 2015/05/25 00:12:59 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ +/* NetHack 3.7 xwindowp.h $NHDT-Date: 1596498575 2020/08/03 23:49:35 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.9 $ */ /* Copyright (c) Dean Luick, 1992 */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/include/you.h b/include/you.h index da85c9c21..79d3737ff 100644 --- a/include/you.h +++ b/include/you.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 you.h $NHDT-Date: 1593768079 2020/07/03 09:21:19 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.46 $ */ +/* NetHack 3.7 you.h $NHDT-Date: 1596498576 2020/08/03 23:49:36 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.48 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2016. */ /* NetHack may be freely redistributed. See license for details. */ @@ -93,7 +93,9 @@ enum achivements { ACH_NOVL = 20, /* read at least one passage from a Discworld novel */ ACH_SOKO = 21, /* entered Sokoban */ ACH_BGRM = 22, /* entered Bigroom (not guaranteed to be in every dgn) */ - /* 23..30 are negated if hero is female at the time new rank is gained */ + /* role's rank titles, beyond first (#0 at level one, not an achievement); + 23..30 are negated if hero is female at the time new rank is gained + so that disclosing them can use the gender which applied at the time */ ACH_RNK1 = 23, ACH_RNK2 = 24, ACH_RNK3 = 25, ACH_RNK4 = 26, ACH_RNK5 = 27, ACH_RNK6 = 28, ACH_RNK7 = 29, ACH_RNK8 = 30, /* foo=31, 1 available potential achievement; #32 currently off-limits */ @@ -102,6 +104,8 @@ enum achivements { /* * Other potential achievements to track (this comment briefly resided * in encodeachieve(topten.c) and has been revised since moving here: + * AC <= 0, AC <= -10, AC <= -20 (stop there; lower is better but + * not something to encourage with achievements), * got quest summons, * entered quest branch, * chatted with leader, @@ -334,6 +338,15 @@ enum utraptypes { TT_BURIEDBALL = 5 }; +enum utotypes { + UTOTYPE_NONE = 0x00, + UTOTYPE_ATSTAIRS = 0x01, + UTOTYPE_FALLING = 0x02, + UTOTYPE_PORTAL = 0x04, + UTOTYPE_RMPORTAL = 0x10, /* remove portal */ + UTOTYPE_DEFERRED = 0x20 /* deferred_goto */ +}; + /*** Information about the player ***/ struct you { xchar ux, uy; /* current map coordinates */ @@ -359,7 +372,7 @@ struct you { char ushops_entered[5]; /* ditto, shops entered this turn */ char ushops_left[5]; /* ditto, shops exited this turn */ - int uhunger; /* refd only in eat.c and shk.c */ + int uhunger; /* refd only in eat.c and shk.c (also insight.c) */ unsigned uhs; /* hunger state - see eat.c */ struct prop uprops[LAST_PROP + 1]; @@ -422,14 +435,18 @@ struct you { #define A_CURRENT 0 aligntyp ualignbase[CONVERT]; /* for ualign conversion record */ schar uluck, moreluck; /* luck and luck bonus */ + /* default u.uluck is 0 except on special days (full moon: +1, Fri 13: -1, + both: 0); equilibrium for luck timeout is changed to those values, + but Luck max and min stay at 10+3 and -10-3 even on those days */ #define Luck (u.uluck + u.moreluck) #define LUCKADD 3 /* value of u.moreluck when carrying luck stone; - + when blessed or uncursed, - when cursed */ -#define LUCKMAX 10 /* maximum value of u.ulUck */ + * +3 when blessed or uncursed, -3 when cursed */ +#define LUCKMAX 10 /* maximum value of u.uluck */ #define LUCKMIN (-10) /* minimum value of u.uluck */ schar uhitinc; schar udaminc; schar uac; +#define AC_MAX 99 /* abs(u.uac) <= 99; likewise for monster AC */ uchar uspellprot; /* protection by SPE_PROTECTION */ uchar usptime; /* #moves until uspellprot-- */ uchar uspmtime; /* #moves between uspellprot-- */ @@ -462,5 +479,6 @@ struct you { }; /* end of `struct you' */ #define Upolyd (u.umonnum != u.umonster) +#define Ugender ((Upolyd ? u.mfemale : flags.female) ? 1 : 0) #endif /* YOU_H */ diff --git a/include/youprop.h b/include/youprop.h index c7bce068c..ff26d3e03 100644 --- a/include/youprop.h +++ b/include/youprop.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 youprop.h $NHDT-Date: 1579655025 2020/01/22 01:03:45 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.30 $ */ +/* NetHack 3.7 youprop.h $NHDT-Date: 1596498577 2020/08/03 23:49:37 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.32 $ */ /* Copyright (c) 1989 Mike Threepoint */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/.travis.yml b/outdated/.travis.yml similarity index 70% rename from .travis.yml rename to outdated/.travis.yml index 4ed41b36f..454ca418e 100644 --- a/.travis.yml +++ b/outdated/.travis.yml @@ -1,62 +1,9 @@ language: c matrix: include: - - name: linux-xenial-gcc + - name: linux-xenial-gcc-win-all os: linux - env: HINTS=linux LUA_VERSION=5.4.0 - compiler: gcc - script: - - cd sys/unix/ && sh setup.sh hints/$HINTS && cd ../../ - - make fetch-lua - - test -d "lib/lua-$LUA_VERSION/src" || exit 0 - - make install - - name: linux-xenial-gcc-nocommon - os: linux - env: HINTS=linux LUA_VERSION=5.4.0 - compiler: gcc - script: - - echo "CFLAGS+=-fno-common" >>sys/unix/hints/$HINTS - - cd sys/unix/ && sh setup.sh hints/$HINTS && cd ../../ - - make fetch-lua - - test -d "lib/lua-$LUA_VERSION/src" || exit 0 - - make install - - name: linux-bionic-gcc - os: linux - env: HINTS=linux LUA_VERSION=5.4.0 - dist: bionic - compiler: gcc - script: - - cd sys/unix/ && sh setup.sh hints/$HINTS && cd ../../ - - make fetch-lua - - test -d "lib/lua-$LUA_VERSION/src" || exit 0 - - make install - - name: linux-xenial-clang - os: linux - env: HINTS=linux LUA_VERSION=5.4.0 - compiler: clang - script: - - cd sys/unix/ && sh setup.sh hints/$HINTS && cd ../../ - - make fetch-lua - - test -d "lib/lua-$LUA_VERSION/src" || exit 0 - - make install - - name: linux-xenial-gcc-x11 - os: linux - env: HINTS=linux-x11 LUA_VERSION=5.4.0 - compiler: gcc - addons: - apt: - packages: - - libx11-dev - - libxaw7-dev - - xfonts-utils - script: - - cd sys/unix/ && sh setup.sh hints/$HINTS && cd ../../ - - make fetch-lua - - test -d "lib/lua-$LUA_VERSION/src" || exit 0 - - make install - - name: linux-xenial-gcc-qt5 - os: linux - env: HINTS=linux-qt5 LUA_VERSION=5.4.0 + env: HINTS=linux.2020 LUA_VERSION=5.4.2 compiler: gcc addons: apt: @@ -69,12 +16,12 @@ matrix: - qtbase5-dev-tools script: - cd sys/unix/ && sh setup.sh hints/$HINTS && cd ../../ - - make fetch-lua + - make fetch-lua LUA_VERSION=$LUA_VERSION - test -d "lib/lua-$LUA_VERSION/src" || exit 0 - - make QT_SELECT=5 MOC=moc install - - name: linux-bionic-gcc-x11 + - make LUA_VERSION=$LUA_VERSION WANT_WIN_ALL=1 QT_SELECT=5 MOC=moc install + - name: linux-bionic-gcc-win-all os: linux - env: HINTS=linux-x11 LUA_VERSION=5.4.0 + env: HINTS=linux.2020 LUA_VERSION=5.4.2 dist: bionic compiler: gcc addons: @@ -83,14 +30,68 @@ matrix: - libx11-dev - libxaw7-dev - xfonts-utils + - qtbase5-dev + - qtmultimedia5-dev + - qtbase5-dev-tools script: - cd sys/unix/ && sh setup.sh hints/$HINTS && cd ../../ - - make fetch-lua + - make fetch-lua LUA_VERSION=$LUA_VERSION + - test -d "lib/lua-$LUA_VERSION/src" || exit 0 + - make LUA_VERSION=$LUA_VERSION WANT_WIN_ALL=1 QT_SELECT=5 MOC=moc install + - name: linux-focal-clang-win-all + os: linux + env: HINTS=linux.2020 LUA_VERSION=5.4.2 + dist: focal + compiler: clang + addons: + apt: + packages: + - xfonts-utils + - libx11-dev + - libxaw7-dev + - qtbase5-dev + - qtmultimedia5-dev + - qtbase5-dev-tools + script: + - cd sys/unix/ && sh setup.sh hints/$HINTS && cd ../../ + - make fetch-lua LUA_VERSION=$LUA_VERSION + - test -d "lib/lua-$LUA_VERSION/src" || exit 0 + - make LUA_VERSION=$LUA_VERSION WANT_WIN_ALL=1 QT_SELECT=5 MOC=moc install + - name: linux-xenial-gcc-nocommon + os: linux + env: HINTS=linux.2020 LUA_VERSION=5.4.2 + dist: xenial + compiler: gcc + script: + - echo "CFLAGS+=-fno-common" >>sys/unix/hints/$HINTS + - cd sys/unix/ && sh setup.sh hints/$HINTS && cd ../../ + - make fetch-lua LUA_VERSION=$LUA_VERSION - test -d "lib/lua-$LUA_VERSION/src" || exit 0 - make install + - name: linux-focal-gcc9-win-all + os: linux + env: HINTS=linux.2020 LUA_VERSION=5.4.2 + dist: focal + compiler: gcc + addons: + apt: + packages: + - gcc-9 + - g++-9 + - libx11-dev + - libxaw7-dev + - xfonts-utils + - qtbase5-dev + - qtmultimedia5-dev + - qtbase5-dev-tools + script: + - cd sys/unix/ && sh setup.sh hints/$HINTS && cd ../../ + - make fetch-lua LUA_VERSION=$LUA_VERSION + - test -d "lib/lua-$LUA_VERSION/src" || exit 0 + - make LUA_VERSION=$LUA_VERSION WANT_WIN_ALL=1 QT_SELECT=5 MOC=moc install - name: linux-xenial-gcc-minimal os: linux - env: HINTS=linux-minimal LUA_VERSION=5.4.0 + env: HINTS=linux-minimal LUA_VERSION=5.4.2 compiler: gcc script: | cd sys/unix/ && sh setup.sh hints/$HINTS && cd ../../ @@ -113,39 +114,43 @@ matrix: sed -i '/^#define SHELL/d' include/unixconf.h sed -i '/^#define SUSPEND/d' include/unixconf.h sed -i 's/^#define TEXTCOLOR//' include/unixconf.h - make fetch-lua + make fetch-lua LUA_VERSION=$LUA_VERSION test -d "lib/lua-$LUA_VERSION/src" || exit 0 - make install + make LUA_VERSION=$LUA_VERSION WANT_WIN_ALL=1 install cat dat/options - name: windows-visualstudio os: windows language: shell script: - - ./win/win32/vs2017/travisci.sh + - ./win/win32/vs/travisci.sh - name: windows-mingw os: windows # install: choco install mingw script: - export ADD_CURSES=Y - export PDCURSES_TOP=../lib/pdcurses - - export LUA_VERSION=5.4.0 + - export LUA_VERSION=5.4.2 - sh sys/winnt/travis-gcc.sh - test -d "lib/lua-$LUA_VERSION/src" || exit 0 - test -d "lib/pdcurses" || exit 0 - cd src - cp ../sys/winnt/Makefile.gcc ./Makefile - - mingw32-make install - - name: msdos-linuxhost-crosscompile + - mingw32-make LUA_VERSION=$LUA_VERSION install + - name: msdos-linux-focal-djgpp-crosscompile os: linux - env: HINTS=linux LUA_VERSION=5.4.0 + env: HINTS=linux.2020 LUA_VERSION=5.4.2 + dist: focal compiler: gcc script: # - export +# - export GCCVER=gcc550 + - export GCCVER=gcc1010 - cd sys/unix/ && sh setup.sh hints/$HINTS && cd ../../ - make fetch-lua - test -d "lib/lua-$LUA_VERSION/src" || exit 0 - - cd lib/lua-$LUA_VERSION/src && make a && cd ../../.. - - sh sys/msdos/msdos-cross-compile.sh + - sh sys/msdos/fetch-cross-compiler.sh + - make LUA_VERSION=$LUA_VERSION WANT_WIN_TTY=1 WANT_WIN_CURSES=1 CROSS_TO_MSDOS=1 all + - make LUA_VERSION=$LUA_VERSION WANT_WIN_TTY=1 WANT_WIN_CURSES=1 CROSS_TO_MSDOS=1 package exclude: # - os: osx # osx_image: xcode10.3 diff --git a/outdated/include/amiconf.h b/outdated/include/amiconf.h index 122854b4a..477c9248a 100644 --- a/outdated/include/amiconf.h +++ b/outdated/include/amiconf.h @@ -14,6 +14,11 @@ #include /* get time_t defined before use! */ +#ifdef CROSS_TO_AMIGA +#include +#include +#endif + #ifdef __SASC_60 /* since SAS can prevent re-inclusion */ #include /* general things, including builtins */ #include @@ -40,6 +45,8 @@ typedef long off_t; LEVELDIR, SAVEDIR, BONESDIR, DATADIR, \ SCOREDIR, LOCKDIR, CONFIGDIR, and TROUBLEDIR */ +#define PATHLEN 130 + /* data librarian defs */ #ifndef NOCWD_ASSUMPTIONS #define DLBFILE "NetHack:nhdat" /* main library */ @@ -49,7 +56,11 @@ typedef long off_t; #define DLBFILE2 "nhsdat" /* sound library */ #endif +#ifndef CROSS_TO_AMIGA #define FILENAME_CMP stricmp /* case insensitive */ +#else +#define FILENAME_CMP strcmpi /* case insensitive */ +#endif #ifndef __SASC_60 #define O_BINARY 0 @@ -65,7 +76,9 @@ typedef long off_t; #define MFLOPPY /* You'll probably want this; provides assistance \ * for typical personal computer configurations \ */ +#ifndef CROSS_TO_AMIGA #define RANDOM +#endif /* ### amidos.c ### */ @@ -123,8 +136,6 @@ extern FILE *FDECL(freopen, (const char *, const char *, FILE *)); extern char *FDECL(gets, (char *)); #endif -#define msmsg printf - /* * If AZTEC_C we can't use the long cpath in vision.c.... */ @@ -138,7 +149,9 @@ extern char *FDECL(gets, (char *)); #define TEXTCOLOR /* Use colored monsters and objects */ #define HACKFONT /* Use special hack.font */ -#define SHELL /* Have a shell escape command (!) */ +#ifndef CROSS_TO_AMIGA /* issues with prototype and spawnl */ +#define SHELL /* Have a shell escape command (!) */ +#endif #define MAIL /* Get mail at unexpected occasions */ #define DEFAULT_ICON "NetHack:default.icon" /* private icon */ #define AMIFLUSH /* toss typeahead (select flush in .cnf) */ @@ -186,5 +199,24 @@ void FDECL(amii_setpens, (int)); #undef M #define M(c) ((c) -128) #endif +struct ami_sysflags { + char sysflagsid[10]; +#ifdef AMIFLUSH + boolean altmeta; /* use ALT keys as META */ + boolean amiflush; /* kill typeahead */ +#endif +#ifdef AMII_GRAPHICS + int numcols; + unsigned short amii_dripens[20]; /* DrawInfo Pens currently there are 13 in v39 */ + AMII_COLOR_TYPE amii_curmap[AMII_MAXCOLORS]; /* colormap */ +#endif +#ifdef OPT_DISPMAP + boolean fast_map; /* use optimized, less flexible map display */ +#endif +#ifdef MFLOPPY + boolean asksavedisk; +#endif +}; +extern struct ami_sysflags sysflags; #endif /* AMICONF_H */ diff --git a/include/mac-carbon.h b/outdated/include/mac-carbon.h similarity index 88% rename from include/mac-carbon.h rename to outdated/include/mac-carbon.h index da53c622a..b773c732f 100644 --- a/include/mac-carbon.h +++ b/outdated/include/mac-carbon.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 mac-carbon.h $NHDT-Date: 1432512777 2015/05/25 00:12:57 $ $NHDT-Branch: master $:$NHDT-Revision: 1.7 $ */ +/* NetHack 3.7 mac-carbon.h $NHDT-Date: 1596498540 2020/08/03 23:49:00 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.9 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 2003. */ /*-Copyright (c) Kevin Hugo, 2003. */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/include/mac-qt.h b/outdated/include/mac-qt.h similarity index 88% rename from include/mac-qt.h rename to outdated/include/mac-qt.h index 96e406b4d..429106c92 100644 --- a/include/mac-qt.h +++ b/outdated/include/mac-qt.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 mac-qt.h $NHDT-Date: 1432512776 2015/05/25 00:12:56 $ $NHDT-Branch: master $:$NHDT-Revision: 1.7 $ */ +/* NetHack 3.7 mac-qt.h $NHDT-Date: 1596498541 2020/08/03 23:49:01 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.9 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 2003. */ /*-Copyright (c) Kevin Hugo, 2003. */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/include/mac-term.h b/outdated/include/mac-term.h similarity index 89% rename from include/mac-term.h rename to outdated/include/mac-term.h index 9f4ba462f..8bef72d0b 100644 --- a/include/mac-term.h +++ b/outdated/include/mac-term.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 mac-term.h $NHDT-Date: 1432512775 2015/05/25 00:12:55 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ +/* NetHack 3.7 mac-term.h $NHDT-Date: 1596498541 2020/08/03 23:49:01 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.10 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 2003. */ /*-Copyright (c) Kevin Hugo, 2003. */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/include/macpopup.h b/outdated/include/macpopup.h similarity index 76% rename from include/macpopup.h rename to outdated/include/macpopup.h index 491592b1f..873af3cc6 100644 --- a/include/macpopup.h +++ b/outdated/include/macpopup.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 macpopup.h $NHDT-Date: 1432512781 2015/05/25 00:13:01 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ */ +/* NetHack 3.7 macpopup.h $NHDT-Date: 1596498542 2020/08/03 23:49:02 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.12 $ */ /* Copyright (c) Nethack Development Team, 1999. */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/include/mactty.h b/outdated/include/mactty.h similarity index 98% rename from include/mactty.h rename to outdated/include/mactty.h index 086aa050f..7f84747bc 100644 --- a/include/mactty.h +++ b/outdated/include/mactty.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 mactty.h $NHDT-Date: 1447755970 2015/11/17 10:26:10 $ $NHDT-Branch: master $:$NHDT-Revision: 1.12 $ */ +/* NetHack 3.7 mactty.h $NHDT-Date: 1596498543 2020/08/03 23:49:03 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.14 $ */ /* Copyright (c) Jon W{tte 1993. */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/include/macwin.h b/outdated/include/macwin.h similarity index 98% rename from include/macwin.h rename to outdated/include/macwin.h index b1ea4a2f1..8dad9ea57 100644 --- a/include/macwin.h +++ b/outdated/include/macwin.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 macwin.h $NHDT-Date: 1447755970 2015/11/17 10:26:10 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ */ +/* NetHack 3.7 macwin.h $NHDT-Date: 1596498543 2020/08/03 23:49:03 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.14 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Kevin Hugo, 2003. */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/include/mttypriv.h b/outdated/include/mttypriv.h similarity index 91% rename from include/mttypriv.h rename to outdated/include/mttypriv.h index e07813709..5fc90abc4 100644 --- a/include/mttypriv.h +++ b/outdated/include/mttypriv.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 mttypriv.h $NHDT-Date: 1432512780 2015/05/25 00:13:00 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ */ +/* NetHack 3.7 mttypriv.h $NHDT-Date: 1596498551 2020/08/03 23:49:11 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.10 $ */ /* Copyright (c) Jon W{tte 1993. */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/include/trampoli.h b/outdated/include/trampoli.h similarity index 98% rename from include/trampoli.h rename to outdated/include/trampoli.h index f6c8cec5a..344dacc93 100644 --- a/include/trampoli.h +++ b/outdated/include/trampoli.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 trampoli.h $NHDT-Date: 1433806581 2015/06/08 23:36:21 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ */ +/* NetHack 3.7 trampoli.h $NHDT-Date: 1596498566 2020/08/03 23:49:26 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.13 $ */ /* Copyright (c) 1989, by Norm Meluch and Stephen Spackman */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/outdated/sys/amiga/Makefile.agc b/outdated/sys/amiga/Makefile.agc index da5b38567..5f36d0049 100644 --- a/outdated/sys/amiga/Makefile.agc +++ b/outdated/sys/amiga/Makefile.agc @@ -184,7 +184,7 @@ MAKEDEFOBJ = \ AMIGAOBJ = \ $(O)amidos.o $(O)amirip.o $(O)amistack.o \ $(O)amiwind.o $(O)winami.o $(O)winchar.o $(O)winfuncs.o \ - $(O)winkey.o $(O)winmenu.o $(O)winreq.o $(O)winstr.o + $(O)winkey.o $(O)winamenu.o $(O)winreq.o $(O)winstr.o # Objects from assembly sources (because DMake can't handle default rules) AMIGAOBJ2 = \ @@ -572,7 +572,7 @@ $(O)winfuncs.o: $(AMI)winfuncs.c $(HDEP) $(AMDEP) $(I)patchlevel.h $(O)winkey.o: $(AMI)winkey.c $(HDEP) $(AMDEP) -$(O)winmenu.o: $(AMI)winmenu.c $(HDEP) $(AMDEP) +$(O)winamenu.o: $(AMI)winamenu.c $(HDEP) $(AMDEP) $(O)winami.o: $(AMI)winami.c $(HDEP) $(AMDEP) #$(AMI)char.c $(AMI)randwin.c @@ -1185,7 +1185,7 @@ $(I)global.h: $(I)coord.h $(I)pcconf.h $(I)amiconf.h $(I)hack.h: $(I)config.h $(I)context.h $(I)trap.h $(I)decl.h $(I)dungeon.h $(I)monsym.h $(I)mkroom.h $(I)objclass.h $(I)flag.h $(I)rm.h $(I)vision.h $(I)display.h $(I)wintype.h $(I)engrave.h - $(I)rect.h $(I)region.h $(I)trampoli.h $(I)sys.h + $(I)rect.h $(I)region.h $(I)sys.h -setdate $(I)hack.h -c:wait 2 @@ -1211,7 +1211,7 @@ $(I)dungeon.h: $(I)align.h -setdate $(I)dungeon.h -c:wait 2 -$(I)engrave.h: $(I)trampoli.h $(I)rect.h +$(I)engrave.h: $(I)rect.h -setdate $(I)engrave.h -c:wait 2 diff --git a/outdated/sys/amiga/Makefile.ami b/outdated/sys/amiga/Makefile.ami index 7d7f676e4..d07a6633b 100644 --- a/outdated/sys/amiga/Makefile.ami +++ b/outdated/sys/amiga/Makefile.ami @@ -391,7 +391,7 @@ MAKEDEFOBJ = \ AMIGAOBJ = \ $(O)amidos.o $(O)amirip.o $(O)amistack.o \ $(O)amiwind.o $(O)winami.o $(O)winchar.o $(O)winfuncs.o \ - $(O)winkey.o $(O)winmenu.o $(O)winreq.o $(O)winstr.o + $(O)winkey.o $(O)winamenu.o $(O)winreq.o $(O)winstr.o # Objects from assembly sources (because DMake can't handle default rules) AMIGAOBJ2 = \ @@ -844,7 +844,7 @@ $(O)winfuncs.o: $(AMI)winfuncs.c $(HDEP) $(AMDEP) $(I)patchlevel.h $(O)winkey.o: $(AMI)winkey.c $(HDEP) $(AMDEP) -$(O)winmenu.o: $(AMI)winmenu.c $(HDEP) $(AMDEP) +$(O)winamenu.o: $(AMI)winamenu.c $(HDEP) $(AMDEP) $(O)winami.o: $(AMI)winami.c $(HDEP) $(AMDEP) #$(AMI)char.c $(AMI)randwin.c @@ -1521,7 +1521,7 @@ $(I)global.h: $(I)coord.h $(I)pcconf.h $(I)amiconf.h $(I)hack.h: $(I)config.h $(I)context.h $(I)trap.h $(I)decl.h $(I)dungeon.h \ $(I)monsym.h $(I)mkroom.h $(I)objclass.h $(I)flag.h $(I)rm.h \ $(I)vision.h $(I)display.h $(I)wintype.h $(I)engrave.h \ - $(I)rect.h $(I)region.h $(I)trampoli.h $(I)sys.h + $(I)rect.h $(I)region.h $(I)sys.h -setdate $(I)hack.h -wait 2 @@ -1547,7 +1547,7 @@ $(I)dungeon.h: $(I)align.h -setdate $(I)dungeon.h -wait 2 -$(I)engrave.h: $(I)trampoli.h $(I)rect.h +$(I)engrave.h: $(I)rect.h -setdate $(I)engrave.h -wait 2 diff --git a/outdated/sys/amiga/amidos.c b/outdated/sys/amiga/amidos.c index 926948946..402e29535 100644 --- a/outdated/sys/amiga/amidos.c +++ b/outdated/sys/amiga/amidos.c @@ -29,12 +29,19 @@ #endif /* Prototypes */ -#include "NH:sys/amiga/winami.p" +#ifndef CROSS_TO_AMIGA #include "NH:sys/amiga/amiwind.p" +#include "NH:sys/amiga/winami.p" #include "NH:sys/amiga/amidos.p" +#else +#include "winami.p" +#include "winami.p" +#include "amidos.p" +#endif extern char Initialized; extern struct window_procs amii_procs; +struct ami_sysflags sysflags = {0}; #ifndef __SASC_60 int Enable_Abort = 0; /* for stdio package */ @@ -272,6 +279,7 @@ const char *from, *to; } #endif +#ifdef MFLOPPY /* this should be replaced */ saveDiskPrompt(start) { @@ -325,6 +333,7 @@ saveDiskPrompt(start) } return 1; } +#endif /* MFLOPPY */ /* Return 1 if the record file was found */ static boolean diff --git a/outdated/sys/amiga/amigst.c b/outdated/sys/amiga/amigst.c index 91f0d3430..8f6a74f64 100644 --- a/outdated/sys/amiga/amigst.c +++ b/outdated/sys/amiga/amigst.c @@ -36,8 +36,14 @@ #include #endif +#ifndef CROSS_TO_AMIGA #include "NH:sys/amiga/winami.p" #include "NH:sys/amiga/amiwind.p" #include "NH:sys/amiga/amidos.p" +#else +#include "winami.p" +#include "amiwind.p" +#include "amidos.p" +#endif /* end amigst.c */ diff --git a/outdated/sys/amiga/amirip.c b/outdated/sys/amiga/amirip.c index eea00e2a0..ba17cbdf0 100644 --- a/outdated/sys/amiga/amirip.c +++ b/outdated/sys/amiga/amirip.c @@ -191,7 +191,7 @@ time_t when; tomb_text(buf); /* Put $ on stone */ - Sprintf(buf, "%ld Au", done_money); + Sprintf(buf, "%ld Au", g.done_money); buf[STONE_LINE_LEN] = 0; /* It could be a *lot* of gold :-) */ tomb_text(buf); diff --git a/outdated/sys/amiga/amiwind.c b/outdated/sys/amiga/amiwind.c index a5c4f7d67..456b727c9 100644 --- a/outdated/sys/amiga/amiwind.c +++ b/outdated/sys/amiga/amiwind.c @@ -3,9 +3,15 @@ /* Copyright (c) Kenneth Lorber, Bethesda, Maryland 1993,1996 */ /* NetHack may be freely redistributed. See license for details. */ +#ifndef CROSS_TO_AMIGA #include "NH:sys/amiga/windefs.h" #include "NH:sys/amiga/winext.h" #include "NH:sys/amiga/winproto.h" +#else +#include "windefs.h" +#include "winext.h" +#include "winproto.h" +#endif /* Have to undef CLOSE as display.h and intuition.h both use it */ #undef CLOSE @@ -20,10 +26,21 @@ static int BufferGetchar(void); static void ProcessMessage(register struct IntuiMessage *message); #define BufferQueueChar(ch) (KbdBuffer[KbdBuffered++] = (ch)) - +#ifndef CROSS_TO_AMIGA struct Library *ConsoleDevice; +#else +struct Device * +# ifdef __CONSTLIBBASEDECL__ + __CONSTLIBBASEDECL__ +# endif /* __CONSTLIBBASEDECL__ */ + ConsoleDevice; +#endif +#ifndef CROSS_TO_AMIGA #include "NH:sys/amiga/amimenu.c" +#else +#include "amimenu.c" +#endif /* Now our own variables */ diff --git a/outdated/sys/amiga/winmenu.c b/outdated/sys/amiga/winamenu.c similarity index 99% rename from outdated/sys/amiga/winmenu.c rename to outdated/sys/amiga/winamenu.c index 085294008..4762bc8a4 100644 --- a/outdated/sys/amiga/winmenu.c +++ b/outdated/sys/amiga/winamenu.c @@ -1,11 +1,17 @@ -/* NetHack 3.6 winmenu.c $NHDT-Date: 1432512796 2015/05/25 00:13:16 $ $NHDT-Branch: master $:$NHDT-Revision: 1.7 $ */ +/* NetHack 3.6 winamenu.c $NHDT-Date: 1432512796 2015/05/25 00:13:16 $ $NHDT-Branch: master $:$NHDT-Revision: 1.7 $ */ /* Copyright (c) Gregg Wonderly, Naperville, Illinois, 1991,1992,1993,1996. */ /* NetHack may be freely redistributed. See license for details. */ +#ifndef CROSS_TO_AMIGA #include "NH:sys/amiga/windefs.h" #include "NH:sys/amiga/winext.h" #include "NH:sys/amiga/winproto.h" +#else +#include "windefs.h" +#include "winext.h" +#include "winproto.h" +#endif /* Start building the text for a menu */ void diff --git a/outdated/sys/amiga/winami.c b/outdated/sys/amiga/winami.c index 5045d1592..3e743fb38 100644 --- a/outdated/sys/amiga/winami.c +++ b/outdated/sys/amiga/winami.c @@ -3,11 +3,22 @@ */ /* NetHack may be freely redistributed. See license for details. */ +#ifndef CROSS_TO_AMIGA #include "NH:sys/amiga/windefs.h" #include "NH:sys/amiga/winext.h" #include "NH:sys/amiga/winproto.h" +#else +#include "windefs.h" +#include "winext.h" +#include "winproto.h" +#endif + #include "dlb.h" +#ifdef CROSS_TO_AMIGA +#define strnicmp strncmpi +#endif + #ifdef AMIGA_INTUITION static int FDECL(put_ext_cmd, (char *, int, struct amii_WinDesc *, int)); @@ -29,8 +40,9 @@ long amii_scrnmode; */ struct window_procs amii_procs = { "amii", WC_COLOR | WC_HILITE_PET | WC_INVERSE, + 0L, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, /* color availability */ - 0L, amii_init_nhwindows, + amii_init_nhwindows, amii_player_selection, amii_askname, amii_get_nh_event, amii_exit_nhwindows, amii_suspend_nhwindows, amii_resume_nhwindows, amii_create_nhwindow, amii_clear_nhwindow, amii_display_nhwindow, @@ -63,8 +75,9 @@ struct window_procs amii_procs = { */ struct window_procs amiv_procs = { "amitile", WC_COLOR | WC_HILITE_PET | WC_INVERSE, + 0L, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, /* color availability */ - 0L, amii_init_nhwindows, + amii_init_nhwindows, amii_player_selection, amii_askname, amii_get_nh_event, amii_exit_nhwindows, amii_suspend_nhwindows, amii_resume_nhwindows, amii_create_nhwindow, amii_clear_nhwindow, amii_display_nhwindow, @@ -1134,7 +1147,7 @@ boolean complain; register int win; register dlb *fp; register char *t; - register char buf[200]; + char buf[200]; if (fn == NULL) panic("NULL file name in display_file()"); diff --git a/outdated/sys/amiga/winchar.c b/outdated/sys/amiga/winchar.c index b7960c01a..9fb0508dc 100644 --- a/outdated/sys/amiga/winchar.c +++ b/outdated/sys/amiga/winchar.c @@ -14,14 +14,24 @@ #ifdef TESTING #include "hack.h" #else +#ifndef CROSS_TO_AMIGA #include "NH:src/tile.c" +#else +#include "../src/tile.c" +#endif #endif +#ifndef CROSS_TO_AMIGA #include "NH:win/share/tile.h" - #include "NH:sys/amiga/windefs.h" #include "NH:sys/amiga/winext.h" #include "NH:sys/amiga/winproto.h" +#else +#include "tile.h" +#include "windefs.h" +#include "winext.h" +#include "winproto.h" +#endif #ifdef OPT_DISPMAP #define DISPMAP /* use display_map() from dispmap.s */ diff --git a/outdated/sys/amiga/winfuncs.c b/outdated/sys/amiga/winfuncs.c index 380954681..dfbae4312 100644 --- a/outdated/sys/amiga/winfuncs.c +++ b/outdated/sys/amiga/winfuncs.c @@ -3,14 +3,29 @@ */ /* NetHack may be freely redistributed. See license for details. */ +#ifndef CROSS_TO_AMIGA #include "NH:sys/amiga/windefs.h" #include "NH:sys/amiga/winext.h" #include "NH:sys/amiga/winproto.h" +#else +#include "windefs.h" +#include "winext.h" +#include "winproto.h" +#endif + #include "patchlevel.h" #include "date.h" extern struct TagItem scrntags[]; - +#ifndef CROSS_TO_AMIGA +extern struct Library *ConsoleDevice; +#else +extern struct Device * +# ifdef __CONSTLIBBASEDECL__ + __CONSTLIBBASEDECL__ +# endif /* __CONSTLIBBASEDECL__ */ + ConsoleDevice; +#endif static BitMapHeader amii_bmhd; static void cursor_common(struct RastPort *, int, int); @@ -776,8 +791,17 @@ amii_create_nhwindow(type) register int type; Abort(AG_OpenDev | AO_ConsoleDev); } - ConsoleDevice = (struct Library *) ConsoleIO.io_Device; - + ConsoleDevice = +#ifndef CROSS_TO_AMIGA + (struct Library *) +#else + (struct Device * +# ifdef __CONSTLIBBASEDECL__ + __CONSTLIBBASEDECL__ +# endif /* __CONSTLIBBASEDECL__ */ + ) +#endif + ConsoleIO.io_Device; KbdBuffered = 0; #ifdef HACKFONT diff --git a/outdated/sys/amiga/winkey.c b/outdated/sys/amiga/winkey.c index c90e06fc8..9534c0c6d 100644 --- a/outdated/sys/amiga/winkey.c +++ b/outdated/sys/amiga/winkey.c @@ -2,9 +2,15 @@ /* Copyright (c) Gregg Wonderly, Naperville, Illinois, 1991,1992,1993. */ /* NetHack may be freely redistributed. See license for details. */ +#ifndef CROSS_TO_AMIGA #include "NH:sys/amiga/windefs.h" #include "NH:sys/amiga/winext.h" #include "NH:sys/amiga/winproto.h" +#else +#include "windefs.h" +#include "winext.h" +#include "winproto.h" +#endif amii_nh_poskey(x, y, mod) int *x, *y, *mod; { diff --git a/outdated/sys/amiga/winproto.h b/outdated/sys/amiga/winproto.h index dffa90f67..5fb1441c7 100644 --- a/outdated/sys/amiga/winproto.h +++ b/outdated/sys/amiga/winproto.h @@ -65,7 +65,7 @@ void Abort(long rc); #endif void CleanUp(void); void flush_glyph_buffer(struct Window *w); -void amiga_print_glyph(winid window, int color_index, int glyph, int bkglyph); +void amiga_print_glyph(winid window, int color_index, int glyph); void start_glyphout(winid window); void amii_end_glyphout(winid window); struct NewWindow *DupNewWindow(struct NewWindow *win); diff --git a/outdated/sys/amiga/winreq.c b/outdated/sys/amiga/winreq.c index 3d59f5960..af4c303de 100644 --- a/outdated/sys/amiga/winreq.c +++ b/outdated/sys/amiga/winreq.c @@ -2,9 +2,15 @@ /* Copyright (c) Gregg Wonderly, Naperville, Illinois, 1991,1992,1993. */ /* NetHack may be freely redistributed. See license for details. */ +#ifndef CROSS_TO_AMIGA #include "NH:sys/amiga/windefs.h" #include "NH:sys/amiga/winext.h" #include "NH:sys/amiga/winproto.h" +#else +#include "windefs.h" +#include "winext.h" +#include "winproto.h" +#endif #define GADBLUEPEN 2 #define GADREDPEN 3 @@ -39,7 +45,11 @@ struct NewWindow StrWindow = { &String, NULL, NULL, NULL, NULL, 5, 5, 0xffff, 0xffff, CUSTOMSCREEN }; +#ifndef CROSS_TO_AMIGA #include "NH:sys/amiga/colorwin.c" +#else +#include "colorwin.c" +#endif #define XSIZE 2 #define YSIZE 3 @@ -48,7 +58,11 @@ struct NewWindow StrWindow = { #define GADOKAY 6 #define GADCANCEL 7 +#ifndef CROSS_TO_AMIGA #include "NH:sys/amiga/clipwin.c" +#else +#include "clipwin.c" +#endif void ClearCol(struct Window *w); diff --git a/outdated/sys/amiga/winstr.c b/outdated/sys/amiga/winstr.c index 75d1d2509..cbca9ba4b 100644 --- a/outdated/sys/amiga/winstr.c +++ b/outdated/sys/amiga/winstr.c @@ -2,10 +2,15 @@ /* Copyright (c) Gregg Wonderly, Naperville, Illinois, 1991,1992,1993. */ /* NetHack may be freely redistributed. See license for details. */ +#ifndef CROSS_TO_AMIGA #include "NH:sys/amiga/windefs.h" #include "NH:sys/amiga/winext.h" #include "NH:sys/amiga/winproto.h" - +#else +#include "windefs.h" +#include "winext.h" +#include "winproto.h" +#endif /* Put a string into the indicated window using the indicated attribute */ void @@ -76,8 +81,8 @@ const char *str; while (isspace(*str)) str++; - strncpy(toplines, str, TBUFSZ); - toplines[TBUFSZ - 1] = 0; + strncpy(g.toplines, str, TBUFSZ); + g.toplines[TBUFSZ - 1] = 0; /* For initial message to be visible, we need to explicitly position * the @@ -96,15 +101,15 @@ const char *str; memcpy(cw->data, &cw->data[1], (iflags.msg_history - 1) * sizeof(char *)); cw->data[iflags.msg_history - 1] = - (char *) alloc(strlen(toplines) + 5); + (char *) alloc(strlen(g.toplines) + 5); strcpy(cw->data[i = iflags.msg_history - 1] + SOFF + (scrollmsg != 0), - toplines); + g.toplines); } else { /* Otherwise, allocate a new one and copy the line in */ - cw->data[cw->maxrow] = (char *) alloc(strlen(toplines) + 5); + cw->data[cw->maxrow] = (char *) alloc(strlen(g.toplines) + 5); strcpy(cw->data[i = cw->maxrow++] + SOFF + (scrollmsg != 0), - toplines); + g.toplines); } cw->data[i][SEL_ITEM] = 1; cw->data[i][VATTR] = attr + 1; @@ -177,7 +182,7 @@ const char *str; / w->RPort->TxHeight, totalvis, totalvis); } - i = strlen(toplines + SOFF); + i = strlen(g.toplines + SOFF); cw->maxcol = max(cw->maxcol, i); cw->vwy = cw->maxrow; break; diff --git a/sys/unix/README.linux b/outdated/sys/unix/README.linux similarity index 100% rename from sys/unix/README.linux rename to outdated/sys/unix/README.linux diff --git a/outdated/sys/wince/bootstrp.mak b/outdated/sys/wince/bootstrp.mak index 35cb62595..3d2414cb1 100644 --- a/outdated/sys/wince/bootstrp.mak +++ b/outdated/sys/wince/bootstrp.mak @@ -200,7 +200,7 @@ HACK_H = $(INCL)\hack.h $(CONFIG_H) $(INCL)\align.h \ $(INCL)\trap.h $(INCL)\flag.h $(INCL)\rm.h \ $(INCL)\vision.h $(INCL)\display.h $(INCL)\engrave.h \ $(INCL)\rect.h $(INCL)\region.h $(INCL)\winprocs.h \ - $(INCL)\wintty.h $(INCL)\trampoli.h + $(INCL)\wintty.h DGN_FILE_H = $(INCL)\dgn_file.h LEV_COMP_H = $(INCL)\lev_comp.h diff --git a/outdated/sys/wince/mhmsgwnd.c b/outdated/sys/wince/mhmsgwnd.c index 1c8976564..a73eec3e9 100644 --- a/outdated/sys/wince/mhmsgwnd.c +++ b/outdated/sys/wince/mhmsgwnd.c @@ -609,7 +609,7 @@ mswin_message_window_size(HWND hWnd, LPSIZE sz) data = (PNHMessageWindow) GetWindowLong(hWnd, GWL_USERDATA); if (data) { - /* set size to accomodate MSG_VISIBLE_LINES, highligh rectangle and + /* set size to accommodate MSG_VISIBLE_LINES, highligh rectangle and horizontal scroll bar (difference between window rect and client rect */ GetClientRect(hWnd, &client_rt); diff --git a/outdated/win/Qt3/qt3_win.cpp b/outdated/win/Qt3/qt3_win.cpp index f48c0d211..30b23370b 100644 --- a/outdated/win/Qt3/qt3_win.cpp +++ b/outdated/win/Qt3/qt3_win.cpp @@ -1,4 +1,4 @@ -// NetHack 3.6 qt_win.cpp $NHDT-Date: 1575917720 2019/12/09 18:55:20 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.0 $ +// NetHack 3.6 qt_win.cpp $NHDT-Date: 1596404695 2020/08/02 21:44:55 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.91 $ // Copyright (c) Warwick Allison, 1999. // NetHack may be freely redistributed. See license for details. @@ -146,23 +146,44 @@ static const char nh_attribution[] = "
NetHack" static QString aboutMsg() { + char vbuf[BUFSZ]; QString msg; msg.sprintf( - "Qt NetHack is a version of NetHack built\n" + // format + "Qt NetHack is a version of NetHack\n" + "built using" // no newline #ifdef KDE - "using KDE and the Qt GUI toolkit.\n" + " KDE and" // ditto +#endif + " the Qt %d GUI toolkit.\n" + "\nThis is NetHack %s%s.\n" + "\nNetHack's Qt interface originally developed by Warwick Allison.\n" + "\n" +#if 0 + "Homepage:\n http://trolls.troll.no/warwick/nethack/\n" //obsolete +#endif +#ifdef KDE + "KDE:\n https://kde.org/\n" +#endif +#if 1 + "Qt:\n https://qt.io/\n" #else - "using the Qt GUI toolkit.\n" + "Qt:\n http://www.troll.no/\n" // obsolete #endif - "This is version %d.%d.%d\n\n" - "Homepage:\n http://trolls.troll.no/warwick/nethack/\n\n" -#ifdef KDE - "KDE:\n http://www.kde.org\n" + "NetHack:\n %s\n", + // arguments +#ifdef QT_VERSION_MAJOR + QT_VERSION_MAJOR, +#else + 3, // Qt version macro should exist; if not, assume Qt3 #endif - "Qt:\n http://www.troll.no", - VERSION_MAJOR, - VERSION_MINOR, - PATCHLEVEL); + version_string(vbuf), /* nethack version */ +#ifdef QT_VERSION_STR + " with Qt " QT_VERSION_STR, +#else + "", +#endif + DEVTEAM_URL); return msg; } diff --git a/src/allmain.c b/src/allmain.c index 2d22937a8..6cdf9bd4d 100644 --- a/src/allmain.c +++ b/src/allmain.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 allmain.c $NHDT-Date: 1593953342 2020/07/05 12:49:02 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.144 $ */ +/* NetHack 3.7 allmain.c $NHDT-Date: 1596498146 2020/08/03 23:42:26 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.145 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -215,17 +215,7 @@ boolean resuming; if (wtcap > MOD_ENCUMBER && u.umoved) { if (!(wtcap < EXT_ENCUMBER ? g.moves % 30 : g.moves % 10)) { - if (Upolyd && u.mh > 1) { - u.mh--; - g.context.botl = TRUE; - } else if (!Upolyd && u.uhp > 1) { - u.uhp--; - g.context.botl = TRUE; - } else { - You("pass out from exertion!"); - exercise(A_CON, FALSE); - fall_asleep(-10, FALSE); - } + overexert_hp(); } } @@ -471,6 +461,8 @@ boolean resuming; } } +#define U_CAN_REGEN() (Regeneration || (Sleepy && u.usleep)) + /* maybe recover some lost health (or lose some when an eel out of water) */ static void regen_hp(wtcap) @@ -491,7 +483,7 @@ int wtcap; && (!Half_physical_damage || !(g.moves % 2L))) heal = -1; } else if (u.mh < u.mhmax) { - if (Regeneration || (encumbrance_ok && !(g.moves % 20L))) + if (U_CAN_REGEN() || (encumbrance_ok && !(g.moves % 20L))) heal = 1; } if (heal) { @@ -506,7 +498,7 @@ int wtcap; no !Upolyd check here, so poly'd hero recovered lost u.uhp once u.mh reached u.mhmax; that may have been convenient for the player, but it didn't make sense for gameplay...] */ - if (u.uhp < u.uhpmax && (encumbrance_ok || Regeneration)) { + if (u.uhp < u.uhpmax && (encumbrance_ok || U_CAN_REGEN())) { if (u.ulevel > 9) { if (!(g.moves % 3L)) { int Con = (int) ACURR(A_CON); @@ -523,8 +515,10 @@ int wtcap; if (!(g.moves % (long) ((MAXULEV + 12) / (u.ulevel + 2) + 1))) heal = 1; } - if (Regeneration && !heal) + if (U_CAN_REGEN() && !heal) heal = 1; + if (Sleepy && u.usleep) + heal++; if (heal) { g.context.botl = TRUE; @@ -541,6 +535,8 @@ int wtcap; interrupt_multi("You are in full health."); } +#undef U_CAN_REGEN + void stop_occupation() { @@ -706,43 +702,21 @@ do_positionbar() { static char pbar[COLNO]; char *p; + stairway *stway = g.stairs; p = pbar; - /* up stairway */ - if (g.upstair.sx - && (glyph_to_cmap(g.level.locations[g.upstair.sx][g.upstair.sy].glyph) - == S_upstair - || glyph_to_cmap(g.level.locations[g.upstair.sx][g.upstair.sy].glyph) - == S_upladder)) { - *p++ = '<'; - *p++ = g.upstair.sx; - } - if (g.sstairs.sx - && (glyph_to_cmap(g.level.locations[g.sstairs.sx][g.sstairs.sy].glyph) - == S_upstair - || glyph_to_cmap(g.level.locations[g.sstairs.sx][g.sstairs.sy].glyph) - == S_upladder)) { - *p++ = '<'; - *p++ = g.sstairs.sx; - } + /* TODO: use the same method as getpos() so objects don't cover stairs */ + while (stway) { + int x = stway->sx; + int y = stway->sy; + int glyph = glyph_to_cmap(g.level.locations[x][y].glyph); - /* down stairway */ - if (g.dnstair.sx - && (glyph_to_cmap(g.level.locations[g.dnstair.sx][g.dnstair.sy].glyph) - == S_dnstair - || glyph_to_cmap(g.level.locations[g.dnstair.sx][g.dnstair.sy].glyph) - == S_dnladder)) { - *p++ = '>'; - *p++ = g.dnstair.sx; - } - if (g.sstairs.sx - && (glyph_to_cmap(g.level.locations[g.sstairs.sx][g.sstairs.sy].glyph) - == S_dnstair - || glyph_to_cmap(g.level.locations[g.sstairs.sx][g.sstairs.sy].glyph) - == S_dnladder)) { - *p++ = '>'; - *p++ = g.sstairs.sx; - } + if (is_cmap_stairs(glyph)) { + *p++ = (stway->up ? '<' : '>'); + *p++ = stway->sx; + } + stway = stway->next; + } /* hero location */ if (u.ux) { diff --git a/src/alloc.c b/src/alloc.c index c6944aba4..a1792e1f9 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 alloc.c $NHDT-Date: 1454376505 2016/02/02 01:28:25 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.16 $ */ +/* NetHack 3.7 alloc.c $NHDT-Date: 1596498147 2020/08/03 23:42:27 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.18 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/src/apply.c b/src/apply.c index c1e31010e..737836f15 100644 --- a/src/apply.c +++ b/src/apply.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 apply.c $NHDT-Date: 1593614972 2020/07/01 14:49:32 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.325 $ */ +/* NetHack 3.7 apply.c $NHDT-Date: 1605184220 2020/11/12 12:30:20 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.331 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -272,7 +272,7 @@ int rx, ry, *resp; humanoid(mptr) ? "person" : "creature"); what = buf; } else { - what = mptr->mname; + what = pmname(mptr, NEUTRAL); if (!type_is_pname(mptr)) what = The(what); } @@ -408,7 +408,7 @@ register struct obj *obj; || odummy->otyp == LENSES); break; case M_AP_MONSTER: /* ignore Hallucination here */ - what = mons[mtmp->mappearance].mname; + what = pmname(&mons[mtmp->mappearance], Mgender(mtmp)); break; case M_AP_FURNITURE: what = defsyms[mtmp->mappearance].explanation; @@ -548,20 +548,23 @@ number_leashed() /* otmp is about to be destroyed or stolen */ void o_unleash(otmp) -register struct obj *otmp; +struct obj *otmp; { register struct monst *mtmp; for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) - if (mtmp->m_id == (unsigned) otmp->leashmon) + if (mtmp->m_id == (unsigned) otmp->leashmon) { mtmp->mleashed = 0; - otmp->leashmon = 0; + otmp->leashmon = 0; + update_inventory(); + break; + } } /* mtmp is about to die, or become untame */ void m_unleash(mtmp, feedback) -register struct monst *mtmp; +struct monst *mtmp; boolean feedback; { register struct obj *otmp; @@ -573,8 +576,11 @@ boolean feedback; Your("leash falls slack."); } for (otmp = g.invent; otmp; otmp = otmp->nobj) - if (otmp->otyp == LEASH && otmp->leashmon == (int) mtmp->m_id) + if (otmp->otyp == LEASH && (unsigned) otmp->leashmon == mtmp->m_id) { otmp->leashmon = 0; + update_inventory(); + break; + } mtmp->mleashed = 0; } @@ -686,6 +692,7 @@ struct obj *obj; mtmp->mleashed = 1; obj->leashmon = (int) mtmp->m_id; mtmp->msleeping = 0; + update_inventory(); } } else { /* applying a leash which is currently in use */ @@ -697,6 +704,7 @@ struct obj *obj; } else { mtmp->mleashed = 0; obj->leashmon = 0; + update_inventory(); You("remove the leash from %s%s.", spotmon ? "your " : "", l_monnam(mtmp)); } @@ -711,13 +719,10 @@ struct monst *mtmp; { struct obj *otmp; - otmp = g.invent; - while (otmp) { - if (otmp->otyp == LEASH && otmp->leashmon == (int) mtmp->m_id) - return otmp; - otmp = otmp->nobj; - } - return (struct obj *) 0; + for (otmp = g.invent; otmp; otmp = otmp->nobj) + if (otmp->otyp == LEASH && (unsigned) otmp->leashmon == mtmp->m_id) + break; + return otmp; } boolean @@ -735,13 +740,14 @@ next_to_u() if (distu(mtmp->mx, mtmp->my) > 2) { for (otmp = g.invent; otmp; otmp = otmp->nobj) if (otmp->otyp == LEASH - && otmp->leashmon == (int) mtmp->m_id) { + && (unsigned) otmp->leashmon == mtmp->m_id) { if (otmp->cursed) return FALSE; - You_feel("%s leash go slack.", - (number_leashed() > 1) ? "a" : "the"); mtmp->mleashed = 0; otmp->leashmon = 0; + update_inventory(); + You_feel("%s leash go slack.", + (number_leashed() > 1) ? "a" : "the"); } } } @@ -898,7 +904,7 @@ struct obj *obj; } else if (u.uhs >= WEAK) { You(look_str, "undernourished"); } else if (Upolyd) { - You("look like %s.", an(mons[u.umonnum].mname)); + You("look like %s.", an(pmname(&mons[u.umonnum], Ugender))); } else { You("look as %s as ever.", uvisage); } @@ -979,8 +985,8 @@ struct obj *obj; if (vis) pline("%s confuses itself!", Monnam(mtmp)); mtmp->mconf = 1; - } else if (monable && (mlet == S_NYMPH || mtmp->data == &mons[PM_SUCCUBUS] - || mtmp->data == &mons[PM_INCUBUS])) { + } else if (monable && + (mlet == S_NYMPH || mtmp->data == &mons[PM_AMOROUS_DEMON])) { if (vis) { char buf[BUFSZ]; /* "She" or "He" */ @@ -1340,15 +1346,72 @@ struct obj *obj; return FALSE; } +/* called when lit object is hit by water */ +boolean +splash_lit(obj) +struct obj *obj; +{ + boolean result, dunk = FALSE; + + /* lantern won't be extinguished by a rust trap or rust monster attack + but will be if submerged or placed into a container or swallowed by + a monster (for mobile light source handling, not because it ought + to stop being lit in all those situations...) */ + if (obj->lamplit && obj->otyp == BRASS_LANTERN) { + struct monst *mtmp; + boolean useeit = FALSE, uhearit = FALSE, snuff = TRUE; + + if (obj->where == OBJ_INVENT) { + useeit = !Blind; + uhearit = !Deaf; + /* underwater light sources aren't allowed but if hero + is just entering water, Underwater won't be set yet */ + dunk = (is_pool(u.ux, u.uy) + && ((!Levitation && !Flying && !Wwalking) + || Is_waterlevel(&u.uz))); + snuff = FALSE; + } else if (obj->where == OBJ_MINVENT + /* don't assume that lit lantern has been swallowed; + a nymph might have stolen it or picked it up */ + && ((mtmp = obj->ocarry), humanoid(mtmp->data))) { + xchar x, y; + + useeit = get_obj_location(obj, &x, &y, 0) && cansee(x, y); + uhearit = couldsee(x, y) && distu(x, y) < 5 * 5; + dunk = (is_pool(mtmp->mx, mtmp->my) + && ((!is_flyer(mtmp->data) && !is_floater(mtmp->data)) + || Is_waterlevel(&u.uz))); + snuff = FALSE; + } + + if (useeit || uhearit) + pline("%s %s%s%s.", Yname2(obj), + uhearit ? "crackles" : "", + (uhearit && useeit) ? " and " : "", + useeit ? "flickers" : ""); + if (!dunk && !snuff) + return FALSE; + } + + result = snuff_lit(obj); + + /* this is simpler when we wait until after lantern has been snuffed */ + if (dunk) { + /* drain some of the battery but don't short it out entirely */ + obj->age -= (obj->age > 200L) ? 100L : (obj->age / 2L); + } + return result; +} + /* Called when potentially lightable object is affected by fire_damage(). - Return TRUE if object was lit and FALSE otherwise --ALI */ + Return TRUE if object becomes lit and FALSE otherwise --ALI */ boolean catch_lit(obj) struct obj *obj; { xchar x, y; - if (!obj->lamplit && (obj->otyp == MAGIC_LAMP || ignitable(obj))) { + if (!obj->lamplit && ignitable(obj)) { if ((obj->otyp == MAGIC_LAMP || obj->otyp == CANDELABRUM_OF_INVOCATION) && obj->spe == 0) return FALSE; @@ -1888,12 +1951,12 @@ struct obj *obj; if (poly_when_stoned(g.youmonst.data)) You("tin %s without wearing gloves.", - an(mons[corpse->corpsenm].mname)); + an(mons[corpse->corpsenm].pmnames[NEUTRAL])); else { pline("Tinning %s without wearing gloves is a fatal mistake...", - an(mons[corpse->corpsenm].mname)); + an(mons[corpse->corpsenm].pmnames[NEUTRAL])); Sprintf(kbuf, "trying to tin %s without gloves", - an(mons[corpse->corpsenm].mname)); + an(mons[corpse->corpsenm].pmnames[NEUTRAL])); } instapetrify(kbuf); } @@ -2493,10 +2556,10 @@ struct obj *otmp; what = "in water"; else if (is_lava(u.ux, u.uy)) what = "in lava"; - else if (On_stairs(u.ux, u.uy)) - what = (u.ux == xdnladder || u.ux == xupladder) ? "on the ladder" - : "on the stairs"; - else if (IS_FURNITURE(levtyp) || IS_ROCK(levtyp) + 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) || closed_door(u.ux, u.uy) || t_at(u.ux, u.uy)) what = "here"; else if (Is_airlevel(&u.uz) || Is_waterlevel(&u.uz)) @@ -2832,7 +2895,7 @@ struct obj *obj; char kbuf[BUFSZ]; Sprintf(kbuf, "%s corpse", - an(mons[otmp->corpsenm].mname)); + an(mons[otmp->corpsenm].pmnames[NEUTRAL])); pline("Snatching %s is a fatal mistake.", kbuf); instapetrify(kbuf); } @@ -2882,6 +2945,9 @@ static const char cant_see_spot[] = "won't hit anything if you can't see that spot.", cant_reach[] = "can't reach that spot from here."; +#define glyph_is_poleable(G) \ + (glyph_is_monster(G) || glyph_is_invisible(G) || glyph_is_statue(G)) + /* find pos of monster in range, if only one monster */ static boolean find_poleable_mon(pos, min_range, max_range) @@ -2893,8 +2959,6 @@ int min_range, max_range; boolean impaired; int x, y, lo_x, hi_x, lo_y, hi_y, rt, glyph; - if (Blind) - return FALSE; /* must be able to see target location */ impaired = (Confusion || Stunned || Hallucination); mpos.x = mpos.y = 0; /* no candidate location yet */ rt = isqrt(max_range); @@ -2911,10 +2975,8 @@ int min_range, max_range; && (mtmp = m_at(x, y)) != 0 && (mtmp->mtame || (mtmp->mpeaceful && flags.confirm))) continue; - if (glyph_is_monster(glyph) - || glyph_is_warning(glyph) - || glyph_is_invisible(glyph) - || (glyph_is_statue(glyph) && impaired)) { + if (glyph_is_poleable(glyph) + && (!glyph_is_statue(glyph) || impaired)) { if (mpos.x) return FALSE; /* more than one candidate location */ mpos.x = x, mpos.y = y; @@ -2931,9 +2993,14 @@ static boolean get_valid_polearm_position(x, y) int x, y; { - return (isok(x, y) && ACCESSIBLE(levl[x][y].typ) - && distu(x, y) >= g.polearm_range_min - && distu(x, y) <= g.polearm_range_max); + int glyph; + + glyph = glyph_at(x, y); + + return (isok(x, y) && distu(x, y) >= g.polearm_range_min + && distu(x, y) <= g.polearm_range_max + && (cansee(x, y) || (couldsee(x, y) + && glyph_is_poleable(glyph)))); } static void @@ -3013,7 +3080,7 @@ struct obj *obj; cc.x = u.ux; cc.y = u.uy; if (!find_poleable_mon(&cc, min_range, max_range) && hitm - && !DEADMONSTER(hitm) && cansee(hitm->mx, hitm->my) + && !DEADMONSTER(hitm) && sensemon(hitm) && distu(hitm->mx, hitm->my) <= max_range && distu(hitm->mx, hitm->my) >= min_range) { cc.x = hitm->mx; @@ -3030,8 +3097,7 @@ struct obj *obj; } else if (distu(cc.x, cc.y) < min_range) { pline("Too close!"); return res; - } else if (!cansee(cc.x, cc.y) && !glyph_is_monster(glyph) - && !glyph_is_invisible(glyph) && !glyph_is_statue(glyph)) { + } else if (!cansee(cc.x, cc.y) && !glyph_is_poleable(glyph)) { You(cant_see_spot); return res; } else if (!couldsee(cc.x, cc.y)) { /* Eyes of the Overworld */ @@ -3343,21 +3409,24 @@ struct obj *obj; boolean fillmsg = FALSE; int expltype = EXPL_MAGICAL; char confirm[QBUFSZ], buf[BUFSZ]; - boolean is_fragile = (!strcmp(OBJ_DESCR(objects[obj->otyp]), "balsa")); - - if (!paranoid_query(ParanoidBreakwand, - safe_qbuf(confirm, - "Are you really sure you want to break ", - "?", obj, yname, ysimple_name, "the wand"))) - return 0; + boolean is_fragile = (objdescr_is(obj, "balsa") + || objdescr_is(obj, "glass")); if (nohands(g.youmonst.data)) { You_cant("break %s without hands!", yname(obj)); return 0; + } else if (!freehand()) { + Your("%s are occupied!", makeplural(body_part(HAND))); + return 0; } else if (ACURR(A_STR) < (is_fragile ? 5 : 10)) { You("don't have the strength to break %s!", yname(obj)); return 0; } + if (!paranoid_query(ParanoidBreakwand, + safe_qbuf(confirm, + "Are you really sure you want to break ", + "?", obj, yname, ysimple_name, "the wand"))) + return 0; pline("Raising %s high above your %s, you %s it in two!", yname(obj), body_part(HEAD), is_fragile ? "snap" : "break"); diff --git a/src/artifact.c b/src/artifact.c index bb808e8c6..7bb0fc7d0 100644 --- a/src/artifact.c +++ b/src/artifact.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 artifact.c $NHDT-Date: 1593611274 2020/07/01 13:47:54 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.158 $ */ +/* NetHack 3.7 artifact.c $NHDT-Date: 1606765210 2020/11/30 19:40:10 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.161 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2013. */ /* NetHack may be freely redistributed. See license for details. */ @@ -534,7 +534,8 @@ long wp_mask; * that can print a message--need to guard against being printed * when restoring a game */ - (void) make_hallucinated((long) !on, g.restoring ? FALSE : TRUE, + (void) make_hallucinated((long) !on, + g.program_state.restoring ? FALSE : TRUE, wp_mask); } if (spfx & SPFX_ESP) { @@ -1192,6 +1193,8 @@ int dieroll; /* needed for Magicbane and vorpal blades */ (void) destroy_mitem(mdef, SCROLL_CLASS, AD_FIRE); if (!rn2(7)) (void) destroy_mitem(mdef, SPBOOK_CLASS, AD_FIRE); + if (!rn2(4)) + ignite_items(mdef->minvent); if (youdefend && Slimed) burn_away_slime(); return realizes_damage; diff --git a/src/attrib.c b/src/attrib.c index eb069a1f0..759296702 100644 --- a/src/attrib.c +++ b/src/attrib.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 attrib.c $NHDT-Date: 1579655026 2020/01/22 01:03:46 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.74 $ */ +/* NetHack 3.7 attrib.c $NHDT-Date: 1596498149 2020/08/03 23:42:29 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.75 $ */ /* Copyright 1988, 1989, 1990, 1992, M. Stephenson */ /* NetHack may be freely redistributed. See license for details. */ @@ -298,7 +298,7 @@ boolean thrown_weapon; /* thrown weapons are less deadly */ } /* suppress killer prefix if it already has one */ - i = name_to_mon(pkiller); + i = name_to_mon(pkiller, (int *) 0); if (i >= LOW_PM && (mons[i].geno & G_UNIQ)) { kprefix = KILLED_BY; if (!type_is_pname(&mons[i])) @@ -709,11 +709,11 @@ int r; } roleabils[] = { { PM_ARCHEOLOGIST, arc_abil }, { PM_BARBARIAN, bar_abil }, - { PM_CAVEMAN, cav_abil }, + { PM_CAVE_DWELLER, cav_abil }, { PM_HEALER, hea_abil }, { PM_KNIGHT, kni_abil }, { PM_MONK, mon_abil }, - { PM_PRIEST, pri_abil }, + { PM_CLERIC, pri_abil }, { PM_RANGER, ran_abil }, { PM_ROGUE, rog_abil }, { PM_SAMURAI, sam_abil }, @@ -1054,8 +1054,8 @@ int x; #endif } else if (x == A_CHA) { if (tmp < 18 - && (g.youmonst.data->mlet == S_NYMPH || u.umonnum == PM_SUCCUBUS - || u.umonnum == PM_INCUBUS)) + && (g.youmonst.data->mlet == S_NYMPH + || u.umonnum == PM_AMOROUS_DEMON)) return (schar) 18; } else if (x == A_CON) { if (uwep && uwep->oartifact == ART_OGRESMASHER) diff --git a/src/ball.c b/src/ball.c index 9005f3900..6eeafe6fa 100644 --- a/src/ball.c +++ b/src/ball.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 ball.c $NHDT-Date: 1573940835 2019/11/16 21:47:15 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.44 $ */ +/* NetHack 3.7 ball.c $NHDT-Date: 1596498150 2020/08/03 23:42:30 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.51 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) David Cohrs, 2006. */ /* NetHack may be freely redistributed. See license for details. */ @@ -162,12 +162,13 @@ unplacebc_core() obj_extract_self(uball); if (Blind && (u.bc_felt & BC_BALL)) /* drop glyph */ levl[uball->ox][uball->oy].glyph = u.bglyph; - + maybe_unhide_at(uball->ox, uball->oy); newsym(uball->ox, uball->oy); } obj_extract_self(uchain); if (Blind && (u.bc_felt & BC_CHAIN)) /* drop glyph */ levl[uchain->ox][uchain->oy].glyph = u.cglyph; + maybe_unhide_at(uchain->ox, uchain->oy); newsym(uchain->ox, uchain->oy); u.bc_felt = 0; /* feel nothing */ @@ -536,9 +537,11 @@ xchar ballx, bally, chainx, chainy; /* only matter !before */ } remove_object(uchain); + maybe_unhide_at(uchain->ox, uchain->oy); newsym(uchain->ox, uchain->oy); if (!carried(uball)) { remove_object(uball); + maybe_unhide_at(uball->ox, uball->oy); newsym(uball->ox, uball->oy); } } else { diff --git a/src/bones.c b/src/bones.c index c8ba12a14..e0b81ed3d 100644 --- a/src/bones.c +++ b/src/bones.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 bones.c $NHDT-Date: 1593953344 2020/07/05 12:49:04 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.100 $ */ +/* NetHack 3.7 bones.c $NHDT-Date: 1596498151 2020/08/03 23:42:31 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.103 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985,1993. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -531,8 +531,10 @@ struct obj *corpse; store_version(nhfp); store_savefileinfo(nhfp); 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.nnn */ + bwrite(nhfp->fd, (genericptr_t) bonesid, (unsigned) c); /* DD.nn */ savefruitchn(nhfp); } update_mlstmv(); /* update monsters for eventual restoration */ @@ -585,22 +587,18 @@ getbones() } } if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &c, sizeof c); /* length incl. '\0' */ - mread(nhfp->fd, (genericptr_t) oldbonesid, (unsigned) c); /* DD.nnn */ + /* 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' */ + mread(nhfp->fd, (genericptr_t) oldbonesid, + (unsigned) c); /* DD.nn or Qrrr.n for role rrr */ } - if (strcmp(bonesid, oldbonesid) != 0 - /* from 3.3.0 through 3.6.0, bones in the quest branch stored - a bogus bonesid in the file; 3.6.1 fixed that, but for - 3.6.0 bones to remain compatible, we need an extra test; - once compatibility with 3.6.x goes away, this can too - (we don't try to make this conditional upon the value of - VERSION_COMPATIBILITY) */ - && (strlen(bonesid) <= 2 - || strcmp(bonesid + 2, oldbonesid) != 0)) { + if (strcmp(bonesid, oldbonesid) != 0) { char errbuf[BUFSZ]; - Sprintf(errbuf, "This is bones level '%s', not '%s'!", oldbonesid, - bonesid); + Sprintf(errbuf, "This is bones level '%s', not '%s'!", + oldbonesid, bonesid); if (wizard) { pline1(errbuf); ok = FALSE; /* won't die of trickery */ @@ -619,12 +617,12 @@ getbones() * set to the magic DEFUNCT_MONSTER cookie value. */ for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { - if (has_mname(mtmp)) - sanitize_name(MNAME(mtmp)); + if (has_mgivenname(mtmp)) + sanitize_name(MGIVENNAME(mtmp)); if (mtmp->mhpmax == DEFUNCT_MONSTER) { if (wizard) { debugpline1("Removing defunct monster %s from bones.", - mtmp->data->mname); + mtmp->data->pmnames[NEUTRAL]); } mongone(mtmp); } else diff --git a/src/botl.c b/src/botl.c index 2dfaa11b9..ab225740c 100644 --- a/src/botl.c +++ b/src/botl.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 botl.c $NHDT-Date: 1585647484 2020/03/31 09:38:04 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.187 $ */ +/* NetHack 3.7 botl.c $NHDT-Date: 1606765211 2020/11/30 19:40:11 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.193 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2006. */ /* NetHack may be freely redistributed. See license for details. */ @@ -67,7 +67,7 @@ do_statusline1() char mbot[BUFSZ]; int k = 0; - Strcpy(mbot, mons[u.umonnum].mname); + Strcpy(mbot, pmname(&mons[u.umonnum], Ugender)); while (mbot[k] != 0) { if ((k == 0 || (k > 0 && mbot[k - 1] == ' ')) && 'a' <= mbot[k] && mbot[k] <= 'z') @@ -238,7 +238,8 @@ void bot() { /* dosave() flags completion by setting u.uhp to -1 */ - if ((u.uhp != -1) && g.youmonst.data && iflags.status_updates) { + if (u.uhp != -1 && g.youmonst.data && iflags.status_updates + && !g.program_state.saving && !g.program_state.restoring) { if (VIA_WINDOWPORT()) { bot_via_windowport(); } else { @@ -254,7 +255,8 @@ bot() void timebot() { - if (flags.time && iflags.status_updates) { + if (flags.time && iflags.status_updates + && !g.program_state.saving && !g.program_state.restoring) { if (VIA_WINDOWPORT()) { stat_update_time(); } else { @@ -398,7 +400,8 @@ botl_score() long deepest = deepest_lev_reached(FALSE); long utotal; - utotal = money_cnt(g.invent) + hidden_gold(); + /* hidden_gold(False): only gold in containers whose contents are known */ + utotal = money_cnt(g.invent) + hidden_gold(FALSE); if ((utotal -= u.umoney0) < 0L) utotal = 0L; utotal += u.urexp + (50 * (deepest - 1)) @@ -716,7 +719,7 @@ bot_via_windowport() */ Strcpy(nb = buf, g.plname); nb[0] = highc(nb[0]); - titl = !Upolyd ? rank() : mons[u.umonnum].mname; + titl = !Upolyd ? rank() : pmname(&mons[u.umonnum], Ugender); i = (int) (strlen(buf) + sizeof " the " + strlen(titl) - sizeof ""); /* if "Name the Rank/monster" is too long, we truncate the name but always keep at least 10 characters of it; when hitpintbar is diff --git a/src/cmd.c b/src/cmd.c index cc53f0915..7425264f5 100644 --- a/src/cmd.c +++ b/src/cmd.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 cmd.c $NHDT-Date: 1587317999 2020/04/19 17:39:59 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.418 $ */ +/* NetHack 3.7 cmd.c $NHDT-Date: 1608933418 2020/12/25 21:56:58 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.440 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2013. */ /* NetHack may be freely redistributed. See license for details. */ @@ -141,7 +141,7 @@ static int NDECL(wiz_polyself); static int NDECL(wiz_load_lua); static int NDECL(wiz_level_tele); static int NDECL(wiz_level_change); -static int NDECL(wiz_level_flip); +static int NDECL(wiz_flip_level); static int NDECL(wiz_show_seenv); static int NDECL(wiz_show_vision); static int NDECL(wiz_smell); @@ -181,13 +181,15 @@ static void FDECL(show_direction_keys, (winid, CHAR_P, BOOLEAN_P)); static boolean FDECL(help_dir, (CHAR_P, int, const char *)); static void NDECL(commands_init); -static int FDECL(dokeylist_putcmds, (winid, BOOLEAN_P, int, int, boolean *)); +static boolean FDECL(keylist_func_has_key, (const struct ext_func_tab *, + boolean *)); +static int FDECL(keylist_putcmds, (winid, BOOLEAN_P, int, int, boolean *)); static int FDECL(ch2spkeys, (CHAR_P, int, int)); static boolean FDECL(prefix_cmd, (CHAR_P)); +static const char *FDECL(spkey_name, (int)); static int NDECL((*timed_occ_fn)); -static char *FDECL(doc_extcmd_flagstr, (winid, const struct ext_func_tab *, - BOOLEAN_P)); +static char *FDECL(doc_extcmd_flagstr, (winid, const struct ext_func_tab *)); static const char *readchar_queue = ""; /* for rejecting attempts to use wizard mode commands */ @@ -340,38 +342,47 @@ doextcmd(VOID_ARGS) return retval; } +/* format extended command flags for display */ static char * -doc_extcmd_flagstr(menuwin, efp, doc) +doc_extcmd_flagstr(menuwin, efp) winid menuwin; -const struct ext_func_tab *efp; -boolean doc; +const struct ext_func_tab *efp; /* if Null, add a footnote to the menu */ { - static char buf[BUFSZ]; + static char Abuf[10]; /* 5 would suffice: {'[','m','A',']','\0'} */ - if (doc) { + /* note: tag shown for menu prefix is 'm' even if m-prefix action + has been bound to some other key */ + if (!efp) { + char qbuf[QBUFSZ]; anything any = cg.zeroany; add_menu(menuwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "[A] Command autocompletes", MENU_ITEMFLAGS_NONE); - Sprintf(buf, "[m] Command accepts '%c' prefix", + Sprintf(qbuf, "[m] Command accepts '%c' prefix", g.Cmd.spkeys[NHKF_REQMENU]); - add_menu(menuwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, + add_menu(menuwin, NO_GLYPH, &any, 0, 0, ATR_NONE, qbuf, MENU_ITEMFLAGS_NONE); return (char *) 0; } else { - buf[0] = '\0'; - Sprintf(&buf[1], "%s%s", - (efp->flags & AUTOCOMPLETE) ? "A" : "", - accept_menu_prefix(efp->ef_funct) ? "m" : ""); - if (buf[1]) { - buf[0] = '['; - Strcat(buf, "]"); + boolean mprefix = accept_menu_prefix(efp->ef_funct), + autocomplete = (efp->flags & AUTOCOMPLETE) != 0; + char *p = Abuf; + + /* "" or "[m]" or "[A]" or "[mA]" */ + if (mprefix || autocomplete) { + *p++ = '['; + if (mprefix) + *p++ = 'm'; + if (autocomplete) + *p++ = 'A'; + *p++ = ']'; } - return buf; + *p = '\0'; + return Abuf; } } -/* here after #? - now list all full-word commands and provid +/* here after #? - now list all full-word commands and provide some navigation capability through the long list */ int doextlist(VOID_ARGS) @@ -400,10 +411,8 @@ doextlist(VOID_ARGS) add_menu(menuwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_ITEMFLAGS_NONE); - Strcpy(buf, menumode ? "Show" : "Hide"); - Strcat(buf, " commands that don't autocomplete"); - if (!menumode) - Strcat(buf, " (those not marked with [A])"); + Sprintf(buf, "Switch to %s commands that don't autocomplete", + menumode ? "including" : "excluding"); any.a_int = 1; add_menu(menuwin, NO_GLYPH, &any, 'a', 0, ATR_NONE, buf, MENU_ITEMFLAGS_NONE); @@ -419,7 +428,7 @@ doextlist(VOID_ARGS) "Search extended commands", MENU_ITEMFLAGS_NONE); } else { - Strcpy(buf, "Show all, clear search"); + Strcpy(buf, "Switch back from search"); if (strlen(buf) + strlen(searchbuf) + strlen(" (\"\")") < QBUFSZ) Sprintf(eos(buf), " (\"%s\")", searchbuf); any.a_int = 3; @@ -434,8 +443,8 @@ doextlist(VOID_ARGS) if (wizard) { any.a_int = 4; add_menu(menuwin, NO_GLYPH, &any, 'z', 0, ATR_NONE, - onelist ? "Show debugging commands in separate section" - : "Show all alphabetically, including debugging commands", + onelist ? "Switch to showing debugging commands in separate section" + : "Switch to showing all alphabetically, including debugging commands", MENU_ITEMFLAGS_NONE); } any = cg.zeroany; @@ -486,10 +495,10 @@ doextlist(VOID_ARGS) MENU_ITEMFLAGS_NONE); menushown[pass] = 1; } - Sprintf(buf, " %-14s %-4s %s", - efp->ef_txt, - doc_extcmd_flagstr(menuwin, efp, FALSE), - efp->ef_desc); + /* longest ef_txt at present is "wizrumorcheck" (13 chars); + 2nd field will be " " or " [A]" or " [m]" or "[mA]" */ + Sprintf(buf, " %-14s %4s %s", efp->ef_txt, + doc_extcmd_flagstr(menuwin, efp), efp->ef_desc); add_menu(menuwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_ITEMFLAGS_NONE); ++n; @@ -502,7 +511,7 @@ doextlist(VOID_ARGS) add_menu(menuwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "no matches", MENU_ITEMFLAGS_NONE); else - (void) doc_extcmd_flagstr(menuwin, efp, TRUE); + (void) doc_extcmd_flagstr(menuwin, (struct ext_func_tab *) 0); end_menu(menuwin, (char *) 0); n = select_menu(menuwin, PICK_ONE, &selected); @@ -742,30 +751,37 @@ domonability(VOID_ARGS) int enter_explore_mode(VOID_ARGS) { - if (wizard) { - You("are in debug mode."); - } else if (discover) { + if (discover) { You("are already in explore mode."); } else { + const char *oldmode = !wizard ? "normal game" : "debug mode"; + #ifdef SYSCF #if defined(UNIX) if (!sysopt.explorers || !sysopt.explorers[0] || !check_user_string(sysopt.explorers)) { - You("cannot access explore mode."); - return 0; + if (!wizard) { + You("cannot access explore mode."); + return 0; + } else { + pline( + "Note: normally you wouldn't be allowed into explore mode."); + /* keep going */ + } } #endif #endif - pline( - "Beware! From explore mode there will be no return to normal game."); + pline("Beware! From explore mode there will be no return to %s,", + oldmode); if (paranoid_query(ParanoidQuit, "Do you want to enter explore mode?")) { + discover = TRUE; + wizard = FALSE; clear_nhwindow(WIN_MESSAGE); You("are now in non-scoring explore mode."); - discover = TRUE; } else { clear_nhwindow(WIN_MESSAGE); - pline("Resuming normal game."); + pline("Continuing with %s.", oldmode); } } return 0; @@ -1061,9 +1077,9 @@ wiz_level_tele(VOID_ARGS) return 0; } -/* #wizlevelflip - transpose the current level */ +/* #wizfliplevel - transpose the current level */ static int -wiz_level_flip(VOID_ARGS) +wiz_flip_level(VOID_ARGS) { static const char choices[] = "0123", prmpt[] = "Flip 0=randomly, 1=vertically, 2=horizonally, 3=both:"; @@ -1315,7 +1331,7 @@ wiz_map_levltyp(VOID_ARGS) } { - char dsc[BUFSZ]; + char dsc[COLBUFSZ]; s_level *slev = Is_special(&u.uz); Sprintf(dsc, "D:%d,L:%d", u.uz.dnum, u.uz.dlevel); @@ -1564,6 +1580,9 @@ wiz_intrinsic(VOID_ARGS) continue; } if (p == FIRE_RES) { + /* FIRE_RES and properties beyond it (in the propertynames[] + ordering, not their numerical PROP values), can only be + set to timed values here so show a separator */ any.a_int = 0; add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, "--", MENU_ITEMFLAGS_NONE); @@ -1642,23 +1661,23 @@ wiz_intrinsic(VOID_ARGS) } goto def_feedback; case GLIB: - /* slippery fingers applies to gloves if worn at the time - so persistent inventory might need updating */ + /* slippery fingers might need a persistent inventory update + so needs more than simple incr_itimeout() but we want + the pline() issued with that */ make_glib((int) newtimeout); - goto def_feedback; - case LEVITATION: - case FLYING: - float_vs_flight(); /*FALLTHRU*/ default: def_feedback: - pline("Timeout for %s %s %d.", propertynames[i].prop_name, - oldtimeout ? "increased by" : "set to", amt); if (p != GLIB) incr_itimeout(&u.uprops[p].intrinsic, amt); + g.context.botl = 1; /* have pline() do a status update */ + pline("Timeout for %s %s %d.", propertynames[i].prop_name, + oldtimeout ? "increased by" : "set to", amt); break; } - g.context.botl = 1; /* probably not necessary... */ + /* this has to be after incr_timeout() */ + if (p == LEVITATION || p == FLYING) + float_vs_flight(); } if (n >= 1) free((genericptr_t) pick_list); @@ -1782,9 +1801,10 @@ struct ext_func_tab extcmdlist[] = { doapply }, { C('x'), "attributes", "show your attributes", doattributes, IFBURIED }, - { '@', "autopickup", "toggle the pickup option on/off", + { '@', "autopickup", "toggle the 'autopickup' option on/off", dotogglepickup, IFBURIED }, - { 'C', "call", "call (name) something", docallcmd, IFBURIED }, + { 'C', "call", "name a monster, a specific object, or a type of object", + docallcmd, IFBURIED }, { 'Z', "cast", "zap (cast) a spell", docast, IFBURIED }, { M('c'), "chat", "talk to someone", dotalk, IFBURIED | AUTOCOMPLETE }, { 'c', "close", "close a door", doclose }, @@ -1798,19 +1818,19 @@ struct ext_func_tab extcmdlist[] = { { 'E', "engrave", "engrave writing on the floor", doengrave }, { M('e'), "enhance", "advance or check weapon and spell skills", enhance_weapon_skill, IFBURIED | AUTOCOMPLETE }, - { '\0', "exploremode", "enter explore (discovery) mode", - enter_explore_mode, IFBURIED }, + { M('X'), "exploremode", "enter explore (discovery) mode", + enter_explore_mode, IFBURIED | GENERALCMD }, { 'f', "fire", "fire ammunition from quiver", dofire }, { M('f'), "force", "force a lock", doforce, AUTOCOMPLETE }, { ';', "glance", "show what type of thing a map symbol corresponds to", doquickwhatis, IFBURIED | GENERALCMD }, { '?', "help", "give a help message", dohelp, IFBURIED | GENERALCMD }, { '\0', "herecmdmenu", "show menu of commands you can do here", - doherecmdmenu, IFBURIED }, + doherecmdmenu, IFBURIED | AUTOCOMPLETE | GENERALCMD }, { 'V', "history", "show long version and game history", dohistory, IFBURIED | GENERALCMD }, { 'i', "inventory", "show your inventory", ddoinv, IFBURIED }, - { 'I', "inventtype", "inventory specific item types", + { 'I', "inventtype", "show inventory of one specific item class", dotypeinv, IFBURIED }, { M('i'), "invoke", "invoke an object's special powers", doinvoke, IFBURIED | AUTOCOMPLETE }, @@ -1824,6 +1844,8 @@ struct ext_func_tab extcmdlist[] = { wiz_level_change, IFBURIED | AUTOCOMPLETE | WIZMODECMD }, { '\0', "lightsources", "show mobile light sources", wiz_light_sources, IFBURIED | AUTOCOMPLETE | WIZMODECMD }, + { '\0', "wizmgender", "force added info about monster gender", + wiz_mgender, IFBURIED | AUTOCOMPLETE | WIZMODECMD }, { ':', "look", "look at what is here", dolook, IFBURIED }, { M('l'), "loot", "loot a box on the floor", doloot, AUTOCOMPLETE }, #ifdef DEBUG_MIGRATING_MONS @@ -1832,7 +1854,7 @@ struct ext_func_tab extcmdlist[] = { #endif { M('m'), "monster", "use monster's special ability", domonability, IFBURIED | AUTOCOMPLETE }, - { 'N', "name", "name a monster or an object", + { 'N', "name", "same as call; name a monster or object or object type", docallcmd, IFBURIED | AUTOCOMPLETE }, { M('o'), "offer", "offer a sacrifice to the gods", dosacrifice, AUTOCOMPLETE }, @@ -1870,28 +1892,29 @@ struct ext_func_tab extcmdlist[] = { dopramulet, IFBURIED }, { ARMOR_SYM, "seearmor", "show the armor currently worn", doprarm, IFBURIED }, - { GOLD_SYM, "seegold", "count your gold", doprgold, IFBURIED }, - { '\0', "seenv", "show seen vectors", - wiz_show_seenv, IFBURIED | AUTOCOMPLETE | WIZMODECMD }, { RING_SYM, "seerings", "show the ring(s) currently worn", doprring, IFBURIED }, - { SPBOOK_SYM, "seespells", "list and reorder known spells", - dovspell, IFBURIED }, { TOOL_SYM, "seetools", "show the tools currently in use", doprtool, IFBURIED }, - { '^', "seetrap", "show the type of adjacent trap", doidtrap, IFBURIED }, { WEAPON_SYM, "seeweapon", "show the weapon currently wielded", doprwep, IFBURIED }, - { '!', "shell", "do a shell escape", + { '!', "shell", "leave game to enter a sub-shell ('exit' to come back)", dosh_core, IFBURIED | GENERALCMD #ifndef SHELL | CMD_NOT_AVAILABLE #endif /* SHELL */ }, + /* $ is like ),=,&c but is not included with *, so not called "seegold" */ + { GOLD_SYM, "showgold", "show gold, possibly shop credit or debt", + doprgold, IFBURIED }, + { SPBOOK_SYM, "showspells", "list and reorder known spells", + dovspell, IFBURIED }, + { '^', "showtrap", "describe an adjacent, discovered trap", + doidtrap, IFBURIED }, { M('s'), "sit", "sit down", dosit, AUTOCOMPLETE }, { '\0', "stats", "show memory statistics", wiz_show_stats, IFBURIED | AUTOCOMPLETE | WIZMODECMD }, - { C('z'), "suspend", "suspend the game", + { C('z'), "suspend", "push game to background ('fg' to come back)", dosuspend_core, IFBURIED | GENERALCMD #ifndef SUSPEND | CMD_NOT_AVAILABLE @@ -1901,11 +1924,15 @@ struct ext_func_tab extcmdlist[] = { { 'T', "takeoff", "take off one piece of armor", dotakeoff }, { 'A', "takeoffall", "remove all armor", doddoremarm }, { C('t'), "teleport", "teleport around the level", dotelecmd, IFBURIED }, - { '\0', "terrain", "show map without obstructions", + /* \177 == aka aka ; some terminals have an + option to swap it with so if there's a key labeled + it may or may not actually invoke the #terrain command */ + { '\177', "terrain", + "view map without monsters or objects obstructing it", doterrain, IFBURIED | AUTOCOMPLETE }, { '\0', "therecmdmenu", "menu of commands you can do from here to adjacent spot", - dotherecmdmenu }, + dotherecmdmenu, AUTOCOMPLETE | GENERALCMD }, { 't', "throw", "throw something", dothrow }, { '\0', "timeout", "look at timeout queue and hero's timed intrinsics", wiz_timeout_queue, IFBURIED | AUTOCOMPLETE | WIZMODECMD }, @@ -1921,7 +1948,8 @@ struct ext_func_tab extcmdlist[] = { { M('v'), "version", "list compile time options for this version of NetHack", doextversion, IFBURIED | AUTOCOMPLETE | GENERALCMD }, - { 'v', "versionshort", "show version", doversion, IFBURIED | GENERALCMD }, + { 'v', "versionshort", "show version and date+time program was built", + doversion, IFBURIED | GENERALCMD }, { '\0', "vision", "show vision array", wiz_show_vision, IFBURIED | AUTOCOMPLETE | WIZMODECMD }, { '.', "wait", "rest one move while doing nothing", @@ -1940,14 +1968,14 @@ struct ext_func_tab extcmdlist[] = { #endif { C('e'), "wizdetect", "reveal hidden things within a small radius", wiz_detect, IFBURIED | AUTOCOMPLETE | WIZMODECMD }, + { '\0', "wizfliplevel", "flip the level", + wiz_flip_level, IFBURIED | WIZMODECMD }, { C('g'), "wizgenesis", "create a monster", wiz_genesis, IFBURIED | AUTOCOMPLETE | WIZMODECMD }, { C('i'), "wizidentify", "identify all items in inventory", wiz_identify, IFBURIED | AUTOCOMPLETE | WIZMODECMD }, { '\0', "wizintrinsic", "set an intrinsic", wiz_intrinsic, IFBURIED | AUTOCOMPLETE | WIZMODECMD }, - { '\0', "wizlevelflip", "flip the level", - wiz_level_flip, IFBURIED | WIZMODECMD }, { C('v'), "wizlevelport", "teleport to another level", wiz_level_tele, IFBURIED | AUTOCOMPLETE | WIZMODECMD }, { '\0', "wizloaddes", "load and execute a des-file lua script", @@ -1960,6 +1988,8 @@ struct ext_func_tab extcmdlist[] = { wiz_map, IFBURIED | AUTOCOMPLETE | WIZMODECMD }, { '\0', "wizrumorcheck", "verify rumor boundaries", wiz_rumor_check, IFBURIED | AUTOCOMPLETE | WIZMODECMD }, + { '\0', "wizseenv", "show map locations' seen vectors", + wiz_show_seenv, IFBURIED | AUTOCOMPLETE | WIZMODECMD }, { '\0', "wizsmell", "smell monster", wiz_smell, IFBURIED | AUTOCOMPLETE | WIZMODECMD }, { '\0', "wizwhere", "show locations of special levels", @@ -2048,13 +2078,13 @@ const char *command; struct ext_func_tab *extcmd; /* special case: "nothing" is reserved for unbinding */ - if (!strcmp(command, "nothing")) { + if (!strcmpi(command, "nothing")) { g.Cmd.commands[key] = (struct ext_func_tab *) 0; return TRUE; } for (extcmd = extcmdlist; extcmd->ef_txt; extcmd++) { - if (strcmp(command, extcmd->ef_txt)) + if (strcmpi(command, extcmd->ef_txt)) continue; g.Cmd.commands[key] = extcmd; #if 0 /* silently accept key binding for unavailable command (!SHELL,&c) */ @@ -2104,41 +2134,79 @@ commands_init() (void) bind_key(' ', "wait"); } -static int -dokeylist_putcmds(datawin, docount, cmdflags, exflags, keys_used) -winid datawin; -boolean docount; -int cmdflags, exflags; -boolean *keys_used; /* boolean keys_used[256] */ +static boolean +keylist_func_has_key(extcmd, skip_keys_used) +const struct ext_func_tab *extcmd; +boolean *skip_keys_used; /* boolean keys_used[256] */ { int i; - char buf[BUFSZ]; - char buf2[QBUFSZ]; + + for (i = 0; i < 256; ++i) { + if (skip_keys_used[i]) + continue; + + if (g.Cmd.commands[i] == extcmd) + return TRUE; + } + return FALSE; +} + +static int +keylist_putcmds(datawin, docount, incl_flags, excl_flags, keys_used) +winid datawin; +boolean docount; +int incl_flags, excl_flags; +boolean *keys_used; /* boolean keys_used[256] */ +{ + const struct ext_func_tab *extcmd; + int i; + char buf[BUFSZ], buf2[QBUFSZ]; + boolean keys_already_used[256]; /* copy of keys_used[] before updates */ int count = 0; for (i = 0; i < 256; i++) { - const struct ext_func_tab *extcmd; uchar key = (uchar) i; + keys_already_used[i] = keys_used[i]; if (keys_used[i]) continue; if (key == ' ' && !flags.rest_on_space) continue; if ((extcmd = g.Cmd.commands[i]) != (struct ext_func_tab *) 0) { - if ((cmdflags && !(extcmd->flags & cmdflags)) - || (exflags && (extcmd->flags & exflags))) + if ((incl_flags && !(extcmd->flags & incl_flags)) + || (excl_flags && (extcmd->flags & excl_flags))) continue; if (docount) { count++; continue; } - Sprintf(buf, "%-8s %-12s %s", key2txt(key, buf2), - extcmd->ef_txt, - extcmd->ef_desc); + Sprintf(buf, "%-7s %-13s %s", key2txt(key, buf2), + extcmd->ef_txt, extcmd->ef_desc); putstr(datawin, 0, buf); keys_used[i] = TRUE; } } + /* also list commands that lack key assignments; most are wizard mode */ + for (extcmd = extcmdlist; extcmd->ef_txt; ++extcmd) { + if ((incl_flags && !(extcmd->flags & incl_flags)) + || (excl_flags && (extcmd->flags & excl_flags))) + continue; + /* can't just check for non-Null extcmd->key; it holds the + default assignment and a user-specified binding might hijack + this command's default key for some other command; or this + command might have been assigned a key being used for + movement or as a prefix, intercepting that keystroke */ + if (keylist_func_has_key(extcmd, keys_already_used)) + continue; + /* found a command for current category without any key assignment */ + if (docount) { + count++; + continue; + } + /* '#'+20 for one column here == 7+' '+13 for two columns above */ + Sprintf(buf, "#%-20s %s", extcmd->ef_txt, extcmd->ef_desc); + putstr(datawin, 0, buf); + } return count; } @@ -2146,13 +2214,9 @@ boolean *keys_used; /* boolean keys_used[256] */ void dokeylist(VOID_ARGS) { - char buf[BUFSZ], buf2[BUFSZ]; - uchar key; - boolean keys_used[256] = {0}; - winid datawin; - int i; static const char run_desc[] = "Prefix: run until something very interesting is seen", + rush_desc[] = "Prefix: rush until something interesting is seen", forcefight_desc[] = "Prefix: force fight even if you don't see a monster"; static const struct { @@ -2160,40 +2224,43 @@ dokeylist(VOID_ARGS) const char *desc; boolean numpad; } misc_keys[] = { - { NHKF_ESC, "escape from the current query/action", FALSE }, - { NHKF_RUSH, - "Prefix: rush until something interesting is seen", FALSE }, + { NHKF_ESC, "cancel current prompt or pending prefix", FALSE }, + { NHKF_RUSH, rush_desc, FALSE }, + { NHKF_RUSH2, rush_desc, TRUE }, { NHKF_RUN, run_desc, FALSE }, { NHKF_RUN2, run_desc, TRUE }, { NHKF_FIGHT, forcefight_desc, FALSE }, { NHKF_FIGHT2, forcefight_desc, TRUE } , { NHKF_NOPICKUP, - "Prefix: move without picking up objects/fighting", FALSE }, + "Prefix: move without picking up objects or fighting", FALSE }, { NHKF_RUN_NOPICKUP, - "Prefix: run without picking up objects/fighting", FALSE }, - { NHKF_DOINV, "view inventory", TRUE }, - { NHKF_REQMENU, "Prefix: request a menu", FALSE }, -#ifdef REDO - { NHKF_DOAGAIN , "re-do: perform the previous command again", FALSE }, -#endif + "Prefix: run without picking up objects or fighting", FALSE }, + { NHKF_REQMENU, + "Prefix: request a menu (for some non-movement commands)", FALSE }, + { NHKF_COUNT, + "Prefix: for digits when preceding a command with a count", TRUE }, + { NHKF_DOINV, "numpad: view full inventory", TRUE }, + /* NHKF_DOINV2 for num_pad+pcHack_compat isn't implemented */ + /* { NHKF_DOINV2, "numpad: view inventory of one class of objects", + TRUE }, */ + { NHKF_DOAGAIN , "repeat: perform the previous command again", FALSE }, { 0, (const char *) 0, FALSE } }; + const struct ext_func_tab *extcmd; + winid datawin; + char buf[BUFSZ], buf2[BUFSZ]; + uchar key; + boolean spkey_gap, keys_used[256], mov_seen[256]; + int i, j, pfx_seen[256]; - datawin = create_nhwindow(NHW_TEXT); - putstr(datawin, 0, ""); - putstr(datawin, 0, " Full Current Key Bindings List"); - - /* directional keys */ - putstr(datawin, 0, ""); - putstr(datawin, 0, "Directional keys:"); - show_direction_keys(datawin, '.', FALSE); /* '.'==self in direct'n grid */ + (void) memset((genericptr_t) keys_used, 0, sizeof keys_used); + (void) memset((genericptr_t) pfx_seen, 0, sizeof pfx_seen); keys_used[(uchar) g.Cmd.move_NW] = keys_used[(uchar) g.Cmd.move_N] = keys_used[(uchar) g.Cmd.move_NE] = keys_used[(uchar) g.Cmd.move_W] = keys_used[(uchar) g.Cmd.move_E] = keys_used[(uchar) g.Cmd.move_SW] = keys_used[(uchar) g.Cmd.move_S] = keys_used[(uchar) g.Cmd.move_SE] = TRUE; - if (!iflags.num_pad) { keys_used[(uchar) highc(g.Cmd.move_NW)] = keys_used[(uchar) highc(g.Cmd.move_N)] @@ -2211,52 +2278,138 @@ dokeylist(VOID_ARGS) = keys_used[(uchar) C(g.Cmd.move_SW)] = keys_used[(uchar) C(g.Cmd.move_S)] = keys_used[(uchar) C(g.Cmd.move_SE)] = TRUE; + } else { + /* num_pad */ + keys_used[(uchar) M('1')] = keys_used[(uchar) M('2')] + = keys_used[(uchar) M('3')] = keys_used[(uchar) M('4')] + = keys_used[(uchar) M('6')] = keys_used[(uchar) M('7')] + = keys_used[(uchar) M('8')] = keys_used[(uchar) M('9')] = TRUE; + } +#ifndef NO_SIGNAL + /* this is actually ambiguous; tty raw mode will override SIGINT; + when enabled, treat it like a movement command since assigning + other commands to this keystroke would be unwise... */ + key = (uchar) C('c'); + keys_used[key] = TRUE; +#endif + + /* movement keys have been flagged in keys_used[]; clone them */ + (void) memcpy((genericptr_t) mov_seen, (genericptr_t) keys_used, + sizeof mov_seen); + + spkey_gap = FALSE; + for (i = 0; misc_keys[i].desc; ++i) { + if (misc_keys[i].numpad && !iflags.num_pad) + continue; + j = misc_keys[i].nhkf; + key = (uchar) g.Cmd.spkeys[j]; + if (key && !mov_seen[key] && (!pfx_seen[key] || j == NHKF_REQMENU)) { + keys_used[key] = TRUE; + if (j != NHKF_REQMENU) + pfx_seen[key] = j; + } else + spkey_gap = TRUE; + } + + datawin = create_nhwindow(NHW_TEXT); + putstr(datawin, 0, ""); + Sprintf(buf, "%7s %s", "", " Full Current Key Bindings List"); + putstr(datawin, 0, buf); + for (extcmd = extcmdlist; extcmd->ef_txt; ++extcmd) + if (spkey_gap || !keylist_func_has_key(extcmd, keys_used)) { + Sprintf(buf, "%7s %s", "", + "(also commands with no key assignment)"); + putstr(datawin, 0, buf); + break; + } + + /* directional keys */ + putstr(datawin, 0, ""); + putstr(datawin, 0, "Directional keys:"); + show_direction_keys(datawin, '.', FALSE); /* '.'==self in direct'n grid */ + + if (!iflags.num_pad) { putstr(datawin, 0, ""); putstr(datawin, 0, - "Shift- will move in specified direction until you hit"); - putstr(datawin, 0, " a wall or run into something."); - putstr(datawin, 0, - "Ctrl- will run in specified direction until something"); - putstr(datawin, 0, " very interesting is seen."); + "Ctrl+ will run in specified direction until something very"); + Sprintf(buf, "%7s %s", "", "interesting is seen."); + putstr(datawin, 0, buf); + Strcpy(buf, "Shift"); /* append the rest below */ + } else { + /* num_pad */ + putstr(datawin, 0, ""); + Strcpy(buf, "Meta"); /* append the rest next */ } + Strcat(buf, + "+ will run in specified direction until you encounter"); + putstr(datawin, 0, buf); + Sprintf(buf, "%7s %s", "", "an obstacle."); + putstr(datawin, 0, buf); putstr(datawin, 0, ""); putstr(datawin, 0, "Miscellaneous keys:"); - for (i = 0; misc_keys[i].desc; i++) { - key = g.Cmd.spkeys[misc_keys[i].nhkf]; - if (key && ((misc_keys[i].numpad && iflags.num_pad) - || !misc_keys[i].numpad)) { - keys_used[(uchar) key] = TRUE; - Sprintf(buf, "%-8s %s", key2txt(key, buf2), misc_keys[i].desc); + for (i = 0; misc_keys[i].desc; ++i) { + if (misc_keys[i].numpad && !iflags.num_pad) + continue; + j = misc_keys[i].nhkf; + key = (uchar) g.Cmd.spkeys[j]; + if (key && !mov_seen[key] + && (pfx_seen[key] == j || j == NHKF_REQMENU)) { + Sprintf(buf, "%-7s %s", key2txt(key, buf2), misc_keys[i].desc); putstr(datawin, 0, buf); } } + /* (see above) */ + key = (uchar) C('c'); #ifndef NO_SIGNAL - putstr(datawin, 0, "^c break out of NetHack (SIGINT)"); - keys_used[(uchar) C('c')] = TRUE; + /* last of the special keys */ + Sprintf(buf, "%-7s", key2txt(key, buf2)); +#else + /* first of the keyless commands */ + Sprintf(buf2, "[%s]", key2txt(key, buf)); + Sprintf(buf, "%-21s", buf2); #endif + Strcat(buf, " interrupt: break out of NetHack (SIGINT)"); + putstr(datawin, 0, buf); + /* keyless special key commands, if any */ + if (spkey_gap) { + for (i = 0; misc_keys[i].desc; ++i) { + if (misc_keys[i].numpad && !iflags.num_pad) + continue; + j = misc_keys[i].nhkf; + key = (uchar) g.Cmd.spkeys[j]; + if (!key || (pfx_seen[key] != j && j != NHKF_REQMENU)) { + Sprintf(buf2, "[%s]", spkey_name(j)); + /* lines up with the other unassigned commands which use + "#%-20s ", but not with the other special keys */ + Sprintf(buf, "%-21s %s", buf2, misc_keys[i].desc); + putstr(datawin, 0, buf); + } + } + } putstr(datawin, 0, ""); show_menu_controls(datawin, TRUE); - if (dokeylist_putcmds(datawin, TRUE, GENERALCMD, WIZMODECMD, keys_used)) { + if (keylist_putcmds(datawin, TRUE, GENERALCMD, WIZMODECMD, keys_used)) { putstr(datawin, 0, ""); putstr(datawin, 0, "General commands:"); - (void) dokeylist_putcmds(datawin, FALSE, GENERALCMD, WIZMODECMD, + (void) keylist_putcmds(datawin, FALSE, GENERALCMD, WIZMODECMD, keys_used); } - if (dokeylist_putcmds(datawin, TRUE, 0, WIZMODECMD, keys_used)) { + if (keylist_putcmds(datawin, TRUE, 0, + GENERALCMD | WIZMODECMD, keys_used)) { putstr(datawin, 0, ""); putstr(datawin, 0, "Game commands:"); - (void) dokeylist_putcmds(datawin, FALSE, 0, WIZMODECMD, keys_used); + (void) keylist_putcmds(datawin, FALSE, 0, + GENERALCMD | WIZMODECMD, keys_used); } - if (wizard - && dokeylist_putcmds(datawin, TRUE, WIZMODECMD, 0, keys_used)) { + if (wizard && keylist_putcmds(datawin, TRUE, WIZMODECMD, 0, keys_used)) { putstr(datawin, 0, ""); - putstr(datawin, 0, "Wizard-mode commands:"); - (void) dokeylist_putcmds(datawin, FALSE, WIZMODECMD, 0, keys_used); + putstr(datawin, 0, "Debug mode commands:"); + (void) keylist_putcmds(datawin, FALSE, WIZMODECMD, 0, keys_used); } display_nhwindow(datawin, FALSE); @@ -2269,12 +2422,72 @@ int NDECL((*fn)); { int i; - for (i = 0; i < 256; ++i) + /* skip NUL; allowing it would wreak havoc */ + for (i = 1; i < 256; ++i) { + /* skip space; we'll use it below as last resort if no other + keystroke invokes space's command */ + if (i == ' ') + continue; + if (g.Cmd.commands[i] && g.Cmd.commands[i]->ef_funct == fn) return (char) i; + } + if (g.Cmd.commands[' '] && g.Cmd.commands[' ']->ef_funct == fn) + return ' '; return '\0'; } +/* return extended command name (without leading '#') for command (*fn)() */ +const char * +cmdname_from_func(fn, outbuf, fullname) +int NDECL((*fn)); +char outbuf[]; +boolean fullname; /* False: just enough to disambiguate */ +{ + const struct ext_func_tab *extcmd, *cmdptr = 0; + const char *res = 0; + + for (extcmd = extcmdlist; extcmd->ef_txt; ++extcmd) + if (extcmd->ef_funct == fn) { + cmdptr = extcmd; + res = cmdptr->ef_txt; + break; + } + + if (!res) { + /* make sure output buffer doesn't contain junk or stale data; + return Null below */ + outbuf[0] = '\0'; + } else if (fullname) { + /* easy; the entire command name */ + res = strcpy(outbuf, res); + } else { + const struct ext_func_tab *matchcmd = extcmdlist; + int len = 0; + + /* find the shortest leading substring which is unambiguous */ + do { + if (++len >= (int) strlen(res)) + break; + for (extcmd = matchcmd; extcmd->ef_txt; ++extcmd) { + if (extcmd == cmdptr) + continue; + if ((extcmd->flags & CMD_NOT_AVAILABLE) != 0 + || ((extcmd->flags & WIZMODECMD) != 0 && !wizard)) + continue; + if (!strncmp(res, extcmd->ef_txt, len)) { + matchcmd = extcmd; + break; + } + } + } while (extcmd->ef_txt); + copynchars(outbuf, res, len); + debugpline2("shortened %s: \"%s\"", res, outbuf); + res = outbuf; + } + return res; +} + /* * wizard mode sanity_check code */ @@ -2412,8 +2625,8 @@ boolean incl_wsegs; if (mtmp->mextra) { sz += (int) sizeof (struct mextra); - if (MNAME(mtmp)) - sz += (int) strlen(MNAME(mtmp)) + 1; + if (MGIVENNAME(mtmp)) + sz += (int) strlen(MGIVENNAME(mtmp)) + 1; if (EGD(mtmp)) sz += (int) sizeof (struct egd); if (EPRI(mtmp)) @@ -2705,9 +2918,13 @@ wiz_migrate_mons() } #endif -struct { +#ifndef DOAGAIN /* might have gotten undefined in config.h */ +#define DOAGAIN '\0' /* undefined => 0, '\0' => no key to activate redo */ +#endif + +static struct { int nhkf; - char key; + uchar key; const char *name; } const spkeys_binds[] = { { NHKF_ESC, '\033', (char *) 0 }, /* no binding */ @@ -2716,6 +2933,7 @@ struct { { NHKF_RUN, 'G', "run" }, { NHKF_RUN2, '5', "run.numpad" }, { NHKF_RUSH, 'g', "rush" }, + { NHKF_RUSH2, M('5'), "rush.numpad" }, { NHKF_FIGHT, 'F', "fight" }, { NHKF_FIGHT2, '-', "fight.numpad" }, { NHKF_NOPICKUP, 'm', "nopickup" }, @@ -2760,6 +2978,7 @@ uchar key; const char *command; { int i; + for (i = 0; i < SIZE(spkeys_binds); i++) { if (!spkeys_binds[i].name || strcmp(command, spkeys_binds[i].name)) continue; @@ -2769,19 +2988,37 @@ const char *command; return FALSE; } -/* returns a one-byte character from the text (it may massacre the txt - * buffer) */ -char +static const char * +spkey_name(nhkf) +int nhkf; +{ + const char *name = 0; + int i; + + for (i = 0; i < SIZE(spkeys_binds); i++) { + if (spkeys_binds[i].nhkf == nhkf) { + name = (nhkf == NHKF_ESC) ? "escape" : spkeys_binds[i].name; + break; + } + } + return name; +} + +/* returns a one-byte character from the text; may change txt[] */ +uchar txt2key(txt) char *txt; { + uchar uc; + boolean makemeta = FALSE; + txt = trimspaces(txt); if (!*txt) return '\0'; /* simple character */ if (!txt[1]) - return txt[0]; + return (uchar) txt[0]; /* a few special entries */ if (!strcmp(txt, "")) @@ -2792,25 +3029,55 @@ char *txt; return '\033'; /* control and meta keys */ - switch (*txt) { - case 'm': /* can be mx, Mx, m-x, M-x */ - case 'M': - txt++; + if (highc(*txt) == 'M') { + /* + * M return 'M' + * M - return M-'-' + * M return M- + * otherwise M is pending until after ^/C- processing. + * Since trailing spaces are discarded, the only way to + * specify M-' ' is via "160". + */ + if (!txt[1]) + return (uchar) *txt; + /* skip past 'M' or 'm' and maybe '-' */ + ++txt; if (*txt == '-' && txt[1]) - txt++; - if (txt[1]) - return '\0'; - return M(*txt); - case 'c': /* can be cx, Cx, ^x, c-x, C-x, ^-x */ - case 'C': - case '^': - txt++; - if (*txt == '-' && txt[1]) - txt++; - if (txt[1]) - return '\0'; - return C(*txt); + ++txt; + if (!txt[1]) + return M((uchar) *txt); + makemeta = TRUE; } + if (*txt == '^' || highc(*txt) == 'C') { + /* + * C return 'C' or M-'C' + * C - return '-' or M-'-' + * C [-] return C- or M-C- + * C [-] ? return + * otherwise return C- or M-C- + */ + uc = (uchar) *txt; + if (!txt[1]) + return makemeta ? M(uc) : uc; + ++txt; + /* unlike M-x, lots of values of x are invalid for C-x; + checking and rejecting them is not worthwhile; GIGO; + we do accept "^-x" as synonym for "^x" or "C-x" */ + if (*txt == '-' && txt[1]) + ++txt; + /* and accept ^?, which gets used despite not being a control char */ + if (*txt == '?') + return (uchar) (makemeta ? '\377' : '\177'); /* rubout/delete */ + uc = C((uchar) *txt); + return makemeta ? M(uc) : uc; + } + if (makemeta && *txt) + return M((uchar) *txt); + + /* FIXME: should accept single-quote single-character single-quote + and probably single-quote backslash octal-digits single-quote; + if we do that, the M- and C- results should be pending until + after, so that C-'X' becomes valid for ^X */ /* ascii codes: must be three-digit decimal */ if (*txt >= '0' && *txt <= '9') { @@ -2840,9 +3107,9 @@ char *txt; /* sufficiently long buffer */ if (c == ' ') Sprintf(txt, ""); else if (c == '\033') - Sprintf(txt, ""); + Sprintf(txt, ""); /* "" won't fit */ else if (c == '\n') - Sprintf(txt, ""); + Sprintf(txt, ""); /* "" won't fit */ else if (c == '\177') Sprintf(txt, ""); /* "" won't fit */ else @@ -2942,13 +3209,14 @@ boolean initial; if (flagtemp != g.Cmd.swap_yz) { g.Cmd.swap_yz = flagtemp; ++updated; - /* g.Cmd.swap_yz has been toggled; + /* FIXME? should Cmd.spkeys[] be scanned for y and/or z to swap? + Cmd.swap_yz has been toggled; perform the swap (or reverse previous one) */ for (i = 0; i < SIZE(ylist); i++) { c = ylist[i] & 0xff; - cmdtmp = g.Cmd.commands[c]; /* tmp = [y] */ + cmdtmp = g.Cmd.commands[c]; /* tmp = [y] */ g.Cmd.commands[c] = g.Cmd.commands[c + 1]; /* [y] = [z] */ - g.Cmd.commands[c + 1] = cmdtmp; /* [z] = tmp */ + g.Cmd.commands[c + 1] = cmdtmp; /* [z] = tmp */ } } /* MSDOS compatibility mode (only applicable for num_pad) */ @@ -2957,10 +3225,17 @@ boolean initial; g.Cmd.pcHack_compat = flagtemp; ++updated; /* pcHack_compat has been toggled */ +#if 0 c = M('5') & 0xff; cmdtmp = g.Cmd.commands['5']; g.Cmd.commands['5'] = g.Cmd.commands[c]; g.Cmd.commands[c] = cmdtmp; +#else + c = g.Cmd.spkeys[NHKF_RUN2]; + g.Cmd.spkeys[NHKF_RUN2] = g.Cmd.spkeys[NHKF_RUSH2]; + g.Cmd.spkeys[NHKF_RUSH2] = c; +#endif + /* FIXME: NHKF_DOINV2 ought to be implemented instead of this */ c = M('0') & 0xff; g.Cmd.commands[c] = g.Cmd.pcHack_compat ? g.Cmd.commands['I'] : 0; } @@ -3025,6 +3300,8 @@ int NDECL((*cmd_func)); /* 'm' for removing saddle from adjacent monster without checking for containers at */ || cmd_func == doloot + /* offer menu to choose discoveries sort order */ + || cmd_func == dodiscovered || cmd_func == doclassdisco /* travel: pop up a menu of interesting targets in view */ || cmd_func == dotravel /* wait and search: allow even if next to a hostile monster */ @@ -3151,7 +3428,9 @@ register char *cmd; g.context.move = FALSE; return; } - if (*cmd == DOAGAIN && !g.in_doagain && g.saveq[0]) { + /* DOAGAIN might be '\0'; if so, don't execute it even if *cmd is too */ + if ((*cmd && *cmd == g.Cmd.spkeys[NHKF_DOAGAIN]) + && !g.in_doagain && g.saveq[0]) { g.in_doagain = TRUE; g.stail = 0; rhack((char *) 0); /* read and execute command */ @@ -3171,6 +3450,10 @@ register char *cmd; spkey = ch2spkeys(*cmd, NHKF_RUN, NHKF_CLICKLOOK); switch (spkey) { + case NHKF_RUSH2: + if (!g.Cmd.num_pad) + break; + /*FALLTHRU*/ case NHKF_RUSH: if (movecmd(cmd[1])) { g.context.run = 2; @@ -3258,9 +3541,9 @@ register char *cmd; break; } - /* some special prefix handling */ - /* overload 'm' prefix to mean "request a menu" */ - if (prefix_seen && cmd[0] == g.Cmd.spkeys[NHKF_REQMENU]) { + /* after movement--if reqmenu duplicates a prefix, movement takes + precedence; "request a menu" (default 'm') */ + if (cmd[0] == g.Cmd.spkeys[NHKF_REQMENU]) { /* (for func_tab cast, see below) */ const struct ext_func_tab *ft = g.Cmd.commands[cmd[1] & 0xff]; int NDECL((*func)) = ft ? ((struct ext_func_tab *) ft)->ef_funct : 0; @@ -3268,6 +3551,9 @@ register char *cmd; if (func && accept_menu_prefix(func)) { iflags.menu_requested = TRUE; ++cmd; + prefix_seen = FALSE; + } else { + prefix_seen = TRUE; } } @@ -3301,10 +3587,14 @@ register char *cmd; g.context.mv = TRUE; domove(); return; - } else if (prefix_seen && cmd[1] == g.Cmd.spkeys[NHKF_ESC]) { - /* */ - /* don't report "unknown command" for change of heart... */ - bad_command = FALSE; + } else if (prefix_seen) { + if (cmd[1] == g.Cmd.spkeys[NHKF_ESC]) { + /* */ + /* don't report "unknown command" for change of heart... */ + bad_command = FALSE; + } else { /* prefix followed by non-movement command */ + bad_command = TRUE; /* skip cmdlist[] loop */ + } } else if (*cmd == ' ' && !flags.rest_on_space) { bad_command = TRUE; /* skip cmdlist[] loop */ @@ -3424,13 +3714,15 @@ static boolean prefix_cmd(c) char c; { - return (c == g.Cmd.spkeys[NHKF_RUSH] + return (c == g.Cmd.spkeys[NHKF_REQMENU] + || c == g.Cmd.spkeys[NHKF_RUSH] || c == g.Cmd.spkeys[NHKF_RUN] || c == g.Cmd.spkeys[NHKF_NOPICKUP] || c == g.Cmd.spkeys[NHKF_RUN_NOPICKUP] || c == g.Cmd.spkeys[NHKF_FIGHT] || (g.Cmd.num_pad && (c == g.Cmd.spkeys[NHKF_RUN2] - || c == g.Cmd.spkeys[NHKF_FIGHT2]))); + || c == g.Cmd.spkeys[NHKF_RUSH2] + || c == g.Cmd.spkeys[NHKF_FIGHT2]))); } /* @@ -3584,6 +3876,10 @@ const char *msg; case NHKF_NOPICKUP: dothat = "move"; break; + case NHKF_RUSH2: + if (!g.Cmd.num_pad) + break; + /*FALLTHRU*/ case NHKF_RUSH: dothat = "rush"; break; @@ -3781,6 +4077,9 @@ const char *text; } } +/* offer choice of actions to perform at adjacent location ; + does not work as intended because the actions that get invoked + ask for a direction or target instead of using our */ static char there_cmd_menu(doit, x, y) boolean doit; @@ -3854,6 +4153,18 @@ int x, y; add_herecmd_menuitem(win, doapply, buf); } #if 0 + if (mtmp) { + Sprintf(buf, "%s %s", mon_nam(mtmp), + !has_mname(mtmp) ? "Name" : "Rename"), ++K; + /* need a way to pass mtmp or to an 'int f()' function + as well as reorganizinging do_mname() to use that function */ + add_herecmd_menuitem(win, XXX(), buf); + } +#endif +#if 0 + /* these are necessary if click_to_cmd() is deferring to us; however, + moving/fighting aren't implmented as independent commands so don't + fit our menu's use of command functions */ if (mtmp || glyph_is_invisible(glyph_at(x, y))) { /* "Attack %s", mtmp ? mon_nam(mtmp) : "unseen creature" */ } else { @@ -3869,7 +4180,7 @@ int x, y; npick = 0; } destroy_nhwindow(win); - ch = '\0'; + ch = '\033'; if (npick > 0) { int NDECL((*func)) = picks->item.a_nfunc; free((genericptr_t) picks); @@ -3895,6 +4206,7 @@ boolean doit; schar typ = levl[u.ux][u.uy].typ; int npick; menu_item *picks = (menu_item *) 0; + stairway *stway = stairway_at(u.ux, u.uy); win = create_nhwindow(NHW_MENU); start_menu(win, MENU_BEHAVE_STANDARD); @@ -3911,16 +4223,14 @@ boolean doit; add_herecmd_menuitem(win, dosit, "Sit on the throne"); - if (On_stairs_up(u.ux, u.uy)) { + if (stway && stway->up) { Sprintf(buf, "Go up the %s", - (u.ux == xupladder && u.uy == yupladder) - ? "ladder" : "stairs"); + stway->isladder ? "ladder" : "stairs"); add_herecmd_menuitem(win, doup, buf); } - if (On_stairs_dn(u.ux, u.uy)) { + if (stway && !stway->up) { Sprintf(buf, "Go down the %s", - (u.ux == xupladder && u.uy == yupladder) - ? "ladder" : "stairs"); + stway->isladder ? "ladder" : "stairs"); add_herecmd_menuitem(win, dodown, buf); } if (u.usteed) { /* another movement choice */ @@ -3933,7 +4243,7 @@ boolean doit; #if 0 if (Upolyd) { /* before objects */ Sprintf(buf, "Use %s special ability", - s_suffix(mons[u.umonnum].mname)); + s_suffix(pmname(&mons[u.umonnum], Ugender))); add_herecmd_menuitem(win, domonability, buf); } #endif @@ -3964,7 +4274,7 @@ boolean doit; end_menu(win, "What do you want to do?"); npick = select_menu(win, PICK_ONE, &picks); destroy_nhwindow(win); - ch = '\0'; + ch = '\033'; if (npick > 0) { int NDECL((*func)) = picks->item.a_nfunc; free((genericptr_t) picks); @@ -3989,16 +4299,33 @@ int x, y, mod; { static char cmd[4]; struct obj *o; - int dir; - - cmd[1] = '\0'; + int dir, udist; + cmd[0] = cmd[1] = '\0'; if (iflags.clicklook && mod == CLICK_2) { g.clicklook_cc.x = x; g.clicklook_cc.y = y; cmd[0] = g.Cmd.spkeys[NHKF_CLICKLOOK]; return cmd; } + /* this used to be inside the 'if (flags.travelcmd)' block, but + handle click-on-self even when travel is disabled; unlike + accidentally zooming across the level because of a stray click, + clicking on self can easily be cancelled if it wasn't intended */ + if (iflags.herecmd_menu && isok(x, y)) { + udist = distu(x, y); + if (!udist) { + cmd[0] = here_cmd_menu(FALSE); + return cmd; + } else if (udist <= 2) { +#if 0 /* there_cmd_menu() is broken; the commands it invokes + * tend to ask for a direction or target instead of using + * the adjacent coordinates that are being passed to it */ + cmd[0] = there_cmd_menu(FALSE, x, y); + return cmd; +#endif + } + } x -= u.ux; y -= u.uy; @@ -4014,11 +4341,6 @@ int x, y, mod; } if (x == 0 && y == 0) { - if (iflags.herecmd_menu) { - cmd[0] = here_cmd_menu(FALSE); - return cmd; - } - /* here */ if (IS_FOUNTAIN(levl[u.ux][u.uy].typ) || IS_SINK(levl[u.ux][u.uy].typ)) { @@ -4045,17 +4367,10 @@ int x, y, mod; /* directional commands */ dir = xytod(x, y); - if (!m_at(u.ux + x, u.uy + y) && !test_move(u.ux, u.uy, x, y, TEST_MOVE)) { cmd[1] = g.Cmd.dirchars[dir]; cmd[2] = '\0'; - if (iflags.herecmd_menu) { - cmd[0] = there_cmd_menu(FALSE, u.ux + x, u.uy + y); - if (cmd[0] == '\0') - cmd[1] = '\0'; - return cmd; - } if (IS_DOOR(levl[u.ux + x][u.uy + y].typ)) { /* slight assistance to player: choose kick/open for them */ @@ -4207,7 +4522,7 @@ parse() if (foo == g.Cmd.spkeys[NHKF_ESC]) { /* esc cancels count (TH) */ clear_nhwindow(WIN_MESSAGE); g.multi = g.last_multi = 0; - } else if (foo == g.Cmd.spkeys[NHKF_DOAGAIN] || g.in_doagain) { + } else if ((foo && foo == g.Cmd.spkeys[NHKF_DOAGAIN]) || g.in_doagain) { g.multi = g.last_multi; } else { g.last_multi = g.multi; diff --git a/src/dbridge.c b/src/dbridge.c index ad2b85db8..fd234e801 100644 --- a/src/dbridge.c +++ b/src/dbridge.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 dbridge.c $NHDT-Date: 1503355815 2017/08/21 22:50:15 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.39 $ */ +/* NetHack 3.7 dbridge.c $NHDT-Date: 1596498153 2020/08/03 23:42:33 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.47 $ */ /* Copyright (c) 1989 by Jean-Christophe Collet */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/src/decl.c b/src/decl.c index d390a2dbd..09e6d608a 100644 --- a/src/decl.c +++ b/src/decl.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 decl.c $NHDT-Date: 1593953345 2020/07/05 12:49:05 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.214 $ */ +/* NetHack 3.7 decl.c $NHDT-Date: 1606919256 2020/12/02 14:27:36 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.221 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2009. */ /* NetHack may be freely redistributed. See license for details. */ @@ -270,10 +270,7 @@ const struct instance_globals g_init = { (ROWNO - 1) & ~1, /* y_maze_max */ UNDEFINED_VALUE, /* otg_temp */ 0, /* in_doagain */ - DUMMY, /* dnstair */ - DUMMY, /* upstair */ - DUMMY, /* dnladder */ - DUMMY, /* upladder */ + NULL, /* stairs */ DUMMY, /* smeq */ 0, /* doorindex */ NULL, /* save_cm */ @@ -294,7 +291,6 @@ const struct instance_globals g_init = { UNDEFINED_PTR, /* sp_levchn */ { 0, 0, STRANGE_OBJECT, FALSE }, /* m_shot */ UNDEFINED_VALUES, /* dungeons */ - { 0, 0, { 0, 0 }, 0 }, /* sstairs */ { 0, 0, 0, 0, 0, 0, 0, 0 }, /* updest */ { 0, 0, 0, 0, 0, 0, 0, 0 }, /* dndest */ { 0, 0} , /* inv_pos */ @@ -305,9 +301,6 @@ const struct instance_globals g_init = { FALSE, /* mrg_to_wielded */ NULL, /* plinemsg_types */ UNDEFINED_VALUES, /* toplines */ - UNDEFINED_PTR, /* upstairs_room */ - UNDEFINED_PTR, /* dnstairs_room */ - UNDEFINED_PTR, /* sstairs_room */ DUMMY, /* bhitpos */ FALSE, /* in_steed_dismounting */ DUMMY, /* doors */ @@ -461,9 +454,10 @@ const struct instance_globals g_init = { /* makemon.c */ /* mhitm.c */ - UNDEFINED_VALUE, /* vis */ - UNDEFINED_VALUE, /* far_noise */ - UNDEFINED_VALUE, /* noisetime */ + 0L, /* noisetime */ + FALSE, /* far_noise */ + FALSE, /* vis */ + FALSE, /* skipdrin */ /* mhitu.c */ UNDEFINED_VALUE, /* mhitu_dieroll */ @@ -497,6 +491,7 @@ const struct instance_globals g_init = { /* mon.c */ UNDEFINED_VALUE, /* vamp_rise_msg */ UNDEFINED_VALUE, /* disintegested */ + UNDEFINED_VALUE, /* zombify */ NULL, /* animal_list */ UNDEFINED_VALUE, /* animal_list_count */ @@ -525,17 +520,20 @@ const struct instance_globals g_init = { 0, /* distantname */ /* options.c */ - NULL, /* symset_list */ + (struct symsetentry *) 0, /* symset_list */ UNDEFINED_VALUES, /* mapped_menu_cmds */ UNDEFINED_VALUES, /* mapped_menu_op */ 0, /* n_menu_mapped */ - UNDEFINED_VALUE, /* opt_initial */ - UNDEFINED_VALUE, /* opt_from_file */ - UNDEFINED_VALUE, /* opt_need_redraw */ + FALSE, /* opt_initial */ + FALSE, /* opt_from_file */ + FALSE, /* opt_need_redraw */ + FALSE, /* save_menucolors */ + (struct menucoloring *) 0, /* save_colorings */ + (struct menucoloring *) 0, /* color_colorings */ /* pickup.c */ 0, /* oldcap */ - UNDEFINED_PTR, /* current_container */ + (struct obj *) 0, /* current_container */ UNDEFINED_VALUE, /* abort_looting */ UNDEFINED_VALUE, /* val_for_n_or_more */ UNDEFINED_VALUES, /* valid_menu_classes */ @@ -550,7 +548,7 @@ const struct instance_globals g_init = { 0, /* saved_pline_index */ UNDEFINED_VALUES, #endif - NULL, /* you_buf */ + (char *) 0, /* you_buf */ 0, /* you_buf_siz */ /* polyself.c */ @@ -613,6 +611,8 @@ const struct instance_globals g_init = { TRUE, /* havestate*/ 0, /* ustuck_id */ 0, /* usteed_id */ + (struct obj *) 0, /* looseball */ + (struct obj *) 0, /* loosechain */ /* shk.c */ 'a', /* sell_response */ @@ -642,7 +642,6 @@ const struct instance_globals g_init = { 0, /* stealmid */ /* teleport.c */ - NULL, /* telescroll */ /* timeout.c */ UNDEFINED_PTR, /* timer_base */ diff --git a/src/detect.c b/src/detect.c index 427adbe23..efb56d7b3 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 detect.c $NHDT-Date: 1586815085 2020/04/13 21:58:05 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.118 $ */ +/* NetHack 3.7 detect.c $NHDT-Date: 1606009000 2020/11/22 01:36:40 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.123 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2018. */ /* NetHack may be freely redistributed. See license for details. */ @@ -13,6 +13,7 @@ static boolean NDECL(unconstrain_map); static void NDECL(reconstrain_map); +static void NDECL(map_redisplay); static void FDECL(browse_map, (int, const char *)); static void FDECL(map_monst, (struct monst *, BOOLEAN_P)); static void FDECL(do_dknown_of, (struct obj *)); @@ -52,6 +53,17 @@ reconstrain_map() u.uswallow = iflags.save_uswallow, iflags.save_uswallow = 0; } +static void +map_redisplay() +{ + reconstrain_map(); + docrt(); /* redraw the screen to remove unseen traps from the map */ + if (Underwater) + under_water(2); + if (u.uburied) + under_ground(2); +} + /* use getpos()'s 'autodescribe' to view whatever is currently shown on map */ static void browse_map(ter_typ, ter_explain) @@ -357,7 +369,7 @@ register struct obj *sobj; if (g.youmonst.data == &mons[PM_GOLD_GOLEM]) Sprintf(buf, "You feel like a million %s!", currency(2L)); - else if (money_cnt(g.invent) || hidden_gold()) + else if (money_cnt(g.invent) || hidden_gold(TRUE)) Strcpy(buf, "You feel worried about your future financial situation."); else if (steedgold) @@ -440,12 +452,7 @@ register struct obj *sobj; browse_map(ter_typ, "gold"); - reconstrain_map(); - docrt(); - if (Underwater) - under_water(2); - if (u.uburied) - under_ground(2); + map_redisplay(); return 0; } @@ -564,12 +571,7 @@ register struct obj *sobj; browse_map(ter_typ, "food"); - reconstrain_map(); - docrt(); - if (Underwater) - under_water(2); - if (u.uburied) - under_ground(2); + map_redisplay(); } return 0; } @@ -765,12 +767,7 @@ int class; /* an object class, 0 for all */ else browse_map(ter_typ, "object"); - reconstrain_map(); - docrt(); /* this will correctly reset vision */ - if (Underwater) - under_water(2); - if (u.uburied) - under_ground(2); + map_redisplay(); return 0; } @@ -844,12 +841,7 @@ int mclass; /* monster class, 0 for all */ EDetect_monsters &= ~I_SPECIAL; } - reconstrain_map(); - docrt(); /* redraw the screen to remove unseen monsters from map */ - if (Underwater) - under_water(2); - if (u.uburied) - under_ground(2); + map_redisplay(); } return 0; } @@ -1032,12 +1024,7 @@ struct obj *sobj; /* null if crystal ball, *scroll if gold detection scroll */ browse_map(ter_typ, "trap of interest"); - reconstrain_map(); - docrt(); /* redraw the screen to remove unseen traps from the map */ - if (Underwater) - under_water(2); - if (u.uburied) - under_ground(2); + map_redisplay(); return 0; } @@ -1082,12 +1069,7 @@ furniture_detect() browse_map(TER_DETECT | TER_MAP | TER_TRP | TER_OBJ | TER_MON, "location"); - reconstrain_map(); - docrt(); /* redraw everything */ - if (Underwater) - under_water(2); - if (u.uburied) - under_ground(2); + map_redisplay(); return 0; } @@ -1868,17 +1850,10 @@ register int aflag; /* intrinsic autosearch vs explicit searching */ int dosearch() { - if (!iflags.menu_requested && !g.multi && monster_nearby()) { - char buf[QBUFSZ]; - - buf[0] = '\0'; - if (iflags.cmdassist || !g.already_found_flag++) - Sprintf(buf, " Use '%s' prefix to force another search.", - visctrl(g.Cmd.spkeys[NHKF_REQMENU])); /* default is "m" */ - Norep("You already found a monster.%s", buf); + if (cmd_safety_prevention("another search", + "You already found a monster.", + &g.already_found_flag)) return 0; - } - g.already_found_flag = 0; /* start over */ return dosearch0(0); } @@ -2013,7 +1988,7 @@ dump_map() int x, y, glyph, skippedrows, lastnonblank; int subset = TER_MAP | TER_TRP | TER_OBJ | TER_MON; int default_glyph = cmap_to_glyph(g.level.flags.arboreal ? S_tree : S_stone); - char buf[BUFSZ]; + char buf[COLBUFSZ]; boolean blankrow, toprow; /* @@ -2030,12 +2005,13 @@ dump_map() blankrow = TRUE; /* assume blank until we discover otherwise */ lastnonblank = -1; /* buf[] index rather than map's x */ for (x = 1; x < COLNO; x++) { - int ch, color; - unsigned special; + int ch; + unsigned glyphmod[NUM_GLYPHMOD]; glyph = reveal_terrain_getglyph(x, y, FALSE, u.uswallow, default_glyph, subset); - (void) mapglyph(glyph, &ch, &color, &special, x, y, 0); + map_glyphmod(x, y, glyph, 0, glyphmod); + ch = (int) glyphmod[GM_TTYCHAR]; buf[x - 1] = ch; if (ch != ' ') { blankrow = FALSE; @@ -2115,14 +2091,20 @@ int which_subset; /* when not full, whether to suppress objs and/or traps */ which_subset |= TER_MAP; /* guarantee non-zero */ browse_map(which_subset, "anything of interest"); - reconstrain_map(); - docrt(); /* redraw the screen, restoring regular map */ - if (Underwater) - under_water(2); - if (u.uburied) - under_ground(2); + map_redisplay(); } return; } +int +wiz_mgender(VOID_ARGS) +{ + iflags.wizmgender = !iflags.wizmgender; + pline("wizmgender toggled %s", iflags.wizmgender ? "on" : "off"); + if (!u.uswallow) + see_monsters(); + map_redisplay(); + return 0; /* no time */ +} + /*detect.c*/ diff --git a/src/dig.c b/src/dig.c index ad565aac7..15553d11b 100644 --- a/src/dig.c +++ b/src/dig.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 dig.c $NHDT-Date: 1584350347 2020/03/16 09:19:07 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.138 $ */ +/* NetHack 3.7 dig.c $NHDT-Date: 1596498156 2020/08/03 23:42:36 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.142 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -13,6 +13,7 @@ static int NDECL(dig); static void FDECL(dig_up_grave, (coord *)); static int FDECL(adj_pit_checks, (coord *, char *)); static void FDECL(pit_flow, (struct trap *, SCHAR_P)); +static boolean FDECL(furniture_handled, (int, int, BOOLEAN_P)); /* Indices returned by dig_typ() */ enum dig_types { @@ -188,7 +189,8 @@ int x, y; (madeby == BY_YOU && uwep && is_axe(uwep)) ? "chop" : "dig in"; if (On_stairs(x, y)) { - if (x == xdnladder || x == xupladder) { + stairway *stway = stairway_at(x, y); + if (stway->isladder) { if (verbose) pline_The("ladder resists your effort."); } else if (verbose) @@ -488,6 +490,33 @@ dig(VOID_ARGS) return 1; } +static boolean +furniture_handled(x, y, madeby_u) +int x, y; +boolean madeby_u; +{ + struct rm *lev = &levl[x][y]; + + if (IS_FOUNTAIN(lev->typ)) { + dogushforth(FALSE); + SET_FOUNTAIN_WARNED(x, y); /* force dryup */ + dryup(x, y, madeby_u); + } else if (IS_SINK(lev->typ)) { + breaksink(x, y); + } else if (lev->typ == DRAWBRIDGE_DOWN + || (is_drawbridge_wall(x, y) >= 0)) { + int bx = x, by = y; + + /* if under the portcullis, the bridge is adjacent */ + (void) find_drawbridge(&bx, &by); + destroy_drawbridge(bx, by); + } else { + return FALSE; + } + return TRUE; +} + + /* When will hole be finished? Very rough indication used by shopkeeper. */ int holetime() @@ -557,25 +586,8 @@ int ttyp; reset_utrap(FALSE); } - /* these furniture checks were in dighole(), but wand - breaking bypasses that routine and calls us directly */ - if (IS_FOUNTAIN(lev->typ)) { - dogushforth(FALSE); - SET_FOUNTAIN_WARNED(x, y); /* force dryup */ - dryup(x, y, madeby_u); + if (furniture_handled(x, y, madeby_u)) return; - } else if (IS_SINK(lev->typ)) { - breaksink(x, y); - return; - } else if (lev->typ == DRAWBRIDGE_DOWN - || (is_drawbridge_wall(x, y) >= 0)) { - int bx = x, by = y; - - /* if under the portcullis, the bridge is adjacent */ - (void) find_drawbridge(&bx, &by); - destroy_drawbridge(bx, by); - return; - } if (ttyp != PIT && (!Can_dig_down(&u.uz) && !lev->candig)) { impossible("digactualhole: can't dig %s on this level.", @@ -875,9 +887,11 @@ coord *cc; lev->flags = 0; if (typ != ROOM) { - lev->typ = typ; - liquid_flow(dig_x, dig_y, typ, ttmp, - "As you dig, the hole fills with %s!"); + if (!furniture_handled((int) dig_x, (int) dig_y, TRUE)) { + lev->typ = typ; + liquid_flow(dig_x, dig_y, typ, ttmp, + "As you dig, the hole fills with %s!"); + } return TRUE; } @@ -1431,12 +1445,12 @@ zap_dig() if (!Is_airlevel(&u.uz) && !Is_waterlevel(&u.uz) && !Underwater) { if (u.dz < 0 || On_stairs(u.ux, u.uy)) { int dmg; - if (On_stairs(u.ux, u.uy)) + if (On_stairs(u.ux, u.uy)) { + stairway *stway = stairway_at(u.ux, u.uy); pline_The("beam bounces off the %s and hits the %s.", - (u.ux == xdnladder || u.ux == xupladder) - ? "ladder" - : "stairs", + stway->isladder ? "ladder" : "stairs", ceiling(u.ux, u.uy)); + } You("loosen a rock from the %s.", ceiling(u.ux, u.uy)); pline("It falls on your %s!", body_part(HEAD)); dmg = rnd((uarmh && is_metallic(uarmh)) ? 2 : 6); diff --git a/src/display.c b/src/display.c index 482e9f901..ea7c4080e 100644 --- a/src/display.c +++ b/src/display.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 display.c $NHDT-Date: 1587248921 2020/04/18 22:28:41 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.131 $ */ +/* NetHack 3.7 display.c $NHDT-Date: 1609101156 2020/12/27 20:32:36 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.141 $ */ /* Copyright (c) Dean Luick, with acknowledgements to Kevin Darcy */ /* and Dave Cohrs, 1990. */ /* NetHack may be freely redistributed. See license for details. */ @@ -132,6 +132,9 @@ static void FDECL(display_warning, (struct monst *)); static int FDECL(check_pos, (int, int, int)); static int FDECL(get_bk_glyph, (XCHAR_P, XCHAR_P)); static int FDECL(tether_glyph, (int, int)); +#ifdef UNBUFFERED_GLYPHMOD +static unsigned *FDECL(glyphmod_at, (XCHAR_P, XCHAR_P, int)); +#endif /*#define WA_VERBOSE*/ /* give (x,y) locations for all "bad" spots */ #ifdef WA_VERBOSE @@ -1339,9 +1342,16 @@ void see_objects() { register struct obj *obj; + for (obj = fobj; obj; obj = obj->nobj) if (vobj_at(obj->ox, obj->oy) == obj) newsym(obj->ox, obj->oy); + + /* Qt's "paper doll" subset of persistent inventory shows map tiles + for objects which aren't on the floor so not handled by above loop; + inventory which includes glyphs should also be affected, so do this + for all interfaces in case any feature that for persistent inventory */ + update_inventory(); } /* @@ -1360,6 +1370,18 @@ see_traps() } } +static unsigned no_gm[NUM_GLYPHMOD] = { + MG_BADXY, (unsigned) ' ', (unsigned) NO_COLOR +}; +#ifndef UNBUFFERED_GLYPHMOD +#define Glyphmod_at(x, y, glyph) \ + (((x) < 0 || (y) < 0 || (x) >= COLNO || (y) >= ROWNO) ? &no_gm[0] \ + : &g.gbuf[(y)][(x)].glyphmod[0]) +#else +static unsigned gm[NUM_GLYPHMOD]; +#define Glyphmod_at(x, y, glyph) glyphmod_at(x, y, glyph) +#endif + /* * Put the cursor on the hero. Flush all accumulated glyphs before doing it. */ @@ -1455,7 +1477,8 @@ redraw_map() for (y = 0; y < ROWNO; ++y) for (x = 1; x < COLNO; ++x) { glyph = glyph_at(x, y); /* not levl[x][y].glyph */ - print_glyph(WIN_MAP, x, y, glyph, get_bk_glyph(x, y)); + print_glyph(WIN_MAP, x, y, glyph, get_bk_glyph(x, y), + Glyphmod_at(x, y, glyph)); } flush_screen(1); } @@ -1517,6 +1540,10 @@ void show_glyph(x, y, glyph) int x, y, glyph; { +#ifndef UNBUFFERED_GLYPHMOD + unsigned glyphmod[NUM_GLYPHMOD]; +#endif + /* * Check for bad positions and glyphs. */ @@ -1571,7 +1598,6 @@ int x, y, glyph; text = "monster"; offset = glyph; } - impossible("show_glyph: bad pos %d %d with glyph %d [%s %d].", x, y, glyph, text, offset); return; @@ -1582,10 +1608,27 @@ int x, y, glyph; MAX_GLYPH, x, y); return; } +#ifndef UNBUFFERED_GLYPHMOD + /* without UNBUFFERED_GLYPHMOD defined the glyphmod values are buffered + alongside the glyphs themselves for better performance, increased + buffer size */ + map_glyphmod(x, y, glyph, 0, glyphmod); +#endif - if (g.gbuf[y][x].glyph != glyph || iflags.use_background_glyph) { + if (g.gbuf[y][x].glyph != glyph +#ifndef UNBUFFERED_GLYPHMOD + /* I don't think we have to test for changes in TTYCHAR or COLOR + because they typically only change if the glyph changed */ + || g.gbuf[y][x].glyphmod[GM_FLAGS] != glyphmod[GM_FLAGS] +#endif + || iflags.use_background_glyph ) { g.gbuf[y][x].glyph = glyph; g.gbuf[y][x].gnew = 1; +#ifndef UNBUFFERED_GLYPHMOD + g.gbuf[y][x].glyphmod[GM_FLAGS] = glyphmod[GM_FLAGS]; + g.gbuf[y][x].glyphmod[GM_TTYCHAR] = glyphmod[GM_TTYCHAR]; + g.gbuf[y][x].glyphmod[GM_COLOR] = glyphmod[GM_COLOR]; +#endif if (g.gbuf_start[y] > x) g.gbuf_start[y] = x; if (g.gbuf_stop[y] < x) @@ -1607,6 +1650,14 @@ int x, y, glyph; } \ } +static gbuf_entry nul_gbuf = { + 0, /* gnew */ + GLYPH_UNEXPLORED, /* glyph */ +#ifndef UNBUFFERED_GLYPHMOD + {(unsigned) ' ', (unsigned) NO_COLOR, MG_UNEXPL}, +#endif +}; + /* * Turn the 3rd screen into UNEXPLORED that needs to be refreshed. */ @@ -1614,15 +1665,25 @@ void clear_glyph_buffer() { register int x, y; - register gbuf_entry *gptr, nul_gbuf; - int ch = ' ', color = NO_COLOR; - unsigned special = 0; - - (void) mapglyph(GLYPH_UNEXPLORED, &ch, &color, &special, 0, 0, 0); - nul_gbuf.gnew = (ch != ' ' || color != NO_COLOR - || (special & ~MG_UNEXPL) != 0) ? 1 : 0; - nul_gbuf.glyph = GLYPH_UNEXPLORED; + gbuf_entry *gptr = &g.gbuf[0][0]; + unsigned *gmptr = +#ifndef UNBUFFERED_GLYPHMOD + &gptr->glyphmod[0]; +#else + &gm[0]; + map_glyphmod(0, 0, GLYPH_UNEXPLORED, 0, gmptr); +#endif +#ifndef UNBUFFERED_GLYPHMOD + nul_gbuf.gnew = (gmptr[GM_TTYCHAR] != nul_gbuf.glyphmod[GM_TTYCHAR] + || gmptr[GM_COLOR] != nul_gbuf.glyphmod[GM_COLOR] + || gmptr[GM_FLAGS] != nul_gbuf.glyphmod[GM_FLAGS]) +#else + nul_gbuf.gnew = (gmptr[GM_TTYCHAR] != ' ' + || gmptr[GM_COLOR] != NO_COLOR + || (gmptr[GM_FLAGS] & ~MG_UNEXPL) != 0) +#endif + ? 1 : 0; for (y = 0; y < ROWNO; y++) { gptr = &g.gbuf[y][0]; for (x = COLNO; x; x--) { @@ -1641,16 +1702,31 @@ int start, stop, y; { register int x, glyph; register boolean force; - int ch = ' ', color = NO_COLOR; - unsigned special = 0; - - (void) mapglyph(GLYPH_UNEXPLORED, &ch, &color, &special, 0, 0, 0); - force = (ch != ' ' || color != NO_COLOR || (special & ~MG_UNEXPL) != 0); + gbuf_entry *gptr = &g.gbuf[0][0]; + unsigned *gmptr = +#ifndef UNBUFFERED_GLYPHMOD + &gptr->glyphmod[0]; +#else + &gm[0]; + map_glyphmod(0, 0, GLYPH_UNEXPLORED, 0, gmptr); +#endif +#ifndef UNBUFFERED_GLYPHMOD + force = (gmptr[GM_TTYCHAR] != nul_gbuf.glyphmod[GM_TTYCHAR] + || gmptr[GM_COLOR] != nul_gbuf.glyphmod[GM_COLOR] + || gmptr[GM_FLAGS] != nul_gbuf.glyphmod[GM_FLAGS]) +#else + force = (gmptr[GM_TTYCHAR] != ' ' + || gmptr[GM_COLOR] != NO_COLOR + || (gmptr[GM_FLAGS] & ~MG_UNEXPL) != 0) +#endif + ? 1 : 0; for (x = start; x <= stop; x++) { - glyph = g.gbuf[y][x].glyph; + gptr = &g.gbuf[y][x]; + glyph = gptr->glyph; if (force || glyph != GLYPH_UNEXPLORED) - print_glyph(WIN_MAP, x, y, glyph, get_bk_glyph(x, y)); + print_glyph(WIN_MAP, x, y, glyph, + get_bk_glyph(x, y), Glyphmod_at(x, y, glyph)); } } @@ -1684,6 +1760,10 @@ int cursor_on_u; static int delay_flushing = 0; register int x, y; + /* 3.7: don't update map, status, or perm_invent during save/restore */ + if (g.program_state.saving || g.program_state.restoring) + return; + if (cursor_on_u == -1) delay_flushing = !delay_flushing; if (delay_flushing) @@ -1701,7 +1781,8 @@ int cursor_on_u; for (; x <= g.gbuf_stop[y]; gptr++, x++) if (gptr->gnew) { - print_glyph(WIN_MAP, x, y, gptr->glyph, get_bk_glyph(x, y)); + print_glyph(WIN_MAP, x, y, gptr->glyph, + get_bk_glyph(x, y), Glyphmod_at(x, y, gptr->glyph)); gptr->gnew = 0; } } @@ -1919,6 +2000,17 @@ xchar x, y; return g.gbuf[y][x].glyph; } +#ifdef UNBUFFERED_GLYPHMOD +unsigned * +glyphmod_at(x, y, glyph) +xchar x, y; +int glyph; +{ + map_glyphmod(x, y, glyph, 0, gm); + return &gm[0]; +} +#endif + /* * This will be used to get the glyph for the background so that * it can potentially be merged into graphical window ports to @@ -1991,6 +2083,362 @@ xchar x, y; return bkglyph; } +#define HI_DOMESTIC CLR_WHITE /* monst.c */ +#ifdef TEXTCOLOR +static const int explcolors[] = { + CLR_BLACK, /* dark */ + CLR_GREEN, /* noxious */ + CLR_BROWN, /* muddy */ + CLR_BLUE, /* wet */ + CLR_MAGENTA, /* magical */ + CLR_ORANGE, /* fiery */ + CLR_WHITE, /* frosty */ +}; + +#define zap_color(n) color = iflags.use_color ? zapcolors[n] : NO_COLOR +#define cmap_color(n) color = iflags.use_color ? defsyms[n].color : NO_COLOR +#define obj_color(n) color = iflags.use_color ? objects[n].oc_color : NO_COLOR +#define mon_color(n) color = iflags.use_color ? mons[n].mcolor : NO_COLOR +#define invis_color(n) color = NO_COLOR +#define pet_color(n) color = iflags.use_color ? mons[n].mcolor : NO_COLOR +#define warn_color(n) \ + color = iflags.use_color ? def_warnsyms[n].color : NO_COLOR +#define explode_color(n) color = iflags.use_color ? explcolors[n] : NO_COLOR + +#else /* no text color */ + +#define zap_color(n) +#define cmap_color(n) +#define obj_color(n) +#define mon_color(n) +#define invis_color(n) +#define pet_color(c) +#define warn_color(n) +#define explode_color(n) +#endif + +#if defined(USE_TILES) && defined(MSDOS) +#define HAS_ROGUE_IBM_GRAPHICS \ + (g.currentgraphics == ROGUESET && SYMHANDLING(H_IBM) && !iflags.grmode) +#else +#define HAS_ROGUE_IBM_GRAPHICS \ + (g.currentgraphics == ROGUESET && SYMHANDLING(H_IBM)) +#endif + +#define is_objpile(x,y) (!Hallucination && g.level.objects[(x)][(y)] \ + && g.level.objects[(x)][(y)]->nexthere) + +#define GMAP_SET 0x00000001 +#define GMAP_ROGUELEVEL 0x00000002 +#define GMAP_ALTARCOLOR 0x00000004 + +void +map_glyphmod(x, y, glyph, mgflags, glyphmod) +xchar x, y; +int glyph; +unsigned mgflags, *glyphmod; +{ + register int offset, idx; + int color = NO_COLOR; + unsigned special = 0; + struct obj *obj; /* only used for STATUE */ + + /* condense multiple tests in macro version down to single */ + boolean has_rogue_ibm_graphics = HAS_ROGUE_IBM_GRAPHICS, + is_you = (x == u.ux && y == u.uy), + has_rogue_color = (has_rogue_ibm_graphics + && g.symset[g.currentgraphics].nocolor == 0), + do_mon_checks = FALSE; + + if (x < 0 || y < 0 || x >= COLNO || y >= ROWNO) { + glyphmod[GM_FLAGS] = MG_BADXY; + glyphmod[GM_COLOR] = NO_COLOR; + glyphmod[GM_TTYCHAR] = ' '; + return; + } + + if (!g.glyphmap_perlevel_flags) { + /* + * GMAP_SET 0x00000001 + * GMAP_ROGUELEVEL 0x00000002 + * GMAP_ALTARCOLOR 0x00000004 + */ + g.glyphmap_perlevel_flags |= GMAP_SET; + + if (Is_rogue_level(&u.uz)) { + g.glyphmap_perlevel_flags |= GMAP_ROGUELEVEL; + } else if ((Is_astralevel(&u.uz) || Is_sanctum(&u.uz))) { + g.glyphmap_perlevel_flags |= GMAP_ALTARCOLOR; + } + } + + /* + * Map the glyph to a character and color. + * + * Warning: For speed, this makes an assumption on the order of + * offsets. The order is set in display.h. + */ + if ((offset = (glyph - GLYPH_NOTHING_OFF)) >= 0) { + idx = SYM_NOTHING + SYM_OFF_X; + color = NO_COLOR; + special |= MG_NOTHING; + } else if ((offset = (glyph - GLYPH_UNEXPLORED_OFF)) >= 0) { + idx = SYM_UNEXPLORED + SYM_OFF_X; + color = NO_COLOR; + special |= MG_UNEXPL; + } else if ((offset = (glyph - GLYPH_STATUE_OFF)) >= 0) { /* a statue */ + idx = mons[offset].mlet + SYM_OFF_M; + if (has_rogue_color) + color = CLR_RED; + else + obj_color(STATUE); + special |= MG_STATUE; + if (is_objpile(x,y)) + special |= MG_OBJPILE; + if ((obj = sobj_at(STATUE, x, y)) && (obj->spe & STATUE_FEMALE)) + special |= MG_FEMALE; + } else if ((offset = (glyph - GLYPH_WARNING_OFF)) >= 0) { /* warn flash */ + idx = offset + SYM_OFF_W; + if (has_rogue_color) + color = NO_COLOR; + else + warn_color(offset); + } else if ((offset = (glyph - GLYPH_SWALLOW_OFF)) >= 0) { /* swallow */ + /* see swallow_to_glyph() in display.c */ + idx = (S_sw_tl + (offset & 0x7)) + SYM_OFF_P; + if (has_rogue_color && iflags.use_color) + color = NO_COLOR; + else + mon_color(offset >> 3); + } else if ((offset = (glyph - GLYPH_ZAP_OFF)) >= 0) { /* zap beam */ + /* see zapdir_to_glyph() in display.c */ + idx = (S_vbeam + (offset & 0x3)) + SYM_OFF_P; + if (has_rogue_color && iflags.use_color) + color = NO_COLOR; + else + zap_color((offset >> 2)); + } else if ((offset = (glyph - GLYPH_EXPLODE_OFF)) >= 0) { /* explosion */ + idx = ((offset % MAXEXPCHARS) + S_explode1) + SYM_OFF_P; + explode_color(offset / MAXEXPCHARS); + } else if ((offset = (glyph - GLYPH_CMAP_OFF)) >= 0) { /* cmap */ + idx = offset + SYM_OFF_P; + if (has_rogue_color && iflags.use_color) { + if (offset >= S_vwall && offset <= S_hcdoor) + color = CLR_BROWN; + else if (offset >= S_arrow_trap && offset <= S_polymorph_trap) + color = CLR_MAGENTA; + else if (offset == S_corr || offset == S_litcorr) + color = CLR_GRAY; + else if (offset >= S_room && offset <= S_water + && offset != S_darkroom) + color = CLR_GREEN; + else + color = NO_COLOR; +#ifdef TEXTCOLOR + /* provide a visible difference if normal and lit corridor + use the same symbol */ + } else if (iflags.use_color && offset == S_litcorr + && g.showsyms[idx] == g.showsyms[S_corr + SYM_OFF_P]) { + color = CLR_WHITE; +#endif + /* try to provide a visible difference between water and lava + if they use the same symbol and color is disabled */ + } else if (!iflags.use_color && offset == S_lava + && (g.showsyms[idx] == g.showsyms[S_pool + SYM_OFF_P] + || g.showsyms[idx] + == g.showsyms[S_water + SYM_OFF_P])) { + special |= MG_BW_LAVA; + /* similar for floor [what about empty doorway?] and ice */ + } else if (!iflags.use_color && offset == S_ice + && (g.showsyms[idx] == g.showsyms[S_room + SYM_OFF_P] + || g.showsyms[idx] + == g.showsyms[S_darkroom + SYM_OFF_P])) { + special |= MG_BW_ICE; + } else if (offset == S_altar && iflags.use_color) { + int amsk = altarmask_at(x, y); /* might be a mimic */ + + if ((g.glyphmap_perlevel_flags & GMAP_ALTARCOLOR) + && (amsk & AM_SHRINE) != 0) { + /* high altar */ + color = CLR_BRIGHT_MAGENTA; + } else { + switch (amsk & AM_MASK) { +#if 0 /* + * On OSX with TERM=xterm-color256 these render as + * white -> tty: gray, curses: ok + * gray -> both tty and curses: black + * black -> both tty and curses: blue + * red -> both tty and curses: ok. + * Since the colors have specific associations (with the + * unicorns matched with each alignment), we shouldn't use + * scrambled colors and we don't have sufficient information + * to handle platform-specific color variations. + */ + case AM_LAWFUL: /* 4 */ + color = CLR_WHITE; + break; + case AM_NEUTRAL: /* 2 */ + color = CLR_GRAY; + break; + case AM_CHAOTIC: /* 1 */ + color = CLR_BLACK; + break; +#else /* !0: TEMP? */ + case AM_LAWFUL: /* 4 */ + case AM_NEUTRAL: /* 2 */ + case AM_CHAOTIC: /* 1 */ + cmap_color(S_altar); /* gray */ + break; +#endif /* 0 */ + case AM_NONE: /* 0 */ + color = CLR_RED; + break; + default: /* 3, 5..7 -- shouldn't happen but 3 was possible + * prior to 3.6.3 (due to faulty sink polymorph) */ + color = NO_COLOR; + break; + } + } + } else { + cmap_color(offset); + } + } else if ((offset = (glyph - GLYPH_OBJ_OFF)) >= 0) { /* object */ + idx = objects[offset].oc_class + SYM_OFF_O; + if (offset == BOULDER) + idx = SYM_BOULDER + SYM_OFF_X; + if (has_rogue_color && iflags.use_color) { + switch (objects[offset].oc_class) { + case COIN_CLASS: + color = CLR_YELLOW; + break; + case FOOD_CLASS: + color = CLR_RED; + break; + default: + color = CLR_BRIGHT_BLUE; + break; + } + } else + obj_color(offset); + if (offset != BOULDER && is_objpile(x,y)) + special |= MG_OBJPILE; + } else if ((offset = (glyph - GLYPH_RIDDEN_OFF)) >= 0) { /* mon ridden */ + idx = mons[offset].mlet + SYM_OFF_M; + if (has_rogue_color) + /* This currently implies that the hero is here -- monsters */ + /* don't ride (yet...). Should we set it to yellow like in */ + /* the monster case below? There is no equivalent in rogue. */ + color = NO_COLOR; /* no need to check iflags.use_color */ + else + mon_color(offset); + special |= MG_RIDDEN; + do_mon_checks = TRUE; + } else if ((offset = (glyph - GLYPH_BODY_OFF)) >= 0) { /* a corpse */ + idx = objects[CORPSE].oc_class + SYM_OFF_O; + if (has_rogue_color && iflags.use_color) + color = CLR_RED; + else + mon_color(offset); + special |= MG_CORPSE; + if (is_objpile(x,y)) + special |= MG_OBJPILE; + } else if ((offset = (glyph - GLYPH_DETECT_OFF)) >= 0) { /* mon detect */ + idx = mons[offset].mlet + SYM_OFF_M; + if (has_rogue_color) + color = NO_COLOR; /* no need to check iflags.use_color */ + else + mon_color(offset); + /* Disabled for now; anyone want to get reverse video to work? */ + /* is_reverse = TRUE; */ + special |= MG_DETECT; + do_mon_checks = TRUE; + } else if ((offset = (glyph - GLYPH_INVIS_OFF)) >= 0) { /* invisible */ + idx = SYM_INVISIBLE + SYM_OFF_X; + if (has_rogue_color) + color = NO_COLOR; /* no need to check iflags.use_color */ + else + invis_color(offset); + special |= MG_INVIS; + } else if ((offset = (glyph - GLYPH_PET_OFF)) >= 0) { /* a pet */ + idx = mons[offset].mlet + SYM_OFF_M; + if (has_rogue_color) + color = NO_COLOR; /* no need to check iflags.use_color */ + else + pet_color(offset); + special |= MG_PET; + do_mon_checks = TRUE; + } else { /* a monster */ + idx = mons[glyph].mlet + SYM_OFF_M; + if (has_rogue_color && iflags.use_color) { + if (is_you) + /* actually player should be yellow-on-gray if in corridor */ + color = CLR_YELLOW; + else + color = NO_COLOR; + } else { + mon_color(glyph); +#ifdef TEXTCOLOR + /* special case the hero for `showrace' option */ + if (iflags.use_color && is_you && flags.showrace && !Upolyd) + color = HI_DOMESTIC; +#endif + } + do_mon_checks = TRUE; + } + + if (do_mon_checks) { + struct monst *m; + + if (is_you) { + if (Ugender == FEMALE) + special |= MG_FEMALE; + } else { + /* when hero is riding, steed will be shown at hero's location + but has not been placed on the map so m_at() won't find it */ + m = (x == u.ux && y == u.uy && u.usteed) ? u.usteed : m_at(x, y); + if (m) { + if (!Hallucination) { + if (m->female) + special |= MG_FEMALE; + } else if (rn2_on_display_rng(2)) { + special |= MG_FEMALE; + } + } + } + } + /* These were requested by a blind player to enhance screen reader use */ + if (sysopt.accessibility == 1 && !(mgflags & MG_FLAG_NOOVERRIDE)) { + int ovidx; + + if ((special & MG_PET) != 0) { + ovidx = SYM_PET_OVERRIDE + SYM_OFF_X; + if ((g.glyphmap_perlevel_flags & GMAP_ROGUELEVEL) + ? g.ov_rogue_syms[ovidx] + : g.ov_primary_syms[ovidx]) + idx = ovidx; + } + if (is_you) { + ovidx = SYM_HERO_OVERRIDE + SYM_OFF_X; + if ((g.glyphmap_perlevel_flags & GMAP_ROGUELEVEL) + ? g.ov_rogue_syms[ovidx] + : g.ov_primary_syms[ovidx]) + idx = ovidx; + } + } + + glyphmod[GM_TTYCHAR] = ((mgflags & MG_FLAG_RETURNIDX) != 0) ? idx + : g.showsyms[idx]; + +#ifdef TEXTCOLOR + /* Turn off color if no color defined, or rogue level w/o PC graphics. */ + if (!has_color(color) + || ((g.glyphmap_perlevel_flags & GMAP_ROGUELEVEL) && !has_rogue_color)) +#endif + color = NO_COLOR; + glyphmod[GM_COLOR] = color; + glyphmod[GM_FLAGS] = special; +} + /* ------------------------------------------------------------------------ */ /* Wall Angle ------------------------------------------------------------- */ @@ -2068,17 +2516,15 @@ int x, y, a, b, c; /* Return the wall mode for a T wall. */ static int set_twall(x0, y0, x1, y1, x2, y2, x3, y3) +#ifdef WA_VERBOSE int x0, y0; /* used #if WA_VERBOSE */ +#else +int x0 UNUSED, y0 UNUSED; +#endif int x1, y1, x2, y2, x3, y3; { int wmode, is_1, is_2, is_3; -#ifndef WA_VERBOSE - /* non-verbose more_than_one() doesn't use these */ - nhUse(x0); - nhUse(y0); -#endif - is_1 = check_pos(x1, y1, WM_T_LONG); is_2 = check_pos(x2, y2, WM_T_BL); is_3 = check_pos(x3, y3, WM_T_BR); diff --git a/src/dlb.c b/src/dlb.c index 8d4439894..a2bb28bdb 100644 --- a/src/dlb.c +++ b/src/dlb.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 dlb.c $NHDT-Date: 1446975464 2015/11/08 09:37:44 $ $NHDT-Branch: master $:$NHDT-Revision: 1.15 $ */ +/* NetHack 3.7 dlb.c $NHDT-Date: 1596498157 2020/08/03 23:42:37 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.20 $ */ /* Copyright (c) Kenneth Lorber, Bethesda, Maryland, 1993. */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/src/do.c b/src/do.c index c1601bbdd..5807b8675 100644 --- a/src/do.c +++ b/src/do.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 do.c $NHDT-Date: 1593953347 2020/07/05 12:49:07 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.246 $ */ +/* NetHack 3.7 do.c $NHDT-Date: 1608673689 2020/12/22 21:48:09 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.256 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Derek S. Ray, 2015. */ /* NetHack may be freely redistributed. See license for details. */ @@ -254,6 +254,8 @@ deletedwithboulder: pline("%s %s into %s %s.", The(xname(obj)), otense(obj, "tumble"), the_your[t->madeby_u], is_pit(t->ttyp) ? "pit" : "hole"); + if (is_hole(t->ttyp) && ship_object(obj, x, y, FALSE)) + return TRUE; } else if (obj->globby) { /* Globby things like puddings might stick together */ while (obj && (otmp = obj_nexto_xy(obj, x, y, TRUE)) != 0) { @@ -698,8 +700,6 @@ boolean with_impact; if (obj == uswapwep) setuswapwep((struct obj *) 0); - if (!u.uswallow && flooreffects(obj, u.ux, u.uy, "drop")) - return; if (u.uswallow) { /* hero has dropped an item while inside an engulfer */ if (obj != uball) { /* mon doesn't pick up ball */ @@ -711,6 +711,8 @@ boolean with_impact; (void) mpickobj(u.ustuck, obj); } } else { + if (flooreffects(obj, u.ux, u.uy, "drop")) + return; place_object(obj, u.ux, u.uy); if (with_impact) container_impact_dmg(obj, u.ux, u.uy); @@ -845,8 +847,9 @@ int retry; } else if (flags.menu_style == MENU_FULL) { all_categories = FALSE; n = query_category("Drop what type of items?", g.invent, - UNPAID_TYPES | ALL_TYPES | CHOOSE_ALL | BUC_BLESSED - | BUC_CURSED | BUC_UNCURSED | BUC_UNKNOWN, + (UNPAID_TYPES | ALL_TYPES | CHOOSE_ALL + | BUC_BLESSED | BUC_CURSED | BUC_UNCURSED + | BUC_UNKNOWN | INCLUDE_VENOM), &pick_list, PICK_ANY); if (!n) goto drop_done; @@ -897,7 +900,8 @@ int retry; } else { /* should coordinate with perm invent, maybe not show worn items */ n = query_objlist("What would you like to drop?", &g.invent, - (USE_INVLET | INVORDER_SORT), &pick_list, PICK_ANY, + (USE_INVLET | INVORDER_SORT | INCLUDE_VENOM), + &pick_list, PICK_ANY, all_categories ? allow_all : allow_category); if (n > 0) { /* @@ -948,10 +952,9 @@ int dodown() { struct trap *trap = 0; - boolean stairs_down = ((u.ux == xdnstair && u.uy == ydnstair) - || (u.ux == g.sstairs.sx && u.uy == g.sstairs.sy - && !g.sstairs.up)), - ladder_down = (u.ux == xdnladder && u.uy == ydnladder); + stairway *stway = stairway_at(u.ux, u.uy); + boolean stairs_down = (stway && !stway->up && !stway->isladder), + ladder_down = (stway && !stway->up && stway->isladder); if (u_rooted()) return 1; @@ -1103,6 +1106,8 @@ dodown() int doup() { + stairway *stway = stairway_at(u.ux,u.uy); + if (u_rooted()) return 1; @@ -1112,10 +1117,7 @@ doup() return 1; } - if ((u.ux != xupstair || u.uy != yupstair) - && (!xupladder || u.ux != xupladder || u.uy != yupladder) - && (!g.sstairs.sx || u.ux != g.sstairs.sx || u.uy != g.sstairs.sy - || !g.sstairs.up)) { + if (!stway || (stway && !stway->up)) { You_cant("go up here."); return 0; } @@ -1446,7 +1448,7 @@ boolean at_stairs, falling, portal; assign_level(&u.uz0, &u.uz); assign_level(&u.uz, newlevel); assign_level(&u.utolev, newlevel); - u.utotype = 0; + u.utotype = UTOTYPE_NONE; if (!builds_up(&u.uz)) { /* usual case */ if (dunlev(&u.uz) > dunlev_reached(&u.uz)) dunlev_reached(&u.uz) = dunlev(&u.uz); @@ -1456,6 +1458,7 @@ boolean at_stairs, falling, portal; dunlev_reached(&u.uz) = dunlev(&u.uz); } + stairway_free_all(); /* set default level change destination areas */ /* the special level code may override these */ (void) memset((genericptr_t) &g.updest, 0, sizeof g.updest); @@ -1526,8 +1529,9 @@ boolean at_stairs, falling, portal; } } else if (at_stairs && !In_endgame(&u.uz)) { if (up) { - if (g.at_ladder) - u_on_newpos(xdnladder, ydnladder); + stairway *stway = stairway_find_from(&u.uz0, g.at_ladder); + if (stway) + u_on_newpos(stway->sx, stway->sy); else if (newdungeon) u_on_sstairs(1); else @@ -1542,8 +1546,9 @@ boolean at_stairs, falling, portal; (Flying && g.at_ladder) ? " along" : "", g.at_ladder ? "ladder" : "stairs"); } else { /* down */ - if (g.at_ladder) - u_on_newpos(xupladder, yupladder); + stairway *stway = stairway_find_from(&u.uz0, g.at_ladder); + if (stway) + u_on_newpos(stway->sx, stway->sy); else if (newdungeon) u_on_sstairs(0); else @@ -1781,24 +1786,13 @@ final_level() /* change levels at the end of this turn, after monsters finish moving */ void -schedule_goto(tolev, at_stairs, falling, portal_flag, pre_msg, post_msg) +schedule_goto(tolev, utotype_flags, pre_msg, post_msg) d_level *tolev; -boolean at_stairs, falling; -int portal_flag; +int utotype_flags; const char *pre_msg, *post_msg; { - int typmask = 0100; /* non-zero triggers `deferred_goto' */ - - /* destination flags (`goto_level' args) */ - if (at_stairs) - typmask |= 1; - if (falling) - typmask |= 2; - if (portal_flag) - typmask |= 4; - if (portal_flag < 0) - typmask |= 0200; /* flag for portal removal */ - u.utotype = typmask; + /* UTOTYPE_DEFERRED is used, so UTOTYPE_NONE can trigger deferred_goto() */ + u.utotype = utotype_flags | UTOTYPE_DEFERRED; /* destination level */ assign_level(&u.utolev, tolev); @@ -1820,8 +1814,10 @@ deferred_goto() assign_level(&oldlev, &u.uz); if (g.dfr_pre_msg) pline1(g.dfr_pre_msg); - goto_level(&dest, !!(typmask & 1), !!(typmask & 2), !!(typmask & 4)); - if (typmask & 0200) { /* remove portal */ + goto_level(&dest, !!(typmask & UTOTYPE_ATSTAIRS), + !!(typmask & UTOTYPE_FALLING), + !!(typmask & UTOTYPE_PORTAL)); + if (typmask & UTOTYPE_RMPORTAL) { /* remove portal */ struct trap *t = t_at(u.ux, u.uy); if (t) { @@ -1832,7 +1828,7 @@ deferred_goto() if (g.dfr_post_msg && !on_level(&u.uz, &oldlev)) pline1(g.dfr_post_msg); } - u.utotype = 0; /* our caller keys off of this */ + u.utotype = UTOTYPE_NONE; /* our caller keys off of this */ if (g.dfr_pre_msg) free((genericptr_t) g.dfr_pre_msg), g.dfr_pre_msg = 0; if (g.dfr_post_msg) @@ -1944,7 +1940,7 @@ long timeout UNUSED; /* corpse will revive somewhere else if there is a monster in the way; Riders get a chance to try to bump the obstacle out of their way */ - if ((mptr->mflags3 & M3_DISPLACES) != 0 && body->where == OBJ_FLOOR + if (is_displacer(mptr) && body->where == OBJ_FLOOR && get_obj_location(body, &x, &y, 0) && (mtmp = m_at(x, y)) != 0) { boolean notice_it = canseemon(mtmp); /* before rloc() */ char *monname = Monnam(mtmp); @@ -1966,9 +1962,7 @@ long timeout UNUSED; if (is_rider(mptr) && rn2(99)) { /* Rider usually tries again */ action = REVIVE_MON; - for (when = 3L; when < 67L; when++) - if (!rn2(3)) - break; + when = rider_revival_time(body, TRUE); } else { /* rot this corpse away */ You_feel("%sless hassled.", is_rider(mptr) ? "much " : ""); action = ROT_CORPSE; @@ -1980,22 +1974,58 @@ long timeout UNUSED; } } +/* Timeout callback. Revive the corpse as a zombie. */ +/*ARGSUSED*/ +void +zombify_mon(arg, timeout) +anything *arg; +long timeout UNUSED; +{ + struct obj *body = arg->a_obj; + int zmon = zombie_form(&mons[body->corpsenm]); + + if (zmon != NON_PM) { + + if (has_omid(body)) + free_omid(body); + if (has_omonst(body)) + free_omonst(body); + + body->corpsenm = zmon; + revive_mon(arg, timeout); + } +} + +boolean +cmd_safety_prevention(cmddesc, act, flagcounter) +const char *cmddesc; +const char *act; +int *flagcounter; +{ + if (flags.safe_wait && !iflags.menu_requested + && !g.multi && monster_nearby()) { + char buf[QBUFSZ]; + + buf[0] = '\0'; + if (iflags.cmdassist || !*flagcounter++) + Sprintf(buf, " Use '%s' prefix to force %s.", + visctrl(g.Cmd.spkeys[NHKF_REQMENU]), cmddesc); + Norep("%s%s", act, buf); + return TRUE; + } + *flagcounter = 0; + return FALSE; +} + /* '.' command: do nothing == rest; also the ' ' command iff 'rest_on_space' option is On */ int donull() { - if (!iflags.menu_requested && !g.multi && monster_nearby()) { - char buf[QBUFSZ]; - - buf[0] = '\0'; - if (iflags.cmdassist || !g.did_nothing_flag++) - Sprintf(buf, " Use '%s' prefix to force a no-op (to rest).", - visctrl(g.Cmd.spkeys[NHKF_REQMENU])); /* default is "m" */ - Norep("Are you waiting to get hit?%s", buf); + if (cmd_safety_prevention("a no-op (to rest)", + "Are you waiting to get hit?", + &g.did_nothing_flag)) return 0; - } - g.did_nothing_flag = 0; /* reset */ return 1; /* Do nothing, but let other things happen */ } diff --git a/src/do_name.c b/src/do_name.c index 27bf9f0fa..8a757fb7e 100644 --- a/src/do_name.c +++ b/src/do_name.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 do_name.c $NHDT-Date: 1590904090 2020/05/31 05:48:10 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.181 $ */ +/* NetHack 3.7 do_name.c $NHDT-Date: 1608749030 2020/12/23 18:43:50 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.186 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Pasi Kallinen, 2018. */ /* NetHack may be freely redistributed. See license for details. */ @@ -6,7 +6,8 @@ #include "hack.h" static char *NDECL(nextmbuf); -static void FDECL(getpos_help_keyxhelp, (winid, const char *, const char *, int)); +static void FDECL(getpos_help_keyxhelp, (winid, const char *, + const char *, int)); static void FDECL(getpos_help, (BOOLEAN_P, const char *)); static int FDECL(CFDECLSPEC cmp_coord_distu, (const void *, const void *)); static int FDECL(gloc_filter_classify_glyph, (int)); @@ -17,7 +18,7 @@ static void NDECL(gloc_filter_done); static boolean FDECL(gather_locs_interesting, (int, int, int)); static void FDECL(gather_locs, (coord **, int *, int)); static void FDECL(auto_describe, (int, int)); -static void NDECL(do_mname); +static void NDECL(do_mgivenname); static boolean FDECL(alreadynamed, (struct monst *, char *, char *)); static void FDECL(do_oname, (struct obj *)); static char *FDECL(docall_xname, (struct obj *)); @@ -556,7 +557,7 @@ int cx, cy; if (do_screen_description(cc, TRUE, sym, tmpbuf, &firstmatch, (struct permonst **) 0)) { (void) coord_desc(cx, cy, tmpbuf, iflags.getpos_coords); - custompline(SUPPRESS_HISTORY, + custompline((SUPPRESS_HISTORY | OVERRIDE_MSGTYPE), "%s%s%s%s%s", firstmatch, *tmpbuf ? " " : "", tmpbuf, (iflags.autodescribe && getpos_getvalid && !(*getpos_getvalid)(cx, cy)) @@ -995,7 +996,7 @@ const char *goal; /* allocate space for a monster's name; removes old name if there is one */ void -new_mname(mon, lth) +new_mgivenname(mon, lth) struct monst *mon; int lth; /* desired length (caller handles adding 1 for terminator) */ { @@ -1004,23 +1005,23 @@ int lth; /* desired length (caller handles adding 1 for terminator) */ if (!mon->mextra) mon->mextra = newmextra(); else - free_mname(mon); /* already has mextra, might also have name */ - MNAME(mon) = (char *) alloc((unsigned) lth); + 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_mname(mon)) - free_mname(mon); + if (has_mgivenname(mon)) + free_mgivenname(mon); } } /* release a monster's name; retains mextra even if all fields are now null */ void -free_mname(mon) +free_mgivenname(mon) struct monst *mon; { - if (has_mname(mon)) { - free((genericptr_t) MNAME(mon)); - MNAME(mon) = (char *) 0; + if (has_mgivenname(mon)) { + free((genericptr_t) MGIVENNAME(mon)); + MGIVENNAME(mon) = (char *) 0; } } @@ -1086,14 +1087,14 @@ const char *name; name = strncpy(buf, name, PL_PSIZ - 1); buf[PL_PSIZ - 1] = '\0'; } - new_mname(mtmp, lth); /* removes old name if one is present */ + new_mgivenname(mtmp, lth); /* removes old name if one is present */ if (lth) - Strcpy(MNAME(mtmp), name); + Strcpy(MGIVENNAME(mtmp), name); return mtmp; } /* check whether user-supplied name matches or nearly matches an unnameable - monster's name; if so, give an alternate reject message for do_mname() */ + monster's name; if so, give an alternate reject message for do_mgivenname() */ static boolean alreadynamed(mtmp, monnambuf, usrbuf) struct monst *mtmp; @@ -1125,7 +1126,7 @@ char *monnambuf, *usrbuf; /* allow player to assign a name to some chosen monster */ static void -do_mname() +do_mgivenname() { char buf[BUFSZ], monnambuf[BUFSZ], qbuf[QBUFSZ]; coord cc; @@ -1169,8 +1170,8 @@ do_mname() buf[0] = '\0'; #ifdef EDIT_GETLIN /* if there's an existing name, make it be the default answer */ - if (has_mname(mtmp)) - Strcpy(buf, MNAME(mtmp)); + if (has_mgivenname(mtmp)) + Strcpy(buf, MGIVENNAME(mtmp)); #endif getlin(qbuf, buf); if (!*buf || *buf == '\033') @@ -1196,7 +1197,8 @@ do_mname() || mtmp->data->msound <= MS_ANIMAL)) { if (!alreadynamed(mtmp, monnambuf, buf)) verbalize("I'm %s, not %s.", shkname(mtmp), buf); - } else if (mtmp->ispriest || mtmp->isminion || mtmp->isshk) { + } else if (mtmp->ispriest || mtmp->isminion || mtmp->isshk + || mtmp->data == &mons[PM_GHOST]) { if (!alreadynamed(mtmp, monnambuf, buf)) pline("%s will not accept the name %s.", upstart(monnambuf), buf); } else @@ -1334,7 +1336,7 @@ const char *name; static NEARDATA const char callable[] = { SCROLL_CLASS, POTION_CLASS, WAND_CLASS, RING_CLASS, AMULET_CLASS, - GEM_CLASS, SPBOOK_CLASS, ARMOR_CLASS, TOOL_CLASS, 0 + GEM_CLASS, SPBOOK_CLASS, ARMOR_CLASS, TOOL_CLASS, VENOM_CLASS, 0 }; boolean @@ -1396,7 +1398,7 @@ docallcmd() case 'q': break; case 'm': /* name a visible monster */ - do_mname(); + do_mgivenname(); break; case 'i': /* name an individual object in inventory */ allowall[0] = ALL_CLASSES; @@ -1659,7 +1661,7 @@ boolean called; { char *buf = nextmbuf(); struct permonst *mdat = mtmp->data; - const char *pm_name = mdat->mname; + const char *pm_name = pmname(mdat, Mgender(mtmp)); boolean do_hallu, do_invis, do_it, do_saddle, do_name; boolean name_at_start, has_adjectives; char *bp; @@ -1704,12 +1706,14 @@ boolean called; name += 4; return strcpy(buf, name); } +#if 0 /* an "aligned priest" not flagged as a priest or minion should be "priest" or "priestess" (normally handled by priestname()) */ - if (mdat == &mons[PM_ALIGNED_PRIEST]) + if (mdat == &mons[PM_ALIGNED_CLERIC]) pm_name = mtmp->female ? "priestess" : "priest"; - else if (mdat == &mons[PM_HIGH_PRIEST] && mtmp->female) + else if (mdat == &mons[PM_HIGH_CLERIC] && mtmp->female) pm_name = "high priestess"; +#endif /* Shopkeepers: use shopkeeper name. For normal shopkeepers, just * "Asidonhopo"; for unusual ones, "Asidonhopo the invisible @@ -1753,8 +1757,8 @@ boolean called; Strcat(buf, rname); name_at_start = bogon_is_pname(rnamecode); - } else if (do_name && has_mname(mtmp)) { - char *name = MNAME(mtmp); + } else if (do_name && has_mgivenname(mtmp)) { + char *name = MGIVENNAME(mtmp); if (mdat == &mons[PM_GHOST]) { Sprintf(eos(buf), "%s ghost", s_suffix(name)); @@ -1827,7 +1831,7 @@ l_monnam(mtmp) struct monst *mtmp; { return x_monnam(mtmp, ARTICLE_NONE, (char *) 0, - (has_mname(mtmp)) ? SUPPRESS_SADDLE : 0, TRUE); + (has_mgivenname(mtmp)) ? SUPPRESS_SADDLE : 0, TRUE); } char * @@ -1835,7 +1839,7 @@ mon_nam(mtmp) struct monst *mtmp; { return x_monnam(mtmp, ARTICLE_THE, (char *) 0, - (has_mname(mtmp)) ? SUPPRESS_SADDLE : 0, FALSE); + (has_mgivenname(mtmp)) ? SUPPRESS_SADDLE : 0, FALSE); } /* print the name as if mon_nam() was called, but assume that the player @@ -1847,7 +1851,7 @@ noit_mon_nam(mtmp) struct monst *mtmp; { return x_monnam(mtmp, ARTICLE_THE, (char *) 0, - (has_mname(mtmp)) ? (SUPPRESS_SADDLE | SUPPRESS_IT) + (has_mgivenname(mtmp)) ? (SUPPRESS_SADDLE | SUPPRESS_IT) : SUPPRESS_IT, FALSE); } @@ -1898,7 +1902,7 @@ struct monst *mtmp; int prefix, suppression_flag; prefix = mtmp->mtame ? ARTICLE_YOUR : ARTICLE_THE; - suppression_flag = (has_mname(mtmp) + suppression_flag = (has_mgivenname(mtmp) /* "saddled" is redundant when mounted */ || mtmp == u.usteed) ? SUPPRESS_SADDLE @@ -1913,7 +1917,7 @@ struct monst *mtmp; const char *adj; { char *bp = x_monnam(mtmp, ARTICLE_THE, adj, - has_mname(mtmp) ? SUPPRESS_SADDLE : 0, FALSE); + has_mgivenname(mtmp) ? SUPPRESS_SADDLE : 0, FALSE); *bp = highc(*bp); return bp; @@ -1924,7 +1928,7 @@ a_monnam(mtmp) struct monst *mtmp; { return x_monnam(mtmp, ARTICLE_A, (char *) 0, - has_mname(mtmp) ? SUPPRESS_SADDLE : 0, FALSE); + has_mgivenname(mtmp) ? SUPPRESS_SADDLE : 0, FALSE); } char * @@ -1948,7 +1952,7 @@ char *outbuf; /* high priest(ess)'s identity is concealed on the Astral Plane, unless you're adjacent (overridden for hallucination which does its own obfuscation) */ - if (mon->data == &mons[PM_HIGH_PRIEST] && !Hallucination + if (mon->data == &mons[PM_HIGH_CLERIC] && !Hallucination && Is_astralevel(&u.uz) && distu(mon->mx, mon->my) > 2) { Strcpy(outbuf, article == ARTICLE_THE ? "the " : ""); Strcat(outbuf, mon->female ? "high priestess" : "high priest"); @@ -2046,37 +2050,65 @@ boolean ckloc; } else if (ckloc && ptr == &mons[PM_LONG_WORM] && g.level.monsters[mon->mx][mon->my] != mon) { Sprintf(outbuf, "%s <%d,%d>", - mons[PM_LONG_WORM_TAIL].mname, mon->mx, mon->my); + pmname(&mons[PM_LONG_WORM_TAIL], Mgender(mon)), mon->mx, mon->my); } else { Sprintf(outbuf, "%s%s <%d,%d>", mon->mtame ? "tame " : mon->mpeaceful ? "peaceful " : "", - mon->data->mname, mon->mx, mon->my); + pmname(mon->data, Mgender(mon)), mon->mx, mon->my); if (mon->cham != NON_PM) - Sprintf(eos(outbuf), "{%s}", mons[mon->cham].mname); + Sprintf(eos(outbuf), "{%s}", pmname(&mons[mon->cham], Mgender(mon))); } return outbuf; } +#ifndef PMNAME_MACROS +int +Mgender(mtmp) +struct monst *mtmp; +{ + int mgender = MALE; + + if (mtmp == &g.youmonst) { + if (Upolyd ? u.mfemale : flags.female) + mgender = FEMALE; + } else if (mtmp->female) { + mgender = FEMALE; + } + return mgender; +} + +const char * +pmname(pm, mgender) +struct permonst *pm; +int mgender; +{ + if ((mgender >= MALE && mgender < NUM_MGENDERS) && pm->pmnames[mgender]) + return pm->pmnames[mgender]; + else + return pm->pmnames[NEUTRAL]; +} +#endif /* PMNAME_MACROS */ + /* fake monsters used to be in a hard-coded array, now in a data file */ char * bogusmon(buf, code) char *buf, *code; { static const char bogon_codes[] = "-_+|="; /* see dat/bonusmon.txt */ - char *mname = buf; + char *mnam = buf; if (code) *code = '\0'; /* might fail (return empty buf[]) if the file isn't available */ get_rnd_text(BOGUSMONFILE, buf, rn2_on_display_rng); - if (!*mname) { + if (!*mnam) { Strcpy(buf, "bogon"); - } else if (index(bogon_codes, *mname)) { /* strip prefix if present */ + } else if (index(bogon_codes, *mnam)) { /* strip prefix if present */ if (code) - *code = *mname; - ++mname; + *code = *mnam; + ++mnam; } - return mname; + return mnam; } /* return a random monster name, for hallucination */ @@ -2085,7 +2117,7 @@ rndmonnam(code) char *code; { static char buf[BUFSZ]; - char *mname; + char *mnam; int name; #define BOGUSMONSIZE 100 /* arbitrary */ @@ -2098,11 +2130,11 @@ char *code; && (type_is_pname(&mons[name]) || (mons[name].geno & G_NOGEN))); if (name >= SPECIAL_PM) { - mname = bogusmon(buf, code); + mnam = bogusmon(buf, code); } else { - mname = strcpy(buf, mons[name].mname); + mnam = strcpy(buf, pmname(&mons[name], rn2_on_display_rng(2))); } - return mname; + return mnam; #undef BOGUSMONSIZE } diff --git a/src/do_wear.c b/src/do_wear.c index 28be5050a..044b363d6 100644 --- a/src/do_wear.c +++ b/src/do_wear.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 do_wear.c $NHDT-Date: 1592951498 2020/06/23 22:31:38 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.133 $ */ +/* NetHack 3.7 do_wear.c $NHDT-Date: 1605578866 2020/11/17 02:07:46 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.136 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -424,6 +424,14 @@ Helmet_on(VOID_ARGS) pline("%s %s for a moment.", Tobjnam(uarmh, "glow"), hcolor(NH_BLACK)); curse(uarmh); + /* curse() doesn't touch bknown so doesn't update persistent + inventory; do so now [set_bknown() calls update_inventory()] */ + if (Blind) + set_bknown(uarmh, 0); /* lose bknown if previously set */ + else if (Role_if(PM_CLERIC)) + set_bknown(uarmh, 1); /* (bknown should already be set) */ + else if (uarmh->bknown) + update_inventory(); /* keep bknown as-is; display the curse */ } g.context.botl = 1; /* reveal new alignment or INT & WIS */ if (Hallucination) { @@ -758,6 +766,8 @@ Amulet_on() You("are suddenly very %s!", flags.female ? "feminine" : "masculine"); g.context.botl = 1; + 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 */ @@ -1982,6 +1992,7 @@ struct obj *obj; answer = yn_function(qbuf, "rl", '\0'); switch (answer) { case '\0': + case '\033': return 0; case 'l': case 'L': @@ -2204,19 +2215,26 @@ find_ac() uac -= u.ublessed; uac -= u.uspellprot; - /* [The magic binary numbers 127 and -128 should be replaced with the - * mystic decimal numbers 99 and -99 which require no explanation to - * the uninitiated and would cap the width of a status line value at - * one less character.] - */ - if (uac < -128) - uac = -128; /* u.uac is an schar */ - else if (uac > 127) - uac = 127; /* for completeness */ + /* put a cap on armor class [3.7: was +127,-128, now reduced to +/- 99 */ + if (abs(uac) > AC_MAX) + uac = sgn(uac) * AC_MAX; if (uac != u.uac) { u.uac = uac; g.context.botl = 1; +#if 0 + /* these could conceivably be achieved out of order (by being near + threshold and putting on +N dragon scale mail from bones, for + instance), but if that happens, that's the order it happened; + also, testing for these in the usual order would result in more + record_achievement() attempts and rejects for duplication */ + if (u.uac <= -20) + record_achievement(ACH_AC_20); + else if (u.uac <= -10) + record_achievement(ACH_AC_10); + else if (u.uac <= 0) + record_achievement(ACH_AC_00); +#endif } } diff --git a/src/dog.c b/src/dog.c index a19167794..50ffd00c9 100644 --- a/src/dog.c +++ b/src/dog.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 dog.c $NHDT-Date: 1554580624 2019/04/06 19:57:04 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.85 $ */ +/* NetHack 3.7 dog.c $NHDT-Date: 1599330917 2020/09/05 18:35:17 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.104 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2011. */ /* NetHack may be freely redistributed. See license for details. */ @@ -170,7 +170,7 @@ makedog() /* default pet names */ if (!*petname && pettype == PM_LITTLE_DOG) { /* All of these names were for dogs. */ - if (Role_if(PM_CAVEMAN)) + if (Role_if(PM_CAVE_DWELLER)) petname = "Slasher"; /* The Warrior */ if (Role_if(PM_SAMURAI)) petname = "Hachi"; /* Shibuya Station */ @@ -306,6 +306,8 @@ boolean with_you; xchar xlocale, ylocale, xyloc, xyflags, wander; int num_segs; boolean failed_to_place = FALSE; + stairway *stway; + d_level fromdlev; mtmp->nmon = fmon; fmon = mtmp; @@ -331,6 +333,8 @@ boolean with_you; xyflags = mtmp->mtrack[0].y; xlocale = mtmp->mtrack[1].x; ylocale = mtmp->mtrack[1].y; + fromdlev.dnum = mtmp->mtrack[2].x; + fromdlev.dlevel = mtmp->mtrack[2].y; memset(mtmp->mtrack, 0, sizeof mtmp->mtrack); if (mtmp == u.usteed) @@ -376,19 +380,34 @@ boolean with_you; xlocale = u.ux, ylocale = u.uy; break; case MIGR_STAIRS_UP: - xlocale = xupstair, ylocale = yupstair; + if ((stway = stairway_find_from(&fromdlev, FALSE)) != 0) { + xlocale = stway->sx; + ylocale = stway->sy; + } break; case MIGR_STAIRS_DOWN: - xlocale = xdnstair, ylocale = ydnstair; + if ((stway = stairway_find_from(&fromdlev, FALSE)) != 0) { + xlocale = stway->sx; + ylocale = stway->sy; + } break; case MIGR_LADDER_UP: - xlocale = xupladder, ylocale = yupladder; + if ((stway = stairway_find_from(&fromdlev, TRUE)) != 0) { + xlocale = stway->sx; + ylocale = stway->sy; + } break; case MIGR_LADDER_DOWN: - xlocale = xdnladder, ylocale = ydnladder; + if ((stway = stairway_find_from(&fromdlev, TRUE)) != 0) { + xlocale = stway->sx; + ylocale = stway->sy; + } break; case MIGR_SSTAIRS: - xlocale = g.sstairs.sx, ylocale = g.sstairs.sy; + if ((stway = stairway_find(&fromdlev)) != 0) { + xlocale = stway->sx; + ylocale = stway->sy; + } break; case MIGR_PORTAL: if (In_endgame(&u.uz)) { @@ -719,6 +738,8 @@ coord *cc; /* optional destination coordinates */ xyflags |= 2; mtmp->wormno = num_segs; mtmp->mlstmv = g.monstermoves; + mtmp->mtrack[2].x = u.uz.dnum; /* migrating from this dungeon */ + mtmp->mtrack[2].y = u.uz.dlevel; /* migrating from this dungeon level */ mtmp->mtrack[1].x = cc ? cc->x : mtmp->mx; mtmp->mtrack[1].y = cc ? cc->y : mtmp->my; mtmp->mtrack[0].x = xyloc; @@ -726,8 +747,6 @@ coord *cc; /* optional destination coordinates */ mtmp->mux = new_lev.dnum; mtmp->muy = new_lev.dlevel; mtmp->mx = mtmp->my = 0; /* this implies migration */ - if (mtmp == g.context.polearm.hitmon) - g.context.polearm.hitmon = (struct monst *) 0; } /* return quality of food; the lower the better */ diff --git a/src/dogmove.c b/src/dogmove.c index 90faaad60..8d255ec3e 100644 --- a/src/dogmove.c +++ b/src/dogmove.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 dogmove.c $NHDT-Date: 1557094801 2019/05/05 22:20:01 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.74 $ */ +/* NetHack 3.7 dogmove.c $NHDT-Date: 1607374000 2020/12/07 20:46:40 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.94 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -934,17 +934,7 @@ int after; /* this is extra fast monster movement */ if (appr == -2) return 0; - allowflags = ALLOW_M | ALLOW_TRAPS | ALLOW_SSM | ALLOW_SANCT; - if (passes_walls(mtmp->data)) - allowflags |= (ALLOW_ROCK | ALLOW_WALL); - if (passes_bars(mtmp->data)) - allowflags |= ALLOW_BARS; - if (throws_rocks(mtmp->data)) - allowflags |= ALLOW_ROCK; - if (is_displacer(mtmp->data)) - allowflags |= ALLOW_MDISP; if (Conflict && !resist(mtmp, RING_CLASS, 0, 0)) { - allowflags |= ALLOW_U; if (!has_edog) { /* Guardian angel refuses to be conflicted; rather, * it disappears, angrily, and sends in some nasties @@ -960,18 +950,7 @@ int after; /* this is extra fast monster movement */ You("get released!"); } #endif - if (!nohands(mtmp->data) && !verysmall(mtmp->data)) { - allowflags |= OPENDOOR; - if (monhaskey(mtmp, TRUE)) - allowflags |= UNLOCKDOOR; - /* note: the Wizard and Riders can unlock doors without a key; - they won't use that ability if someone manages to tame them */ - } - if (is_giant(mtmp->data)) - allowflags |= BUSTDOOR; - if (tunnels(mtmp->data) - && !Is_rogue_level(&u.uz)) /* same restriction as m_move() */ - allowflags |= ALLOW_DIG; + allowflags = mon_allowflags(mtmp); cnt = mfndpos(mtmp, poss, info, allowflags); /* Normally dogs don't step on cursed items, but if they have no @@ -1156,11 +1135,17 @@ int after; /* this is extra fast monster movement */ /* Hungry pets are unlikely to use breath/spit attacks */ if (mtarg && (!hungry || !rn2(5))) { - int mstatus; + int mstatus = MM_MISS; if (mtarg == &g.youmonst) { if (mattacku(mtmp)) return 2; + /* Treat this as the pet having initiated an attack even if it + * didn't, so it will lose its move. This isn't entirely fair, + * but mattacku doesn't distinguish between "did not attack" and + * "attacked but didn't die" cases, and this is preferable to + * letting the pet attack the player and continuing to move */ + mstatus = MM_HIT; } else { mstatus = mattackm(mtmp, mtarg); @@ -1187,7 +1172,18 @@ int after; /* this is extra fast monster movement */ } } } - return 3; + /* Only return 3 if the pet actually made a ranged attack, and thus + * should lose the rest of its move. + * There's a chain of assumptions here: + * 1. score_targ and best_target will never select a monster that + * can be attacked in melee, so the mattackm call can only ever + * try ranged options + * 2. if the only attacks available to mattackm are ranged options, + * and the monster cannot make a ranged attack, it will return + * MM_MISS. + */ + if (mstatus != MM_MISS) + return 3; } } @@ -1315,7 +1311,9 @@ xchar mx, my, fx, fy; if (dist2(i, j, fx, fy) >= dist) continue; if (IS_ROCK(levl[i][j].typ) && !passes_walls(mon->data) - && (!may_dig(i, j) || !tunnels(mon->data))) + && (!may_dig(i, j) || !tunnels(mon->data) + /* tunnelling monsters can't do that on the rogue level */ + || Is_rogue_level(&u.uz))) continue; if (IS_DOOR(levl[i][j].typ) && (levl[i][j].doormask & (D_CLOSED | D_LOCKED))) @@ -1431,7 +1429,8 @@ struct monst *mtmp; && OBJ_NAME(objects[mtmp->mappearance])) ? an(OBJ_NAME(objects[mtmp->mappearance])) : (M_AP_TYPE(mtmp) == M_AP_MONSTER) - ? an(mons[mtmp->mappearance].mname) + ? an(pmname(&mons[mtmp->mappearance], + Mgender(mtmp))) : something, cansee(mtmp->mx, mtmp->my) ? "" : "has ", cansee(mtmp->mx, mtmp->my) ? "" : "ed", diff --git a/src/dokick.c b/src/dokick.c index a0ffff9f4..c685fa201 100644 --- a/src/dokick.c +++ b/src/dokick.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 dokick.c $NHDT-Date: 1582155880 2020/02/19 23:44:40 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.153 $ */ +/* NetHack 3.7 dokick.c $NHDT-Date: 1608673689 2020/12/22 21:48:09 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.162 $ */ /* Copyright (c) Izchak Miller, Mike Stephenson, Steve Linhart, 1989. */ /* NetHack may be freely redistributed. See license for details. */ @@ -18,8 +18,8 @@ static void FDECL(kick_monster, (struct monst *, XCHAR_P, XCHAR_P)); static int FDECL(kick_object, (XCHAR_P, XCHAR_P, char *)); static int FDECL(really_kick_object, (XCHAR_P, XCHAR_P)); static char *FDECL(kickstr, (char *, const char *)); -static void FDECL(otransit_msg, (struct obj *, BOOLEAN_P, long)); -static void FDECL(drop_to, (coord *, SCHAR_P)); +static void FDECL(otransit_msg, (struct obj *, BOOLEAN_P, BOOLEAN_P, long)); +static void FDECL(drop_to, (coord *, SCHAR_P, XCHAR_P, XCHAR_P)); static const char kick_passes_thru[] = "kick passes harmlessly through"; @@ -341,14 +341,12 @@ register struct obj *gold; out of the vault. If he did do that, player could try fighting, then weasle out of being killed by throwing his/her gold when losing. */ - verbalize( - umoney - ? "Drop the rest and follow me." - : hidden_gold() - ? "You still have hidden gold. Drop it now." - : mtmp->mpeaceful - ? "I'll take care of that; please move along." - : "I'll take that; now get moving."); + verbalize(umoney ? "Drop the rest and follow me." + : hidden_gold(TRUE) + ? "You still have hidden gold. Drop it now." + : mtmp->mpeaceful + ? "I'll take care of that; please move along." + : "I'll take that; now get moving."); } else if (is_mercenary(mtmp->data)) { long goldreqd = 0L; @@ -510,7 +508,8 @@ xchar x, y; } if (!uarmf && g.kickedobj->otyp == CORPSE - && touch_petrifies(&mons[g.kickedobj->corpsenm]) && !Stone_resistance) { + && touch_petrifies(&mons[g.kickedobj->corpsenm]) + && !Stone_resistance) { You("kick %s with your bare %s.", corpse_xname(g.kickedobj, (const char *) 0, CXN_PFX_THE), makeplural(body_part(FOOT))); @@ -707,12 +706,23 @@ xchar x, y; else (void) stolen_value(g.kickedobj, x, y, (boolean) shkp->mpeaceful, FALSE); + costly = FALSE; /* already billed */ } if (flooreffects(g.kickedobj, g.bhitpos.x, g.bhitpos.y, "fall")) return 1; - if (g.kickedobj->unpaid) - subfrombill(g.kickedobj, shkp); + if (costly) { + long gt = 0L; + + /* costly + landed outside shop handled above; must be inside shop */ + if (g.kickedobj->unpaid) + subfrombill(g.kickedobj, shkp); + + /* if billed for contained gold during kick, get a refund now */ + if (Has_contents(g.kickedobj) + && (gt = contained_gold(g.kickedobj, TRUE)) > 0L) + donate_gold(gt, shkp, FALSE); + } place_object(g.kickedobj, g.bhitpos.x, g.bhitpos.y); stackobj(g.kickedobj); newsym(g.kickedobj->ox, g.kickedobj->oy); @@ -1149,9 +1159,6 @@ dokick() } if (IS_SINK(g.maploc->typ)) { int gend = poly_gender(); - short washerndx = (gend == 1 || (gend == 2 && rn2(2))) - ? PM_INCUBUS - : PM_SUCCUBUS; if (Levitation) goto dumb; @@ -1175,10 +1182,12 @@ dokick() g.maploc->looted |= S_LPUDDING; return 1; } else if (!(g.maploc->looted & S_LDWASHER) && !rn2(3) - && !(g.mvitals[washerndx].mvflags & G_GONE)) { + && !(g.mvitals[PM_AMOROUS_DEMON].mvflags & G_GONE)) { /* can't resist... */ pline("%s returns!", (Blind ? Something : "The dish washer")); - if (makemon(&mons[washerndx], x, y, NO_MM_FLAGS)) + if (makemon(&mons[PM_AMOROUS_DEMON], x, y, + (gend == 1 || (gend == 2 && rn2(2))) + ? MM_FEMALE : MM_MALE)) newsym(x, y); g.maploc->looted |= S_LDWASHER; exercise(A_DEX, TRUE); @@ -1322,10 +1331,13 @@ dokick() } static void -drop_to(cc, loc) +drop_to(cc, loc, x,y) coord *cc; schar loc; +xchar x,y; { + stairway *stway = stairway_at(x, y); + /* cover all the MIGR_xxx choices generated by down_gate() */ switch (loc) { case MIGR_RANDOM: /* trap door or hole */ @@ -1340,12 +1352,14 @@ schar loc; /*FALLTHRU*/ case MIGR_STAIRS_UP: case MIGR_LADDER_UP: - cc->x = u.uz.dnum; - cc->y = u.uz.dlevel + 1; - break; case MIGR_SSTAIRS: - cc->x = g.sstairs.tolev.dnum; - cc->y = g.sstairs.tolev.dlevel; + if (stway) { + cc->x = stway->tolev.dnum; + cc->y = stway->tolev.dlevel; + } else { + cc->x = u.uz.dnum; + cc->y = u.uz.dlevel + 1; + } break; default: case MIGR_NOWHERE: @@ -1373,7 +1387,7 @@ xchar dlev; /* if !0 send to dlev near player */ return; toloc = down_gate(x, y); - drop_to(&cc, toloc); + drop_to(&cc, toloc, x, y); if (!cc.y) return; @@ -1495,14 +1509,14 @@ boolean shop_floor_obj; coord cc; struct obj *obj; struct trap *t; - boolean nodrop, unpaid, container, impact = FALSE; + boolean nodrop, unpaid, container, impact = FALSE, chainthere = FALSE; long n = 0L; if (!otmp) return FALSE; if ((toloc = down_gate(x, y)) == MIGR_NOWHERE) return FALSE; - drop_to(&cc, toloc); + drop_to(&cc, toloc, x, y); if (!cc.y) return FALSE; @@ -1515,9 +1529,12 @@ boolean shop_floor_obj; unpaid = is_unpaid(otmp); if (OBJ_AT(x, y)) { - for (obj = g.level.objects[x][y]; obj; obj = obj->nexthere) - if (obj != otmp) + for (obj = g.level.objects[x][y]; obj; obj = obj->nexthere) { + if (obj == uchain) + chainthere = TRUE; + else if (obj != otmp) n += obj->quan; + } if (n) impact = TRUE; } @@ -1531,7 +1548,7 @@ boolean shop_floor_obj; } if (cansee(x, y)) - otransit_msg(otmp, nodrop, n); + otransit_msg(otmp, nodrop, chainthere, n); if (nodrop) { if (impact) @@ -1586,6 +1603,7 @@ boolean shop_floor_obj; otmp->ox = cc.x; otmp->oy = cc.y; otmp->owornmask = (long) toloc; + /* boulder from rolling boulder trap, no longer part of the trap */ if (otmp->otyp == BOULDER) otmp->otrapped = 0; @@ -1611,9 +1629,12 @@ obj_delivery(near_hero) boolean near_hero; { register struct obj *otmp, *otmp2; - register int nx, ny; + int nx = 0, ny = 0; int where; boolean nobreak, noscatter; + stairway *stway; + d_level fromdlev; + boolean isladder; for (otmp = g.migrating_objs; otmp; otmp = otmp2) { otmp2 = otmp->nobj; @@ -1633,16 +1654,21 @@ boolean near_hero; obj_extract_self(otmp); otmp->owornmask = 0L; + fromdlev.dnum = otmp->omigr_from_dnum; + fromdlev.dlevel = otmp->omigr_from_dlevel; + + isladder = FALSE; switch (where) { - case MIGR_STAIRS_UP: - nx = xupstair, ny = yupstair; - break; case MIGR_LADDER_UP: - nx = xupladder, ny = yupladder; - break; + isladder = TRUE; + /*FALLTHRU*/ + case MIGR_STAIRS_UP: case MIGR_SSTAIRS: - nx = g.sstairs.sx, ny = g.sstairs.sy; + if ((stway = stairway_find_from(&fromdlev, isladder)) != 0) { + nx = stway->sx; + ny = stway->sy; + } break; case MIGR_WITH_HERO: nx = u.ux, ny = u.uy; @@ -1652,6 +1678,8 @@ boolean near_hero; nx = ny = 0; break; } + otmp->omigr_from_dnum = 0; + otmp->omigr_from_dlevel = 0; if (nx > 0) { place_object(otmp, nx, ny); if (!nobreak && !IS_SOFT(levl[nx][ny].typ)) { @@ -1708,14 +1736,16 @@ unsigned long deliverflags; if ((where & MIGR_TO_SPECIES) == 0) continue; - if ((mtmp->data->mflags2 & DELIVER_PM) == otmp->corpsenm) { + if (otmp->migr_species != NON_PM + && ((mtmp->data->mflags2 & DELIVER_PM) + == (unsigned) otmp->migr_species)) { obj_extract_self(otmp); otmp->owornmask = 0L; otmp->ox = otmp->oy = 0; /* special treatment for orcs and their kind */ if ((otmp->corpsenm & M2_ORC) != 0 && has_oname(otmp)) { - if (!has_mname(mtmp)) { + if (!has_mgivenname(mtmp)) { if (at_crime_scene || !rn2(2)) mtmp = christen_orc(mtmp, at_crime_scene ? ONAME(otmp) @@ -1725,7 +1755,9 @@ unsigned long deliverflags; } free_oname(otmp); } - otmp->corpsenm = NON_PM; + otmp->migr_species = NON_PM; + otmp->omigr_from_dnum = 0; + otmp->omigr_from_dlevel = 0; (void) add_to_minv(mtmp, otmp); cnt++; if (maxobj && cnt >= maxobj) @@ -1736,9 +1768,9 @@ unsigned long deliverflags; } static void -otransit_msg(otmp, nodrop, num) +otransit_msg(otmp, nodrop, chainthere, num) register struct obj *otmp; -register boolean nodrop; +boolean nodrop, chainthere; long num; { char *optr = 0, obuf[BUFSZ], xbuf[BUFSZ]; @@ -1752,15 +1784,20 @@ long num; } Strcpy(obuf, optr); - if (num) { /* means: other objects are impacted */ + if (num || chainthere) { /* As of 3.6.2: use a separate buffer for the suffix to avoid risk of overrunning obuf[] (let pline() handle truncation if necessary) */ - Sprintf(xbuf, " %s %s object%s", otense(otmp, "hit"), - (num == 1L) ? "another" : "other", (num > 1L) ? "s" : ""); + if (num) { /* means: other objects are impacted */ + Sprintf(xbuf, " %s %s object%s", otense(otmp, "hit"), + (num == 1L) ? "another" : "other", (num > 1L) ? "s" : ""); + } else { /* chain-only msg */ + Sprintf(xbuf, " %s your chain", otense(otmp, "rattle")); + } if (nodrop) Sprintf(eos(xbuf), "."); else - Sprintf(eos(xbuf), " and %s %s.", otense(otmp, "fall"), g.gate_str); + Sprintf(eos(xbuf), " and %s %s.", + otense(otmp, "fall"), g.gate_str); pline("%s%s", obuf, xbuf); } else if (!nodrop) pline("%s %s %s.", obuf, otense(otmp, "fall"), g.gate_str); @@ -1772,27 +1809,26 @@ down_gate(x, y) xchar x, y; { struct trap *ttmp; + stairway *stway = stairway_at(x, y); g.gate_str = 0; /* this matches the player restriction in goto_level() */ - if (on_level(&u.uz, &qstart_level) && !ok_to_quest()) + if (on_level(&u.uz, &qstart_level) && !ok_to_quest()) { return MIGR_NOWHERE; - - if ((xdnstair == x && ydnstair == y) - || (g.sstairs.sx == x && g.sstairs.sy == y && !g.sstairs.up)) { + } + if (stway && !stway->up && !stway->isladder) { g.gate_str = "down the stairs"; - return (xdnstair == x && ydnstair == y) ? MIGR_STAIRS_UP + return (stway->tolev.dnum == u.uz.dnum) ? MIGR_STAIRS_UP : MIGR_SSTAIRS; } - if (xdnladder == x && ydnladder == y) { + if (stway && !stway->up && stway->isladder) { g.gate_str = "down the ladder"; return MIGR_LADDER_UP; } - - if (((ttmp = t_at(x, y)) != 0 && ttmp->tseen) - && is_hole(ttmp->ttyp)) { + /* hole will always be flagged as seen; trap drop might or might not */ + if ((ttmp = t_at(x, y)) != 0 && ttmp->tseen && is_hole(ttmp->ttyp)) { g.gate_str = (ttmp->ttyp == TRAPDOOR) ? "through the trap door" - : "through the hole"; + : "through the hole"; return MIGR_RANDOM; } return MIGR_NOWHERE; diff --git a/src/dothrow.c b/src/dothrow.c index 1e6930c8e..8318bafb3 100644 --- a/src/dothrow.c +++ b/src/dothrow.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 dothrow.c $NHDT-Date: 1584398443 2020/03/16 22:40:43 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.184 $ */ +/* NetHack 3.7 dothrow.c $NHDT-Date: 1608673690 2020/12/22 21:48:10 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.192 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2013. */ /* NetHack may be freely redistributed. See license for details. */ @@ -23,8 +23,9 @@ static boolean FDECL(mhurtle_step, (genericptr_t, int, int)); static NEARDATA const char toss_objs[] = { ALLOW_COUNT, COIN_CLASS, ALL_CLASSES, WEAPON_CLASS, 0 }; /* different default choices when wielding a sling (gold must be included) */ -static NEARDATA const char bullets[] = { ALLOW_COUNT, COIN_CLASS, ALL_CLASSES, - GEM_CLASS, 0 }; +static NEARDATA const char t_bullets[] = { + ALLOW_COUNT, COIN_CLASS, ALL_CLASSES, GEM_CLASS, 0 +}; /* g.thrownobj (decl.c) tracks an object until it lands */ @@ -38,7 +39,7 @@ struct obj *launcher; /* can be NULL */ schar skill = objects[ammo->otyp].oc_skill; switch (pm) { - case PM_CAVEMAN: + case PM_CAVE_DWELLER: /* give bonus for low-tech gear */ if (skill == -P_SLING || skill == P_SPEAR) multishot++; @@ -157,7 +158,7 @@ int shotlimit; : obj->oclass == WEAPON_CLASS) && !(Confusion || Stunned)) { /* some roles don't get a volley bonus until becoming expert */ - weakmultishot = (Role_if(PM_WIZARD) || Role_if(PM_PRIEST) + weakmultishot = (Role_if(PM_WIZARD) || Role_if(PM_CLERIC) || (Role_if(PM_HEALER) && skill != P_KNIFE) || (Role_if(PM_TOURIST) && skill != -P_DART) /* poor dexterity also inhibits multishot */ @@ -295,7 +296,7 @@ dothrow() if (!ok_to_throw(&shotlimit)) return 0; - obj = getobj(uslinging() ? bullets : toss_objs, "throw"); + obj = getobj(uslinging() ? t_bullets : toss_objs, "throw"); /* it is also possible to throw food */ /* (or jewels, or iron balls... ) */ @@ -407,7 +408,7 @@ dofire() use direction of previous throw as getobj()'s choice here */ g.in_doagain = 0; /* choose something from inventory, then usually quiver it */ - obj = getobj(uslinging() ? bullets : toss_objs, "throw"); + obj = getobj(uslinging() ? t_bullets : toss_objs, "throw"); /* Q command doesn't allow gold in quiver */ if (obj && !obj->owornmask && obj->oclass != COIN_CLASS) setuqwep(obj); /* demi-autoquiver */ @@ -450,11 +451,32 @@ boolean verbosely; /* usually True; False if caller has given drop message */ dropy(obj); return; } - if (IS_ALTAR(levl[u.ux][u.uy].typ)) + if (IS_ALTAR(levl[u.ux][u.uy].typ)) { doaltarobj(obj); - else if (verbosely) - pline("%s %s the %s.", Doname2(obj), otense(obj, "hit"), - surface(u.ux, u.uy)); + } else if (verbosely) { + const char *surf = surface(u.ux, u.uy); + struct trap *t = t_at(u.ux, u.uy); + + /* describe something that might keep the object where it is + or precede next message stating that it falls */ + if (t && t->tseen) { + switch (t->ttyp) { + case TRAPDOOR: + surf = "trap door"; + break; + case HOLE: + surf = "edge of the hole"; + break; + case PIT: + case SPIKED_PIT: + surf = "edge of the pit"; + break; + default: + break; + } + } + pline("%s %s the %s.", Doname2(obj), otense(obj, "hit"), surf); + } if (hero_breaks(obj, u.ux, u.uy, TRUE)) return; @@ -935,10 +957,15 @@ boolean broken; /* ushops0: in case we threw while levitating and recoiled out of shop (most likely to the shk's spot in front of door) */ if (*oshops == *u.ushops || *oshops == *u.ushops0) { - if (is_unpaid(obj)) + if (is_unpaid(obj)) { + long gt = Has_contents(obj) ? contained_gold(obj, TRUE) : 0L; + subfrombill(obj, shkp); - else if (x != shkp->mx || y != shkp->my) + if (gt > 0L) + donate_gold(gt, shkp, TRUE); + } else if (x != shkp->mx || y != shkp->my) { sellobj(obj, x, y); + } } } } @@ -1071,7 +1098,7 @@ boolean hitsroof; } hitfloor(obj, TRUE); g.thrownobj = 0; - losehp(Maybe_Half_Phys(dmg), "falling object", KILLED_BY_AN); + losehp(dmg, "falling object", KILLED_BY_AN); } return TRUE; } @@ -1611,7 +1638,13 @@ register struct obj *obj; /* g.thrownobj or g.kickedobj or uwep */ tmp += 1000; /* Guaranteed hit */ } - if (obj->oclass == GEM_CLASS && is_unicorn(mon->data)) { + /* throwing real gems to co-aligned unicorns boosts Luck, + to cross-aligned unicorns changes Luck by random amount; + throwing worthless glass doesn't affect Luck but doesn't anger them; + 3.7: treat rocks and gray stones as attacks rather than like glass + and also treat gems or glass shot via sling as attacks */ + if (obj->oclass == GEM_CLASS && is_unicorn(mon->data) + && objects[obj->otyp].oc_material != MINERAL && !uslinging()) { if (mon->msleeping || !mon->mcanmove) { tmiss(obj, mon, FALSE); return 0; @@ -1628,8 +1661,8 @@ register struct obj *obj; /* g.thrownobj or g.kickedobj or uwep */ at leader... (kicked artifact is ok too; HMON_APPLIED could occur if quest artifact polearm or grapnel ever gets added) */ if (hmode != HMON_APPLIED && quest_arti_hits_leader(obj, mon)) { - /* AIS: changes to wakeup() means that it's now less inappropriate here - than it used to be, but the manual version works just as well */ + /* AIS: changes to wakeup() means that it's now less inappropriate + here than it used to be, but manual version works just as well */ mon->msleeping = 0; mon->mstrategy &= ~STRAT_WAITMASK; @@ -1823,15 +1856,16 @@ gem_accept(mon, obj) register struct monst *mon; register struct obj *obj; { + static NEARDATA const char + nogood[] = " is not interested in your junk.", + acceptgift[] = " accepts your gift.", + maybeluck[] = " hesitatingly", + noluck[] = " graciously", + addluck[] = " gratefully"; char buf[BUFSZ]; boolean is_buddy = sgn(mon->data->maligntyp) == sgn(u.ualign.type); boolean is_gem = objects[obj->otyp].oc_material == GEMSTONE; int ret = 0; - static NEARDATA const char nogood[] = " is not interested in your junk."; - static NEARDATA const char acceptgift[] = " accepts your gift."; - static NEARDATA const char maybeluck[] = " hesitatingly"; - static NEARDATA const char noluck[] = " graciously"; - static NEARDATA const char addluck[] = " gratefully"; Strcpy(buf, Monnam(mon)); mon->mpeaceful = 1; @@ -1851,7 +1885,8 @@ register struct obj *obj; Strcat(buf, nogood); goto nopick; } - /* making guesses */ + + /* making guesses */ } else if (has_oname(obj) || objects[obj->otyp].oc_uname) { if (is_gem) { if (is_buddy) { @@ -1865,7 +1900,8 @@ register struct obj *obj; Strcat(buf, nogood); goto nopick; } - /* value completely unknown to @ */ + + /* value completely unknown to @ */ } else { if (is_gem) { if (is_buddy) { diff --git a/src/drawing.c b/src/drawing.c index 7d9932e19..6ea864b9f 100644 --- a/src/drawing.c +++ b/src/drawing.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 drawing.c $NHDT-Date: 1588778111 2020/05/06 15:15:11 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.76 $ */ +/* NetHack 3.7 drawing.c $NHDT-Date: 1596498163 2020/08/03 23:42:43 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.78 $ */ /* Copyright (c) NetHack Development Team 1992. */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/src/dungeon.c b/src/dungeon.c index f376e5237..f27f0cae2 100644 --- a/src/dungeon.c +++ b/src/dungeon.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 dungeon.c $NHDT-Date: 1580607225 2020/02/02 01:33:45 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.124 $ */ +/* NetHack 3.7 dungeon.c $NHDT-Date: 1605305480 2020/11/13 22:11:20 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.138 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1398,13 +1398,14 @@ void next_level(at_stairs) boolean at_stairs; { - if (at_stairs && u.ux == g.sstairs.sx && u.uy == g.sstairs.sy) { - /* Taking a down dungeon branch. */ - goto_level(&g.sstairs.tolev, at_stairs, FALSE, FALSE); - } else { - /* Going down a stairs or jump in a trap door. */ - d_level newlevel; + stairway *stway = stairway_at(u.ux, u.uy); + d_level newlevel; + if (at_stairs && stway) { + newlevel.dnum = stway->tolev.dnum; + newlevel.dlevel = stway->tolev.dlevel; + goto_level(&newlevel, at_stairs, FALSE, FALSE); + } else { newlevel.dnum = u.uz.dnum; newlevel.dlevel = u.uz.dlevel + 1; goto_level(&newlevel, at_stairs, !at_stairs, FALSE); @@ -1416,17 +1417,22 @@ void prev_level(at_stairs) boolean at_stairs; { - if (at_stairs && u.ux == g.sstairs.sx && u.uy == g.sstairs.sy) { + stairway *stway = stairway_at(u.ux, u.uy); + d_level newlevel; + + if (at_stairs && stway && stway->tolev.dnum != u.uz.dnum) { /* Taking an up dungeon branch. */ /* KMH -- Upwards branches are okay if not level 1 */ /* (Just make sure it doesn't go above depth 1) */ if (!u.uz.dnum && u.uz.dlevel == 1 && !u.uhave.amulet) done(ESCAPED); - else - goto_level(&g.sstairs.tolev, at_stairs, FALSE, FALSE); + else { + newlevel.dnum = stway->tolev.dnum; + newlevel.dlevel = stway->tolev.dlevel; + goto_level(&newlevel, at_stairs, FALSE, FALSE); + } } else { /* Going up a stairs or rising through the ceiling. */ - d_level newlevel; newlevel.dnum = u.uz.dnum; newlevel.dlevel = u.uz.dlevel - 1; goto_level(&newlevel, at_stairs, FALSE, FALSE); @@ -1492,13 +1498,134 @@ int upflag; switch_terrain(); } +void +stairway_add(x, y, up, isladder, dest) +int x, y; +boolean up, isladder; +d_level *dest; +{ + stairway *tmp = (stairway *)alloc(sizeof(stairway)); + + tmp->sx = x; + tmp->sy = y; + tmp->up = up; + tmp->isladder = isladder; + assign_level(&(tmp->tolev), dest); + tmp->next = g.stairs; + g.stairs = tmp; +} + +void +stairway_free_all() +{ + stairway *tmp = g.stairs; + + while (tmp) { + stairway *tmp2 = tmp->next; + free(tmp); + tmp = tmp2; + } + g.stairs = NULL; +} + +stairway * +stairway_at(x,y) +int x,y; +{ + stairway *tmp = g.stairs; + + while (tmp && !(tmp->sx == x && tmp->sy == y)) + tmp = tmp->next; + return tmp; +} + +stairway * +stairway_find(fromdlev) +d_level *fromdlev; +{ + stairway *tmp = g.stairs; + + while (tmp) { + if (tmp->tolev.dnum == fromdlev->dnum + && tmp->tolev.dlevel == fromdlev->dlevel) + break; /* return */ + tmp = tmp->next; + } + return tmp; +} + +stairway * +stairway_find_from(fromdlev, isladder) +d_level *fromdlev; +boolean isladder; +{ + stairway *tmp = g.stairs; + + while (tmp) { + if (tmp->tolev.dnum == fromdlev->dnum + && tmp->tolev.dlevel == fromdlev->dlevel + && tmp->isladder == isladder) + break; /* return */ + tmp = tmp->next; + } + return tmp; +} + +stairway * +stairway_find_dir(up) +boolean up; +{ + stairway *tmp = g.stairs; + + while (tmp && !(tmp->up == up)) + tmp = tmp->next; + return tmp; +} + +stairway * +stairway_find_ladder() +{ + stairway *tmp = g.stairs; + + while (tmp && !tmp->isladder) + tmp = tmp->next; + return tmp; +} + +stairway * +stairway_find_type_dir(isladder, up) +boolean isladder, up; +{ + stairway *tmp = g.stairs; + + while (tmp && !(tmp->isladder == isladder && tmp->up == up)) + tmp = tmp->next; + return tmp; +} + +stairway * +stairway_find_special_dir(up) +boolean up; +{ + stairway *tmp = g.stairs; + + while (tmp) { + if (tmp->tolev.dnum != u.uz.dnum && tmp->up != up) + return tmp; + tmp = tmp->next; + } + return tmp; +} + /* place you on the special staircase */ void u_on_sstairs(upflag) int upflag; { - if (g.sstairs.sx) - u_on_newpos(g.sstairs.sx, g.sstairs.sy); + stairway *stway = stairway_find_special_dir(upflag); + + if (stway) + u_on_newpos(stway->sx, stway->sy); else u_on_rndspot(upflag); } @@ -1507,8 +1634,10 @@ int upflag; void u_on_upstairs() { - if (xupstair) - u_on_newpos(xupstair, yupstair); + stairway *stway = stairway_find_dir(TRUE); + + if (stway) + u_on_newpos(stway->sx, stway->sy); else u_on_sstairs(0); /* destination upstairs implies moving down */ } @@ -1517,8 +1646,10 @@ u_on_upstairs() void u_on_dnstairs() { - if (xdnstair) - u_on_newpos(xdnstair, ydnstair); + stairway *stway = stairway_find_dir(FALSE); + + if (stway) + u_on_newpos(stway->sx, stway->sy); else u_on_sstairs(1); /* destination dnstairs implies moving up */ } @@ -1527,37 +1658,34 @@ boolean On_stairs(x, y) xchar x, y; { - return (boolean) ((x == xupstair && y == yupstair) - || (x == xdnstair && y == ydnstair) - || (x == xdnladder && y == ydnladder) - || (x == xupladder && y == yupladder) - || (x == g.sstairs.sx && y == g.sstairs.sy)); + return (stairway_at(x,y) != NULL); } boolean On_ladder(x, y) xchar x, y; { - return (boolean) ((x == xdnladder && y == ydnladder) - || (x == xupladder && y == yupladder)); + stairway *stway = stairway_at(x,y); + + return (boolean) (stway && stway->isladder); } boolean On_stairs_up(x, y) xchar x, y; { - return ((x == xupstair && y == yupstair) - || (x == g.sstairs.sx && y == g.sstairs.sy && g.sstairs.up) - || (x == xupladder && y == yupladder)); + stairway *stway = stairway_at(x,y); + + return (boolean) (stway && stway->up); } boolean On_stairs_dn(x, y) xchar x, y; { - return ((x == xdnstair && y == ydnstair) - || (x == g.sstairs.sx && y == g.sstairs.sy && !g.sstairs.up) - || (x == xdnladder && y == ydnladder)); + stairway *stway = stairway_at(x,y); + + return (boolean) (stway && !stway->up); } boolean @@ -1599,6 +1727,8 @@ Can_rise_up(x, y, lev) int x, y; d_level *lev; { + stairway *stway = stairway_find_special_dir(FALSE); + /* can't rise up from inside the top of the Wizard's tower */ /* KMH -- or in sokoban */ if (In_endgame(lev) || In_sokoban(lev) @@ -1607,7 +1737,7 @@ d_level *lev; return (boolean) (lev->dlevel > 1 || (g.dungeons[lev->dnum].entry_lev == 1 && ledger_no(lev) != 1 - && g.sstairs.sx && g.sstairs.up)); + && stway && stway->up)); } boolean @@ -2672,8 +2802,8 @@ recalc_mapseen() struct monst *mtmp; struct cemetery *bp, **bonesaddr; struct trap *t; - unsigned i, ridx; - int x, y, ltyp, count, atmp; + unsigned i, ridx, atmp; + int x, y, ltyp, count; /* Should not happen in general, but possible if in the process * of being booted from the quest. The mapseen object gets @@ -2842,10 +2972,13 @@ recalc_mapseen() mptr->feat.ngrave = count; break; case ALTAR: + /* get the altarmask for this location; might be a mimic */ + atmp = altarmask_at(x, y); + /* convert to index: 0..3 */ atmp = (Is_astralevel(&u.uz) && (levl[x][y].seenv & SVALL) != SVALL) ? MSA_NONE - : Amask2msa(levl[x][y].altarmask); + : Amask2msa(atmp); if (!mptr->feat.naltar) mptr->feat.msalign = atmp; else if (mptr->feat.msalign != atmp) @@ -3297,6 +3430,8 @@ boolean printdun; an(shop_string(mptr->feat.shoptype))); } if (mptr->feat.naltar > 0) { + unsigned atmp; + /* Temples + non-temple altars get munged into just "altars" */ if (mptr->feat.ntemple != mptr->feat.naltar) ADDNTOBUF("altar", mptr->feat.naltar); @@ -3304,7 +3439,9 @@ boolean printdun; ADDNTOBUF("temple", mptr->feat.ntemple); /* only print out altar's god if they are all to your god */ - if (Amask2align(Msa2amask(mptr->feat.msalign)) == u.ualign.type) + atmp = mptr->feat.msalign; /* 0, 1, 2, 3 */ + atmp = Msa2amask(atmp); /* 0, 1, 2, 4 */ + if (Amask2align(atmp) == u.ualign.type) /* -128, -1, 0, +1 */ Sprintf(eos(buf), " to %s", align_gname(u.ualign.type)); } ADDNTOBUF("throne", mptr->feat.nthrone); diff --git a/src/eat.c b/src/eat.c index de5e698b6..13628642b 100644 --- a/src/eat.c +++ b/src/eat.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 eat.c $NHDT-Date: 1590971980 2020/06/01 00:39:40 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.230 $ */ +/* NetHack 3.7 eat.c $NHDT-Date: 1603507384 2020/10/24 02:43:04 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.235 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -40,7 +40,7 @@ static int FDECL(tin_variety, (struct obj *, BOOLEAN_P)); static boolean FDECL(maybe_cannibal, (int, BOOLEAN_P)); /* also used to see if you're allowed to eat cats and dogs */ -#define CANNIBAL_ALLOWED() (Role_if(PM_CAVEMAN) || Race_if(PM_ORC)) +#define CANNIBAL_ALLOWED() (Role_if(PM_CAVE_DWELLER) || Race_if(PM_ORC)) /* monster types that cause hero to be turned into stone if eaten */ #define flesh_petrifies(pm) (touch_petrifies(pm) || (pm) == &mons[PM_MEDUSA]) @@ -516,7 +516,8 @@ int *dmg_p; /* for dishing out extra damage in lieu of Int loss */ tentacle-touch should have been caught before reaching this far) */ if (magr == &g.youmonst) { if (!Stone_resistance && !Stoned) - make_stoned(5L, (char *) 0, KILLED_BY_AN, pd->mname); + make_stoned(5L, (char *) 0, KILLED_BY_AN, + pmname(pd, Mgender(mdef))); } else { /* no need to check for poly_when_stoned or Stone_resistance; mind flayers don't have those capabilities */ @@ -546,7 +547,8 @@ int *dmg_p; /* for dishing out extra damage in lieu of Int loss */ return MM_MISS; } else if (is_rider(pd)) { pline("Ingesting that is fatal."); - Sprintf(g.killer.name, "unwisely ate the brain of %s", pd->mname); + Sprintf(g.killer.name, "unwisely ate the brain of %s", + pmname(pd, Mgender(mdef))); g.killer.format = NO_KILLER_PREFIX; done(DIED); /* life-saving needed to reach here */ @@ -676,7 +678,8 @@ register int pm; if (!Stone_resistance && !(poly_when_stoned(g.youmonst.data) && polymon(PM_STONE_GOLEM))) { - Sprintf(g.killer.name, "tasting %s meat", mons[pm].mname); + Sprintf(g.killer.name, "tasting %s meat", + mons[pm].pmnames[NEUTRAL]); g.killer.format = KILLED_BY; You("turn to stone."); done(STONING); @@ -695,7 +698,8 @@ register int pm; case PM_LARGE_CAT: /* cannibals are allowed to eat domestic animals without penalty */ if (!CANNIBAL_ALLOWED()) { - You_feel("that eating the %s was a bad idea.", mons[pm].mname); + You_feel("that eating the %s was a bad idea.", + mons[pm].pmnames[NEUTRAL]); HAggravate_monster |= FROMOUTSIDE; } break; @@ -707,7 +711,8 @@ register int pm; case PM_PESTILENCE: case PM_FAMINE: { pline("Eating that is instantly fatal."); - Sprintf(g.killer.name, "unwisely ate the body of %s", mons[pm].mname); + Sprintf(g.killer.name, "unwisely ate the body of %s", + mons[pm].pmnames[NEUTRAL]); g.killer.format = NO_KILLER_PREFIX; done(DIED); /* life-saving needed to reach here */ @@ -1033,7 +1038,7 @@ int pm; Hallucination ? "You suddenly dread being peeled and mimic %s again!" : "You now prefer mimicking %s again.", - an(Upolyd ? g.youmonst.data->mname : g.urace.noun)); + an(Upolyd ? pmname(g.youmonst.data, Ugender) : g.urace.noun)); g.eatmbuf = dupstr(buf); g.nomovemsg = g.eatmbuf; g.afternmv = eatmdone; @@ -1247,9 +1252,9 @@ char *buf; Strcpy(eos(buf), " of "); } if (vegetarian(&mons[mnum])) - Sprintf(eos(buf), "%s", mons[mnum].mname); + Sprintf(eos(buf), "%s", mons[mnum].pmnames[NEUTRAL]); else - Sprintf(eos(buf), "%s meat", mons[mnum].mname); + Sprintf(eos(buf), "%s meat", mons[mnum].pmnames[NEUTRAL]); } } } @@ -1343,7 +1348,7 @@ const char *mesg; } else if (Hallucination) { what = rndmonnam(NULL); } else { - what = mons[mnum].mname; + what = mons[mnum].pmnames[NEUTRAL]; if (the_unique_pm(&mons[mnum])) which = 2; else if (type_is_pname(&mons[mnum])) @@ -1370,7 +1375,7 @@ const char *mesg; g.context.victual.fullwarn = g.context.victual.eating = g.context.victual.doreset = FALSE; - You("consume %s %s.", tintxts[r].txt, mons[mnum].mname); + You("consume %s %s.", tintxts[r].txt, mons[mnum].pmnames[NEUTRAL]); eating_conducts(&mons[mnum]); @@ -1449,7 +1454,8 @@ opentin(VOID_ARGS) { /* perhaps it was stolen (although that should cause interruption) */ if (!carried(g.context.tin.tin) - && (!obj_here(g.context.tin.tin, u.ux, u.uy) || !can_reach_floor(TRUE))) + && (!obj_here(g.context.tin.tin, u.ux, u.uy) + || !can_reach_floor(TRUE))) return 0; /* %% probably we should use tinoid */ if (g.context.tin.usedtime++ >= 50) { You("give up your attempt to open the tin."); @@ -2134,7 +2140,7 @@ eatspecial() pline("Yuck%c", otmp->blessed ? '!' : '.'); else if (otmp->oclass == SCROLL_CLASS /* check description after checking for specific scrolls */ - && !strcmpi(OBJ_DESCR(objects[otmp->otyp]), "YUM YUM")) + && objdescr_is(otmp, "YUM YUM")) pline("Yum%c", otmp->blessed ? '!' : '.'); else pline("Needs salt..."); @@ -2253,7 +2259,7 @@ struct obj *otmp; && polymon(PM_STONE_GOLEM))) { if (!Stoned) { Sprintf(g.killer.name, "%s egg", - mons[otmp->corpsenm].mname); + mons[otmp->corpsenm].pmnames[NEUTRAL]); make_stoned(5L, (char *) 0, KILLED_BY_AN, g.killer.name); } } @@ -2488,6 +2494,18 @@ doeat() } } + /* from floorfood(), &zeroobj means iron bars at current spot */ + if (otmp == &cg.zeroobj) { + /* hero in metallivore form is eating [diggable] iron bars + at current location so skip the other assorted checks; + operates as if digging rather than via the eat occupation */ + if (still_chewing(u.ux, u.uy) && levl[u.ux][u.uy].typ == IRONBARS) { + /* this is verbose, but player will see the hero rather than the + bars so wouldn't know that more turns of eating are required */ + You("pause to swallow."); + } + return 1; + } /* We have to make non-foods take 1 move to eat, unless we want to * do ridiculous amounts of coding to deal with partly eaten plate * mails, players who polymorph back to human in the middle of their @@ -2811,6 +2829,8 @@ bite() void gethungry() { + int accessorytime; + if (u.uinvulnerable) return; /* you don't feel hungrier */ @@ -2825,14 +2845,25 @@ gethungry() && !Slow_digestion) u.uhunger--; /* ordinary food consumption */ - if (g.moves % 2) { /* odd turns */ + /* + * 3.7: trigger is randomized instead of (moves % N). Makes + * ring juggling (using the 'time' option to see the turn counter + * in order to time swapping of a pair of rings of slow digestion, + * wearing one on one hand, then putting on the other and taking + * off the first, then vice versa, over and over and over and ... + * to avoid any hunger from wearing a ring) become ineffective. + * Also causes melee-induced hunger to vary from turn-based hunger + * instead of just replicating that. + */ + accessorytime = rn2(20); /* rn2(20) replaces (int) (g.moves % 20L) */ + if (accessorytime % 2) { /* odd */ /* Regeneration uses up food, unless due to an artifact */ if ((HRegeneration & ~FROMFORM) || (ERegeneration & ~(W_ARTI | W_WEP))) u.uhunger--; if (near_capacity() > SLT_ENCUMBER) u.uhunger--; - } else { /* even turns */ + } else { /* even */ if (Hunger) u.uhunger--; /* Conflict uses up food too */ @@ -2851,7 +2882,7 @@ gethungry() * cancellation") if hero doesn't have protection from some * other source (cloak or second ring). */ - switch ((int) (g.moves % 20)) { /* note: use even cases only */ + switch (accessorytime) { /* note: use even cases among 0..19 only */ case 4: if (uleft && uleft->otyp != MEAT_RING /* more hungry if +/- is nonzero or +/- doesn't apply or @@ -3143,18 +3174,18 @@ int corpsecheck; /* 0, no check, 1, corpses, 2, tinnable corpses */ register struct obj *otmp; char qbuf[QBUFSZ]; char c; - boolean feeding = !strcmp(verb, "eat"), /* corpsecheck==0 */ - offering = !strcmp(verb, "sacrifice"); /* corpsecheck==1 */ + struct permonst *uptr = g.youmonst.data; + boolean feeding = !strcmp(verb, "eat"), /* corpsecheck==0 */ + offering = !strcmp(verb, "sacrifice"); /* corpsecheck==1 */ /* if we can't touch floor objects then use invent food only */ if (iflags.menu_requested /* command was preceded by 'm' prefix */ || !can_reach_floor(TRUE) || (feeding && u.usteed) || (is_pool_or_lava(u.ux, u.uy) - && (Wwalking || is_clinger(g.youmonst.data) - || (Flying && !Breathless)))) + && (Wwalking || is_clinger(uptr) || (Flying && !Breathless)))) goto skipfloor; - if (feeding && metallivorous(g.youmonst.data)) { + if (feeding && metallivorous(uptr)) { struct obj *gold; struct trap *ttmp = t_at(u.ux, u.uy); @@ -3175,8 +3206,30 @@ int corpsecheck; /* 0, no check, 1, corpses, 2, tinnable corpses */ return (struct obj *) 0; } } + if (levl[u.ux][u.uy].typ == IRONBARS) { + /* already verified that hero is metallivorous above */ + boolean nodig = (levl[u.ux][u.uy].wall_info & W_NONDIGGABLE) != 0; - if (g.youmonst.data != &mons[PM_RUST_MONSTER] + c = 'n'; + Strcpy(qbuf, "There are iron bars here"); + if (nodig || u.uhunger > 1500) { + pline("%s but you %s eat them.", qbuf, + nodig ? "cannot" : "are too full to"); + } else { + Strcat(qbuf, ((!g.context.digging.chew + || g.context.digging.pos.x != u.ux + || g.context.digging.pos.y != u.uy + || !on_level(&g.context.digging.level, &u.uz)) + ? "; eat them?" + : "; resume eating them?")); + c = yn_function(qbuf, ynqchars, 'n'); + } + if (c == 'y') + return (struct obj *) &cg.zeroobj; /* csst away 'const' */ + else if (c == 'q') + return (struct obj *) 0; + } + if (uptr != &mons[PM_RUST_MONSTER] && (gold = g_at(u.ux, u.uy)) != 0) { if (gold->quan == 1L) Sprintf(qbuf, "There is 1 gold piece here; eat it?"); diff --git a/src/end.c b/src/end.c index a33e9ef07..f362a07c6 100644 --- a/src/end.c +++ b/src/end.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 end.c $NHDT-Date: 1583190253 2020/03/02 23:04:13 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.208 $ */ +/* NetHack 3.7 end.c $NHDT-Date: 1608749031 2020/12/23 18:43:51 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.216 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -409,16 +409,17 @@ int how; /* "killed by the high priest of Crom" is okay, "killed by the high priest" alone isn't */ if ((mptr->geno & G_UNIQ) != 0 && !(imitator && !mimicker) - && !(mptr == &mons[PM_HIGH_PRIEST] && !mtmp->ispriest)) { + && !(mptr == &mons[PM_HIGH_CLERIC] && !mtmp->ispriest)) { if (!type_is_pname(mptr)) Strcat(buf, "the "); g.killer.format = KILLED_BY; } /* _the_ ghost of Dudley */ - if (mptr == &mons[PM_GHOST] && has_mname(mtmp)) { + if (mptr == &mons[PM_GHOST] && has_mgivenname(mtmp)) { Strcat(buf, "the "); g.killer.format = KILLED_BY; } + (void) monhealthdescr(mtmp, TRUE, eos(buf)); if (mtmp->minvis) Strcat(buf, "invisible "); if (distorted) @@ -426,14 +427,15 @@ int how; if (imitator) { char shape[BUFSZ]; - const char *realnm = champtr->mname, *fakenm = mptr->mname; + const char *realnm = pmname(champtr, Mgender(mtmp)), + *fakenm = pmname(mptr, Mgender(mtmp)); boolean alt = is_vampshifter(mtmp); if (mimicker) { /* realnm is already correct because champtr==mptr; set up fake mptr for type_is_pname/the_unique_pm */ mptr = &mons[mtmp->mappearance]; - fakenm = mptr->mname; + fakenm = pmname(mptr, Mgender(mtmp)); } else if (alt && strstri(realnm, "vampire") && !strcmp(fakenm, "vampire bat")) { /* special case: use "vampire in bat form" in preference @@ -458,8 +460,8 @@ int how; mptr = mtmp->data; /* reset for mimicker case */ } else if (mptr == &mons[PM_GHOST]) { Strcat(buf, "ghost"); - if (has_mname(mtmp)) - Sprintf(eos(buf), " of %s", MNAME(mtmp)); + if (has_mgivenname(mtmp)) + Sprintf(eos(buf), " of %s", MGIVENNAME(mtmp)); } else if (mtmp->isshk) { const char *shknm = shkname(mtmp), *honorific = shkname_is_pname(mtmp) ? "" @@ -472,9 +474,9 @@ int how; it overrides the effect of Hallucination on priestname() */ Strcat(buf, m_monnam(mtmp)); } else { - Strcat(buf, mptr->mname); - if (has_mname(mtmp)) - Sprintf(eos(buf), " called %s", MNAME(mtmp)); + Strcat(buf, pmname(mptr, Mgender(mtmp))); + if (has_mgivenname(mtmp)) + Sprintf(eos(buf), " called %s", MGIVENNAME(mtmp)); } Strcpy(g.killer.name, buf); @@ -491,6 +493,8 @@ int how; u.ugrave_arise = PM_WRAITH; else if (mptr->mlet == S_MUMMY && g.urace.mummynum != NON_PM) u.ugrave_arise = g.urace.mummynum; + else if (zombie_maker(mptr) && zombie_form(g.youmonst.data) != NON_PM) + u.ugrave_arise = zombie_form(g.youmonst.data); else if (mptr->mlet == S_VAMPIRE && Race_if(PM_HUMAN)) u.ugrave_arise = PM_VAMPIRE; else if (mptr == &mons[PM_GHOUL]) @@ -784,7 +788,7 @@ boolean taken; c = ask ? yn_function(qbuf, ynqchars, defquery) : defquery; if (c == 'y') { /* caller has already ID'd everything */ - (void) display_inventory((char *) 0, TRUE); + (void) display_inventory((char *) 0, FALSE); container_contents(g.invent, TRUE, TRUE, FALSE); } if (c == 'q') @@ -818,9 +822,14 @@ boolean taken; if (should_query_disclose_option('c', &defquery)) { int acnt = count_achievements(); - Sprintf(qbuf, "Do you want to see your conduct%s%s?", - (acnt > 0) ? " and achievement" : "", - (acnt > 1) ? "s" : ""); + Sprintf(qbuf, "Do you want to see your conduct%s?", + /* this was distinguishing between one achievement and + multiple achievements, but "conduct and achievement" + looked strange if multiple conducts got shown (which + is usual for an early game death); we could switch + to plural vs singular for conducts but the less + specific "conduct and achievements" is sufficient */ + (acnt > 0) ? " and achievements" : ""); c = yn_function(qbuf, ynqchars, defquery); } else { c = defquery; @@ -1315,8 +1324,7 @@ int how; for (obj = g.invent; obj; obj = obj->nobj) { discover_object(obj->otyp, TRUE, FALSE); obj->known = obj->bknown = obj->dknown = obj->rknown = 1; - if (Is_container(obj) || obj->otyp == STATUE) - obj->cknown = obj->lknown = 1; + set_cknown_lknown(obj); /* set flags when applicable */ /* we resolve Schroedinger's cat now in case of both disclosure and dumplog, where the 50:50 chance for live cat has to be the same both times */ @@ -1376,8 +1384,8 @@ int how; umoney = money_cnt(g.invent); tmp = u.umoney0; - umoney += hidden_gold(); /* accumulate gold from containers */ - tmp = umoney - tmp; /* net gain */ + umoney += hidden_gold(TRUE); /* accumulate gold from containers */ + tmp = umoney - tmp; /* net gain */ if (tmp < 0L) tmp = 0L; @@ -1407,7 +1415,7 @@ int how; (u.ugrave_arise != PM_GREEN_SLIME) ? "body rises from the dead" : "revenant persists", - an(mons[u.ugrave_arise].mname)); + an(pmname(&mons[u.ugrave_arise], Ugender))); display_nhwindow(WIN_MESSAGE, FALSE); } diff --git a/src/engrave.c b/src/engrave.c index f78545329..c35311d23 100644 --- a/src/engrave.c +++ b/src/engrave.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 engrave.c $NHDT-Date: 1589827569 2020/05/18 18:46:09 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.97 $ */ +/* NetHack 3.7 engrave.c $NHDT-Date: 1608673691 2020/12/22 21:48:11 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.99 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -146,20 +146,23 @@ boolean check_pit; { struct trap *t; - if (u.uswallow) + if (u.uswallow || (u.ustuck && !sticks(g.youmonst.data)) + || (Levitation && !(Is_airlevel(&u.uz) || Is_waterlevel(&u.uz)))) return FALSE; /* Restricted/unskilled riders can't reach the floor */ if (u.usteed && P_SKILL(P_RIDING) < P_BASIC) return FALSE; - if (check_pit && !Flying - && (t = t_at(u.ux, u.uy)) != 0 + if (u.uundetected && ceiling_hider(g.youmonst.data)) + return FALSE; + + if (Flying || g.youmonst.data->msize >= MZ_HUGE) + return TRUE; + + if (check_pit && (t = t_at(u.ux, u.uy)) != 0 && (uteetering_at_seen_pit(t) || uescaped_shaft(t))) return FALSE; - return (boolean) ((!Levitation || Is_airlevel(&u.uz) - || Is_waterlevel(&u.uz)) - && (!u.uundetected || !is_hider(g.youmonst.data) - || u.umonnum == PM_TRAPPER)); + return TRUE; } /* give a message after caller has determined that hero can't reach */ diff --git a/src/exper.c b/src/exper.c index f7e426db4..ea2dcc6bb 100644 --- a/src/exper.c +++ b/src/exper.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 exper.c $NHDT-Date: 1562114352 2019/07/03 00:39:12 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.33 $ */ +/* NetHack 3.7 exper.c $NHDT-Date: 1596498167 2020/08/03 23:42:47 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.43 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2007. */ /* NetHack may be freely redistributed. See license for details. */ @@ -28,7 +28,7 @@ enermod(en) int en; { switch (Role_switch) { - case PM_PRIEST: + case PM_CLERIC: case PM_WIZARD: return (2 * en); case PM_HEALER: diff --git a/src/explode.c b/src/explode.c index c44baa261..30dc6b92c 100644 --- a/src/explode.c +++ b/src/explode.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 explode.c $NHDT-Date: 1589322381 2020/05/12 22:26:21 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.70 $ */ +/* NetHack 3.7 explode.c $NHDT-Date: 1596498168 2020/08/03 23:42:48 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.71 $ */ /* Copyright (C) 1990 by Ken Arromdee */ /* NetHack may be freely redistributed. See license for details. */ @@ -66,7 +66,7 @@ int expltype; type = 0; } switch (Role_switch) { - case PM_PRIEST: + case PM_CLERIC: case PM_MONK: case PM_WIZARD: damu /= 5; @@ -412,6 +412,9 @@ int expltype; idamnonres += destroy_mitem(mtmp, WAND_CLASS, (int) adtyp); idamnonres += destroy_mitem(mtmp, RING_CLASS, (int) adtyp); + if (adtyp == AD_FIRE) + ignite_items(mtmp->minvent); + if (explmask[i][j] == 1) { golemeffects(mtmp, (int) adtyp, dam + idamres); mtmp->mhp -= idamnonres; @@ -500,8 +503,10 @@ int expltype; You("are unharmed!"); } else if (adtyp == AD_PHYS || physical_dmg) damu = Maybe_Half_Phys(damu); - if (adtyp == AD_FIRE) + if (adtyp == AD_FIRE) { (void) burnarmor(&g.youmonst); + ignite_items(g.invent); + } destroy_item(SCROLL_CLASS, (int) adtyp); destroy_item(SPBOOK_CLASS, (int) adtyp); destroy_item(POTION_CLASS, (int) adtyp); diff --git a/src/extralev.c b/src/extralev.c index b3a19504d..4e03acac0 100644 --- a/src/extralev.c +++ b/src/extralev.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 extralev.c $NHDT-Date: 1446975468 2015/11/08 09:37:48 $ $NHDT-Branch: master $:$NHDT-Revision: 1.12 $ */ +/* NetHack 3.7 extralev.c $NHDT-Date: 1596498169 2020/08/03 23:42:49 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.19 $ */ /* Copyright 1988, 1989 by Ken Arromdee */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/src/files.c b/src/files.c index d106ed4f3..f995f8d1a 100644 --- a/src/files.c +++ b/src/files.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 files.c $NHDT-Date: 1593953349 2020/07/05 12:49:09 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.315 $ */ +/* NetHack 3.7 files.c $NHDT-Date: 1596785343 2020/08/07 07:29:03 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.318 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Derek S. Ray, 2015. */ /* NetHack may be freely redistributed. See license for details. */ @@ -163,7 +163,7 @@ static void FDECL(adjust_prefix, (char *, int)); static boolean FDECL(config_error_nextline, (const char *)); static void NDECL(free_config_sections); static char *FDECL(choose_random_part, (char *, CHAR_P)); -static boolean FDECL(is_config_section, (const char *)); +static char *FDECL(is_config_section, (char *)); static boolean FDECL(handle_config_section, (char *)); static char *FDECL(find_optparam, (const char *)); static void FDECL(parseformat, (int *, char *)); @@ -630,10 +630,10 @@ clearlocks() #endif #ifndef NO_SIGNAL (void) signal(SIGINT, SIG_IGN); -#endif #if defined(UNIX) || defined(VMS) sethanguphandler((void FDECL((*), (int) )) SIG_IGN); #endif +#endif /* NO_SIGNAL */ /* can't access maxledgerno() before dungeons are created -dlc */ for (x = (g.n_dgns ? maxledgerno() : 0); x >= 0; x--) delete_levelfile(x); /* not all levels need be present */ @@ -686,12 +686,12 @@ d_level *lev; char *dptr; /* - * "bonD0.nn.le" = bones for level nn in the main dungeon; - * "bonM0.T.le" = bones for Minetown; - * "bonQBar.n.le" = bones for level n in the Barbarian quest; - * "bon3D0.nn.le" = \ - * "bon3M0.T.le" = > same as above, but for bones pool #3. - * "bon3QBar.n.le" = / + * "bonD0.nn" = bones for level nn in the main dungeon; + * "bonM0.T" = bones for Minetown; + * "bonQBar.n" = bones for level n in the Barbarian quest; + * "bon3D0.nn" = \ + * "bon3M0.T" = > same as above, but for bones pool #3. + * "bon3QBar.n" = / * * Return value for content validation skips "bon" and the * pool number (if present), making it feasible for the admin @@ -707,15 +707,9 @@ d_level *lev; Sprintf(eos(file), "%u", poolnum); } #endif - dptr = eos(file); /* this used to be after the following Sprintf() - and the return value was (dptr - 2) */ + dptr = eos(file); /* when this naming scheme was adopted, 'filecode' was one letter; - 3.3.0 turned it into a three letter string (via roles[] in role.c); - from that version through 3.6.0, 'dptr' pointed past the filecode - and the return value of (dptr - 2) was wrong for bones produced - in the quest branch, skipping the boneid character 'Q' and the - first letter of the role's filecode; bones loading still worked - because the bonesid used for validation had the same error */ + 3.3.0 turned it into a three letter string for quest levels */ Sprintf(dptr, "%c%s", g.dungeons[lev->dnum].boneid, In_quest(lev) ? g.urole.filecode : "0"); if ((sptr = Is_special(lev)) != 0) @@ -779,7 +773,8 @@ char errbuf[]; /* 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); + nhfp->fd = open(file, + O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, FCMASK); #else #ifdef MAC nhfp->fd = maccreat(file, BONE_TYPE); @@ -2263,7 +2258,7 @@ int prefixid; /* Choose at random one of the sep separated parts from str. Mangles str. */ static char * -choose_random_part(str,sep) +choose_random_part(str, sep) char *str; char sep; { @@ -2315,28 +2310,58 @@ free_config_sections() } } -static boolean +/* check for " [ anything-except-bracket-or-empty ] # arbitrary-comment" + with spaces optional; returns pointer to "anything-except..." (with + trailing " ] #..." stripped) if ok, otherwise Null */ +static char * is_config_section(str) -const char *str; +char *str; /* trailing spaces will be stripped, ']' too iff result is good */ { - const char *a = rindex(str, ']'); + char *a, *c, *z; - return (a && *str == '[' && *(a+1) == '\0' && (int)(a - str) > 0); + /* 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 = index(a, ']'); + if (!z) + return (char *) 0; + for (c = z + 1; *c && *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); } static boolean handle_config_section(buf) char *buf; { - if (is_config_section(buf)) { - char *send; - if (g.config_section_current) { - free(g.config_section_current); + char *sect = is_config_section(buf); + + if (sect) { + if (g.config_section_current) + free(g.config_section_current), g.config_section_current = 0; + /* is_config_section() removed brackets from 'sect' */ + if (!g.config_section_chosen) { + config_error_add("Section \"[%s]\" without CHOOSE", sect); + return TRUE; + } + if (*sect) { /* got a section name */ + g.config_section_current = dupstr(sect); + debugpline1("set config section: '%s'", g.config_section_current); + } else { /* empty section name => end of sections */ + free_config_sections(); + debugpline0("unset config section"); } - g.config_section_current = dupstr(&buf[1]); - send = rindex(g.config_section_current, ']'); - *send = '\0'; - debugpline1("set config section: '%s'", g.config_section_current); return TRUE; } @@ -2675,8 +2700,7 @@ char *origbuf; retval = FALSE; #endif } else if (match_varname(buf, "WARNINGS", 5)) { - (void) get_uchars(bufp, translate, FALSE, WARNCOUNT, - "WARNINGS"); + (void) get_uchars(bufp, translate, FALSE, WARNCOUNT, "WARNINGS"); assign_warnings(translate); } else if (match_varname(buf, "ROGUESYMBOLS", 4)) { if (!parsesymbols(bufp, ROGUESET)) { @@ -3065,7 +3089,7 @@ struct obj *obj; /* subset of starting inventory pre-ID */ obj->dknown = 1; - if (Role_if(PM_PRIEST)) + if (Role_if(PM_CLERIC)) obj->bknown = 1; /* ok to bypass set_bknown() */ /* same criteria as lift_object()'s check for available inventory slot */ if (obj->oclass != COIN_CLASS && inv_cnt(FALSE) >= 52 diff --git a/src/fountain.c b/src/fountain.c index 14b5a5a9f..f5be392dd 100644 --- a/src/fountain.c +++ b/src/fountain.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 fountain.c $NHDT-Date: 1583926845 2020/03/11 11:40:45 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.67 $ */ +/* NetHack 3.7 fountain.c $NHDT-Date: 1596498170 2020/08/03 23:42:50 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.69 $ */ /* Copyright Scott R. Turner, srt@ucla, 10/27/86 */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/src/hack.c b/src/hack.c index 81ed3c38e..30ea83a96 100644 --- a/src/hack.c +++ b/src/hack.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 hack.c $NHDT-Date: 1585993266 2020/04/04 09:41:06 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.254 $ */ +/* NetHack 3.7 hack.c $NHDT-Date: 1608673692 2020/12/22 21:48:12 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.274 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Derek S. Ray, 2015. */ /* NetHack may be freely redistributed. See license for details. */ @@ -9,7 +9,6 @@ static void NDECL(maybe_wail); static int NDECL(moverock); -static int FDECL(still_chewing, (XCHAR_P, XCHAR_P)); static void NDECL(dosinkfall); static boolean FDECL(findtravelpath, (int)); static boolean FDECL(trapmove, (int, int, struct trap *)); @@ -394,7 +393,7 @@ moverock() * Chew on a wall, door, or boulder. [What about statues?] * Returns TRUE if still eating, FALSE when done. */ -static int +int still_chewing(x, y) xchar x, y; { @@ -418,7 +417,15 @@ xchar x, y; : "hard stone"); nomul(0); return 1; - } else if (g.context.digging.pos.x != x || g.context.digging.pos.y != y + } else if (lev->typ == IRONBARS + && metallivorous(g.youmonst.data) && u.uhunger > 1500) { + /* finishing eating via 'morehungry()' doesn't handle choking */ + You("are too full to eat the bars."); + nomul(0); + return 1; + } else if (!g.context.digging.chew + || g.context.digging.pos.x != x + || g.context.digging.pos.y != y || !on_level(&g.context.digging.level, &u.uz)) { g.context.digging.down = FALSE; g.context.digging.chew = TRUE; @@ -504,7 +511,20 @@ xchar x, y; digtxt = "chew through the tree."; lev->typ = ROOM; } else if (lev->typ == IRONBARS) { - digtxt = "eat through the bars."; + if (metallivorous(g.youmonst.data)) { /* should always be True here */ + /* arbitrary amount; unlike proper eating, nutrition is + bestowed in a lump sum at the end */ + int nut = (int) objects[HEAVY_IRON_BALL].oc_weight; + + /* lesshungry() requires that victual be set up, so skip it; + morehungry() of a negative amount will increase nutrition + without any possibility of choking to death on the meal; + updates hunger state and requests status update if changed */ + morehungry(-nut); + } + digtxt = (x == u.ux && y == u.uy) + ? "devour the iron bars." + : "eat through the bars."; dissolve_bars(x, y); } else if (lev->typ == SDOOR) { if (lev->doormask & D_TRAPPED) { @@ -552,6 +572,7 @@ register xchar ox, oy; { /* optimize by leaving on the fobj chain? */ remove_object(obj); + maybe_unhide_at(obj->ox, obj->oy); newsym(obj->ox, obj->oy); place_object(obj, ox, oy); newsym(ox, oy); @@ -745,8 +766,10 @@ int mode; pline("There is an obstacle there."); return FALSE; } else if (tmpr->typ == IRONBARS) { - if ((dmgtype(g.youmonst.data, AD_RUST) - || dmgtype(g.youmonst.data, AD_CORR)) && mode == DO_MOVE + if (mode == DO_MOVE + && (dmgtype(g.youmonst.data, AD_RUST) + || dmgtype(g.youmonst.data, AD_CORR) + || metallivorous(g.youmonst.data)) && still_chewing(x, y)) { return FALSE; } @@ -1866,14 +1889,12 @@ domove_core() /* can't swap places when pet won't fit thru the opening */ You("stop. %s won't fit through.", upstart(y_monnam(mtmp))); didnt_move = TRUE; - } else if ((mtmp->mpeaceful || mtmp->mtame) && mtmp->mtrapped) { - /* Since peaceful monsters simply being unable to move out of traps - * was inconsistent with pets being able to but being untamed in - * the process, apply this logic equally to pets and peacefuls. */ + } else if (mtmp->mpeaceful && mtmp->mtrapped) { + /* all mtame are also mpeaceful, so this affects pets too */ You("stop. %s can't move out of that trap.", upstart(y_monnam(mtmp))); didnt_move = TRUE; - } else if (mtmp->mpeaceful && !mtmp->mtame + } else if (mtmp->mpeaceful && (!goodpos(u.ux0, u.uy0, mtmp, 0) || t_at(u.ux0, u.uy0) != NULL || mundisplaceable(mtmp))) { @@ -1892,10 +1913,10 @@ domove_core() You("%s %s.", mtmp->mpeaceful ? "swap places with" : "frighten", x_monnam(mtmp, mtmp->mtame ? ARTICLE_YOUR - : (!has_mname(mtmp) && !type_is_pname(mtmp->data)) + : (!has_mgivenname(mtmp) && !type_is_pname(mtmp->data)) ? ARTICLE_THE : ARTICLE_NONE, (mtmp->mpeaceful && !mtmp->mtame) ? "peaceful" : 0, - has_mname(mtmp) ? SUPPRESS_SADDLE : 0, FALSE)); + has_mgivenname(mtmp) ? SUPPRESS_SADDLE : 0, FALSE)); /* check for displacing it into pools and traps */ switch (minliquid(mtmp) ? 2 : mintrap(mtmp)) { @@ -2039,6 +2060,22 @@ int x1, y1, x2, y2; } } +/* HP loss or passing out from overexerting yourself */ +void +overexert_hp() +{ + int *hp = (!Upolyd ? &u.uhp : &u.mh); + + if (*hp > 1) { + *hp -= 1; + g.context.botl = TRUE; + } else { + You("pass out from exertion!"); + exercise(A_CON, FALSE); + fall_asleep(-10, FALSE); + } +} + /* combat increases metabolism */ boolean overexertion() @@ -2048,15 +2085,7 @@ overexertion() execute if you decline to attack a peaceful monster */ gethungry(); if ((g.moves % 3L) != 0L && near_capacity() >= HVY_ENCUMBER) { - int *hp = (!Upolyd ? &u.uhp : &u.mh); - - if (*hp > 1) { - *hp -= 1; - } else { - You("pass out from exertion!"); - exercise(A_CON, FALSE); - fall_asleep(-10, FALSE); - } + overexert_hp(); } return (boolean) (g.multi < 0); /* might have fainted (forced to sleep) */ } @@ -2663,6 +2692,8 @@ boolean newlev; static int pickup_checks() { + struct trap *traphere; + /* uswallow case added by GAN 01/29/87 */ if (u.uswallow) { if (!u.ustuck->minvent) { @@ -2678,8 +2709,8 @@ pickup_checks() } } if (is_pool(u.ux, u.uy)) { - if (Wwalking || is_floater(g.youmonst.data) || is_clinger(g.youmonst.data) - || (Flying && !Breathless)) { + if (Wwalking || is_floater(g.youmonst.data) + || is_clinger(g.youmonst.data) || (Flying && !Breathless)) { You("cannot dive into the %s to pick things up.", hliquid("water")); return 0; @@ -2689,8 +2720,8 @@ pickup_checks() } } if (is_lava(u.ux, u.uy)) { - if (Wwalking || is_floater(g.youmonst.data) || is_clinger(g.youmonst.data) - || (Flying && !Breathless)) { + if (Wwalking || is_floater(g.youmonst.data) + || is_clinger(g.youmonst.data) || (Flying && !Breathless)) { You_cant("reach the bottom to pick things up."); return 0; } else if (!likes_lava(g.youmonst.data)) { @@ -2720,18 +2751,27 @@ pickup_checks() There("is nothing here to pick up."); return 0; } - if (!can_reach_floor(TRUE)) { - struct trap *traphere = t_at(u.ux, u.uy); - if (traphere - && (uteetering_at_seen_pit(traphere) || uescaped_shaft(traphere))) - You("cannot reach the bottom of the %s.", - is_pit(traphere->ttyp) ? "pit" : "abyss"); - else if (u.usteed && P_SKILL(P_RIDING) < P_BASIC) + traphere = t_at(u.ux, u.uy); + if (!can_reach_floor(traphere && is_pit(traphere->ttyp))) { + /* it here's a hole here, any objects here clearly aren't at + the bottom so only check for pits */ + if (traphere && uteetering_at_seen_pit(traphere)) { + You("cannot reach the bottom of the pit."); + } else if (u.usteed && P_SKILL(P_RIDING) < P_BASIC) { rider_cant_reach(); - else if (Blind && !can_reach_floor(TRUE)) + } else if (Blind) { You("cannot reach anything here."); - else - You("cannot reach the %s.", surface(u.ux, u.uy)); + } else { + const char *surf = surface(u.ux, u.uy); + + if (traphere) { + if (traphere->ttyp == HOLE) + surf = "edge of the hole"; + else if (traphere->ttyp == TRAPDOOR) + surf = "trap door"; + } + You("cannot reach the %s.", surf); + } return 0; } return -1; /* can do normal pickup */ @@ -2969,12 +3009,13 @@ monster_nearby() for (y = u.uy - 1; y <= u.uy + 1; y++) { if (!isok(x, y) || (x == u.ux && y == u.uy)) continue; - if ((mtmp = m_at(x, y)) && M_AP_TYPE(mtmp) != M_AP_FURNITURE + if ((mtmp = m_at(x, y)) != 0 + && M_AP_TYPE(mtmp) != M_AP_FURNITURE && M_AP_TYPE(mtmp) != M_AP_OBJECT - && (!mtmp->mpeaceful || Hallucination) + && (Hallucination + || (!mtmp->mpeaceful && !noattacks(mtmp->data))) && (!is_hider(mtmp->data) || !mtmp->mundetected) - && !noattacks(mtmp->data) && mtmp->mcanmove - && !mtmp->msleeping /* aplvax!jcn */ + && mtmp->mcanmove && !mtmp->msleeping && !onscary(u.ux, u.uy, mtmp) && canspotmon(mtmp)) return 1; } @@ -3030,7 +3071,8 @@ const char *msg_override; if life-saved while poly'd and Unchanging (explore or wizard mode declining to die since can't be both Unchanging and Lifesaved) */ if (Upolyd && !strncmpi(g.nomovemsg, "You survived that ", 18)) - You("are %s.", an(mons[u.umonnum].mname)); /* (ignore Hallu) */ + You("are %s.", + an(pmname(&mons[u.umonnum], Ugender))); /* (ignore Hallu) */ } g.nomovemsg = 0; u.usleep = 0; diff --git a/src/hacklib.c b/src/hacklib.c index 60f1dfd76..3600ec798 100644 --- a/src/hacklib.c +++ b/src/hacklib.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 hacklib.c $NHDT-Date: 1578137629 2020/01/04 11:33:49 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.80 $ */ +/* NetHack 3.7 hacklib.c $NHDT-Date: 1596498172 2020/08/03 23:42:52 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.85 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2007. */ /* Copyright (c) Robert Patrick Rankin, 1991 */ diff --git a/src/insight.c b/src/insight.c index b26e1efbf..fd5bbfd3e 100644 --- a/src/insight.c +++ b/src/insight.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 insight.c $NHDT-Date: 1593771616 2020/07/03 10:20:16 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.18 $ */ +/* NetHack 3.7 insight.c $NHDT-Date: 1608115734 2020/12/16 10:48:54 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.23 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -259,9 +259,7 @@ int final; /* ENL_GAMEINPROGRESS:0, ENL_GAMEOVERALIVE, ENL_GAMEOVERDEAD */ characteristics_enlightenment(mode, final); } /* expanded status line information, including things which aren't - included there due to space considerations--such as obvious - alternative movement indicators (riding, levitation, &c), and - various troubles (turning to stone, trapped, confusion, &c); + included there due to space considerations; shown for both basic and magic enlightenment */ status_enlightenment(mode, final); /* remaining attributes; shown for potion,&c or wizard mode and @@ -270,6 +268,13 @@ int final; /* ENL_GAMEINPROGRESS:0, ENL_GAMEOVERALIVE, ENL_GAMEOVERDEAD */ /* intrinsics and other traditional enlightenment feedback */ attributes_enlightenment(mode, final); } + /* reminder to player and/or information for dumplog */ + if ((mode & BASICENLIGHTENMENT) != 0 && (wizard || discover)) { + enlght_out(""); /* separator */ + enlght_out("Miscellaneous:"); + Sprintf(buf, "running in %s mode", wizard ? "debug" : "explore"); + you_are(buf, ""); + } if (!g.en_via_menu) { display_nhwindow(g.en_win, TRUE); @@ -322,10 +327,12 @@ int final; if (!is_male(uasmon) && !is_female(uasmon) && !is_neuter(uasmon)) Sprintf(tmpbuf, "%s ", genders[flags.female ? 1 : 0].adj); if (altphrasing) - Sprintf(eos(tmpbuf), "%s in ", mons[g.youmonst.cham].mname); + Sprintf(eos(tmpbuf), "%s in ", + pmname(&mons[g.youmonst.cham], + flags.female ? FEMALE : MALE)); Sprintf(buf, "%s%s%s%s form", !final ? "currently " : "", altphrasing ? just_an(anbuf, tmpbuf) : "in ", - tmpbuf, uasmon->mname); + tmpbuf, pmname(uasmon, flags.female ? FEMALE : MALE)); you_are(buf, ""); } @@ -585,7 +592,11 @@ int final; you_have(buf, ""); } + find_ac(); /* enforces AC_MAX cap */ Sprintf(buf, "%d", u.uac); + if (abs(u.uac) == AC_MAX) + Sprintf(eos(buf), ", the %s possible", + (u.uac < 0) ? "best" : "worst"); enl_msg("Your armor class ", "is ", "was ", buf, ""); /* gold; similar to doprgold(#seegold) but without shop billing info; @@ -976,12 +987,18 @@ int final; } Strcpy(buf, hu_stat[u.uhs]); /* hunger status; omitted if "normal" */ mungspaces(buf); /* strip trailing spaces */ - if (*buf) { + /* status line doesn't show hunger when state is "not hungry", we do; + needed for wizard mode's reveal of u.uhunger but add it for everyone */ + if (!*buf) + Strcpy(buf, "not hungry"); + if (*buf) { /* (since "not hungry" was added, this will always be True) */ *buf = lowc(*buf); /* override capitalization */ if (!strcmp(buf, "weak")) Strcat(buf, " from severe hunger"); else if (!strncmp(buf, "faint", 5)) /* fainting, fainted */ Strcat(buf, " due to starvation"); + if (wizard) + Sprintf(eos(buf), " <%d>", u.uhunger); you_are(buf, ""); } /* encumbrance */ @@ -1007,6 +1024,8 @@ int final; adj = "not possible"; break; } + if (wizard) + Sprintf(eos(buf), " <%d>", inv_weight()); Sprintf(eos(buf), "; movement %s %s%s", !final ? "is" : "was", adj, (cap < OVERLOADED) ? " slowed" : ""); you_are(buf, ""); @@ -1014,10 +1033,22 @@ int final; /* last resort entry, guarantees Status section is non-empty (no longer needed for that purpose since weapon status added; still useful though) */ - you_are("unencumbered", ""); + Strcpy(buf, "unencumbered"); + if (wizard) + Sprintf(eos(buf), " <%d>", inv_weight()); + you_are(buf, ""); } /* current weapon(s) and corresponding skill level(s) */ weapon_insight(final); + /* unlike ring of increase accuracy's effect, the monk's suit penalty + is too blatant to be restricted to magical enlightenment */ + if (iflags.tux_penalty && !Upolyd) { + (void) enlght_combatinc("to hit", -g.urole.spelarmr, final, buf); + /* if from_what() ever gets extended from wizard mode to normal + play, it could be adapted to handle this */ + Sprintf(eos(buf), " due to your %s", suit_simple_name(uarm)); + you_have(buf, ""); + } /* report 'nudity' */ if (!uarm && !uarmu && !uarmc && !uarms && !uarmg && !uarmf && !uarmh) { if (u.uroleplay.nudist) @@ -1338,7 +1369,7 @@ int final; } if (Warn_of_mon && g.context.warntype.speciesidx >= LOW_PM) { Sprintf(buf, "aware of the presence of %s", - makeplural(mons[g.context.warntype.speciesidx].mname)); + makeplural(mons[g.context.warntype.speciesidx].pmnames[NEUTRAL])); you_are(buf, from_what(WARN_OF_MON)); } if (Undead_warning) @@ -1467,8 +1498,17 @@ int final; enl_msg("You regenerate", "", "d", "", from_what(REGENERATION)); if (Slow_digestion) you_have("slower digestion", from_what(SLOW_DIGESTION)); - if (u.uhitinc) - you_have(enlght_combatinc("to hit", u.uhitinc, final, buf), ""); + if (u.uhitinc) { + (void) enlght_combatinc("to hit", u.uhitinc, final, buf); + if (iflags.tux_penalty && !Upolyd) + Sprintf(eos(buf), " %s your suit's penalty", + (u.uhitinc < 0) ? "increasing" + : (u.uhitinc < 4 * g.urole.spelarmr / 5) + ? "partly offsetting" + : (u.uhitinc < g.urole.spelarmr) ? "nearly offseting" + : "overcoming"); + you_have(buf, ""); + } if (u.udaminc) you_have(enlght_combatinc("damage", u.udaminc, final, buf), ""); if (u.uspellprot || Protection) { @@ -1536,10 +1576,14 @@ int final; && u.umonnum == PM_GREEN_SLIME && !Unchanging)) { /* foreign shape (except were-form which is handled below) */ if (!vampshifted(&g.youmonst)) - Sprintf(buf, "polymorphed into %s", an(g.youmonst.data->mname)); + Sprintf(buf, "polymorphed into %s", + an(pmname(g.youmonst.data, + flags.female ? FEMALE : MALE))); else Sprintf(buf, "polymorphed into %s in %s form", - an(mons[g.youmonst.cham].mname), g.youmonst.data->mname); + an(pmname(&mons[g.youmonst.cham], + flags.female ? FEMALE : MALE)), + pmname(g.youmonst.data, flags.female ? FEMALE : MALE)); if (wizard) Sprintf(eos(buf), " (%d)", u.mtimedone); you_are(buf, ""); @@ -1548,7 +1592,8 @@ int final; you_can("lay eggs", ""); if (u.ulycn >= LOW_PM) { /* "you are a werecreature [in beast form]" */ - Strcpy(buf, an(mons[u.ulycn].mname)); + Strcpy(buf, an(pmname(&mons[u.ulycn], + flags.female ? FEMALE : MALE))); if (u.umonnum == u.ulycn) { Strcat(buf, " in beast form"); if (wizard) @@ -2188,15 +2233,16 @@ const genericptr vptr2; res = mstr2 - mstr1; /* monstr high to low */ break; case VANQ_ALPHA_SEP: - uniq1 = ((mons[indx1].geno & G_UNIQ) && indx1 != PM_HIGH_PRIEST); - uniq2 = ((mons[indx2].geno & G_UNIQ) && indx2 != PM_HIGH_PRIEST); + uniq1 = ((mons[indx1].geno & G_UNIQ) && indx1 != PM_HIGH_CLERIC); + uniq2 = ((mons[indx2].geno & G_UNIQ) && indx2 != PM_HIGH_CLERIC); if (uniq1 ^ uniq2) { /* one or other uniq, but not both */ res = uniq2 - uniq1; break; } /* else both unique or neither unique */ /*FALLTHRU*/ case VANQ_ALPHA_MIX: - name1 = mons[indx1].mname, name2 = mons[indx2].mname; + name1 = mons[indx1].pmnames[NEUTRAL], + name2 = mons[indx2].pmnames[NEUTRAL]; res = strcmpi(name1, name2); /* caseblind alhpa, low to high */ break; case VANQ_MCLS_HTOL: @@ -2306,7 +2352,7 @@ doborn() g.mvitals[i].died, g.mvitals[i].born, ((g.mvitals[i].mvflags & G_GONE) == G_EXTINCT) ? 'E' : ((g.mvitals[i].mvflags & G_GONE) == G_GENOD) ? 'G' : ' ', - mons[i].mname); + mons[i].pmnames[NEUTRAL]); putstr(datawin, 0, buf); nborn += g.mvitals[i].born; ndied += g.mvitals[i].died; @@ -2323,7 +2369,7 @@ doborn() /* high priests aren't unique but are flagged as such to simplify something */ #define UniqCritterIndx(mndx) ((mons[mndx].geno & G_UNIQ) \ - && mndx != PM_HIGH_PRIEST) + && mndx != PM_HIGH_CLERIC) #define done_stopprint g.program_state.stopprint @@ -2397,7 +2443,7 @@ boolean ask; if (UniqCritterIndx(i)) { Sprintf(buf, "%s%s", !type_is_pname(&mons[i]) ? "the " : "", - mons[i].mname); + mons[i].pmnames[NEUTRAL]); if (nkilled > 1) { switch (nkilled) { case 2: @@ -2420,10 +2466,10 @@ boolean ask; /* trolls or undead might have come back, but we don't keep track of that */ if (nkilled == 1) - Strcpy(buf, an(mons[i].mname)); + Strcpy(buf, an(mons[i].pmnames[NEUTRAL])); else Sprintf(buf, "%3d %s", nkilled, - makeplural(mons[i].mname)); + makeplural(mons[i].pmnames[NEUTRAL])); } /* number of leading spaces to match 3 digit prefix */ pfx = !strncmpi(buf, "the ", 3) ? 0 @@ -2469,7 +2515,7 @@ num_genocides() ++n; if (UniqCritterIndx(i)) impossible("unique creature '%d: %s' genocided?", - i, mons[i].mname); + i, mons[i].pmnames[NEUTRAL]); } } return n; @@ -2532,7 +2578,7 @@ boolean ask; if (UniqCritterIndx(i)) continue; if (g.mvitals[i].mvflags & G_GONE) { - Sprintf(buf, " %s", makeplural(mons[i].mname)); + Sprintf(buf, " %s", makeplural(mons[i].pmnames[NEUTRAL])); /* * "Extinct" is unfortunate terminology. A species * is marked extinct when its birth limit is reached, diff --git a/src/invent.c b/src/invent.c index 0e0ccec8f..8b1a96287 100644 --- a/src/invent.c +++ b/src/invent.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 invent.c $NHDT-Date: 1590343765 2020/05/24 18:09:25 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.299 $ */ +/* NetHack 3.7 invent.c $NHDT-Date: 1608846067 2020/12/24 21:41:07 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.310 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Derek S. Ray, 2015. */ /* NetHack may be freely redistributed. See license for details. */ @@ -13,7 +13,6 @@ #define CONTAINED_SYM '>' /* designator for inside a container */ #define HANDS_SYM '-' -static void FDECL(loot_classify, (Loot *, struct obj *)); static char *FDECL(loot_xname, (struct obj *)); static int FDECL(invletter_value, (CHAR_P)); static int FDECL(CFDECLSPEC sortloot_cmp, (const genericptr, @@ -54,7 +53,7 @@ static char FDECL(obj_to_let, (struct obj *)); static const char venom_inv[] = { VENOM_CLASS, 0 }; /* (constant) */ /* sortloot() classification; called at most once [per sort] for each object */ -static void +void loot_classify(sort_item, obj) Loot *sort_item; struct obj *obj; @@ -1225,8 +1224,10 @@ register struct obj *obj; } update_map = (obj->where == OBJ_FLOOR); obj_extract_self(obj); - if (update_map) + if (update_map) { + maybe_unhide_at(obj->ox, obj->oy); newsym(obj->ox, obj->oy); + } obfree(obj, (struct obj *) 0); /* frees contents also */ } @@ -1462,6 +1463,157 @@ const char *action; return !strcmp(action, "wear") || !strcmp(action, "put on"); } +/* helper for getobj(), exclude obj if it cannot be used to do word */ +static boolean +getobj_obj_exclude(word, otmp) +const char *word; +struct obj *otmp; +{ + return ((taking_off(word) /* exclude if not worn */ + && !(otmp->owornmask & (W_ARMOR | W_ACCESSORY))) + || (putting_on(word) /* exclude if already worn */ + && (otmp->owornmask & (W_ARMOR | W_ACCESSORY))) +#if 0 /* 3.4.1 -- include currently wielded weapon among 'wield' choices */ + || (!strcmp(word, "wield") + && (otmp->owornmask & W_WEP)) +#endif + || (!strcmp(word, "ready") /* exclude when wielded... */ + && ((otmp == uwep || (otmp == uswapwep && u.twoweap)) + && otmp->quan == 1L)) /* ...unless more than one */ + || ((!strcmp(word, "dip") || !strcmp(word, "grease")) + && inaccessible_equipment(otmp, (const char *) 0, FALSE))); +} + +/* helper for getobj(), exclude obj if it cannot be used to do word */ +static boolean +getobj_obj_exclude_too(word, otmp) +const char *word; +struct obj *otmp; +{ + short otyp = otmp->otyp; + + return ((putting_on(word) + && ((otmp->oclass == FOOD_CLASS && otyp != MEAT_RING) + || (otmp->oclass == TOOL_CLASS && otyp != BLINDFOLD + && otyp != TOWEL && otyp != LENSES))) + || (!strcmp(word, "wield") + && (otmp->oclass == TOOL_CLASS && !is_weptool(otmp))) + || (!strcmp(word, "eat") && !is_edible(otmp)) + || (!strcmp(word, "sacrifice") + && (otyp != CORPSE && otyp != AMULET_OF_YENDOR + && otyp != FAKE_AMULET_OF_YENDOR)) + || (!strcmp(word, "write with") + && (otmp->oclass == TOOL_CLASS + && otyp != MAGIC_MARKER && otyp != TOWEL)) + || (!strcmp(word, "tin") + && (otyp != CORPSE || !tinnable(otmp))) + || (!strcmp(word, "rub") + && ((otmp->oclass == TOOL_CLASS && otyp != OIL_LAMP + && otyp != MAGIC_LAMP && otyp != BRASS_LANTERN) + || (otmp->oclass == GEM_CLASS && !is_graystone(otmp)) + || (otmp->oclass == FOOD_CLASS + && otmp->otyp != LUMP_OF_ROYAL_JELLY))) + || (!strcmp(word, "use or apply") + /* Picks, axes, pole-weapons, bullwhips */ + && ((otmp->oclass == WEAPON_CLASS + && !is_pick(otmp) && !is_axe(otmp) + && !is_pole(otmp) && otyp != BULLWHIP) + || (otmp->oclass == POTION_CLASS + /* only applicable potion is oil, and it will only + be offered as a choice when already discovered */ + && (otyp != POT_OIL || !otmp->dknown + || !objects[POT_OIL].oc_name_known)) + || (otmp->oclass == FOOD_CLASS + && otyp != CREAM_PIE && otyp != EUCALYPTUS_LEAF + && otyp != LUMP_OF_ROYAL_JELLY) + || (otmp->oclass == GEM_CLASS && !is_graystone(otmp)))) + || (!strcmp(word, "rub the royal jelly on") && otmp->otyp != EGG) + || (!strcmp(word, "invoke") + && !otmp->oartifact + && !objects[otyp].oc_unique + && (otyp != FAKE_AMULET_OF_YENDOR || otmp->known) + && otyp != CRYSTAL_BALL /* synonym for apply */ + /* note: presenting the possibility of invoking non-artifact + mirrors and/or lamps is simply a cruel deception... */ + && otyp != MIRROR + && otyp != MAGIC_LAMP + && (otyp != OIL_LAMP /* don't list known oil lamp */ + || (otmp->dknown && objects[OIL_LAMP].oc_name_known))) + || (!strcmp(word, "untrap with") + && ((otmp->oclass == TOOL_CLASS && otyp != CAN_OF_GREASE) + || (otmp->oclass == POTION_CLASS + /* only applicable potion is oil, and it will only + be offered as a choice when already discovered */ + && (otyp != POT_OIL || !otmp->dknown + || !objects[POT_OIL].oc_name_known)))) + || (!strcmp(word, "tip") && !Is_container(otmp) + /* include horn of plenty if sufficiently discovered */ + && (otmp->otyp != HORN_OF_PLENTY || !otmp->dknown + || !objects[HORN_OF_PLENTY].oc_name_known)) + || (!strcmp(word, "charge") && !is_chargeable(otmp)) + || (!strcmp(word, "open") && otyp != TIN) + || (!strcmp(word, "call") && !objtyp_is_callable(otyp))); +} + +/* helper for getobj(), obj is acceptable but not listed */ +static boolean +getobj_obj_acceptable_unlisted(word, otmp, let) +const char *word; +struct obj *otmp; +char let; +{ + long dummymask; + short otyp = otmp->otyp; + + return (/* ugly check for unworn armor that can't be worn */ + (putting_on(word) && let == ARMOR_CLASS + && !canwearobj(otmp, &dummymask, FALSE)) + /* or armor with 'P' or 'R' or accessory with 'W' or 'T' */ + || ((putting_on(word) || taking_off(word)) + && ((let == ARMOR_CLASS) ^ (otmp->oclass == ARMOR_CLASS))) + /* or unsuitable items rubbed on known touchstone */ + || (!strncmp(word, "rub on the stone", 16) + && let == GEM_CLASS && otmp->dknown + && objects[otyp].oc_name_known) + /* suppress corpses on astral, amulets elsewhere */ + || (!strcmp(word, "sacrifice") + /* (!astral && amulet) || (astral && !amulet) */ + && (!Is_astralevel(&u.uz) ^ (otmp->oclass != AMULET_CLASS))) + /* suppress container being stashed into */ + || (!strcmp(word, "stash") && !ck_bag(otmp)) + /* worn armor (shirt, suit) covered by worn armor (suit, cloak) + or accessory (ring) covered by cursed worn armor (gloves) */ + || (taking_off(word) + && inaccessible_equipment(otmp, (const char *) 0, + (boolean) (otmp->oclass == RING_CLASS))) + || (!strcmp(word, "write on") + && (!(otyp == SCR_BLANK_PAPER || otyp == SPE_BLANK_PAPER) + || !otmp->dknown || !objects[otyp].oc_name_known))); +} + +void +mime_action(word) +const char *word; +{ + char buf[BUFSZ]; + char *bp = buf; + char *suf = (char *) 0; + + strcpy(buf, word); + if ((bp = strstr(buf, " on the ")) != 0) { + /* rub on the stone[s] */ + *bp = '\0'; + suf = (bp + 1); + } + if ((bp = strstr(buf, " or ")) != 0) { + *bp = '\0'; + bp = (rn2(2) ? buf : (bp + 4)); + } else + bp = buf; + You("mime %s something%s%s.", ing_suffix(bp), suf ? " " : "", + suf ? suf : ""); +} + /* * getobj returns: * struct obj *xxx: object to do something with. @@ -1490,7 +1642,6 @@ register const char *let, *word; boolean cntgiven = FALSE; boolean msggiven = FALSE; boolean oneloop = FALSE; - long dummymask; Loot *sortedinvent, *srtinv; if (*let == ALLOW_COUNT) @@ -1545,137 +1696,27 @@ register const char *let, *word; if (!*let || index(let, otmp->oclass) || (usegold && otmp->invlet == GOLD_SYM) || (useboulder && otmp->otyp == BOULDER)) { - register int otyp = otmp->otyp; - bp[foo++] = otmp->invlet; -/* clang-format off */ -/* *INDENT-OFF* */ - /* ugly check: remove inappropriate things */ - if ( - (taking_off(word) /* exclude if not worn */ - && !(otmp->owornmask & (W_ARMOR | W_ACCESSORY))) - || (putting_on(word) /* exclude if already worn */ - && (otmp->owornmask & (W_ARMOR | W_ACCESSORY))) -#if 0 /* 3.4.1 -- include currently wielded weapon among 'wield' choices */ - || (!strcmp(word, "wield") - && (otmp->owornmask & W_WEP)) -#endif - || (!strcmp(word, "ready") /* exclude when wielded... */ - && ((otmp == uwep || (otmp == uswapwep && u.twoweap)) - && otmp->quan == 1L)) /* ...unless more than one */ - || ((!strcmp(word, "dip") || !strcmp(word, "grease")) - && inaccessible_equipment(otmp, (const char *) 0, FALSE)) - ) { + + /* remove inappropriate things */ + if (getobj_obj_exclude(word, otmp)) { foo--; foox++; - } - /* Second ugly check; unlike the first it won't trigger an - * "else" in "you don't have anything else to ___". - */ - else if ( - (putting_on(word) - && ((otmp->oclass == FOOD_CLASS && otmp->otyp != MEAT_RING) - || (otmp->oclass == TOOL_CLASS && otyp != BLINDFOLD - && otyp != TOWEL && otyp != LENSES))) - || (!strcmp(word, "wield") - && (otmp->oclass == TOOL_CLASS && !is_weptool(otmp))) - || (!strcmp(word, "eat") && !is_edible(otmp)) - || (!strcmp(word, "sacrifice") - && (otyp != CORPSE && otyp != AMULET_OF_YENDOR - && otyp != FAKE_AMULET_OF_YENDOR)) - || (!strcmp(word, "write with") - && (otmp->oclass == TOOL_CLASS - && otyp != MAGIC_MARKER && otyp != TOWEL)) - || (!strcmp(word, "tin") - && (otyp != CORPSE || !tinnable(otmp))) - || (!strcmp(word, "rub") - && ((otmp->oclass == TOOL_CLASS && otyp != OIL_LAMP - && otyp != MAGIC_LAMP && otyp != BRASS_LANTERN) - || (otmp->oclass == GEM_CLASS && !is_graystone(otmp)) - || (otmp->oclass == FOOD_CLASS - && otmp->otyp != LUMP_OF_ROYAL_JELLY))) - || (!strcmp(word, "use or apply") - /* Picks, axes, pole-weapons, bullwhips */ - && ((otmp->oclass == WEAPON_CLASS - && !is_pick(otmp) && !is_axe(otmp) - && !is_pole(otmp) && otyp != BULLWHIP) - || (otmp->oclass == POTION_CLASS - /* only applicable potion is oil, and it will only - be offered as a choice when already discovered */ - && (otyp != POT_OIL || !otmp->dknown - || !objects[POT_OIL].oc_name_known)) - || (otmp->oclass == FOOD_CLASS - && otyp != CREAM_PIE && otyp != EUCALYPTUS_LEAF - && otyp != LUMP_OF_ROYAL_JELLY) - || (otmp->oclass == GEM_CLASS && !is_graystone(otmp)))) - || (!strcmp(word, "rub the royal jelly on") && otmp->otyp != EGG) - || (!strcmp(word, "invoke") - && !otmp->oartifact - && !objects[otyp].oc_unique - && (otyp != FAKE_AMULET_OF_YENDOR || otmp->known) - && otyp != CRYSTAL_BALL /* synonym for apply */ - /* note: presenting the possibility of invoking non-artifact - mirrors and/or lamps is simply a cruel deception... */ - && otyp != MIRROR - && otyp != MAGIC_LAMP - && (otyp != OIL_LAMP /* don't list known oil lamp */ - || (otmp->dknown && objects[OIL_LAMP].oc_name_known))) - || (!strcmp(word, "untrap with") - && ((otmp->oclass == TOOL_CLASS && otyp != CAN_OF_GREASE) - || (otmp->oclass == POTION_CLASS - /* only applicable potion is oil, and it will only - be offered as a choice when already discovered */ - && (otyp != POT_OIL || !otmp->dknown - || !objects[POT_OIL].oc_name_known)))) - || (!strcmp(word, "tip") && !Is_container(otmp) - /* include horn of plenty if sufficiently discovered */ - && (otmp->otyp != HORN_OF_PLENTY || !otmp->dknown - || !objects[HORN_OF_PLENTY].oc_name_known)) - || (!strcmp(word, "charge") && !is_chargeable(otmp)) - || (!strcmp(word, "open") && otyp != TIN) - || (!strcmp(word, "call") && !objtyp_is_callable(otyp)) - || (!strcmp(word, "adjust") && otmp->oclass == COIN_CLASS - && !usegold) - ) { + + /* remove more inappropriate things, but unlike the first it won't + trigger an "else" in "you don't have anything else to ___" */ + } else if (getobj_obj_exclude_too(word, otmp) + || (!strcmp(word, "adjust") + && otmp->oclass == COIN_CLASS && !usegold)) { foo--; - } - /* Third ugly check: acceptable but not listed as likely - * candidates in the prompt or in the inventory subset if - * player responds with '?'. - */ - else if ( - /* ugly check for unworn armor that can't be worn */ - (putting_on(word) && *let == ARMOR_CLASS - && !canwearobj(otmp, &dummymask, FALSE)) - /* or armor with 'P' or 'R' or accessory with 'W' or 'T' */ - || ((putting_on(word) || taking_off(word)) - && ((*let == ARMOR_CLASS) ^ (otmp->oclass == ARMOR_CLASS))) - /* or unsuitable items rubbed on known touchstone */ - || (!strncmp(word, "rub on the stone", 16) - && *let == GEM_CLASS && otmp->dknown - && objects[otyp].oc_name_known) - /* suppress corpses on astral, amulets elsewhere */ - || (!strcmp(word, "sacrifice") - /* (!astral && amulet) || (astral && !amulet) */ - && (!Is_astralevel(&u.uz) ^ (otmp->oclass != AMULET_CLASS))) - /* suppress container being stashed into */ - || (!strcmp(word, "stash") && !ck_bag(otmp)) - /* worn armor (shirt, suit) covered by worn armor (suit, cloak) - or accessory (ring) covered by cursed worn armor (gloves) */ - || (taking_off(word) - && inaccessible_equipment(otmp, (const char *) 0, - (boolean) (otmp->oclass == RING_CLASS))) - || (!strcmp(word, "write on") - && (!(otyp == SCR_BLANK_PAPER || otyp == SPE_BLANK_PAPER) - || !otmp->dknown || !objects[otyp].oc_name_known)) - ) { - /* acceptable but not listed as likely candidate */ + + /* acceptable but not listed as likely candidates in the prompt + or in the inventory subset if player responds with '?' */ + } else if (getobj_obj_acceptable_unlisted(word, otmp, *let)) { foo--; allowall = TRUE; *ap++ = otmp->invlet; } -/* *INDENT-ON* */ -/* clang-format on */ } else { /* "ugly check" for reading fortune cookies, part 2 */ if ((!strcmp(word, "read") && is_readable(otmp))) @@ -1684,9 +1725,9 @@ register const char *let, *word; } unsortloot(&sortedinvent); - bp[foo] = 0; + bp[foo] = '\0'; if (foo == 0 && bp > buf && bp[-1] == ' ') - *--bp = 0; + *--bp = '\0'; Strcpy(lets, bp); /* necessary since we destroy buf */ if (foo > 5) /* compactify string */ compactify(bp); @@ -1741,23 +1782,8 @@ register const char *let, *word; return (struct obj *) 0; } if (ilet == HANDS_SYM) { /* '-' */ - if (!allownone) { - char *suf = (char *) 0; - - strcpy(buf, word); - if ((bp = strstr(buf, " on the ")) != 0) { - /* rub on the stone[s] */ - *bp = '\0'; - suf = (bp + 1); - } - if ((bp = strstr(buf, " or ")) != 0) { - *bp = '\0'; - bp = (rn2(2) ? buf : (bp + 4)); - } else - bp = buf; - You("mime %s something%s%s.", ing_suffix(bp), suf ? " " : "", - suf ? suf : ""); - } + if (!allownone) + mime_action(word); return (allownone ? (struct obj *) &cg.zeroobj : (struct obj *) 0); } redo_menu: @@ -1884,11 +1910,14 @@ register const char *let, *word; void silly_thing(word, otmp) const char *word; +#ifdef OBSOLETE_HANDLING struct obj *otmp; -{ -#if 1 /* 'P','R' vs 'W','T' handling is obsolete */ - nhUse(otmp); #else +struct obj *otmp UNUSED; +#endif +{ +#ifdef OBSOLETE_HANDLING + /* 'P','R' vs 'W','T' handling is obsolete */ const char *s1, *s2, *s3; int ocls = otmp->oclass, otyp = otmp->otyp; @@ -2102,9 +2131,7 @@ unsigned *resultflags; } } - if (oc_of_sym == COIN_CLASS && !combo) { - g.context.botl = 1; - } else if (sym == 'a') { + if (sym == 'a') { allflag = TRUE; } else if (sym == 'A') { ; /* same as the default */ @@ -2118,11 +2145,11 @@ unsigned *resultflags; m_seen = TRUE; } else if (oc_of_sym == MAXOCLASSES) { You("don't have any %c's.", sym); - } else if (oc_of_sym != VENOM_CLASS) { /* suppress venom */ + } else { if (!index(olets, oc_of_sym)) { add_valid_menu_class(oc_of_sym); olets[oletct++] = oc_of_sym; - olets[oletct] = 0; + olets[oletct] = '\0'; } } } @@ -2133,11 +2160,6 @@ unsigned *resultflags; ? -2 : -3; } else if (flags.menu_style != MENU_TRADITIONAL && combo && !allflag) { return 0; -#if 0 - /* !!!! test gold dropping */ - } else if (allowgold == 2 && !oletct) { - return 1; /* you dropped gold (or at least tried to) */ -#endif } else { int cnt = askchain(&g.invent, olets, allflag, fn, ckfn, mx, word); /* @@ -2315,6 +2337,20 @@ int FDECL((*fn), (OBJ_P)), FDECL((*ckfn), (OBJ_P)); * Object identification routines: */ +/* set the cknown and lknown flags on an object if they're applicable */ +void +set_cknown_lknown(obj) +struct obj *obj; +{ + if (Is_container(obj) || obj->otyp == STATUE) + obj->cknown = obj->lknown = 1; + else if (obj->otyp == TIN) + obj->cknown = 1; + /* TODO? cknown might be extended to candy bar, where it would mean that + wrapper's text was known which in turn indicates candy bar's content */ + return; +} + /* make an object actually be identified; no display updating */ void fully_identify_obj(otmp) @@ -2324,8 +2360,7 @@ struct obj *otmp; if (otmp->oartifact) discover_artifact((xchar) otmp->oartifact); otmp->known = otmp->dknown = otmp->bknown = otmp->rknown = 1; - if (Is_container(otmp) || otmp->otyp == STATUE) - otmp->cknown = otmp->lknown = 1; + set_cknown_lknown(otmp); /* set otmp->{cknown,lknown} if applicable */ if (otmp->otyp == EGG && otmp->corpsenm != NON_PM) learn_egg_type(otmp->corpsenm); } @@ -2354,7 +2389,7 @@ int id_limit; Sprintf(buf, "What would you like to identify %s?", first ? "first" : "next"); n = query_objlist(buf, &g.invent, (SIGNAL_NOMENU | SIGNAL_ESCAPE - | USE_INVLET | INVORDER_SORT), + | USE_INVLET | INVORDER_SORT), &pick_list, PICK_ANY, not_fully_identified); if (n > 0) { @@ -2460,7 +2495,7 @@ learn_unseen_invent() void update_inventory() { - if (g.restoring) + if (g.program_state.saving || g.program_state.restoring) return; /* @@ -2945,7 +2980,7 @@ boolean FDECL((*filterfunc), (OBJ_P)); for (; list; list = list->nobj) { /* priests always know bless/curse state */ - if (Role_if(PM_PRIEST)) + if (Role_if(PM_CLERIC)) list->bknown = (list->oclass != COIN_CLASS); /* some actions exclude some or most items */ if (filterfunc && !(*filterfunc)(list)) @@ -2985,7 +3020,7 @@ int *bcp, *ucp, *ccp, *xcp, *ocp; *bcp = *ucp = *ccp = *xcp = *ocp = 0; for ( ; list; list = (by_nexthere ? list->nexthere : list->nobj)) { /* priests always know bless/curse state */ - if (Role_if(PM_PRIEST)) + if (Role_if(PM_CLERIC)) list->bknown = (list->oclass != COIN_CLASS); /* coins are either uncursed or unknown based upon option setting */ if (list->oclass == COIN_CLASS) { @@ -3211,6 +3246,7 @@ dotypeinv() i |= BUC_CURSED; if (xcnt) i |= BUC_UNKNOWN; + i |= INCLUDE_VENOM; n = query_category(prompt, g.invent, i, &pick_list, PICK_ONE); if (!n) return 0; @@ -3219,8 +3255,7 @@ dotypeinv() } } if (traditional) { - /* collect a list of classes of objects carried, for use as a prompt - */ + /* collect list of classes of objects carried, for use as a prompt */ types[0] = 0; class_count = collect_obj_classes(types, g.invent, FALSE, (boolean FDECL((*), (OBJ_P))) 0, @@ -3336,7 +3371,7 @@ dotypeinv() } if (query_objlist((char *) 0, &g.invent, ((flags.invlet_constant ? USE_INVLET : 0) - | INVORDER_SORT), + | INVORDER_SORT | INCLUDE_VENOM), &pick_list, PICK_NONE, this_type_only) > 0) free((genericptr_t) pick_list); return 0; @@ -3353,6 +3388,7 @@ char *buf; int ltyp = lev->typ, cmap = -1; const char *dfeature = 0; static char altbuf[BUFSZ]; + stairway *stway = stairway_at(x,y); if (IS_DOOR(ltyp)) { switch (lev->doormask) { @@ -3393,15 +3429,13 @@ char *buf; a_gname(), align_str(Amask2align(lev->altarmask & ~AM_SHRINE))); dfeature = altbuf; - } else if ((x == xupstair && y == yupstair) - || (x == g.sstairs.sx && y == g.sstairs.sy && g.sstairs.up)) + } else if (stway && !stway->isladder && stway->up) cmap = S_upstair; /* "staircase up" */ - else if ((x == xdnstair && y == ydnstair) - || (x == g.sstairs.sx && y == g.sstairs.sy && !g.sstairs.up)) + else if (stway && !stway->isladder && !stway->up) cmap = S_dnstair; /* "staircase down" */ - else if (x == xupladder && y == yupladder) + else if (stway && stway->isladder && stway->up) cmap = S_upladder; /* "ladder up" */ - else if (x == xdnladder && y == ydnladder) + else if (stway && stway->isladder && !stway->up) cmap = S_dnladder; /* "ladder down" */ else if (ltyp == DRAWBRIDGE_DOWN) cmap = S_vodbridge; /* "lowered drawbridge" */ @@ -3697,7 +3731,7 @@ register struct obj *otmp, *obj; return FALSE; if (obj->dknown != otmp->dknown - || (obj->bknown != otmp->bknown && !Role_if(PM_PRIEST)) + || (obj->bknown != otmp->bknown && !Role_if(PM_CLERIC)) || obj->oeroded != otmp->oeroded || obj->oeroded2 != otmp->oeroded2 || obj->greased != otmp->greased) return FALSE; @@ -3750,6 +3784,15 @@ register struct obj *otmp, *obj; : (!has_omailcmd(otmp) || strcmp(OMAILCMD(obj), OMAILCMD(otmp)) != 0)) return FALSE; +#ifdef MAIL_STRUCTURES + if (obj->otyp == SCR_MAIL + /* wished or bones mail and hand written stamped scrolls + each have two flavors; spe keeps them separate from each + other but we want to keep their flavors separate too */ + && obj->spe > 0 && (obj->o_id % 2) != (otmp->o_id % 2)) + return FALSE; +#endif + /* should be moot since matching artifacts wouldn't be unique */ if (obj->oartifact != otmp->oartifact) return FALSE; diff --git a/src/light.c b/src/light.c index bcf797b55..26f832777 100644 --- a/src/light.c +++ b/src/light.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 light.c $NHDT-Date: 1559994625 2019/06/08 11:50:25 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.30 $ */ +/* NetHack 3.7 light.c $NHDT-Date: 1604442297 2020/11/03 22:24:57 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.46 $ */ /* Copyright (c) Dean Luick, 1994 */ /* NetHack may be freely redistributed. See license for details. */ @@ -48,8 +48,8 @@ static void FDECL(write_ls, (NHFILE *, light_source *)); static int FDECL(maybe_write_ls, (NHFILE *, int, BOOLEAN_P)); /* imported from vision.c, for small circles */ -extern char circle_data[]; -extern char circle_start[]; +extern xchar circle_data[]; +extern xchar circle_start[]; /* Create a new light source. Caller (and extern.h) doesn't need to know @@ -144,13 +144,13 @@ anything *id; /* Mark locations that are temporarily lit via mobile light sources. */ void do_light_sources(cs_rows) -char **cs_rows; +xchar **cs_rows; { int x, y, min_x, max_x, max_y, offset; - char *limits; + xchar *limits; short at_hero_range = 0; light_source *ls; - char *row; + xchar *row; for (ls = g.light_base; ls; ls = ls->next) { ls->flags &= ~LSF_SHOW; @@ -691,8 +691,7 @@ boolean obj_is_burning(obj) struct obj *obj; { - return (boolean) (obj->lamplit && (obj->otyp == MAGIC_LAMP - || ignitable(obj) + return (boolean) (obj->lamplit && (ignitable(obj) || artifact_light(obj))); } diff --git a/src/lock.c b/src/lock.c index 892bacb1e..b14256856 100644 --- a/src/lock.c +++ b/src/lock.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 lock.c $NHDT-Date: 1578297245 2020/01/06 07:54:05 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.98 $ */ +/* NetHack 3.7 lock.c $NHDT-Date: 1602355548 2020/10/10 18:45:48 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.100 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2011. */ /* NetHack may be freely redistributed. See license for details. */ @@ -480,7 +480,8 @@ struct obj *container; /* container, for autounlock */ } if (otmp->obroken) { - You_cant("fix its broken lock with %s.", doname(pick)); + You_cant("fix its broken lock with %s.", + ansimpleoname(pick)); return PICKLOCK_LEARNED_SOMETHING; } else if (picktyp == CREDIT_CARD && !otmp->olocked) { /* credit cards are only good for unlocking */ diff --git a/src/mail.c b/src/mail.c index a6ec5ddc6..1eeae3118 100644 --- a/src/mail.c +++ b/src/mail.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 mail.c $NHDT-Date: 1568508711 2019/09/15 00:51:51 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.40 $ */ +/* NetHack 3.7 mail.c $NHDT-Date: 1596498174 2020/08/03 23:42:54 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.47 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Pasi Kallinen, 2018. */ /* NetHack may be freely redistributed. See license for details. */ @@ -151,6 +151,7 @@ coord *startp; int lax; /* if TRUE, pick a position in sight. */ int dd; /* distance to current point */ int max_distance; /* max distance found so far */ + stairway *stway = g.stairs; /* * If blind and not telepathic, then it doesn't matter what we pick --- @@ -166,15 +167,13 @@ coord *startp; * Arrive at an up or down stairwell if it is in line of sight from the * hero. */ - if (couldsee(g.upstair.sx, g.upstair.sy)) { - startp->x = g.upstair.sx; - startp->y = g.upstair.sy; - return TRUE; - } - if (couldsee(g.dnstair.sx, g.dnstair.sy)) { - startp->x = g.dnstair.sx; - startp->y = g.dnstair.sy; - return TRUE; + while (stway) { + if (stway->tolev.dnum == u.uz.dnum && couldsee(stway->sx, stway->sy)) { + startp->x = stway->sx; + startp->y = stway->sy; + return TRUE; + } + stway = stway->next; } /* diff --git a/src/makemon.c b/src/makemon.c index b325c64a7..0199cedb4 100644 --- a/src/makemon.c +++ b/src/makemon.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 makemon.c $NHDT-Date: 1591178397 2020/06/03 09:59:57 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.173 $ */ +/* NetHack 3.7 makemon.c $NHDT-Date: 1606033928 2020/11/22 08:32:08 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.180 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -247,14 +247,14 @@ register struct monst *mtmp; } break; } - if (mm == PM_ELVENKING) { + if (mm == PM_ELVEN_MONARCH) { if (rn2(3) || (g.in_mklev && Is_earthlevel(&u.uz))) (void) mongets(mtmp, PICK_AXE); if (!rn2(50)) (void) mongets(mtmp, CRYSTAL_BALL); } } else if (ptr->msound == MS_PRIEST - || quest_mon_represents_role(ptr, PM_PRIEST)) { + || quest_mon_represents_role(ptr, PM_CLERIC)) { otmp = mksobj(MACE, FALSE, FALSE); otmp->spe = rnd(3); if (!rn2(2)) @@ -428,7 +428,7 @@ register struct monst *mtmp; } break; case S_OGRE: - if (!rn2(mm == PM_OGRE_KING ? 3 : mm == PM_OGRE_LORD ? 6 : 12)) + if (!rn2(mm == PM_OGRE_TYRANT ? 3 : mm == PM_OGRE_LEADER ? 6 : 12)) (void) mongets(mtmp, BATTLE_AXE); else (void) mongets(mtmp, CLUB); @@ -700,7 +700,7 @@ register struct monst *mtmp; (void) mongets(mtmp, WAN_STRIKING); } } else if (ptr->msound == MS_PRIEST - || quest_mon_represents_role(ptr, PM_PRIEST)) { + || quest_mon_represents_role(ptr, PM_CLERIC)) { (void) mongets(mtmp, rn2(7) ? ROBE : rn2(3) ? CLOAK_OF_PROTECTION : CLOAK_OF_MAGIC_RESISTANCE); @@ -755,7 +755,7 @@ register struct monst *mtmp; (void) mongets(mtmp, MUMMY_WRAPPING); break; case S_QUANTMECH: - if (!rn2(20)) { + if (!rn2(20) && ptr == &mons[PM_QUANTUM_MECHANIC]) { struct obj *catcorpse; otmp = mksobj(LARGE_BOX, FALSE, FALSE); @@ -882,8 +882,8 @@ xchar x, y; /* clone's preferred location or 0 (near mon) */ new_light_source(m2->mx, m2->my, emits_light(m2->data), LS_MONSTER, monst_to_any(m2)); /* if 'parent' is named, give the clone the same name */ - if (has_mname(mon)) { - m2 = christen_monst(m2, MNAME(mon)); + if (has_mgivenname(mon)) { + m2 = christen_monst(m2, MGIVENNAME(mon)); } else if (mon->isshk) { m2 = christen_monst(m2, shkname(mon)); } @@ -946,7 +946,7 @@ boolean ghostly; result = ((int) g.mvitals[mndx].born < lim && !gone) ? TRUE : FALSE; /* if it's unique, don't ever make it again */ - if ((mons[mndx].geno & G_UNIQ) != 0 && mndx != PM_HIGH_PRIEST) + if ((mons[mndx].geno & G_UNIQ) != 0 && mndx != PM_HIGH_CLERIC) g.mvitals[mndx].mvflags |= G_EXTINCT; if (g.mvitals[mndx].born < 255 && tally && (!ghostly || result)) @@ -956,7 +956,7 @@ boolean ghostly; && !(g.mvitals[mndx].mvflags & G_EXTINCT)) { if (wizard) { debugpline1("Automatically extinguished %s.", - makeplural(mons[mndx].mname)); + makeplural(mons[mndx].pmnames[NEUTRAL])); } g.mvitals[mndx].mvflags |= G_EXTINCT; } @@ -997,13 +997,16 @@ struct monst *mon; int mndx; { struct permonst *ptr = &mons[mndx]; + int basehp = 0; mon->m_lev = adj_lev(ptr); if (is_golem(ptr)) { + /* golems have a fixed amount of HP, varying by golem type */ mon->mhpmax = mon->mhp = golemhp(mndx); } else if (is_rider(ptr)) { /* we want low HP, but a high mlevel so they can attack well */ - mon->mhpmax = mon->mhp = d(10, 8); + basehp = 10; /* minimum is 1 per false (weaker) level */ + mon->mhpmax = mon->mhp = d(basehp, 8); } else if (ptr->mlevel > 49) { /* "special" fixed hp monster * the hit points are encoded in the mlevel in a somewhat strange @@ -1012,18 +1015,37 @@ int mndx; mon->mhpmax = mon->mhp = 2 * (ptr->mlevel - 6); mon->m_lev = mon->mhp / 4; /* approximation */ } else if (ptr->mlet == S_DRAGON && mndx >= PM_GRAY_DRAGON) { - /* adult dragons */ - mon->mhpmax = mon->mhp = - (int) (In_endgame(&u.uz) - ? (8 * mon->m_lev) - : (4 * mon->m_lev + d((int) mon->m_lev, 4))); + /* adult dragons; N*(4+rnd(4)) before endgame, N*8 once there */ + basehp = (int) mon->m_lev; /* not really applicable; isolates cast */ + mon->mhpmax = mon->mhp = In_endgame(&u.uz) ? (8 * basehp) + : (4 * basehp + d(basehp, 4)); } else if (!mon->m_lev) { + basehp = 1; /* minimum is 1, increased to 2 below */ mon->mhpmax = mon->mhp = rnd(4); } else { - mon->mhpmax = mon->mhp = d((int) mon->m_lev, 8); + basehp = (int) mon->m_lev; /* minimum possible is one per level */ + mon->mhpmax = mon->mhp = d(basehp, 8); if (is_home_elemental(ptr)) - mon->mhpmax = (mon->mhp *= 3); + mon->mhpmax = (mon->mhp *= 3); /* leave 'basehp' as-is */ } + + /* if d(X,8) rolled a 1 all X times, give a boost; + most beneficial for level 0 and level 1 monsters, making mhpmax + and starting mhp always be at least 2 */ + if (mon->mhpmax == basehp) { + mon->mhpmax += 1; + mon->mhp = mon->mhpmax; + } +} + +static const struct mextra zeromextra = DUMMY; + +static void +init_mextra(mex) +struct mextra *mex; +{ + *mex = zeromextra; + mex->mcorpsenm = NON_PM; } struct mextra * @@ -1032,13 +1054,7 @@ newmextra() struct mextra *mextra; mextra = (struct mextra *) alloc(sizeof(struct mextra)); - mextra->mname = 0; - mextra->egd = 0; - mextra->epri = 0; - mextra->eshk = 0; - mextra->emin = 0; - mextra->edog = 0; - mextra->mcorpsenm = NON_PM; + init_mextra(mextra); return mextra; } @@ -1079,20 +1095,16 @@ coord *cc; goto gotgood; } if (bl == 0 && (!mon || mon->data->mmove)) { + stairway *stway = g.stairs; /* all map positions are visible (or not good), try to pick something logical */ - if (g.dnstair.sx && !rn2(2)) { - nx = g.dnstair.sx; - ny = g.dnstair.sy; - } else if (g.upstair.sx && !rn2(2)) { - nx = g.upstair.sx; - ny = g.upstair.sy; - } else if (g.dnladder.sx && !rn2(2)) { - nx = g.dnladder.sx; - ny = g.dnladder.sy; - } else if (g.upladder.sx && !rn2(2)) { - nx = g.upladder.sx; - ny = g.upladder.sy; + while (stway) { + if (stway->tolev.dnum == u.uz.dnum && !rn2(2)) { + nx = stway->sx; + ny = stway->sy; + break; + } + stway = stway->next; } if (goodpos(nx, ny, mon, gpflags)) goto gotgood; @@ -1172,7 +1184,7 @@ long mmflags; return (struct monst *) 0; if (wizard && (g.mvitals[mndx].mvflags & G_EXTINCT)) { debugpline1("Explicitly creating extinct monster %s.", - mons[mndx].mname); + mons[mndx].pmnames[NEUTRAL]); } } else { /* make a random (common) monster that can survive here. @@ -1224,9 +1236,9 @@ long mmflags; /* set up level and hit points */ newmonhp(mtmp, mndx); - if (is_female(ptr)) + if (is_female(ptr) || ((mmflags & MM_FEMALE) && !is_male(ptr))) mtmp->female = TRUE; - else if (is_male(ptr)) + else if (is_male(ptr) || ((mmflags & MM_MALE) && !is_female(ptr))) mtmp->female = FALSE; /* leader and nemesis gender is usually hardcoded in mons[], but for ones which can be random, it has already been chosen @@ -1357,7 +1369,7 @@ long mmflags; types; make sure their extended data is initialized to something sensible if caller hasn't specified MM_EPRI|MM_EMIN (when they're specified, caller intends to handle this itself) */ - if ((mndx == PM_ALIGNED_PRIEST || mndx == PM_HIGH_PRIEST) + if ((mndx == PM_ALIGNED_CLERIC || mndx == PM_HIGH_CLERIC) ? !(mmflags & (MM_EPRI | MM_EMIN)) : (mndx == PM_ANGEL && !(mmflags & MM_EMIN) && !rn2(3))) { struct emin *eminp; @@ -1490,8 +1502,12 @@ boolean neverask; if (!mptr && u.uinwater && enexto(&c, x, y, &mons[PM_GIANT_EEL])) x = c.x, y = c.y; - mon = makemon(mptr, x, y, NO_MM_FLAGS); - if (mon && canspotmon(mon)) + if ((mon = makemon(mptr, x, y, NO_MM_FLAGS)) == 0) + continue; /* try again [should probably stop instead] */ + + if ((canseemon(mon) && (M_AP_TYPE(mon) == M_AP_NOTHING + || M_AP_TYPE(mon) == M_AP_MONSTER)) + || sensemon(mon)) known = TRUE; } return known; @@ -1841,8 +1857,11 @@ struct monst *mtmp, *victim; oldtype = monsndx(ptr); newtype = (oldtype == PM_KILLER_BEE && !victim) ? PM_QUEEN_BEE : little_to_big(oldtype); +#if 0 + /* gender-neutral PM_CLERIC now */ if (newtype == PM_PRIEST && mtmp->female) newtype = PM_PRIESTESS; +#endif /* growth limits differ depending on method of advancement */ if (victim) { /* killed a monster */ @@ -1898,7 +1917,7 @@ struct monst *mtmp, *victim; if (g.mvitals[newtype].mvflags & G_GENOD) { /* allow G_EXTINCT */ if (canspotmon(mtmp)) pline("As %s grows up into %s, %s %s!", mon_nam(mtmp), - an(ptr->mname), mhe(mtmp), + an(pmname(ptr, Mgender(mtmp))), mhe(mtmp), nonliving(ptr) ? "expires" : "dies"); set_mon_data(mtmp, ptr); /* keep g.mvitals[] accurate */ mondied(mtmp); @@ -1916,7 +1935,7 @@ struct monst *mtmp, *victim; (can't happen with 3.6.0 mons[], but perhaps slightly less sexist if prepared for it...) */ : (fem && !mtmp->female) ? "female " : "", - ptr->mname); + pmname(ptr, fem)); pline("%s %s %s.", upstart(y_monnam(mtmp)), (fem != mtmp->female) ? "changes into" : humanoid(ptr) ? "becomes" @@ -2347,7 +2366,9 @@ int *seencount; /* secondary output */ mtmp = makemon((struct permonst *) 0, u.ux, u.uy, NO_MM_FLAGS); if (mtmp) { ++moncount; - if (canspotmon(mtmp)) + if ((canseemon(mtmp) && (M_AP_TYPE(mtmp) == M_AP_NOTHING + || M_AP_TYPE(mtmp) == M_AP_MONSTER)) + || sensemon(mtmp)) ++seecount; } } while (--creatcnt > 0); diff --git a/src/mapglyph.c b/src/mapglyph.c index 91e827e17..a28c94670 100644 --- a/src/mapglyph.c +++ b/src/mapglyph.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 mapglyph.c $NHDT-Date: 1587110793 2020/04/17 08:06:33 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.64 $ */ +/* NetHack 3.7 mapglyph.c $NHDT-Date: 1596498176 2020/08/03 23:42:56 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.65 $ */ /* Copyright (c) David Cohrs, 1991 */ /* NetHack may be freely redistributed. See license for details. */ @@ -77,9 +77,10 @@ unsigned mgflags; unsigned special = 0; /* condense multiple tests in macro version down to single */ boolean has_rogue_ibm_graphics = HAS_ROGUE_IBM_GRAPHICS, - is_you = (x == u.ux && y == u.uy), + is_you = (x == u.ux && y == u.uy && !u.usteed), has_rogue_color = (has_rogue_ibm_graphics - && g.symset[g.currentgraphics].nocolor == 0); + && g.symset[g.currentgraphics].nocolor == 0), + do_mon_checks = FALSE; if (!g.glyphmap_perlevel_flags) { /* @@ -254,6 +255,7 @@ unsigned mgflags; else mon_color(offset); special |= MG_RIDDEN; + do_mon_checks = TRUE; } else if ((offset = (glyph - GLYPH_BODY_OFF)) >= 0) { /* a corpse */ idx = objects[CORPSE].oc_class + SYM_OFF_O; if (has_rogue_color && iflags.use_color) @@ -272,6 +274,7 @@ unsigned mgflags; /* Disabled for now; anyone want to get reverse video to work? */ /* is_reverse = TRUE; */ special |= MG_DETECT; + do_mon_checks = TRUE; } else if ((offset = (glyph - GLYPH_INVIS_OFF)) >= 0) { /* invisible */ idx = SYM_INVISIBLE + SYM_OFF_X; if (has_rogue_color) @@ -286,6 +289,7 @@ unsigned mgflags; else pet_color(offset); special |= MG_PET; + do_mon_checks = TRUE; } else { /* a monster */ idx = mons[glyph].mlet + SYM_OFF_M; if (has_rogue_color && iflags.use_color) { @@ -302,6 +306,21 @@ unsigned mgflags; color = HI_DOMESTIC; #endif } + do_mon_checks = TRUE; + } + if (do_mon_checks) { + struct monst *m; + + if (is_you) { + if (Ugender == FEMALE) + special |= MG_FEMALE; + } else { + /* when hero is riding, steed will be shown at hero's location + but has not been placed on the map so m_at() won't find it */ + m = (x == u.ux && y == u.uy && u.usteed) ? u.usteed : m_at(x, y); + if (m && m->female) + special |= MG_FEMALE; + } } /* These were requested by a blind player to enhance screen reader use */ @@ -354,14 +373,14 @@ const char *str; { static const char hex[] = "00112233445566778899aAbBcCdDeEfF"; char *put = buf; + unsigned glyphmod[NUM_GLYPHMOD]; if (!str) return strcpy(buf, ""); while (*str) { if (*str == '\\') { - int rndchk, dcount, so, gv, ch = 0, oc = 0; - unsigned os = 0; + int rndchk, dcount, so, gv; const char *dp, *save_str; save_str = str++; @@ -380,7 +399,8 @@ const char *str; gv = (gv * 16) + ((int) (dp - hex) / 2); else break; - so = mapglyph(gv, &ch, &oc, &os, 0, 0, 0); + map_glyphmod(0, 0, gv, MG_FLAG_RETURNIDX, glyphmod); + so = glyphmod[GM_TTYCHAR]; *put++ = g.showsyms[so]; /* 'str' is ready for the next loop iteration and '*str' should not be copied at the end of this iteration */ diff --git a/src/mcastu.c b/src/mcastu.c index bc1000fbe..f6b23986e 100644 --- a/src/mcastu.c +++ b/src/mcastu.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 mcastu.c $NHDT-Date: 1590904092 2020/05/31 05:48:12 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.67 $ */ +/* NetHack 3.7 mcastu.c $NHDT-Date: 1596498177 2020/08/03 23:42:57 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.68 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2011. */ /* NetHack may be freely redistributed. See license for details. */ @@ -553,6 +553,7 @@ int spellnum; destroy_item(SCROLL_CLASS, AD_FIRE); destroy_item(POTION_CLASS, AD_FIRE); destroy_item(SPBOOK_CLASS, AD_FIRE); + ignite_items(g.invent); (void) burn_floor_objects(u.ux, u.uy, TRUE, FALSE); break; case CLC_LIGHTNING: { diff --git a/src/mdlib.c b/src/mdlib.c index d42ee02b8..c1595450f 100644 --- a/src/mdlib.c +++ b/src/mdlib.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 mdlib.c $NHDT-Date: 1593953352 2020/07/05 12:49:12 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.9 $ */ +/* NetHack 3.7 mdlib.c $NHDT-Date: 1608933420 2020/12/25 21:57:00 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.17 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Kenneth Lorber, Kensington, Maryland, 2015. */ /* Copyright (c) M. Stephenson, 1990, 1991. */ @@ -60,11 +60,24 @@ static char *FDECL(version_string, (char *, const char *)); static char *FDECL(version_id_string, (char *, const char *)); static char *FDECL(bannerc_string, (char *, const char *)); -static int FDECL(case_insensitive_comp, (const char *, const char *)); static void NDECL(make_version); static char *FDECL(eos, (char *)); +#if 0 static char *FDECL(mdlib_strsubst, (char *, const char *, const char *)); +#endif + +#ifndef HAS_NO_MKSTEMP +#ifdef _MSC_VER +static int FDECL(mkstemp, (char *)); +#endif +#endif #endif /* MAKEDEFS_C || FOR_RUNTIME */ + +#if defined(MAKEDEFS_C) || defined(FOR_RUNTIME) || defined(WIN32) \ + || (defined(CROSSCOMPILE_TARGET) && defined(__DATE__) && defined(__TIME__)) +static int FDECL(case_insensitive_comp, (const char *, const char *)); +#endif + #if !defined(MAKEDEFS_C) && defined(WIN32) extern int GUILaunched; #endif @@ -79,7 +92,10 @@ static void FDECL(opt_out_words, (char *, int *)); static void NDECL(build_savebones_compat_string); static int idxopttext, done_runtime_opt_init_once = 0; #define MAXOPT 40 +#if !defined(MAKEDEFS_C) && defined(CROSSCOMPILE_TARGET) \ + && defined(__DATE__) && defined(__TIME__) static char rttimebuf[MAXOPT]; +#endif static char *opttext[120] = { 0 }; char optbuf[BUFSZ]; static struct version_info version; @@ -118,6 +134,14 @@ static struct win_info window_opts[] = { #ifdef QT_GRAPHICS /* too vague; there are multiple incompatible versions */ { "Qt", "Qt", TRUE }, #endif +#ifdef MSWIN_GRAPHICS /* win32 */ + { "mswin", "Windows GUI", TRUE }, +#endif +#ifdef SHIM_GRAPHICS + { "shim", "NetHack Library Windowing Shim", TRUE }, +#endif + +#if 0 /* remainder have been retired */ #ifdef GNOME_GRAPHICS /* unmaintained/defunct */ { "Gnome", "Gnome", TRUE }, #endif @@ -130,12 +154,10 @@ static struct win_info window_opts[] = { #ifdef GEM_GRAPHICS /* defunct Atari interface */ { "Gem", "Gem", TRUE }, #endif -#ifdef MSWIN_GRAPHICS /* win32 */ - { "mswin", "mswin", TRUE }, -#endif #ifdef BEOS_GRAPHICS /* unmaintained/defunct */ { "BeOS", "BeOS InterfaceKit", TRUE }, #endif +#endif /* 0 => retired */ { 0, 0, FALSE } }; @@ -314,8 +336,27 @@ const char *build_date; return outbuf; } +#ifndef HAS_NO_MKSTEMP +#ifdef _MSC_VER +int +mkstemp(template) +char *template; +{ + int err; + + err = _mktemp_s(template, strlen(template) + 1); + if( err != 0 ) + return -1; + return _open(template, + _O_RDWR | _O_BINARY | _O_TEMPORARY | _O_CREAT, + _S_IREAD | _S_IWRITE); +} +#endif /* _MSC_VER */ +#endif /* HAS_NO_MKSTEMP */ #endif /* MAKEDEFS_C || FOR_RUNTIME */ +#if defined(MAKEDEFS_C) || defined(FOR_RUNTIME) || defined(WIN32) \ + || (defined(CROSSCOMPILE_TARGET) && defined(__DATE__) && defined(__TIME__)) static int case_insensitive_comp(s1, s2) const char *s1; @@ -335,6 +376,7 @@ const char *s2; } return u1 - u2; } +#endif static char * eos(str) @@ -345,6 +387,7 @@ char *str; return str; } +#if 0 static char * mdlib_strsubst(bp, orig, replacement) char *bp; @@ -363,6 +406,7 @@ const char *orig, *replacement; } return bp; } +#endif static char save_bones_compat_buf[BUFSZ]; @@ -434,6 +478,13 @@ static const char *build_opts[] = { #if defined(MSGHANDLER) && (defined(POSIX_TYPES) || defined(__GNUC__)) "external program as a message handler", #endif +#if defined(HANGUPHANDLING) && !defined(NO_SIGNAL) +#ifdef SAFERHANGUP + "deferred handling of hangup signal", +#else + "immediate handling of hangup signal", +#endif +#endif #ifdef INSURANCE "insurance files for recovering from crashes", #endif @@ -615,8 +666,7 @@ int *length_p; /* in/out */ } else { Sprintf(eos(optbuf), " "), (*length_p)++; } - Sprintf(eos(optbuf), - "%s", str), *length_p += (int) strlen(str); + Sprintf(eos(optbuf), "%s", str), *length_p += (int) strlen(str); str += strlen(str) + (word ? 1 : 0); } } @@ -666,9 +716,9 @@ build_options() continue; #endif #endif /* !MAKEDEFS_C && FOR_RUNTIME */ - opt_out_words(strcat(strcpy(buf, build_opts[i]), - (i < SIZE(build_opts) - 1) ? "," : "."), - &length); + Strcat(strcpy(buf, build_opts[i]), + (i < SIZE(build_opts) - 1) ? "," : "."); + opt_out_words(buf, &length); } opttext[idxopttext] = strdup(optbuf); if (idxopttext < (MAXOPT - 1)) @@ -694,23 +744,24 @@ build_options() Sprintf(eos(buf), " (%s)", window_opts[i].name); /* * 1 : foo. - * 2 : foo and bar (note no period; comes from 'with default' below) - * 3+: for, bar, and quux + * 2 : foo and bar, + * 3+: for, bar, and quux, + * + * 2+ will be followed by " with a default of..." */ - if (cnt != (winsyscnt - 1)) { - Strcat(buf, (winsyscnt == 1) ? "." /* no 'default' */ - : (winsyscnt == 2 && cnt == 0) ? " and" - : (cnt == winsyscnt - 2) ? ", and" - : ","); - } + Strcat(buf, (winsyscnt == 1) ? "." /* no 'default' */ + : (winsyscnt == 2 && cnt == 0) ? " and" + : (cnt == winsyscnt - 2) ? ", and" + : ","); opt_out_words(buf, &length); cnt++; } if (cnt > 1) { - Sprintf(buf, ", with a default of \"%s\".", defwinsys); + /* loop ended with a comma; opt_out_words() will insert a space */ + Sprintf(buf, "with a default of \"%s\".", defwinsys); opt_out_words(buf, &length); } - (void) mdlib_strsubst(optbuf, " , ", ", "); + opttext[idxopttext] = strdup(optbuf); if (idxopttext < (MAXOPT - 1)) idxopttext++; @@ -765,6 +816,8 @@ build_options() void runtime_info_init() { +#if !defined(MAKEDEFS_C) && defined(CROSSCOMPILE_TARGET) \ + && defined(__DATE__) && defined(__TIME__) int i; char tmpbuf[BUFSZ], *strp; const char *mth[] = { @@ -772,12 +825,15 @@ runtime_info_init() "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; struct tm t = {0}; time_t timeresult; +#endif if (!done_runtime_opt_init_once) { done_runtime_opt_init_once = 1; build_savebones_compat_string(); /* construct the current version number */ make_version(); +#if !defined(MAKEDEFS_C) && defined(CROSSCOMPILE_TARGET) +#if defined(__DATE__) && defined(__TIME__) /* * In a cross-compiled environment, you can't execute * the target binaries during the build, so we can't @@ -797,8 +853,6 @@ runtime_info_init() * gcc, msvc, clang __TIME__ "23:59:01" * */ - -#if defined(__DATE__) && defined(__TIME__) if (sizeof __DATE__ + sizeof __TIME__ + sizeof "123" < sizeof rttimebuf) Sprintf(rttimebuf, "%s %s", __DATE__, __TIME__); @@ -825,35 +879,28 @@ runtime_info_init() extract_field(tmpbuf, rttimebuf, 2, 18); /* sec */ t.tm_sec = atoi(tmpbuf); timeresult = mktime(&t); -#if !defined(MAKEDEFS_C) && defined(CROSSCOMPILE_TARGET) BUILD_TIME = (unsigned long) timeresult; BUILD_DATE = rttimebuf; -#endif -#else /* __DATE__ && __TIME__ */ - nhUse(strp); + } #endif /* __DATE__ && __TIME__ */ - -#if !defined(MAKEDEFS_C) && defined(CROSSCOMPILE_TARGET) - VERSION_NUMBER = version.incarnation; - VERSION_FEATURES = version.feature_set; + VERSION_NUMBER = version.incarnation; + VERSION_FEATURES = version.feature_set; #ifdef MD_IGNORED_FEATURES - IGNORED_FEATURES = MD_IGNORED_FEATURES; + IGNORED_FEATURES = MD_IGNORED_FEATURES; #endif - VERSION_SANITY1 = version.entity_count; - VERSION_SANITY2 = version.struct_sizes1; - VERSION_SANITY3 = version.struct_sizes2; - - VERSION_STRING = strdup(version_string(tmpbuf, ".")); - VERSION_ID = strdup(version_id_string(tmpbuf, BUILD_DATE)); - COPYRIGHT_BANNER_C = strdup(bannerc_string(tmpbuf, BUILD_DATE)); + VERSION_SANITY1 = version.entity_count; + VERSION_SANITY2 = version.struct_sizes1; + VERSION_SANITY3 = version.struct_sizes2; + VERSION_STRING = strdup(version_string(tmpbuf, ".")); + VERSION_ID = strdup(version_id_string(tmpbuf, BUILD_DATE)); + COPYRIGHT_BANNER_C = strdup(bannerc_string(tmpbuf, BUILD_DATE)); #ifdef NETHACK_HOST_GIT_SHA - NETHACK_GIT_SHA = strdup(NETHACK_HOST_GIT_SHA); + NETHACK_GIT_SHA = strdup(NETHACK_HOST_GIT_SHA); #endif #ifdef NETHACK_HOST_GIT_BRANCH - NETHACK_GIT_BRANCH = strdup(NETHACK_HOST_GIT_BRANCH); + NETHACK_GIT_BRANCH = strdup(NETHACK_HOST_GIT_BRANCH); #endif #endif /* !MAKEDEFS_C && CROSSCOMPILE_TARGET */ - } idxopttext = 0; build_options(); } diff --git a/src/mhitm.c b/src/mhitm.c index 00628cc9a..f86843035 100644 --- a/src/mhitm.c +++ b/src/mhitm.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 mhitm.c $NHDT-Date: 1593614973 2020/07/01 14:49:33 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.138 $ */ +/* NetHack 3.7 mhitm.c $NHDT-Date: 1606558747 2020/11/28 10:19:07 $ $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. */ @@ -267,6 +267,7 @@ boolean quietly; * / / / * x x x * + * 0x8 MM_AGR_DONE * 0x4 MM_AGR_DIED * 0x2 MM_DEF_DIED * 0x1 MM_HIT @@ -335,8 +336,8 @@ register struct monst *magr, *mdef; tmp++; /* Set up the visibility of action */ - g.vis = (cansee(magr->mx, magr->my) && cansee(mdef->mx, mdef->my) - && (canspotmon(magr) || canspotmon(mdef))); + g.vis = ((cansee(magr->mx, magr->my) && canspotmon(magr)) + || (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 @@ -345,17 +346,32 @@ register struct monst *magr, *mdef; */ magr->mlstmv = g.monstermoves; + /* controls whether a mind flayer uses all of its tentacle-for-DRIN + attacks; when fighting a headless monster, stop after the first + one because repeating the same failing hit (or even an ordinary + tentacle miss) is very verbose and makes the flayer look stupid */ + g.skipdrin = FALSE; + /* Now perform all attacks for the monster. */ for (i = 0; i < NATTK; i++) { res[i] = MM_MISS; mattk = getmattk(magr, mdef, i, res, &alt_attk); mwep = (struct obj *) 0; attk = 1; + /* reduce verbosity for mind flayer attacking creature without a + head (or worm's tail); this is similar to monster with multiple + attacks after a wildmiss against displaced or invisible hero */ + if (g.skipdrin && mattk->aatyp == AT_TENT && mattk->adtyp == AD_DRIN) + continue; + switch (mattk->aatyp) { case AT_WEAP: /* "hand to hand" attacks */ if (distmin(magr->mx, magr->my, mdef->mx, mdef->my) > 1) { /* D: Do a ranged attack here! */ - strike = thrwmm(magr, mdef); + strike = (thrwmm(magr, mdef) == MM_MISS) ? 0 : 1; + if (strike) + /* don't really know if we hit or not; pretend we did */ + res[i] |= MM_HIT; if (DEADMONSTER(mdef)) res[i] = MM_DEF_DIED; if (DEADMONSTER(magr)) @@ -365,7 +381,7 @@ register struct monst *magr, *mdef; if (magr->weapon_check == NEED_WEAPON || !MON_WEP(magr)) { magr->weapon_check = NEED_HTH_WEAPON; if (mon_wield_item(magr) != 0) - return 0; + return MM_MISS; } possibly_unwield(magr, FALSE); if ((mwep = MON_WEP(magr)) != 0) { @@ -474,7 +490,7 @@ register struct monst *magr, *mdef; case AT_BREA: if (!monnear(magr, mdef->mx, mdef->my)) { - strike = breamm(magr, mattk, mdef); + strike = (breamm(magr, mattk, mdef) == MM_MISS) ? 0 : 1; /* We don't really know if we hit or not; pretend we did. */ if (strike) @@ -490,7 +506,7 @@ register struct monst *magr, *mdef; case AT_SPIT: if (!monnear(magr, mdef->mx, mdef->my)) { - strike = spitmm(magr, mattk, mdef); + strike = (spitmm(magr, mattk, mdef) == MM_MISS) ? 0 : 1; /* We don't really know if we hit or not; pretend we did. */ if (strike) @@ -840,13 +856,16 @@ struct attack *mattk; struct obj *mwep; int dieroll; { - struct obj *obj; - char buf[BUFSZ]; struct permonst *pa = magr->data, *pd = mdef->data; - int armpro, num, - tmp = d((int) mattk->damn, (int) mattk->damd), - res = MM_MISS; + int armpro; boolean cancelled; + struct mhitm_data mhm; + mhm.damage = d((int) mattk->damn, (int) mattk->damd); + mhm.hitflags = MM_MISS; + mhm.permdmg = 0; + mhm.specialdmg = 0; + mhm.dieroll = dieroll; + mhm.done = FALSE; if ((touch_petrifies(pd) /* or flesh_petrifies() */ || (mattk->adtyp == AD_DGST && pd == &mons[PM_MEDUSA])) @@ -879,597 +898,30 @@ int dieroll; armpro = magic_negation(mdef); cancelled = magr->mcan || !(rn2(10) >= 3 * armpro); - switch (mattk->adtyp) { - case AD_DGST: - /* eating a Rider or its corpse is fatal */ - if (is_rider(pd)) { - if (g.vis && canseemon(magr)) - pline("%s %s!", Monnam(magr), - (pd == &mons[PM_FAMINE]) - ? "belches feebly, shrivels up and dies" - : (pd == &mons[PM_PESTILENCE]) - ? "coughs spasmodically and collapses" - : "vomits violently and drops dead"); - mondied(magr); - if (!DEADMONSTER(magr)) - return 0; /* lifesaved */ - else if (magr->mtame && !g.vis) - You(brief_feeling, "queasy"); - return MM_AGR_DIED; - } - if (flags.verbose && !Deaf) - verbalize("Burrrrp!"); - tmp = mdef->mhp; - /* Use up amulet of life saving */ - if ((obj = mlifesaver(mdef)) != 0) - m_useup(mdef, obj); + mhitm_adtyping(magr, mattk, mdef, &mhm); + if (mhm.done) + return mhm.hitflags; - /* Is a corpse for nutrition possible? It may kill magr */ - if (!corpse_chance(mdef, magr, TRUE) || DEADMONSTER(magr)) - break; + if (!mhm.damage) + return mhm.hitflags; - /* Pets get nutrition from swallowing monster whole. - * No nutrition from G_NOCORPSE monster, eg, undead. - * DGST monsters don't die from undead corpses - */ - num = monsndx(pd); - if (magr->mtame && !magr->isminion - && !(g.mvitals[num].mvflags & G_NOCORPSE)) { - struct obj *virtualcorpse = mksobj(CORPSE, FALSE, FALSE); - int nutrit; - - set_corpsenm(virtualcorpse, num); - nutrit = dog_nutrition(magr, virtualcorpse); - dealloc_obj(virtualcorpse); - - /* only 50% nutrition, 25% of normal eating time */ - if (magr->meating > 1) - magr->meating = (magr->meating + 3) / 4; - if (nutrit > 1) - nutrit /= 2; - EDOG(magr)->hungrytime += nutrit; - } - break; - case AD_STUN: - if (magr->mcan) - break; - if (canseemon(mdef)) - pline("%s %s for a moment.", Monnam(mdef), - makeplural(stagger(pd, "stagger"))); - mdef->mstun = 1; - goto physical; - case AD_LEGS: - if (magr->mcan) { - tmp = 0; - break; - } - goto physical; - case AD_WERE: - case AD_HEAL: - case AD_PHYS: - physical: - if (mattk->aatyp != AT_WEAP && mattk->aatyp != AT_CLAW) - mwep = 0; - - if (shade_miss(magr, mdef, mwep, FALSE, TRUE)) { - tmp = 0; - } else if (mattk->aatyp == AT_KICK && thick_skinned(pd)) { - /* [no 'kicking boots' check needed; monsters with kick attacks - can't wear boots and monsters that wear boots don't kick] */ - tmp = 0; - } else if (mwep) { /* non-Null 'mwep' implies AT_WEAP || AT_CLAW */ - struct obj *marmg; - - if (mwep->otyp == CORPSE - && touch_petrifies(&mons[mwep->corpsenm])) - goto do_stone; - - tmp += dmgval(mwep, mdef); - if ((marmg = which_armor(magr, W_ARMG)) != 0 - && marmg->otyp == GAUNTLETS_OF_POWER) - tmp += rn1(4, 3); /* 3..6 */ - if (tmp < 1) /* is this necessary? mhitu.c has it... */ - tmp = 1; - if (mwep->oartifact) { - /* when magr's weapon is an artifact, caller suppressed its - usual 'hit' message in case artifact_hit() delivers one; - now we'll know and might need to deliver skipped message - (note: if there's no message there'll be no auxilliary - damage so the message here isn't coming too late) */ - if (!artifact_hit(magr, mdef, mwep, &tmp, dieroll)) { - if (g.vis) - pline("%s hits %s.", Monnam(magr), - mon_nam_too(mdef, magr)); - } - /* artifact_hit updates 'tmp' but doesn't inflict any - damage; however, it might cause carried items to be - destroyed and they might do so */ - if (DEADMONSTER(mdef)) - return (MM_DEF_DIED - | (grow_up(magr, mdef) ? 0 : MM_AGR_DIED)); - } - if (tmp) - rustm(mdef, mwep); - } 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 - won't swallow the corpse; but if the target survives, - the subsequent engulf attack should accomplish that */ - if (tmp >= mdef->mhp && mdef->mhp > 1) - tmp = mdef->mhp - 1; - } - break; - case AD_FIRE: - if (cancelled) { - tmp = 0; - break; - } - if (g.vis && canseemon(mdef)) - pline("%s is %s!", Monnam(mdef), on_fire(pd, mattk)); - if (completelyburns(pd)) { /* paper golem or straw golem */ - if (g.vis && canseemon(mdef)) - pline("%s burns completely!", Monnam(mdef)); - mondead(mdef); /* was mondied() but that dropped paper scrolls */ - if (!DEADMONSTER(mdef)) - return 0; - else if (mdef->mtame && !g.vis) - pline("May %s roast in peace.", mon_nam(mdef)); - return (MM_DEF_DIED | (grow_up(magr, mdef) ? 0 : MM_AGR_DIED)); - } - tmp += destroy_mitem(mdef, SCROLL_CLASS, AD_FIRE); - tmp += destroy_mitem(mdef, SPBOOK_CLASS, AD_FIRE); - if (resists_fire(mdef)) { - if (g.vis && canseemon(mdef)) - pline_The("fire doesn't seem to burn %s!", mon_nam(mdef)); - shieldeff(mdef->mx, mdef->my); - golemeffects(mdef, AD_FIRE, tmp); - tmp = 0; - } - /* only potions damage resistant players in destroy_item */ - tmp += destroy_mitem(mdef, POTION_CLASS, AD_FIRE); - break; - case AD_COLD: - if (cancelled) { - tmp = 0; - break; - } - if (g.vis && canseemon(mdef)) - pline("%s is covered in frost!", Monnam(mdef)); - if (resists_cold(mdef)) { - if (g.vis && canseemon(mdef)) - pline_The("frost doesn't seem to chill %s!", mon_nam(mdef)); - shieldeff(mdef->mx, mdef->my); - golemeffects(mdef, AD_COLD, tmp); - tmp = 0; - } - tmp += destroy_mitem(mdef, POTION_CLASS, AD_COLD); - break; - case AD_ELEC: - if (cancelled) { - tmp = 0; - break; - } - if (g.vis && canseemon(mdef)) - pline("%s gets zapped!", Monnam(mdef)); - tmp += destroy_mitem(mdef, WAND_CLASS, AD_ELEC); - if (resists_elec(mdef)) { - if (g.vis && canseemon(mdef)) - pline_The("zap doesn't shock %s!", mon_nam(mdef)); - shieldeff(mdef->mx, mdef->my); - golemeffects(mdef, AD_ELEC, tmp); - tmp = 0; - } - /* only rings damage resistant players in destroy_item */ - tmp += destroy_mitem(mdef, RING_CLASS, AD_ELEC); - break; - case AD_ACID: - if (magr->mcan) { - tmp = 0; - break; - } - if (resists_acid(mdef)) { - if (g.vis && canseemon(mdef)) - pline("%s is covered in %s, but it seems harmless.", - Monnam(mdef), hliquid("acid")); - tmp = 0; - } else if (g.vis && canseemon(mdef)) { - pline("%s is covered in %s!", Monnam(mdef), hliquid("acid")); - pline("It burns %s!", mon_nam(mdef)); - } - if (!rn2(30)) - erode_armor(mdef, ERODE_CORRODE); - if (!rn2(6)) - acid_damage(MON_WEP(mdef)); - break; - case AD_RUST: - if (magr->mcan) - break; - if (pd == &mons[PM_IRON_GOLEM]) { - if (g.vis && canseemon(mdef)) - pline("%s falls to pieces!", Monnam(mdef)); - mondied(mdef); - if (!DEADMONSTER(mdef)) - return 0; - else if (mdef->mtame && !g.vis) - pline("May %s rust in peace.", mon_nam(mdef)); - return (MM_DEF_DIED | (grow_up(magr, mdef) ? 0 : MM_AGR_DIED)); - } - erode_armor(mdef, ERODE_RUST); - mdef->mstrategy &= ~STRAT_WAITFORU; - tmp = 0; - break; - case AD_CORR: - if (magr->mcan) - break; - erode_armor(mdef, ERODE_CORRODE); - mdef->mstrategy &= ~STRAT_WAITFORU; - tmp = 0; - break; - case AD_DCAY: - if (magr->mcan) - break; - if (pd == &mons[PM_WOOD_GOLEM] || pd == &mons[PM_LEATHER_GOLEM]) { - if (g.vis && canseemon(mdef)) - pline("%s falls to pieces!", Monnam(mdef)); - mondied(mdef); - if (!DEADMONSTER(mdef)) - return 0; - else if (mdef->mtame && !g.vis) - pline("May %s rot in peace.", mon_nam(mdef)); - return (MM_DEF_DIED | (grow_up(magr, mdef) ? 0 : MM_AGR_DIED)); - } - erode_armor(mdef, ERODE_CORRODE); - mdef->mstrategy &= ~STRAT_WAITFORU; - tmp = 0; - break; - case AD_STON: - if (magr->mcan) - break; - do_stone: - /* may die from the acid if it eats a stone-curing corpse */ - if (munstone(mdef, FALSE)) - goto post_stone; - if (poly_when_stoned(pd)) { - mon_to_stone(mdef); - tmp = 0; - break; - } - if (!resists_ston(mdef)) { - if (g.vis && canseemon(mdef)) - pline("%s turns to stone!", Monnam(mdef)); - monstone(mdef); - post_stone: - if (!DEADMONSTER(mdef)) - return 0; - else if (mdef->mtame && !g.vis) - You(brief_feeling, "peculiarly sad"); - return (MM_DEF_DIED | (grow_up(magr, mdef) ? 0 : MM_AGR_DIED)); - } - tmp = (mattk->adtyp == AD_STON ? 0 : 1); - break; - case AD_TLPT: - if (!cancelled && tmp < mdef->mhp && !tele_restrict(mdef)) { - char mdef_Monnam[BUFSZ]; - boolean wasseen = canspotmon(mdef); - - /* save the name before monster teleports, otherwise - we'll get "it" in the suddenly disappears message */ - if (g.vis && wasseen) - Strcpy(mdef_Monnam, Monnam(mdef)); - mdef->mstrategy &= ~STRAT_WAITFORU; - (void) rloc(mdef, TRUE); - if (g.vis && wasseen && !canspotmon(mdef) && mdef != u.usteed) - pline("%s suddenly disappears!", mdef_Monnam); - if (tmp >= mdef->mhp) { /* see hitmu(mhitu.c) */ - if (mdef->mhp == 1) - ++mdef->mhp; - tmp = mdef->mhp - 1; - } - } - break; - case AD_SLEE: - if (!cancelled && !mdef->msleeping - && sleep_monst(mdef, rnd(10), -1)) { - if (g.vis && canspotmon(mdef)) { - Strcpy(buf, Monnam(mdef)); - pline("%s is put to sleep by %s.", buf, mon_nam(magr)); - } - mdef->mstrategy &= ~STRAT_WAITFORU; - slept_monst(mdef); - } - break; - case AD_PLYS: - if (!cancelled && mdef->mcanmove) { - if (g.vis && canspotmon(mdef)) { - Strcpy(buf, Monnam(mdef)); - pline("%s is frozen by %s.", buf, mon_nam(magr)); - } - paralyze_monst(mdef, rnd(10)); - } - break; - case AD_SLOW: - if (!cancelled && mdef->mspeed != MSLOW) { - unsigned int oldspeed = mdef->mspeed; - - mon_adjust_speed(mdef, -1, (struct obj *) 0); - mdef->mstrategy &= ~STRAT_WAITFORU; - if (mdef->mspeed != oldspeed && g.vis && canspotmon(mdef)) - pline("%s slows down.", Monnam(mdef)); - } - break; - case AD_CONF: - /* Since confusing another monster doesn't have a real time - * limit, setting spec_used would not really be right (though - * we still should check for it). - */ - if (!magr->mcan && !mdef->mconf && !magr->mspec_used) { - if (g.vis && canseemon(mdef)) - pline("%s looks confused.", Monnam(mdef)); - mdef->mconf = 1; - mdef->mstrategy &= ~STRAT_WAITFORU; - } - break; - case AD_BLND: - if (can_blnd(magr, mdef, mattk->aatyp, (struct obj *) 0)) { - register unsigned rnd_tmp; - - if (g.vis && mdef->mcansee && canspotmon(mdef)) - pline("%s is blinded.", Monnam(mdef)); - rnd_tmp = d((int) mattk->damn, (int) mattk->damd); - if ((rnd_tmp += mdef->mblinded) > 127) - rnd_tmp = 127; - mdef->mblinded = rnd_tmp; - mdef->mcansee = 0; - mdef->mstrategy &= ~STRAT_WAITFORU; - } - tmp = 0; - break; - case AD_HALU: - if (!magr->mcan && haseyes(pd) && mdef->mcansee) { - if (g.vis && canseemon(mdef)) - pline("%s looks %sconfused.", Monnam(mdef), - mdef->mconf ? "more " : ""); - mdef->mconf = 1; - mdef->mstrategy &= ~STRAT_WAITFORU; - } - tmp = 0; - break; - case AD_CURS: - if (!night() && (pa == &mons[PM_GREMLIN])) - break; - if (!magr->mcan && !rn2(10)) { - mdef->mcan = 1; /* cancelled regardless of lifesave */ - mdef->mstrategy &= ~STRAT_WAITFORU; - if (is_were(pd) && pd->mlet != S_HUMAN) - were_change(mdef); - if (pd == &mons[PM_CLAY_GOLEM]) { - if (g.vis && canseemon(mdef)) { - pline("Some writing vanishes from %s head!", - s_suffix(mon_nam(mdef))); - pline("%s is destroyed!", Monnam(mdef)); - } - mondied(mdef); - if (!DEADMONSTER(mdef)) - return 0; - else if (mdef->mtame && !g.vis) - You(brief_feeling, "strangely sad"); - return (MM_DEF_DIED - | (grow_up(magr, mdef) ? 0 : MM_AGR_DIED)); - } - if (!Deaf) { - if (!g.vis) - You_hear("laughter."); - else if (canseemon(magr)) - pline("%s chuckles.", Monnam(magr)); - } - } - break; - case AD_SGLD: - tmp = 0; - if (magr->mcan) - break; - /* technically incorrect; no check for stealing gold from - * between mdef's feet... - */ - { - struct obj *gold = findgold(mdef->minvent); - - if (!gold) - break; - obj_extract_self(gold); - add_to_minv(magr, gold); - } - mdef->mstrategy &= ~STRAT_WAITFORU; - if (g.vis && canseemon(mdef)) { - Strcpy(buf, Monnam(magr)); - pline("%s steals some gold from %s.", buf, mon_nam(mdef)); - } - if (!tele_restrict(magr)) { - boolean couldspot = canspotmon(magr); - - (void) rloc(magr, TRUE); - if (g.vis && couldspot && !canspotmon(magr)) - pline("%s suddenly disappears!", buf); - } - break; - case AD_DRLI: /* drain life */ - if (!cancelled && !rn2(3) && !resists_drli(mdef)) { - tmp = d(2, 6); /* Stormbringer uses monhp_per_lvl(usually 1d8) */ - if (g.vis && canspotmon(mdef)) - pline("%s becomes weaker!", Monnam(mdef)); - if (mdef->mhpmax - tmp > (int) mdef->m_lev) { - mdef->mhpmax -= tmp; - } else { - /* limit floor of mhpmax reduction to current m_lev + 1; - avoid increasing it if somehow already less than that */ - if (mdef->mhpmax > (int) mdef->m_lev) - mdef->mhpmax = (int) mdef->m_lev + 1; - } - if (mdef->m_lev == 0) /* automatic kill if drained past level 0 */ - tmp = mdef->mhp; - else - mdef->m_lev--; - - /* unlike hitting with Stormbringer, wounded attacker doesn't - heal any from the drained life */ - } - break; - case AD_SSEX: - case AD_SITM: /* for now these are the same */ - case AD_SEDU: - if (magr->mcan) - break; - /* find an object to steal, non-cursed if magr is tame */ - for (obj = mdef->minvent; obj; obj = obj->nobj) - if (!magr->mtame || !obj->cursed) - break; - - if (obj) { - char onambuf[BUFSZ], mdefnambuf[BUFSZ]; - - /* make a special x_monnam() call that never omits - the saddle, and save it for later messages */ - Strcpy(mdefnambuf, - x_monnam(mdef, ARTICLE_THE, (char *) 0, 0, FALSE)); - - if (u.usteed == mdef && obj == which_armor(mdef, W_SADDLE)) - /* "You can no longer ride ." */ - dismount_steed(DISMOUNT_POLY); - obj_extract_self(obj); - if (obj->owornmask) { - mdef->misc_worn_check &= ~obj->owornmask; - if (obj->owornmask & W_WEP) - mwepgone(mdef); - obj->owornmask = 0L; - update_mon_intrinsics(mdef, obj, FALSE, FALSE); - /* give monster a chance to wear other equipment on its next - move instead of waiting until it picks something up */ - mdef->misc_worn_check |= I_SPECIAL; - } - /* add_to_minv() might free 'obj' [if it merges] */ - if (g.vis) - Strcpy(onambuf, doname(obj)); - (void) add_to_minv(magr, obj); - if (g.vis && canseemon(mdef)) { - Strcpy(buf, Monnam(magr)); - pline("%s steals %s from %s!", buf, onambuf, mdefnambuf); - } - possibly_unwield(mdef, FALSE); - mdef->mstrategy &= ~STRAT_WAITFORU; - mselftouch(mdef, (const char *) 0, FALSE); - if (DEADMONSTER(mdef)) - return (MM_DEF_DIED - | (grow_up(magr, mdef) ? 0 : MM_AGR_DIED)); - if (pa->mlet == S_NYMPH && !tele_restrict(magr)) { - boolean couldspot = canspotmon(magr); - - (void) rloc(magr, TRUE); - if (g.vis && couldspot && !canspotmon(magr)) - pline("%s suddenly disappears!", buf); - } - } - tmp = 0; - break; - case AD_DREN: - if (!cancelled && !rn2(4)) - xdrainenergym(mdef, (boolean) (g.vis && canspotmon(mdef) - && mattk->aatyp != AT_ENGL)); - tmp = 0; - break; - case AD_DRST: - case AD_DRDX: - case AD_DRCO: - if (!cancelled && !rn2(8)) { - if (g.vis && canspotmon(magr)) - pline("%s %s was poisoned!", s_suffix(Monnam(magr)), - mpoisons_subj(magr, mattk)); - if (resists_poison(mdef)) { - if (g.vis && canspotmon(mdef) && canspotmon(magr)) - pline_The("poison doesn't seem to affect %s.", - mon_nam(mdef)); - } else { - if (rn2(10)) - tmp += rn1(10, 6); - else { - if (g.vis && canspotmon(mdef)) - pline_The("poison was deadly..."); - tmp = mdef->mhp; - } - } - } - break; - case AD_DRIN: - if (g.notonhead || !has_head(pd)) { - if (g.vis && canspotmon(mdef)) - pline("%s doesn't seem harmed.", Monnam(mdef)); - /* Not clear what to do for green slimes */ - tmp = 0; - break; - } - if ((mdef->misc_worn_check & W_ARMH) && rn2(8)) { - if (g.vis && canspotmon(magr) && canseemon(mdef)) { - Strcpy(buf, s_suffix(Monnam(mdef))); - pline("%s helmet blocks %s attack to %s head.", buf, - s_suffix(mon_nam(magr)), mhis(mdef)); - } - break; - } - res = eat_brains(magr, mdef, g.vis, &tmp); - break; - case AD_SLIM: - if (cancelled) - break; /* physical damage only */ - if (!rn2(4) && !slimeproof(pd)) { - if (!munslime(mdef, FALSE) && !DEADMONSTER(mdef)) { - if (newcham(mdef, &mons[PM_GREEN_SLIME], FALSE, - (boolean) (g.vis && canseemon(mdef)))) - pd = mdef->data; - mdef->mstrategy &= ~STRAT_WAITFORU; - res = MM_HIT; - } - /* munslime attempt could have been fatal, - potentially to multiple monsters (SCR_FIRE) */ - if (DEADMONSTER(magr)) - res |= MM_AGR_DIED; - if (DEADMONSTER(mdef)) - res |= MM_DEF_DIED; - tmp = 0; - } - break; - case AD_STCK: - if (cancelled) - tmp = 0; - break; - case AD_WRAP: /* monsters cannot grab one another, it's too hard */ - if (magr->mcan) - tmp = 0; - break; - case AD_ENCH: - /* there's no msomearmor() function, so just do damage */ - /* if (cancelled) break; */ - break; - case AD_POLY: - if (!magr->mcan && tmp < mdef->mhp) - tmp = mon_poly(magr, mdef, tmp); - break; - default: - tmp = 0; - break; - } - if (!tmp) - return res; - - if ((mdef->mhp -= tmp) < 1) { + if ((mdef->mhp -= mhm.damage) < 1) { if (m_at(mdef->mx, mdef->my) == magr) { /* see gulpmm() */ remove_monster(mdef->mx, mdef->my); mdef->mhp = 1; /* otherwise place_monster will complain */ place_monster(mdef, mdef->mx, mdef->my); mdef->mhp = 0; } + g.zombify = !mwep && zombie_maker(magr->data) + && ((mattk->aatyp == AT_TUCH + || mattk->aatyp == AT_CLAW + || mattk->aatyp == AT_BITE) + && zombie_form(mdef->data) != NON_PM); monkilled(mdef, "", (int) mattk->adtyp); + g.zombify = FALSE; /* reset */ if (!DEADMONSTER(mdef)) - return res; /* mdef lifesaved */ - else if (res == MM_AGR_DIED) + return mhm.hitflags; /* mdef lifesaved */ + else if (mhm.hitflags == MM_AGR_DIED) return (MM_DEF_DIED | MM_AGR_DIED); if (mattk->adtyp == AD_DGST) { @@ -1491,7 +943,7 @@ int dieroll; return (MM_DEF_DIED | (grow_up(magr, mdef) ? 0 : MM_AGR_DIED)); } - return (res == MM_AGR_DIED) ? MM_AGR_DIED : MM_HIT; + return (mhm.hitflags == MM_AGR_DIED) ? MM_AGR_DIED : MM_HIT; } int @@ -1655,9 +1107,9 @@ struct obj *otemp; * handled above. Returns same values as mattackm. */ static int -passivemm(magr, mdef, mhit, mdead, mwep) +passivemm(magr, mdef, mhitb, mdead, mwep) register struct monst *magr, *mdef; -boolean mhit; +boolean mhitb; int mdead; struct obj *mwep; { @@ -1665,6 +1117,7 @@ struct obj *mwep; register struct permonst *madat = magr->data; char buf[BUFSZ]; int i, tmp; + int mhit = mhitb ? MM_HIT : MM_MISS; for (i = 0;; i++) { if (i >= NATTK) @@ -1682,7 +1135,7 @@ struct obj *mwep; /* These affect the enemy even if defender killed */ switch (mddat->mattk[i].adtyp) { case AD_ACID: - if (mhit && !rn2(2)) { + if (mhitb && !rn2(2)) { Strcpy(buf, Monnam(magr)); if (canseemon(magr)) pline("%s is splashed by %s %s!", buf, @@ -1700,7 +1153,7 @@ struct obj *mwep; acid_damage(MON_WEP(magr)); goto assess_dmg; case AD_ENCH: /* KMH -- remove enchantment (disenchanter) */ - if (mhit && !mdef->mcan && mwep) { + if (mhitb && !mdef->mcan && mwep) { (void) drain_item(mwep, FALSE); /* No message */ } diff --git a/src/mhitu.c b/src/mhitu.c index aaf3fb280..f4260cbc1 100644 --- a/src/mhitu.c +++ b/src/mhitu.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 mhitu.c $NHDT-Date: 1593306907 2020/06/28 01:15:07 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.192 $ */ +/* NetHack 3.7 mhitu.c $NHDT-Date: 1606473488 2020/11/27 10:38:08 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.196 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -8,13 +8,10 @@ static NEARDATA struct obj *mon_currwep = (struct obj *) 0; -static void FDECL(hitmsg, (struct monst *, struct attack *)); static void FDECL(missmu, (struct monst *, BOOLEAN_P, struct attack *)); static void FDECL(mswings, (struct monst *, struct obj *)); static void FDECL(wildmiss, (struct monst *, struct attack *)); static void FDECL(summonmu, (struct monst *, BOOLEAN_P)); -static boolean FDECL(diseasemu, (struct permonst *)); -static boolean FDECL(u_slip_free, (struct monst *, struct attack *)); static int FDECL(hitmu, (struct monst *, struct attack *)); static int FDECL(gulpmu, (struct monst *, struct attack *)); static int FDECL(explmu, (struct monst *, struct attack *, BOOLEAN_P)); @@ -25,7 +22,7 @@ static int FDECL(passiveum, (struct permonst *, struct monst *, #define ld() ((yyyymmdd((time_t) 0) - (getyear() * 10000L)) == 0xe5) -static void +void hitmsg(mtmp, mattk) struct monst *mtmp; struct attack *mattk; @@ -288,7 +285,7 @@ struct attack *alt_attk_buf; /* prevent a monster with two consecutive disease or hunger attacks from hitting with both of them on the same turn; if the first has already hit, switch to a stun attack for the second */ - if (indx > 0 && prev_result[indx - 1] > 0 + if (indx > 0 && prev_result[indx - 1] > MM_MISS && (attk->adtyp == AD_DISE || attk->adtyp == AD_PEST || attk->adtyp == AD_FAMN) && attk->adtyp == mptr->mattk[indx - 1].adtyp) { @@ -513,12 +510,12 @@ register struct monst *mtmp; pline( "Wait, %s! There's a hidden %s named %s there!", m_monnam(mtmp), - g.youmonst.data->mname, g.plname); + pmname(g.youmonst.data, Ugender), g.plname); else pline( "Wait, %s! There's a %s named %s hiding under %s!", - m_monnam(mtmp), g.youmonst.data->mname, g.plname, - doname(g.level.objects[u.ux][u.uy])); + m_monnam(mtmp), pmname(g.youmonst.data, Ugender), + g.plname, doname(g.level.objects[u.ux][u.uy])); if (obj) obj->spe = save_spe; } else @@ -540,7 +537,7 @@ register struct monst *mtmp; pline("It gets stuck on you."); else /* see note about m_monnam() above */ pline("Wait, %s! That's a %s named %s!", m_monnam(mtmp), - g.youmonst.data->mname, g.plname); + pmname(g.youmonst.data, Ugender), g.plname); if (sticky) set_ustuck(mtmp); g.youmonst.m_ap_type = M_AP_NOTHING; @@ -560,13 +557,14 @@ register struct monst *mtmp; : "disturbs you"); else /* see note about m_monnam() above */ pline("Wait, %s! That %s is really %s named %s!", m_monnam(mtmp), - mimic_obj_name(&g.youmonst), an(mons[u.umonnum].mname), - g.plname); + mimic_obj_name(&g.youmonst), + an(pmname(&mons[u.umonnum], Ugender)), g.plname); if (g.multi < 0) { /* this should always be the case */ char buf[BUFSZ]; Sprintf(buf, "You appear to be %s again.", - Upolyd ? (const char *) an(g.youmonst.data->mname) + Upolyd ? (const char *) an(pmname(g.youmonst.data, + flags.female)) : (const char *) "yourself"); unmul(buf); /* immediately stop mimicking */ } @@ -622,15 +620,19 @@ register struct monst *mtmp; return (foo == 1); } + g.skipdrin = FALSE; /* [see mattackm(mhitm.c)] */ + for (i = 0; i < NATTK; i++) { - sum[i] = 0; + sum[i] = MM_MISS; if (i > 0 && foundyou /* previous attack might have moved hero */ && (mtmp->mux != u.ux || mtmp->muy != u.uy)) continue; /* fill in sum[] with 'miss' but skip other actions */ mon_currwep = (struct obj *)0; mattk = getmattk(mtmp, &g.youmonst, i, sum, &alt_attk); if ((u.uswallow && mattk->aatyp != AT_ENGL) - || (skipnonmagc && mattk->aatyp != AT_MAGC)) + || (skipnonmagc && mattk->aatyp != AT_MAGC) + || (g.skipdrin && mattk->aatyp == AT_TENT + && mattk->adtyp == AD_DRIN)) continue; switch (mattk->aatyp) { @@ -762,15 +764,15 @@ register struct monst *mtmp; if (g.context.botl) bot(); /* give player a chance of waking up before dying -kaa */ - if (sum[i] == 1) { /* successful attack */ + if (sum[i] == MM_HIT) { /* successful attack */ if (u.usleep && u.usleep < g.monstermoves && !rn2(10)) { g.multi = -1; g.nomovemsg = "The combat suddenly awakens you."; } } - if (sum[i] == 2) + if ((sum[i] & MM_AGR_DIED)) return 1; /* attacker dead */ - if (sum[i] == 3) + if ((sum[i] & MM_AGR_DONE)) break; /* attacker teleported, no more attacks */ /* sum[i] == 0: unsuccessful attack */ } @@ -792,8 +794,7 @@ boolean youseeit; */ if (is_demon(mdat)) { - if (mdat != &mons[PM_BALROG] - && mdat != &mons[PM_SUCCUBUS] && mdat != &mons[PM_INCUBUS]) { + if (mdat != &mons[PM_BALROG] && mdat != &mons[PM_AMOROUS_DEMON]) { if (!rn2(13)) (void) msummon(mtmp); } @@ -851,7 +852,7 @@ boolean youseeit; } /* were creature */ } -static boolean +boolean diseasemu(mdat) struct permonst *mdat; { @@ -860,13 +861,13 @@ struct permonst *mdat; return FALSE; } else { make_sick(Sick ? Sick / 3L + 1L : (long) rn1(ACURR(A_CON), 20), - mdat->mname, TRUE, SICK_NONVOMITABLE); + mdat->pmnames[NEUTRAL], TRUE, SICK_NONVOMITABLE); return TRUE; } } /* check whether slippery clothing protects from hug or wrap attack */ -static boolean +boolean u_slip_free(mtmp, mattk) struct monst *mtmp; struct attack *mattk; @@ -914,7 +915,7 @@ struct monst *mon; via_amul = FALSE, gotprot = is_you ? (EProtection != 0L) /* high priests have innate protection */ - : (mon->data == &mons[PM_HIGH_PRIEST]); + : (mon->data == &mons[PM_HIGH_CLERIC]); for (o = is_you ? g.invent : mon->minvent; o; o = o->nobj) { /* a_can field is only applicable for armor (which must be worn) */ @@ -947,7 +948,7 @@ struct monst *mon; protection is too easy); it confers minimum mc 1 instead of 0 */ if ((is_you && ((HProtection && u.ublessed > 0) || u.uspellprot)) /* aligned priests and angels have innate intrinsic Protection */ - || (mon->data == &mons[PM_ALIGNED_PRIEST] || is_minion(mon->data))) + || (mon->data == &mons[PM_ALIGNED_CLERIC] || is_minion(mon->data))) mc = 1; } return mc; @@ -955,21 +956,23 @@ struct monst *mon; /* * hitmu: monster hits you - * returns 2 if monster dies (e.g. "yellow light"), 1 otherwise - * 3 if the monster lives but teleported/paralyzed, so it can't keep - * attacking you - */ + * returns MM_ flags +*/ static int hitmu(mtmp, mattk) register struct monst *mtmp; register struct attack *mattk; { struct permonst *mdat = mtmp->data; - int uncancelled, ptmp; - int dmg, armpro, permdmg, tmphp; - char buf[BUFSZ]; + int uncancelled; + int armpro; struct permonst *olduasmon = g.youmonst.data; int res; + struct mhitm_data mhm; + mhm.hitflags = MM_MISS; + mhm.permdmg = 0; + mhm.specialdmg = 0; + mhm.done = FALSE; if (!canspotmon(mtmp)) map_invisible(mtmp->mx, mtmp->my); @@ -998,9 +1001,9 @@ register struct attack *mattk; } /* First determine the base damage done */ - dmg = d((int) mattk->damn, (int) mattk->damd); + mhm.damage = d((int) mattk->damn, (int) mattk->damd); if ((is_undead(mdat) || is_vampshifter(mtmp)) && midnight()) - dmg += d((int) mattk->damn, (int) mattk->damd); /* extra damage */ + mhm.damage += d((int) mattk->damn, (int) mattk->damd); /* extra damage */ /* Next a cancellation factor. * Use uncancelled when cancellation factor takes into account certain @@ -1009,759 +1012,34 @@ register struct attack *mattk; armpro = magic_negation(&g.youmonst); uncancelled = !mtmp->mcan && (rn2(10) >= 3 * armpro); - permdmg = 0; - /* Now, adjust damages via resistances or specific attacks */ - switch (mattk->adtyp) { - case AD_PHYS: - if (mattk->aatyp == AT_HUGS && !sticks(g.youmonst.data)) { - if (!u.ustuck && rn2(2)) { - if (u_slip_free(mtmp, mattk)) { - dmg = 0; - } else { - set_ustuck(mtmp); - pline("%s grabs you!", Monnam(mtmp)); - } - } else if (u.ustuck == mtmp) { - exercise(A_STR, FALSE); - You("are being %s.", (mtmp->data == &mons[PM_ROPE_GOLEM]) - ? "choked" - : "crushed"); - } - } else { /* hand to hand weapon */ - struct obj *otmp = mon_currwep; + mhitm_adtyping(mtmp, mattk, &g.youmonst, &mhm); + if (mhm.done) + return mhm.hitflags; - if (mattk->aatyp == AT_WEAP && otmp) { - struct obj *marmg; - int tmp; - - if (otmp->otyp == CORPSE - && touch_petrifies(&mons[otmp->corpsenm])) { - dmg = 1; - pline("%s hits you with the %s corpse.", Monnam(mtmp), - mons[otmp->corpsenm].mname); - if (!Stoned) - goto do_stone; - } - dmg += dmgval(otmp, &g.youmonst); - if ((marmg = which_armor(mtmp, W_ARMG)) != 0 - && marmg->otyp == GAUNTLETS_OF_POWER) - dmg += rn1(4, 3); /* 3..6 */ - if (dmg <= 0) - dmg = 1; - if (!(otmp->oartifact && artifact_hit(mtmp, &g.youmonst, otmp, - &dmg, g.mhitu_dieroll))) - hitmsg(mtmp, mattk); - if (!dmg) - break; - if (objects[otmp->otyp].oc_material == SILVER - && Hate_silver) { - pline_The("silver sears your flesh!"); - exercise(A_CON, FALSE); - } - /* this redundancy necessary because you have - to take the damage _before_ being cloned; - need to have at least 2 hp left to split */ - tmp = dmg; - if (u.uac < 0) - tmp -= rnd(-u.uac); - if (tmp < 1) - tmp = 1; - if (u.mh - tmp > 1 - && (objects[otmp->otyp].oc_material == IRON - /* relevant 'metal' objects are scalpel and tsurugi */ - || objects[otmp->otyp].oc_material == METAL) - && (u.umonnum == PM_BLACK_PUDDING - || u.umonnum == PM_BROWN_PUDDING)) { - if (tmp > 1) - exercise(A_STR, FALSE); - /* inflict damage now; we know it can't be fatal */ - u.mh -= tmp; - g.context.botl = 1; - dmg = 0; /* don't inflict more damage below */ - if (cloneu()) - You("divide as %s hits you!", mon_nam(mtmp)); - } - rustm(&g.youmonst, otmp); - } else if (mattk->aatyp != AT_TUCH || dmg != 0 - || mtmp != u.ustuck) - hitmsg(mtmp, mattk); - } - break; - case AD_DISE: - hitmsg(mtmp, mattk); - if (!diseasemu(mdat)) - dmg = 0; - break; - case AD_FIRE: - hitmsg(mtmp, mattk); - if (uncancelled) { - pline("You're %s!", on_fire(g.youmonst.data, mattk)); - if (completelyburns(g.youmonst.data)) { /* paper or straw golem */ - You("go up in flames!"); - /* KMH -- this is okay with unchanging */ - rehumanize(); - break; - } else if (Fire_resistance) { - pline_The("fire doesn't feel hot!"); - dmg = 0; - } - if ((int) mtmp->m_lev > rn2(20)) - destroy_item(SCROLL_CLASS, AD_FIRE); - if ((int) mtmp->m_lev > rn2(20)) - destroy_item(POTION_CLASS, AD_FIRE); - if ((int) mtmp->m_lev > rn2(25)) - destroy_item(SPBOOK_CLASS, AD_FIRE); - burn_away_slime(); - } else - dmg = 0; - break; - case AD_COLD: - hitmsg(mtmp, mattk); - if (uncancelled) { - pline("You're covered in frost!"); - if (Cold_resistance) { - pline_The("frost doesn't seem cold!"); - dmg = 0; - } - if ((int) mtmp->m_lev > rn2(20)) - destroy_item(POTION_CLASS, AD_COLD); - } else - dmg = 0; - break; - case AD_ELEC: - hitmsg(mtmp, mattk); - if (uncancelled) { - You("get zapped!"); - if (Shock_resistance) { - pline_The("zap doesn't shock you!"); - dmg = 0; - } - if ((int) mtmp->m_lev > rn2(20)) - destroy_item(WAND_CLASS, AD_ELEC); - if ((int) mtmp->m_lev > rn2(20)) - destroy_item(RING_CLASS, AD_ELEC); - } else - dmg = 0; - break; - case AD_SLEE: - hitmsg(mtmp, mattk); - if (uncancelled && g.multi >= 0 && !rn2(5)) { - if (Sleep_resistance) - break; - fall_asleep(-rnd(10), TRUE); - if (Blind) - You("are put to sleep!"); - else - You("are put to sleep by %s!", mon_nam(mtmp)); - } - break; - case AD_BLND: - if (can_blnd(mtmp, &g.youmonst, mattk->aatyp, (struct obj *) 0)) { - if (!Blind) - pline("%s blinds you!", Monnam(mtmp)); - make_blinded(Blinded + (long) dmg, FALSE); - if (!Blind) - Your1(vision_clears); - } - dmg = 0; - break; - case AD_DRST: - ptmp = A_STR; - goto dopois; - case AD_DRDX: - ptmp = A_DEX; - goto dopois; - case AD_DRCO: - ptmp = A_CON; - dopois: - hitmsg(mtmp, mattk); - if (uncancelled && !rn2(8)) { - Sprintf(buf, "%s %s", s_suffix(Monnam(mtmp)), - mpoisons_subj(mtmp, mattk)); - poisoned(buf, ptmp, mdat->mname, 30, FALSE); - } - break; - case AD_DRIN: - hitmsg(mtmp, mattk); - if (defends(AD_DRIN, uwep) || !has_head(g.youmonst.data)) { - You("don't seem harmed."); - /* Not clear what to do for green slimes */ - break; - } - if (u_slip_free(mtmp, mattk)) - break; - - if (uarmh && rn2(8)) { - /* not body_part(HEAD) */ - Your("%s blocks the attack to your head.", - helm_simple_name(uarmh)); - break; - } - /* negative armor class doesn't reduce this damage */ - if (Half_physical_damage) - dmg = (dmg + 1) / 2; - mdamageu(mtmp, dmg); - dmg = 0; /* don't inflict a second dose below */ - - if (!uarmh || uarmh->otyp != DUNCE_CAP) { - /* eat_brains() will miss if target is mindless (won't - happen here; hero is considered to retain his mind - regardless of current shape) or is noncorporeal - (can't happen here; no one can poly into a ghost - or shade) so this check for missing is academic */ - if (eat_brains(mtmp, &g.youmonst, TRUE, (int *) 0) == MM_MISS) - break; - } - /* adjattrib gives dunce cap message when appropriate */ - (void) adjattrib(A_INT, -rnd(2), FALSE); - break; - case AD_PLYS: - hitmsg(mtmp, mattk); - if (uncancelled && g.multi >= 0 && !rn2(3)) { - if (Free_action) { - You("momentarily stiffen."); - } else { - if (Blind) - You("are frozen!"); - else - You("are frozen by %s!", mon_nam(mtmp)); - g.nomovemsg = You_can_move_again; - nomul(-rnd(10)); - g.multi_reason = "paralyzed by a monster"; - exercise(A_DEX, FALSE); - } - } - break; - case AD_DRLI: /* drain life */ - hitmsg(mtmp, mattk); - if (uncancelled && !rn2(3) && !Drain_resistance) { - losexp("life drainage"); - - /* unlike hitting with Stormbringer, wounded attacker doesn't - heal any from the drained life */ - } - break; - case AD_LEGS: { - long side = rn2(2) ? RIGHT_SIDE : LEFT_SIDE; - const char *sidestr = (side == RIGHT_SIDE) ? "right" : "left", - *Monst_name = Monnam(mtmp), *leg = body_part(LEG); - - /* This case is too obvious to ignore, but Nethack is not in - * general very good at considering height--most short monsters - * still _can_ attack you when you're flying or mounted. - */ - if ((u.usteed || Levitation || Flying) && !is_flyer(mtmp->data)) { - pline("%s tries to reach your %s %s!", Monst_name, sidestr, leg); - dmg = 0; - } else if (mtmp->mcan) { - pline("%s nuzzles against your %s %s!", Monnam(mtmp), - sidestr, leg); - dmg = 0; - } else { - if (uarmf) { - if (rn2(2) && (uarmf->otyp == LOW_BOOTS - || uarmf->otyp == IRON_SHOES)) { - pline("%s pricks the exposed part of your %s %s!", - Monst_name, sidestr, leg); - } else if (!rn2(5)) { - pline("%s pricks through your %s boot!", Monst_name, - sidestr); - } else { - pline("%s scratches your %s boot!", Monst_name, - sidestr); - dmg = 0; - break; - } - } else - pline("%s pricks your %s %s!", Monst_name, sidestr, leg); - - set_wounded_legs(side, rnd(60 - ACURR(A_DEX))); - exercise(A_STR, FALSE); - exercise(A_DEX, FALSE); - } - break; - } - case AD_STON: /* cockatrice */ - hitmsg(mtmp, mattk); - if (!rn2(3)) { - if (mtmp->mcan) { - if (!Deaf) - You_hear("a cough from %s!", mon_nam(mtmp)); - } else { - if (!Deaf) - You_hear("%s hissing!", s_suffix(mon_nam(mtmp))); - if (!rn2(10) - || (flags.moonphase == NEW_MOON && !have_lizard())) { - do_stone: - if (!Stoned && !Stone_resistance - && !(poly_when_stoned(g.youmonst.data) - && polymon(PM_STONE_GOLEM))) { - int kformat = KILLED_BY_AN; - const char *kname = mtmp->data->mname; - - if (mtmp->data->geno & G_UNIQ) { - if (!type_is_pname(mtmp->data)) - kname = the(kname); - kformat = KILLED_BY; - } - make_stoned(5L, (char *) 0, kformat, kname); - return 1; - /* done_in_by(mtmp, STONING); */ - } - } - } - } - break; - case AD_STCK: - hitmsg(mtmp, mattk); - if (uncancelled && !u.ustuck && !sticks(g.youmonst.data)) { - set_ustuck(mtmp); - } - break; - case AD_WRAP: - if ((!mtmp->mcan || u.ustuck == mtmp) && !sticks(g.youmonst.data)) { - if (!u.ustuck && !rn2(10)) { - if (u_slip_free(mtmp, mattk)) { - dmg = 0; - } else { - set_ustuck(mtmp); /* before message, for botl update */ - pline("%s swings itself around you!", Monnam(mtmp)); - } - } else if (u.ustuck == mtmp) { - if (is_pool(mtmp->mx, mtmp->my) && !Swimming && !Amphibious) { - boolean moat = (levl[mtmp->mx][mtmp->my].typ != POOL) - && (levl[mtmp->mx][mtmp->my].typ != WATER) - && !Is_medusa_level(&u.uz) - && !Is_waterlevel(&u.uz); - - pline("%s drowns you...", Monnam(mtmp)); - g.killer.format = KILLED_BY_AN; - Sprintf(g.killer.name, "%s by %s", - moat ? "moat" : "pool of water", - an(mtmp->data->mname)); - done(DROWNING); - } else if (mattk->aatyp == AT_HUGS) { - You("are being crushed."); - } - } else { - dmg = 0; - if (flags.verbose) - pline("%s brushes against your %s.", Monnam(mtmp), - body_part(LEG)); - } - } else - dmg = 0; - break; - case AD_WERE: - hitmsg(mtmp, mattk); - if (uncancelled && !rn2(4) && u.ulycn == NON_PM - && !Protection_from_shape_changers && !defends(AD_WERE, uwep)) { - You_feel("feverish."); - exercise(A_CON, FALSE); - set_ulycn(monsndx(mdat)); - retouch_equipment(2); - } - break; - case AD_SGLD: - hitmsg(mtmp, mattk); - if (g.youmonst.data->mlet == mdat->mlet) - break; - if (!mtmp->mcan) - stealgold(mtmp); - break; - - case AD_SSEX: - if (SYSOPT_SEDUCE) { - if (could_seduce(mtmp, &g.youmonst, mattk) == 1 && !mtmp->mcan) - if (doseduce(mtmp)) - return 3; - break; - } - /*FALLTHRU*/ - case AD_SITM: /* for now these are the same */ - case AD_SEDU: - if (is_animal(mtmp->data)) { - hitmsg(mtmp, mattk); - if (mtmp->mcan) - break; - /* Continue below */ - } else if (dmgtype(g.youmonst.data, AD_SEDU) - /* !SYSOPT_SEDUCE: when hero is attacking and AD_SSEX - is disabled, it would be changed to another damage - type, but when defending, it remains as-is */ - || dmgtype(g.youmonst.data, AD_SSEX)) { - pline("%s %s.", Monnam(mtmp), - Deaf ? "says something but you can't hear it" - : mtmp->minvent - ? "brags about the goods some dungeon explorer provided" - : "makes some remarks about how difficult theft is lately"); - if (!tele_restrict(mtmp)) - (void) rloc(mtmp, TRUE); - return 3; - } else if (mtmp->mcan) { - if (!Blind) - pline("%s tries to %s you, but you seem %s.", - Adjmonnam(mtmp, "plain"), - flags.female ? "charm" : "seduce", - flags.female ? "unaffected" : "uninterested"); - if (rn2(3)) { - if (!tele_restrict(mtmp)) - (void) rloc(mtmp, TRUE); - return 3; - } - break; - } - buf[0] = '\0'; - switch (steal(mtmp, buf)) { - case -1: - return 2; - case 0: - break; - default: - if (!is_animal(mtmp->data) && !tele_restrict(mtmp)) - (void) rloc(mtmp, TRUE); - if (is_animal(mtmp->data) && *buf) { - if (canseemon(mtmp)) - pline("%s tries to %s away with %s.", Monnam(mtmp), - locomotion(mtmp->data, "run"), buf); - } - monflee(mtmp, 0, FALSE, FALSE); - return 3; - } - break; - - case AD_SAMU: - hitmsg(mtmp, mattk); - /* when the Wizard or quest nemesis hits, there's a 1/20 chance - to steal a quest artifact (any, not just the one for the hero's - own role) or the Amulet or one of the invocation tools */ - if (!rn2(20)) - stealamulet(mtmp); - break; - - case AD_TLPT: - hitmsg(mtmp, mattk); - if (uncancelled) { - if (flags.verbose) - Your("position suddenly seems %suncertain!", - (Teleport_control && !Stunned && !unconscious()) ? "" - : "very "); - tele(); - /* As of 3.6.2: make sure damage isn't fatal; previously, it - was possible to be teleported and then drop dead at - the destination when QM's 1d4 damage gets applied below; - even though that wasn't "wrong", it seemed strange, - particularly if the teleportation had been controlled - [applying the damage first and not teleporting if fatal - is another alternative but it has its own complications] */ - if ((Half_physical_damage ? (dmg - 1) / 2 : dmg) - >= (tmphp = (Upolyd ? u.mh : u.uhp))) { - dmg = tmphp - 1; - if (Half_physical_damage) - dmg *= 2; /* doesn't actually increase damage; we only - * get here if half the original damage would - * would have been fatal, so double reduced - * damage will be less than original damage */ - if (dmg < 1) { /* implies (tmphp <= 1) */ - dmg = 1; - /* this might increase current HP beyond maximum HP but - it will be immediately reduced below, so that should - be indistinguishable from zero damage; we don't drop - damage all the way to zero because that inhibits any - passive counterattack if poly'd hero has one */ - if (Upolyd && u.mh == 1) - ++u.mh; - else if (!Upolyd && u.uhp == 1) - ++u.uhp; - /* [don't set context.botl here] */ - } - } - } - break; - case AD_RUST: - hitmsg(mtmp, mattk); - if (mtmp->mcan) - break; - if (u.umonnum == PM_IRON_GOLEM) { - You("rust!"); - /* KMH -- this is okay with unchanging */ - rehumanize(); - break; - } - erode_armor(&g.youmonst, ERODE_RUST); - break; - case AD_CORR: - hitmsg(mtmp, mattk); - if (mtmp->mcan) - break; - erode_armor(&g.youmonst, ERODE_CORRODE); - break; - case AD_DCAY: - hitmsg(mtmp, mattk); - if (mtmp->mcan) - break; - if (u.umonnum == PM_WOOD_GOLEM || u.umonnum == PM_LEATHER_GOLEM) { - You("rot!"); - /* KMH -- this is okay with unchanging */ - rehumanize(); - break; - } - erode_armor(&g.youmonst, ERODE_ROT); - break; - case AD_HEAL: - /* a cancelled nurse is just an ordinary monster, - * nurses don't heal those that cause petrification */ - if (mtmp->mcan || (Upolyd && touch_petrifies(g.youmonst.data))) { - hitmsg(mtmp, mattk); - break; - } - /* weapon check should match the one in sounds.c for MS_NURSE */ - if (!(uwep && (uwep->oclass == WEAPON_CLASS || is_weptool(uwep))) - && !uarmu && !uarm && !uarmc - && !uarms && !uarmg && !uarmf && !uarmh) { - boolean goaway = FALSE; - - pline("%s hits! (I hope you don't mind.)", Monnam(mtmp)); - if (Upolyd) { - u.mh += rnd(7); - if (!rn2(7)) { - /* no upper limit necessary; effect is temporary */ - u.mhmax++; - if (!rn2(13)) - goaway = TRUE; - } - if (u.mh > u.mhmax) - u.mh = u.mhmax; - } else { - u.uhp += rnd(7); - if (!rn2(7)) { - /* hard upper limit via nurse care: 25 * ulevel */ - if (u.uhpmax < 5 * u.ulevel + d(2 * u.ulevel, 10)) - u.uhpmax++; - if (!rn2(13)) - goaway = TRUE; - } - if (u.uhp > u.uhpmax) - u.uhp = u.uhpmax; - } - if (!rn2(3)) - exercise(A_STR, TRUE); - if (!rn2(3)) - exercise(A_CON, TRUE); - if (Sick) - make_sick(0L, (char *) 0, FALSE, SICK_ALL); - g.context.botl = 1; - if (goaway) { - mongone(mtmp); - return 2; - } else if (!rn2(33)) { - if (!tele_restrict(mtmp)) - (void) rloc(mtmp, TRUE); - monflee(mtmp, d(3, 6), TRUE, FALSE); - return 3; - } - dmg = 0; - } else { - if (Role_if(PM_HEALER)) { - if (!Deaf && !(g.moves % 5)) - verbalize("Doc, I can't help you unless you cooperate."); - dmg = 0; - } else - hitmsg(mtmp, mattk); - } - break; - case AD_CURS: - hitmsg(mtmp, mattk); - if (!night() && mdat == &mons[PM_GREMLIN]) - break; - if (!mtmp->mcan && !rn2(10)) { - if (!Deaf) { - if (Blind) - You_hear("laughter."); - else - pline("%s chuckles.", Monnam(mtmp)); - } - if (u.umonnum == PM_CLAY_GOLEM) { - pline("Some writing vanishes from your head!"); - /* KMH -- this is okay with unchanging */ - rehumanize(); - break; - } - attrcurse(); - } - break; - case AD_STUN: - hitmsg(mtmp, mattk); - if (!mtmp->mcan && !rn2(4)) { - make_stunned((HStun & TIMEOUT) + (long) dmg, TRUE); - dmg /= 2; - } - break; - case AD_ACID: - hitmsg(mtmp, mattk); - if (!mtmp->mcan && !rn2(3)) - if (Acid_resistance) { - pline("You're covered in %s, but it seems harmless.", - hliquid("acid")); - dmg = 0; - } else { - pline("You're covered in %s! It burns!", hliquid("acid")); - exercise(A_STR, FALSE); - } - else - dmg = 0; - break; - case AD_SLOW: - hitmsg(mtmp, mattk); - if (uncancelled && HFast && !defends(AD_SLOW, uwep) && !rn2(4)) - u_slow_down(); - break; - case AD_DREN: - hitmsg(mtmp, mattk); - if (uncancelled && !rn2(4)) /* 25% chance */ - drain_en(dmg); - dmg = 0; - break; - case AD_CONF: - hitmsg(mtmp, mattk); - if (!mtmp->mcan && !rn2(4) && !mtmp->mspec_used) { - mtmp->mspec_used = mtmp->mspec_used + (dmg + rn2(6)); - if (Confusion) - You("are getting even more confused."); - else - You("are getting confused."); - make_confused(HConfusion + dmg, FALSE); - } - dmg = 0; - break; - case AD_DETH: - pline("%s reaches out with its deadly touch.", Monnam(mtmp)); - if (is_undead(g.youmonst.data)) { - /* Still does normal damage */ - pline("Was that the touch of death?"); - break; - } - switch (rn2(20)) { - case 19: - case 18: - case 17: - if (!Antimagic) { - g.killer.format = KILLED_BY_AN; - Strcpy(g.killer.name, "touch of death"); - done(DIED); - dmg = 0; - break; - } - /*FALLTHRU*/ - default: /* case 16: ... case 5: */ - You_feel("your life force draining away..."); - permdmg = 1; /* actual damage done below */ - break; - case 4: - case 3: - case 2: - case 1: - case 0: - if (Antimagic) - shieldeff(u.ux, u.uy); - pline("Lucky for you, it didn't work!"); - dmg = 0; - break; - } - break; - case AD_PEST: - pline("%s reaches out, and you feel fever and chills.", Monnam(mtmp)); - (void) diseasemu(mdat); /* plus the normal damage */ - break; - case AD_FAMN: - pline("%s reaches out, and your body shrivels.", Monnam(mtmp)); - exercise(A_CON, FALSE); - if (!is_fainted()) - morehungry(rn1(40, 40)); - /* plus the normal damage */ - break; - case AD_SLIM: - hitmsg(mtmp, mattk); - if (!uncancelled) - break; - if (flaming(g.youmonst.data)) { - pline_The("slime burns away!"); - dmg = 0; - } else if (Unchanging || noncorporeal(g.youmonst.data) - || g.youmonst.data == &mons[PM_GREEN_SLIME]) { - You("are unaffected."); - dmg = 0; - } else if (!Slimed) { - You("don't feel very well."); - make_slimed(10L, (char *) 0); - delayed_killer(SLIMED, KILLED_BY_AN, mtmp->data->mname); - } else - pline("Yuck!"); - break; - case AD_ENCH: /* KMH -- remove enchantment (disenchanter) */ - hitmsg(mtmp, mattk); - /* uncancelled is sufficient enough; please - don't make this attack less frequent */ - if (uncancelled) { - struct obj *obj = some_armor(&g.youmonst); - - if (!obj) { - /* some rings are susceptible; - amulets and blindfolds aren't (at present) */ - switch (rn2(5)) { - case 0: - break; - case 1: - obj = uright; - break; - case 2: - obj = uleft; - break; - case 3: - obj = uamul; - break; - case 4: - obj = ublindf; - break; - } - } - if (drain_item(obj, FALSE)) { - pline("%s less effective.", Yobjnam2(obj, "seem")); - } - } - break; - case AD_POLY: - if (uncancelled && Maybe_Half_Phys(dmg) < (Upolyd ? u.mh : u.uhp)) - dmg = mon_poly(mtmp, &g.youmonst, dmg); - break; - default: - dmg = 0; - break; - } if ((Upolyd ? u.mh : u.uhp) < 1) { /* already dead? call rehumanize() or done_in_by() as appropriate */ mdamageu(mtmp, 1); - dmg = 0; + mhm.damage = 0; } /* Negative armor class reduces damage done instead of fully protecting * against hits. */ - if (dmg && u.uac < 0) { - dmg -= rnd(-u.uac); - if (dmg < 1) - dmg = 1; + if (mhm.damage && u.uac < 0) { + mhm.damage -= rnd(-u.uac); + if (mhm.damage < 1) + mhm.damage = 1; } - if (dmg) { + if (mhm.damage) { if (Half_physical_damage /* Mitre of Holiness */ - || (Role_if(PM_PRIEST) && uarmh && is_quest_artifact(uarmh) + || (Role_if(PM_CLERIC) && uarmh && is_quest_artifact(uarmh) && (is_undead(mtmp->data) || is_demon(mtmp->data) || is_vampshifter(mtmp)))) - dmg = (dmg + 1) / 2; + mhm.damage = (mhm.damage + 1) / 2; - if (permdmg) { /* Death's life force drain */ + if (mhm.permdmg) { /* Death's life force drain */ int lowerlimit, *hpmax_p; /* * Apply some of the damage to permanent hit points: @@ -1772,13 +1050,13 @@ register struct attack *mattk; * otherwise 0..50% * Never reduces hpmax below 1 hit point per level. */ - permdmg = rn2(dmg / 2 + 1); + mhm.permdmg = rn2(mhm.damage / 2 + 1); if (Upolyd || u.uhpmax > 25 * u.ulevel) - permdmg = dmg; + mhm.permdmg = mhm.damage; else if (u.uhpmax > 10 * u.ulevel) - permdmg += dmg / 2; + mhm.permdmg += mhm.damage / 2; else if (u.uhpmax > 5 * u.ulevel) - permdmg += dmg / 4; + mhm.permdmg += mhm.damage / 4; if (Upolyd) { hpmax_p = &u.mhmax; @@ -1788,8 +1066,8 @@ register struct attack *mattk; hpmax_p = &u.uhpmax; lowerlimit = u.ulevel; } - if (*hpmax_p - permdmg > lowerlimit) - *hpmax_p -= permdmg; + if (*hpmax_p - mhm.permdmg > lowerlimit) + *hpmax_p -= mhm.permdmg; else if (*hpmax_p > lowerlimit) *hpmax_p = lowerlimit; /* else unlikely... @@ -1797,13 +1075,13 @@ register struct attack *mattk; g.context.botl = 1; } - mdamageu(mtmp, dmg); + mdamageu(mtmp, mhm.damage); } - if (dmg) + if (mhm.damage) res = passiveum(olduasmon, mtmp, mattk); else - res = 1; + res = MM_HIT; stop_occupation(); return res; } @@ -1843,9 +1121,9 @@ struct attack *mattk; int omx = mtmp->mx, omy = mtmp->my; if (!engulf_target(mtmp, &g.youmonst)) - return 0; + return MM_MISS; if ((t && is_pit(t->ttyp)) && sobj_at(BOULDER, u.ux, u.uy)) - return 0; + return MM_MISS; if (Punished) unplacebc(); /* ball&chain go away */ @@ -1896,7 +1174,7 @@ struct attack *mattk; if (Punished) placebc(); set_ustuck((struct monst *) 0); - return (!DEADMONSTER(mtmp)) ? 0 : 2; + return (!DEADMONSTER(mtmp)) ? MM_MISS : MM_AGR_DIED; } display_nhwindow(WIN_MESSAGE, FALSE); @@ -1927,7 +1205,7 @@ struct attack *mattk; } if (mtmp != u.ustuck) - return 0; + return MM_MISS; if (Punished) { /* ball&chain are in limbo while swallowed; update their internal location to be at swallower's spot */ @@ -2082,7 +1360,7 @@ struct attack *mattk; pline("Obviously %s doesn't like your taste.", mon_nam(mtmp)); expels(mtmp, mtmp->data, FALSE); } - return 1; + return MM_HIT; } /* monster explodes in your face */ @@ -2095,7 +1373,7 @@ boolean ufound; boolean physical_damage = TRUE, kill_agr = TRUE; if (mtmp->mcan) - return 0; + return MM_MISS; if (!ufound) { pline("%s explodes at a spot in %s!", @@ -2187,7 +1465,7 @@ boolean ufound; if (kill_agr) mondead(mtmp); wake_nearto(mtmp->mx, mtmp->my, 7 * 7); - return (!DEADMONSTER(mtmp)) ? 0 : 2; + return (!DEADMONSTER(mtmp)) ? MM_MISS : MM_AGR_DIED; } /* monster gazes at you */ @@ -2255,7 +1533,7 @@ struct attack *mattk; if (!DEADMONSTER(mtmp)) break; - return 2; + return MM_AGR_DIED; } if (canseemon(mtmp) && couldsee(mtmp->mx, mtmp->my) && !Stone_resistance) { @@ -2265,7 +1543,7 @@ struct attack *mattk; break; You("turn to stone..."); g.killer.format = KILLED_BY; - Strcpy(g.killer.name, mtmp->data->mname); + Strcpy(g.killer.name, pmname(mtmp->data, Mgender(mtmp))); done(STONING); } break; @@ -2356,6 +1634,8 @@ struct attack *mattk; destroy_item(POTION_CLASS, AD_FIRE); if (lev > rn2(25)) destroy_item(SPBOOK_CLASS, AD_FIRE); + if (lev > rn2(20)) + ignite_items(g.invent); if (dmg) mdamageu(mtmp, dmg); } @@ -2403,7 +1683,7 @@ struct attack *mattk; : (!rn2(2) ? "a bit " : "somewhat "), reactions[react]); } - return 0; + return MM_MISS; } /* mtmp hits you for n points damage */ @@ -2471,8 +1751,7 @@ struct attack *mattk; /* non-Null: current attack; Null: general capability */ for seduction, both pass the could_seduce() test; incubi/succubi have three attacks, their claw attacks for damage don't pass the test */ - if ((pagr->mlet != S_NYMPH - && pagr != &mons[PM_INCUBUS] && pagr != &mons[PM_SUCCUBUS]) + if ((pagr->mlet != S_NYMPH && pagr != &mons[PM_AMOROUS_DEMON]) || (adtyp != AD_SEDU && adtyp != AD_SSEX && adtyp != AD_SITM)) return 0; @@ -2485,7 +1764,8 @@ doseduce(mon) struct monst *mon; { struct obj *ring, *nring; - boolean fem = (mon->data == &mons[PM_SUCCUBUS]); /* otherwise incubus */ + boolean fem = (mon->data == &mons[PM_AMOROUS_DEMON] + && Mgender(mon) == FEMALE); /* otherwise incubus */ boolean seewho, naked; /* True iff no armor */ int attr_tot, tried_gloves = 0; char qbuf[QBUFSZ], Who[QBUFSZ]; @@ -2859,7 +2139,7 @@ struct attack *mattk; */ for (i = 0; !oldu_mattk; i++) { if (i >= NATTK) - return 1; + return MM_HIT; if (olduasmon->mattk[i].aatyp == AT_NONE || olduasmon->mattk[i].aatyp == AT_BOOM) oldu_mattk = &olduasmon->mattk[i]; @@ -2912,10 +2192,10 @@ struct attack *mattk; g.stoned = 1; xkilled(mtmp, XKILL_NOMSG); if (!DEADMONSTER(mtmp)) - return 1; - return 2; + return MM_HIT; + return MM_AGR_DIED; } - return 1; + return MM_HIT; } case AD_ENCH: /* KMH -- remove enchantment (disenchanter) */ if (mon_currwep) { @@ -2924,12 +2204,12 @@ struct attack *mattk; (void) drain_item(mon_currwep, TRUE); /* No message */ } - return 1; + return MM_HIT; default: break; } if (!Upolyd) - return 1; + return MM_HIT; /* These affect the enemy only if you are still a monster */ if (rn2(3)) @@ -2952,22 +2232,23 @@ struct attack *mattk; && (perceives(mtmp->data) || !Invis)) { if (Blind) pline("As a blind %s, you cannot defend yourself.", - g.youmonst.data->mname); + pmname(g.youmonst.data, + flags.female ? FEMALE : MALE)); else { if (mon_reflects(mtmp, "Your gaze is reflected by %s %s.")) return 1; pline("%s is frozen by your gaze!", Monnam(mtmp)); paralyze_monst(mtmp, tmp); - return 3; + return MM_AGR_DONE; } } } else { /* gelatinous cube */ pline("%s is frozen by you.", Monnam(mtmp)); paralyze_monst(mtmp, tmp); - return 3; + return MM_AGR_DONE; } - return 1; + return MM_HIT; case AD_COLD: /* Brown mold or blue jelly */ if (resists_cold(mtmp)) { shieldeff(mtmp->mx, mtmp->my); @@ -3023,10 +2304,10 @@ struct attack *mattk; pline("%s dies!", Monnam(mtmp)); xkilled(mtmp, XKILL_NOMSG); if (!DEADMONSTER(mtmp)) - return 1; - return 2; + return MM_HIT; + return MM_AGR_DIED; } - return 1; + return MM_HIT; } struct monst * diff --git a/src/minion.c b/src/minion.c index 03706027a..c6a7dec58 100644 --- a/src/minion.c +++ b/src/minion.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 minion.c $NHDT-Date: 1583688543 2020/03/08 17:29:03 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.53 $ */ +/* NetHack 3.7 minion.c $NHDT-Date: 1596498180 2020/08/03 23:43:00 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.55 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2008. */ /* NetHack may be freely redistributed. See license for details. */ @@ -196,7 +196,7 @@ boolean talk; EMIN(mon)->renegade = FALSE; } } else if (mnum != PM_SHOPKEEPER && mnum != PM_GUARD - && mnum != PM_ALIGNED_PRIEST && mnum != PM_HIGH_PRIEST) { + && mnum != PM_ALIGNED_CLERIC && mnum != PM_HIGH_CLERIC) { /* This was mons[mnum].pxlth == 0 but is this restriction appropriate or necessary now that the structures are separate? */ mon = makemon(&mons[mnum], u.ux, u.uy, MM_EMIN); diff --git a/src/mklev.c b/src/mklev.c index 007262ea0..51616aaf4 100644 --- a/src/mklev.c +++ b/src/mklev.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 mklev.c $NHDT-Date: 1587291592 2020/04/19 10:19:52 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.85 $ */ +/* NetHack 3.7 mklev.c $NHDT-Date: 1605305491 2020/11/13 22:11:31 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.96 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Alex Smith, 2017. */ /* NetHack may be freely redistributed. See license for details. */ @@ -19,6 +19,7 @@ static void FDECL(mkaltar, (struct mkroom *)); static void FDECL(mkgrave, (struct mkroom *)); static void NDECL(makevtele); void NDECL(clear_level_structures); +static void FDECL(fill_ordinary_room, (struct mkroom *)); static void NDECL(makelevel); static boolean FDECL(bydoor, (XCHAR_P, XCHAR_P)); static struct mkroom *FDECL(find_branch_room, (coord *)); @@ -34,6 +35,7 @@ static void FDECL(do_room_or_subroom, (struct mkroom *, int, int, int, int, BOOLEAN_P, SCHAR_P, BOOLEAN_P, BOOLEAN_P)); static void NDECL(makerooms); +static boolean FDECL(door_into_nonjoined, (XCHAR_P, XCHAR_P)); static void FDECL(finddpos, (coord *, XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P)); static void FDECL(mkinvpos, (XCHAR_P, XCHAR_P, int)); @@ -67,6 +69,33 @@ const genericptr vy; #endif /* LINT */ } +/* 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 = 0. + * 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. + */ +static boolean +door_into_nonjoined(x, y) +xchar x, y; +{ + xchar tx, ty, diridx; + + for (diridx = 0; diridx <= 6; diridx += 2) { + tx = x + xdir[diridx]; + ty = y + ydir[diridx]; + if (!isok(tx, ty) || IS_ROCK(levl[tx][ty].typ)) + continue; + + /* Is this connecting to a room that doesn't want joining? */ + if (levl[tx][ty].roomno >= ROOMOFFSET && + !g.rooms[levl[tx][ty].roomno - ROOMOFFSET].needjoining) { + return TRUE; + } + } + return FALSE; +} + static void finddpos(cc, xl, yl, xh, yh) coord *cc; @@ -76,12 +105,12 @@ xchar xl, yl, xh, yh; x = rn1(xh - xl + 1, xl); y = rn1(yh - yl + 1, yl); - if (okdoor(x, y)) + if (okdoor(x, y) && !door_into_nonjoined(x, y)) goto gotit; for (x = xl; x <= xh; x++) for (y = yl; y <= yh; y++) - if (okdoor(x, y)) + if (okdoor(x, y) && !door_into_nonjoined(x, y)) goto gotit; for (x = xl; x <= xh; x++) @@ -91,6 +120,8 @@ xchar xl, yl, xh, yh; /* cannot find something reasonable -- strange */ x = xl; y = yh; + impossible("finddpos: couldn't find door pos within (%d,%d,%d,%d)", + xl, yl, xh, yh); gotit: cc->x = x; cc->y = y; @@ -718,10 +749,7 @@ clear_level_structures() g.doorindex = 0; init_rect(); init_vault(); - xdnstair = ydnstair = xupstair = yupstair = 0; - g.sstairs.sx = g.sstairs.sy = 0; - xdnladder = ydnladder = xupladder = yupladder = 0; - g.dnstairs_room = g.upstairs_room = g.sstairs_room = (struct mkroom *) 0; + stairway_free_all(); g.made_branch = FALSE; clear_regions(); g.xstart = 1; @@ -734,103 +762,198 @@ clear_level_structures() } } +/* Fill a "random" room (i.e. a typical non-special room in the Dungeons of + * Doom) with random monsters, objects, and dungeon features. + */ +static void +fill_ordinary_room(croom) +struct mkroom *croom; +{ + int trycnt = 0; + coord pos; + struct monst *tmonst; /* always put a web with a spider */ + int x, y; + + if (croom->rtype != OROOM && croom->rtype != THEMEROOM) + return; + + /* If there are subrooms, fill them now - we don't want an outer room + * that's specified to be unfilled to block an inner subroom that's + * specified to be filled. */ + for (x = 0; x < croom->nsubrooms; ++x) { + fill_ordinary_room(croom->sbrooms[x]); + } + + if (croom->needfill != FILL_NORMAL) + return; + + /* put a sleeping monster inside */ + /* Note: monster may be on the stairs. This cannot be + avoided: maybe the player fell through a trap door + while a monster was on the stairs. Conclusion: + we have to check for monsters on the stairs anyway. */ + + if ((u.uhave.amulet || !rn2(3)) && somexyspace(croom, &pos)) { + tmonst = makemon((struct permonst *) 0, pos.x, pos.y, MM_NOGRP); + if (tmonst && tmonst->data == &mons[PM_GIANT_SPIDER] + && !occupied(pos.x, pos.y)) + (void) maketrap(pos.x, pos.y, WEB); + } + /* put traps and mimics inside */ + x = 8 - (level_difficulty() / 6); + if (x <= 1) + x = 2; + while (!rn2(x) && (++trycnt < 1000)) + mktrap(0, 0, croom, (coord *) 0); + if (!rn2(3) && somexyspace(croom, &pos)) + (void) mkgold(0L, pos.x, pos.y); + if (Is_rogue_level(&u.uz)) + goto skip_nonrogue; + if (!rn2(10)) + mkfount(0, croom); + if (!rn2(60)) + mksink(croom); + if (!rn2(60)) + mkaltar(croom); + x = 80 - (depth(&u.uz) * 2); + if (x < 2) + x = 2; + if (!rn2(x)) + mkgrave(croom); + + /* put statues inside */ + if (!rn2(20) && somexyspace(croom, &pos)) + (void) mkcorpstat(STATUE, (struct monst *) 0, + (struct permonst *) 0, pos.x, + pos.y, CORPSTAT_INIT); + /* put box/chest inside; + * 40% chance for at least 1 box, regardless of number + * of rooms; about 5 - 7.5% for 2 boxes, least likely + * when few rooms; chance for 3 or more is negligible. + */ + if (!rn2(g.nroom * 5 / 2) && somexyspace(croom, &pos)) + (void) mksobj_at((rn2(3)) ? LARGE_BOX : CHEST, + pos.x, pos.y, TRUE, FALSE); + + /* maybe make some graffiti */ + if (!rn2(27 + 3 * abs(depth(&u.uz)))) { + char buf[BUFSZ]; + const char *mesg = random_engraving(buf); + + if (mesg) { + do { + somexyspace(croom, &pos); + x = pos.x; + y = pos.y; + } while (levl[x][y].typ != ROOM && !rn2(40)); + if (!(IS_POOL(levl[x][y].typ) + || IS_FURNITURE(levl[x][y].typ))) + make_engr_at(x, y, mesg, 0L, MARK); + } + } + + skip_nonrogue: + if (!rn2(3) && somexyspace(croom, &pos)) { + (void) mkobj_at(0, pos.x, pos.y, TRUE); + trycnt = 0; + while (!rn2(5)) { + if (++trycnt > 100) { + impossible("trycnt overflow4"); + break; + } + (void) mkobj_at(0, pos.x, pos.y, TRUE); + } + } +} + static void makelevel() { register struct mkroom *croom; - register int tryct; - register int x, y; - struct monst *tmonst; /* always put a web with a spider */ branch *branchp; int room_threshold; + register s_level *slev = Is_special(&u.uz); + int i; if (wiz1_level.dlevel == 0) init_dungeons(); oinit(); /* assign level dependent obj probabilities */ clear_level_structures(); - { - register s_level *slev = Is_special(&u.uz); + /* check for special levels */ + if (slev && !Is_rogue_level(&u.uz)) { + makemaz(slev->proto); + } else if (g.dungeons[u.uz.dnum].proto[0]) { + makemaz(""); + } else if (g.dungeons[u.uz.dnum].fill_lvl[0]) { + makemaz(g.dungeons[u.uz.dnum].fill_lvl); + } else if (In_quest(&u.uz)) { + char fillname[9]; + s_level *loc_lev; - /* check for special levels */ - if (slev && !Is_rogue_level(&u.uz)) { - makemaz(slev->proto); - return; - } else if (g.dungeons[u.uz.dnum].proto[0]) { - makemaz(""); - return; - } else if (g.dungeons[u.uz.dnum].fill_lvl[0]) { - makemaz(g.dungeons[u.uz.dnum].fill_lvl); - return; - } else if (In_quest(&u.uz)) { - char fillname[9]; - s_level *loc_lev; + Sprintf(fillname, "%s-loca", g.urole.filecode); + loc_lev = find_level(fillname); - Sprintf(fillname, "%s-loca", g.urole.filecode); - loc_lev = find_level(fillname); - - Sprintf(fillname, "%s-fil", g.urole.filecode); - Strcat(fillname, - (u.uz.dlevel < loc_lev->dlevel.dlevel) ? "a" : "b"); - makemaz(fillname); - return; - } else if (In_hell(&u.uz) - || (rn2(5) && u.uz.dnum == medusa_level.dnum - && depth(&u.uz) > depth(&medusa_level))) { - makemaz(""); - return; - } - } - - /* otherwise, fall through - it's a "regular" level. */ - - if (Is_rogue_level(&u.uz)) { - makeroguerooms(); - makerogueghost(); - } else - makerooms(); - sort_rooms(); - - generate_stairs(); /* up and down stairs */ - - branchp = Is_branchlev(&u.uz); /* possible dungeon branch */ - room_threshold = branchp ? 4 : 3; /* minimum number of rooms needed - to allow a random special room */ - if (Is_rogue_level(&u.uz)) - goto skip0; - makecorridors(); - make_niches(); - - /* make a secret treasure vault, not connected to the rest */ - if (do_vault()) { - xchar w, h; - - debugpline0("trying to make a vault..."); - w = 1; - h = 1; - if (check_room(&g.vault_x, &w, &g.vault_y, &h, TRUE)) { - fill_vault: - add_room(g.vault_x, g.vault_y, g.vault_x + w, g.vault_y + h, - TRUE, VAULT, FALSE); - g.level.flags.has_vault = 1; - ++room_threshold; - fill_room(&g.rooms[g.nroom - 1], FALSE); - mk_knox_portal(g.vault_x + w, g.vault_y + h); - if (!g.level.flags.noteleport && !rn2(3)) - makevtele(); - } else if (rnd_rect() && create_vault()) { - g.vault_x = g.rooms[g.nroom].lx; - g.vault_y = g.rooms[g.nroom].ly; - if (check_room(&g.vault_x, &w, &g.vault_y, &h, TRUE)) - goto fill_vault; - else - g.rooms[g.nroom].hx = -1; - } - } - - { + Sprintf(fillname, "%s-fil", g.urole.filecode); + Strcat(fillname, + (u.uz.dlevel < loc_lev->dlevel.dlevel) ? "a" : "b"); + makemaz(fillname); + } else if (In_hell(&u.uz) + || (rn2(5) && u.uz.dnum == medusa_level.dnum + && depth(&u.uz) > depth(&medusa_level))) { + makemaz(""); + } else { + /* otherwise, fall through - it's a "regular" level. */ register int u_depth = depth(&u.uz); + if (Is_rogue_level(&u.uz)) { + makeroguerooms(); + makerogueghost(); + } else + makerooms(); + sort_rooms(); + + generate_stairs(); /* up and down stairs */ + + branchp = Is_branchlev(&u.uz); /* possible dungeon branch */ + room_threshold = branchp ? 4 : 3; /* minimum number of rooms needed + to allow a random special room */ + if (Is_rogue_level(&u.uz)) + goto skip0; + makecorridors(); + make_niches(); + + /* make a secret treasure vault, not connected to the rest */ + if (do_vault()) { + xchar w, h; + + debugpline0("trying to make a vault..."); + w = 1; + h = 1; + if (check_room(&g.vault_x, &w, &g.vault_y, &h, TRUE)) { + fill_vault: + add_room(g.vault_x, g.vault_y, g.vault_x + w, g.vault_y + h, + TRUE, VAULT, FALSE); + g.level.flags.has_vault = 1; + ++room_threshold; + g.rooms[g.nroom - 1].needfill = FILL_NORMAL; + fill_special_room(&g.rooms[g.nroom - 1]); + mk_knox_portal(g.vault_x + w, g.vault_y + h); + if (!g.level.flags.noteleport && !rn2(3)) + makevtele(); + } else if (rnd_rect() && create_vault()) { + g.vault_x = g.rooms[g.nroom].lx; + g.vault_y = g.rooms[g.nroom].ly; + if (check_room(&g.vault_x, &w, &g.vault_y, &h, TRUE)) + goto fill_vault; + else + g.rooms[g.nroom].hx = -1; + } + } + + /* make up to 1 special room, with type dependent on depth; + * note that mkroom doesn't guarantee a room gets created, and that this + * step only sets the room's rtype - it doesn't fill it yet. */ if (wizard && nh_getenv("SHOPTYPE")) mkroom(SHOPBASE); else if (u_depth > 1 && u_depth < depth(&medusa_level) @@ -860,99 +983,21 @@ makelevel() else if (u_depth > 16 && !rn2(8) && !(g.mvitals[PM_COCKATRICE].mvflags & G_GONE)) mkroom(COCKNEST); - } skip0: - /* Place multi-dungeon branch. */ - place_branch(branchp, 0, 0); + /* Place multi-dungeon branch. */ + place_branch(branchp, 0, 0); - /* for each room: put things inside */ - for (croom = g.rooms; croom->hx > 0; croom++) { - int trycnt = 0; - coord pos; - if (croom->rtype != OROOM && croom->rtype != THEMEROOM) - continue; - if (!croom->needfill) - continue; - - /* put a sleeping monster inside */ - /* Note: monster may be on the stairs. This cannot be - avoided: maybe the player fell through a trap door - while a monster was on the stairs. Conclusion: - we have to check for monsters on the stairs anyway. */ - - if ((u.uhave.amulet || !rn2(3)) && somexyspace(croom, &pos)) { - tmonst = makemon((struct permonst *) 0, pos.x, pos.y, MM_NOGRP); - if (tmonst && tmonst->data == &mons[PM_GIANT_SPIDER] - && !occupied(pos.x, pos.y)) - (void) maketrap(pos.x, pos.y, WEB); - } - /* put traps and mimics inside */ - x = 8 - (level_difficulty() / 6); - if (x <= 1) - x = 2; - while (!rn2(x) && (++trycnt < 1000)) - mktrap(0, 0, croom, (coord *) 0); - if (!rn2(3) && somexyspace(croom, &pos)) - (void) mkgold(0L, pos.x, pos.y); - if (Is_rogue_level(&u.uz)) - goto skip_nonrogue; - if (!rn2(10)) - mkfount(0, croom); - if (!rn2(60)) - mksink(croom); - if (!rn2(60)) - mkaltar(croom); - x = 80 - (depth(&u.uz) * 2); - if (x < 2) - x = 2; - if (!rn2(x)) - mkgrave(croom); - - /* put statues inside */ - if (!rn2(20) && somexyspace(croom, &pos)) - (void) mkcorpstat(STATUE, (struct monst *) 0, - (struct permonst *) 0, pos.x, - pos.y, CORPSTAT_INIT); - /* put box/chest inside; - * 40% chance for at least 1 box, regardless of number - * of rooms; about 5 - 7.5% for 2 boxes, least likely - * when few rooms; chance for 3 or more is negligible. - */ - if (!rn2(g.nroom * 5 / 2) && somexyspace(croom, &pos)) - (void) mksobj_at((rn2(3)) ? LARGE_BOX : CHEST, - pos.x, pos.y, TRUE, FALSE); - - /* maybe make some graffiti */ - if (!rn2(27 + 3 * abs(depth(&u.uz)))) { - char buf[BUFSZ]; - const char *mesg = random_engraving(buf); - - if (mesg) { - do { - somexyspace(croom, &pos); - x = pos.x; - y = pos.y; - } while (levl[x][y].typ != ROOM && !rn2(40)); - if (!(IS_POOL(levl[x][y].typ) - || IS_FURNITURE(levl[x][y].typ))) - make_engr_at(x, y, mesg, 0L, MARK); - } - } - - skip_nonrogue: - if (!rn2(3) && somexyspace(croom, &pos)) { - (void) mkobj_at(0, pos.x, pos.y, TRUE); - tryct = 0; - while (!rn2(5)) { - if (++tryct > 100) { - impossible("tryct overflow4"); - break; - } - (void) mkobj_at(0, pos.x, pos.y, TRUE); - } + /* for each room: put things inside */ + for (croom = g.rooms; croom->hx > 0; croom++) { + fill_ordinary_room(croom); } } + /* Fill all special rooms now, regardless of whether this is a special + * level, proto level, or ordinary level. */ + for (i = 0; i < g.nroom; ++i) { + fill_special_room(&g.rooms[i]); + } } /* @@ -1094,13 +1139,6 @@ mklev() for (ridx = 0; ridx < SIZE(g.rooms); ridx++) g.rooms[ridx].orig_rtype = g.rooms[ridx].rtype; - /* something like this usually belongs in clear_level_structures() - but these aren't saved and restored so might not retain their - values for the life of the current level; reset them to default - now so that they never do and no one will be tempted to introduce - a new use of them for anything on this level */ - g.dnstairs_room = g.upstairs_room = g.sstairs_room = (struct mkroom *) 0; - reseed_random(rn2); reseed_random(rn2_on_display_rng); } @@ -1244,14 +1282,11 @@ xchar x, y; /* location */ if (br->type == BR_PORTAL) { mkportal(x, y, dest->dnum, dest->dlevel); } else if (make_stairs) { - g.sstairs.sx = x; - g.sstairs.sy = y; - g.sstairs.up = - (char) on_level(&br->end1, &u.uz) ? br->end1_up : !br->end1_up; - assign_level(&g.sstairs.tolev, dest); - g.sstairs_room = br_room; + boolean goes_up = on_level(&br->end1, &u.uz) ? br->end1_up + : !br->end1_up; - levl[x][y].ladder = g.sstairs.up ? LA_UP : LA_DOWN; + stairway_add(x,y, goes_up, FALSE, dest); + levl[x][y].ladder = goes_up ? LA_UP : LA_DOWN; levl[x][y].typ = STAIRS; } /* @@ -1597,9 +1632,11 @@ coord *tm; void mkstairs(x, y, up, croom) xchar x, y; -char up; -struct mkroom *croom; +char up; /* [why 'char' when usage is boolean?] */ +struct mkroom *croom UNUSED; { + d_level dest; + if (!x) { impossible("mkstairs: bogus stair attempt at <%d,%d>", x, y); return; @@ -1614,15 +1651,9 @@ struct mkroom *croom; || (dunlev(&u.uz) == dunlevs_in_dungeon(&u.uz) && !up)) return; - if (up) { - xupstair = x; - yupstair = y; - g.upstairs_room = croom; - } else { - xdnstair = x; - ydnstair = y; - g.dnstairs_room = croom; - } + dest.dnum = u.uz.dnum; + dest.dlevel = u.uz.dlevel + (up ? -1 : 1); + stairway_add(x, y, up ? TRUE : FALSE, FALSE, &dest); levl[x][y].typ = STAIRS; levl[x][y].ladder = up ? LA_UP : LA_DOWN; @@ -1641,10 +1672,10 @@ struct mkroom *croom; int phase; { return (croom && (croom->needjoining || (phase < 0)) - && ((croom != g.dnstairs_room && croom != g.upstairs_room) + && ((!has_dnstairs(croom) && !has_upstairs(croom)) || phase < 1) && (croom->rtype == OROOM - || ((phase < 2) || croom->rtype == THEMEROOM))); + || ((phase < 2) && croom->rtype == THEMEROOM))); } /* find a good room to generate an up or down stairs in */ diff --git a/src/mkmap.c b/src/mkmap.c index d6fa6dc0d..8100394ca 100644 --- a/src/mkmap.c +++ b/src/mkmap.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 mkmap.c $NHDT-Date: 1432512767 2015/05/25 00:12:47 $ $NHDT-Branch: master $:$NHDT-Revision: 1.16 $ */ +/* NetHack 3.7 mkmap.c $NHDT-Date: 1596498181 2020/08/03 23:43:01 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.28 $ */ /* Copyright (c) J. C. Collet, M. Stephenson and D. Cohrs, 1992 */ /* NetHack may be freely redistributed. See license for details. */ @@ -14,7 +14,6 @@ static schar FDECL(get_map, (int, int, SCHAR_P)); static void FDECL(pass_one, (SCHAR_P, SCHAR_P)); static void FDECL(pass_two, (SCHAR_P, SCHAR_P)); static void FDECL(pass_three, (SCHAR_P, SCHAR_P)); -static void NDECL(wallify_map); static void FDECL(join_map, (SCHAR_P, SCHAR_P)); static void FDECL(finish_map, (SCHAR_P, SCHAR_P, BOOLEAN_P, BOOLEAN_P, BOOLEAN_P)); @@ -193,7 +192,10 @@ boolean anyroom; levl[ii][jj].edge = 1; if (lit) levl[ii][jj].lit = lit; - if ((int) levl[ii][jj].roomno != rmno) + + if (levl[ii][jj].roomno == NO_ROOM) + levl[ii][jj].roomno = rmno; + else if ((int) levl[ii][jj].roomno != rmno) levl[ii][jj].roomno = SHARED; } } @@ -244,29 +246,6 @@ boolean anyroom; g.max_ry = sy; } -/* - * If we have drawn a map without walls, this allows us to - * auto-magically wallify it. Taken from lev_main.c. - */ -static void -wallify_map() -{ - int x, y, xx, yy; - - for (x = 1; x < COLNO; x++) - for (y = 0; y < ROWNO; y++) - if (levl[x][y].typ == STONE) { - for (yy = y - 1; yy <= y + 1; yy++) - for (xx = x - 1; xx <= x + 1; xx++) - if (isok(xx, yy) && levl[xx][yy].typ == ROOM) { - if (yy != y) - levl[x][y].typ = HWALL; - else - levl[x][y].typ = VWALL; - } - } -} - static void join_map(bg_typ, fg_typ) schar bg_typ, fg_typ; @@ -348,7 +327,7 @@ boolean lit, walled, icedpools; int i, j; if (walled) - wallify_map(); + wallify_map(1, 0, COLNO-1, ROWNO-1); if (lit) { for (i = 1; i < COLNO; i++) diff --git a/src/mkmaze.c b/src/mkmaze.c index 014bdd3fd..c79068bf1 100644 --- a/src/mkmaze.c +++ b/src/mkmaze.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 mkmaze.c $NHDT-Date: 1577674536 2019/12/30 02:55:36 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.104 $ */ +/* NetHack 3.7 mkmaze.c $NHDT-Date: 1596498182 2020/08/03 23:43:02 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.114 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Pasi Kallinen, 2018. */ /* NetHack may be freely redistributed. See license for details. */ @@ -541,7 +541,7 @@ fixup_special() struct obj *otmp; int tryct; - croom = &g.rooms[0]; /* only one room on the medusa level */ + croom = &g.rooms[0]; /* the first room defined on the medusa level */ for (tryct = rnd(4); tryct; tryct--) { x = somex(croom); y = somey(croom); @@ -569,20 +569,11 @@ fixup_special() set_corpsenm(otmp, rndmonnum()); } } - } else if (Role_if(PM_PRIEST) && In_quest(&u.uz)) { + } else if (Role_if(PM_CLERIC) && In_quest(&u.uz)) { /* less chance for undead corpses (lured from lower morgues) */ g.level.flags.graveyard = 1; } else if (Is_stronghold(&u.uz)) { g.level.flags.graveyard = 1; - } else if (on_level(&u.uz, &orcus_level)) { - struct monst *mtmp, *mtmp2; - - /* it's a ghost town, get rid of shopkeepers */ - for (mtmp = fmon; mtmp; mtmp = mtmp2) { - mtmp2 = mtmp->nmon; - if (mtmp->isshk) - mongone(mtmp); - } } else if (on_level(&u.uz, &baalzebub_level)) { /* custom wallify the "beetle" potion of the level */ baalz_fixup(); @@ -751,7 +742,7 @@ stolen_booty(VOID_ARGS) if (DEADMONSTER(mtmp)) continue; - if (is_orc(mtmp->data) && !has_mname(mtmp) && rn2(10)) { + if (is_orc(mtmp->data) && !has_mgivenname(mtmp) && rn2(10)) { /* * We'll consider the orc captain from the level * description to be the captain of a rival orc horde @@ -1024,6 +1015,7 @@ const char *s; mazexy(&mm); mkstairs(mm.x, mm.y, 0, (struct mkroom *) 0); /* down */ } else { /* choose "vibrating square" location */ + stairway *stway; int trycnt = 0; #define x_maze_min 2 #define y_maze_min 2 @@ -1056,10 +1048,11 @@ const char *s; to be on a spot that's already in use (wall|trap) */ if (++trycnt > 1000) break; - } while (x == xupstair || y == yupstair /*(direct line)*/ - || abs(x - xupstair) == abs(y - yupstair) - || distmin(x, y, xupstair, yupstair) <= INVPOS_DISTANCE - || !SPACE_POS(levl[x][y].typ) || occupied(x, y)); + } while (((stway = stairway_find_dir(TRUE)) != 0) + && (x == stway->sx || y == stway->sy /*(direct line)*/ + || abs(x - stway->sx) == abs(y - stway->sy) + || distmin(x, y, stway->sx, stway->sy) <= INVPOS_DISTANCE + || !SPACE_POS(levl[x][y].typ) || occupied(x, y))); g.inv_pos.x = x; g.inv_pos.y = y; maketrap(g.inv_pos.x, g.inv_pos.y, VIBRATING_SQUARE); diff --git a/src/mkobj.c b/src/mkobj.c index b439461b4..85052e3fd 100644 --- a/src/mkobj.c +++ b/src/mkobj.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 mkobj.c $NHDT-Date: 1593306908 2020/06/28 01:15:08 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.181 $ */ +/* NetHack 3.7 mkobj.c $NHDT-Date: 1606343579 2020/11/25 22:32:59 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.191 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Derek S. Ray, 2015. */ /* NetHack may be freely redistributed. See license for details. */ @@ -67,16 +67,22 @@ static const struct icp hellprobs[] = { { 20, WEAPON_CLASS }, { 8, RING_CLASS }, { 4, AMULET_CLASS } }; +static const struct oextra zerooextra = DUMMY; + +static void +init_oextra(oex) +struct oextra *oex; +{ + *oex = zerooextra; +} + struct oextra * newoextra() { struct oextra *oextra; oextra = (struct oextra *) alloc(sizeof (struct oextra)); - oextra->oname = 0; - oextra->omonst = 0; - oextra->omailcmd = 0; - oextra->omid = 0; + init_oextra(oextra); return oextra; } @@ -204,7 +210,7 @@ boolean init, artif; otmp = mksobj(otyp, init, artif); add_to_migration(otmp); otmp->owornmask = (long) MIGR_TO_SPECIES; - otmp->corpsenm = mflags2; + otmp->migr_species = mflags2; return otmp; } @@ -627,9 +633,7 @@ register struct obj *otmp; *dummy = *otmp; dummy->oextra = (struct oextra *) 0; dummy->where = OBJ_FREE; - dummy->o_id = g.context.ident++; - if (!dummy->o_id) - dummy->o_id = g.context.ident++; /* ident overflowed */ + dummy->o_id = nextoid(otmp, dummy); dummy->timed = 0; copy_oextra(dummy, otmp); if (has_omid(dummy)) @@ -641,8 +645,8 @@ register struct obj *otmp; if (cost) alter_cost(dummy, -cost); /* no_charge is only valid for some locations */ - otmp->no_charge = - (otmp->where == OBJ_FLOOR || otmp->where == OBJ_CONTAINED) ? 1 : 0; + otmp->no_charge = (otmp->where == OBJ_FLOOR + || otmp->where == OBJ_CONTAINED) ? 1 : 0; otmp->unpaid = 0; return; } @@ -836,6 +840,12 @@ boolean artif; case KELP_FROND: otmp->quan = (long) rnd(2); break; + case CANDY_BAR: + /* set otmp->spe */ + assign_candy_wrapper(otmp); + break; + default: + break; } if (Is_pudding(otmp)) { otmp->quan = 1L; /* for emphasis; glob quantity is always 1 */ @@ -1136,6 +1146,23 @@ int id; } } +/* Return the number of turns after which a Rider corpse revives */ +long +rider_revival_time(body, retry) +struct obj *body; +boolean retry; +{ + long when; + long minturn = retry ? 3L : (body->corpsenm == PM_DEATH) ? 6L : 12L; + + /* Riders have a 1/3 chance per turn of reviving after 12, 6, or 3 turns. + Always revive by 67. */ + for (when = minturn; when < 67L; when++) + if (!rn2(3)) + break; + return when; +} + /* * Start a corpse decay or revive timer. * This takes the age of the corpse into consideration as of 3.4.0. @@ -1168,15 +1195,8 @@ struct obj *body; when += (long) (rnz(rot_adjust) - rot_adjust); if (is_rider(&mons[body->corpsenm])) { - /* - * Riders always revive. They have a 1/3 chance per turn - * of reviving after 12 turns. Always revive by 500. - */ action = REVIVE_MON; - for (when = 12L; when < 500L; when++) - if (!rn2(3)) - break; - + when = rider_revival_time(body, FALSE); } else if (mons[body->corpsenm].mlet == S_TROLL && !no_revival) { long age; @@ -1186,6 +1206,10 @@ struct obj *body; when = age; break; } + } else if (!no_revival && g.zombify + && zombie_form(&mons[body->corpsenm]) != NON_PM) { + action = ZOMBIFY_MON; + when = 5 + rn2(15); } (void) start_timer(when, TIMER_OBJECT, action, obj_to_any(body)); @@ -1516,6 +1540,10 @@ unsigned corpstatflags; if (!ptr) ptr = mtmp->data; + + /* don't give a revive timer to a cancelled troll's corpse */ + if (mtmp->mcan && !is_rider(ptr)) + otmp->norevive = 1; } /* when 'ptr' is non-null it comes from our caller or from 'mtmp'; @@ -1525,7 +1553,7 @@ unsigned corpstatflags; otmp->corpsenm = monsndx(ptr); otmp->owt = weight(otmp); - if (otmp->otyp == CORPSE && (special_corpse(old_corpsenm) + if (otmp->otyp == CORPSE && (g.zombify || special_corpse(old_corpsenm) || special_corpse(otmp->corpsenm))) { obj_stop_timers(otmp); start_corpse_timeout(otmp); @@ -1639,6 +1667,7 @@ boolean copyof; /* Never insert this returned pointer into mon chains! */ mnew = mtmp; } + mnew->data = &mons[mnew->mnum]; } return mnew; } @@ -2109,6 +2138,8 @@ struct obj *obj; obj->where = OBJ_MIGRATING; obj->nobj = g.migrating_objs; + obj->omigr_from_dnum = u.uz.dnum; + obj->omigr_from_dlevel = u.uz.dlevel; g.migrating_objs = obj; } diff --git a/src/mkroom.c b/src/mkroom.c index d41b74b39..496b4c426 100644 --- a/src/mkroom.c +++ b/src/mkroom.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 mkroom.c $NHDT-Date: 1446887530 2015/11/07 09:12:10 $ $NHDT-Branch: master $:$NHDT-Revision: 1.24 $ */ +/* NetHack 3.7 mkroom.c $NHDT-Date: 1596498184 2020/08/03 23:43:04 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.45 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2011. */ /* NetHack may be freely redistributed. See license for details. */ @@ -199,8 +199,10 @@ gottype: topologize(sroom); #endif - /* stock the room with a shopkeeper and artifacts */ - stock_room(i, sroom); + /* The shop used to be stocked here, but this no longer happens - all we do + * is set its rtype, and it gets stocked at the end of makelevel() along + * with other special rooms. */ + sroom->needfill = FILL_NORMAL; } /* pick an unused room, preferably with only one door */ @@ -237,7 +239,9 @@ int type; if ((sroom = pick_room(FALSE)) != 0) { sroom->rtype = type; - fill_zoo(sroom); + /* room does not get stocked at this time - it will get stocked at the + * end of makelevel() */ + sroom->needfill = FILL_NORMAL; } } @@ -246,10 +250,10 @@ mk_zoo_thronemon(x,y) int x,y; { int i = rnd(level_difficulty()); - int pm = (i > 9) ? PM_OGRE_KING - : (i > 5) ? PM_ELVENKING - : (i > 2) ? PM_DWARF_KING - : PM_GNOME_KING; + int pm = (i > 9) ? PM_OGRE_TYRANT + : (i > 5) ? PM_ELVEN_MONARCH + : (i > 2) ? PM_DWARF_RULER + : PM_GNOME_RULER; struct monst *mon = makemon(&mons[pm], x, y, NO_MM_FLAGS); if (mon) { @@ -271,6 +275,8 @@ struct mkroom *sroom; int rmno = (int) ((sroom - g.rooms) + ROOMOFFSET); coord mm; + /* Note: This doesn't check needfill; it assumes the caller has already done + * that. */ sh = sroom->fdoor; switch (type) { case COURT: @@ -616,10 +622,13 @@ boolean has_dnstairs(sroom) register struct mkroom *sroom; { - if (sroom == g.dnstairs_room) - return TRUE; - if (g.sstairs.sx && !g.sstairs.up) - return (boolean) (sroom == g.sstairs_room); + stairway *stway = g.stairs; + + while (stway) { + if (!stway->up && inside_room(sroom, stway->sx, stway->sy)) + return TRUE; + stway = stway->next; + } return FALSE; } @@ -627,10 +636,13 @@ boolean has_upstairs(sroom) register struct mkroom *sroom; { - if (sroom == g.upstairs_room) - return TRUE; - if (g.sstairs.sx && g.sstairs.up) - return (boolean) (sroom == g.sstairs_room); + stairway *stway = g.stairs; + + while (stway) { + if (stway->up && inside_room(sroom, stway->sx, stway->sy)) + return TRUE; + stway = stway->next; + } return FALSE; } diff --git a/src/mon.c b/src/mon.c index 0096f00dd..dd2ea4e3f 100644 --- a/src/mon.c +++ b/src/mon.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 mon.c $NHDT-Date: 1593306909 2020/06/28 01:15:09 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.338 $ */ +/* NetHack 3.7 mon.c $NHDT-Date: 1609281168 2020/12/29 22:32:48 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.364 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Derek S. Ray, 2015. */ /* NetHack may be freely redistributed. See license for details. */ @@ -10,6 +10,7 @@ static void FDECL(sanity_check_single_mon, (struct monst *, BOOLEAN_P, const char *)); static boolean FDECL(restrap, (struct monst *)); +static long FDECL(mm_2way_aggression, (struct monst *, struct monst *)); static long FDECL(mm_aggression, (struct monst *, struct monst *)); static long FDECL(mm_displacement, (struct monst *, struct monst *)); static int NDECL(pick_animal); @@ -45,38 +46,55 @@ struct monst *mtmp; boolean chk_geno; const char *msg; { - if (mtmp->data < &mons[LOW_PM] || mtmp->data >= &mons[NUMMONS]) { - impossible("illegal mon data %s; mnum=%d (%s)", - fmt_ptr((genericptr_t) mtmp->data), mtmp->mnum, msg); + struct permonst *mptr = mtmp->data; + int mx = mtmp->mx, my = mtmp->my; + + if (!mptr || mptr < &mons[LOW_PM] || mptr >= &mons[NUMMONS]) { + /* most sanity checks issue warnings if they detect a problem, + but this would be too extreme to keep going */ + panic("illegal mon data %s; mnum=%d (%s)", + fmt_ptr((genericptr_t) mptr), mtmp->mnum, msg); } else { - int mndx = monsndx(mtmp->data); + int mndx = monsndx(mptr); if (mtmp->mnum != mndx) { impossible("monster mnum=%d, monsndx=%d (%s)", mtmp->mnum, mndx, msg); mtmp->mnum = mndx; } +#if 0 /* + * Gremlims don't obey the (mhpmax >= m_lev) rule so disable + * this check, at least for the time being. We could skip it + * when the cloned flag is set, but the original gremlim would + * still be an issue. + */ /* check before DEADMONSTER() because dead monsters should still have sane mhpmax */ if (mtmp->mhpmax < 1 - || mtmp->mhpmax < (int) mtmp->m_lev + 1 + || mtmp->mhpmax < (int) mtmp->m_lev || mtmp->mhp > mtmp->mhpmax) impossible( "%s: level %d monster #%u [%s] has %d cur HP, %d max HP", msg, (int) mtmp->m_lev, mtmp->m_id, fmt_ptr((genericptr_t) mtmp), mtmp->mhp, mtmp->mhpmax); +#endif if (DEADMONSTER(mtmp)) { #if 0 /* bad if not fmons list or if not vault guard */ if (strcmp(msg, "fmon") || !mtmp->isgd) impossible("dead monster on %s; %s at <%d,%d>", - msg, mons[mndx].mname, mtmp->mx, mtmp->my); + msg, mons[mndx].pmnames[NEUTRAL], + mx, my); #endif return; } if (chk_geno && (g.mvitals[mndx].mvflags & G_GENOD) != 0) - impossible("genocided %s in play (%s)", mons[mndx].mname, msg); + impossible("genocided %s in play (%s)", + pmname(&mons[mndx], Mgender(mtmp)), msg); + if (mtmp->mtame && !mtmp->mpeaceful) + impossible("tame %s is not peaceful (%s)", + pmname(&mons[mndx], Mgender(mtmp)), msg); } if (mtmp->isshk && !has_eshk(mtmp)) impossible("shk without eshk (%s)", msg); @@ -89,6 +107,71 @@ const char *msg; /* guardian angel on astral level is tame but has emin rather than edog */ if (mtmp->mtame && !has_edog(mtmp) && !mtmp->isminion) impossible("pet without edog (%s)", msg); + + if (mtmp->mtrapped) { + if (mtmp->wormno) { + /* TODO: how to check worm in trap? */ + } else if (!t_at(mx, my)) + impossible("trapped without a trap (%s)", msg); + } + + /* monster is hiding? */ + if (mtmp->mundetected) { + struct trap *t; + + if (!isok(mx, my)) /* caller will have checked this but not fixed it */ + mx = my = 0; + if (mtmp == u.ustuck) + impossible("hiding monster stuck to you (%s)", msg); + if (m_at(mx, my) == mtmp && hides_under(mptr) && !OBJ_AT(mx, my)) + impossible("mon hiding under nonexistent obj (%s)", msg); + if (mptr->mlet == S_EEL + && !is_pool(mx, my) && !Is_waterlevel(&u.uz)) + impossible("eel hiding out of water (%s)", msg); + if (ceiling_hider(mptr) + /* normally !accessible would be overridable with passes_walls, + but not for hiding on the ceiling */ + && (!has_ceiling(&u.uz) || !accessible(mx, my))) + impossible("ceiling hider hiding %s (%s)", + !has_ceiling(&u.uz) ? "without ceiling" + : "in solid stone", + msg); + if (mtmp->mtrapped && (t = t_at(mx, my)) != 0 + && !(t->ttyp == PIT || t->ttyp == SPIKED_PIT)) + impossible("hiding while trapped in a non-pit (%s)", msg); + } else if (M_AP_TYPE(mtmp) != M_AP_NOTHING) { + boolean is_mimic = (mptr->mlet == S_MIMIC); + const char *what = (M_AP_TYPE(mtmp) == M_AP_FURNITURE) ? "furniture" + : (M_AP_TYPE(mtmp) == M_AP_MONSTER) ? "a monster" + : (M_AP_TYPE(mtmp) == M_AP_OBJECT) ? "an object" + : "something strange"; + + if (Protection_from_shape_changers) + impossible( + "mimic%s concealed as %s despite Prot-from-shape-changers %s", + is_mimic ? "" : "ker", what, msg); + /* the Wizard's clone after "double trouble" starts out mimicking + some other monster; pet's quickmimic effect can temporarily take + on furniture, object, or monster shape, but only until the pet + finishes eating a mimic corpse */ + if (!(is_mimic || mtmp->meating + || (mtmp->iswiz && M_AP_TYPE(mtmp) == M_AP_MONSTER))) + impossible("non-mimic (%s) posing as %s (%s)", + mptr->pmnames[NEUTRAL], what, msg); +#if 0 /* mimics who end up in strange locations do still hide while there */ + if (!(accessible(mx, my) || passes_walls(mptr))) { + char buf[BUFSZ]; + const char *typnam = levltyp_to_name(levl[mx][my].typ); + + if (!typnam) { + Sprintf(buf, "[%d]", levl[mx][my].typ); + typnam = buf; + } + impossible("mimic%s concealed in inaccessible location: %s (%s)", + is_mimic ? "" : "ker", typnam, msg); + } +#endif + } } void @@ -143,6 +226,8 @@ mon_sanity_check() for (mtmp = g.migrating_mons; mtmp; mtmp = mtmp->nmon) { sanity_check_single_mon(mtmp, FALSE, "migr"); } + + wormno_sanity_check(); /* test for bogus worm tail */ } /* Would monster be OK with poison gas? */ @@ -180,6 +265,59 @@ struct monst *mtmp; return M_POISONGAS_BAD; } +/* Return TRUE if this monster is capable of converting other monsters into + * zombies. */ +boolean +zombie_maker(pm) +struct permonst *pm; +{ + switch(pm->mlet) { + case S_ZOMBIE: + /* Z-class monsters that aren't actually zombies go here */ + if (pm == &mons[PM_GHOUL] || pm == &mons[PM_SKELETON]) + return FALSE; + return TRUE; + case S_LICH: + /* all liches will create zombies as well */ + return TRUE; + } + return FALSE; +} + +/* return the monster index of the zombie monster which this monster could be + * turned into, or NON_PM if it doesn't have a direct counterpart. Sort of the + * zombie-specific inverse of undead_to_corpse. + * If a zombie gets passed to this function, it should return NON_PM, not the + * same monster again. */ +int +zombie_form(pm) +struct permonst *pm; +{ + switch(pm->mlet) { + case S_KOBOLD: + return PM_KOBOLD_ZOMBIE; + case S_ORC: + return PM_ORC_ZOMBIE; + case S_GIANT: + if (pm == &mons[PM_ETTIN]) + return PM_ETTIN_ZOMBIE; + return PM_GIANT_ZOMBIE; + case S_HUMAN: + case S_KOP: + if (is_elf(pm)) + return PM_ELF_ZOMBIE; + return PM_HUMAN_ZOMBIE; + case S_HUMANOID: + if (is_dwarf(pm)) + return PM_DWARF_ZOMBIE; + else + break; + case S_GNOME: + return PM_GNOME_ZOMBIE; + } + return NON_PM; +} + /* convert the monster index of an undead to its living counterpart */ int undead_to_corpse(mndx) @@ -207,7 +345,7 @@ int mndx; mndx = PM_ELF; break; case PM_VAMPIRE: - case PM_VAMPIRE_LORD: + case PM_VAMPIRE_LEADER: #if 0 /* DEFERRED */ case PM_VAMPIRE_MAGE: #endif @@ -248,7 +386,7 @@ int mndx, mode; mndx = mode ? PM_BARBARIAN : PM_HUMAN; break; case PM_NEANDERTHAL: - mndx = mode ? PM_CAVEMAN : PM_HUMAN; + mndx = mode ? PM_CAVE_DWELLER : PM_HUMAN; break; case PM_ATTENDANT: mndx = mode ? PM_HEALER : PM_HUMAN; @@ -260,7 +398,7 @@ int mndx, mode; mndx = mode ? PM_MONK : PM_HUMAN; break; case PM_ACOLYTE: - mndx = mode ? PM_PRIEST : PM_HUMAN; + mndx = mode ? PM_CLERIC : PM_HUMAN; break; case PM_HUNTER: mndx = mode ? PM_RANGER : PM_HUMAN; @@ -384,7 +522,7 @@ unsigned corpseflags; (void) mksobj_at(WORM_TOOTH, x, y, TRUE, FALSE); goto default_1; case PM_VAMPIRE: - case PM_VAMPIRE_LORD: + case PM_VAMPIRE_LEADER: /* include mtmp in the mkcorpstat() call */ num = undead_to_corpse(mndx); corpstatflags |= CORPSTAT_INIT; @@ -416,19 +554,19 @@ unsigned corpseflags; num = d(2, 6); while (num--) obj = mksobj_at(IRON_CHAIN, x, y, TRUE, FALSE); - free_mname(mtmp); /* don't christen obj */ + free_mgivenname(mtmp); /* don't christen obj */ break; case PM_GLASS_GOLEM: num = d(2, 4); /* very low chance of creating all glass gems */ while (num--) obj = mksobj_at((LAST_GEM + rnd(9)), x, y, TRUE, FALSE); - free_mname(mtmp); + free_mgivenname(mtmp); break; case PM_CLAY_GOLEM: obj = mksobj_at(ROCK, x, y, FALSE, FALSE); obj->quan = (long) (rn2(20) + 50); obj->owt = weight(obj); - free_mname(mtmp); + free_mgivenname(mtmp); break; case PM_STONE_GOLEM: corpstatflags &= ~CORPSTAT_INIT; @@ -440,24 +578,24 @@ unsigned corpseflags; while (num--) { obj = mksobj_at(QUARTERSTAFF, x, y, TRUE, FALSE); } - free_mname(mtmp); + free_mgivenname(mtmp); break; case PM_LEATHER_GOLEM: num = d(2, 4); while (num--) obj = mksobj_at(LEATHER_ARMOR, x, y, TRUE, FALSE); - free_mname(mtmp); + free_mgivenname(mtmp); break; case PM_GOLD_GOLEM: /* Good luck gives more coins */ obj = mkgold((long) (200 - rnl(101)), x, y); - free_mname(mtmp); + free_mgivenname(mtmp); break; case PM_PAPER_GOLEM: num = rnd(4); while (num--) obj = mksobj_at(SCR_BLANK_PAPER, x, y, TRUE, FALSE); - free_mname(mtmp); + free_mgivenname(mtmp); break; /* expired puddings will congeal into a large blob; like dragons, relies on the order remaining consistent */ @@ -474,7 +612,7 @@ unsigned corpseflags; pudding_merge_message(obj, otmp); obj = obj_meld(&obj, &otmp); } - free_mname(mtmp); + free_mgivenname(mtmp); return obj; default: default_1: @@ -505,8 +643,8 @@ unsigned corpseflags; if (g.context.bypasses) bypass_obj(obj); - if (has_mname(mtmp)) - obj = oname(obj, MNAME(mtmp)); + if (has_mgivenname(mtmp)) + obj = oname(obj, MGIVENNAME(mtmp)); /* Avoid "It was hidden under a green mold corpse!" * during Blind combat. An unseen monster referred to as "it" @@ -1103,7 +1241,7 @@ struct monst *mtmp; distant_name(otmp, doname)); /* give this one even if !verbose */ if (otmp->oclass == SCROLL_CLASS - && !strcmpi(OBJ_DESCR(objects[otmp->otyp]), "YUM YUM")) + && objdescr_is(otmp, "YUM YUM")) pline("Yum%c", otmp->blessed ? '!' : '.'); } else { if (flags.verbose) @@ -1453,6 +1591,69 @@ struct obj *otmp; return iquan; } +/* return flags based on monster data, for mfndpos() */ +long +mon_allowflags(mtmp) +struct monst *mtmp; +{ + long allowflags = 0L; + boolean can_open = !(nohands(mtmp->data) || verysmall(mtmp->data)); + boolean can_unlock = ((can_open && monhaskey(mtmp, TRUE)) + || mtmp->iswiz || is_rider(mtmp->data)); + boolean doorbuster = is_giant(mtmp->data); + /* don't tunnel if on rogue level or if hostile and close enough + to prefer a weapon; same criteria as in m_move() */ + boolean can_tunnel = (tunnels(mtmp->data) && !Is_rogue_level(&u.uz)); + + if (can_tunnel && needspick(mtmp->data) + && ((!mtmp->mpeaceful || Conflict) + && dist2(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy) <= 8)) + can_tunnel = FALSE; + + if (mtmp->mtame) + allowflags |= ALLOW_M | ALLOW_TRAPS | ALLOW_SANCT | ALLOW_SSM; + else if (mtmp->mpeaceful) + allowflags |= ALLOW_SANCT | ALLOW_SSM; + else + allowflags |= ALLOW_U; + if (Conflict && !resist(mtmp, RING_CLASS, 0, 0)) + allowflags |= ALLOW_U; + if (mtmp->isshk) + allowflags |= ALLOW_SSM; + if (mtmp->ispriest) + allowflags |= ALLOW_SSM | ALLOW_SANCT; + if (passes_walls(mtmp->data)) + allowflags |= (ALLOW_ROCK | ALLOW_WALL); + if (throws_rocks(mtmp->data)) + allowflags |= ALLOW_ROCK; + if (can_tunnel) + allowflags |= ALLOW_DIG; + if (doorbuster) + allowflags |= BUSTDOOR; + if (can_open) + allowflags |= OPENDOOR; + if (can_unlock) + allowflags |= UNLOCKDOOR; + if (passes_bars(mtmp->data)) + allowflags |= ALLOW_BARS; +#if 0 /* can't do this here; leave it for mfndpos() */ + if (is_displacer(mtmp->data)) + allowflags |= ALLOW_MDISP; +#endif + if (is_minion(mtmp->data) || is_rider(mtmp->data)) + allowflags |= ALLOW_SANCT; + /* unicorn may not be able to avoid hero on a noteleport level */ + if (is_unicorn(mtmp->data) && !noteleport_level(mtmp)) + allowflags |= NOTONL; + if (is_human(mtmp->data) || mtmp->data == &mons[PM_MINOTAUR]) + allowflags |= ALLOW_SSM; + if ((is_undead(mtmp->data) && mtmp->data->mlet != S_GHOST) + || is_vampshifter(mtmp)) + allowflags |= NOGARLIC; + + return allowflags; +} + /* return number of acceptable neighbour positions */ int mfndpos(mon, poss, info, flag) @@ -1563,7 +1764,7 @@ long flag; || (m_at(x, ny) && m_at(nx, y) && worm_cross(x, y, nx, ny) && !m_at(nx, ny) && (nx != u.ux || ny != u.uy)))) continue; - if ((is_pool(nx, ny) == wantpool || poolok) + if ((poolok || is_pool(nx, ny) == wantpool) && (lavaok || !is_lava(nx, ny))) { int dispx, dispy; boolean monseeu = (mon->mcansee @@ -1615,6 +1816,7 @@ long flag; info[cnt] |= ALLOW_TM; } } else { + flag &= ~ALLOW_MDISP; /* depends upon defender */ mmflag = flag | mm_displacement(mon, mtmp2); if (!(mmflag & ALLOW_MDISP)) continue; @@ -1699,6 +1901,23 @@ long flag; return cnt; } +/* Part of mm_aggression that represents two-way aggression. To avoid having to + * code each case twice, this function contains those cases that ought to + * happen twice, and mm_aggression will call it twice. */ +static long +mm_2way_aggression(magr, mdef) +struct monst *magr, *mdef; +{ + struct permonst *ma = magr->data; + struct permonst *md = mdef->data; + + /* zombies vs things that can be zombified */ + if (zombie_maker(ma) && zombie_form(md) != NON_PM) + return ALLOW_M|ALLOW_TM; + + return 0; +} + /* Monster against monster special attacks; for the specified monster combinations, this allows one monster to attack another adjacent one in the absence of Conflict. There is no provision for targetting @@ -1711,6 +1930,10 @@ struct monst *magr, /* monster that is currently deciding where to move */ { int mndx = monsndx(magr->data); + /* don't allow pets to fight each other */ + if (magr->mtame && mdef->mtame) + return 0; + /* supposedly purple worms are attracted to shrieking because they like to eat shriekers, so attack the latter when feasible */ if ((mndx == PM_PURPLE_WORM || mndx == PM_BABY_PURPLE_WORM) @@ -1719,7 +1942,7 @@ struct monst *magr, /* monster that is currently deciding where to move */ /* Various other combinations such as dog vs cat, cat vs rat, and elf vs orc have been suggested. For the time being we don't support those. */ - return 0L; + return (mm_2way_aggression(magr, mdef) | mm_2way_aggression(mdef, magr)); } /* Monster displacing another monster out of the way */ @@ -1735,8 +1958,7 @@ struct monst *magr, /* monster that is currently deciding where to move */ as high as the attacker, don't let attacker do so, otherwise they might just end up swapping places again when defender gets its chance to move */ - if ((pa->mflags3 & M3_DISPLACES) != 0 - && ((pd->mflags3 & M3_DISPLACES) == 0 || magr->m_lev > mdef->m_lev) + if (is_displacer(pa) && (!is_displacer(pd) || magr->m_lev > mdef->m_lev) /* no displacing grid bugs diagonally */ && !(magr->mx != mdef->mx && magr->my != mdef->my && NODIAG(monsndx(pd))) @@ -1803,6 +2025,9 @@ struct monst *mtmp, *mtmp2; otmp->ocarry = mtmp2; } mtmp->minvent = 0; + /* before relmon(mtmp), because it could clear polearm.hitmon */ + if (g.context.polearm.hitmon == mtmp) + g.context.polearm.hitmon = mtmp2; /* remove the old monster from the map and from `fmon' list */ relmon(mtmp, (struct monst **) 0); @@ -1811,7 +2036,7 @@ struct monst *mtmp, *mtmp2; if (mtmp != u.usteed) /* don't place steed onto the map */ place_monster(mtmp2, mtmp2->mx, mtmp2->my); if (mtmp2->wormno) /* update level.monsters[wseg->wx][wseg->wy] */ - place_wsegs(mtmp2, NULL); /* locations to mtmp2 not mtmp. */ + place_wsegs(mtmp2, mtmp); /* locations to mtmp2 not mtmp. */ if (emits_light(mtmp2->data)) { /* since this is so rare, we don't have any `mon_move_light_source' */ new_light_source(mtmp2->mx, mtmp2->my, emits_light(mtmp2->data), @@ -1847,6 +2072,9 @@ struct monst **monst_list; /* &g.migrating_mons or &g.mydogs or null */ if (!fmon) panic("relmon: no fmon available."); + if (mon == g.context.polearm.hitmon) + g.context.polearm.hitmon = (struct monst *) 0; + if (unhide) { /* can't remain hidden across level changes (exception: wizard clone can continue imitating some other monster form); also, @@ -1898,9 +2126,9 @@ struct monst *mtmp2, *mtmp1; if (!mtmp2->mextra) mtmp2->mextra = newmextra(); - if (MNAME(mtmp1)) { - new_mname(mtmp2, (int) strlen(MNAME(mtmp1)) + 1); - Strcpy(MNAME(mtmp2), MNAME(mtmp1)); + if (MGIVENNAME(mtmp1)) { + new_mgivenname(mtmp2, (int) strlen(MGIVENNAME(mtmp1)) + 1); + Strcpy(MGIVENNAME(mtmp2), MGIVENNAME(mtmp1)); } if (EGD(mtmp1)) { if (!EGD(mtmp2)) @@ -1938,8 +2166,8 @@ struct monst *m; struct mextra *x = m->mextra; if (x) { - if (x->mname) - free((genericptr_t) x->mname); + if (x->mgivenname) + free((genericptr_t) x->mgivenname); if (x->egd) free((genericptr_t) x->egd); if (x->epri) @@ -1988,9 +2216,14 @@ struct permonst *mptr; /* reflects mtmp->data _prior_ to mtmp's death */ /* to prevent an infinite relobj-flooreffects-hmon-killed loop */ mtmp->mtrapped = 0; mtmp->mhp = 0; /* simplify some tests: force mhp to 0 */ + if (mtmp->iswiz) + wizdead(); + if (mtmp->data->msound == MS_NEMESIS) + nemdead(); if (mtmp->m_id == g.stealmid) thiefdead(); relobj(mtmp, 0, FALSE); + if (onmap || mtmp == g.level.monsters[0][0]) { if (mtmp->wormno) remove_worm(mtmp); @@ -2231,11 +2464,15 @@ register struct monst *mtmp; #endif if (mtmp->data->mlet == S_KOP) { + stairway *stway = stairway_find_type_dir(FALSE, FALSE); + /* Dead Kops may come back. */ switch (rnd(5)) { case 1: /* returns near the stairs */ - (void) makemon(mtmp->data, xdnstair, ydnstair, NO_MM_FLAGS); - break; + if (stway) { + (void) makemon(mtmp->data, stway->sx, stway->sy, NO_MM_FLAGS); + break; + } case 2: /* randomly */ (void) makemon(mtmp->data, 0, 0, NO_MM_FLAGS); break; @@ -2243,10 +2480,12 @@ register struct monst *mtmp; break; } } +#if 0 /* moved to m_detach() to kick in if mongone() happens */ if (mtmp->iswiz) wizdead(); if (mtmp->data->msound == MS_NEMESIS) nemdead(); +#endif if (mtmp->data == &mons[PM_MEDUSA]) record_achievement(ACH_MEDU); if (glyph_is_invisible(levl[mtmp->mx][mtmp->my].glyph)) @@ -2283,7 +2522,7 @@ boolean was_swallowed; /* digestion */ if (magr == &g.youmonst) { There("is an explosion in your %s!", body_part(STOMACH)); Sprintf(g.killer.name, "%s explosion", - s_suffix(mdat->mname)); + s_suffix(pmname(mdat, Mgender(mon)))); losehp(Maybe_Half_Phys(tmp), g.killer.name, KILLED_BY_AN); } else { You_hear("an explosion."); @@ -2300,7 +2539,8 @@ boolean was_swallowed; /* digestion */ return FALSE; } - Sprintf(g.killer.name, "%s explosion", s_suffix(mdat->mname)); + Sprintf(g.killer.name, "%s explosion", + s_suffix(pmname(mdat, Mgender(mon)))); g.killer.format = KILLED_BY_AN; explode(mon->mx, mon->my, -1, tmp, MON_EXPLODE, EXPL_NOXIOUS); g.killer.name[0] = '\0'; @@ -2418,8 +2658,8 @@ struct monst *mdef; so that saved monster traits won't retain any stale item-conferred attributes */ otmp = mkcorpstat(STATUE, mdef, mdef->data, x, y, CORPSTAT_NONE); - if (has_mname(mdef)) - otmp = oname(otmp, MNAME(mdef)); + if (has_mgivenname(mdef)) + otmp = oname(otmp, MGIVENNAME(mdef)); while ((obj = oldminvent) != 0) { oldminvent = obj->nobj; obj->nobj = 0; /* avoid merged-> obfree-> dealloc_obj-> panic */ @@ -2457,26 +2697,53 @@ struct monst *mdef; const char *fltxt; int how; { - if ((mdef->wormno ? worm_known(mdef) : cansee(mdef->mx, mdef->my)) - && fltxt) + struct permonst *mptr = mdef->data; + + if (fltxt && (mdef->wormno ? worm_known(mdef) + : cansee(mdef->mx, mdef->my))) pline("%s is %s%s%s!", Monnam(mdef), - nonliving(mdef->data) ? "destroyed" : "killed", + nonliving(mptr) ? "destroyed" : "killed", *fltxt ? " by the " : "", fltxt); else - iflags.sad_feeling = (mdef->mtame != 0); + /* sad feeling is deferred until after potential life-saving */ + iflags.sad_feeling = mdef->mtame ? TRUE : FALSE; - /* no corpses if digested or disintegrated */ - g.disintegested = (how == AD_DGST || how == -AD_RBRE); + /* no corpse if digested or disintegrated or flammable golem burnt up; + no corpse for a paper golem means no scrolls; golems that rust or + rot completely are described as "falling to pieces" so they do + leave a corpse (which means staves for wood golem, leather armor for + leather golem, iron chains for iron golem, not a regular corpse) */ + g.disintegested = (how == AD_DGST || how == -AD_RBRE + || (how == AD_FIRE && completelyburns(mptr))); if (g.disintegested) - mondead(mdef); + mondead(mdef); /* never leaves a corpse */ else - mondied(mdef); + mondied(mdef); /* calls mondead() and maybe leaves a corpse */ + + if (!DEADMONSTER(mdef)) + return; /* life-saved */ + /* extra message if pet golem is completely destroyed; + if not visible, this will follow "you have a sad feeling" */ + if (mdef->mtame) { + const char *rxt = (how == AD_FIRE && completelyburns(mptr)) ? "roast" + : (how == AD_RUST && completelyrusts(mptr)) ? "rust" + : (how == AD_DCAY && completelyrots(mptr)) ? "rot" + : 0; + if (rxt) + pline("May %s %s in peace.", noit_mon_nam(mdef), rxt); + } } void set_ustuck(mtmp) struct monst *mtmp; { + if (iflags.sanity_check || iflags.debug_fuzzer) { + if (mtmp && distu(mtmp->mx, mtmp->my) > 2) + impossible("Sticking to %s at distu %d?", + mon_nam(mtmp), distu(mtmp->mx, mtmp->my)); + } + g.context.botl = 1; u.ustuck = mtmp; } @@ -2540,7 +2807,7 @@ int xkill_flags; /* 1: suppress message, 2: suppress corpse, 4: pacifist */ u.uconduct.killer++; if (!nomsg) { - boolean namedpet = has_mname(mtmp) && !Hallucination; + boolean namedpet = has_mgivenname(mtmp) && !Hallucination; You("%s %s!", nonliving(mtmp->data) ? "destroy" : "kill", @@ -2642,8 +2909,12 @@ int xkill_flags; /* 1: suppress message, 2: suppress corpse, 4: pacifist */ } /* corpse--none if hero was inside the monster */ if (!wasinside && corpse_chance(mtmp, (struct monst *) 0, FALSE)) { + g.zombify = (!g.thrownobj && !g.stoned && !uwep + && zombie_maker(g.youmonst.data) + && zombie_form(mtmp->data) != NON_PM); cadaver = make_corpse(mtmp, burycorpse ? CORPSTAT_BURIED : CORPSTAT_NONE); + g.zombify = FALSE; /* reset */ if (burycorpse && cadaver && cansee(x, y) && !mtmp->minvis && cadaver->where == OBJ_BURIED && !nomsg) { pline("%s corpse ends up buried.", s_suffix(Monnam(mtmp))); @@ -2725,7 +2996,7 @@ struct monst *mtmp; pline("%s solidifies...", Monnam(mtmp)); if (newcham(mtmp, &mons[PM_STONE_GOLEM], FALSE, FALSE)) { if (canseemon(mtmp)) - pline("Now it's %s.", an(mtmp->data->mname)); + pline("Now it's %s.", an(pmname(mtmp->data, Mgender(mtmp)))); } else { if (canseemon(mtmp)) pline("... and returns to normal."); @@ -3115,6 +3386,9 @@ boolean via_attack; mtmp->mstrategy &= ~STRAT_WAITMASK; if (!mtmp->mpeaceful) return; + /* [FIXME: this logic seems wrong; peaceful humanoids gasp or exclaim + when they see you attack a peaceful monster but they just casually + look the other way when you attack a pet?] */ if (mtmp->mtame) return; mtmp->mpeaceful = 0; @@ -3150,7 +3424,7 @@ boolean via_attack; } } if (got_mad && !Hallucination) { - const char *who = q_guardian->mname; + const char *who = q_guardian->pmnames[NEUTRAL]; if (got_mad > 1) who = makeplural(who); @@ -3161,9 +3435,6 @@ boolean via_attack; /* make other peaceful monsters react */ if (!g.context.mon_moving) { - static const char *const Exclam[] = { - "Gasp!", "Uh-oh.", "Oh my!", "What?", "Why?", - }; struct monst *mon; int mndx = monsndx(mtmp->data); @@ -3176,29 +3447,53 @@ boolean via_attack; if (!mindless(mon->data) && mon->mpeaceful && couldsee(mon->mx, mon->my) && !mon->msleeping && mon->mcansee && m_canseeu(mon)) { - boolean exclaimed = FALSE; + char buf[BUFSZ]; + boolean exclaimed = FALSE, needpunct = FALSE, alreadyfleeing; + buf[0] = '\0'; if (humanoid(mon->data) || mon->isshk || mon->ispriest) { if (is_watch(mon->data)) { verbalize("Halt! You're under arrest!"); (void) angry_guards(!!Deaf); } else { - if (!rn2(5)) { - verbalize("%s", Exclam[mon->m_id % SIZE(Exclam)]); - exclaimed = TRUE; + if (!Deaf && !rn2(5)) { + const char *gasp = maybe_gasp(mon); + + if (gasp) { + if (!strncmpi(gasp, "gasp", 4)) { + Sprintf(buf, "%s gasps", Monnam(mon)); + needpunct = TRUE; + } else { + Sprintf(buf, "%s exclaims \"%s\"", + Monnam(mon), gasp); + } + exclaimed = TRUE; + } } /* shopkeepers and temple priests might gasp in surprise, but they won't become angry here */ - if (mon->isshk || mon->ispriest) + if (mon->isshk || mon->ispriest) { + if (exclaimed) + pline("%s%s", buf, " then shrugs."); continue; + } if (mon->data->mlevel < rn2(10)) { + alreadyfleeing = (mon->mflee || mon->mfleetim); monflee(mon, rn2(50) + 25, TRUE, !exclaimed); - exclaimed = TRUE; + if (exclaimed) { + if (flags.verbose && !alreadyfleeing) { + Strcat(buf, " and then turns to flee."); + needpunct = FALSE; + } + } else + exclaimed = TRUE; /* got msg from monflee() */ } + if (*buf) + pline("%s%s", buf, needpunct ? "." : ""); if (mon->mtame) { - /* mustn't set mpeaceful to 0 as below; - perhaps reduce tameness? */ + ; /* mustn't set mpeaceful to 0 as below; + * perhaps reduce tameness? */ } else { mon->mpeaceful = 0; adjalign(-1); @@ -3209,12 +3504,18 @@ boolean via_attack; } else if (mon->data->mlet == mtmp->data->mlet && big_little_match(mndx, monsndx(mon->data)) && !rn2(3)) { - if (!rn2(4)) { + if (!Deaf && !rn2(4)) { growl(mon); - exclaimed = TRUE; + exclaimed = (iflags.last_msg == PLNMSG_GROWL); } - if (rn2(6)) + if (rn2(6)) { + alreadyfleeing = (mon->mflee || mon->mfleetim); monflee(mon, rn2(25) + 15, TRUE, !exclaimed); + if (exclaimed && !alreadyfleeing) + /* word like a separate sentence so that we + don't have to poke around inside growl() */ + pline("And then starts to flee."); + } } } } @@ -3228,8 +3529,11 @@ register struct monst *mtmp; boolean via_attack; { mtmp->msleeping = 0; - if (M_AP_TYPE(mtmp)) { - seemimic(mtmp); + if (M_AP_TYPE(mtmp) != M_AP_NOTHING) { + /* mimics come out of hiding, but disguised Wizard doesn't + have to lose his disguise */ + if (M_AP_TYPE(mtmp) != M_AP_MONSTER) + seemimic(mtmp); } else if (g.context.forcefight && !g.context.mon_moving && mtmp->mundetected) { mtmp->mundetected = 0; @@ -3316,11 +3620,19 @@ rescham() } if (is_were(mtmp->data) && mtmp->data->mlet != S_HUMAN) new_were(mtmp); - if (M_AP_TYPE(mtmp) && cansee(mtmp->mx, mtmp->my)) { - seemimic(mtmp); - /* we pretend that the mimic doesn't - know that it has been unmasked */ - mtmp->msleeping = 1; + if (M_AP_TYPE(mtmp) != M_AP_NOTHING) { + /* this used to include a cansee() check but Protection_from_ + _shape_changers shouldn't be trumped by being unseen */ + if (!mtmp->meating) { + /* make revealed mimic fall asleep in lieu of shape change */ + if (M_AP_TYPE(mtmp) != M_AP_MONSTER) + mtmp->msleeping = 1; + seemimic(mtmp); + } else { + /* quickmimic: pet is midst of eating a mimic corpse; + this terminates the meal early */ + finish_meating(mtmp); + } } } } @@ -3392,6 +3704,19 @@ register struct monst *mtmp; return FALSE; } +/* reveal a monster at x,y hiding under an object, + if there are no objects there */ +void +maybe_unhide_at(x, y) +xchar x, y; +{ + struct monst *mtmp; + + if (!OBJ_AT(x, y) && (mtmp = m_at(x, y)) != 0 + && mtmp->mundetected && hides_under(mtmp->data)) + (void) hideunder(mtmp); +} + /* monster/hero tries to hide under something at the current location */ boolean hideunder(mtmp) @@ -3572,7 +3897,7 @@ struct monst *mon; break; /* leave mndx as is */ wolfchance = 3; /*FALLTHRU*/ - case PM_VAMPIRE_LORD: /* vampire lord or Vlad can become wolf */ + case PM_VAMPIRE_LEADER: /* vampire lord or Vlad can become wolf */ if (!rn2(wolfchance) && !uppercase_only) { mndx = PM_WOLF; break; @@ -3723,7 +4048,7 @@ struct monst *mon; mndx = pick_animal(); break; case PM_VLAD_THE_IMPALER: - case PM_VAMPIRE_LORD: + case PM_VAMPIRE_LEADER: case PM_VAMPIRE: mndx = pickvampshape(mon); break; @@ -3781,7 +4106,7 @@ struct monst *mon; mndx = NON_PM; break; } - mndx = name_to_mon(buf); + mndx = name_to_mon(buf, (int *) 0); if (mndx == NON_PM) { /* didn't get a type, so check whether it's a class (single letter or text match with def_monsyms[]) */ @@ -3906,7 +4231,7 @@ boolean msg; /* "The oldmon turns into a newmon!" */ } /* we need this one whether msg is true or not */ Strcpy(l_oldname, x_monnam(mtmp, ARTICLE_THE, (char *) 0, - has_mname(mtmp) ? SUPPRESS_SADDLE : 0, FALSE)); + has_mgivenname(mtmp) ? SUPPRESS_SADDLE : 0, FALSE)); /* mdat = 0 -> caller wants a random monster shape */ if (mdat == 0) { @@ -3939,7 +4264,7 @@ boolean msg; /* "The oldmon turns into a newmon!" */ * polymorphed, so dropping rank for mplayers seems reasonable. */ if (In_endgame(&u.uz) && is_mplayer(olddata) - && has_mname(mtmp) && (p = strstr(MNAME(mtmp), " the ")) != 0) + && has_mgivenname(mtmp) && (p = strstr(MGIVENNAME(mtmp), " the ")) != 0) *p = '\0'; if (mtmp->wormno) { /* throw tail away */ @@ -4362,8 +4687,7 @@ struct permonst *mdat; You("notice a bovine smell."); msg_given = TRUE; break; - case PM_CAVEMAN: - case PM_CAVEWOMAN: + case PM_CAVE_DWELLER: case PM_BARBARIAN: case PM_NEANDERTHAL: You("smell body odor."); diff --git a/src/mondata.c b/src/mondata.c index 4e0ba2d0a..142d44c2b 100644 --- a/src/mondata.c +++ b/src/mondata.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 mondata.c $NHDT-Date: 1581803740 2020/02/15 21:55:40 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.77 $ */ +/* NetHack 3.7 mondata.c $NHDT-Date: 1606473489 2020/11/27 10:38:09 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.87 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2011. */ /* NetHack may be freely redistributed. See license for details. */ @@ -195,7 +195,6 @@ struct obj *obj; /* aatyp == AT_WEAP, AT_SPIT */ boolean is_you = (mdef == &g.youmonst); boolean check_visor = FALSE; struct obj *o; - const char *s; /* no eyes protect against all attacks for now */ if (!haseyes(mdef->data)) @@ -271,8 +270,7 @@ struct obj *obj; /* aatyp == AT_WEAP, AT_SPIT */ o = (mdef == &g.youmonst) ? g.invent : mdef->minvent; for (; o; o = o->nobj) if ((o->owornmask & W_ARMH) - && (s = OBJ_DESCR(objects[o->otyp])) != (char *) 0 - && !strcmp(s, "visored helmet")) + && objdescr_is(o, "visored helmet")) return FALSE; } @@ -336,7 +334,10 @@ struct permonst *mptr; { return (boolean) (passes_walls(mptr) || amorphous(mptr) || unsolid(mptr) || is_whirly(mptr) || verysmall(mptr) - || dmgtype(mptr, AD_CORR) || dmgtype(mptr, AD_RUST) + /* rust monsters and some puddings can destroy bars */ + || dmgtype(mptr, AD_RUST) || dmgtype(mptr, AD_CORR) + /* rock moles can eat bars */ + || metallivorous(mptr) || (slithy(mptr) && !bigmonst(mptr))); } @@ -508,7 +509,7 @@ int max_passive_dmg(mdef, magr) register struct monst *mdef, *magr; { - int i, dmg = 0, multi2 = 0; + int i, dmg, multi2 = 0; uchar adtyp; /* each attack by magr can result in passive damage */ @@ -530,25 +531,29 @@ register struct monst *mdef, *magr; break; } + dmg = 0; for (i = 0; i < NATTK; i++) if (mdef->data->mattk[i].aatyp == AT_NONE || mdef->data->mattk[i].aatyp == AT_BOOM) { adtyp = mdef->data->mattk[i].adtyp; - if ((adtyp == AD_ACID && !resists_acid(magr)) - || (adtyp == AD_COLD && !resists_cold(magr)) - || (adtyp == AD_FIRE && !resists_fire(magr)) - || (adtyp == AD_ELEC && !resists_elec(magr)) - || adtyp == AD_PHYS) { + if ((adtyp == AD_FIRE && completelyburns(magr->data)) + || (adtyp == AD_DCAY && completelyrots(magr->data)) + || (adtyp == AD_RUST && completelyrusts(magr->data))) { + dmg = magr->mhp; + } else if ((adtyp == AD_ACID && !resists_acid(magr)) + || (adtyp == AD_COLD && !resists_cold(magr)) + || (adtyp == AD_FIRE && !resists_fire(magr)) + || (adtyp == AD_ELEC && !resists_elec(magr)) + || adtyp == AD_PHYS) { dmg = mdef->data->mattk[i].damn; if (!dmg) dmg = mdef->data->mlevel + 1; dmg *= mdef->data->mattk[i].damd; - } else - dmg = 0; - - return dmg * multi2; + } + dmg *= multi2; + break; } - return 0; + return dmg; } /* determine whether two monster types are from the same species */ @@ -676,15 +681,17 @@ struct permonst *ptr; struct alt_spl { const char *name; short pm_val; + int genderhint; }; /* figure out what type of monster a user-supplied string is specifying; ingore anything past the monster name */ int -name_to_mon(in_str) +name_to_mon(in_str, gender_name_var) const char *in_str; +int *gender_name_var; { - return name_to_monplus(in_str, (const char **) 0); + return name_to_monplus(in_str, (const char **) 0, gender_name_var); } /* figure out what type of monster a user-supplied string is specifying; @@ -692,9 +699,10 @@ const char *in_str; caller wants to strip off the name and it matches one of the alternate names rather the canonical mons[].mname */ int -name_to_monplus(in_str, remainder_p) +name_to_monplus(in_str, remainder_p, gender_name_var) const char *in_str; const char **remainder_p; +int *gender_name_var; { /* Be careful. We must check the entire string in case it was * something such as "ettin zombie corpse". The calling routine @@ -712,7 +720,8 @@ const char **remainder_p; register int mntmp = NON_PM; register char *s, *str, *term; char buf[BUFSZ]; - int len, slen; + int len, slen, mgend; + boolean exact_match = FALSE; if (remainder_p) *remainder_p = (const char *) 0; @@ -744,70 +753,72 @@ const char **remainder_p; { static const struct alt_spl names[] = { /* Alternate spellings */ - { "grey dragon", PM_GRAY_DRAGON }, - { "baby grey dragon", PM_BABY_GRAY_DRAGON }, - { "grey unicorn", PM_GRAY_UNICORN }, - { "grey ooze", PM_GRAY_OOZE }, - { "gray-elf", PM_GREY_ELF }, - { "mindflayer", PM_MIND_FLAYER }, - { "master mindflayer", PM_MASTER_MIND_FLAYER }, + { "grey dragon", PM_GRAY_DRAGON, NEUTRAL }, + { "baby grey dragon", PM_BABY_GRAY_DRAGON, NEUTRAL }, + { "grey unicorn", PM_GRAY_UNICORN, NEUTRAL }, + { "grey ooze", PM_GRAY_OOZE, NEUTRAL }, + { "gray-elf", PM_GREY_ELF, NEUTRAL }, + { "mindflayer", PM_MIND_FLAYER, NEUTRAL }, + { "master mindflayer", PM_MASTER_MIND_FLAYER, NEUTRAL }, /* More alternates; priest and priestess are separate monster types but that isn't the case for {aligned,high} priests */ - { "aligned priestess", PM_ALIGNED_PRIEST }, - { "high priestess", PM_HIGH_PRIEST }, + { "aligned priestess", PM_ALIGNED_CLERIC, NEUTRAL }, + { "high priestess", PM_HIGH_CLERIC, NEUTRAL }, /* Inappropriate singularization by -ves check above */ - { "master of thief", PM_MASTER_OF_THIEVES }, + { "master of thief", PM_MASTER_OF_THIEVES, NEUTRAL }, /* Potential misspellings where we want to avoid falling back to the rank title prefix (input has been singularized) */ - { "master thief", PM_MASTER_OF_THIEVES }, - { "master of assassin", PM_MASTER_ASSASSIN }, + { "master thief", PM_MASTER_OF_THIEVES, NEUTRAL }, + { "master of assassin", PM_MASTER_ASSASSIN, NEUTRAL }, /* Outdated names */ - { "invisible stalker", PM_STALKER }, - { "high-elf", PM_ELVENKING }, /* PM_HIGH_ELF is obsolete */ + { "invisible stalker", PM_STALKER, NEUTRAL }, + { "high-elf", PM_ELVEN_MONARCH, NEUTRAL }, /* PM_HIGH_ELF is obsolete */ /* other misspellings or incorrect words */ - { "wood-elf", PM_WOODLAND_ELF }, - { "wood elf", PM_WOODLAND_ELF }, - { "woodland nymph", PM_WOOD_NYMPH }, - { "halfling", PM_HOBBIT }, /* potential guess for polyself */ - { "genie", PM_DJINNI }, /* potential guess for ^G/#wizgenesis */ + { "wood-elf", PM_WOODLAND_ELF, NEUTRAL }, + { "wood elf", PM_WOODLAND_ELF, NEUTRAL }, + { "woodland nymph", PM_WOOD_NYMPH, NEUTRAL }, + { "halfling", PM_HOBBIT, NEUTRAL }, /* potential guess for polyself */ + { "genie", PM_DJINNI, NEUTRAL }, /* potential guess for ^G/#wizgenesis */ /* prefix used to workaround duplicate monster names for monsters with alternate forms */ - { "human wererat", PM_HUMAN_WERERAT }, - { "human werejackal", PM_HUMAN_WEREJACKAL }, - { "human werewolf", PM_HUMAN_WEREWOLF }, + { "human wererat", PM_HUMAN_WERERAT, NEUTRAL }, + { "human werejackal", PM_HUMAN_WEREJACKAL, NEUTRAL }, + { "human werewolf", PM_HUMAN_WEREWOLF, NEUTRAL }, /* for completeness */ - { "rat wererat", PM_WERERAT }, - { "jackal werejackal", PM_WEREJACKAL }, - { "wolf werewolf", PM_WEREWOLF }, + { "rat wererat", PM_WERERAT, NEUTRAL }, + { "jackal werejackal", PM_WEREJACKAL, NEUTRAL }, + { "wolf werewolf", PM_WEREWOLF, NEUTRAL }, /* Hyphenated names -- it would be nice to handle these via fuzzymatch() but it isn't able to ignore trailing stuff */ - { "ki rin", PM_KI_RIN }, - { "kirin", PM_KI_RIN }, - { "uruk hai", PM_URUK_HAI }, - { "orc captain", PM_ORC_CAPTAIN }, - { "woodland elf", PM_WOODLAND_ELF }, - { "green elf", PM_GREEN_ELF }, - { "grey elf", PM_GREY_ELF }, - { "gray elf", PM_GREY_ELF }, - { "elf lord", PM_ELF_LORD }, - { "olog hai", PM_OLOG_HAI }, - { "arch lich", PM_ARCH_LICH }, - { "archlich", PM_ARCH_LICH }, + { "ki rin", PM_KI_RIN, NEUTRAL }, + { "kirin", PM_KI_RIN, NEUTRAL }, + { "uruk hai", PM_URUK_HAI, NEUTRAL }, + { "orc captain", PM_ORC_CAPTAIN, NEUTRAL }, + { "woodland elf", PM_WOODLAND_ELF, NEUTRAL }, + { "green elf", PM_GREEN_ELF, NEUTRAL }, + { "grey elf", PM_GREY_ELF, NEUTRAL }, + { "gray elf", PM_GREY_ELF, NEUTRAL }, + { "elf lady", PM_ELF_NOBLE, FEMALE }, + { "elf lord", PM_ELF_NOBLE, MALE }, + { "elf noble", PM_ELF_NOBLE, NEUTRAL }, + { "olog hai", PM_OLOG_HAI, NEUTRAL }, + { "arch lich", PM_ARCH_LICH, NEUTRAL }, + { "archlich", PM_ARCH_LICH, NEUTRAL }, /* Some irregular plurals */ - { "incubi", PM_INCUBUS }, - { "succubi", PM_SUCCUBUS }, - { "violet fungi", PM_VIOLET_FUNGUS }, - { "homunculi", PM_HOMUNCULUS }, - { "baluchitheria", PM_BALUCHITHERIUM }, - { "lurkers above", PM_LURKER_ABOVE }, - { "cavemen", PM_CAVEMAN }, - { "cavewomen", PM_CAVEWOMAN }, - { "watchmen", PM_WATCHMAN }, - { "djinn", PM_DJINNI }, - { "mumakil", PM_MUMAK }, - { "erinyes", PM_ERINYS }, + { "incubi", PM_AMOROUS_DEMON, MALE }, + { "succubi", PM_AMOROUS_DEMON, FEMALE }, + { "violet fungi", PM_VIOLET_FUNGUS, NEUTRAL }, + { "homunculi", PM_HOMUNCULUS, NEUTRAL }, + { "baluchitheria", PM_BALUCHITHERIUM, NEUTRAL }, + { "lurkers above", PM_LURKER_ABOVE, NEUTRAL }, + { "cavemen", PM_CAVE_DWELLER, MALE }, + { "cavewomen", PM_CAVE_DWELLER, FEMALE }, + { "watchmen", PM_WATCHMAN, NEUTRAL }, + { "djinn", PM_DJINNI, NEUTRAL }, + { "mumakil", PM_MUMAK, NEUTRAL }, + { "erinyes", PM_ERINYS, NEUTRAL }, /* end of list */ - { 0, NON_PM } + { 0, NON_PM, NEUTRAL } }; register const struct alt_spl *namep; @@ -818,18 +829,28 @@ const char **remainder_p; && (!str[len] || str[len] == ' ' || str[len] == '\'')) { if (remainder_p) *remainder_p = in_str + (&str[len] - buf); + if (gender_name_var != (int *) 0) + *gender_name_var = namep->genderhint; return namep->pm_val; } } } for (len = 0, i = LOW_PM; i < NUMMONS; i++) { - register int m_i_len = (int) strlen(mons[i].mname); + for (mgend = MALE; mgend < NUM_MGENDERS; mgend++) { + int m_i_len; - if (m_i_len > len && !strncmpi(mons[i].mname, str, m_i_len)) { + if (!mons[i].pmnames[mgend]) + continue; + + m_i_len = (int) strlen(mons[i].pmnames[mgend]); + if (m_i_len > len && !strncmpi(mons[i].pmnames[mgend], str, m_i_len)) { if (m_i_len == slen) { mntmp = i; len = m_i_len; + if (gender_name_var != (int *) 0) + *gender_name_var = mgend; + exact_match = TRUE; break; /* exact match */ } else if (slen > m_i_len && (str[m_i_len] == ' ' @@ -845,6 +866,9 @@ const char **remainder_p; len = m_i_len; } } + } + if (exact_match) + break; } if (mntmp == NON_PM) mntmp = title_to_mon(str, (int *) 0, &len); @@ -863,8 +887,8 @@ int *mndx_p; /* Single letters are matched against def_monsyms[].sym; words or phrases are first matched against def_monsyms[].explain to check class description; if not found there, then against - mons[].mname to test individual monster types. Input can be a - substring of the full description or mname, but to be accepted, + mons[].pmnames[] to test individual monster types. Input can be a + substring of the full description or pmname, but to be accepted, such partial matches must start at beginning of a word. Some class descriptions include "foo or bar" and "foo or other foo" so we don't want to accept "or", "other", "or other" there. */ @@ -876,16 +900,16 @@ int *mndx_p; static NEARDATA const struct alt_spl truematch[] = { /* "long worm" won't match "worm" class but would accidentally match "long worm tail" class before the comparison with monster types */ - { "long worm", PM_LONG_WORM }, + { "long worm", PM_LONG_WORM, NEUTRAL }, /* matches wrong--or at least suboptimal--class */ - { "demon", -S_DEMON }, /* hits "imp or minor demon" */ + { "demon", -S_DEMON, NEUTRAL }, /* hits "imp or minor demon" */ /* matches specific monster (overly restrictive) */ - { "devil", -S_DEMON }, /* always "horned devil" */ + { "devil", -S_DEMON, NEUTRAL }, /* always "horned devil" */ /* some plausible guesses which need help */ - { "bug", -S_XAN }, /* would match bugbear... */ - { "fish", -S_EEL }, /* wouldn't match anything */ + { "bug", -S_XAN, NEUTRAL }, /* would match bugbear... */ + { "fish", -S_EEL, NEUTRAL }, /* wouldn't match anything */ /* end of list */ - { 0, NON_PM } + { 0, NON_PM, NEUTRAL} }; const char *p, *x; int i, len; @@ -936,7 +960,7 @@ int *mndx_p; return i; } /* check individual species names */ - i = name_to_mon(in_str); + i = name_to_mon(in_str, (int *) 0); if (i != NON_PM) { if (mndx_p) *mndx_p = i; @@ -1009,11 +1033,11 @@ static const short grownups[][2] = { { PM_PONY, PM_HORSE }, { PM_HORSE, PM_WARHORSE }, { PM_KOBOLD, PM_LARGE_KOBOLD }, - { PM_LARGE_KOBOLD, PM_KOBOLD_LORD }, - { PM_GNOME, PM_GNOME_LORD }, - { PM_GNOME_LORD, PM_GNOME_KING }, - { PM_DWARF, PM_DWARF_LORD }, - { PM_DWARF_LORD, PM_DWARF_KING }, + { PM_LARGE_KOBOLD, PM_KOBOLD_LEADER }, + { PM_GNOME, PM_GNOME_LEADER }, + { PM_GNOME_LEADER, PM_GNOME_RULER }, + { PM_DWARF, PM_DWARF_LEADER }, + { PM_DWARF_LEADER, PM_DWARF_RULER }, { PM_MIND_FLAYER, PM_MASTER_MIND_FLAYER }, { PM_ORC, PM_ORC_CAPTAIN }, { PM_HILL_ORC, PM_ORC_CAPTAIN }, @@ -1021,17 +1045,17 @@ static const short grownups[][2] = { { PM_URUK_HAI, PM_ORC_CAPTAIN }, { PM_SEWER_RAT, PM_GIANT_RAT }, { PM_CAVE_SPIDER, PM_GIANT_SPIDER }, - { PM_OGRE, PM_OGRE_LORD }, - { PM_OGRE_LORD, PM_OGRE_KING }, - { PM_ELF, PM_ELF_LORD }, - { PM_WOODLAND_ELF, PM_ELF_LORD }, - { PM_GREEN_ELF, PM_ELF_LORD }, - { PM_GREY_ELF, PM_ELF_LORD }, - { PM_ELF_LORD, PM_ELVENKING }, + { PM_OGRE, PM_OGRE_LEADER }, + { PM_OGRE_LEADER, PM_OGRE_TYRANT }, + { PM_ELF, PM_ELF_NOBLE }, + { PM_WOODLAND_ELF, PM_ELF_NOBLE }, + { PM_GREEN_ELF, PM_ELF_NOBLE }, + { PM_GREY_ELF, PM_ELF_NOBLE }, + { PM_ELF_NOBLE, PM_ELVEN_MONARCH }, { PM_LICH, PM_DEMILICH }, { PM_DEMILICH, PM_MASTER_LICH }, { PM_MASTER_LICH, PM_ARCH_LICH }, - { PM_VAMPIRE, PM_VAMPIRE_LORD }, + { PM_VAMPIRE, PM_VAMPIRE_LEADER }, { PM_BAT, PM_GIANT_BAT }, { PM_BABY_GRAY_DRAGON, PM_GRAY_DRAGON }, { PM_BABY_SILVER_DRAGON, PM_SILVER_DRAGON }, @@ -1058,11 +1082,11 @@ static const short grownups[][2] = { { PM_SERGEANT, PM_LIEUTENANT }, { PM_LIEUTENANT, PM_CAPTAIN }, { PM_WATCHMAN, PM_WATCH_CAPTAIN }, - { PM_ALIGNED_PRIEST, PM_HIGH_PRIEST }, + { PM_ALIGNED_CLERIC, PM_HIGH_CLERIC }, { PM_STUDENT, PM_ARCHEOLOGIST }, { PM_ATTENDANT, PM_HEALER }, { PM_PAGE, PM_KNIGHT }, - { PM_ACOLYTE, PM_PRIEST }, + { PM_ACOLYTE, PM_CLERIC }, { PM_APPRENTICE, PM_WIZARD }, { PM_MANES, PM_LEMURE }, { PM_KEYSTONE_KOP, PM_KOP_SERGEANT }, diff --git a/src/monmove.c b/src/monmove.c index 7c03b2236..dc64ae9d2 100644 --- a/src/monmove.c +++ b/src/monmove.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 monmove.c $NHDT-Date: 1586091452 2020/04/05 12:57:32 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.137 $ */ +/* NetHack 3.7 monmove.c $NHDT-Date: 1603507386 2020/10/24 02:43:06 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.146 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2006. */ /* NetHack may be freely redistributed. See license for details. */ @@ -114,16 +114,18 @@ register struct monst *mtmp; /* a similar check is in monster_nearby() in hack.c */ /* check whether hero notices monster and stops current activity */ - if (g.occupation && !rd && !Confusion && (!mtmp->mpeaceful || Hallucination) + if (g.occupation && !rd + /* monster is hostile and can attack (or hallu distorts knowledge) */ + && (Hallucination || (!mtmp->mpeaceful && !noattacks(mtmp->data))) /* it's close enough to be a threat */ - && distu(x, y) <= (BOLT_LIM + 1) * (BOLT_LIM + 1) + && distu(mtmp->mx, mtmp->my) <= (BOLT_LIM + 1) * (BOLT_LIM + 1) /* and either couldn't see it before, or it was too far away */ && (!already_saw_mon || !couldsee(x, y) || distu(x, y) > (BOLT_LIM + 1) * (BOLT_LIM + 1)) /* can see it now, or sense it and would normally see it */ - && (canseemon(mtmp) || (sensemon(mtmp) && couldsee(x, y))) - && mtmp->mcanmove && !noattacks(mtmp->data) - && !onscary(u.ux, u.uy, mtmp)) + && canspotmon(mtmp) && couldsee(mtmp->mx, mtmp->my) + /* monster isn't paralyzed or afraid (scare monster/Elbereth) */ + && mtmp->mcanmove && !onscary(u.ux, u.uy, mtmp)) stop_occupation(); return rd; @@ -562,13 +564,27 @@ register struct monst *mtmp; && (!Conflict || resist(mtmp, RING_CLASS, 0, 0))) { pline("It feels quite soothing."); } else if (!u.uinvulnerable) { - register boolean m_sen = sensemon(mtmp); + int dmg; + boolean m_sen = sensemon(mtmp); if (m_sen || (Blind_telepat && rn2(2)) || !rn2(10)) { - int dmg; + /* hiding monsters are brought out of hiding when hit by + a psychic blast, so do the same for hiding poly'd hero */ + if (u.uundetected) { + u.uundetected = 0; + newsym(u.ux, u.uy); + } else if (U_AP_TYPE != M_AP_NOTHING + /* hero has no way to hide as monster but + check for that theoretical case anyway */ + && U_AP_TYPE != M_AP_MONSTER) { + g.youmonst.m_ap_type = M_AP_NOTHING; + g.youmonst.mappearance = 0; + newsym(u.ux, u.uy); + } pline("It locks on to your %s!", - m_sen ? "telepathy" : Blind_telepat ? "latent telepathy" - : "mind"); + m_sen ? "telepathy" + : Blind_telepat ? "latent telepathy" + : "mind"); /* note: hero is never mindless */ dmg = rnd(15); if (Half_spell_damage) dmg = (dmg + 1) / 2; @@ -587,13 +603,13 @@ register struct monst *mtmp; continue; if ((telepathic(m2->data) && (rn2(2) || m2->mblinded)) || !rn2(10)) { + /* wake it up first, to bring hidden monster out of hiding */ + wakeup(m2, FALSE); if (cansee(m2->mx, m2->my)) pline("It locks on to %s.", mon_nam(m2)); m2->mhp -= rnd(15); if (DEADMONSTER(m2)) monkilled(m2, "", AD_DRIN); - else - m2->msleeping = 0; } } } @@ -999,10 +1015,11 @@ register int after; > ((ygold = findgold(g.invent)) ? ygold->quan : 0L)))) appr = -1; - /* hostile monsters with ranged thrown weapons try to stay away */ + /* hostiles with ranged weapons or spit attack try to stay away */ if (!mtmp->mpeaceful && (dist2(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy) < 5*5) - && m_canseeu(mtmp) && m_has_launcher_and_ammo(mtmp)) + && m_canseeu(mtmp) && + (m_has_launcher_and_ammo(mtmp) || attacktype(mtmp->data, AT_SPIT))) appr = -1; if (!should_see && can_track(ptr)) { @@ -1156,34 +1173,7 @@ register int after; nix = omx; niy = omy; - flag = 0L; - if (mtmp->mpeaceful && (!Conflict || resist(mtmp, RING_CLASS, 0, 0))) - flag |= (ALLOW_SANCT | ALLOW_SSM); - else - flag |= ALLOW_U; - if (is_minion(ptr) || is_rider(ptr)) - flag |= ALLOW_SANCT; - /* unicorn may not be able to avoid hero on a noteleport level */ - if (is_unicorn(ptr) && !noteleport_level(mtmp)) - flag |= NOTONL; - if (passes_walls(ptr)) - flag |= (ALLOW_WALL | ALLOW_ROCK); - if (passes_bars(ptr)) - flag |= ALLOW_BARS; - if (can_tunnel) - flag |= ALLOW_DIG; - if (is_human(ptr) || ptr == &mons[PM_MINOTAUR]) - flag |= ALLOW_SSM; - if ((is_undead(ptr) && ptr->mlet != S_GHOST) || is_vampshifter(mtmp)) - flag |= NOGARLIC; - if (throws_rocks(ptr)) - flag |= ALLOW_ROCK; - if (can_open) - flag |= OPENDOOR; - if (can_unlock) - flag |= UNLOCKDOOR; - if (doorbuster) - flag |= BUSTDOOR; + flag = mon_allowflags(mtmp); { register int i, j, nx, ny, nearer; int jcnt, cnt; @@ -1276,29 +1266,8 @@ register int after; * Pets get taken care of above and shouldn't reach this code. * Conflict gets handled even farther away (movemon()). */ - if ((info[chi] & ALLOW_M) || (nix == mtmp->mux && niy == mtmp->muy)) { - struct monst *mtmp2; - int mstatus; - - mtmp2 = m_at(nix, niy); - - g.notonhead = mtmp2 && (nix != mtmp2->mx || niy != mtmp2->my); - /* note: mstatus returns 0 if mtmp2 is nonexistent */ - mstatus = mattackm(mtmp, mtmp2); - - if (mstatus & MM_AGR_DIED) /* aggressor died */ - return 2; - - if ((mstatus & MM_HIT) && !(mstatus & MM_DEF_DIED) && rn2(4) - && mtmp2->movement >= NORMAL_SPEED) { - mtmp2->movement -= NORMAL_SPEED; - g.notonhead = 0; - mstatus = mattackm(mtmp2, mtmp); /* return attack */ - if (mstatus & MM_DEF_DIED) - return 2; - } - return 3; - } + if ((info[chi] & ALLOW_M) || (nix == mtmp->mux && niy == mtmp->muy)) + return m_move_aggress(mtmp, nix, niy); if ((info[chi] & ALLOW_MDISP)) { struct monst *mtmp2; @@ -1481,9 +1450,12 @@ register int after; add_damage(mtmp->mx, mtmp->my, 0L); } } else if (levl[mtmp->mx][mtmp->my].typ == IRONBARS) { - /* 3.6.2: was using may_dig() but it doesn't handle bars */ + /* 3.6.2: was using may_dig() but that doesn't handle bars; + AD_RUST catches rust monsters but metallivorous() is + needed for xorns and rock moles */ if (!(levl[mtmp->mx][mtmp->my].wall_info & W_NONDIGGABLE) - && (dmgtype(ptr, AD_RUST) || dmgtype(ptr, AD_CORR))) { + && (dmgtype(ptr, AD_RUST) || dmgtype(ptr, AD_CORR) + || metallivorous(ptr))) { if (canseemon(mtmp)) pline("%s eats through the iron bars.", Monnam(mtmp)); dissolve_bars(mtmp->mx, mtmp->my); @@ -1590,6 +1562,44 @@ register int after; return mmoved; } +/* The part of m_move that deals with a monster attacking another monster (and + * that monster possibly retaliating). + * Extracted into its own function so that it can be called with monsters that + * have special move patterns (shopkeepers, priests, etc) that want to attack + * other monsters but aren't just roaming freely around the level (so allowing + * m_move to run fully for them could select an invalid move). + * x and y are the coordinates mtmp wants to attack. + * Return values are the same as for m_move, but this function only return 2 + * (mtmp died) or 3 (mtmp made its move). + */ +int +m_move_aggress(mtmp, x, y) +struct monst * mtmp; +xchar x, y; +{ + struct monst *mtmp2; + int mstatus; + + mtmp2 = m_at(x, y); + + g.notonhead = mtmp2 && (x != mtmp2->mx || y != mtmp2->my); + /* note: mstatus returns 0 if mtmp2 is nonexistent */ + mstatus = mattackm(mtmp, mtmp2); + + if (mstatus & MM_AGR_DIED) /* aggressor died */ + return 2; + + if ((mstatus & MM_HIT) && !(mstatus & MM_DEF_DIED) && rn2(4) + && mtmp2->movement >= NORMAL_SPEED) { + mtmp2->movement -= NORMAL_SPEED; + g.notonhead = 0; + mstatus = mattackm(mtmp2, mtmp); /* return attack */ + if (mstatus & MM_DEF_DIED) + return 2; + } + return 3; +} + void dissolve_bars(x, y) register int x, y; @@ -1597,6 +1607,8 @@ register int x, y; levl[x][y].typ = (Is_special(&u.uz) || *in_rooms(x, y, 0)) ? ROOM : CORR; levl[x][y].flags = 0; newsym(x, y); + if (x == u.ux && y == u.uy) + switch_terrain(); } boolean diff --git a/src/monst.c b/src/monst.c index 9b8961636..fbd1f8a99 100644 --- a/src/monst.c +++ b/src/monst.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 monst.c $NHDT-Date: 1587502224 2020/04/21 20:50:24 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.73 $ */ +/* NetHack 3.7 monst.c $NHDT-Date: 1605726850 2020/11/18 19:14:10 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.78 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2006. */ /* NetHack may be freely redistributed. See license for details. */ @@ -45,7 +45,13 @@ */ #define MON(nam, sym, lvl, gen, atk, siz, mr1, mr2, flg1, flg2, flg3, d, col) \ { \ - nam, sym, lvl, gen, atk, siz, mr1, mr2, flg1, flg2, flg3, d, C(col) \ + {(const char *) 0, (const char *) 0, nam}, \ + sym, lvl, gen, atk, siz, mr1, mr2, flg1, flg2, flg3, d, C(col) \ + } +#define MON3(namm, namf, namn, sym, lvl, gen, atk, siz, mr1, mr2, flg1, flg2, flg3, d, col) \ + { \ + {namm, namf, namn}, \ + sym, lvl, gen, atk, siz, mr1, mr2, flg1, flg2, flg3, d, C(col) \ } /* LVL() and SIZ() collect several fields to cut down on number of args * for MON() @@ -436,20 +442,21 @@ NEARDATA struct permonst mons_init[] = { NO_ATTK), SIZ(1250, 250, MS_GROWL, MZ_LARGE), 0, 0, M1_HUMANOID | M1_OMNIVORE, M2_STRONG | M2_COLLECT, M3_INFRAVISIBLE | M3_INFRAVISION, 5, CLR_BROWN), - MON("dwarf lord", S_HUMANOID, LVL(4, 6, 10, 10, 5), (G_GENO | 2), + MON3("dwarf lord", "dwarf lady", "dwarf leader", + S_HUMANOID, LVL(4, 6, 10, 10, 5), (G_GENO | 2), A(ATTK(AT_WEAP, AD_PHYS, 2, 4), ATTK(AT_WEAP, AD_PHYS, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(900, 300, MS_HUMANOID, MZ_HUMAN), 0, 0, M1_TUNNEL | M1_NEEDPICK | M1_HUMANOID | M1_OMNIVORE, - M2_DWARF | M2_STRONG | M2_LORD | M2_MALE | M2_GREEDY | M2_JEWELS - | M2_COLLECT, + M2_DWARF | M2_STRONG | M2_LORD | M2_GREEDY | M2_JEWELS | M2_COLLECT, M3_INFRAVISIBLE | M3_INFRAVISION, 6, CLR_BLUE), - MON("dwarf king", S_HUMANOID, LVL(6, 6, 10, 20, 6), (G_GENO | 1), + MON3("dwarf king", "dwarf queen", "dwarf ruler", + S_HUMANOID, LVL(6, 6, 10, 20, 6), (G_GENO | 1), A(ATTK(AT_WEAP, AD_PHYS, 2, 6), ATTK(AT_WEAP, AD_PHYS, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(900, 300, MS_HUMANOID, MZ_HUMAN), 0, 0, M1_TUNNEL | M1_NEEDPICK | M1_HUMANOID | M1_OMNIVORE, - M2_DWARF | M2_STRONG | M2_PRINCE | M2_MALE | M2_GREEDY | M2_JEWELS + M2_DWARF | M2_STRONG | M2_PRINCE | M2_GREEDY | M2_JEWELS | M2_COLLECT, M3_INFRAVISIBLE | M3_INFRAVISION, 8, HI_LORD), MON("mind flayer", S_HUMANOID, LVL(9, 12, 5, 90, -8), (G_GENO | 1), @@ -547,12 +554,13 @@ NEARDATA struct permonst mons_init[] = { SIZ(450, 150, MS_ORC, MZ_SMALL), MR_POISON, 0, M1_HUMANOID | M1_POIS | M1_OMNIVORE, M2_HOSTILE | M2_COLLECT, M3_INFRAVISIBLE | M3_INFRAVISION, 2, CLR_RED), - MON("kobold lord", S_KOBOLD, LVL(2, 6, 10, 0, -4), (G_GENO | 1), + MON3("kobold lord", "kobold lady", "kobold leader", + S_KOBOLD, LVL(2, 6, 10, 0, -4), (G_GENO | 1), A(ATTK(AT_WEAP, AD_PHYS, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(500, 200, MS_ORC, MZ_SMALL), MR_POISON, 0, M1_HUMANOID | M1_POIS | M1_OMNIVORE, - M2_HOSTILE | M2_LORD | M2_MALE | M2_COLLECT, + M2_HOSTILE | M2_LORD | M2_COLLECT, M3_INFRAVISIBLE | M3_INFRAVISION, 3, HI_LORD), MON("kobold shaman", S_KOBOLD, LVL(2, 6, 6, 10, -4), (G_GENO | 1), A(ATTK(AT_MAGC, AD_SPEL, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, @@ -1020,13 +1028,15 @@ NEARDATA struct permonst mons_init[] = { M1_FLY | M1_HUMANOID | M1_SEE_INVIS, M2_NOPOLY | M2_MINION | M2_STALK | M2_STRONG | M2_NASTY | M2_COLLECT, M3_INFRAVISIBLE | M3_INFRAVISION, 19, CLR_WHITE), + /* the AD&D Monster Manual depicts ki-rin as very similar to unicorns + except that they fly (without wings) and can cast spells */ MON("ki-rin", S_ANGEL, LVL(16, 18, -5, 90, 15), (G_NOHELL | G_NOCORPSE | 1), A(ATTK(AT_KICK, AD_PHYS, 2, 4), ATTK(AT_KICK, AD_PHYS, 2, 4), ATTK(AT_BUTT, AD_PHYS, 3, 6), ATTK(AT_MAGC, AD_SPEL, 2, 6), NO_ATTK, NO_ATTK), - SIZ(WT_HUMAN, 400, MS_NEIGH, MZ_LARGE), 0, 0, - M1_FLY | M1_ANIMAL | M1_NOHANDS | M1_SEE_INVIS, + SIZ(WT_HUMAN, 400, MS_SPELL, MZ_LARGE), MR_POISON, 0, + M1_FLY | M1_NOHANDS | M1_SEE_INVIS, M2_NOPOLY | M2_MINION | M2_STALK | M2_STRONG | M2_NASTY | M2_LORD, M3_INFRAVISIBLE | M3_INFRAVISION, 21, HI_GOLD), MON("Archon", S_ANGEL, LVL(19, 16, -6, 80, 15), @@ -1357,22 +1367,24 @@ NEARDATA struct permonst mons_init[] = { SIZ(650, 100, MS_ORC, MZ_SMALL), 0, 0, M1_HUMANOID | M1_OMNIVORE, M2_NOPOLY | M2_GNOME | M2_COLLECT, M3_INFRAVISIBLE | M3_INFRAVISION, 3, CLR_BROWN), - MON("gnome lord", S_GNOME, LVL(3, 8, 10, 4, 0), (G_GENO | 2), + MON3("gnome lord", "gnome lady", "gnome leader", + S_GNOME, LVL(3, 8, 10, 4, 0), (G_GENO | 2), A(ATTK(AT_WEAP, AD_PHYS, 1, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(700, 120, MS_ORC, MZ_SMALL), 0, 0, M1_HUMANOID | M1_OMNIVORE, - M2_GNOME | M2_LORD | M2_MALE | M2_COLLECT, + M2_GNOME | M2_LORD | M2_COLLECT, M3_INFRAVISIBLE | M3_INFRAVISION, 4, CLR_BLUE), MON("gnomish wizard", S_GNOME, LVL(3, 10, 4, 10, 0), (G_GENO | 1), A(ATTK(AT_MAGC, AD_SPEL, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(700, 120, MS_ORC, MZ_SMALL), 0, 0, M1_HUMANOID | M1_OMNIVORE, M2_GNOME | M2_MAGIC, M3_INFRAVISIBLE | M3_INFRAVISION, 5, HI_ZAP), - MON("gnome king", S_GNOME, LVL(5, 10, 10, 20, 0), (G_GENO | 1), + MON3("gnome king", "gnome queen", "gnome ruler", + S_GNOME, LVL(5, 10, 10, 20, 0), (G_GENO | 1), A(ATTK(AT_WEAP, AD_PHYS, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(750, 150, MS_ORC, MZ_SMALL), 0, 0, M1_HUMANOID | M1_OMNIVORE, - M2_GNOME | M2_PRINCE | M2_MALE | M2_COLLECT, + M2_GNOME | M2_PRINCE | M2_COLLECT, M3_INFRAVISIBLE | M3_INFRAVISION, 6, HI_LORD), #ifdef SPLITMON_1 }; @@ -1679,17 +1691,19 @@ struct permonst _mons2[] = { SIZ(1600, 500, MS_GRUNT, MZ_LARGE), 0, 0, M1_HUMANOID | M1_CARNIVORE, M2_STRONG | M2_GREEDY | M2_JEWELS | M2_COLLECT, M3_INFRAVISIBLE | M3_INFRAVISION, 7, CLR_BROWN), - MON("ogre lord", S_OGRE, LVL(7, 12, 3, 30, -5), (G_GENO | 2), + MON3("ogre lord", "ogre lady", "ogre leader", + S_OGRE, LVL(7, 12, 3, 30, -5), (G_GENO | 2), A(ATTK(AT_WEAP, AD_PHYS, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1700, 700, MS_GRUNT, MZ_LARGE), 0, 0, M1_HUMANOID | M1_CARNIVORE, - M2_STRONG | M2_LORD | M2_MALE | M2_GREEDY | M2_JEWELS | M2_COLLECT, + M2_STRONG | M2_LORD | M2_GREEDY | M2_JEWELS | M2_COLLECT, M3_INFRAVISIBLE | M3_INFRAVISION, 9, CLR_RED), - MON("ogre king", S_OGRE, LVL(9, 14, 4, 60, -7), (G_GENO | 2), + MON3("ogre king", "ogre queen", "ogre tyrant", + S_OGRE, LVL(9, 14, 4, 60, -7), (G_GENO | 2), A(ATTK(AT_WEAP, AD_PHYS, 3, 5), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1700, 750, MS_GRUNT, MZ_LARGE), 0, 0, M1_HUMANOID | M1_CARNIVORE, - M2_STRONG | M2_PRINCE | M2_MALE | M2_GREEDY | M2_JEWELS | M2_COLLECT, + M2_STRONG | M2_PRINCE | M2_GREEDY | M2_JEWELS | M2_COLLECT, M3_INFRAVISIBLE | M3_INFRAVISION, 11, HI_LORD), /* * Puddings @@ -1869,14 +1883,15 @@ struct permonst _mons2[] = { M2_UNDEAD | M2_STALK | M2_HOSTILE | M2_STRONG | M2_NASTY | M2_SHAPESHIFTER, M3_INFRAVISIBLE, 12, CLR_RED), - MON("vampire lord", S_VAMPIRE, LVL(12, 14, 0, 50, -9), + MON3("vampire lord", "vampire lady", "vampire leader", + S_VAMPIRE, LVL(12, 14, 0, 50, -9), (G_GENO | G_NOCORPSE | 1), A(ATTK(AT_CLAW, AD_PHYS, 1, 8), ATTK(AT_BITE, AD_DRLI, 1, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_VAMPIRE, MZ_HUMAN), MR_SLEEP | MR_POISON, 0, M1_FLY | M1_BREATHLESS | M1_HUMANOID | M1_POIS | M1_REGEN, M2_UNDEAD | M2_STALK | M2_HOSTILE | M2_STRONG | M2_NASTY | M2_LORD - | M2_MALE | M2_SHAPESHIFTER, + | M2_SHAPESHIFTER, M3_INFRAVISIBLE, 14, CLR_BLUE), #if 0 /* DEFERRED */ MON("vampire mage", S_VAMPIRE, @@ -2185,19 +2200,21 @@ struct permonst _mons2[] = { SIZ(WT_ELF, 350, MS_HUMANOID, MZ_HUMAN), MR_SLEEP, MR_SLEEP, M1_HUMANOID | M1_OMNIVORE | M1_SEE_INVIS, M2_ELF | M2_COLLECT, M3_INFRAVISIBLE | M3_INFRAVISION, 8, CLR_GRAY), - MON("elf-lord", S_HUMAN, LVL(8, 12, 10, 20, -9), (G_GENO | G_SGROUP | 2), + MON3("elf-lord", "elf-queen", "elf-noble", + S_HUMAN, LVL(8, 12, 10, 20, -9), (G_GENO | G_SGROUP | 2), A(ATTK(AT_WEAP, AD_PHYS, 2, 4), ATTK(AT_WEAP, AD_PHYS, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_ELF, 350, MS_HUMANOID, MZ_HUMAN), MR_SLEEP, MR_SLEEP, M1_HUMANOID | M1_OMNIVORE | M1_SEE_INVIS, - M2_ELF | M2_STRONG | M2_LORD | M2_MALE | M2_COLLECT, + M2_ELF | M2_STRONG | M2_LORD | M2_COLLECT, M3_INFRAVISIBLE | M3_INFRAVISION, 11, CLR_BRIGHT_BLUE), - MON("Elvenking", S_HUMAN, LVL(9, 12, 10, 25, -10), (G_GENO | 1), + MON3("Elvenking", "Elvenqueen", "elven monarch", + S_HUMAN, LVL(9, 12, 10, 25, -10), (G_GENO | 1), A(ATTK(AT_WEAP, AD_PHYS, 2, 4), ATTK(AT_WEAP, AD_PHYS, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_ELF, 350, MS_HUMANOID, MZ_HUMAN), MR_SLEEP, MR_SLEEP, M1_HUMANOID | M1_OMNIVORE | M1_SEE_INVIS, - M2_ELF | M2_STRONG | M2_PRINCE | M2_MALE | M2_COLLECT, + M2_ELF | M2_STRONG | M2_PRINCE | M2_COLLECT, M3_INFRAVISIBLE | M3_INFRAVISION, 11, HI_LORD), MON("doppelganger", S_HUMAN, LVL(9, 12, 5, 20, 0), (G_GENO | 1), A(ATTK(AT_WEAP, AD_PHYS, 1, 12), @@ -2240,7 +2257,8 @@ struct permonst _mons2[] = { /* aligned priests always have the epri extension attached; individual instantiations should always have either ispriest or isminion set */ - MON("aligned priest", S_HUMAN, LVL(12, 12, 10, 50, 0), G_NOGEN, + MON3("priest", "priestess", "aligned cleric", + S_HUMAN, LVL(12, 12, 10, 50, 0), G_NOGEN, A(ATTK(AT_WEAP, AD_PHYS, 4, 10), ATTK(AT_KICK, AD_PHYS, 1, 4), ATTK(AT_MAGC, AD_CLRC, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_PRIEST, MZ_HUMAN), MR_ELEC, 0, @@ -2248,7 +2266,8 @@ struct permonst _mons2[] = { M2_NOPOLY | M2_HUMAN | M2_LORD | M2_PEACEFUL | M2_COLLECT, M3_INFRAVISIBLE, 15, CLR_WHITE), /* high priests always have epri and always have ispriest set */ - MON("high priest", S_HUMAN, LVL(25, 15, 7, 70, 0), (G_NOGEN | G_UNIQ), + MON3("high priest", "high priestess", "high cleric", + S_HUMAN, LVL(25, 15, 7, 70, 0), (G_NOGEN | G_UNIQ), A(ATTK(AT_WEAP, AD_PHYS, 4, 10), ATTK(AT_KICK, AD_PHYS, 2, 8), ATTK(AT_MAGC, AD_CLRC, 2, 8), ATTK(AT_MAGC, AD_CLRC, 2, 8), NO_ATTK, NO_ATTK), @@ -2390,10 +2409,12 @@ struct permonst _mons2[] = { #define SEDUCTION_ATTACKS_NO \ A(ATTK(AT_CLAW, AD_PHYS, 1, 3), ATTK(AT_CLAW, AD_PHYS, 1, 3), \ ATTK(AT_BITE, AD_DRLI, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK) - MON("succubus", S_DEMON, LVL(6, 12, 0, 70, -9), (G_NOCORPSE | 1), + /* incubus and succubus */ + MON3("incubus", "succubus", "amorous demon", + S_DEMON, LVL(6, 12, 0, 70, -9), (G_NOCORPSE | 1), SEDUCTION_ATTACKS_YES, SIZ(WT_HUMAN, 400, MS_SEDUCE, MZ_HUMAN), MR_FIRE | MR_POISON, 0, M1_HUMANOID | M1_FLY | M1_POIS, - M2_DEMON | M2_STALK | M2_HOSTILE | M2_NASTY | M2_FEMALE, + M2_DEMON | M2_STALK | M2_HOSTILE | M2_NASTY, M3_INFRAVISIBLE | M3_INFRAVISION, 8, CLR_GRAY), MON("horned devil", S_DEMON, LVL(6, 9, -5, 50, 11), (G_HELL | G_NOCORPSE | 2), @@ -2403,11 +2424,6 @@ struct permonst _mons2[] = { SIZ(WT_HUMAN, 400, MS_SILENT, MZ_HUMAN), MR_FIRE | MR_POISON, 0, M1_POIS | M1_THICK_HIDE, M2_DEMON | M2_STALK | M2_HOSTILE | M2_NASTY, M3_INFRAVISIBLE | M3_INFRAVISION, 9, CLR_BROWN), - MON("incubus", S_DEMON, LVL(6, 12, 0, 70, -9), (G_NOCORPSE | 1), - SEDUCTION_ATTACKS_YES, SIZ(WT_HUMAN, 400, MS_SEDUCE, MZ_HUMAN), - MR_FIRE | MR_POISON, 0, M1_HUMANOID | M1_FLY | M1_POIS, - M2_DEMON | M2_STALK | M2_HOSTILE | M2_NASTY | M2_MALE, - M3_INFRAVISIBLE | M3_INFRAVISION, 8, CLR_GRAY), /* Used by AD&D for a type of demon, originally one of the Furies and spelled this way */ MON("erinys", S_DEMON, LVL(7, 12, 2, 30, 10), @@ -2636,9 +2652,9 @@ struct permonst _mons2[] = { M1_SWIM | M1_AMPHIBIOUS | M1_SLITHY | M1_NOLIMBS | M1_NOHEAD | M1_NOTAKE | M1_POIS, M2_HOSTILE, 0, 5, CLR_BLUE), - MON("piranha", S_EEL, LVL(5, 12, 4, 0, 0), (G_GENO | G_NOGEN | G_SGROUP), - A(ATTK(AT_BITE, AD_PHYS, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, - NO_ATTK), + MON("piranha", S_EEL, LVL(5, 18, 4, 0, 0), (G_GENO | G_NOGEN | G_SGROUP), + A(ATTK(AT_BITE, AD_PHYS, 2, 6), ATTK(AT_BITE, AD_PHYS, 2, 6), + NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(60, 30, MS_SILENT, MZ_SMALL), 0, 0, M1_SWIM | M1_AMPHIBIOUS | M1_ANIMAL | M1_SLITHY | M1_NOLIMBS | M1_CARNIVORE | M1_OVIPAROUS | M1_NOTAKE, @@ -2755,19 +2771,13 @@ struct permonst _mons2[] = { M1_HUMANOID | M1_OMNIVORE, M2_NOPOLY | M2_HUMAN | M2_STRONG | M2_COLLECT, M3_INFRAVISIBLE, 12, HI_DOMESTIC), - MON("caveman", S_HUMAN, LVL(10, 12, 10, 0, 1), G_NOGEN, + MON3("caveman", "cavewoman", "cave dweller", + S_HUMAN, LVL(10, 12, 10, 0, 1), G_NOGEN, A(ATTK(AT_WEAP, AD_PHYS, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_HUMANOID, MZ_HUMAN), 0, 0, M1_HUMANOID | M1_OMNIVORE, - M2_NOPOLY | M2_HUMAN | M2_STRONG | M2_MALE | M2_COLLECT, - M3_INFRAVISIBLE, 12, HI_DOMESTIC), - MON("cavewoman", S_HUMAN, LVL(10, 12, 10, 0, 1), G_NOGEN, - A(ATTK(AT_WEAP, AD_PHYS, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, - NO_ATTK), - SIZ(WT_HUMAN, 400, MS_HUMANOID, MZ_HUMAN), 0, 0, - M1_HUMANOID | M1_OMNIVORE, - M2_NOPOLY | M2_HUMAN | M2_STRONG | M2_FEMALE | M2_COLLECT, + M2_NOPOLY | M2_HUMAN | M2_STRONG | M2_COLLECT, M3_INFRAVISIBLE, 12, HI_DOMESTIC), MON("healer", S_HUMAN, LVL(10, 12, 10, 1, 0), G_NOGEN, A(ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, @@ -2790,19 +2800,13 @@ struct permonst _mons2[] = { M1_HUMANOID | M1_HERBIVORE, M2_NOPOLY | M2_HUMAN | M2_STRONG | M2_COLLECT | M2_MALE, M3_INFRAVISIBLE, 11, HI_DOMESTIC), - MON("priest", S_HUMAN, LVL(10, 12, 10, 2, 0), G_NOGEN, + MON3("priest", "priestess", "cleric", + S_HUMAN, LVL(10, 12, 10, 2, 0), G_NOGEN, A(ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, MS_HUMANOID, MZ_HUMAN), 0, 0, M1_HUMANOID | M1_OMNIVORE, - M2_NOPOLY | M2_HUMAN | M2_STRONG | M2_MALE | M2_COLLECT, - M3_INFRAVISIBLE, 12, HI_DOMESTIC), - MON("priestess", S_HUMAN, LVL(10, 12, 10, 2, 0), G_NOGEN, - A(ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, - NO_ATTK), - SIZ(WT_HUMAN, 400, MS_HUMANOID, MZ_HUMAN), 0, 0, - M1_HUMANOID | M1_OMNIVORE, - M2_NOPOLY | M2_HUMAN | M2_STRONG | M2_FEMALE | M2_COLLECT, + M2_NOPOLY | M2_HUMAN | M2_STRONG | M2_COLLECT, M3_INFRAVISIBLE, 12, HI_DOMESTIC), MON("ranger", S_HUMAN, LVL(10, 12, 10, 2, -3), G_NOGEN, A(ATTK(AT_WEAP, AD_PHYS, 1, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, diff --git a/src/mplayer.c b/src/mplayer.c index 13a44ed35..78f8f84f3 100644 --- a/src/mplayer.c +++ b/src/mplayer.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 mplayer.c $NHDT-Date: 1550524564 2019/02/18 21:16:04 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.26 $ */ +/* NetHack 3.7 mplayer.c $NHDT-Date: 1596498188 2020/08/03 23:43:08 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.30 $ */ /* Copyright (c) Izchak Miller, 1992. */ /* NetHack may be freely redistributed. See license for details. */ @@ -53,7 +53,8 @@ dev_name() for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (!is_mplayer(mtmp->data)) continue; - if (!strncmp(developers[i], (has_mname(mtmp)) ? MNAME(mtmp) : "", + if (!strncmp(developers[i], + (has_mgivenname(mtmp)) ? MGIVENNAME(mtmp) : "", strlen(developers[i]))) { match = TRUE; break; @@ -176,8 +177,7 @@ register boolean special; if (helm == HELM_OF_BRILLIANCE) helm = STRANGE_OBJECT; break; - case PM_CAVEMAN: - case PM_CAVEWOMAN: + case PM_CAVE_DWELLER: if (rn2(4)) weapon = MACE; else if (rn2(2)) @@ -208,8 +208,7 @@ register boolean special; if (rn2(2)) shield = STRANGE_OBJECT; break; - case PM_PRIEST: - case PM_PRIESTESS: + case PM_CLERIC: if (rn2(2)) weapon = MACE; if (rn2(2)) diff --git a/src/mthrowu.c b/src/mthrowu.c index e7340a04b..bba8fd939 100644 --- a/src/mthrowu.c +++ b/src/mthrowu.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 mthrowu.c $NHDT-Date: 1586567393 2020/04/11 01:09:53 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.99 $ */ +/* NetHack 3.7 mthrowu.c $NHDT-Date: 1605315160 2020/11/14 00:52:40 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.103 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Pasi Kallinen, 2016. */ /* NetHack may be freely redistributed. See license for details. */ @@ -345,7 +345,8 @@ boolean verbose; /* give message(s) even when you can't see what happened */ if (vis) { if (otmp->otyp == EGG) pline("Splat! %s is hit with %s egg!", Monnam(mtmp), - otmp->known ? an(mons[otmp->corpsenm].mname) : "an"); + otmp->known ? an(mons[otmp->corpsenm].pmnames[NEUTRAL]) + : "an"); else hit(distant_name(otmp, mshot_xname), mtmp, exclam(damage)); } else if (verbose && !g.mtarget) @@ -395,8 +396,8 @@ boolean verbose; /* give message(s) even when you can't see what happened */ } } if (otmp->otyp == EGG && touch_petrifies(&mons[otmp->corpsenm])) { - if (!munstone(mtmp, TRUE)) - minstapetrify(mtmp, TRUE); + if (!munstone(mtmp, FALSE)) + minstapetrify(mtmp, FALSE); if (resists_ston(mtmp)) damage = 0; } @@ -425,7 +426,14 @@ boolean verbose; /* give message(s) even when you can't see what happened */ : AT_WEAP), otmp)) { if (vis && mtmp->mcansee) - pline("%s is blinded by %s.", Monnam(mtmp), the(xname(otmp))); + /* shorten object name to reduce redundancy in the + two message [first via hit() above] sequence: + "The {splash of venom,cream pie} hits ." + " is blinded by the {venom,pie}." */ + pline("%s is blinded by %s.", Monnam(mtmp), + the((otmp->oclass == VENOM_CLASS) ? "venom" + : (otmp->otyp == CREAM_PIE) ? "pie" + : xname(otmp))); /* catchall; not used */ mtmp->mcansee = 0; tmp = (int) mtmp->mblinded + rnd(25) + 20; if (tmp > 127) @@ -697,13 +705,13 @@ struct monst *mtmp, *mtarg; mtmp->weapon_check = NEED_RANGED_WEAPON; /* mon_wield_item resets weapon_check as appropriate */ if (mon_wield_item(mtmp) != 0) - return 0; + return MM_MISS; } /* Pick a weapon */ otmp = select_rwep(mtmp); if (!otmp) - return 0; + return MM_MISS; ispole = is_pole(otmp); x = mtmp->mx; @@ -718,17 +726,17 @@ struct monst *mtmp, *mtarg; if (ammo_and_launcher(otmp, mwep) && dist2(mtmp->mx, mtmp->my, mtarg->mx, mtarg->my) > PET_MISSILE_RANGE2) - return 0; /* Out of range */ + return MM_MISS; /* Out of range */ /* Set target monster */ g.mtarget = mtarg; g.marcher = mtmp; monshoot(mtmp, otmp, mwep); /* multishot shooting or throwing */ g.marcher = g.mtarget = (struct monst *) 0; nomul(0); - return 1; + return MM_HIT; } } - return 0; + return MM_MISS; } /* monster spits substance at monster */ @@ -743,27 +751,32 @@ struct attack *mattk; if (!Deaf) pline("A dry rattle comes from %s throat.", s_suffix(mon_nam(mtmp))); - return 0; + return MM_MISS; } if (m_lined_up(mtarg, mtmp)) { + boolean utarg = (mtarg == &g.youmonst); + xchar tx = utarg ? mtmp->mux : mtarg->mx; + xchar ty = utarg ? mtmp->muy : mtarg->my; + switch (mattk->adtyp) { case AD_BLND: case AD_DRST: otmp = mksobj(BLINDING_VENOM, TRUE, FALSE); break; default: - impossible("bad attack type in spitmu"); + impossible("bad attack type in spitmm"); /*FALLTHRU*/ case AD_ACID: otmp = mksobj(ACID_VENOM, TRUE, FALSE); break; } - if (!rn2(BOLT_LIM-distmin(mtmp->mx,mtmp->my,mtarg->mx,mtarg->my))) { + if (!rn2(BOLT_LIM-distmin(mtmp->mx,mtmp->my,tx,ty))) { if (canseemon(mtmp)) pline("%s spits venom!", Monnam(mtmp)); - g.mtarget = mtarg; + if (!utarg) + g.mtarget = mtarg; m_throw(mtmp, mtmp->mx, mtmp->my, sgn(g.tbx), sgn(g.tby), - distmin(mtmp->mx,mtmp->my,mtarg->mx,mtarg->my), otmp); + distmin(mtmp->mx,mtmp->my,tx,ty), otmp); g.mtarget = (struct monst *)0; nomul(0); @@ -777,10 +790,13 @@ struct attack *mattk; dog->hungrytime -= 5; } - return 1; + return MM_HIT; + } else { + obj_extract_self(otmp); + obfree(otmp, (struct obj *) 0); } } - return 0; + return MM_MISS; } /* monster breathes at monster (ranged) */ @@ -800,7 +816,7 @@ struct attack *mattk; else You_hear("a cough."); } - return 0; + return MM_MISS; } if (!mtmp->mspec_used && rn2(3)) { if ((typ >= AD_MAGM) && (typ <= AD_ACID)) { @@ -829,9 +845,9 @@ struct attack *mattk; } } else impossible("Breath weapon %d used", typ-1); } else - return 0; + return MM_MISS; } - return 1; + return MM_HIT; } @@ -942,41 +958,7 @@ spitmu(mtmp, mattk) struct monst *mtmp; struct attack *mattk; { - struct obj *otmp; - - if (mtmp->mcan) { - if (!Deaf) - pline("A dry rattle comes from %s throat.", - s_suffix(mon_nam(mtmp))); - return 0; - } - if (lined_up(mtmp)) { - switch (mattk->adtyp) { - case AD_BLND: - case AD_DRST: - otmp = mksobj(BLINDING_VENOM, TRUE, FALSE); - break; - default: - impossible("bad attack type in spitmu"); - /* fall through */ - case AD_ACID: - otmp = mksobj(ACID_VENOM, TRUE, FALSE); - break; - } - if (!rn2(BOLT_LIM - - distmin(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy))) { - if (canseemon(mtmp)) - pline("%s spits venom!", Monnam(mtmp)); - m_throw(mtmp, mtmp->mx, mtmp->my, sgn(g.tbx), sgn(g.tby), - distmin(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy), otmp); - nomul(0); - return 0; - } else { - obj_extract_self(otmp); - obfree(otmp, (struct obj *) 0); - } - } - return 0; + return spitmm(mtmp, mattk, &g.youmonst); } /* monster breathes at you (ranged) */ @@ -988,6 +970,43 @@ struct attack *mattk; return breamm(mtmp, mattk, &g.youmonst); } +/* Move from (ax,ay) to (bx,by), but only if distance is up to BOLT_LIM + and only in straight line or diagonal, calling fnc for each step. + Stops if fnc return TRUE, or if step was blocked by wall or closed door. + Returns TRUE if fnc returned TRUE. */ +boolean +linedup_callback(ax, ay, bx, by, fnc) +xchar ax, ay, bx, by; +boolean FDECL((*fnc), (int, int)); +{ + int dx, dy; + + /* These two values are set for use after successful return. */ + g.tbx = ax - bx; + g.tby = ay - by; + + /* sometimes displacement makes a monster think that you're at its + own location; prevent it from throwing and zapping in that case */ + if (!g.tbx && !g.tby) + return FALSE; + + if ((!g.tbx || !g.tby || abs(g.tbx) == abs(g.tby)) /* straight line or diagonal */ + && distmin(g.tbx, g.tby, 0, 0) < BOLT_LIM) { + dx = sgn(ax - bx), dy = sgn(ay - by); + do { + /* is guaranteed to eventually converge with */ + bx += dx, by += dy; + if (!isok(bx, by)) + return FALSE; + if (IS_ROCK(levl[bx][by].typ) || closed_door(bx, by)) + return FALSE; + if ((*fnc)(bx, by)) + return TRUE; + } while (bx != ax || by != ay); + } + return FALSE; +} + boolean linedup(ax, ay, bx, by, boulderhandling) register xchar ax, ay, bx, by; diff --git a/src/muse.c b/src/muse.c index b0ff3427a..91aaa9c8e 100644 --- a/src/muse.c +++ b/src/muse.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 muse.c $NHDT-Date: 1590870788 2020/05/30 20:33:08 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.127 $ */ +/* NetHack 3.7 muse.c $NHDT-Date: 1607734843 2020/12/12 01:00:43 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.136 $ */ /* Copyright (C) 1990 by Ken Arromdee */ /* NetHack may be freely redistributed. See license for details. */ @@ -20,6 +20,8 @@ static void FDECL(mplayhorn, (struct monst *, struct obj *, BOOLEAN_P)); static void FDECL(mreadmsg, (struct monst *, struct obj *)); static void FDECL(mquaffmsg, (struct monst *, struct obj *)); static boolean FDECL(m_use_healing, (struct monst *)); +static boolean FDECL(linedup_chk_corpse, (int, int)); +static void FDECL(m_use_undead_turning, (struct monst *, struct obj *)); static int FDECL(mbhitm, (struct monst *, struct obj *)); static void FDECL(mbhit, (struct monst *, int, int FDECL((*), (MONST_P, OBJ_P)), @@ -28,7 +30,9 @@ static struct permonst *FDECL(muse_newcham_mon, (struct monst *)); static int FDECL(mloot_container, (struct monst *mon, struct obj *, BOOLEAN_P)); static void FDECL(you_aggravate, (struct monst *)); +#if 0 static boolean FDECL(necrophiliac, (struct obj *, BOOLEAN_P)); +#endif static void FDECL(mon_consume_unstone, (struct monst *, struct obj *, BOOLEAN_P, BOOLEAN_P)); static boolean FDECL(cures_stoning, (struct monst *, struct obj *, @@ -57,11 +61,9 @@ struct obj *obj; if (obj->oclass == POTION_CLASS) { coord cc; static const char *empty = "The potion turns out to be empty."; - const char *potion_descr; struct monst *mtmp; - potion_descr = OBJ_DESCR(objects[obj->otyp]); - if (potion_descr && !strcmp(potion_descr, "milky")) { + if (objdescr_is(obj, "milky")) { if (!(g.mvitals[PM_GHOST].mvflags & G_GONE) && !rn2(POTION_OCCUPANT_CHANCE(g.mvitals[PM_GHOST].born))) { if (!enexto(&cc, mon->mx, mon->my, &mons[PM_GHOST])) @@ -87,7 +89,7 @@ struct obj *obj; return 2; } } - if (potion_descr && !strcmp(potion_descr, "smoky") + if (objdescr_is(obj, "smoky") && !(g.mvitals[PM_DJINNI].mvflags & G_GONE) && !rn2(POTION_OCCUPANT_CHANCE(g.mvitals[PM_DJINNI].born))) { if (!enexto(&cc, mon->mx, mon->my, &mons[PM_DJINNI])) @@ -185,6 +187,8 @@ struct monst *mtmp; struct obj *otmp; boolean self; { + char *objnamp, objbuf[BUFSZ]; + if (!canseemon(mtmp)) { int range = couldsee(mtmp->mx, mtmp->my) /* 9 or 5 */ ? (BOLT_LIM + 1) : (BOLT_LIM - 3); @@ -193,9 +197,7 @@ boolean self; (distu(mtmp->mx, mtmp->my) <= range * range) ? "nearby" : "in the distance"); otmp->known = 0; /* hero doesn't know how many charges are left */ - } else { - char *objnamp, objbuf[BUFSZ]; - + } else if (self) { otmp->dknown = 1; objnamp = xname(otmp); if (strlen(objnamp) >= QBUFSZ) @@ -204,8 +206,17 @@ boolean self; /* " plays a directed at himself!" */ pline("%s!", monverbself(mtmp, Monnam(mtmp), "play", objbuf)); makeknown(otmp->otyp); /* (wands handle this slightly differently) */ - if (!self) - stop_occupation(); + } else { + otmp->dknown = 1; + objnamp = xname(otmp); + if (strlen(objnamp) >= QBUFSZ) + objnamp = simpleonames(otmp); + pline("%s %s %s directed at you!", + /* monverbself() would adjust the verb if hallucination made + subject plural; stick with singular here, at least for now */ + Monnam(mtmp), "plays", an(objnamp)); + makeknown(otmp->otyp); + stop_occupation(); } otmp->spe -= 1; /* use a charge */ } @@ -230,7 +241,7 @@ struct obj *otmp; saverole = Role_switch; if (!vismon) { otmp->bknown = 0; - if (Role_if(PM_PRIEST)) + if (Role_if(PM_CLERIC)) Role_switch = 0; } Strcpy(onambuf, singular(otmp, doname)); @@ -324,11 +335,15 @@ boolean find_defensive(mtmp) struct monst *mtmp; { - register struct obj *obj = 0; + struct obj *obj; struct trap *t; int fraction, x = mtmp->mx, y = mtmp->my; boolean stuck = (mtmp == u.ustuck), immobile = (mtmp->data->mmove == 0); + stairway *stway; + + g.m.defensive = (struct obj *) 0; + g.m.has_defense = 0; if (is_animal(mtmp->data) || mindless(mtmp->data)) return FALSE; @@ -337,19 +352,25 @@ struct monst *mtmp; if (u.uswallow && stuck) return FALSE; - g.m.defensive = (struct obj *) 0; - g.m.has_defense = 0; - - /* since unicorn horns don't get used up, the monster would look - * silly trying to use the same cursed horn round after round + /* + * Since unicorn horns don't get used up, the monster would look + * silly trying to use the same cursed horn round after round, + * so skip cursed unicorn horns. + * + * Unicorns use their own horns; they're excluded from inventory + * scanning by nohands(). Ki-rin is depicted in the AD&D Monster + * Manual with same horn as a unicorn, so let it use its horn too. + * is_unicorn() doesn't include it; the class differs and it has + * no interest in gems. */ if (mtmp->mconf || mtmp->mstun || !mtmp->mcansee) { - if (!is_unicorn(mtmp->data) && !nohands(mtmp->data)) { + obj = 0; + if (!nohands(mtmp->data)) { for (obj = mtmp->minvent; obj; obj = obj->nobj) if (obj->otyp == UNICORN_HORN && !obj->cursed) break; } - if (obj || is_unicorn(mtmp->data)) { + if (obj || is_unicorn(mtmp->data) || mtmp->data == &mons[PM_KI_RIN]) { g.m.defensive = obj; g.m.has_defense = MUSE_UNICORN_HORN; return TRUE; @@ -425,23 +446,25 @@ struct monst *mtmp; if (stuck || immobile) { ; /* fleeing by stairs or traps is not possible */ } else if (levl[x][y].typ == STAIRS) { - if (x == xdnstair && y == ydnstair) { + stway = stairway_at(x,y); + if (stway && !stway->up && stway->tolev.dnum == u.uz.dnum) { if (!is_floater(mtmp->data)) g.m.has_defense = MUSE_DOWNSTAIRS; - } else if (x == xupstair && y == yupstair) { + } else if (stway && stway->up && stway->tolev.dnum == u.uz.dnum) { g.m.has_defense = MUSE_UPSTAIRS; - } else if (g.sstairs.sx && x == g.sstairs.sx && y == g.sstairs.sy) { - if (g.sstairs.up || !is_floater(mtmp->data)) + } else if (stway && stway->tolev.dnum != u.uz.dnum) { + if (stway->up || !is_floater(mtmp->data)) g.m.has_defense = MUSE_SSTAIRS; } } else if (levl[x][y].typ == LADDER) { - if (x == xupladder && y == yupladder) { + stway = stairway_at(x,y); + if (stway && stway->up && stway->tolev.dnum == u.uz.dnum) { g.m.has_defense = MUSE_UP_LADDER; - } else if (x == xdnladder && y == ydnladder) { + } else if (stway && !stway->up && stway->tolev.dnum == u.uz.dnum) { if (!is_floater(mtmp->data)) g.m.has_defense = MUSE_DN_LADDER; - } else if (g.sstairs.sx && x == g.sstairs.sx && y == g.sstairs.sy) { - if (g.sstairs.up || !is_floater(mtmp->data)) + } else if (stway && stway->tolev.dnum != u.uz.dnum) { + if (stway->up || !is_floater(mtmp->data)) g.m.has_defense = MUSE_SSTAIRS; } } else { @@ -646,6 +669,7 @@ struct monst *mtmp; struct obj *otmp = g.m.defensive; boolean vis, vismon, oseen; const char *Mnam; + stairway *stway; if ((i = precheck(mtmp, otmp)) != 0) return i; @@ -763,8 +787,7 @@ struct monst *mtmp; if (IS_FURNITURE(levl[mtmp->mx][mtmp->my].typ) || IS_DRAWBRIDGE(levl[mtmp->mx][mtmp->my].typ) || (is_drawbridge_wall(mtmp->mx, mtmp->my) >= 0) - || (g.sstairs.sx && g.sstairs.sx == mtmp->mx - && g.sstairs.sy == mtmp->my)) { + || stairway_at(mtmp->mx, mtmp->my)) { pline_The("digging ray is ineffective."); return 2; } @@ -886,6 +909,9 @@ struct monst *mtmp; return 2; case MUSE_UPSTAIRS: m_flee(mtmp); + stway = stairway_at(mtmp->mx, mtmp->my); + if (!stway) + return 0; if (ledger_no(&u.uz) == 1) goto escape; /* impossible; level 1 upstairs are SSTAIRS */ if (Inhell && mon_has_amulet(mtmp) && !rn2(4) @@ -903,33 +929,45 @@ struct monst *mtmp; } else { if (vismon) pline("%s escapes upstairs!", Monnam(mtmp)); - migrate_to_level(mtmp, ledger_no(&u.uz) - 1, MIGR_STAIRS_DOWN, + migrate_to_level(mtmp, ledger_no(&(stway->tolev)), MIGR_STAIRS_DOWN, (coord *) 0); } return 2; case MUSE_DOWNSTAIRS: m_flee(mtmp); + stway = stairway_at(mtmp->mx, mtmp->my); + if (!stway) + return 0; if (vismon) pline("%s escapes downstairs!", Monnam(mtmp)); - migrate_to_level(mtmp, ledger_no(&u.uz) + 1, MIGR_STAIRS_UP, + migrate_to_level(mtmp, ledger_no(&(stway->tolev)), MIGR_STAIRS_UP, (coord *) 0); return 2; case MUSE_UP_LADDER: m_flee(mtmp); + stway = stairway_at(mtmp->mx, mtmp->my); + if (!stway) + return 0; if (vismon) pline("%s escapes up the ladder!", Monnam(mtmp)); - migrate_to_level(mtmp, ledger_no(&u.uz) - 1, MIGR_LADDER_DOWN, + migrate_to_level(mtmp, ledger_no(&(stway->tolev)), MIGR_LADDER_DOWN, (coord *) 0); return 2; case MUSE_DN_LADDER: m_flee(mtmp); + stway = stairway_at(mtmp->mx, mtmp->my); + if (!stway) + return 0; if (vismon) pline("%s escapes down the ladder!", Monnam(mtmp)); - migrate_to_level(mtmp, ledger_no(&u.uz) + 1, MIGR_LADDER_UP, + migrate_to_level(mtmp, ledger_no(&(stway->tolev)), MIGR_LADDER_UP, (coord *) 0); return 2; case MUSE_SSTAIRS: m_flee(mtmp); + stway = stairway_at(mtmp->mx, mtmp->my); + if (!stway) + return 0; if (ledger_no(&u.uz) == 1) { escape: /* Monsters without the Amulet escape the dungeon and @@ -938,8 +976,12 @@ struct monst *mtmp; * (mongone -> mdrop_special_objs) but we force any * monster who manages to acquire it or the invocation * tools to stick around instead of letting it escape. + * Don't let the Wizard escape even when not carrying + * anything of interest unless there are more than 1 + * of him. */ - if (mon_has_special(mtmp)) + if (mon_has_special(mtmp) + || (mtmp->iswiz && g.context.no_of_wizards < 2)) return 0; if (vismon) pline("%s escapes the dungeon!", Monnam(mtmp)); @@ -948,12 +990,12 @@ struct monst *mtmp; } if (vismon) pline("%s escapes %sstairs!", Monnam(mtmp), - g.sstairs.up ? "up" : "down"); + stway->up ? "up" : "down"); /* going from the Valley to Castle (Stronghold) has no sstairs to target, but having g.sstairs. == <0,0> will work the same as specifying MIGR_RANDOM when mon_arrive() eventually places the monster, so we can use MIGR_SSTAIRS unconditionally */ - migrate_to_level(mtmp, ledger_no(&g.sstairs.tolev), MIGR_SSTAIRS, + migrate_to_level(mtmp, ledger_no(&(stway->tolev)), MIGR_SSTAIRS, (coord *) 0); return 2; case MUSE_TELEPORT_TRAP: @@ -1096,6 +1138,60 @@ struct monst *mtmp; /*#define MUSE_WAN_UNDEAD_TURNING 20*/ /* also a defensive item so don't * redefine; nonconsecutive value is ok */ +static boolean +linedup_chk_corpse(x, y) +int x, y; +{ + return (sobj_at(CORPSE, x, y) != 0); +} + +static void +m_use_undead_turning(mtmp, obj) +struct monst *mtmp; +struct obj *obj; +{ + int ax = u.ux + sgn(mtmp->mux - mtmp->mx) * 3, + ay = u.uy + sgn(mtmp->muy - mtmp->my) * 3; + int bx = mtmp->mx, by = mtmp->my; + + if (!(obj->otyp == WAN_UNDEAD_TURNING && obj->spe > 0)) + return; + + /* not necrophiliac(); unlike deciding whether to pick this + type of wand up, we aren't interested in corpses within + carried containers until they're moved into open inventory; + we don't check whether hero is poly'd into an undead--the + wand's turning effect is too weak to be a useful direct + attack--only whether hero is carrying at least one corpse */ + if (carrying(CORPSE)) { + /* + * Hero is carrying one or more corpses but isn't wielding + * a cockatrice corpse (unless being hit by one won't do + * the monster much harm); otherwise we'd be using this wand + * as a defensive item with higher priority. + * + * Might be cockatrice intended as a weapon (or being denied + * to glove-wearing monsters for use as a weapon) or lizard + * intended as a cure or lichen intended as veggy food or + * sacrifice fodder being lugged to an altar. Zapping with + * this will deprive hero of one from each stack although + * they might subsequently be recovered after killing again. + * In the sacrifice fodder case, it could even be to the + * player's advantage (fresher corpse if a new one gets + * dropped; player might not choose to spend a wand charge + * on that when/if hero acquires this wand). + */ + g.m.offensive = obj; + g.m.has_offense = MUSE_WAN_UNDEAD_TURNING; + } else if (linedup_callback(ax, ay, bx, by, linedup_chk_corpse)) { + /* There's a corpse on the ground in a direct line from the + * monster to the hero, and up to 3 steps beyond. + */ + g.m.offensive = obj; + g.m.has_offense = MUSE_WAN_UNDEAD_TURNING; + } +} + /* Select an offensive item/action for a monster. Returns TRUE iff one is * found. */ @@ -1170,34 +1266,7 @@ struct monst *mtmp; } } nomore(MUSE_WAN_UNDEAD_TURNING); - if (obj->otyp == WAN_UNDEAD_TURNING && obj->spe > 0 - /* not necrophiliac(); unlike deciding whether to pick this - type of wand up, we aren't interested in corpses within - carried containers until they're moved into open inventory; - we don't check whether hero is poly'd into an undead--the - wand's turning effect is too weak to be a useful direct - attack--only whether hero is carrying at least one corpse */ - && carrying(CORPSE)) { - /* - * Hero is carrying one or more corpses but isn't wielding - * a cockatrice corpse (unless being hit by one won't do - * the monster much harm); otherwise we'd be using this wand - * as a defensive item with higher priority. - * - * Might be cockatrice intended as a weapon (or being denied - * to glove-wearing monsters for use as a weapon) or lizard - * intended as a cure or lichen intended as veggy food or - * sacrifice fodder being lugged to an altar. Zapping with - * this will deprive hero of one from each stack although - * they might subsequently be recovered after killing again. - * In the sacrifice fodder case, it could even be to the - * player's advantage (fresher corpse if a new one gets - * dropped; player might not choose to spend a wand charge - * on that when/if hero acquires this wand). - */ - g.m.offensive = obj; - g.m.has_offense = MUSE_WAN_UNDEAD_TURNING; - } + m_use_undead_turning(mtmp, obj); nomore(MUSE_WAN_STRIKING); if (obj->otyp == WAN_STRIKING && obj->spe > 0) { g.m.offensive = obj; @@ -1212,11 +1281,7 @@ struct monst *mtmp; && !Teleport_control /* do try to move hero to a more vulnerable spot */ && (onscary(u.ux, u.uy, mtmp) - || (u.ux == xupstair && u.uy == yupstair) - || (u.ux == xdnstair && u.uy == ydnstair) - || (u.ux == g.sstairs.sx && u.uy == g.sstairs.sy) - || (u.ux == xupladder && u.uy == yupladder) - || (u.ux == xdnladder && u.uy == ydnladder))) { + || (stairway_at(u.ux, u.uy))) { g.m.offensive = obj; g.m.has_offense = MUSE_WAN_TELEPORTATION; } @@ -1590,6 +1655,7 @@ struct monst *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); + ignite_items(mtmp->minvent); num = (2 * (rn1(3, 3) + 2 * bcsign(otmp)) + 1) / 3; if (Fire_resistance) You("are not harmed."); @@ -2257,6 +2323,7 @@ struct monst *mtmp; return 0; } +#if 0 /* check whether hero is carrying a corpse or contained petrifier corpse */ static boolean necrophiliac(objlist, any_corpse) @@ -2273,6 +2340,7 @@ boolean any_corpse; } return FALSE; } +#endif boolean searches_for_item(mon, obj) @@ -2307,11 +2375,9 @@ struct obj *obj; if (typ == WAN_POLYMORPH) return (boolean) (mons[monsndx(mon->data)].difficulty < 6); if (objects[typ].oc_dir == RAY || typ == WAN_STRIKING + || typ == WAN_UNDEAD_TURNING || typ == WAN_TELEPORTATION || typ == WAN_CREATE_MONSTER) return TRUE; - if (typ == WAN_UNDEAD_TURNING) - return (necrophiliac(g.invent, TRUE) - || (Upolyd && is_undead(g.youmonst.data))); break; case POTION_CLASS: if (typ == POT_HEALING || typ == POT_EXTRA_HEALING @@ -2337,10 +2403,12 @@ struct obj *obj; if (typ == PICK_AXE) return (boolean) needspick(mon->data); if (typ == UNICORN_HORN) - return (boolean) (!obj->cursed && !is_unicorn(mon->data)); + return (boolean) (!obj->cursed && !is_unicorn(mon->data) + && mon->data != &mons[PM_KI_RIN]); if (typ == FROST_HORN || typ == FIRE_HORN) return (obj->spe > 0 && can_blow(mon)); - if (Is_container(obj) && !(Is_mbag(obj) && obj->cursed)) + if (Is_container(obj) && !(Is_mbag(obj) && obj->cursed) + && !obj->olocked) return TRUE; break; case FOOD_CLASS: @@ -2821,7 +2889,9 @@ struct monst *mon; return (ptr->mcolor == CLR_GREEN || ptr->mcolor == CLR_BRIGHT_GREEN); #endif /* approximation */ - if (strstri(ptr->mname, "green")) + if (strstri(ptr->pmnames[NEUTRAL], "green") + || (ptr->pmnames[MALE] && strstri(ptr->pmnames[MALE], "green")) + || (ptr->pmnames[FEMALE] && strstri(ptr->pmnames[FEMALE], "green"))) return TRUE; switch (monsndx(ptr)) { case PM_FOREST_CENTAUR: diff --git a/src/music.c b/src/music.c index 86a49b85a..3dc60efc3 100644 --- a/src/music.c +++ b/src/music.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 music.c $NHDT-Date: 1578252632 2020/01/05 19:30:32 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.67 $ */ +/* NetHack 3.7 music.c $NHDT-Date: 1596498191 2020/08/03 23:43:11 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.69 $ */ /* Copyright (c) 1989 by Jean-Christophe Collet */ /* NetHack may be freely redistributed. See license for details. */ @@ -387,7 +387,7 @@ int force; You("destroy %s!", mtmp->mtame ? x_monnam(mtmp, ARTICLE_THE, "poor", - has_mname(mtmp) + has_mgivenname(mtmp) ? SUPPRESS_SADDLE : 0, FALSE) : mon_nam(mtmp)); diff --git a/src/nhlobj.c b/src/nhlobj.c index ca9567d8d..03e07401d 100644 --- a/src/nhlobj.c +++ b/src/nhlobj.c @@ -318,7 +318,8 @@ lua_State *L; if (obj->corpsenm != NON_PM && (obj->otyp == TIN || obj->otyp == CORPSE || obj->otyp == EGG || obj->otyp == FIGURINE || obj->otyp == STATUE)) - nhl_add_table_entry_str(L, "corpsenm_name", mons[obj->corpsenm].mname); + nhl_add_table_entry_str(L, "corpsenm_name", + mons[obj->corpsenm].pmnames[NEUTRAL]); /* TODO: leashmon, fromsink, novelidx, record_achieve_special */ nhl_add_table_entry_int(L, "usecount", obj->usecount); /* TODO: spestudied */ diff --git a/src/nhlsel.c b/src/nhlsel.c index 26edad483..bfe09db3e 100644 --- a/src/nhlsel.c +++ b/src/nhlsel.c @@ -14,7 +14,7 @@ static int FDECL(l_selection_not, (lua_State *)); static int FDECL(l_selection_filter_percent, (lua_State *)); static int FDECL(l_selection_rndcoord, (lua_State *)); static boolean FDECL(params_sel_2coords, (lua_State *, struct selectionvar **, - schar *, schar *, schar *, schar *)); + xchar *, xchar *, xchar *, xchar *)); static int FDECL(l_selection_line, (lua_State *)); static int FDECL(l_selection_randline, (lua_State *)); static int FDECL(l_selection_rect, (lua_State *)); @@ -143,7 +143,7 @@ l_selection_setpoint(L) lua_State *L; { struct selectionvar *sel = (struct selectionvar *) 0; - schar x = -1, y = -1; + xchar x = -1, y = -1; int val = 1; int argc = lua_gettop(L); long crd = 0L; @@ -153,15 +153,15 @@ lua_State *L; } else if (argc == 1) { sel = l_selection_check(L, 1); } else if (argc == 2) { - x = (schar) luaL_checkinteger(L, 1); - y = (schar) luaL_checkinteger(L, 2); + x = (xchar) luaL_checkinteger(L, 1); + y = (xchar) luaL_checkinteger(L, 2); lua_pop(L, 2); (void) l_selection_new(L); sel = l_selection_check(L, 1); } else { sel = l_selection_check(L, 1); - x = (schar) luaL_checkinteger(L, 2); - y = (schar) luaL_checkinteger(L, 3); + x = (xchar) luaL_checkinteger(L, 2); + y = (xchar) luaL_checkinteger(L, 3); val = (int) luaL_optinteger(L, 4, 1); } @@ -188,8 +188,8 @@ l_selection_getpoint(L) lua_State *L; { struct selectionvar *sel = l_selection_check(L, 1); - schar x = (schar) luaL_checkinteger(L, 2); - schar y = (schar) luaL_checkinteger(L, 3); + xchar x = (xchar) luaL_checkinteger(L, 2); + xchar y = (xchar) luaL_checkinteger(L, 3); int val; long crd; @@ -318,7 +318,7 @@ lua_State *L; { struct selectionvar *sel = l_selection_check(L, 1); int removeit = (int) luaL_optinteger(L, 2, 0); - schar x, y; + xchar x, y; selection_rndcoord(sel, &x, &y, removeit); update_croom(); if (g.coder && g.coder->croom) { @@ -344,16 +344,16 @@ static boolean params_sel_2coords(L, sel, x1,y1, x2,y2) lua_State *L; struct selectionvar **sel; -schar *x1, *y1, *x2, *y2; +xchar *x1, *y1, *x2, *y2; { int argc = lua_gettop(L); if (argc == 4) { (void) l_selection_new(L); - *x1 = (schar) luaL_checkinteger(L, 1); - *y1 = (schar) luaL_checkinteger(L, 2); - *x2 = (schar) luaL_checkinteger(L, 3); - *y2 = (schar) luaL_checkinteger(L, 4); + *x1 = (xchar) luaL_checkinteger(L, 1); + *y1 = (xchar) luaL_checkinteger(L, 2); + *x2 = (xchar) luaL_checkinteger(L, 3); + *y2 = (xchar) luaL_checkinteger(L, 4); *sel = l_selection_check(L, 5); lua_remove(L, 1); lua_remove(L, 1); @@ -362,10 +362,10 @@ schar *x1, *y1, *x2, *y2; return TRUE; } else if (argc == 5) { *sel = l_selection_check(L, 1); - *x1 = (schar) luaL_checkinteger(L, 2); - *y1 = (schar) luaL_checkinteger(L, 3); - *x2 = (schar) luaL_checkinteger(L, 4); - *y2 = (schar) luaL_checkinteger(L, 5); + *x1 = (xchar) luaL_checkinteger(L, 2); + *y1 = (xchar) luaL_checkinteger(L, 3); + *x2 = (xchar) luaL_checkinteger(L, 4); + *y2 = (xchar) luaL_checkinteger(L, 5); lua_pop(L, 4); return TRUE; } @@ -380,10 +380,7 @@ l_selection_line(L) lua_State *L; { struct selectionvar *sel = NULL; - schar x1; - schar y1; - schar x2; - schar y2; + xchar x1, y1, x2, y2; if (!params_sel_2coords(L, &sel, &x1, &y1, &x2, &y2)) { nhl_error(L, "selection.line: illegal arguments"); @@ -404,10 +401,7 @@ l_selection_rect(L) lua_State *L; { struct selectionvar *sel = NULL; - schar x1; - schar y1; - schar x2; - schar y2; + xchar x1, y1, x2, y2; if (!params_sel_2coords(L, &sel, &x1, &y1, &x2, &y2)) { nhl_error(L, "selection.rect: illegal arguments"); @@ -437,10 +431,7 @@ lua_State *L; { struct selectionvar *sel = NULL; int y; - schar x1; - schar y1; - schar x2; - schar y2; + xchar x1, y1, x2, y2; if (!params_sel_2coords(L, &sel, &x1, &y1, &x2, &y2)) { nhl_error(L, "selection.fillrect: illegal arguments"); @@ -473,22 +464,22 @@ lua_State *L; { int argc = lua_gettop(L); struct selectionvar *sel = (struct selectionvar *) 0; - schar x1, y1, x2, y2; + xchar x1, y1, x2, y2; int roughness = 7; if (argc == 6) { sel = l_selection_check(L, 1); - x1 = (schar) luaL_checkinteger(L, 2); - y1 = (schar) luaL_checkinteger(L, 3); - x2 = (schar) luaL_checkinteger(L, 4); - y2 = (schar) luaL_checkinteger(L, 5); + x1 = (xchar) luaL_checkinteger(L, 2); + y1 = (xchar) luaL_checkinteger(L, 3); + x2 = (xchar) luaL_checkinteger(L, 4); + y2 = (xchar) luaL_checkinteger(L, 5); roughness = (int) luaL_checkinteger(L, 6); lua_pop(L, 5); } else if (argc == 5 && lua_type(L, 1) == LUA_TNUMBER) { - x1 = (schar) luaL_checkinteger(L, 1); - y1 = (schar) luaL_checkinteger(L, 2); - x2 = (schar) luaL_checkinteger(L, 3); - y2 = (schar) luaL_checkinteger(L, 4); + x1 = (xchar) luaL_checkinteger(L, 1); + y1 = (xchar) luaL_checkinteger(L, 2); + x2 = (xchar) luaL_checkinteger(L, 3); + y2 = (xchar) luaL_checkinteger(L, 4); roughness = (int) luaL_checkinteger(L, 5); lua_pop(L, 5); (void) l_selection_new(L); @@ -610,11 +601,11 @@ lua_State *L; { int argc = lua_gettop(L); struct selectionvar *sel = (struct selectionvar *) 0; - schar x, y; + xchar x, y; if (argc == 2) { - x = (schar) luaL_checkinteger(L, 1); - y = (schar) luaL_checkinteger(L, 2); + x = (xchar) luaL_checkinteger(L, 1); + y = (xchar) luaL_checkinteger(L, 2); lua_pop(L, 2); (void) l_selection_new(L); sel = l_selection_check(L, 1); @@ -644,20 +635,20 @@ lua_State *L; { int argc = lua_gettop(L); struct selectionvar *sel = (struct selectionvar *) 0; - schar x = 0, y = 0; + xchar x = 0, y = 0; int r = 0, filled = 0; if (argc == 3) { - x = (schar) luaL_checkinteger(L, 1); - y = (schar) luaL_checkinteger(L, 2); + x = (xchar) luaL_checkinteger(L, 1); + y = (xchar) luaL_checkinteger(L, 2); r = (int) luaL_checkinteger(L, 3); lua_pop(L, 3); (void) l_selection_new(L); sel = l_selection_check(L, 1); filled = 0; } else if (argc == 4 && lua_type(L, 1) == LUA_TNUMBER) { - x = (schar) luaL_checkinteger(L, 1); - y = (schar) luaL_checkinteger(L, 2); + x = (xchar) luaL_checkinteger(L, 1); + y = (xchar) luaL_checkinteger(L, 2); r = (int) luaL_checkinteger(L, 3); filled = (int) luaL_checkinteger(L, 4); /* TODO: boolean*/ lua_pop(L, 4); @@ -665,8 +656,8 @@ lua_State *L; sel = l_selection_check(L, 1); } else if (argc == 4 || argc == 5) { sel = l_selection_check(L, 1); - x = (schar) luaL_checkinteger(L, 2); - y = (schar) luaL_checkinteger(L, 3); + x = (xchar) luaL_checkinteger(L, 2); + y = (xchar) luaL_checkinteger(L, 3); r = (int) luaL_checkinteger(L, 4); filled = (int) luaL_optinteger(L, 5, 0); /* TODO: boolean */ } else { @@ -693,12 +684,12 @@ lua_State *L; { int argc = lua_gettop(L); struct selectionvar *sel = (struct selectionvar *) 0; - schar x = 0, y = 0; + xchar x = 0, y = 0; int r1 = 0, r2 = 0, filled = 0; if (argc == 4) { - x = (schar) luaL_checkinteger(L, 1); - y = (schar) luaL_checkinteger(L, 2); + x = (xchar) luaL_checkinteger(L, 1); + y = (xchar) luaL_checkinteger(L, 2); r1 = (int) luaL_checkinteger(L, 3); r2 = (int) luaL_checkinteger(L, 4); lua_pop(L, 4); @@ -706,8 +697,8 @@ lua_State *L; sel = l_selection_check(L, 1); filled = 0; } else if (argc == 5 && lua_type(L, 1) == LUA_TNUMBER) { - x = (schar) luaL_checkinteger(L, 1); - y = (schar) luaL_checkinteger(L, 2); + x = (xchar) luaL_checkinteger(L, 1); + y = (xchar) luaL_checkinteger(L, 2); r1 = (int) luaL_checkinteger(L, 3); r2 = (int) luaL_checkinteger(L, 4); filled = (int) luaL_optinteger(L, 5, 0); /* TODO: boolean */ @@ -716,8 +707,8 @@ lua_State *L; sel = l_selection_check(L, 1); } else if (argc == 5 || argc == 6) { sel = l_selection_check(L, 1); - x = (schar) luaL_checkinteger(L, 2); - y = (schar) luaL_checkinteger(L, 3); + x = (xchar) luaL_checkinteger(L, 2); + y = (xchar) luaL_checkinteger(L, 3); r1 = (int) luaL_checkinteger(L, 4); r2 = (int) luaL_checkinteger(L, 5); filled = (int) luaL_optinteger(L, 6, 0); /* TODO: boolean */ @@ -748,7 +739,7 @@ lua_State *L; struct selectionvar *sel = (struct selectionvar *) 0; /* if x2 and y2 aren't set, the gradient has a single center point of x,y; * if they are set, the gradient is centered on a (x,y) to (x2,y2) line */ - schar x = 0, y = 0, x2 = -1, y2 = -1; + xchar x = 0, y = 0, x2 = -1, y2 = -1; /* points will not be added within mindist of the center; the chance for a * point between mindist and maxdist to be added to the selection starts at * 0% at mindist and increases linearly to 100% at maxdist */ @@ -767,10 +758,10 @@ lua_State *L; if (argc == 1 && lua_type(L, 1) == LUA_TTABLE) { lcheck_param_table(L); type = gradtypes2i[get_table_option(L, "type", "radial", gradtypes)]; - x = (schar) get_table_int(L, "x"); - y = (schar) get_table_int(L, "y"); - x2 = (schar) get_table_int_opt(L, "x2", -1); - y2 = (schar) get_table_int_opt(L, "y2", -1); + x = (xchar) get_table_int(L, "x"); + y = (xchar) get_table_int(L, "y"); + x2 = (xchar) get_table_int_opt(L, "x2", -1); + y2 = (xchar) get_table_int_opt(L, "y2", -1); /* maxdist is required because there's no obvious default value for it, * whereas mindist has an obvious defalt of 0 */ maxdist = get_table_int(L, "maxdist"); diff --git a/src/nhlua.c b/src/nhlua.c index 24bcc5d59..b3906592b 100644 --- a/src/nhlua.c +++ b/src/nhlua.c @@ -34,6 +34,7 @@ static int FDECL(nhl_ing_suffix, (lua_State *)); static int FDECL(nhl_an, (lua_State *)); static int FDECL(nhl_rn2, (lua_State *)); static int FDECL(nhl_random, (lua_State *)); +static int FDECL(nhl_level_difficulty, (lua_State *)); static void FDECL(init_nhc_data, (lua_State *)); static int FDECL(nhl_push_anything, (lua_State *, int, void *)); static int FDECL(nhl_meta_u_index, (lua_State *)); @@ -657,6 +658,21 @@ lua_State *L; return 1; } +/* level_difficulty() */ +static int +nhl_level_difficulty(L) +lua_State *L; +{ + int argc = lua_gettop(L); + if (argc == 0) { + lua_pushinteger(L, level_difficulty()); + } + else { + nhl_error(L, "level_difficulty should not have any args"); + } + return 1; +} + /* get mandatory integer value from table */ int get_table_int(L, name) @@ -831,6 +847,7 @@ static const struct luaL_Reg nhl_functions[] = { {"an", nhl_an}, {"rn2", nhl_rn2}, {"random", nhl_random}, + {"level_difficulty", nhl_level_difficulty}, {NULL, NULL} }; diff --git a/src/o_init.c b/src/o_init.c index 8bce36391..5806e9ee3 100644 --- a/src/o_init.c +++ b/src/o_init.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 o_init.c $NHDT-Date: 1545383615 2018/12/21 09:13:35 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.25 $ */ +/* NetHack 3.7 o_init.c $NHDT-Date: 1596498193 2020/08/03 23:43:13 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.43 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2011. */ /* NetHack may be freely redistributed. See license for details. */ @@ -9,6 +9,8 @@ static void FDECL(setgemprobs, (d_level *)); static void FDECL(shuffle, (int, int, BOOLEAN_P)); static void NDECL(shuffle_all); static boolean FDECL(interesting_to_discover, (int)); +static int FDECL(CFDECLSPEC discovered_cmp, (const genericptr, + const genericptr)); static char *FDECL(oclass_to_name, (CHAR_P, char *)); #ifdef USE_TILES @@ -282,6 +284,26 @@ shuffle_all() return; } +/* Return TRUE if the provided string matches the unidentified description of + * the provided object. */ +boolean +objdescr_is(obj, descr) +struct obj *obj; +const char *descr; +{ + const char *objdescr; + + if (!obj) { + impossible("objdescr_is: null obj"); + return FALSE; + } + + objdescr = OBJ_DESCR(objects[obj->otyp]); + if (!objdescr) + return FALSE; /* no obj description, no match */ + return !strcmp(objdescr, descr); +} + /* find the object index for snow boots; used [once] by slippery ice code */ int find_skates() @@ -445,37 +467,167 @@ static const short uniq_objs[] = { BELL_OF_OPENING, }; +/* discoveries qsort comparison function */ +static int CFDECLSPEC +discovered_cmp(v1, v2) +const genericptr v1; +const genericptr v2; +{ + const char *s1 = *(const char **) v1; + const char *s2 = *(const char **) v2; + /* each element starts with "* " or " " but we don't sort by those */ + int res = strcmpi(s1 + 2, s2 + 2); + + if (res == 0) { + ; /* no tie-breaker needed */ + } + return res; +} + +static char * +sortloot_descr(otyp, outbuf) +int otyp; +char *outbuf; +{ + Loot sl_cookie; + struct obj o; + + o = cg.zeroobj; + o.otyp = otyp; + o.oclass = objects[otyp].oc_class; + o.dknown = 1; + o.known = (objects[otyp].oc_name_known || !objects[otyp].oc_uses_known) + ? 1 : 0; + o.corpsenm = NON_PM; /* suppress statue and figurine details */ + /* but suppressing fruit details leads to "bad fruit #0" */ + if (otyp == SLIME_MOLD) + o.spe = g.context.current_fruit; + + (void) memset((genericptr_t) &sl_cookie, 0, sizeof sl_cookie); + sl_cookie.obj = (struct obj *) 0; + sl_cookie.str = (char *) 0; + + loot_classify(&sl_cookie, &o); + Sprintf(outbuf, "%02d%02d%1d ", + sl_cookie.orderclass, sl_cookie.subclass, sl_cookie.disco); + return outbuf; +} + +#define DISCO_BYCLASS 0 /* by discovery order within each class */ +#define DISCO_SORTLOOT 1 /* by discovery order within each subclass */ +#define DISCO_ALPHABYCLASS 2 /* alphabetized within each class */ +#define DISCO_ALPHABETIZED 3 /* alphabetized across all classes */ +/* also used in options.c (optfn_sortdiscoveries) */ +const char disco_order_let[] = "osca"; +const char *const disco_orders_descr[] = { + "by order of discovery within each class", + "sortloot order (by class with some sub-class groupings)", + "alphabetical within each class", + "alphabetical across all classes", + (char *) 0 +}; + +int +choose_disco_sort(mode) +int mode; /* 0 => 'O' cmd, 1 => full discoveries; 2 => class discoveries */ +{ + winid tmpwin; + menu_item *selected; + anything any; + int i, n, choice; + + tmpwin = create_nhwindow(NHW_MENU); + start_menu(tmpwin, MENU_BEHAVE_STANDARD); + any = cg.zeroany; /* zero out all bits */ + for (i = 0; disco_orders_descr[i]; ++i) { + any.a_int = disco_order_let[i]; + add_menu(tmpwin, NO_GLYPH, &any, (char) any.a_int, 0, ATR_NONE, + disco_orders_descr[i], + (disco_order_let[i] == flags.discosort) + ? MENU_ITEMFLAGS_SELECTED + : MENU_ITEMFLAGS_NONE); + } + if (mode == 2) { + /* called via 'm `' where full alphabetize doesn't make sense + (only showing one class so can't span all classes) but the + chosen sort will stick and also apply to '\' usage */ + any = cg.zeroany; + add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, + "", MENU_ITEMFLAGS_NONE); + add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, + "Note: full alphabetical and alphabetical within class", + MENU_ITEMFLAGS_NONE); + add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, + " are equivalent for single class discovery, but", + MENU_ITEMFLAGS_NONE); + add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, + " will matter for future use of total discoveries.", + MENU_ITEMFLAGS_NONE); + } + end_menu(tmpwin, "Ordering of discoveries"); + + n = select_menu(tmpwin, PICK_ONE, &selected); + destroy_nhwindow(tmpwin); + if (n > 0) { + choice = selected[0].item.a_int; + /* skip preselected entry if we have more than one item chosen */ + if (n > 1 && choice == (int) flags.discosort) + choice = selected[1].item.a_int; + free((genericptr_t) selected); + flags.discosort = choice; + } + return n; +} + /* the '\' command - show discovered object types */ int dodiscovered() /* free after Robert Viduya */ { - register int i, dis; - int ct = 0; - char *s, oclass, prev_class, classes[MAXOCLASSES], buf[BUFSZ]; winid tmpwin; + char *s, *p, oclass, prev_class, + classes[MAXOCLASSES], buf[BUFSZ], + *sorted_lines[NUM_OBJECTS]; /* overkill */ + int i, j, sortindx, dis, ct, uniq_ct, arti_ct, sorted_ct; + boolean alphabetized, alphabyclass, lootsort; + + if (!flags.discosort || !(p = index(disco_order_let, flags.discosort))) + flags.discosort = 'o'; + + if (iflags.menu_requested) { + if (choose_disco_sort(1) < 0) + return 0; + } + alphabyclass = (flags.discosort == 'c'); + alphabetized = (flags.discosort == 'a' || alphabyclass); + lootsort = (flags.discosort == 's'); + sortindx = index(disco_order_let, flags.discosort) - disco_order_let; tmpwin = create_nhwindow(NHW_MENU); - putstr(tmpwin, 0, "Discoveries"); + Sprintf(buf, "Discoveries, %s", disco_orders_descr[sortindx]); + putstr(tmpwin, 0, buf); putstr(tmpwin, 0, ""); /* gather "unique objects" into a pseudo-class; note that they'll also be displayed individually within their regular class */ + uniq_ct = 0; for (i = dis = 0; i < SIZE(uniq_objs); i++) if (objects[uniq_objs[i]].oc_name_known) { if (!dis++) putstr(tmpwin, iflags.menu_headings, "Unique items"); + ++uniq_ct; Sprintf(buf, " %s", OBJ_NAME(objects[uniq_objs[i]])); putstr(tmpwin, 0, buf); - ++ct; } /* display any known artifacts as another pseudo-class */ - ct += disp_artifact_discoveries(tmpwin); + arti_ct = disp_artifact_discoveries(tmpwin); /* several classes are omitted from packorder; one is of interest here */ Strcpy(classes, flags.inv_order); if (!index(classes, VENOM_CLASS)) (void) strkitten(classes, VENOM_CLASS); /* append char to string */ + ct = uniq_ct + arti_ct; + sorted_ct = 0; for (s = classes; *s; s++) { oclass = *s; prev_class = oclass + 1; /* forced different from oclass */ @@ -484,21 +636,63 @@ dodiscovered() /* free after Robert Viduya */ if ((dis = g.disco[i]) != 0 && interesting_to_discover(dis)) { ct++; if (oclass != prev_class) { - putstr(tmpwin, iflags.menu_headings, - let_to_name(oclass, FALSE, FALSE)); - prev_class = oclass; + if ((alphabyclass || lootsort) && sorted_ct) { + /* output previous class */ + qsort(sorted_lines, sorted_ct, sizeof (char *), + discovered_cmp); + for (j = 0; j < sorted_ct; ++j) { + p = sorted_lines[j]; + if (lootsort) { + p[6] = p[0]; /* '*' or ' ' */ + p += 6; + } + putstr(tmpwin, 0, p); + free(sorted_lines[j]), sorted_lines[j] = 0; + } + sorted_ct = 0; + } + if (!alphabetized || alphabyclass) { + /* header for new class */ + putstr(tmpwin, iflags.menu_headings, + let_to_name(oclass, FALSE, FALSE)); + prev_class = oclass; + } } - Sprintf(buf, "%s %s", - (objects[dis].oc_pre_discovered ? "*" : " "), - obj_typename(dis)); - putstr(tmpwin, 0, buf); + Strcpy(buf, objects[dis].oc_pre_discovered ? "* " : " "); + if (lootsort) + (void) sortloot_descr(dis, &buf[2]); + Strcat(buf, obj_typename(dis)); + + if (!alphabetized && !lootsort) + putstr(tmpwin, 0, buf); + else + sorted_lines[sorted_ct++] = dupstr(buf); } } } if (ct == 0) { You("haven't discovered anything yet..."); - } else + } else { + if (sorted_ct) { + /* if we're alphabetizing by class, we've already shown the + relevant header above; if we're alphabetizing across all + classes, we normally don't need a header; but it we showed + any unique items or any artifacts then we do need one */ + if ((uniq_ct || arti_ct) && !alphabyclass) + putstr(tmpwin, iflags.menu_headings, "Discovered items"); + qsort(sorted_lines, sorted_ct, sizeof (char *), discovered_cmp); + for (j = 0; j < sorted_ct; ++j) { + p = sorted_lines[j]; + if (lootsort) { + p[6] = p[0]; /* '*' or ' ' */ + p += 6; + } + putstr(tmpwin, 0, p); + free(sorted_lines[j]), sorted_lines[j] = 0; + } + } display_nhwindow(tmpwin, TRUE); + } destroy_nhwindow(tmpwin); return 0; @@ -527,13 +721,24 @@ doclassdisco() havent_discovered_any[] = "haven't discovered any %s yet.", unique_items[] = "unique items", artifact_items[] = "artifacts"; - char *s, c, oclass, menulet, allclasses[MAXOCLASSES], - discosyms[2 + MAXOCLASSES + 1], buf[BUFSZ]; - int i, ct, dis, xtras; - boolean traditional; winid tmpwin = WIN_ERR; - anything any; menu_item *pick_list = 0; + anything any; + char *p, *s, c, oclass, menulet, allclasses[MAXOCLASSES], + discosyms[2 + MAXOCLASSES + 1], buf[BUFSZ], + *sorted_lines[NUM_OBJECTS]; /* overkill */ + int i, ct, dis, xtras, sorted_ct; + boolean traditional, alphabetized, lootsort; + + if (!flags.discosort || !(p = index(disco_order_let, flags.discosort))) + flags.discosort = 'o'; + + if (iflags.menu_requested) { + if (choose_disco_sort(2) < 0) + return 0; + } + alphabetized = (flags.discosort == 'a' || flags.discosort == 'c'); + lootsort = (flags.discosort == 's'); discosyms[0] = '\0'; traditional = (flags.menu_style == MENU_TRADITIONAL @@ -650,9 +855,9 @@ doclassdisco() upstart(strcpy(buf, unique_items))); for (i = 0; i < SIZE(uniq_objs); i++) if (objects[uniq_objs[i]].oc_name_known) { + ++ct; Sprintf(buf, " %s", OBJ_NAME(objects[uniq_objs[i]])); putstr(tmpwin, 0, buf); - ++ct; } if (!ct) You(havent_discovered_any, unique_items); @@ -665,20 +870,40 @@ doclassdisco() break; default: oclass = def_char_to_objclass(c); - Sprintf(buf, "Discovered %s", let_to_name(oclass, FALSE, FALSE)); - putstr(tmpwin, iflags.menu_headings, buf); - for (i = g.bases[(int) oclass]; - i < NUM_OBJECTS && objects[i].oc_class == oclass; ++i) { + Sprintf(buf, "Discovered %s in %s", let_to_name(oclass, FALSE, FALSE), + (flags.discosort == 'o') ? "order of discovery" + : (flags.discosort == 's') ? "'sortloot' order" + : "alphabetical order"); + putstr(tmpwin, 0, buf); /* skip iflags.menu_headings */ + sorted_ct = 0; + for (i = g.bases[(int) oclass]; i < g.bases[oclass + 1] - 1; ++i) { if ((dis = g.disco[i]) != 0 && interesting_to_discover(dis)) { - Sprintf(buf, "%s %s", - objects[dis].oc_pre_discovered ? "*" : " ", - obj_typename(dis)); - putstr(tmpwin, 0, buf); ++ct; + Strcpy(buf, objects[dis].oc_pre_discovered ? "* " : " "); + if (lootsort) + (void) sortloot_descr(dis, &buf[2]); + Strcat(buf, obj_typename(dis)); + + if (!alphabetized && !lootsort) + putstr(tmpwin, 0, buf); + else + sorted_lines[sorted_ct++] = dupstr(buf); } } - if (!ct) + if (!ct) { You(havent_discovered_any, oclass_to_name(oclass, buf)); + } else if (sorted_ct) { + qsort(sorted_lines, sorted_ct, sizeof (char *), discovered_cmp); + for (i = 0; i < sorted_ct; ++i) { + p = sorted_lines[i]; + if (lootsort) { + p[6] = p[0]; /* '*' or ' ' */ + p += 6; + } + putstr(tmpwin, 0, p); + free(sorted_lines[i]), sorted_lines[i] = 0; + } + } break; } if (ct) diff --git a/src/objects.c b/src/objects.c index 8c4d2a9ab..782e8019f 100644 --- a/src/objects.c +++ b/src/objects.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 objects.c $NHDT-Date: 1578855624 2020/01/12 19:00:24 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.61 $ */ +/* NetHack 3.7 objects.c $NHDT-Date: 1596498192 2020/08/03 23:43:12 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.66 $ */ /* Copyright (c) Mike Threepoint, 1989. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1150,10 +1150,10 @@ OBJECT(OBJ("iron chain", None), /* Venom is normally a transitory missile (spit by various creatures) * but can be wished for in wizard mode so could occur in bones data. */ -OBJECT(OBJ("blinding venom", "splash of venom"), +OBJECT(OBJ("splash of blinding venom", "splash of venom"), BITS(0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, P_NONE, LIQUID), 0, VENOM_CLASS, 500, 0, 1, 0, 0, 0, 0, 0, 0, HI_ORGANIC), -OBJECT(OBJ("acid venom", "splash of venom"), +OBJECT(OBJ("splash of acid venom", "splash of venom"), BITS(0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, P_NONE, LIQUID), 0, VENOM_CLASS, 500, 0, 1, 0, 6, 6, 0, 0, 0, HI_ORGANIC), /* +d6 small or large */ diff --git a/src/objnam.c b/src/objnam.c index ab70f3c03..2330fa4dc 100644 --- a/src/objnam.c +++ b/src/objnam.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 objnam.c $NHDT-Date: 1583315888 2020/03/04 09:58:08 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.293 $ */ +/* NetHack 3.7 objnam.c $NHDT-Date: 1607945434 2020/12/14 11:30:34 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.308 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2011. */ /* NetHack may be freely redistributed. See license for details. */ @@ -10,6 +10,26 @@ #define SCHAR_LIM 127 #define NUMOBUF 12 +struct _readobjnam_data { + char globbuf[BUFSZ]; + char fruitbuf[BUFSZ]; + char *bp; + char *origbp; + char oclass; + char *un, *dn, *actualn; + const char *name; + char *p; + int cnt, spe, spesgn, typ, very, rechrg; + int blessed, uncursed, iscursed, ispoisoned, isgreased; + int eroded, eroded2, erodeproof, locked, unlocked, broken, real, fake; + int halfeaten, mntmp, contents; + int islit, unlabeled, ishistoric, isdiluted, trapped; + int tmp, tinv, tvariety, mgend; + int wetness, gsize; + int ftype; + struct obj *otmp; +}; + static char *FDECL(strprepend, (char *, const char *)); static char *NDECL(nextobuf); static void FDECL(releaseobuf, (char *)); @@ -25,6 +45,12 @@ static boolean FDECL(wishymatch, (const char *, const char *, BOOLEAN_P)); static short FDECL(rnd_otyp_by_wpnskill, (SCHAR_P)); static short FDECL(rnd_otyp_by_namedesc, (const char *, CHAR_P, int)); static struct obj *FDECL(wizterrainwish, (char *, char *, int, int)); +static void FDECL(readobjnam_init, (char *, struct _readobjnam_data *)); +static int FDECL(readobjnam_preparse, (struct _readobjnam_data *)); +static void FDECL(readobjnam_parse_charges, (struct _readobjnam_data *)); +static int FDECL(readobjnam_postparse1, (struct _readobjnam_data *)); +static int FDECL(readobjnam_postparse2, (struct _readobjnam_data *)); +static int FDECL(readobjnam_postparse3, (struct _readobjnam_data *)); struct Jitem { int item; @@ -445,7 +471,7 @@ unsigned cxn_flags; /* bitmask of CXN_xxx values */ obj->known = 0; if (!Blind && !g.distantname) obj->dknown = 1; - if (Role_if(PM_PRIEST)) + if (Role_if(PM_CLERIC)) obj->bknown = 1; /* actively avoid set_bknown(); * we mustn't call update_inventory() now because * it would call xname() (via doname()) recursively @@ -502,8 +528,8 @@ unsigned cxn_flags; /* bitmask of CXN_xxx values */ char anbuf[10]; /* [4] would be enough: 'a','n',' ','\0' */ Sprintf(eos(buf), " of %s%s", - just_an(anbuf, mons[omndx].mname), - mons[omndx].mname); + just_an(anbuf, mons[omndx].pmnames[NEUTRAL]), + mons[omndx].pmnames[NEUTRAL]); } else if (is_wet_towel(obj)) { if (wizard) Sprintf(eos(buf), " (%d)", obj->spe); @@ -591,6 +617,7 @@ unsigned cxn_flags; /* bitmask of CXN_xxx values */ case ROCK_CLASS: if (typ == STATUE && omndx != NON_PM) { char anbuf[10]; + int mgend = (obj->spe & STATUE_FEMALE) ? FEMALE : MALE; Sprintf(buf, "%s%s of %s%s", (Role_if(PM_ARCHEOLOGIST) && (obj->spe & STATUE_HISTORIC)) @@ -601,8 +628,8 @@ unsigned cxn_flags; /* bitmask of CXN_xxx values */ ? "" : the_unique_pm(&mons[omndx]) ? "the " - : just_an(anbuf, mons[omndx].mname), - mons[omndx].mname); + : just_an(anbuf, pmname(&mons[omndx], mgend)), + pmname(&mons[omndx], mgend)); } else Strcpy(buf, actualn); break; @@ -713,14 +740,33 @@ unsigned cxn_flags; /* bitmask of CXN_xxx values */ } default: Sprintf(buf, "glorkum %d %d %d", obj->oclass, typ, obj->spe); + break; } if (pluralize) Strcpy(buf, makeplural(buf)); - if (obj->otyp == T_SHIRT && g.program_state.gameover) { + /* maybe give some extra information which isn't shown during play */ + if (g.program_state.gameover) { + const char *lbl; char tmpbuf[BUFSZ]; - Sprintf(eos(buf), " with text \"%s\"", tshirt_text(obj, tmpbuf)); + /* disclose without breaking illiterate conduct, but mainly tip off + players who aren't aware that something readable is present */ + switch (obj->otyp) { + case T_SHIRT: + case ALCHEMY_SMOCK: + Sprintf(eos(buf), " with text \"%s\"", + (obj->otyp == T_SHIRT) ? tshirt_text(obj, tmpbuf) + : apron_text(obj, tmpbuf)); + break; + case CANDY_BAR: + lbl = candy_wrapper_text(obj); + if (*lbl) + Sprintf(eos(buf), " labeled \"%s\"", lbl); + break; + default: + break; + } } if (has_oname(obj) && dknown) { @@ -777,7 +823,7 @@ struct obj *obj; bufp = distant_name(&bareobj, xname); /* xname(&bareobj) */ if (!strncmp(bufp, "uncursed ", 9)) - bufp += 9; /* Role_if(PM_PRIEST) */ + bufp += 9; /* Role_if(PM_CLERIC) */ objects[otyp].oc_uname = saveobcls.oc_uname; objects[otyp].oc_name_known = saveobcls.oc_name_known; @@ -833,7 +879,7 @@ struct permonst *ptr; /* high priest is unique if it includes "of ", otherwise not (caller needs to handle the 1st possibility; we assume the 2nd); worm tail should be irrelevant but is included for completeness */ - if (ptr == &mons[PM_HIGH_PRIEST] || ptr == &mons[PM_LONG_WORM_TAIL]) + if (ptr == &mons[PM_HIGH_CLERIC] || ptr == &mons[PM_LONG_WORM_TAIL]) uniq = FALSE; /* Wizard no longer needs this; he's flagged as unique these days */ if (ptr == &mons[PM_WIZARD_OF_YENDOR]) @@ -1017,7 +1063,7 @@ unsigned doname_flags; #endif && obj->otyp != FAKE_AMULET_OF_YENDOR && obj->otyp != AMULET_OF_YENDOR - && !Role_if(PM_PRIEST))) + && !Role_if(PM_CLERIC))) Strcat(prefix, "uncursed "); } @@ -1155,7 +1201,7 @@ unsigned doname_flags; #endif if (omndx >= LOW_PM && (known || (g.mvitals[omndx].mvflags & MV_KNOWS_EGG))) { - Strcat(prefix, mons[omndx].mname); + Strcat(prefix, mons[omndx].pmnames[NEUTRAL]); Strcat(prefix, " "); if (obj->spe == 1) Strcat(bp, " (laid by you)"); @@ -1251,9 +1297,9 @@ unsigned doname_flags; /* treat 'restoring' like suppress_price because shopkeeper and bill might not be available yet while restore is in progress (objects won't normally be formatted during that time, but if - 'perm_invent' is enabled then they might be) */ - if (iflags.suppress_price || g.restoring) { - ; /* don't attempt to obtain any stop pricing, even if 'with_price' */ + 'perm_invent' is enabled then they might be [not any more...]) */ + if (iflags.suppress_price || g.program_state.restoring) { + ; /* don't attempt to obtain any shop pricing, even if 'with_price' */ } else if (is_unpaid(obj)) { /* in inventory or in container in invent */ long quotedprice = unpaid_cost(obj, TRUE); @@ -1388,21 +1434,21 @@ unsigned cxn_flags; /* bitmask of CXN_xxx values */ omit_corpse = (cxn_flags & CXN_NOCORPSE) != 0, possessive = FALSE, glob = (otmp->otyp != CORPSE && otmp->globby); - const char *mname; + const char *mnam; if (glob) { - mname = OBJ_NAME(objects[otmp->otyp]); /* "glob of " */ + mnam = OBJ_NAME(objects[otmp->otyp]); /* "glob of " */ } else if (omndx == NON_PM) { /* paranoia */ - mname = "thing"; + mnam = "thing"; /* [Possible enhancement: check whether corpse has monster traits attached in order to use priestname() for priests and minions.] */ - } else if (omndx == PM_ALIGNED_PRIEST) { + } else if (omndx == PM_ALIGNED_CLERIC) { /* avoid "aligned priest"; it just exposes internal details */ - mname = "priest"; + mnam = "priest"; } else { - mname = mons[omndx].mname; + mnam = mons[omndx].pmnames[NEUTRAL]; if (the_unique_pm(&mons[omndx]) || type_is_pname(&mons[omndx])) { - mname = s_suffix(mname); + mnam = s_suffix(mnam); possessive = TRUE; /* don't precede personal name like "Medusa" with an article */ if (type_is_pname(&mons[omndx])) @@ -1428,13 +1474,13 @@ unsigned cxn_flags; /* bitmask of CXN_xxx values */ if (!adjective || !*adjective) { /* normal case: newt corpse */ - Strcat(nambuf, mname); + Strcat(nambuf, mnam); } else { /* adjective positioning depends upon format of monster name */ if (possessive) /* Medusa's cursed partly eaten corpse */ - Sprintf(eos(nambuf), "%s %s", mname, adjective); + Sprintf(eos(nambuf), "%s %s", mnam, adjective); else /* cursed partly eaten troll corpse */ - Sprintf(eos(nambuf), "%s %s", adjective, mname); + Sprintf(eos(nambuf), "%s %s", adjective, mnam); /* in case adjective has a trailing space, squeeze it out */ mungspaces(nambuf); /* doname() might include a count in the adjective argument; @@ -2592,6 +2638,7 @@ const char *oldstr; || !BSTRCMPI(bp, p - 4, "nxes") /* lynxes */ || !BSTRCMPI(bp, p - 4, "ches") || !BSTRCMPI(bp, p - 4, "uses") /* lotuses */ + || !BSTRCMPI(bp, p - 4, "shes") /* splashes [of venom] */ || !BSTRCMPI(bp, p - 4, "sses") /* priestesses */ || !BSTRCMPI(bp, p - 5, "atoes") /* tomatoes */ || !BSTRCMPI(bp, p - 7, "dingoes") @@ -3208,251 +3255,223 @@ int locked, trapped; return (struct obj *) 0; } -/* - * Return something wished for. Specifying a null pointer for - * the user request string results in a random object. Otherwise, - * if asking explicitly for "nothing" (or "nil") return no_wish; - * if not an object return &cg.zeroobj; if an error (no matching object), - * return null. - */ -struct obj * -readobjnam(bp, no_wish) -register char *bp; -struct obj *no_wish; -{ - register char *p; - register int i; - register struct obj *otmp; - int cnt, spe, spesgn, typ, very, rechrg; - int blessed, uncursed, iscursed, ispoisoned, isgreased; - int eroded, eroded2, erodeproof, locked, unlocked, broken, real, fake; - int halfeaten, mntmp, contents; - int islit, unlabeled, ishistoric, isdiluted, trapped; - int tmp, tinv, tvariety; - int wetness, gsize = 0; - struct fruit *f; - int ftype = g.context.current_fruit; - char fruitbuf[BUFSZ], globbuf[BUFSZ]; - /* Fruits must not mess up the ability to wish for real objects (since - * you can leave a fruit in a bones file and it will be added to - * another person's game), so they must be checked for last, after - * stripping all the possible prefixes and seeing if there's a real - * name in there. So we have to save the full original name. However, - * it's still possible to do things like "uncursed burnt Alaska", - * or worse yet, "2 burned 5 course meals", so we need to loop to - * strip off the prefixes again, this time stripping only the ones - * possible on food. - * We could get even more detailed so as to allow food names with - * prefixes that _are_ possible on food, so you could wish for - * "2 3 alarm chilis". Currently this isn't allowed; options.c - * automatically sticks 'candied' in front of such names. - */ - char oclass; - char *un, *dn, *actualn, *origbp = bp; - const char *name = 0; - - cnt = spe = spesgn = typ = 0; - very = rechrg = blessed = uncursed = iscursed = ispoisoned = - isgreased = eroded = eroded2 = erodeproof = halfeaten = - islit = unlabeled = ishistoric = isdiluted = trapped = - locked = unlocked = broken = real = fake = 0; - tvariety = RANDOM_TIN; - mntmp = NON_PM; #define UNDEFINED 0 #define EMPTY 1 #define SPINACH 2 - contents = UNDEFINED; - oclass = 0; - actualn = dn = un = 0; - wetness = 0; - if (!bp) - goto any; - /* first, remove extra whitespace they may have typed */ - (void) mungspaces(bp); - /* allow wishing for "nothing" to preserve wishless conduct... - [now requires "wand of nothing" if that's what was really wanted] */ - if (!strcmpi(bp, "nothing") || !strcmpi(bp, "nil") - || !strcmpi(bp, "none")) - return no_wish; - /* save the [nearly] unmodified choice string */ - Strcpy(fruitbuf, bp); +static void +readobjnam_init(bp, d) +char *bp; +struct _readobjnam_data *d; +{ + d->cnt = d->spe = d->spesgn = d->typ = 0; + d->very = d->rechrg = d->blessed = d->uncursed = d->iscursed + = d->ispoisoned = d->isgreased = d->eroded = d->eroded2 + = d->erodeproof = d->halfeaten = d->islit = d->unlabeled + = d->ishistoric = d->isdiluted = d->trapped = d->locked + = d->unlocked = d->broken = d->real = d->fake = 0; + d->tvariety = RANDOM_TIN; + d->mgend = MALE; + d->mntmp = NON_PM; + d->contents = UNDEFINED; + d->oclass = 0; + d->actualn = d->dn = d->un = 0; + d->wetness = 0; + d->gsize = 0; + d->bp = d->origbp = bp; + d->p = (char *) 0; + d->name = (const char *) 0; + d->otmp = (struct obj *) 0; + d->ftype = g.context.current_fruit; +} +static int +readobjnam_preparse(d) +struct _readobjnam_data *d; +{ for (;;) { register int l; - if (!bp || !*bp) - goto any; - if (!strncmpi(bp, "an ", l = 3) || !strncmpi(bp, "a ", l = 2)) { - cnt = 1; - } else if (!strncmpi(bp, "the ", l = 4)) { + if (!d->bp || !*d->bp) + return 1; + if (!strncmpi(d->bp, "an ", l = 3) || !strncmpi(d->bp, "a ", l = 2)) { + d->cnt = 1; + } else if (!strncmpi(d->bp, "the ", l = 4)) { ; /* just increment `bp' by `l' below */ - } else if (!cnt && digit(*bp) && strcmp(bp, "0")) { - cnt = atoi(bp); - while (digit(*bp)) - bp++; - while (*bp == ' ') - bp++; + } else if (!d->cnt && digit(*d->bp) && strcmp(d->bp, "0")) { + d->cnt = atoi(d->bp); + while (digit(*d->bp)) + d->bp++; + while (*d->bp == ' ') + d->bp++; l = 0; - } else if (*bp == '+' || *bp == '-') { - spesgn = (*bp++ == '+') ? 1 : -1; - spe = atoi(bp); - while (digit(*bp)) - bp++; - while (*bp == ' ') - bp++; + } else if (*d->bp == '+' || *d->bp == '-') { + d->spesgn = (*d->bp++ == '+') ? 1 : -1; + d->spe = atoi(d->bp); + while (digit(*d->bp)) + d->bp++; + while (*d->bp == ' ') + d->bp++; l = 0; - } else if (!strncmpi(bp, "blessed ", l = 8) - || !strncmpi(bp, "holy ", l = 5)) { - blessed = 1; - } else if (!strncmpi(bp, "moist ", l = 6) - || !strncmpi(bp, "wet ", l = 4)) { - if (!strncmpi(bp, "wet ", 4)) - wetness = rn2(3) + 3; + } else if (!strncmpi(d->bp, "blessed ", l = 8) + || !strncmpi(d->bp, "holy ", l = 5)) { + d->blessed = 1; + } else if (!strncmpi(d->bp, "moist ", l = 6) + || !strncmpi(d->bp, "wet ", l = 4)) { + if (!strncmpi(d->bp, "wet ", 4)) + d->wetness = rn2(3) + 3; else - wetness = rnd(2); - } else if (!strncmpi(bp, "cursed ", l = 7) - || !strncmpi(bp, "unholy ", l = 7)) { - iscursed = 1; - } else if (!strncmpi(bp, "uncursed ", l = 9)) { - uncursed = 1; - } else if (!strncmpi(bp, "rustproof ", l = 10) - || !strncmpi(bp, "erodeproof ", l = 11) - || !strncmpi(bp, "corrodeproof ", l = 13) - || !strncmpi(bp, "fixed ", l = 6) - || !strncmpi(bp, "fireproof ", l = 10) - || !strncmpi(bp, "rotproof ", l = 9)) { - erodeproof = 1; - } else if (!strncmpi(bp, "lit ", l = 4) - || !strncmpi(bp, "burning ", l = 8)) { - islit = 1; - } else if (!strncmpi(bp, "unlit ", l = 6) - || !strncmpi(bp, "extinguished ", l = 13)) { - islit = 0; + d->wetness = rnd(2); + } else if (!strncmpi(d->bp, "cursed ", l = 7) + || !strncmpi(d->bp, "unholy ", l = 7)) { + d->iscursed = 1; + } else if (!strncmpi(d->bp, "uncursed ", l = 9)) { + d->uncursed = 1; + } else if (!strncmpi(d->bp, "rustproof ", l = 10) + || !strncmpi(d->bp, "erodeproof ", l = 11) + || !strncmpi(d->bp, "corrodeproof ", l = 13) + || !strncmpi(d->bp, "fixed ", l = 6) + || !strncmpi(d->bp, "fireproof ", l = 10) + || !strncmpi(d->bp, "rotproof ", l = 9)) { + d->erodeproof = 1; + } else if (!strncmpi(d->bp, "lit ", l = 4) + || !strncmpi(d->bp, "burning ", l = 8)) { + d->islit = 1; + } else if (!strncmpi(d->bp, "unlit ", l = 6) + || !strncmpi(d->bp, "extinguished ", l = 13)) { + d->islit = 0; /* "unlabeled" and "blank" are synonymous */ - } else if (!strncmpi(bp, "unlabeled ", l = 10) - || !strncmpi(bp, "unlabelled ", l = 11) - || !strncmpi(bp, "blank ", l = 6)) { - unlabeled = 1; - } else if (!strncmpi(bp, "poisoned ", l = 9)) { - ispoisoned = 1; + } else if (!strncmpi(d->bp, "unlabeled ", l = 10) + || !strncmpi(d->bp, "unlabelled ", l = 11) + || !strncmpi(d->bp, "blank ", l = 6)) { + d->unlabeled = 1; + } else if (!strncmpi(d->bp, "poisoned ", l = 9)) { + d->ispoisoned = 1; /* "trapped" recognized but not honored outside wizard mode */ - } else if (!strncmpi(bp, "trapped ", l = 8)) { - trapped = 0; /* undo any previous "untrapped" */ + } else if (!strncmpi(d->bp, "trapped ", l = 8)) { + d->trapped = 0; /* undo any previous "untrapped" */ if (wizard) - trapped = 1; - } else if (!strncmpi(bp, "untrapped ", l = 10)) { - trapped = 2; /* not trapped */ + d->trapped = 1; + } else if (!strncmpi(d->bp, "untrapped ", l = 10)) { + d->trapped = 2; /* not trapped */ /* locked, unlocked, broken: box/chest lock states */ - } else if (!strncmpi(bp, "locked ", l = 7)) { - locked = 1, unlocked = broken = 0; - } else if (!strncmpi(bp, "unlocked ", l = 9)) { - unlocked = 1, locked = broken = 0; - } else if (!strncmpi(bp, "broken ", l = 7)) { - broken = 1, locked = unlocked = 0; - } else if (!strncmpi(bp, "greased ", l = 8)) { - isgreased = 1; - } else if (!strncmpi(bp, "very ", l = 5)) { + } else if (!strncmpi(d->bp, "locked ", l = 7)) { + d->locked = 1, d->unlocked = d->broken = 0; + } else if (!strncmpi(d->bp, "unlocked ", l = 9)) { + d->unlocked = 1, d->locked = d->broken = 0; + } else if (!strncmpi(d->bp, "broken ", l = 7)) { + d->broken = 1, d->locked = d->unlocked = 0; + } else if (!strncmpi(d->bp, "greased ", l = 8)) { + d->isgreased = 1; + } else if (!strncmpi(d->bp, "very ", l = 5)) { /* very rusted very heavy iron ball */ - very = 1; - } else if (!strncmpi(bp, "thoroughly ", l = 11)) { - very = 2; - } else if (!strncmpi(bp, "rusty ", l = 6) - || !strncmpi(bp, "rusted ", l = 7) - || !strncmpi(bp, "burnt ", l = 6) - || !strncmpi(bp, "burned ", l = 7)) { - eroded = 1 + very; - very = 0; - } else if (!strncmpi(bp, "corroded ", l = 9) - || !strncmpi(bp, "rotted ", l = 7)) { - eroded2 = 1 + very; - very = 0; - } else if (!strncmpi(bp, "partly eaten ", l = 13) - || !strncmpi(bp, "partially eaten ", l = 16)) { - halfeaten = 1; - } else if (!strncmpi(bp, "historic ", l = 9)) { - ishistoric = 1; - } else if (!strncmpi(bp, "diluted ", l = 8)) { - isdiluted = 1; - } else if (!strncmpi(bp, "empty ", l = 6)) { - contents = EMPTY; - } else if (!strncmpi(bp, "small ", l = 6)) { /* glob sizes */ + d->very = 1; + } else if (!strncmpi(d->bp, "thoroughly ", l = 11)) { + d->very = 2; + } else if (!strncmpi(d->bp, "rusty ", l = 6) + || !strncmpi(d->bp, "rusted ", l = 7) + || !strncmpi(d->bp, "burnt ", l = 6) + || !strncmpi(d->bp, "burned ", l = 7)) { + d->eroded = 1 + d->very; + d->very = 0; + } else if (!strncmpi(d->bp, "corroded ", l = 9) + || !strncmpi(d->bp, "rotted ", l = 7)) { + d->eroded2 = 1 + d->very; + d->very = 0; + } else if (!strncmpi(d->bp, "partly eaten ", l = 13) + || !strncmpi(d->bp, "partially eaten ", l = 16)) { + d->halfeaten = 1; + } else if (!strncmpi(d->bp, "historic ", l = 9)) { + d->ishistoric = 1; + } else if (!strncmpi(d->bp, "diluted ", l = 8)) { + d->isdiluted = 1; + } else if (!strncmpi(d->bp, "empty ", l = 6)) { + d->contents = EMPTY; + } else if (!strncmpi(d->bp, "small ", l = 6)) { /* glob sizes */ /* "small" might be part of monster name (mimic, if wishing for its corpse) rather than prefix for glob size; when used for globs, it might be either "small glob of " or "small glob" and user might add 's' even though plural doesn't accomplish anything because globs don't stack */ - if (strncmpi(bp + l, "glob", 4) && !strstri(bp + l, " glob")) + if (strncmpi(d->bp + l, "glob", 4) && !strstri(d->bp + l, " glob")) break; - gsize = 1; - } else if (!strncmpi(bp, "medium ", l = 7)) { + d->gsize = 1; + } else if (!strncmpi(d->bp, "medium ", l = 7)) { /* xname() doesn't display "medium" but without this there'd be no way to ask for the intermediate size ("glob" without size prefix yields smallest one) */ - gsize = 2; - } else if (!strncmpi(bp, "large ", l = 6)) { + d->gsize = 2; + } else if (!strncmpi(d->bp, "large ", l = 6)) { /* "large" might be part of monster name (dog, cat, koboold, mimic) or object name (box, round shield) rather than prefix for glob size */ - if (strncmpi(bp + l, "glob", 4) && !strstri(bp + l, " glob")) + if (strncmpi(d->bp + l, "glob", 4) && !strstri(d->bp + l, " glob")) break; /* "very large " had "very " peeled off on previous iteration */ - gsize = (very != 1) ? 3 : 4; - } else if (!strncmpi(bp, "real ", l = 5)) { + d->gsize = (d->very != 1) ? 3 : 4; + } else if (!strncmpi(d->bp, "real ", l = 5)) { /* accept "real Amulet of Yendor" with "blessed" or "cursed" or useless "erodeproof" before or after "real" ... */ - real = 1; /* don't negate 'fake' here; "real fake amulet" and + d->real = 1; /* don't negate 'fake' here; "real fake amulet" and * "fake real amulet" will both yield fake amulet * (so will "real amulet" outside of wizard mode) */ - } else if (!strncmpi(bp, "fake ", l = 5)) { + } else if (!strncmpi(d->bp, "fake ", l = 5)) { /* ... and "fake Amulet of Yendor" likewise */ - fake = 1, real = 0; + d->fake = 1, d->real = 0; /* ['real' isn't actually needed (unless we someday add "real gem" for random non-glass, non-stone)] */ } else break; - bp += l; + d->bp += l; } - if (!cnt) - cnt = 1; /* will be changed to 2 if makesingular() changes string */ - if (strlen(bp) > 1 && (p = rindex(bp, '(')) != 0) { - boolean keeptrailingchars = TRUE; + return 0; +} - p[(p > bp && p[-1] == ' ') ? -1 : 0] = '\0'; /*terminate bp */ - ++p; /* advance past '(' */ - if (!strncmpi(p, "lit)", 4)) { - islit = 1; - p += 4 - 1; /* point at ')' */ +static void +readobjnam_parse_charges(d) +struct _readobjnam_data *d; +{ + if (strlen(d->bp) > 1 && (d->p = rindex(d->bp, '(')) != 0) { + boolean keeptrailingchars = TRUE; + int idx = 0; + + if (d->p > d->bp && d->p[-1] == ' ') + idx = -1; + d->p[idx] = '\0'; /* terminate bp */ + ++d->p; /* advance past '(' */ + if (!strncmpi(d->p, "lit)", 4)) { + d->islit = 1; + d->p += 4 - 1; /* point at ')' */ } else { - spe = atoi(p); - while (digit(*p)) - p++; - if (*p == ':') { - p++; - rechrg = spe; - spe = atoi(p); - while (digit(*p)) - p++; + d->spe = atoi(d->p); + while (digit(*d->p)) + d->p++; + if (*d->p == ':') { + d->p++; + d->rechrg = d->spe; + d->spe = atoi(d->p); + while (digit(*d->p)) + d->p++; } - if (*p != ')') { - spe = rechrg = 0; + if (*d->p != ')') { + d->spe = d->rechrg = 0; /* mis-matched parentheses; rest of string will be ignored * [probably we should restore everything back to '(' * instead since it might be part of "named ..."] */ keeptrailingchars = FALSE; } else { - spesgn = 1; + d->spesgn = 1; } } if (keeptrailingchars) { - char *pp = eos(bp); + char *pp = eos(d->bp); /* 'pp' points at 'pb's terminating '\0', 'p' points at ')' and will be incremented past it */ do { - *pp++ = *++p; - } while (*p); + *pp++ = *++d->p; + } while (*d->p); } } /* @@ -3460,14 +3479,22 @@ struct obj *no_wish; * smaller. Also, spe should always be positive --some cheaters may * try to confuse atoi(). */ - if (spe < 0) { - spesgn = -1; /* cheaters get what they deserve */ - spe = abs(spe); + if (d->spe < 0) { + d->spesgn = -1; /* cheaters get what they deserve */ + d->spe = abs(d->spe); } - if (spe > SCHAR_LIM) - spe = SCHAR_LIM; - if (rechrg < 0 || rechrg > 7) - rechrg = 7; /* recharge_limit */ + /* cap on obj->spe is independent of (and less than) SCHAR_LIM */ + if (d->spe > SPE_LIM) + d->spe = SPE_LIM; /* slime mold uses d.ftype, so not affected */ + if (d->rechrg < 0 || d->rechrg > 7) + d->rechrg = 7; /* recharge_limit */ +} + +static int +readobjnam_postparse1(d) +struct _readobjnam_data *d; +{ + int i; /* now we have the actual name, as delivered by xname, say * green potions called whisky @@ -3478,38 +3505,38 @@ struct obj *no_wish; * wand of wishing * elven cloak */ - if ((p = strstri(bp, " named ")) != 0) { - *p = 0; - name = p + 7; + if ((d->p = strstri(d->bp, " named ")) != 0) { + *d->p = 0; + d->name = d->p + 7; } - if ((p = strstri(bp, " called ")) != 0) { - *p = 0; - un = p + 8; + if ((d->p = strstri(d->bp, " called ")) != 0) { + *d->p = 0; + d->un = d->p + 8; /* "helmet called telepathy" is not "helmet" (a specific type) * "shield called reflection" is not "shield" (a general type) */ for (i = 0; i < SIZE(o_ranges); i++) - if (!strcmpi(bp, o_ranges[i].name)) { - oclass = o_ranges[i].oclass; - goto srch; + if (!strcmpi(d->bp, o_ranges[i].name)) { + d->oclass = o_ranges[i].oclass; + return 1; /*goto srch;*/ } } - if ((p = strstri(bp, " labeled ")) != 0) { - *p = 0; - dn = p + 9; - } else if ((p = strstri(bp, " labelled ")) != 0) { - *p = 0; - dn = p + 10; + if ((d->p = strstri(d->bp, " labeled ")) != 0) { + *d->p = 0; + d->dn = d->p + 9; + } else if ((d->p = strstri(d->bp, " labelled ")) != 0) { + *d->p = 0; + d->dn = d->p + 10; } - if ((p = strstri(bp, " of spinach")) != 0) { - *p = 0; - contents = SPINACH; + if ((d->p = strstri(d->bp, " of spinach")) != 0) { + *d->p = 0; + d->contents = SPINACH; } /* real vs fake is only useful for wizard mode but we'll accept its parsing in normal play (result is never real Amulet for that case) */ - if ((p = strstri(bp, OBJ_DESCR(objects[AMULET_OF_YENDOR]))) != 0 - && (p == bp || p[-1] == ' ')) { - char *s = bp; + if ((d->p = strstri(d->bp, OBJ_DESCR(objects[AMULET_OF_YENDOR]))) != 0 + && (d->p == d->bp || d->p[-1] == ' ')) { + char *s = d->bp; /* "Amulet of Yendor" matches two items, name of real Amulet and description of fake one; player can explicitly specify @@ -3521,17 +3548,17 @@ struct obj *no_wish; loop above, these have to be in the right order when more than one is present (similar to worthless glass gems below) */ if (!strncmpi(s, "cheap ", 6)) - fake = 1, s += 6; + d->fake = 1, s += 6; if (!strncmpi(s, "plastic ", 8)) - fake = 1, s += 8; + d->fake = 1, s += 8; if (!strncmpi(s, "imitation ", 10)) - fake = 1, s += 10; + d->fake = 1, s += 10; nhUse(s); /* suppress potential assigned-but-not-used complaint */ /* when 'fake' is True, it overrides 'real' if both were given; when it is False, force 'real' whether that was specified or not */ - real = !fake; - typ = real ? AMULET_OF_YENDOR : FAKE_AMULET_OF_YENDOR; - goto typfnd; + d->real = !d->fake; + d->typ = d->real ? AMULET_OF_YENDOR : FAKE_AMULET_OF_YENDOR; + return 2; /*goto typfnd;*/ } /* @@ -3547,17 +3574,17 @@ struct obj *no_wish; * -- boots, gloves, and lenses -- are also not mergable, so cnt is * ignored anyway. */ - if (!strncmpi(bp, "pair of ", 8)) { - bp += 8; - cnt *= 2; - } else if (!strncmpi(bp, "pairs of ", 9)) { - bp += 9; - if (cnt > 1) - cnt *= 2; - } else if (!strncmpi(bp, "set of ", 7)) { - bp += 7; - } else if (!strncmpi(bp, "sets of ", 8)) { - bp += 8; + if (!strncmpi(d->bp, "pair of ", 8)) { + d->bp += 8; + d->cnt *= 2; + } else if (!strncmpi(d->bp, "pairs of ", 9)) { + d->bp += 9; + if (d->cnt > 1) + d->cnt *= 2; + } else if (!strncmpi(d->bp, "set of ", 7)) { + d->bp += 7; + } else if (!strncmpi(d->bp, "sets of ", 8)) { + d->bp += 8; } /* intercept pudding globs here; they're a valid wish target, @@ -3565,28 +3592,29 @@ struct obj *no_wish; * * also don't let player wish for multiple globs. */ - i = (int) strlen(bp); - p = (char *) 0; + i = (int) strlen(d->bp); + d->p = (char *) 0; /* check for "glob", " glob", and "glob of " */ - if (!strcmpi(bp, "glob") || !BSTRCMPI(bp, bp + i - 5, " glob") - || !strcmpi(bp, "globs") || !BSTRCMPI(bp, bp + i - 6, " globs") - || (p = strstri(bp, "glob of ")) != 0 - || (p = strstri(bp, "globs of ")) != 0) { - mntmp = name_to_mon(!p ? bp : (strstri(p, " of ") + 4)); + if (!strcmpi(d->bp, "glob") || !BSTRCMPI(d->bp, d->bp + i - 5, " glob") + || !strcmpi(d->bp, "globs") || !BSTRCMPI(d->bp, d->bp + i - 6, " globs") + || (d->p = strstri(d->bp, "glob of ")) != 0 + || (d->p = strstri(d->bp, "globs of ")) != 0) { + d->mntmp = name_to_mon(!d->p ? d->bp + : (strstri(d->p, " of ") + 4), (int *) 0); /* if we didn't recognize monster type, pick a valid one at random */ - if (mntmp == NON_PM) - mntmp = rn1(PM_BLACK_PUDDING - PM_GRAY_OOZE, PM_GRAY_OOZE); + if (d->mntmp == NON_PM) + d->mntmp = rn1(PM_BLACK_PUDDING - PM_GRAY_OOZE, PM_GRAY_OOZE); /* construct canonical spelling in case name_to_mon() recognized a variant (grey ooze) or player used inverted syntax ( glob); if player has given a valid monster type but not valid glob type, object name lookup won't find it and wish attempt will fail */ - Sprintf(globbuf, "glob of %s", mons[mntmp].mname); - bp = globbuf; - mntmp = NON_PM; /* not useful for "glob of " object lookup */ - cnt = 0; /* globs don't stack */ - oclass = FOOD_CLASS; - actualn = bp, dn = 0; - goto srch; + Sprintf(d->globbuf, "glob of %s", mons[d->mntmp].pmnames[NEUTRAL]); + d->bp = d->globbuf; + d->mntmp = NON_PM; /* not useful for "glob of " object lookup */ + d->cnt = 0; /* globs don't stack */ + d->oclass = FOOD_CLASS; + d->actualn = d->bp, d->dn = 0; + return 1; /*goto srch;*/ } else { /* * Find corpse type using "of" (figurine of an orc, tin of orc meat) @@ -3596,77 +3624,79 @@ struct obj *no_wish; * names "gauntlets of ogre power" and "gauntlets of giant strength" * (or the alternate spelling of those, "gloves of ..."). */ - if (!strstri(bp, "wand ") && !strstri(bp, "spellbook ") - && !strstri(bp, "gauntlets ") && !strstri(bp, "gloves ") - && !strstri(bp, "finger ")) { - if ((p = strstri(bp, "tin of ")) != 0) { - if (!strcmpi(p + 7, "spinach")) { - contents = SPINACH; - mntmp = NON_PM; + if (!strstri(d->bp, "wand ") && !strstri(d->bp, "spellbook ") + && !strstri(d->bp, "gauntlets ") && !strstri(d->bp, "gloves ") + && !strstri(d->bp, "finger ")) { + if ((d->p = strstri(d->bp, "tin of ")) != 0) { + if (!strcmpi(d->p + 7, "spinach")) { + d->contents = SPINACH; + d->mntmp = NON_PM; } else { - tmp = tin_variety_txt(p + 7, &tinv); - tvariety = tinv; - mntmp = name_to_mon(p + 7 + tmp); + d->tmp = tin_variety_txt(d->p + 7, &d->tinv); + d->tvariety = d->tinv; + d->mntmp = name_to_mon(d->p + 7 + d->tmp, &d->mgend); } - typ = TIN; - goto typfnd; - } else if ((p = strstri(bp, " of ")) != 0 - && (mntmp = name_to_mon(p + 4)) >= LOW_PM) - *p = 0; + d->typ = TIN; + return 2; /*goto typfnd;*/ + } else if ((d->p = strstri(d->bp, " of ")) != 0 + && (d->mntmp = name_to_mon(d->p + 4, + &d->mgend)) >= LOW_PM) + *d->p = 0; } } /* Find corpse type w/o "of" (red dragon scale mail, yeti corpse) */ - if (strncmpi(bp, "samurai sword", 13) /* not the "samurai" monster! */ - && strncmpi(bp, "wizard lock", 11) /* not the "wizard" monster! */ - && strncmpi(bp, "ninja-to", 8) /* not the "ninja" rank */ - && strncmpi(bp, "master key", 10) /* not the "master" rank */ - && strncmpi(bp, "magenta", 7)) { /* not the "mage" rank */ + if (strncmpi(d->bp, "samurai sword", 13) /* not the "samurai" monster! */ + && strncmpi(d->bp, "wizard lock", 11) /* not the "wizard" monster! */ + && strncmpi(d->bp, "ninja-to", 8) /* not the "ninja" rank */ + && strncmpi(d->bp, "master key", 10) /* not the "master" rank */ + && strncmpi(d->bp, "magenta", 7)) { /* not the "mage" rank */ const char *rest = 0; - if (mntmp < LOW_PM && strlen(bp) > 2 - && (mntmp = name_to_monplus(bp, &rest)) >= LOW_PM) { - char *obp = bp; + if (d->mntmp < LOW_PM && strlen(d->bp) > 2 + && (d->mntmp = name_to_monplus(d->bp, &rest, + &d->mgend)) >= LOW_PM) { + char *obp = d->bp; /* 'rest' is a pointer past the matching portion; if that was an alternate name or a rank title rather than the canonical monster name we wouldn't otherwise know how much to skip */ - bp = (char *) rest; /* cast away const */ + d->bp = (char *) rest; /* cast away const */ - if (*bp == ' ') { - bp++; - } else if (!strncmpi(bp, "s ", 2) - || (bp > origbp && !strncmpi(bp - 1, "s' ", 3))) { - bp += 2; - } else if (!strncmpi(bp, "es ", 3) - || !strncmpi(bp, "'s ", 3)) { - bp += 3; - } else if (!*bp && !actualn && !dn && !un && !oclass) { + if (*d->bp == ' ') { + d->bp++; + } else if (!strncmpi(d->bp, "s ", 2) + || (d->bp > d->origbp && !strncmpi(d->bp - 1, "s' ", 3))) { + d->bp += 2; + } else if (!strncmpi(d->bp, "es ", 3) + || !strncmpi(d->bp, "'s ", 3)) { + d->bp += 3; + } else if (!*d->bp && !d->actualn && !d->dn && !d->un && !d->oclass) { /* no referent; they don't really mean a monster type */ - bp = obp; - mntmp = NON_PM; + d->bp = obp; + d->mntmp = NON_PM; } } } /* first change to singular if necessary */ - if (*bp + if (*d->bp /* we want "tricks" to match "bag of tricks" [rnd_otyp_by_namedesc()] but that wouldn't work if it gets singularized to "trick" ["tricks bag" matches whether or not this exception is present because singularize operates on "bag" and wishymatch()'s 'of inversion' finds a match] */ - && strcmpi(bp, "tricks") + && strcmpi(d->bp, "tricks") /* an odd potential wish; fail rather than get a false match with "cloth" because it might yield a "cloth spellbook" rather than a "piece of cloth" cloak [maybe we should give random armor?] */ - && strcmpi(bp, "clothes") + && strcmpi(d->bp, "clothes") ) { - char *sng = makesingular(bp); + char *sng = makesingular(d->bp); - if (strcmp(bp, sng)) { - if (cnt == 1) - cnt = 2; - Strcpy(bp, sng); + if (strcmp(d->bp, sng)) { + if (d->cnt == 1) + d->cnt = 2; + Strcpy(d->bp, sng); } } @@ -3675,53 +3705,53 @@ struct obj *no_wish; const struct alt_spellings *as = spellings; while (as->sp) { - if (wishymatch(bp, as->sp, TRUE)) { - typ = as->ob; - goto typfnd; + if (wishymatch(d->bp, as->sp, TRUE)) { + d->typ = as->ob; + return 2; /*goto typfnd;*/ } as++; } /* can't use spellings list for this one due to shuffling */ - if (!strncmpi(bp, "grey spell", 10)) - *(bp + 2) = 'a'; + if (!strncmpi(d->bp, "grey spell", 10)) + *(d->bp + 2) = 'a'; - if ((p = strstri(bp, "armour")) != 0) { + if ((d->p = strstri(d->bp, "armour")) != 0) { /* skip past "armo", then copy remainder beyond "u" */ - p += 4; - while ((*p = *(p + 1)) != '\0') - ++p; /* self terminating */ + d->p += 4; + while ((*d->p = *(d->p + 1)) != '\0') + ++d->p; /* self terminating */ } } /* dragon scales - assumes order of dragons */ - if (!strcmpi(bp, "scales") && mntmp >= PM_GRAY_DRAGON - && mntmp <= PM_YELLOW_DRAGON) { - typ = GRAY_DRAGON_SCALES + mntmp - PM_GRAY_DRAGON; - mntmp = NON_PM; /* no monster */ - goto typfnd; + if (!strcmpi(d->bp, "scales") && d->mntmp >= PM_GRAY_DRAGON + && d->mntmp <= PM_YELLOW_DRAGON) { + d->typ = GRAY_DRAGON_SCALES + d->mntmp - PM_GRAY_DRAGON; + d->mntmp = NON_PM; /* no monster */ + return 2; /*goto typfnd;*/ } - p = eos(bp); - if (!BSTRCMPI(bp, p - 10, "holy water")) { - typ = POT_WATER; - if ((p - bp) >= 12 && *(p - 12) == 'u') - iscursed = 1; /* unholy water */ + d->p = eos(d->bp); + if (!BSTRCMPI(d->bp, d->p - 10, "holy water")) { + d->typ = POT_WATER; + if ((d->p - d->bp) >= 12 && *(d->p - 12) == 'u') + d->iscursed = 1; /* unholy water */ else - blessed = 1; - goto typfnd; + d->blessed = 1; + return 2; /*goto typfnd;*/ } - if (unlabeled && !BSTRCMPI(bp, p - 6, "scroll")) { - typ = SCR_BLANK_PAPER; - goto typfnd; + if (d->unlabeled && !BSTRCMPI(d->bp, d->p - 6, "scroll")) { + d->typ = SCR_BLANK_PAPER; + return 2; /*goto typfnd;*/ } - if (unlabeled && !BSTRCMPI(bp, p - 9, "spellbook")) { - typ = SPE_BLANK_PAPER; - goto typfnd; + if (d->unlabeled && !BSTRCMPI(d->bp, d->p - 9, "spellbook")) { + d->typ = SPE_BLANK_PAPER; + return 2; /*goto typfnd;*/ } /* specific food rather than color of gem/potion/spellbook[/scales] */ - if (!BSTRCMPI(bp, p - 6, "orange") && mntmp == NON_PM) { - typ = ORANGE; - goto typfnd; + if (!BSTRCMPI(d->bp, d->p - 6, "orange") && d->mntmp == NON_PM) { + d->typ = ORANGE; + return 2; /*goto typfnd;*/ } /* * NOTE: Gold pieces are handled as objects nowadays, and therefore @@ -3729,62 +3759,62 @@ struct obj *no_wish; * gold/money concept. Maybe we want to add other monetary units as * well in the future. (TH) */ - if (!BSTRCMPI(bp, p - 10, "gold piece") - || !BSTRCMPI(bp, p - 7, "zorkmid") - || !strcmpi(bp, "gold") || !strcmpi(bp, "money") - || !strcmpi(bp, "coin") || *bp == GOLD_SYM) { - if (cnt > 5000 && !wizard) - cnt = 5000; - else if (cnt < 1) - cnt = 1; - otmp = mksobj(GOLD_PIECE, FALSE, FALSE); - otmp->quan = (long) cnt; - otmp->owt = weight(otmp); + if (!BSTRCMPI(d->bp, d->p - 10, "gold piece") + || !BSTRCMPI(d->bp, d->p - 7, "zorkmid") + || !strcmpi(d->bp, "gold") || !strcmpi(d->bp, "money") + || !strcmpi(d->bp, "coin") || *d->bp == GOLD_SYM) { + if (d->cnt > 5000 && !wizard) + d->cnt = 5000; + else if (d->cnt < 1) + d->cnt = 1; + d->otmp = mksobj(GOLD_PIECE, FALSE, FALSE); + d->otmp->quan = (long) d->cnt; + d->otmp->owt = weight(d->otmp); g.context.botl = 1; - return otmp; + return 3; /*return otmp;*/ } /* check for single character object class code ("/" for wand, &c) */ - if (strlen(bp) == 1 && (i = def_char_to_objclass(*bp)) < MAXOCLASSES + if (strlen(d->bp) == 1 && (i = def_char_to_objclass(*d->bp)) < MAXOCLASSES && i > ILLOBJ_CLASS && (i != VENOM_CLASS || wizard)) { - oclass = i; - goto any; + d->oclass = i; + return 4; /*goto any;*/ } /* Search for class names: XXXXX potion, scroll of XXXXX. Avoid */ /* false hits on, e.g., rings for "ring mail". */ - if (strncmpi(bp, "enchant ", 8) - && strncmpi(bp, "destroy ", 8) - && strncmpi(bp, "detect food", 11) - && strncmpi(bp, "food detection", 14) - && strncmpi(bp, "ring mail", 9) - && strncmpi(bp, "studded leather armor", 21) - && strncmpi(bp, "leather armor", 13) - && strncmpi(bp, "tooled horn", 11) - && strncmpi(bp, "food ration", 11) - && strncmpi(bp, "meat ring", 9)) + if (strncmpi(d->bp, "enchant ", 8) + && strncmpi(d->bp, "destroy ", 8) + && strncmpi(d->bp, "detect food", 11) + && strncmpi(d->bp, "food detection", 14) + && strncmpi(d->bp, "ring mail", 9) + && strncmpi(d->bp, "studded leather armor", 21) + && strncmpi(d->bp, "leather armor", 13) + && strncmpi(d->bp, "tooled horn", 11) + && strncmpi(d->bp, "food ration", 11) + && strncmpi(d->bp, "meat ring", 9)) for (i = 0; i < (int) (sizeof wrpsym); i++) { register int j = strlen(wrp[i]); - if (!strncmpi(bp, wrp[i], j)) { - oclass = wrpsym[i]; - if (oclass != AMULET_CLASS) { - bp += j; - if (!strncmpi(bp, " of ", 4)) - actualn = bp + 4; + if (!strncmpi(d->bp, wrp[i], j)) { + d->oclass = wrpsym[i]; + if (d->oclass != AMULET_CLASS) { + d->bp += j; + if (!strncmpi(d->bp, " of ", 4)) + d->actualn = d->bp + 4; /* else if(*bp) ?? */ } else - actualn = bp; - goto srch; + d->actualn = d->bp; + return 1; /*goto srch;*/ } - if (!BSTRCMPI(bp, p - j, wrp[i])) { - oclass = wrpsym[i]; - p -= j; - *p = 0; - if (p > bp && p[-1] == ' ') - p[-1] = 0; - actualn = dn = bp; - goto srch; + if (!BSTRCMPI(d->bp, d->p - j, wrp[i])) { + d->oclass = wrpsym[i]; + d->p -= j; + *d->p = 0; + if (d->p > d->bp && d->p[-1] == ' ') + d->p[-1] = 0; + d->actualn = d->dn = d->bp; + return 1; /*goto srch;*/ } } @@ -3804,51 +3834,61 @@ struct obj *no_wish; * " object", but " trap" is suggested--to either the trap * name or the object name. */ - if (wizard && (!strncmpi(bp, "bear", 4) || !strncmpi(bp, "land", 4))) { - boolean beartrap = (lowc(*bp) == 'b'); - char *zp = bp + 4; /* skip "bear"/"land" */ + if (wizard && (!strncmpi(d->bp, "bear", 4) || !strncmpi(d->bp, "land", 4))) { + boolean beartrap = (lowc(*d->bp) == 'b'); + char *zp = d->bp + 4; /* skip "bear"/"land" */ if (*zp == ' ') ++zp; /* embedded space is optional */ if (!strncmpi(zp, beartrap ? "trap" : "mine", 4)) { zp += 4; - if (trapped == 2 || !strcmpi(zp, " object")) { + if (d->trapped == 2 || !strcmpi(zp, " object")) { /* "untrapped " or " object" */ - typ = beartrap ? BEARTRAP : LAND_MINE; - goto typfnd; - } else if (trapped == 1 || *zp != '\0') { + d->typ = beartrap ? BEARTRAP : LAND_MINE; + return 2; /*goto typfnd;*/ + } else if (d->trapped == 1 || *zp != '\0') { /* "trapped " or " trap" (actually "*") */ /* use canonical trap spelling, skip object matching */ - Strcpy(bp, trapname(beartrap ? BEAR_TRAP : LANDMINE, TRUE)); - goto wiztrap; + Strcpy(d->bp, trapname(beartrap ? BEAR_TRAP : LANDMINE, TRUE)); + return 5; /*goto wiztrap;*/ } /* [no prefix or suffix; we're going to end up matching the object name and getting a disarmed trap object] */ } } - retry: + return 0; +} + +static int +readobjnam_postparse2(d) +struct _readobjnam_data *d; +{ + int i; + /* "grey stone" check must be before general "stone" */ for (i = 0; i < SIZE(o_ranges); i++) - if (!strcmpi(bp, o_ranges[i].name)) { - typ = rnd_class(o_ranges[i].f_o_range, o_ranges[i].l_o_range); - goto typfnd; + if (!strcmpi(d->bp, o_ranges[i].name)) { + d->typ = rnd_class(o_ranges[i].f_o_range, o_ranges[i].l_o_range); + return 2; /*goto typfnd;*/ } - if (!BSTRCMPI(bp, p - 6, " stone") || !BSTRCMPI(bp, p - 4, " gem")) { - p[!strcmpi(p - 4, " gem") ? -4 : -6] = '\0'; - oclass = GEM_CLASS; - dn = actualn = bp; - goto srch; - } else if (!strcmpi(bp, "looking glass")) { + if (!BSTRCMPI(d->bp, d->p - 6, " stone") || !BSTRCMPI(d->bp, d->p - 4, " gem")) { + d->p[!strcmpi(d->p - 4, " gem") ? -4 : -6] = '\0'; + d->oclass = GEM_CLASS; + d->dn = d->actualn = d->bp; + return 1; /*goto srch;*/ + } else if (!strcmpi(d->bp, "looking glass")) { ; /* avoid false hit on "* glass" */ - } else if (!BSTRCMPI(bp, p - 6, " glass") || !strcmpi(bp, "glass")) { - register char *s = bp; + } else if (!BSTRCMPI(d->bp, d->p - 6, " glass") || !strcmpi(d->bp, "glass")) { + register char *s = d->bp; /* treat "broken glass" as a non-existent item; since "broken" is also a chest/box prefix it might have been stripped off above */ - if (broken || strstri(s, "broken")) - return (struct obj *) 0; + if (d->broken || strstri(s, "broken")) { + d->otmp = (struct obj *) 0; + return 3; /* return otmp */ + } if (!strncmpi(s, "worthless ", 10)) s += 10; if (!strncmpi(s, "piece of ", 9)) @@ -3859,59 +3899,68 @@ struct obj *no_wish; s += 9; if (!strcmpi(s, "glass")) { /* choose random color */ /* 9 different kinds */ - typ = LAST_GEM + rnd(9); - if (objects[typ].oc_class == GEM_CLASS) - goto typfnd; + d->typ = LAST_GEM + rnd(9); + if (objects[d->typ].oc_class == GEM_CLASS) + return 2; /*goto typfnd;*/ else - typ = 0; /* somebody changed objects[]? punt */ + d->typ = 0; /* somebody changed objects[]? punt */ } else { /* try to construct canonical form */ char tbuf[BUFSZ]; Strcpy(tbuf, "worthless piece of "); Strcat(tbuf, s); /* assume it starts with the color */ - Strcpy(bp, tbuf); + Strcpy(d->bp, tbuf); } } - actualn = bp; - if (!dn) - dn = actualn; /* ex. "skull cap" */ - srch: + d->actualn = d->bp; + if (!d->dn) + d->dn = d->actualn; /* ex. "skull cap" */ + + return 0; +} + +static int +readobjnam_postparse3(d) +struct _readobjnam_data *d; +{ + int i; + /* check real names of gems first */ - if (!oclass && actualn) { + if (!d->oclass && d->actualn) { for (i = g.bases[GEM_CLASS]; i <= LAST_GEM; i++) { register const char *zn; - if ((zn = OBJ_NAME(objects[i])) != 0 && !strcmpi(actualn, zn)) { - typ = i; - goto typfnd; + if ((zn = OBJ_NAME(objects[i])) != 0 && !strcmpi(d->actualn, zn)) { + d->typ = i; + return 2; /*goto typfnd;*/ } } /* "tin of foo" would be caught above, but plain "tin" has a random chance of yielding "tin wand" unless we do this */ - if (!strcmpi(actualn, "tin")) { - typ = TIN; - goto typfnd; + if (!strcmpi(d->actualn, "tin")) { + d->typ = TIN; + return 2; /*goto typfnd;*/ } } - if (((typ = rnd_otyp_by_namedesc(actualn, oclass, 1)) != STRANGE_OBJECT) - || (dn != actualn - && (typ = rnd_otyp_by_namedesc(dn, oclass, 1)) != STRANGE_OBJECT) - || ((typ = rnd_otyp_by_namedesc(un, oclass, 1)) != STRANGE_OBJECT) - || (origbp != actualn - && ((typ = rnd_otyp_by_namedesc(origbp, oclass, 1)) + if (((d->typ = rnd_otyp_by_namedesc(d->actualn, d->oclass, 1)) != STRANGE_OBJECT) + || (d->dn != d->actualn + && (d->typ = rnd_otyp_by_namedesc(d->dn, d->oclass, 1)) != STRANGE_OBJECT) + || ((d->typ = rnd_otyp_by_namedesc(d->un, d->oclass, 1)) != STRANGE_OBJECT) + || (d->origbp != d->actualn + && ((d->typ = rnd_otyp_by_namedesc(d->origbp, d->oclass, 1)) != STRANGE_OBJECT))) - goto typfnd; - typ = 0; + return 2; /*goto typfnd;*/ + d->typ = 0; - if (actualn) { + if (d->actualn) { struct Jitem *j = Japanese_items; while (j->item) { - if (actualn && !strcmpi(actualn, j->name)) { - typ = j->item; - goto typfnd; + if (d->actualn && !strcmpi(d->actualn, j->name)) { + d->typ = j->item; + return 2; /*goto typfnd;*/ } j++; } @@ -3919,17 +3968,31 @@ struct obj *no_wish; /* if we've stripped off "armor" and failed to match anything in objects[], append "mail" and try again to catch misnamed requests like "plate armor" and "yellow dragon scale armor" */ - if (oclass == ARMOR_CLASS && !strstri(bp, "mail")) { + if (d->oclass == ARMOR_CLASS && !strstri(d->bp, "mail")) { /* modifying bp's string is ok; we're about to resort to random armor if this also fails to match anything */ - Strcat(bp, " mail"); - goto retry; + Strcat(d->bp, " mail"); + return 6; /*goto retry;*/ } - if (!strcmpi(bp, "spinach")) { - contents = SPINACH; - typ = TIN; - goto typfnd; + if (!strcmpi(d->bp, "spinach")) { + d->contents = SPINACH; + d->typ = TIN; + return 2; /*goto typfnd;*/ } + /* Fruits must not mess up the ability to wish for real objects (since + * you can leave a fruit in a bones file and it will be added to + * another person's game), so they must be checked for last, after + * stripping all the possible prefixes and seeing if there's a real + * name in there. So we have to save the full original name. However, + * it's still possible to do things like "uncursed burnt Alaska", + * or worse yet, "2 burned 5 course meals", so we need to loop to + * strip off the prefixes again, this time stripping only the ones + * possible on food. + * We could get even more detailed so as to allow food names with + * prefixes that _are_ possible on food, so you could wish for + * "2 3 alarm chilis". Currently this isn't allowed; options.c + * automatically sticks 'candied' in front of such names. + */ /* Note: not strcmpi. 2 fruits, one capital, one not, are possible. Also not strncmp. We used to ignore trailing text with it, but that resulted in "grapefruit" matching "grape" if the latter came @@ -3938,11 +4001,12 @@ struct obj *no_wish; char *fp; int l, cntf; int blessedf, iscursedf, uncursedf, halfeatenf; + struct fruit *f; blessedf = iscursedf = uncursedf = halfeatenf = 0; cntf = 0; - fp = fruitbuf; + fp = d->fruitbuf; for (;;) { if (!fp || !*fp) break; @@ -3980,11 +4044,11 @@ struct obj *no_wish; else if (!strcmp(fp, makeplural(f->fname))) ftyp = 3; if (ftyp) { - typ = SLIME_MOLD; - blessed = blessedf; - iscursed = iscursedf; - uncursed = uncursedf; - halfeaten = halfeatenf; + d->typ = SLIME_MOLD; + d->blessed = blessedf; + d->iscursed = iscursedf; + d->uncursed = uncursedf; + d->halfeaten = halfeatenf; /* adjust count if user explicitly asked for singular amount (can't happen unless fruit has been given an already pluralized name) @@ -3993,24 +4057,97 @@ struct obj *no_wish; cntf = 1; else if (ftyp == 3 && !cntf) cntf = 2; - cnt = cntf; - ftype = f->fid; - goto typfnd; + d->cnt = cntf; + d->ftype = f->fid; + return 2; /*goto typfnd;*/ } } } - if (!oclass && actualn) { + if (!d->oclass && d->actualn) { short objtyp; /* Perhaps it's an artifact specified by name, not type */ - name = artifact_name(actualn, &objtyp); - if (name) { - typ = objtyp; - goto typfnd; + d->name = artifact_name(d->actualn, &objtyp); + if (d->name) { + d->typ = objtyp; + return 2; /*goto typfnd;*/ } } + return 0; +} + + +/* + * Return something wished for. Specifying a null pointer for + * the user request string results in a random object. Otherwise, + * if asking explicitly for "nothing" (or "nil") return no_wish; + * if not an object return &cg.zeroobj; if an error (no matching object), + * return null. + */ +struct obj * +readobjnam(bp, no_wish) +register char *bp; +struct obj *no_wish; +{ + struct _readobjnam_data d; + + readobjnam_init(bp, &d); + if (!bp) + goto any; + + /* first, remove extra whitespace they may have typed */ + (void) mungspaces(bp); + /* allow wishing for "nothing" to preserve wishless conduct... + [now requires "wand of nothing" if that's what was really wanted] */ + if (!strcmpi(bp, "nothing") || !strcmpi(bp, "nil") + || !strcmpi(bp, "none")) + return no_wish; + /* save the [nearly] unmodified choice string */ + Strcpy(d.fruitbuf, bp); + + if (readobjnam_preparse(&d)) + goto any; + + if (!d.cnt) + d.cnt = 1; /* will be changed to 2 if makesingular() changes string */ + + readobjnam_parse_charges(&d); + + switch (readobjnam_postparse1(&d)) { + default: + case 0: break; + case 1: goto srch; + case 2: goto typfnd; + case 3: return d.otmp; + case 4: goto any; + case 5: goto wiztrap; + } + + retry: + switch (readobjnam_postparse2(&d)) { + default: + case 0: break; + case 1: goto srch; + case 2: goto typfnd; + case 3: return d.otmp; + case 4: goto any; + case 5: goto wiztrap; + } + + srch: + switch (readobjnam_postparse3(&d)) { + default: + case 0: break; + case 1: goto srch; + case 2: goto typfnd; + case 3: return d.otmp; + case 4: goto any; + case 5: goto wiztrap; + case 6: goto retry; + } + /* * Let wizards wish for traps and furniture. * Must come after objects check so wizards can still wish for @@ -4020,50 +4157,50 @@ struct obj *no_wish; wiztrap: if (wizard && !g.program_state.wizkit_wishing) { /* [inline code moved to separate routine to unclutter readobjnam] */ - if ((otmp = wizterrainwish(bp, p, locked, trapped)) != 0) - return otmp; + if ((d.otmp = wizterrainwish(d.bp, d.p, d.locked, d.trapped)) != 0) + return d.otmp; } - if (!oclass && !typ) { - if (!strncmpi(bp, "polearm", 7)) { - typ = rnd_otyp_by_wpnskill(P_POLEARMS); + if (!d.oclass && !d.typ) { + if (!strncmpi(d.bp, "polearm", 7)) { + d.typ = rnd_otyp_by_wpnskill(P_POLEARMS); goto typfnd; - } else if (!strncmpi(bp, "hammer", 6)) { - typ = rnd_otyp_by_wpnskill(P_HAMMER); + } else if (!strncmpi(d.bp, "hammer", 6)) { + d.typ = rnd_otyp_by_wpnskill(P_HAMMER); goto typfnd; } } - if (!oclass) + if (!d.oclass) return ((struct obj *) 0); any: - if (!oclass) - oclass = wrpsym[rn2((int) sizeof wrpsym)]; + if (!d.oclass) + d.oclass = wrpsym[rn2((int) sizeof wrpsym)]; typfnd: - if (typ) - oclass = objects[typ].oc_class; + if (d.typ) + d.oclass = objects[d.typ].oc_class; /* handle some objects that are only allowed in wizard mode */ - if (typ && !wizard) { - switch (typ) { + if (d.typ && !wizard) { + switch (d.typ) { case AMULET_OF_YENDOR: - typ = FAKE_AMULET_OF_YENDOR; + d.typ = FAKE_AMULET_OF_YENDOR; break; case CANDELABRUM_OF_INVOCATION: - typ = rnd_class(TALLOW_CANDLE, WAX_CANDLE); + d.typ = rnd_class(TALLOW_CANDLE, WAX_CANDLE); break; case BELL_OF_OPENING: - typ = BELL; + d.typ = BELL; break; case SPE_BOOK_OF_THE_DEAD: - typ = SPE_BLANK_PAPER; + d.typ = SPE_BLANK_PAPER; break; case MAGIC_LAMP: - typ = OIL_LAMP; + d.typ = OIL_LAMP; break; default: /* catch any other non-wishable objects (venom) */ - if (objects[typ].oc_nowish) + if (objects[d.typ].oc_nowish) return (struct obj *) 0; break; } @@ -4071,159 +4208,168 @@ struct obj *no_wish; /* if asking for corpse of a monster which leaves behind a glob, give glob instead of rejecting the monster type to create random corpse */ - if (typ == CORPSE && mntmp >= LOW_PM && mons[mntmp].mlet == S_PUDDING) { - typ = GLOB_OF_GRAY_OOZE + (mntmp - PM_GRAY_OOZE); - mntmp = NON_PM; /* not used for globs */ + if (d.typ == CORPSE && d.mntmp >= LOW_PM + && mons[d.mntmp].mlet == S_PUDDING) { + d.typ = GLOB_OF_GRAY_OOZE + (d.mntmp - PM_GRAY_OOZE); + d.mntmp = NON_PM; /* not used for globs */ } /* * Create the object, then fine-tune it. */ - otmp = typ ? mksobj(typ, TRUE, FALSE) : mkobj(oclass, FALSE); - typ = otmp->otyp, oclass = otmp->oclass; /* what we actually got */ + d.otmp = d.typ ? mksobj(d.typ, TRUE, FALSE) : mkobj(d.oclass, FALSE); + d.typ = d.otmp->otyp, d.oclass = d.otmp->oclass; /* what we actually got */ - if (islit && (typ == OIL_LAMP || typ == MAGIC_LAMP || typ == BRASS_LANTERN - || Is_candle(otmp) || typ == POT_OIL)) { - place_object(otmp, u.ux, u.uy); /* make it viable light source */ - begin_burn(otmp, FALSE); - obj_extract_self(otmp); /* now release it for caller's use */ + if (d.islit && (d.typ == OIL_LAMP || d.typ == MAGIC_LAMP + || d.typ == BRASS_LANTERN + || Is_candle(d.otmp) || d.typ == POT_OIL)) { + place_object(d.otmp, u.ux, u.uy); /* make it viable light source */ + begin_burn(d.otmp, FALSE); + obj_extract_self(d.otmp); /* now release it for caller's use */ } /* if player specified a reasonable count, maybe honor it */ - if (cnt > 0 && objects[typ].oc_merge - && (wizard || cnt < rnd(6) || (cnt <= 7 && Is_candle(otmp)) - || (cnt <= 20 && ((oclass == WEAPON_CLASS && is_ammo(otmp)) - || typ == ROCK || is_missile(otmp))))) - otmp->quan = (long) cnt; + if (d.cnt > 0 && objects[d.typ].oc_merge + && (wizard || d.cnt < rnd(6) || (d.cnt <= 7 && Is_candle(d.otmp)) + || (d.cnt <= 20 && ((d.oclass == WEAPON_CLASS && is_ammo(d.otmp)) + || d.typ == ROCK || is_missile(d.otmp))))) + d.otmp->quan = (long) d.cnt; - if (oclass == VENOM_CLASS) - otmp->spe = 1; - - if (spesgn == 0) { - spe = otmp->spe; + if (d.spesgn == 0) { + /* spe not specifed; retain the randomly assigned value */ + d.spe = d.otmp->spe; } else if (wizard) { - ; /* no alteration to spe */ - } else if (oclass == ARMOR_CLASS || oclass == WEAPON_CLASS - || is_weptool(otmp) - || (oclass == RING_CLASS && objects[typ].oc_charged)) { - if (spe > rnd(5) && spe > otmp->spe) - spe = 0; - if (spe > 2 && Luck < 0) - spesgn = -1; + ; /* no restrictions except SPE_LIM */ + } else if (d.oclass == ARMOR_CLASS || d.oclass == WEAPON_CLASS + || is_weptool(d.otmp) + || (d.oclass == RING_CLASS && objects[d.typ].oc_charged)) { + if (d.spe > rnd(5) && d.spe > d.otmp->spe) + d.spe = 0; + if (d.spe > 2 && Luck < 0) + d.spesgn = -1; } else { - if (oclass == WAND_CLASS) { - if (spe > 1 && spesgn == -1) - spe = 1; + /* crystal ball cancels like a wand, to (n:-1) */ + if (d.oclass == WAND_CLASS || d.typ == CRYSTAL_BALL) { + if (d.spe > 1 && d.spesgn == -1) + d.spe = 1; } else { - if (spe > 0 && spesgn == -1) - spe = 0; + if (d.spe > 0 && d.spesgn == -1) + d.spe = 0; } - if (spe > otmp->spe) - spe = otmp->spe; + if (d.spe > d.otmp->spe) + d.spe = d.otmp->spe; } - if (spesgn == -1) - spe = -spe; + if (d.spesgn == -1) + d.spe = -d.spe; /* set otmp->spe. This may, or may not, use spe... */ - switch (typ) { + switch (d.typ) { case TIN: - if (contents == EMPTY) { - otmp->corpsenm = NON_PM; - otmp->spe = 0; - } else if (contents == SPINACH) { - otmp->corpsenm = NON_PM; - otmp->spe = 1; + if (d.contents == EMPTY) { + d.otmp->corpsenm = NON_PM; + d.otmp->spe = 0; + } else if (d.contents == SPINACH) { + d.otmp->corpsenm = NON_PM; + d.otmp->spe = 1; } break; case TOWEL: - if (wetness) - otmp->spe = wetness; + if (d.wetness) + d.otmp->spe = d.wetness; break; case SLIME_MOLD: - otmp->spe = ftype; + d.otmp->spe = d.ftype; /* Fall through */ case SKELETON_KEY: case CHEST: case LARGE_BOX: case HEAVY_IRON_BALL: case IRON_CHAIN: + break; case STATUE: /* otmp->cobj already done in mksobj() */ + if (d.mgend) + d.otmp->spe |= STATUE_FEMALE; break; #ifdef MAIL_STRUCTURES + /* 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: - /* 0: delivered in-game via external event (or randomly for fake mail); - 1: from bones or wishing; 2: written with marker */ - otmp->spe = 1; - break; + /*FALLTHRU*/ #endif + /* splash of venom: 0: normal, and transitory; 1: wishing */ + case ACID_VENOM: + case BLINDING_VENOM: + d.otmp->spe = 1; + break; case WAN_WISHING: if (!wizard) { - otmp->spe = (rn2(10) ? -1 : 0); + d.otmp->spe = (rn2(10) ? -1 : 0); break; } /*FALLTHRU*/ default: - otmp->spe = spe; + d.otmp->spe = d.spe; } /* set otmp->corpsenm or dragon scale [mail] */ - if (mntmp >= LOW_PM) { + if (d.mntmp >= LOW_PM) { int humanwere; - if (mntmp == PM_LONG_WORM_TAIL) - mntmp = PM_LONG_WORM; + if (d.mntmp == PM_LONG_WORM_TAIL) + d.mntmp = PM_LONG_WORM; /* werecreatures in beast form are all flagged no-corpse so for corpses and tins, switch to their corresponding human form; for figurines, override the can't-be-human restriction instead */ - if (typ != FIGURINE && is_were(&mons[mntmp]) - && (g.mvitals[mntmp].mvflags & G_NOCORPSE) != 0 - && (humanwere = counter_were(mntmp)) != NON_PM) - mntmp = humanwere; + if (d.typ != FIGURINE && is_were(&mons[d.mntmp]) + && (g.mvitals[d.mntmp].mvflags & G_NOCORPSE) != 0 + && (humanwere = counter_were(d.mntmp)) != NON_PM) + d.mntmp = humanwere; - switch (typ) { + switch (d.typ) { case TIN: - otmp->spe = 0; /* No spinach */ - if (dead_species(mntmp, FALSE)) { - otmp->corpsenm = NON_PM; /* it's empty */ - } else if ((!(mons[mntmp].geno & G_UNIQ) || wizard) - && !(g.mvitals[mntmp].mvflags & G_NOCORPSE) - && mons[mntmp].cnutrit != 0) { - otmp->corpsenm = mntmp; + d.otmp->spe = 0; /* No spinach */ + if (dead_species(d.mntmp, FALSE)) { + d.otmp->corpsenm = NON_PM; /* it's empty */ + } else if ((!(mons[d.mntmp].geno & G_UNIQ) || wizard) + && !(g.mvitals[d.mntmp].mvflags & G_NOCORPSE) + && mons[d.mntmp].cnutrit != 0) { + d.otmp->corpsenm = d.mntmp; } break; case CORPSE: - if ((!(mons[mntmp].geno & G_UNIQ) || wizard) - && !(g.mvitals[mntmp].mvflags & G_NOCORPSE)) { - if (mons[mntmp].msound == MS_GUARDIAN) - mntmp = genus(mntmp, 1); - set_corpsenm(otmp, mntmp); + if ((!(mons[d.mntmp].geno & G_UNIQ) || wizard) + && !(g.mvitals[d.mntmp].mvflags & G_NOCORPSE)) { + if (mons[d.mntmp].msound == MS_GUARDIAN) + d.mntmp = genus(d.mntmp, 1); + set_corpsenm(d.otmp, d.mntmp); } break; case EGG: - mntmp = can_be_hatched(mntmp); + d.mntmp = can_be_hatched(d.mntmp); /* this also sets hatch timer if appropriate */ - set_corpsenm(otmp, mntmp); + set_corpsenm(d.otmp, d.mntmp); break; case FIGURINE: - if (!(mons[mntmp].geno & G_UNIQ) - && (!is_human(&mons[mntmp]) || is_were(&mons[mntmp])) + if (!(mons[d.mntmp].geno & G_UNIQ) + && (!is_human(&mons[d.mntmp]) || is_were(&mons[d.mntmp])) #ifdef MAIL_STRUCTURES - && mntmp != PM_MAIL_DAEMON + && d.mntmp != PM_MAIL_DAEMON #endif ) - otmp->corpsenm = mntmp; + d.otmp->corpsenm = d.mntmp; break; case STATUE: - otmp->corpsenm = mntmp; - if (Has_contents(otmp) && verysmall(&mons[mntmp])) - delete_contents(otmp); /* no spellbook */ - otmp->spe = ishistoric ? STATUE_HISTORIC : 0; + d.otmp->corpsenm = d.mntmp; + if (Has_contents(d.otmp) && verysmall(&mons[d.mntmp])) + delete_contents(d.otmp); /* no spellbook */ + d.otmp->spe |= d.ishistoric ? STATUE_HISTORIC : 0; break; case SCALE_MAIL: /* Dragon mail - depends on the order of objects & dragons. */ - if (mntmp >= PM_GRAY_DRAGON && mntmp <= PM_YELLOW_DRAGON) - otmp->otyp = GRAY_DRAGON_SCALE_MAIL + mntmp - PM_GRAY_DRAGON; + if (d.mntmp >= PM_GRAY_DRAGON && d.mntmp <= PM_YELLOW_DRAGON) + d.otmp->otyp = GRAY_DRAGON_SCALE_MAIL + + d.mntmp - PM_GRAY_DRAGON; break; } } @@ -4231,143 +4377,144 @@ struct obj *no_wish; /* set blessed/cursed -- setting the fields directly is safe * since weight() is called below and addinv() will take care * of luck */ - if (iscursed) { - curse(otmp); - } else if (uncursed) { - otmp->blessed = 0; - otmp->cursed = (Luck < 0 && !wizard); - } else if (blessed) { - otmp->blessed = (Luck >= 0 || wizard); - otmp->cursed = (Luck < 0 && !wizard); - } else if (spesgn < 0) { - curse(otmp); + if (d.iscursed) { + curse(d.otmp); + } else if (d.uncursed) { + d.otmp->blessed = 0; + d.otmp->cursed = (Luck < 0 && !wizard); + } else if (d.blessed) { + d.otmp->blessed = (Luck >= 0 || wizard); + d.otmp->cursed = (Luck < 0 && !wizard); + } else if (d.spesgn < 0) { + curse(d.otmp); } /* set eroded and erodeproof */ - if (erosion_matters(otmp)) { - if (eroded && (is_flammable(otmp) || is_rustprone(otmp))) - otmp->oeroded = eroded; - if (eroded2 && (is_corrodeable(otmp) || is_rottable(otmp))) - otmp->oeroded2 = eroded2; + if (erosion_matters(d.otmp)) { + if (d.eroded && (is_flammable(d.otmp) || is_rustprone(d.otmp))) + d.otmp->oeroded = d.eroded; + if (d.eroded2 && (is_corrodeable(d.otmp) || is_rottable(d.otmp))) + d.otmp->oeroded2 = d.eroded2; /* * 3.6.1: earlier versions included `&& !eroded && !eroded2' here, * but damageproof combined with damaged is feasible (eroded * armor modified by confused reading of cursed destroy armor) * so don't prevent player from wishing for such a combination. */ - if (erodeproof && (is_damageable(otmp) || otmp->otyp == CRYSKNIFE)) - otmp->oerodeproof = (Luck >= 0 || wizard); + if (d.erodeproof + && (is_damageable(d.otmp) || d.otmp->otyp == CRYSKNIFE)) + d.otmp->oerodeproof = (Luck >= 0 || wizard); } /* set otmp->recharged */ - if (oclass == WAND_CLASS) { + if (d.oclass == WAND_CLASS) { /* prevent wishing abuse */ - if (otmp->otyp == WAN_WISHING && !wizard) - rechrg = 1; - otmp->recharged = (unsigned) rechrg; + if (d.otmp->otyp == WAN_WISHING && !wizard) + d.rechrg = 1; + d.otmp->recharged = (unsigned) d.rechrg; } /* set poisoned */ - if (ispoisoned) { - if (is_poisonable(otmp)) - otmp->opoisoned = (Luck >= 0); - else if (oclass == FOOD_CLASS) + if (d.ispoisoned) { + if (is_poisonable(d.otmp)) + d.otmp->opoisoned = (Luck >= 0); + else if (d.oclass == FOOD_CLASS) /* try to taint by making it as old as possible */ - otmp->age = 1L; + d.otmp->age = 1L; } /* and [un]trapped */ - if (trapped) { - if (Is_box(otmp) || typ == TIN) - otmp->otrapped = (trapped == 1); + if (d.trapped) { + if (Is_box(d.otmp) || d.typ == TIN) + d.otmp->otrapped = (d.trapped == 1); } /* empty for containers rather than for tins */ - if (contents == EMPTY) { - if (otmp->otyp == BAG_OF_TRICKS || otmp->otyp == HORN_OF_PLENTY) { - if (otmp->spe > 0) - otmp->spe = 0; - } else if (Has_contents(otmp)) { + if (d.contents == EMPTY) { + if (d.otmp->otyp == BAG_OF_TRICKS || d.otmp->otyp == HORN_OF_PLENTY) { + if (d.otmp->spe > 0) + d.otmp->spe = 0; + } else if (Has_contents(d.otmp)) { /* this assumes that artifacts can't be randomly generated inside containers */ - delete_contents(otmp); - otmp->owt = weight(otmp); + delete_contents(d.otmp); + d.otmp->owt = weight(d.otmp); } } /* set locked/unlocked/broken */ - if (Is_box(otmp)) { - if (locked) { - otmp->olocked = 1, otmp->obroken = 0; - } else if (unlocked) { - otmp->olocked = 0, otmp->obroken = 0; - } else if (broken) { - otmp->olocked = 0, otmp->obroken = 1; + if (Is_box(d.otmp)) { + if (d.locked) { + d.otmp->olocked = 1, d.otmp->obroken = 0; + } else if (d.unlocked) { + d.otmp->olocked = 0, d.otmp->obroken = 0; + } else if (d.broken) { + d.otmp->olocked = 0, d.otmp->obroken = 1; } } - if (isgreased) - otmp->greased = 1; + if (d.isgreased) + d.otmp->greased = 1; - if (isdiluted && otmp->oclass == POTION_CLASS && otmp->otyp != POT_WATER) - otmp->odiluted = 1; + if (d.isdiluted && d.otmp->oclass == POTION_CLASS) + d.otmp->odiluted = (d.otmp->otyp != POT_WATER); /* set tin variety */ - if (otmp->otyp == TIN && tvariety >= 0 && (rn2(4) || wizard)) - set_tin_variety(otmp, tvariety); + if (d.otmp->otyp == TIN && d.tvariety >= 0 && (rn2(4) || wizard)) + set_tin_variety(d.otmp, d.tvariety); - if (name) { + if (d.name) { const char *aname; short objtyp; /* an artifact name might need capitalization fixing */ - aname = artifact_name(name, &objtyp); - if (aname && objtyp == otmp->otyp) - name = aname; + aname = artifact_name(d.name, &objtyp); + if (aname && objtyp == d.otmp->otyp) + d.name = aname; /* 3.6 tribute - fix up novel */ - if (otmp->otyp == SPE_NOVEL) { + if (d.otmp->otyp == SPE_NOVEL) { const char *novelname; - novelname = lookup_novel(name, &otmp->novelidx); + novelname = lookup_novel(d.name, &d.otmp->novelidx); if (novelname) - name = novelname; + d.name = novelname; } - otmp = oname(otmp, name); + d.otmp = oname(d.otmp, d.name); /* name==aname => wished for artifact (otmp->oartifact => got it) */ - if (otmp->oartifact || name == aname) { - otmp->quan = 1L; + if (d.otmp->oartifact || d.name == aname) { + d.otmp->quan = 1L; u.uconduct.wisharti++; /* KMH, conduct */ } } /* more wishing abuse: don't allow wishing for certain artifacts */ /* and make them pay; charge them for the wish anyway! */ - if ((is_quest_artifact(otmp) - || (otmp->oartifact && rn2(nartifact_exist()) > 1)) && !wizard) { - artifact_exists(otmp, safe_oname(otmp), FALSE); - obfree(otmp, (struct obj *) 0); - otmp = (struct obj *) &cg.zeroobj; + if ((is_quest_artifact(d.otmp) + || (d.otmp->oartifact && rn2(nartifact_exist()) > 1)) && !wizard) { + artifact_exists(d.otmp, safe_oname(d.otmp), FALSE); + obfree(d.otmp, (struct obj *) 0); + d.otmp = (struct obj *) &cg.zeroobj; pline("For a moment, you feel %s in your %s, but it disappears!", something, makeplural(body_part(HAND))); - return otmp; + return d.otmp; } - if (halfeaten && otmp->oclass == FOOD_CLASS) { - if (otmp->otyp == CORPSE) - otmp->oeaten = mons[otmp->corpsenm].cnutrit; + if (d.halfeaten && d.otmp->oclass == FOOD_CLASS) { + if (d.otmp->otyp == CORPSE) + d.otmp->oeaten = mons[d.otmp->corpsenm].cnutrit; else - otmp->oeaten = objects[otmp->otyp].oc_nutrition; + d.otmp->oeaten = objects[d.otmp->otyp].oc_nutrition; /* (do this adjustment before setting up object's weight) */ - consume_oeaten(otmp, 1); + consume_oeaten(d.otmp, 1); } - otmp->owt = weight(otmp); - if (very && otmp->otyp == HEAVY_IRON_BALL) - otmp->owt += IRON_BALL_W_INCR; - else if (gsize > 1 && otmp->globby) + d.otmp->owt = weight(d.otmp); + if (d.very && d.otmp->otyp == HEAVY_IRON_BALL) + d.otmp->owt += IRON_BALL_W_INCR; + else if (d.gsize > 1 && d.otmp->globby) /* 0: unspecified => small; 1: small => keep default owt of 20; 2: medium => 120; 3: large => 320; 4: very large => 520 */ - otmp->owt += 100 + (gsize - 2) * 200; + d.otmp->owt += 100 + (d.gsize - 2) * 200; - return otmp; + return d.otmp; } int diff --git a/src/options.c b/src/options.c index 871fcf21e..d58c4e1f0 100644 --- a/src/options.c +++ b/src/options.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 options.c $NHDT-Date: 1594168619 2020/07/08 00:36:59 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.468 $ */ +/* NetHack 3.7 options.c $NHDT-Date: 1608606126 2020/12/22 03:02:06 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.489 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2008. */ /* NetHack may be freely redistributed. See license for details. */ @@ -204,18 +204,19 @@ static NEARDATA const char *runmodes[] = { "teleport", "run", "walk", static NEARDATA const char *sortltype[] = { "none", "loot", "full" }; static const menu_cmd_t default_menu_cmd_info[] = { - { "menu_first_page", MENU_FIRST_PAGE, "Go to first page" }, - { "menu_last_page", MENU_LAST_PAGE, "Go to last page" }, { "menu_next_page", MENU_NEXT_PAGE, "Go to next page" }, { "menu_previous_page", MENU_PREVIOUS_PAGE, "Go to previous page" }, - { "menu_select_all", MENU_SELECT_ALL, "Select all items" }, - { "menu_deselect_all", MENU_UNSELECT_ALL, "Unselect all items" }, - { "menu_invert_all", MENU_INVERT_ALL, "Invert selection" }, - { "menu_select_page", MENU_SELECT_PAGE, "Select items in current page" }, + { "menu_first_page", MENU_FIRST_PAGE, "Go to first page" }, + { "menu_last_page", MENU_LAST_PAGE, "Go to last page" }, + { "menu_select_all", MENU_SELECT_ALL, "Select all items in entire menu" }, + { "menu_invert_all", MENU_INVERT_ALL, "Invert selection for all items" }, + { "menu_deselect_all", MENU_UNSELECT_ALL, + "Unselect all items in entire menu" }, + { "menu_select_page", MENU_SELECT_PAGE, "Select all items on current page" }, + { "menu_invert_page", MENU_INVERT_PAGE, "Invert current page's selections" }, { "menu_deselect_page", MENU_UNSELECT_PAGE, - "Unselect items in current page" }, - { "menu_invert_page", MENU_INVERT_PAGE, "Invert current page selection" }, - { "menu_search", MENU_SEARCH, "Search and toggle matching items" }, + "Unselect all items on current page" }, + { "menu_search", MENU_SEARCH, "Search and invert matching items" }, }; static void FDECL(nmcpy, (char *, const char *, int)); @@ -235,23 +236,23 @@ static int FDECL(check_misc_menu_command, (char *, char *)); int FDECL(spcfn_misc_menu_cmd, (int, int, BOOLEAN_P, char *, char *)); static const char *FDECL(attr2attrname, (int)); +static void FDECL(basic_menu_colors, (BOOLEAN_P)); static const char * FDECL(msgtype2name, (int)); static int NDECL(query_msgtype); static boolean FDECL(msgtype_add, (int, char *)); static void FDECL(free_one_msgtype, (int)); static int NDECL(msgtype_count); static boolean FDECL(test_regex_pattern, (const char *, const char *)); -static boolean FDECL(add_menu_coloring_parsed, (char *, int, int)); +static boolean FDECL(add_menu_coloring_parsed, (const char *, int, int)); static void FDECL(free_one_menu_coloring, (int)); static int NDECL(count_menucolors); static boolean FDECL(parse_role_opts, (int, BOOLEAN_P, const char *, - char *, char **)); + char *, char **)); static void FDECL(doset_add_menu, (winid, const char *, int, int)); -static void FDECL(opts_add_others, (winid, const char *, int, - char *, int)); +static void FDECL(opts_add_others, (winid, const char *, int, char *, int)); static int FDECL(handle_add_list_remove, (const char *, int)); static void FDECL(remove_autopickup_exception, - (struct autopickup_exception *)); + (struct autopickup_exception *)); static int NDECL(count_apes); static int NDECL(count_cond); @@ -281,7 +282,7 @@ static boolean FDECL(is_wc2_option, (const char *)); static boolean FDECL(wc2_supported, (const char *)); static void FDECL(wc_set_font_name, (int, char *)); static int FDECL(wc_set_window_colors, (char *)); -static boolean FDECL(illegal_menu_cmd_key, (CHAR_P)); +static boolean FDECL(illegal_menu_cmd_key, (UCHAR_P)); #ifndef CHANGE_COLOR int FDECL(optfn_palette, (int, int, BOOLEAN_P, char *, char *)); #endif @@ -303,7 +304,10 @@ register char *opts; boolean tinitial, tfrom_file; { char *op; - boolean negated, got_match = FALSE, has_val = FALSE; + boolean negated, got_match = FALSE; +#if 0 + boolean has_val = FALSE; +#endif int i, matchidx = -1, optresult = optn_err, optlen, optlen_wo_val; boolean retval = TRUE; @@ -344,11 +348,16 @@ boolean tinitial, tfrom_file; optlen = (int) strlen(opts); optlen_wo_val = length_without_val(opts, optlen); if (optlen_wo_val < optlen) { +#if 0 has_val = TRUE; +#endif optlen = optlen_wo_val; - } else { + } +#if 0 + else { has_val = FALSE; } +#endif for (i = 0; i < OPTCOUNT; ++i) { got_match = FALSE; @@ -359,14 +368,12 @@ boolean tinitial, tfrom_file; got_match = TRUE; } } - -#if 0 +#if 0 /* this prevents "boolopt:True" &c */ if (!got_match) { if (has_val && !allopt[i].valok) continue; } #endif - /* * During option initialization, the function * determine_ambiguities() @@ -692,8 +699,7 @@ char *op UNUSED; #ifdef BACKWARD_COMPAT /* if ((opts = string_for_env_opt(allopt[optidx].name, opts, FALSE)) - == - empty_optstr) + == empty_optstr) */ if ((opts = string_for_opt(opts, FALSE)) == empty_optstr) return FALSE; @@ -1452,14 +1458,15 @@ char *op; if (g.symset[PRIMARY].name) { badflag = TRUE; } else { - g.symset[PRIMARY].name = dupstr(fullname); + g.symset[PRIMARY].name = dupstr(allopt[optidx].name); if (!read_sym_file(PRIMARY)) { badflag = TRUE; clear_symsetentry(PRIMARY, TRUE); } } if (badflag) { - config_error_add("Failure to load symbol set %s.", fullname); + config_error_add("Failure to load symbol set %s.", + allopt[optidx].name); return FALSE; } else { switch_symbols(TRUE); @@ -2079,6 +2086,13 @@ char *op; return optn_ok; } +/* whether the 'msg_window' option is used to control ^P behavior */ +#if defined(TTY_GRAPHICS) || defined(CURSES_GRAPHICS) +#define PREV_MSGS 1 +#else +#define PREV_MSGS 0 +#endif + int optfn_msg_window(optidx, req, negated, opts, op) int optidx; @@ -2088,8 +2102,12 @@ char *opts; char *op; { int retval = optn_ok; -#ifdef TTY_GRAPHICS +#if PREV_MSGS int tmp; +#else + nhUse(optidx); + nhUse(negated); + nhUse(op); #endif if (req == do_init) { @@ -2098,8 +2116,8 @@ char *op; if (req == do_set) { /* msg_window:single, combo, full or reversed */ -/* allow option to be silently ignored by non-tty ports */ -#ifdef TTY_GRAPHICS + /* allow option to be silently ignored by non-tty ports */ +#if PREV_MSGS if (op == empty_optstr) { tmp = negated ? 's' : 'f'; } else { @@ -2111,16 +2129,10 @@ char *op; } switch (tmp) { case 's': /* single message history cycle (default if negated) */ - iflags.prevmsg_window = 's'; - break; - case 'c': /* combination: two singles, then full page */ - iflags.prevmsg_window = 'c'; - break; + case 'c': /* combination: first two as singles, then full page */ case 'f': /* full page (default if specified without argument) */ - iflags.prevmsg_window = 'f'; - break; - case 'r': /* full page (reversed) */ - iflags.prevmsg_window = 'r'; + case 'r': /* full page in reverse order (LIFO; default for curses) */ + iflags.prevmsg_window = (char) tmp; break; default: config_error_add("Unknown %s parameter '%s'", allopt[optidx].name, @@ -2134,11 +2146,16 @@ char *op; if (!opts) return optn_err; opts[0] = '\0'; -#ifdef TTY_GRAPHICS - Sprintf(opts, "%s", (iflags.prevmsg_window == 's') ? "single" - : (iflags.prevmsg_window == 'c') ? "combination" - : (iflags.prevmsg_window == 'f') ? "full" - : "reversed"); +#if PREV_MSGS + tmp = iflags.prevmsg_window; + if (WINDOWPORT("curses")) { + if (tmp == 's' || tmp == 'c') + tmp = iflags.prevmsg_window = 'r'; + } + Sprintf(opts, "%s", (tmp == 's') ? "single" + : (tmp == 'c') ? "combination" + : (tmp == 'f') ? "full" + : "reversed"); #endif return optn_ok; } @@ -2432,6 +2449,7 @@ char *op; if (!g.opt_initial) { g.opt_need_redraw = TRUE; } + } #endif /* CHANGE_COLOR */ return optn_ok; } @@ -2447,6 +2465,7 @@ char *op; return optn_ok; } + int optfn_paranoid_confirmation(optidx, req, negated, opts, op) int optidx; @@ -3237,6 +3256,66 @@ char *op; return optn_ok; } +int +optfn_sortdiscoveries(optidx, req, negated, opts, op) +int optidx; +int req; +boolean negated; +char *opts; +char *op; +{ + if (req == do_init) { + flags.discosort = 'o'; + return optn_ok; + } + if (req == do_set) { + op = string_for_env_opt(allopt[optidx].name, opts, FALSE); + if (negated) { + flags.discosort = 'o'; + } else if (op != empty_optstr) { + switch (lowc(*op)) { + case '0': + case 'o': /* order of discovery */ + flags.discosort = 'o'; + break; + case '1': + case 's': /* sortloot order (subclasses for some classes) */ + flags.discosort = 's'; + break; + case '2': + case 'c': /* alphabetical within each class */ + flags.discosort = 'c'; + break; + case '3': + case 'a': /* alphabetical across all classes */ + flags.discosort = 'a'; + break; + default: + config_error_add("Unknown %s parameter '%s'", + allopt[optidx].name, op); + return optn_silenterr; + } + } else + return optn_err; + return optn_ok; + } + if (req == get_val) { + extern const char *const disco_orders_descr[]; /* o_init.c */ + extern const char disco_order_let[]; + const char *p = index(disco_order_let, flags.discosort); + + if (!p) + flags.discosort = 'o', p = disco_order_let; + Strcpy(opts, disco_orders_descr[p - disco_order_let]); + return optn_ok; + } + if (req == do_handler) { + /* return handler_sortdiscoveries(); */ + (void) choose_disco_sort(0); /* o_init.c */ + } + return optn_ok; +} + int optfn_sortloot(optidx, req, negated, opts, op) int optidx; @@ -3362,9 +3441,9 @@ char *op; itmp = atoi(op); } if (itmp < 2 || itmp > 3) { - config_error_add("'%s' requires a value of 2 or 3", - allopt[optidx].name); - retval = optn_err; + config_error_add("'%s:%s' is invalid; must be 2 or 3", + allopt[optidx].name, op); + retval = optn_silenterr; } else { iflags.wc2_statuslines = itmp; if (!g.opt_initial) @@ -3483,6 +3562,9 @@ char *op; Strcat(opts, ", active"); return optn_ok; } + if (req == do_handler) { + return handler_symset(optidx); + } return optn_ok; } @@ -4190,13 +4272,9 @@ char *op; if ((op = string_for_env_opt(allopt[optidx].name, opts, FALSE)) != empty_optstr) { + nmcpy(g.chosen_windowtype, op, WINTYPELEN); if (!iflags.windowtype_deferred) { - char buf[WINTYPELEN]; - - nmcpy(buf, op, WINTYPELEN); - choose_windows(buf); - } else { - nmcpy(g.chosen_windowtype, op, WINTYPELEN); + choose_windows(g.chosen_windowtype); } } else return optn_err; @@ -4215,7 +4293,8 @@ char *op; * Prefix-handling functions */ -int pfxfn_cond_(optidx, req, negated, opts, op) +int +pfxfn_cond_(optidx, req, negated, opts, op) int optidx UNUSED; int req; boolean negated; @@ -4259,7 +4338,8 @@ char *op UNUSED; return optn_ok; } -int pfxfn_font(optidx, req, negated, opts, op) +int +pfxfn_font(optidx, req, negated, opts, op) int optidx; int req; boolean negated; @@ -4395,7 +4475,8 @@ char *op; } #if defined(MICRO) && !defined(AMIGA) -int pfxfn_IBM_(optidx, req, negated, opts, op) +int +pfxfn_IBM_(optidx, req, negated, opts, op) int optidx; int req; boolean negated; @@ -4435,6 +4516,8 @@ char *op; return optn_ok; } if (req == do_set) { + boolean nosexchange = FALSE; + if (!allopt[optidx].addr) return optn_ok; /* silent retreat */ @@ -4450,18 +4533,23 @@ char *op; config_error_add( "Negated boolean '%s' should not have a parameter", allopt[optidx].name); - return optn_err; + return optn_silenterr; } + /* length is greater than 0 or we wouldn't have gotten here */ ln = (int) strlen(op); - if (!strncmpi(op, "true", max(ln, 3)) - || !strcmpi(op, "yes") || !strcmpi(op, "on")) { + if (!strncmpi(op, "true", ln) + || !strncmpi(op, "yes", ln) + || !strcmpi(op, "on") + || (digit(*op) && atoi(op) == 1)) { negated = FALSE; - } else if (!strncmpi(op, "false", max(ln, 3)) - || !strcmpi(op, "no") || !strcmpi(op, "off")) { + } else if (!strncmpi(op, "false", ln) + || !strncmpi(op, "no", ln) + || !strcmpi(op, "off") + || (digit(*op) && atoi(op) == 0)) { negated = TRUE; } else if (!allopt[optidx].valok) { - config_error_add("Illegal parameter for a boolean"); - return optn_err; + config_error_add("'%s' is not valid for a boolean", opts); + return optn_silenterr; } } if (iflags.debug_fuzzer && !g.opt_initial) { @@ -4474,8 +4562,7 @@ char *op; case opt_female: if (!strncmpi(opts, "female", 3)) { if (!g.opt_initial && flags.female == negated) { - config_error_add("That is not anatomically possible."); - return optn_err; + nosexchange = TRUE; } else { flags.initgend = flags.female = !negated; return optn_ok; @@ -4483,8 +4570,7 @@ char *op; } if (!strncmpi(opts, "male", 3)) { if (!g.opt_initial && flags.female != negated) { - config_error_add("That is not anatomically possible."); - return optn_err; + nosexchange = TRUE; } else { flags.initgend = flags.female = negated; return optn_ok; @@ -4492,6 +4578,19 @@ char *op; } break; } + /* this dates from when 'O' prompted for a line of options text + rather than use a menu to control access to which options can + be modified during play; it was possible to attempt to use + 'O' to specify female or negate male when playing as male or + to specify male or negate female when playing as female; + options processing rejects that for !opt_initial; not possible + now but kept in case someone brings the old 'O' behavior back */ + if (nosexchange) { + /* can't arbitrarily change sex after game has started; + magic (amulet or polymorph) is required for that */ + config_error_add("'%s' is not anatomically possible.", opts); + return optn_silenterr; + } *(allopt[optidx].addr) = !negated; /* <==== SET IT HERE */ @@ -4567,6 +4666,12 @@ char *op; /* [is reassessment really needed here?] */ status_initialize(REASSESS_ONLY); g.opt_need_redraw = TRUE; +#ifdef QT_GRAPHICS + } else if (WINDOWPORT("Qt")) { + /* Qt doesn't support HILITE_STATUS or FLUSH_STATUS so fails + VIA_WINDOWPORT(), but it does support WC2_HITPOINTBAR */ + g.context.botlx = TRUE; +#endif } break; case opt_color: @@ -4599,7 +4704,8 @@ char *op; return optn_ok; } -int spcfn_misc_menu_cmd(midx, req, negated, opts, op) +int +spcfn_misc_menu_cmd(midx, req, negated, opts, op) int midx; int req; boolean negated; @@ -4619,7 +4725,7 @@ char *op; escapes(op, op_buf); c = *op_buf; - if (illegal_menu_cmd_key(c)) + if (illegal_menu_cmd_key((uchar) c)) return optn_err; add_menu_cmd_alias(c, default_menu_cmd_info[midx].cmd); } @@ -4763,11 +4869,13 @@ handler_disclose(VOID_ARGS) any.a_char = DISCLOSE_NO_WITHOUT_PROMPT; add_menu(tmpwin, NO_GLYPH, &any, 0, any.a_char, ATR_NONE, "Never disclose, without prompting", - (c == any.a_char) ? MENU_ITEMFLAGS_SELECTED : MENU_ITEMFLAGS_NONE); + (c == any.a_char) ? MENU_ITEMFLAGS_SELECTED + : MENU_ITEMFLAGS_NONE); any.a_char = DISCLOSE_YES_WITHOUT_PROMPT; add_menu(tmpwin, NO_GLYPH, &any, 0, any.a_char, ATR_NONE, "Always disclose, without prompting", - (c == any.a_char) ? MENU_ITEMFLAGS_SELECTED : MENU_ITEMFLAGS_NONE); + (c == any.a_char) ? MENU_ITEMFLAGS_SELECTED + : MENU_ITEMFLAGS_NONE); if (*disclosure_names[i] == 'v') { any.a_char = DISCLOSE_SPECIAL_WITHOUT_PROMPT; /* '#' */ add_menu(tmpwin, NO_GLYPH, &any, 0, any.a_char, ATR_NONE, @@ -4778,11 +4886,13 @@ handler_disclose(VOID_ARGS) any.a_char = DISCLOSE_PROMPT_DEFAULT_NO; add_menu(tmpwin, NO_GLYPH, &any, 0, any.a_char, ATR_NONE, "Prompt, with default answer of \"No\"", - (c == any.a_char) ? MENU_ITEMFLAGS_SELECTED : MENU_ITEMFLAGS_NONE); + (c == any.a_char) ? MENU_ITEMFLAGS_SELECTED + : MENU_ITEMFLAGS_NONE); any.a_char = DISCLOSE_PROMPT_DEFAULT_YES; add_menu(tmpwin, NO_GLYPH, &any, 0, any.a_char, ATR_NONE, "Prompt, with default answer of \"Yes\"", - (c == any.a_char) ? MENU_ITEMFLAGS_SELECTED : MENU_ITEMFLAGS_NONE); + (c == any.a_char) ? MENU_ITEMFLAGS_SELECTED + : MENU_ITEMFLAGS_NONE); if (*disclosure_names[i] == 'v') { any.a_char = DISCLOSE_PROMPT_DEFAULT_SPECIAL; /* '?' */ add_menu(tmpwin, NO_GLYPH, &any, 0, any.a_char, ATR_NONE, @@ -5035,7 +5145,8 @@ handler_sortloot(VOID_ARGS) any.a_char = *sortl_name; add_menu(tmpwin, NO_GLYPH, &any, *sortl_name, 0, ATR_NONE, sortl_name, (flags.sortloot == *sortl_name) - ? MENU_ITEMFLAGS_SELECTED : MENU_ITEMFLAGS_NONE); + ? MENU_ITEMFLAGS_SELECTED + : MENU_ITEMFLAGS_NONE); } end_menu(tmpwin, "Select loot sorting type:"); n = select_menu(tmpwin, PICK_ONE, &sortl_pick); @@ -5698,8 +5809,8 @@ int len; substring of a particular option name; option string might have a colon or equals sign and arbitrary value appended to it */ boolean -match_optname(user_string, opt_name, min_length, val_allowed) -const char *user_string, *opt_name; +match_optname(user_string, optn_name, min_length, val_allowed) +const char *user_string, *optn_name; int min_length; boolean val_allowed; { @@ -5709,7 +5820,7 @@ boolean val_allowed; len = length_without_val(user_string, len); return (boolean) (len >= min_length - && !strncmpi(opt_name, user_string, len)); + && !strncmpi(optn_name, user_string, len)); } void @@ -5746,7 +5857,8 @@ int optidx; if (using_alias) Sprintf(buf, " (via alias: %s)", allopt[optidx].alias); config_error_add("%s option specified multiple times: %s%s", - (allopt[optidx].opttyp == CompOpt) ? "compound" : "boolean", + (allopt[optidx].opttyp == CompOpt) ? "compound" + : "boolean", allopt[optidx].name, buf); #endif /* ?MAC */ return; @@ -6316,10 +6428,10 @@ const char *optn; /* parse key:command */ boolean parsebindings(bindings) -char* bindings; +char *bindings; { char *bind; - char key; + uchar key; int i; boolean ret = FALSE; @@ -6354,7 +6466,7 @@ char* bindings; config_error_add("Bad menu key %s:%s", visctrl(key), bind); return FALSE; } else - add_menu_cmd_alias(key, default_menu_cmd_info[i].cmd); + add_menu_cmd_alias((char) key, default_menu_cmd_info[i].cmd); return TRUE; } } @@ -6374,9 +6486,9 @@ char* bindings; * */ -static const struct { +static const struct color_names { const char *name; - const int color; + int color; } colornames[] = { { "black", CLR_BLACK }, { "red", CLR_RED }, @@ -6407,9 +6519,9 @@ static const struct { { "bright cyan", CLR_BRIGHT_CYAN } }; -static const struct { +static const struct attr_names { const char *name; - const int attr; + int attr; } attrnames[] = { { "none", ATR_NONE }, { "bold", ATR_BOLD }, @@ -6492,6 +6604,62 @@ boolean complain; return a; } +extern const char regex_id[]; /* from sys/share/regex.{c,cpp} */ + +/* True: temporarily replace menu color entries with a fake set of menu + colors, { "light blue"=light_blue, "blue"=blue, "red"=red, &c }, that + illustrates most colors for use when the pick-a-color menu is rendered; + suppresses black and white because one of those will likely be invisible + due to matching the background; False: restore user-specified colorings */ +static void +basic_menu_colors(load_colors) +boolean load_colors; +{ + if (load_colors) { + /* replace normal menu colors with a set specifically for colors */ + g.save_menucolors = iflags.use_menu_color; + g.save_colorings = g.menu_colorings; + + iflags.use_menu_color = TRUE; + if (g.color_colorings) { + /* use the alternate colorings which were set up previously */ + g.menu_colorings = g.color_colorings; + } else { + /* create the alternate colorings once */ + char cnm[QBUFSZ]; + int i, c; + boolean pmatchregex = !strcmpi(regex_id, "pmatchregex"); + const char *patternfmt = pmatchregex ? "*%s" : "%s"; + + /* menu_colorings pointer has been saved; clear it in order + to add the alternate entries as if from scratch */ + g.menu_colorings = (struct menucoloring *) 0; + + /* this orders the patterns last-in/first-out; that means + that the "light " variations come before the basic + "" ones, which is exactly what we want */ + for (i = 0; i < SIZE(colornames); ++i) { + if (!colornames[i].name) /* first alias entry has no name */ + break; + c = colornames[i].color; + if (c == CLR_BLACK || c == CLR_WHITE || c == NO_COLOR) + continue; /* skip these */ + Sprintf(cnm, patternfmt, colornames[i].name); + add_menu_coloring_parsed(cnm, c, ATR_NONE); + } + + /* right now, menu_colorings contains the alternate color list; + remember that list for future pick-a-color instances and + also keep it as is for this instance */ + g.color_colorings = g.menu_colorings; + } + } else { + /* restore normal user-specified menu colors */ + iflags.use_menu_color = g.save_menucolors; + g.menu_colorings = g.save_colorings; + } +} + int query_color(prompt) const char *prompt; @@ -6501,6 +6669,9 @@ const char *prompt; int i, pick_cnt; menu_item *picks = (menu_item *) 0; + /* replace user patterns with color name ones and force 'menucolors' On */ + basic_menu_colors(TRUE); + tmpwin = create_nhwindow(NHW_MENU); start_menu(tmpwin, MENU_BEHAVE_STANDARD); any = cg.zeroany; @@ -6515,6 +6686,11 @@ const char *prompt; end_menu(tmpwin, (prompt && *prompt) ? prompt : "Pick a color"); pick_cnt = select_menu(tmpwin, PICK_ONE, &picks); destroy_nhwindow(tmpwin); + + /* remove temporary color name patterns and restore user-specified ones; + reset 'menucolors' option to its previous value */ + basic_menu_colors(FALSE); + if (pick_cnt > 0) { i = colornames[picks[0].item.a_int - 1].color; /* pick_cnt==2: explicitly picked something other than the @@ -6848,7 +7024,7 @@ const char *errmsg; static boolean add_menu_coloring_parsed(str, c, a) -char *str; +const char *str; int c, a; { static const char re_error[] = "Menucolor regex error"; @@ -6942,20 +7118,27 @@ int *color, *attr; return FALSE; } +/* release all menu color patterns */ void free_menu_coloring() { - struct menucoloring *tmp, *tmp2; + /* either menu_colorings or color_colorings or both might need to + be freed or already be Null; do-loop will iterate at most twice */ + do { + struct menucoloring *tmp, *tmp2; - for (tmp = g.menu_colorings; tmp; tmp = tmp2) { - tmp2 = tmp->next; - regex_free(tmp->match); - free((genericptr_t) tmp->origstr); - free((genericptr_t) tmp); - } - g.menu_colorings = (struct menucoloring *) 0; + for (tmp = g.menu_colorings; tmp; tmp = tmp2) { + tmp2 = tmp->next; + regex_free(tmp->match); + free((genericptr_t) tmp->origstr); + free((genericptr_t) tmp); + } + g.menu_colorings = g.color_colorings; + g.color_colorings = (struct menucoloring *) 0; + } while (g.menu_colorings); } +/* release a specific menu color pattern; not used for color_colorings */ static void free_one_menu_coloring(idx) int idx; /* 0 .. */ @@ -7034,18 +7217,19 @@ char **opp; /* Check if character c is illegal as a menu command key */ boolean illegal_menu_cmd_key(c) -char c; +uchar c; { - if (c == 0 || c == '\r' || c == '\n' || c == '\033' - || c == ' ' || digit(c) || (letter(c) && c != '@')) { - config_error_add("Reserved menu command key '%s'", visctrl(c)); + if (c == 0 || c == '\r' || c == '\n' || c == '\033' || c == ' ' + || digit((char) c) || (letter((char) c) && c != '@')) { + config_error_add("Reserved menu command key '%s'", visctrl((char) c)); return TRUE; } else { /* reject default object class symbols */ int j; + for (j = 1; j < MAXOCLASSES; j++) - if (c == def_oc_syms[j].sym) { + if (c == (uchar) def_oc_syms[j].sym) { config_error_add("Menu command key '%s' is an object class", - visctrl(c)); + visctrl((char) c)); return TRUE; } } @@ -7192,13 +7376,13 @@ struct fruit *replace_fruit; || !strncmp(g.pl_fruit, "partly eaten ", 13) || (!strncmp(g.pl_fruit, "tin of ", 7) && (!strcmp(g.pl_fruit + 7, "spinach") - || name_to_mon(g.pl_fruit + 7) >= LOW_PM)) + || name_to_mon(g.pl_fruit + 7, (int *) 0) >= LOW_PM)) || !strcmp(g.pl_fruit, "empty tin") || (!strcmp(g.pl_fruit, "glob") || (globpfx > 0 && !strcmp("glob", &g.pl_fruit[globpfx]))) || ((str_end_is(g.pl_fruit, " corpse") || str_end_is(g.pl_fruit, " egg")) - && name_to_mon(g.pl_fruit) >= LOW_PM)) { + && name_to_mon(g.pl_fruit, (int *) 0) >= LOW_PM)) { Strcpy(buf, g.pl_fruit); Strcpy(g.pl_fruit, "candied "); nmcpy(g.pl_fruit + 8, buf, PL_FSIZ - 8); @@ -7287,10 +7471,9 @@ static struct other_opts { int NDECL((*othr_count_func)); } othropt[] = { { "autopickup exceptions", set_in_game, OPT_OTHER_APEXC, count_apes }, - { "status condition fields", set_in_game, - OPT_OTHER_COND, count_cond }, { "menu colors", set_in_game, OPT_OTHER_MENUCOLOR, count_menucolors }, { "message types", set_in_game, OPT_OTHER_MSGTYPE, msgtype_count }, + { "status condition fields", set_in_game, OPT_OTHER_COND, count_cond }, #ifdef STATUS_HILITES { "status hilite rules", set_in_game, OPT_OTHER_STATHILITE, count_status_hilites }, @@ -7475,7 +7658,7 @@ doset() /* changing options via menu by Per Liboriussen */ (void) parseoptions(buf, setinitial, fromfile); } else { /* compound option */ - int k = opt_indx, reslt; + int k = opt_indx, reslt UNUSED; if (allopt[k].has_handler && allopt[k].optfn) { reslt = (*allopt[k].optfn)(allopt[k].idx, do_handler, @@ -7508,7 +7691,8 @@ doset() /* changing options via menu by Per Liboriussen */ check_gold_symbol(); reglyph_darkroom(); (void) doredraw(); - } else if (g.context.botl || g.context.botlx) { + } + if (g.context.botl || g.context.botlx) { bot(); } return 0; @@ -7588,58 +7772,97 @@ int nset; add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_ITEMFLAGS_NONE); } -/* - * used by cmd.c and pager.c - */ +/* display keys for menu actions; used by cmd.c '?i' and pager.c '?k' */ void show_menu_controls(win, dolist) winid win; boolean dolist; { + struct xtra_cntrls { + const char *key, *desc; + }; + static const struct xtra_cntrls hardcoded[] = { + { "Return", "Accept current choice(s) and dismiss menu" }, + { "Enter", "Same as Return" }, + { "Space", "If not on last page, advance one page;" }, + { " ", "when on last page, treat like Return" }, + { "Escape", "Cancel menu without making any choice(s)" }, + { (char *) 0, (char *) 0} + }; + static const char mc_fmt[] = "%8s %-6s %s", + mc_altfmt[] = "%9s %-6s %s"; char buf[BUFSZ]; + const char *fmt, *arg; + const struct xtra_cntrls *xcp; + + /* + * Relies on spaces to line things up in columns, so must be rendered + * with a fixed-width font or will look dreadful. + */ putstr(win, 0, "Menu control keys:"); - if (dolist) { + if (dolist) { /* key bindings help: '?i' */ int i; + fmt = "%-7s %s"; for (i = 0; i < SIZE(default_menu_cmd_info); i++) { - Sprintf(buf, "%-8s %s", + Sprintf(buf, fmt, visctrl(get_menu_cmd_key(default_menu_cmd_info[i].cmd)), default_menu_cmd_info[i].desc); putstr(win, 0, buf); } - } else { + /* no separator before hardcoded */ + fmt = "%s%-7s %s"; /* extra specifier to absorb 'arg' */ + arg = ""; /* no extra prefix for 'dolist' */ + } else { /* menu controls help: '?k' */ putstr(win, 0, ""); - putstr(win, 0, " Page All items"); - Sprintf(buf, " Select %s %s", - visctrl(get_menu_cmd_key(MENU_SELECT_PAGE)), - visctrl(get_menu_cmd_key(MENU_SELECT_ALL))); + Sprintf(buf, mc_altfmt, "", "Whole", "Current"); putstr(win, 0, buf); - Sprintf(buf, "Deselect %s %s", - visctrl(get_menu_cmd_key(MENU_UNSELECT_PAGE)), - visctrl(get_menu_cmd_key(MENU_UNSELECT_ALL))); + Sprintf(buf, mc_altfmt, "", " Menu", " Page"); putstr(win, 0, buf); - Sprintf(buf, " Invert %s %s", - visctrl(get_menu_cmd_key(MENU_INVERT_PAGE)), - visctrl(get_menu_cmd_key(MENU_INVERT_ALL))); + Sprintf(buf, mc_fmt, "Select", + visctrl(get_menu_cmd_key(MENU_SELECT_ALL)), + visctrl(get_menu_cmd_key(MENU_SELECT_PAGE))); + putstr(win, 0, buf); + Sprintf(buf, mc_fmt, "Invert", + visctrl(get_menu_cmd_key(MENU_INVERT_ALL)), + visctrl(get_menu_cmd_key(MENU_INVERT_PAGE))); + putstr(win, 0, buf); + Sprintf(buf, mc_fmt, "Deselect", + visctrl(get_menu_cmd_key(MENU_UNSELECT_ALL)), + visctrl(get_menu_cmd_key(MENU_UNSELECT_PAGE))); putstr(win, 0, buf); putstr(win, 0, ""); - Sprintf(buf, " Go to %s Next page", - visctrl(get_menu_cmd_key(MENU_NEXT_PAGE))); + Sprintf(buf, mc_fmt, "Go to", + visctrl(get_menu_cmd_key(MENU_NEXT_PAGE)), + "Next page"); putstr(win, 0, buf); - Sprintf(buf, " %s Previous page", - visctrl(get_menu_cmd_key(MENU_PREVIOUS_PAGE))); + Sprintf(buf, mc_fmt, "", + visctrl(get_menu_cmd_key(MENU_PREVIOUS_PAGE)), + "Previous page"); putstr(win, 0, buf); - Sprintf(buf, " %s First page", - visctrl(get_menu_cmd_key(MENU_FIRST_PAGE))); + Sprintf(buf, mc_fmt, "", + visctrl(get_menu_cmd_key(MENU_FIRST_PAGE)), + "First page"); putstr(win, 0, buf); - Sprintf(buf, " %s Last page", - visctrl(get_menu_cmd_key(MENU_LAST_PAGE))); + Sprintf(buf, mc_fmt, "", + visctrl(get_menu_cmd_key(MENU_LAST_PAGE)), + "Last page"); putstr(win, 0, buf); putstr(win, 0, ""); - Sprintf(buf, " %s Search and toggle matching entries", - visctrl(get_menu_cmd_key(MENU_SEARCH))); + Sprintf(buf, mc_fmt, "Search", + visctrl(get_menu_cmd_key(MENU_SEARCH)), + "Exter a target string and invert all matching entries"); putstr(win, 0, buf); + /* separator before hardcoded */ + putstr(win, 0, ""); + fmt = "%9s %-8s %s"; + arg = "Other "; /* prefix for first hardcoded[] entry, then reset */ + } + for (xcp = hardcoded; xcp->key; ++xcp) { + Sprintf(buf, fmt, arg, xcp->key, xcp->desc); + putstr(win, 0, buf); + arg = ""; } } static int @@ -7988,8 +8211,14 @@ static const char *opt_intro[] = { static const char *opt_epilog[] = { "", - "Some of the options can be set only before the game is started; those", - "items will not be selectable in the 'O' command's menu.", + "Some of the options can only be set before the game is started;", + "those items will not be selectable in the 'O' command's menu.", + "Some options are stored in a game's save file, and will keep saved", + "values when restoring that game even if you have updated your config-", + "uration file to change them. Such changes will matter for new games.", + "The \"other settings\" can be set with 'O', but when set within the", + "configuration file they use their own directives rather than OPTIONS.", + "See NetHack's \"Guidebook\" for details.", (char *) 0 }; @@ -7997,6 +8226,7 @@ void option_help() { char buf[BUFSZ], buf2[BUFSZ]; + const char *optname; register int i; winid datawin; @@ -8008,28 +8238,63 @@ option_help() /* Boolean options */ for (i = 0; allopt[i].name; i++) { - if (allopt[i].addr) { - if (allopt[i].addr == &iflags.sanity_check && !wizard) - continue; - if (allopt[i].addr == &iflags.menu_tab_sep && !wizard) - continue; - next_opt(datawin, allopt[i].name); - } + if ((allopt[i].opttyp != BoolOpt || !allopt[i].addr) + || (allopt[i].setwhere == set_wizonly && !wizard)) + continue; + optname = allopt[i].name; + if ((is_wc_option(optname) && !wc_supported(optname)) + || (is_wc2_option(optname) && !wc2_supported(optname))) + continue; + next_opt(datawin, optname); } next_opt(datawin, ""); /* Compound options */ putstr(datawin, 0, "Compound options:"); for (i = 0; allopt[i].name; i++) { - Sprintf(buf2, "`%s'", allopt[i].name); + if (allopt[i].opttyp != CompOpt + || (allopt[i].setwhere == set_wizonly && !wizard)) + continue; + optname = allopt[i].name; + if ((is_wc_option(optname) && !wc_supported(optname)) + || (is_wc2_option(optname) && !wc2_supported(optname))) + continue; + Sprintf(buf2, "`%s'", optname); Sprintf(buf, "%-20s - %s%c", buf2, allopt[i].descr, allopt[i + 1].name ? ',' : '.'); putstr(datawin, 0, buf); } + putstr(datawin, 0, ""); + + putstr(datawin, 0, "Other settings:"); + for (i = 0; othropt[i].name; ++i) { + Sprintf(buf, " %s", othropt[i].name); + putstr(datawin, 0, buf); + } for (i = 0; opt_epilog[i]; i++) putstr(datawin, 0, opt_epilog[i]); + /* + * TODO: + * briefly describe interface-specific option-like settings for + * the currently active interface: + * X11 uses X-specific "application defaults" from NetHack.ad; + * Qt has menu accessible "game -> Qt settings" (non-OSX) or + * "nethack -> Preferences" (OSX) to maintain a few options + * (font size, map tile size, paperdoll show/hide flag and + * tile size) which persist across games; + * Windows GUI also has some port-specific menus; + * tty and curses: anything? + * Best done via a new windowprocs function rather than plugging + * in details here. + * + * Maybe: + * switch from text window to pick-none menu so that user can + * scroll back up. (Not necessary for Qt where text windows are + * already scrollable.) + */ + display_nhwindow(datawin, FALSE); destroy_nhwindow(datawin); return; @@ -8049,7 +8314,7 @@ const char *str; char *s; if (!buf) - *(buf = (char *) alloc(BUFSZ)) = '\0'; + *(buf = (char *) alloc(COLBUFSZ)) = '\0'; if (!*str) { s = eos(buf); diff --git a/src/pager.c b/src/pager.c index 83856f30c..197cd4b3c 100644 --- a/src/pager.c +++ b/src/pager.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 pager.c $NHDT-Date: 1588778117 2020/05/06 15:15:17 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.188 $ */ +/* NetHack 3.7 pager.c $NHDT-Date: 1608749031 2020/12/23 18:43:51 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.192 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2018. */ /* NetHack may be freely redistributed. See license for details. */ @@ -12,14 +12,13 @@ static boolean FDECL(is_swallow_sym, (int)); static int FDECL(append_str, (char *, const char *)); static void FDECL(look_at_object, (char *, int, int, int)); -static void FDECL(look_at_monster, (char *, char *, - struct monst *, int, int)); +static void FDECL(look_at_monster, (char *, char *, struct monst *, int, int)); static struct permonst *FDECL(lookat, (int, int, char *, char *)); static void FDECL(checkfile, (char *, struct permonst *, - BOOLEAN_P, BOOLEAN_P, char *)); + BOOLEAN_P, BOOLEAN_P, char *)); static void FDECL(look_all, (BOOLEAN_P,BOOLEAN_P)); static void FDECL(do_supplemental_info, (char *, struct permonst *, - BOOLEAN_P)); + BOOLEAN_P)); static void NDECL(whatdoes_help); static void NDECL(docontact); static void NDECL(dispfile_help); @@ -90,7 +89,7 @@ char *outbuf; Sprintf(outbuf, "%s%s%s called %s", /* being blinded may hide invisibility from self */ (Invis && (senseself() || !Blind)) ? "invisible " : "", race, - mons[u.umonnum].mname, g.plname); + pmname(&mons[u.umonnum], Ugender), g.plname); if (u.usteed) Sprintf(eos(outbuf), ", mounted on %s", y_monnam(u.usteed)); if (u.uundetected || (Upolyd && U_AP_TYPE)) @@ -103,6 +102,32 @@ char *outbuf; return outbuf; } +/* format description of 'mon's health for look_at_monster(), done_in_by() */ +char * +monhealthdescr(mon, addspace, outbuf) +struct monst *mon; +boolean addspace; +char *outbuf; +{ + int mhp_max = max(mon->mhpmax, 1), /* bullet proofing */ + pct = (mon->mhp * 100) / mhp_max; + + if (mon->mhp >= mhp_max) + Strcpy(outbuf, "uninjured"); + else if (mon->mhp <= 1 || pct < 5) + Sprintf(outbuf, "%s%s", (mon->mhp > 0) ? "nearly " : "", + !nonliving(mon->data) ? "deceased" : "defunct"); + else + Sprintf(outbuf, "%swounded", + (pct >= 95) ? "barely " + : (pct >= 80) ? "slightly " + : (pct < 20) ? "heavily " + : ""); + if (addspace) + (void) strkitten(outbuf, ' '); + return outbuf; +} + /* describe a hidden monster; used for look_at during extended monster detection and for probing; also when looking at self */ void @@ -142,7 +167,7 @@ char *outbuf; } else if (M_AP_TYPE(mon) == M_AP_MONSTER) { if (altmon) Sprintf(outbuf, ", masquerading as %s", - an(mons[mon->mappearance].mname)); + an(pmname(&mons[mon->mappearance], Mgender(mon)))); } else if (isyou ? u.uundetected : mon->mundetected) { Strcpy(outbuf, ", hiding"); if (hides_under(mon->data)) { @@ -280,16 +305,17 @@ char *buf, *monbuf; /* buf: output, monbuf: optional output */ struct monst *mtmp; int x, y; { - char *name, monnambuf[BUFSZ]; + char *name, monnambuf[BUFSZ], healthbuf[BUFSZ]; boolean accurate = !Hallucination; name = (mtmp->data == &mons[PM_COYOTE] && accurate) ? coyotename(mtmp, monnambuf) : distant_monnam(mtmp, ARTICLE_NONE, monnambuf); - Sprintf(buf, "%s%s%s", + Sprintf(buf, "%s%s%s%s", (mtmp->mx != x || mtmp->my != y) ? ((mtmp->isshk && accurate) ? "tail of " : "tail of a ") : "", + accurate ? monhealthdescr(mtmp, TRUE, healthbuf) : "", (mtmp->mtame && accurate) ? "tame " : (mtmp->mpeaceful && accurate) @@ -377,7 +403,7 @@ int x, y; : (mW & M2_ELF & m2) ? "elf" : (mW & M2_ORC & m2) ? "orc" : (mW & M2_DEMON & m2) ? "demon" - : mtmp->data->mname); + : pmname(mtmp->data, Mgender(mtmp))); Sprintf(eos(monbuf), "warned of %s", makeplural(whom)); } @@ -590,7 +616,7 @@ char *supplemental_name; * user_typed_name and picked name. */ if (pm != (struct permonst *) 0 && !user_typed_name) - dbase_str = strcpy(newstr, pm->mname); + dbase_str = strcpy(newstr, pm->pmnames[NEUTRAL]); else dbase_str = strcpy(newstr, inp); (void) lcase(dbase_str); @@ -867,15 +893,14 @@ struct permonst **for_supplement; hallucinate = (Hallucination && !g.program_state.gameover); const char *x_str; nhsym tmpsym; + unsigned glyphmod[NUM_GLYPHMOD]; gobbledygook[0] = '\0'; /* no hallucinatory liquid (yet) */ if (looked) { - int oc; - unsigned os; - glyph = glyph_at(cc.x, cc.y); /* Convert glyph at selected position to a symbol for use below. */ - (void) mapglyph(glyph, &sym, &oc, &os, cc.x, cc.y, 0); + map_glyphmod(cc.x, cc.y, glyph, 0, glyphmod); + sym = glyphmod[GM_TTYCHAR]; Sprintf(prefix, "%s ", encglyph(glyph)); } else @@ -1128,12 +1153,9 @@ struct permonst **for_supplement; break; case SYM_PET_OVERRIDE + SYM_OFF_X: if (looked) { - int oc = 0; - unsigned os = 0; - /* convert to symbol without override in effect */ - (void) mapglyph(glyph, &sym, &oc, &os, - cc.x, cc.y, MG_FLAG_NOOVERRIDE); + map_glyphmod(cc.x, cc.y, glyph, MG_FLAG_NOOVERRIDE, glyphmod); + sym = (int) glyphmod[GM_TTYCHAR]; goto check_monsters; } break; @@ -1252,7 +1274,8 @@ coord *click_cc; any.a_char = '?'; add_menu(win, NO_GLYPH, &any, flags.lootabc ? 0 : any.a_char, 'n', ATR_NONE, - "something else (by symbol or name)", MENU_ITEMFLAGS_NONE); + "something else (by symbol or name)", + MENU_ITEMFLAGS_NONE); if (!u.uswallow && !Hallucination) { any = cg.zeroany; add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, @@ -1489,7 +1512,10 @@ boolean do_mons; /* True => monsters, False => objects */ Sprintf(outbuf, "All %s currently shown on the map:", which); putstr(win, 0, outbuf); - putstr(win, 0, ""); + /* hack alert! Qt watches a text window for any line + with 4 consecutive spaces and renders the window + in a fixed-width font it if finds at least one */ + putstr(win, 0, " "); /* separator */ } /* prefix: "coords C " where 'C' is mon or obj symbol */ Sprintf(outbuf, (cmode == GPCOORDS_SCREEN) ? "%s " @@ -2093,9 +2119,9 @@ static const struct { { hmenu_dowhatdoes, "Info on what a given key does." }, { option_help, "List of game options." }, { dispfile_optionfile, "Longer explanation of game options." }, - { dokeylist, "Full list of keyboard commands" }, + { dokeylist, "Full list of keyboard commands." }, { hmenu_doextlist, "List of extended commands." }, - { domenucontrols, "List menu control keys" }, + { domenucontrols, "List menu control keys." }, { dispfile_license, "The NetHack license." }, { docontact, "Support information." }, #ifdef PORT_HELP diff --git a/src/pickup.c b/src/pickup.c index bd17ab0f9..f271d4c17 100644 --- a/src/pickup.c +++ b/src/pickup.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 pickup.c $NHDT-Date: 1590870789 2020/05/30 20:33:09 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.269 $ */ +/* NetHack 3.7 pickup.c $NHDT-Date: 1608673693 2020/12/22 21:48:13 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.273 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -484,7 +484,7 @@ struct obj *obj; ? TRUE : FALSE) : TRUE; /* catchall: no filters specified, so accept */ - if (Role_if(PM_PRIEST) && !obj->bknown) + if (Role_if(PM_CLERIC) && !obj->bknown) set_bknown(obj, 1); /* @@ -598,11 +598,11 @@ int what; /* should be a long */ return 0; } /* no pickup if levitating & not on air or water level */ - if (!can_reach_floor(TRUE)) { + t = t_at(u.ux, u.uy); + if (!can_reach_floor(t && is_pit(t->ttyp))) { (void) describe_decor(); /* even when !flags.mention_decor */ if ((g.multi && !g.context.run) || (autopickup && !flags.pickup) - || ((t = t_at(u.ux, u.uy)) != 0 - && (uteetering_at_seen_pit(t) || uescaped_shaft(t)))) + || (t && (uteetering_at_seen_pit(t) || uescaped_shaft(t)))) read_engr_at(u.ux, u.uy); return 0; } @@ -910,7 +910,7 @@ boolean FDECL((*allow), (OBJ_P)); /* allow function */ int i, n; winid win; struct obj *curr, *last, fake_hero_object, *olist = *olist_p; - char *pack; + char *pack, packbuf[MAXOCLASSES + 1]; anything any; boolean printed_type_name, first, sorted = (qflags & INVORDER_SORT) != 0, @@ -970,7 +970,9 @@ boolean FDECL((*allow), (OBJ_P)); /* allow function */ * each type so we can group them. The allow function was * called by sortloot() and will be called once per item here. */ - pack = flags.inv_order; + pack = strcpy(packbuf, flags.inv_order); + if (qflags & INCLUDE_VENOM) + (void) strkitten(pack, VENOM_CLASS); /* venom is not in inv_order */ first = TRUE; do { printed_type_name = FALSE; @@ -1095,7 +1097,7 @@ int how; /* type of query */ int n; winid win; struct obj *curr; - char *pack; + char *pack, packbuf[MAXOCLASSES + 1]; anything any; boolean collected_type_name; char invlet; @@ -1154,7 +1156,10 @@ int how; /* type of query */ win = create_nhwindow(NHW_MENU); start_menu(win, MENU_BEHAVE_STANDARD); - pack = flags.inv_order; + + pack = strcpy(packbuf, flags.inv_order); + if (qflags & INCLUDE_VENOM) + (void) strkitten(pack, VENOM_CLASS); /* venom is not in inv_order */ if (qflags & CHOOSE_ALL) { invlet = 'A'; @@ -1775,8 +1780,9 @@ int x, y; boolean looting; /* loot vs tip */ { const char *verb = looting ? "loot" : "tip"; + struct trap *t = t_at(x, y); - if (!can_reach_floor(TRUE)) { + if (!can_reach_floor(t && is_pit(t->ttyp))) { if (u.usteed && P_SKILL(P_RIDING) < P_BASIC) rider_cant_reach(); /* not skilled enough to reach */ else @@ -2351,9 +2357,14 @@ register struct obj *obj; if (Icebox && !age_is_relative(obj)) { obj->age = g.monstermoves - obj->age; /* actual age */ /* stop any corpse timeouts when frozen */ - if (obj->otyp == CORPSE && obj->timed) { - (void) stop_timer(ROT_CORPSE, obj_to_any(obj)); - (void) stop_timer(REVIVE_MON, obj_to_any(obj)); + if (obj->otyp == CORPSE) { + if (obj->timed) { + (void) stop_timer(ROT_CORPSE, obj_to_any(obj)); + (void) stop_timer(REVIVE_MON, obj_to_any(obj)); + } + /* if this is the corpse of a cancelled ice troll, uncancel it */ + if (obj->corpsenm == PM_ICE_TROLL && has_omonst(obj)) + OMONST(obj)->mcan = 0; } } else if (Is_mbag(g.current_container) && mbag_explodes(obj, 0)) { /* explicitly mention what item is triggering the explosion */ @@ -2362,7 +2373,7 @@ register struct obj *obj; /* did not actually insert obj yet */ if (was_unpaid) addtobill(obj, FALSE, FALSE, TRUE); - if (obj->otyp == BAG_OF_HOLDING) /* putting bag of holding into another */ + if (obj->otyp == BAG_OF_HOLDING) /* one bag of holding into another */ do_boh_explosion(obj, (obj->where == OBJ_FLOOR)); obfree(obj, (struct obj *) 0); /* if carried, shop goods will be flagged 'unpaid' and obfree() will @@ -2489,8 +2500,13 @@ struct obj *obj; if (!age_is_relative(obj)) { obj->age = g.monstermoves - obj->age; /* actual age */ if (obj->otyp == CORPSE) { - /* start a rot-away timer but not a troll's revive timer */ - obj->norevive = 1; + struct monst *m = get_mtraits(obj, FALSE); + boolean iceT = m ? (m->data == &mons[PM_ICE_TROLL]) + : (obj->corpsenm == PM_ICE_TROLL); + + /* start a revive timer if this corpse is for an ice troll, + otherwise start a rot-away timer (even for other trolls) */ + obj->norevive = iceT ? 0 : 1; start_corpse_timeout(obj); } } @@ -2980,13 +2996,14 @@ boolean put_in; } } } else { - mflags = INVORDER_SORT; + mflags = INVORDER_SORT | INCLUDE_VENOM; if (put_in && flags.invlet_constant) mflags |= USE_INVLET; if (!put_in) g.current_container->cknown = 1; Sprintf(buf, "%s what?", action); - n = query_objlist(buf, put_in ? &g.invent : &(g.current_container->cobj), + n = query_objlist(buf, + put_in ? &g.invent : &(g.current_container->cobj), mflags, &pick_list, PICK_ANY, all_categories ? allow_all : allow_category); if (n) { diff --git a/src/pline.c b/src/pline.c index 16594654f..f88a34d88 100644 --- a/src/pline.c +++ b/src/pline.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 pline.c $NHDT-Date: 1549327495 2019/02/05 00:44:55 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.73 $ */ +/* NetHack 3.7 pline.c $NHDT-Date: 1606504240 2020/11/27 19:10:40 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.100 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2018. */ /* NetHack may be freely redistributed. See license for details. */ @@ -50,16 +50,16 @@ const char *line; } /* called during save (unlike the interface-specific message history, - this data isn't saved and restored); end-of-game releases saved_pline[] + this data isn't saved and restored); end-of-game releases saved_plines[] while writing its contents to the final dump log */ void dumplogfreemessages() { - unsigned indx; + unsigned i; - for (indx = 0; indx < DUMPLOG_MSG_COUNT; ++indx) - if (g.saved_plines[indx]) - free((genericptr_t) g.saved_plines[indx]), g.saved_plines[indx] = 0; + for (i = 0; i < DUMPLOG_MSG_COUNT; ++i) + if (g.saved_plines[i]) + free((genericptr_t) g.saved_plines[i]), g.saved_plines[i] = 0; g.saved_pline_index = 0; } #endif @@ -619,4 +619,22 @@ VA_DECL(const char *, str) #endif } +/* nhassert_failed is called when an nhassert's condition is false */ +void +nhassert_failed(expression, filepath, line) + const char* expression; + const char * filepath; + int line; +{ + const char * filename; + + /* attempt to get filename from path. TODO: we really need a port provided + * function to return a filename from a path */ + filename = strrchr(filepath, '/'); + filename = (filename == NULL ? strrchr(filepath, '\\') : filename); + filename = (filename == NULL ? filepath : filename + 1); + + impossible("nhassert(%s) failed in file '%s' at line %d", expression, filename, line); +} + /*pline.c*/ diff --git a/src/polyself.c b/src/polyself.c index b06f2287e..3d898ec66 100644 --- a/src/polyself.c +++ b/src/polyself.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 polyself.c $NHDT-Date: 1583073991 2020/03/01 14:46:31 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.152 $ */ +/* NetHack 3.7 polyself.c $NHDT-Date: 1605959204 2020/11/21 11:46:44 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.157 $ */ /* Copyright (C) 1987, 1988, 1989 by Ken Arromdee */ /* NetHack may be freely redistributed. See license for details. */ @@ -263,10 +263,13 @@ change_sex() : g.urole.malenum; if (!already_polyd) { u.umonnum = u.umonster; - } else if (u.umonnum == PM_SUCCUBUS || u.umonnum == PM_INCUBUS) { + } else if (u.umonnum == PM_AMOROUS_DEMON) { flags.female = !flags.female; - /* change monster type to match new sex */ +#if 0 + /* change monster type to match new sex; disabled with PM_AMOROUS_DEMON */ + u.umonnum = (u.umonnum == PM_SUCCUBUS) ? PM_INCUBUS : PM_SUCCUBUS; +#endif set_uasmon(); } } @@ -394,7 +397,7 @@ polyself(psflags) int psflags; { char buf[BUFSZ] = DUMMY; - int old_light, new_light, mntmp, class, tryct; + int old_light, new_light, mntmp, class, tryct, gvariant = NEUTRAL; boolean forcecontrol = (psflags == 1), monsterpoly = (psflags == 2), formrevert = (psflags == 3), @@ -449,7 +452,7 @@ int psflags; continue; /* end do-while(--tryct > 0) loop */ } class = 0; - mntmp = name_to_mon(buf); + mntmp = name_to_mon(buf, &gvariant); if (mntmp < LOW_PM) { by_class: class = name_to_monclass(buf, &mntmp); @@ -489,7 +492,7 @@ int psflags; 0 and trigger thats_enough_tries message */ ++tryct; } - pm_name = mons[mntmp].mname; + pm_name = pmname(&mons[mntmp], flags.female ? FEMALE : MALE); if (the_unique_pm(&mons[mntmp])) pm_name = the(pm_name); else if (!type_is_pname(&mons[mntmp])) @@ -552,7 +555,7 @@ int psflags; } else if (isvamp) { do_vampyr: if (mntmp < LOW_PM || (mons[mntmp].geno & G_UNIQ)) { - mntmp = (g.youmonst.data == &mons[PM_VAMPIRE_LORD] && !rn2(10)) + mntmp = (g.youmonst.data == &mons[PM_VAMPIRE_LEADER] && !rn2(10)) ? PM_WOLF : !rn2(4) ? PM_FOG_CLOUD : PM_VAMPIRE_BAT; if (g.youmonst.cham >= LOW_PM @@ -560,7 +563,8 @@ int psflags; mntmp = g.youmonst.cham; } if (controllable_poly) { - Sprintf(buf, "Become %s?", an(mons[mntmp].mname)); + Sprintf(buf, "Become %s?", + an(pmname(&mons[mntmp], gvariant))); if (yn(buf) != 'y') return; } @@ -622,7 +626,8 @@ int mntmp; int mlvl; if (g.mvitals[mntmp].mvflags & G_GENOD) { /* allow G_EXTINCT */ - You_feel("rather %s-ish.", mons[mntmp].mname); + You_feel("rather %s-ish.", + pmname(&mons[mntmp], flags.female ? FEMALE : MALE)); exercise(A_WIS, TRUE); return 0; } @@ -676,7 +681,7 @@ int mntmp; Strcat(buf, (is_male(&mons[mntmp]) || is_female(&mons[mntmp])) ? "" : flags.female ? "female " : "male "); } - Strcat(buf, mons[mntmp].mname); + Strcat(buf, pmname(&mons[mntmp], flags.female ? FEMALE : MALE)); You("%s %s!", (u.umonnum != mntmp) ? "turn into" : "feel like", an(buf)); if (Stoned && poly_when_stoned(&mons[mntmp])) { @@ -774,7 +779,8 @@ int mntmp; if (touch_petrifies(u.usteed->data) && !Stone_resistance && rnl(3)) { pline("%s touch %s.", no_longer_petrify_resistant, mon_nam(u.usteed)); - Sprintf(buf, "riding %s", an(u.usteed->data->mname)); + Sprintf(buf, "riding %s", + an(pmname(u.usteed->data, Mgender(u.usteed)))); instapetrify(buf); } if (!can_ride(u.usteed)) @@ -1447,6 +1453,8 @@ dogaze() (void) destroy_mitem(mtmp, POTION_CLASS, AD_FIRE); if (lev > rn2(25)) (void) destroy_mitem(mtmp, SPBOOK_CLASS, AD_FIRE); + if (lev > rn2(20)) + ignite_items(mtmp->minvent); if (dmg) mtmp->mhp -= dmg; if (DEADMONSTER(mtmp)) @@ -1574,17 +1582,20 @@ dopoly() if (is_vampire(g.youmonst.data) || is_vampshifter(&g.youmonst)) { polyself(2); if (savedat != g.youmonst.data) { - You("transform into %s.", an(g.youmonst.data->mname)); + You("transform into %s.", + an(pmname(g.youmonst.data, Ugender))); newsym(u.ux, u.uy); } } return 1; } +/* #monster for hero-as-mind_flayer giving psychic blast */ int domindblast() { struct monst *mtmp, *nmon; + int dmg; if (u.uen < 10) { You("concentrate but lack the energy to maintain doing so."); @@ -1605,12 +1616,21 @@ domindblast() continue; if (mtmp->mpeaceful) continue; + if (mindless(mtmp->data)) + continue; u_sen = telepathic(mtmp->data) && !mtmp->mcansee; if (u_sen || (telepathic(mtmp->data) && rn2(2)) || !rn2(10)) { + dmg = rnd(15); + /* wake it up first, to bring hidden monster out of hiding; + but in case it is currently peaceful, don't make it hostile + unless it will survive the psychic blast, otherwise hero + would avoid the penalty for killing it while peaceful */ + wakeup(mtmp, (dmg > mtmp->mhp) ? TRUE : FALSE); You("lock in on %s %s.", s_suffix(mon_nam(mtmp)), u_sen ? "telepathy" - : telepathic(mtmp->data) ? "latent telepathy" : "mind"); - mtmp->mhp -= rnd(15); + : telepathic(mtmp->data) ? "latent telepathy" + : "mind"); + mtmp->mhp -= dmg; if (DEADMONSTER(mtmp)) killed(mtmp); } @@ -1751,7 +1771,7 @@ int part; if ((part == HAND || part == HANDED) && (humanoid(mptr) && attacktype(mptr, AT_CLAW) && !index(not_claws, mptr->mlet) && mptr != &mons[PM_STONE_GOLEM] - && mptr != &mons[PM_INCUBUS] && mptr != &mons[PM_SUCCUBUS])) + && mptr != &mons[PM_AMOROUS_DEMON])) return (part == HAND) ? "claw" : "clawed"; if ((mptr == &mons[PM_MUMAK] || mptr == &mons[PM_MASTODON]) && part == NOSE) @@ -1770,6 +1790,7 @@ int part; if (mptr == &mons[PM_RAVEN]) return bird_parts[part]; if (mptr->mlet == S_CENTAUR || mptr->mlet == S_UNICORN + || mptr == &mons[PM_KI_RIN] || (mptr == &mons[PM_ROTHE] && part != HAIR)) return horse_parts[part]; if (mptr->mlet == S_LIGHT) { @@ -1912,7 +1933,7 @@ polysense() warnidx = PM_SHRIEKER; break; case PM_VAMPIRE: - case PM_VAMPIRE_LORD: + case PM_VAMPIRE_LEADER: g.context.warntype.polyd = M2_HUMAN | M2_ELF; HWarn_of_mon |= FROMRACE; return; diff --git a/src/potion.c b/src/potion.c index c07d96cab..4d3265c0d 100644 --- a/src/potion.c +++ b/src/potion.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 potion.c $NHDT-Date: 1581810073 2020/02/15 23:41:13 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.180 $ */ +/* NetHack 3.7 potion.c $NHDT-Date: 1596498197 2020/08/03 23:43:17 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.182 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2013. */ /* NetHack may be freely redistributed. See license for details. */ @@ -486,7 +486,6 @@ int dodrink() { register struct obj *otmp; - const char *potion_descr; if (Strangled) { pline("If you can't breathe air, how can you drink liquid?"); @@ -538,21 +537,18 @@ dodrink() } otmp->in_use = TRUE; /* you've opened the stopper */ - potion_descr = OBJ_DESCR(objects[otmp->otyp]); - if (potion_descr) { - if (!strcmp(potion_descr, "milky") - && !(g.mvitals[PM_GHOST].mvflags & G_GONE) - && !rn2(POTION_OCCUPANT_CHANCE(g.mvitals[PM_GHOST].born))) { - ghost_from_bottle(); - useup(otmp); - return 1; - } else if (!strcmp(potion_descr, "smoky") - && !(g.mvitals[PM_DJINNI].mvflags & G_GONE) - && !rn2(POTION_OCCUPANT_CHANCE(g.mvitals[PM_DJINNI].born))) { - djinni_from_bottle(otmp); - useup(otmp); - return 1; - } + if (objdescr_is(otmp, "milky") + && !(g.mvitals[PM_GHOST].mvflags & G_GONE) + && !rn2(POTION_OCCUPANT_CHANCE(g.mvitals[PM_GHOST].born))) { + ghost_from_bottle(); + useup(otmp); + return 1; + } else if (objdescr_is(otmp, "smoky") + && !(g.mvitals[PM_DJINNI].mvflags & G_GONE) + && !rn2(POTION_OCCUPANT_CHANCE(g.mvitals[PM_DJINNI].born))) { + djinni_from_bottle(otmp); + useup(otmp); + return 1; } return dopotion(otmp); } @@ -664,7 +660,7 @@ register struct obj *otmp; exercise(A_CON, FALSE); if (u.ulycn >= LOW_PM) { Your("affinity to %s disappears!", - makeplural(mons[u.ulycn].mname)); + makeplural(mons[u.ulycn].pmnames[NEUTRAL])); if (g.youmonst.data == &mons[u.ulycn]) you_unwere(FALSE); set_ulycn(NON_PM); /* cure lycanthropy */ @@ -729,11 +725,7 @@ register struct obj *otmp; (void) adjattrib(A_INT, 1, FALSE); (void) adjattrib(A_WIS, 1, FALSE); } - You_feel("self-knowledgeable..."); - display_nhwindow(WIN_MESSAGE, FALSE); - enlightenment(MAGICENLIGHTENMENT, ENL_GAMEINPROGRESS); - pline_The("feeling subsides."); - exercise(A_WIS, TRUE); + do_enlightenment_effect(); } break; case SPE_INVISIBILITY: @@ -1055,9 +1047,7 @@ register struct obj *otmp; HLevitation &= ~I_SPECIAL; /* can't descend upon demand */ if (BLevitation) { ; /* rising via levitation is blocked */ - } else if ((u.ux == xupstair && u.uy == yupstair) - || (g.sstairs.up && u.ux == g.sstairs.sx && u.uy == g.sstairs.sy) - || (xupladder && u.ux == xupladder && u.uy == yupladder)) { + } else if (stairway_find_dir(TRUE)) { (void) doup(); /* in case we're already Levitating, which would have resulted in incrementing 'nothing' */ @@ -1983,11 +1973,7 @@ dodip() goto poof; } else if (obj->otyp == POT_POLYMORPH || potion->otyp == POT_POLYMORPH) { /* some objects can't be polymorphed */ - if (obj->otyp == potion->otyp /* both POT_POLY */ - || obj->otyp == WAN_POLYMORPH || obj->otyp == SPE_POLYMORPH - || obj == uball || obj == uskin - || obj_resists(obj->otyp == POT_POLYMORPH ? potion : obj, - 5, 95)) { + if (obj_unpolyable(obj->otyp == POT_POLYMORPH ? potion : obj)) { pline1(nothing_happens); } else { short save_otyp = obj->otyp; diff --git a/src/pray.c b/src/pray.c index e0f104601..fa95503ae 100644 --- a/src/pray.c +++ b/src/pray.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 pray.c $NHDT-Date: 1584872363 2020/03/22 10:19:23 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.142 $ */ +/* NetHack 3.7 pray.c $NHDT-Date: 1596498198 2020/08/03 23:43:18 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.144 $ */ /* Copyright (c) Benson I. Margulies, Mike Stephenson, Steve Linhart, 1989. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1979,7 +1979,7 @@ doturn() const char *Gname; int once, range, xlev; - if (!Role_if(PM_PRIEST) && !Role_if(PM_KNIGHT)) { + if (!Role_if(PM_CLERIC) && !Role_if(PM_KNIGHT)) { /* Try to use the "turn undead" spell. * * This used to be based on whether hero knows the name of the diff --git a/src/priest.c b/src/priest.c index 1b5bd3824..354cbc5a4 100644 --- a/src/priest.c +++ b/src/priest.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 priest.c $NHDT-Date: 1578895348 2020/01/13 06:02:28 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.57 $ */ +/* NetHack 3.7 priest.c $NHDT-Date: 1597931337 2020/08/20 13:48:57 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.63 $ */ /* Copyright (c) Izchak Miller, Steve Linhart, 1989. */ /* NetHack may be freely redistributed. See license for details. */ @@ -52,6 +52,7 @@ register xchar omx, omy, gx, gy; schar chcnt, cnt; coord poss[9]; long info[9]; + long ninfo = 0; long allowflags; #if 0 /* dead code; see below */ struct obj *ib = (struct obj *) 0; @@ -66,23 +67,7 @@ register xchar omx, omy, gx, gy; nix = omx; niy = omy; - if (mtmp->isshk) - allowflags = ALLOW_SSM; - else - allowflags = ALLOW_SSM | ALLOW_SANCT; - if (passes_walls(mtmp->data)) - allowflags |= (ALLOW_ROCK | ALLOW_WALL); - if (throws_rocks(mtmp->data)) - allowflags |= ALLOW_ROCK; - if (tunnels(mtmp->data)) - allowflags |= ALLOW_DIG; - if (!nohands(mtmp->data) && !verysmall(mtmp->data)) { - allowflags |= OPENDOOR; - if (monhaskey(mtmp, TRUE)) - allowflags |= UNLOCKDOOR; - } - if (is_giant(mtmp->data)) - allowflags |= BUSTDOOR; + allowflags = mon_allowflags(mtmp); cnt = mfndpos(mtmp, poss, info, allowflags); if (mtmp->isshk && avoid && uondoor) { /* perhaps we cannot avoid him */ @@ -100,12 +85,14 @@ pick_move: ny = poss[i].y; if (IS_ROOM(levl[nx][ny].typ) || (mtmp->isshk && (!in_his_shop || ESHK(mtmp)->following))) { - if (avoid && (info[i] & NOTONL)) + if (avoid && (info[i] & NOTONL) && !(info[i] & ALLOW_M)) continue; if ((!appr && !rn2(++chcnt)) - || (appr && GDIST(nx, ny) < GDIST(nix, niy))) { + || (appr && GDIST(nx, ny) < GDIST(nix, niy)) + || (info[i] & ALLOW_M)) { nix = nx; niy = ny; + ninfo = info[i]; } } } @@ -118,6 +105,19 @@ pick_move: } if (nix != omx || niy != omy) { + + if (ninfo & ALLOW_M) { + /* mtmp is deciding it would like to attack this turn. + * Returns from m_move_aggress don't correspond to the same things + * as this function should return, so we need to translate. */ + switch (m_move_aggress(mtmp, nix, niy)) { + case 2: + return -2; /* died making the attack */ + case 3: + return 1; /* attacked and spent this move */ + } + } + if (MON_AT(nix, niy)) return 0; remove_monster(omx, omy); @@ -233,7 +233,7 @@ boolean sanctum; /* is it the seat of the high priest? */ struct obj *otmp; int cnt; int px = 0, py = 0, i, si = rn2(8); - struct permonst *prim = &mons[sanctum ? PM_HIGH_PRIEST : PM_ALIGNED_PRIEST]; + struct permonst *prim = &mons[sanctum ? PM_HIGH_CLERIC : PM_ALIGNED_CLERIC]; for (i = 0; i < 8; i++) { px = sx + xdir[(i+si) % 8]; @@ -310,10 +310,11 @@ register struct monst *mon; char *pname; /* caller-supplied output buffer */ { boolean do_hallu = Hallucination, - aligned_priest = mon->data == &mons[PM_ALIGNED_PRIEST], - high_priest = mon->data == &mons[PM_HIGH_PRIEST]; + aligned_priest = mon->data == &mons[PM_ALIGNED_CLERIC], + high_priest = mon->data == &mons[PM_HIGH_CLERIC]; char whatcode = '\0'; - const char *what = do_hallu ? rndmonnam(&whatcode) : mon->data->mname; + const char *what = do_hallu ? rndmonnam(&whatcode) + : pmname(mon->data, Mgender(mon)); if (!mon->ispriest && !mon->isminion) /* should never happen... */ return strcpy(pname, what); /* caller must be confused */ @@ -416,7 +417,7 @@ int roomno; epri_p = EPRI(priest); shrined = has_shrine(priest); - sanctum = (priest->data == &mons[PM_HIGH_PRIEST] + sanctum = (priest->data == &mons[PM_HIGH_CLERIC] && (Is_sanctum(&u.uz) || In_endgame(&u.uz))); can_speak = (priest->mcanmove && !priest->msleeping); if (can_speak && !Deaf && g.moves >= epri_p->intone_time) { @@ -636,7 +637,7 @@ register struct monst *priest; && (!(HProtection & INTRINSIC) || (u.ublessed < 20 && (u.ublessed < 9 || !rn2(u.ublessed))))) { - verbalize("Thy devotion has been rewarded."); + verbalize("Thou hast been rewarded for thy devotion."); if (!(HProtection & INTRINSIC)) { HProtection |= FROMOUTSIDE; if (!u.ublessed) @@ -668,7 +669,7 @@ boolean peaceful; register boolean coaligned = (u.ualign.type == alignment); #if 0 /* this was due to permonst's pxlth field which is now gone */ - if (ptr != &mons[PM_ALIGNED_PRIEST] && ptr != &mons[PM_ANGEL]) + if (ptr != &mons[PM_ALIGNED_CLERIC] && ptr != &mons[PM_ANGEL]) return (struct monst *) 0; #endif @@ -697,7 +698,7 @@ register struct monst *roamer; { if (!roamer->isminion) return; - if (roamer->data != &mons[PM_ALIGNED_PRIEST] + if (roamer->data != &mons[PM_ALIGNED_CLERIC] && roamer->data != &mons[PM_ANGEL]) return; diff --git a/src/quest.c b/src/quest.c index a74cdf41b..e1d4dfdbd 100644 --- a/src/quest.c +++ b/src/quest.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 quest.c $NHDT-Date: 1505170343 2017/09/11 22:52:23 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.21 $ */ +/* NetHack 3.7 quest.c $NHDT-Date: 1596498200 2020/08/03 23:43:20 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.29 $ */ /* Copyright 1991, M. Stephenson */ /* NetHack may be freely redistributed. See license for details. */ @@ -182,13 +182,13 @@ boolean seal; branch *br; d_level *dest; struct trap *t; - int portal_flag; + int portal_flag = u.uevent.qexpelled ? UTOTYPE_NONE : UTOTYPE_PORTAL; br = dungeon_branch("The Quest"); dest = (br->end1.dnum == u.uz.dnum) ? &br->end2 : &br->end1; - portal_flag = u.uevent.qexpelled ? 0 /* returned via artifact? */ - : !seal ? 1 : -1; - schedule_goto(dest, FALSE, FALSE, portal_flag, (char *) 0, (char *) 0); + if (seal) + portal_flag |= UTOTYPE_RMPORTAL; + schedule_goto(dest, portal_flag, (char *) 0, (char *) 0); if (seal) { /* remove the portal to the quest - sealing it off */ int reexpelled = u.uevent.qexpelled; @@ -277,6 +277,8 @@ chat_with_leader() /* Rule 5: You aren't yet acceptable - or are you? */ } else { + int purity = 0; + if (!Qstat(met_leader)) { qt_pager("leader_first"); Qstat(met_leader) = TRUE; @@ -293,10 +295,10 @@ chat_with_leader() qt_pager("badlevel"); exercise(A_WIS, TRUE); expulsion(FALSE); - } else if (is_pure(TRUE) < 0) { + } else if ((purity = is_pure(TRUE)) < 0) { com_pager("banished"); expulsion(TRUE); - } else if (is_pure(TRUE) == 0) { + } else if (purity == 0) { qt_pager("badalign"); if (Qstat(not_ready) == MAX_QUEST_TRIES) { qt_pager("leader_last"); diff --git a/src/questpgr.c b/src/questpgr.c index 9f21301d2..2a52de0f1 100644 --- a/src/questpgr.c +++ b/src/questpgr.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 questpgr.c $NHDT-Date: 1590314765 2020/05/24 10:06:05 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.71 $ */ +/* NetHack 3.7 questpgr.c $NHDT-Date: 1596498201 2020/08/03 23:43:21 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.72 $ */ /* Copyright 1991, M. Stephenson */ /* NetHack may be freely redistributed. See license for details. */ @@ -52,7 +52,7 @@ ldrname() int i = g.urole.ldrnum; Sprintf(g.nambuf, "%s%s", type_is_pname(&mons[i]) ? "" : "the ", - mons[i].mname); + mons[i].pmnames[NEUTRAL]); return g.nambuf; } @@ -129,7 +129,7 @@ neminame() int i = g.urole.neminum; Sprintf(g.nambuf, "%s%s", type_is_pname(&mons[i]) ? "" : "the ", - mons[i].mname); + mons[i].pmnames[NEUTRAL]); return g.nambuf; } @@ -138,7 +138,7 @@ guardname() /* return your role leader's guard monster name */ { int i = g.urole.guardnum; - return mons[i].mname; + return mons[i].pmnames[NEUTRAL]; } static const char * diff --git a/src/read.c b/src/read.c index 5ff54c5cb..130259ee3 100644 --- a/src/read.c +++ b/src/read.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 read.c $NHDT-Date: 1592875138 2020/06/23 01:18:58 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.198 $ */ +/* NetHack 3.7 read.c $NHDT-Date: 1609323865 2020/12/30 10:24:25 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.214 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -17,8 +17,8 @@ static NEARDATA const char readable[] = { ALL_CLASSES, SCROLL_CLASS, static const char all_count[] = { ALLOW_COUNT, ALL_CLASSES, 0 }; static boolean FDECL(learnscrolltyp, (SHORT_P)); +static void FDECL(cap_spe, (struct obj *)); static char *FDECL(erode_obj_text, (struct obj *, char *)); -static char *FDECL(apron_text, (struct obj *, char *)); static void FDECL(stripspe, (struct obj *)); static void FDECL(p_glow1, (struct obj *)); static void FDECL(p_glow2, (struct obj *, const char *)); @@ -55,6 +55,17 @@ struct obj *sobj; (void) learnscrolltyp(sobj->otyp); } +/* max spe is +99, min is -99 */ +static void +cap_spe(obj) +struct obj *obj; +{ + if (obj) { + if (abs(obj->spe) > SPE_LIM) + obj->spe = sgn(obj->spe) * SPE_LIM; + } +} + static char * erode_obj_text(otmp, buf) struct obj *otmp; @@ -118,7 +129,7 @@ char *buf; "Meat is Mordor", "Minetown Better Business Bureau", "Minetown Watch", - "Ms. Palm's House of Negotiable Affection -- A Very Reputable House Of Disrepute", + "Ms. Palm's House of Negotiable Affection--A Very Reputable House Of Disrepute", "Protection Racketeer", "Real men love Crom", "Somebody stole my Mojo!", @@ -157,7 +168,7 @@ char *buf; return erode_obj_text(tshirt, buf); } -static char * +char * apron_text(apron, buf) struct obj *apron; char *buf; @@ -172,27 +183,88 @@ char *buf; "If you can't stand the heat, get out of Gehennom!", "If we weren't meant to eat animals, why are they made out of meat?", "If you don't like the food, I'll stab you", + /* In the movie "The Sum of All Fears", a Russian worker in a weapons + facility wears a T-shirt that a translator says reads, "I am a + bomb technician, if you see me running ... try to catch up." + In nethack, the quote is far more suitable to an alchemy smock + (particularly since so many of these others are about cooking) + than a T-shirt and is paraphrased to simplify/shorten it. */ + "If you see me running, try to keep up...", }; Strcpy(buf, apron_msgs[apron->o_id % SIZE(apron_msgs)]); return erode_obj_text(apron, buf); } +static const char *candy_wrappers[] = { + "", /* (none -- should never happen) */ + "Apollo", /* Lost */ + "Moon Crunchy", /* South Park */ + "Snacky Cake", "Chocolate Nuggie", "The Small Bar", + "Crispy Yum Yum", "Nilla Crunchie", "Berry Bar", + "Choco Nummer", "Om-nom", /* Cat Macro */ + "Fruity Oaty", /* Serenity */ + "Wonka Bar", /* Charlie and the Chocolate Factory */ +}; + +/* return the text of a candy bar's wrapper */ +const char * +candy_wrapper_text(obj) +struct obj *obj; +{ + /* modulo operation is just bullet proofing; 'spe' is already in range */ + return candy_wrappers[obj->spe % SIZE(candy_wrappers)]; +} + +/* assign a wrapper to a candy bar stack */ +void +assign_candy_wrapper(obj) +struct obj *obj; +{ + if (obj->otyp == CANDY_BAR) { + /* skips candy_wrappers[0] */ + obj->spe = 1 + rn2(SIZE(candy_wrappers) - 1); + } + return; +} + +/* the 'r' command; read a scroll or spell book or various other things */ int doread() { + static const char find_any_braille[] = "feel any Braille writing."; register struct obj *scroll; boolean confused, nodisappear; + int otyp; + + /* + * Reading while blind is allowed in most cases, including the + * Book of the Dead but not regular spellbooks. For scrolls, the + * description has to have been seen or magically learned (so only + * when scroll->dknown is true): hero recites the label while + * holding the unfurled scroll. We deliberately don't require + * free hands because that would cripple scroll of remove curse, + * but we ought to be requiring hands or at least limbs. The + * recitation could be sub-vocal; actual speech isn't required. + * + * Reading while confused is allowed and can produce alternate + * outcome. + * + * Reading while stunned is currently allowed but probably should + * be prevented.... + */ g.known = FALSE; if (check_capacity((char *) 0)) return 0; + scroll = getobj(readable, "read"); if (!scroll) return 0; + otyp = scroll->otyp; /* outrumor has its own blindness check */ - if (scroll->otyp == FORTUNE_COOKIE) { + if (otyp == FORTUNE_COOKIE) { if (flags.verbose) You("break up the cookie and throw away the pieces."); outrumor(bcsign(scroll), BY_COOKIE); @@ -200,16 +272,16 @@ doread() u.uconduct.literate++; useup(scroll); return 1; - } else if (scroll->otyp == T_SHIRT || scroll->otyp == ALCHEMY_SMOCK) { + } else if (otyp == T_SHIRT || otyp == ALCHEMY_SMOCK) { char buf[BUFSZ], *mesg; const char *endpunct; if (Blind) { - You_cant("feel any Braille writing."); + You_cant(find_any_braille); return 0; } /* can't read shirt worn under suit (under cloak is ok though) */ - if (scroll->otyp == T_SHIRT && uarm && scroll == uarmu) { + if (otyp == T_SHIRT && uarm && scroll == uarmu) { pline("%s shirt is obscured by %s%s.", scroll->unpaid ? "That" : "Your", shk_your(buf, uarm), suit_simple_name(uarm)); @@ -217,8 +289,8 @@ doread() } u.uconduct.literate++; /* populate 'buf[]' */ - mesg = (scroll->otyp == T_SHIRT) ? tshirt_text(scroll, buf) - : apron_text(scroll, buf); + mesg = (otyp == T_SHIRT) ? tshirt_text(scroll, buf) + : apron_text(scroll, buf); endpunct = ""; if (flags.verbose) { int ln = (int) strlen(mesg); @@ -230,7 +302,37 @@ doread() } pline("\"%s\"%s", mesg, endpunct); return 1; - } else if (scroll->otyp == CREDIT_CARD) { + } else if ((otyp == DUNCE_CAP || otyp == CORNUTHAUM) + /* note: "DUNCE" isn't directly connected to tourists but + if everyone could read it, they would always be able to + trivially distinguish between the two types of conical hat; + limiting this to tourists is better than rejecting it */ + && Role_if(PM_TOURIST)) { + /* another note: the misspelling, "wizzard", is correct; + that's what is written on Rincewind's pointy hat from + Pratchett's Discworld series, along with a lot of stars; + rather than inked on or painted on, treat them as stitched + or even separate pieces of fabric which have been attached + (don't recall whether the books mention anything like that...) */ + const char *cap_text = (otyp == DUNCE_CAP) ? "DUNCE" : "WIZZARD"; + + if (scroll->o_id % 3) { + /* no need to vary this when blind; "on this ___" is important + because it suggests that there might be something on others */ + You_cant("find anything to read on this %s.", + simpleonames(scroll)); + return 0; + } + pline("%s on the %s. It reads: %s.", + !Blind ? "There is writing" : "You feel lettering", + simpleonames(scroll), cap_text); + u.uconduct.literate++; + /* yet another note: despite the fact that player will recognize + the object type, don't make it become a discovery for hero */ + if (!objects[otyp].oc_name_known && !objects[otyp].oc_uname) + docall(scroll); + return 1; + } else if (otyp == CREDIT_CARD) { static const char *card_msgs[] = { "Leprechaun Gold Tru$t - Shamrock Card", "Magic Memory Vault Charge Card", @@ -269,12 +371,12 @@ doread() (flags.verbose || Blind) ? "." : ""); u.uconduct.literate++; return 1; - } else if (scroll->otyp == CAN_OF_GREASE) { + } else if (otyp == CAN_OF_GREASE) { pline("This %s has no label.", singular(scroll, xname)); return 0; - } else if (scroll->otyp == MAGIC_MARKER) { + } else if (otyp == MAGIC_MARKER) { if (Blind) { - You_cant("feel any Braille writing."); + You_cant(find_any_braille); return 0; } if (flags.verbose) @@ -298,33 +400,28 @@ doread() pline("\"Odin.\""); u.uconduct.literate++; return 1; - } else if (scroll->otyp == CANDY_BAR) { - static const char *wrapper_msgs[] = { - "Apollo", /* Lost */ - "Moon Crunchy", /* South Park */ - "Snacky Cake", "Chocolate Nuggie", "The Small Bar", - "Crispy Yum Yum", "Nilla Crunchie", "Berry Bar", - "Choco Nummer", "Om-nom", /* Cat Macro */ - "Fruity Oaty", /* Serenity */ - "Wonka Bar" /* Charlie and the Chocolate Factory */ - }; + } else if (otyp == CANDY_BAR) { + const char *wrapper = candy_wrapper_text(scroll); if (Blind) { - You_cant("feel any Braille writing."); + You_cant(find_any_braille); return 0; } - pline("The wrapper reads: \"%s\".", - wrapper_msgs[scroll->o_id % SIZE(wrapper_msgs)]); + if (!*wrapper) { + pline("The candy bar's wrapper is blank."); + return 0; + } + pline("The wrapper reads: \"%s\".", wrapper); u.uconduct.literate++; return 1; } else if (scroll->oclass != SCROLL_CLASS && scroll->oclass != SPBOOK_CLASS) { pline(silly_thing_to, "read"); return 0; - } else if (Blind && (scroll->otyp != SPE_BOOK_OF_THE_DEAD)) { + } else if (Blind && otyp != SPE_BOOK_OF_THE_DEAD) { const char *what = 0; - if (scroll->otyp == SPE_NOVEL) + if (otyp == SPE_NOVEL) /* unseen novels are already distinguishable from unseen spellbooks so this isn't revealing any extra information */ what = "words"; @@ -339,8 +436,8 @@ doread() } confused = (Confusion != 0); -#ifdef MAIL - if (scroll->otyp == SCR_MAIL) { +#ifdef MAIL_STRUCTURES + if (otyp == SCR_MAIL) { confused = FALSE; /* override */ /* reading mail is a convenience for the player and takes place outside the game, so shouldn't affect gameplay; @@ -359,24 +456,22 @@ doread() #endif /* Actions required to win the game aren't counted towards conduct */ - /* Novel conduct is handled in read_tribute so exclude it too*/ - if (scroll->otyp != SPE_BOOK_OF_THE_DEAD - && scroll->otyp != SPE_BLANK_PAPER && scroll->otyp != SCR_BLANK_PAPER - && scroll->otyp != SPE_NOVEL) + /* Novel conduct is handled in read_tribute so exclude it too */ + if (otyp != SPE_BOOK_OF_THE_DEAD && otyp != SPE_NOVEL + && otyp != SPE_BLANK_PAPER && otyp != SCR_BLANK_PAPER) u.uconduct.literate++; if (scroll->oclass == SPBOOK_CLASS) { return study_book(scroll); } scroll->in_use = TRUE; /* scroll, not spellbook, now being read */ - if (scroll->otyp != SCR_BLANK_PAPER) { + if (otyp != SCR_BLANK_PAPER) { boolean silently = !can_chant(&g.youmonst); /* a few scroll feedback messages describe something happening to the scroll itself, so avoid "it disappears" for those */ - nodisappear = (scroll->otyp == SCR_FIRE - || (scroll->otyp == SCR_REMOVE_CURSE - && scroll->cursed)); + nodisappear = (otyp == SCR_FIRE + || (otyp == SCR_REMOVE_CURSE && scroll->cursed)); if (Blind) pline(nodisappear ? "You %s the formula on the scroll." @@ -394,14 +489,14 @@ doread() } } if (!seffects(scroll)) { - if (!objects[scroll->otyp].oc_name_known) { + if (!objects[otyp].oc_name_known) { if (g.known) learnscroll(scroll); - else if (!objects[scroll->otyp].oc_uname) + else if (!objects[otyp].oc_uname) docall(scroll); } scroll->in_use = FALSE; - if (scroll->otyp != SCR_BLANK_PAPER) + if (otyp != SCR_BLANK_PAPER) useup(scroll); } return 1; @@ -455,8 +550,16 @@ struct obj *obj; && objects[obj->otyp].oc_name_known))); if (is_weptool(obj)) /* specific check before general tools */ return FALSE; - if (obj->oclass == TOOL_CLASS) + if (obj->oclass == TOOL_CLASS) { + if (obj->otyp == BRASS_LANTERN + || (obj->otyp == OIL_LAMP) + /* only list magic lamps if they are not identified yet */ + || (obj->otyp == MAGIC_LAMP + && !objects[MAGIC_LAMP].oc_name_known)) { + return TRUE; + } return (boolean) objects[obj->otyp].oc_charged; + } return FALSE; /* why are weapons/armor considered charged anyway? */ } @@ -588,11 +691,10 @@ int curse_bless; case MAGIC_MARKER: case TINNING_KIT: case EXPENSIVE_CAMERA: - if (is_cursed) + if (is_cursed) { stripspe(obj); - else if (rechrg - && obj->otyp - == MAGIC_MARKER) { /* previously recharged */ + } else if (rechrg && obj->otyp == MAGIC_MARKER) { + /* previously recharged */ obj->recharged = 1; /* override increment done above */ if (obj->spe < 3) Your("marker seems permanently dried out."); @@ -618,8 +720,9 @@ int curse_bless; obj->spe = 50; else { int chrg = (int) obj->spe; - if ((chrg + n) > 127) - obj->spe = 127; + + if (chrg + n > SPE_LIM) + obj->spe = SPE_LIM; else obj->spe += n; } @@ -733,9 +836,12 @@ int curse_bless; } /* switch */ } else { - not_chargable: + not_chargable: You("have a feeling of loss."); } + + /* prevent enchantment from getting out of range */ + cap_spe(obj); } /* @@ -847,22 +953,38 @@ struct obj *sobj; /* scroll, or fake spellbook object for scroll-like spell */ || objects[otyp].oc_name_known); switch (otyp) { -#ifdef MAIL - case SCR_MAIL: +#ifdef MAIL_STRUCTURES + case SCR_MAIL: { + boolean odd = (sobj->o_id % 2) == 1; + g.known = TRUE; - if (sobj->spe == 2) + switch (sobj->spe) { + case 2: /* "stamped scroll" created via magic marker--without a stamp */ - pline("This scroll is marked \"postage due\"."); - else if (sobj->spe) + pline("This scroll is marked \"%s\".", + odd ? "Postage Due" : "Return to Sender"); + break; + case 1: /* scroll of mail obtained from bones file or from wishing; - * note to the puzzled: the game Larn actually sends you junk - * mail if you win! - */ - pline( - "This seems to be junk mail addressed to the finder of the Eye of Larn."); - else + note to the puzzled: the game Larn actually sends you junk + mail if you win! */ + pline("This seems to be %s.", + odd ? "a chain letter threatening your luck" + : "junk mail addressed to the finder of the Eye of Larn"); + break; + default: +#ifdef MAIL readmail(sobj); +#else + /* unreachable since with MAIL undefined, sobj->spe won't be 0; + as a precaution, be prepared to give arbitrary feedback; + caller has already reported that it disappears upon reading */ + pline("That was a scroll of mail?"); +#endif + break; + } break; + } #endif case SCR_ENCHANT_ARMOR: { register schar s; @@ -948,6 +1070,7 @@ struct obj *sobj; /* scroll, or fake spellbook object for scroll-like spell */ otmp->otyp += GRAY_DRAGON_SCALE_MAIL - GRAY_DRAGON_SCALES; if (sblessed) { otmp->spe++; + cap_spe(otmp); if (!otmp->blessed) bless(otmp); } else if (otmp->cursed) @@ -959,7 +1082,7 @@ struct obj *sobj; /* scroll, or fake spellbook object for scroll-like spell */ break; } pline("%s %s%s%s%s for a %s.", Yname2(otmp), - s == 0 ? "violently " : "", + (s == 0) ? "violently " : "", otense(otmp, Blind ? "vibrate" : "glow"), (!Blind && !same_color) ? " " : "", (Blind || same_color) @@ -976,8 +1099,15 @@ struct obj *sobj; /* scroll, or fake spellbook object for scroll-like spell */ else if (!scursed && otmp->cursed) uncurse(otmp); if (s) { + int oldspe = otmp->spe; + /* despite being schar, it shouldn't be possible for spe to wrap + here because it has been capped at 99 and s is quite small; + however, might need to change s if it takes spe past 99 */ otmp->spe += s; - adj_abon(otmp, s); + cap_spe(otmp); /* make sure that it doesn't exceed SPE_LIM */ + s = otmp->spe - oldspe; /* cap_spe() might have throttled 's' */ + if (s) /* skip if it got changed to 0 */ + adj_abon(otmp, s); /* adjust armor bonus for Dex or Int+Wis */ g.known = otmp->known; /* update shop bill to reflect new higher price */ if (s > 0 && otmp->unpaid) @@ -1240,6 +1370,8 @@ struct obj *sobj; /* scroll, or fake spellbook object for scroll-like spell */ : sblessed ? rnd(3 - uwep->spe / 3) : 1)) sobj = 0; /* nothing enchanted: strange_feeling -> useup */ + if (uwep) + cap_spe(uwep); break; case SCR_TAMING: case SPE_CHARM_MONSTER: { @@ -1330,8 +1462,14 @@ struct obj *sobj; /* scroll, or fake spellbook object for scroll-like spell */ case SCR_TELEPORTATION: if (confused || scursed) { level_tele(); + /* gives "materialize on different/same level!" message, must + be a teleport scroll */ + g.known = TRUE; } else { - g.known = scrolltele(sobj); + scrolltele(sobj); + /* this will call learnscroll() as appropriate, and has results + which maybe shouldn't result in the scroll becoming known; + either way, no need to set g.known here */ } break; case SCR_GOLD_DETECTION: @@ -1345,34 +1483,36 @@ struct obj *sobj; /* scroll, or fake spellbook object for scroll-like spell */ break; case SCR_IDENTIFY: /* known = TRUE; -- handled inline here */ - /* use up the scroll first, before makeknown() performs a - perm_invent update; also simplifies empty invent check */ + /* use up the scroll first, before learnscrolltyp() -> makeknown() + performs perm_invent update; also simplifies empty invent check */ useup(sobj); sobj = 0; /* it's gone */ - if (confused) + /* scroll just identifies itself for any scroll read while confused + or for cursed scroll read without knowing identify yet */ + if (confused || (scursed && !already_known)) You("identify this as an identify scroll."); - else if (!already_known || !g.invent) - /* force feedback now if invent became - empty after using up this scroll */ + else if (!already_known) pline("This is an identify scroll."); if (!already_known) (void) learnscrolltyp(SCR_IDENTIFY); + if (confused || (scursed && !already_known)) + break; /*FALLTHRU*/ case SPE_IDENTIFY: - cval = 1; - if (sblessed || (!scursed && !rn2(5))) { - cval = rn2(5); - /* note: if cval==0, identify all items */ - if (cval == 1 && sblessed && Luck > 0) - ++cval; - } - if (g.invent && !confused) { + if (g.invent) { + cval = 1; + if (sblessed || (!scursed && !rn2(5))) { + cval = rn2(5); + /* note: if cval==0, identify all items */ + if (cval == 1 && sblessed && Luck > 0) + ++cval; + } identify_pack(cval, !already_known); - } else if (otyp == SPE_IDENTIFY) { - /* when casting a spell we know we're not confused, - so inventory must be empty (another message has - already been given above if reading a scroll) */ - pline("You're not carrying anything to be identified."); + } else { + /* spell cast with inventory empty or scroll read when it's + the only item leaving empty inventory after being used up */ + pline("You're not carrying anything%s to be identified.", + (otyp == SCR_IDENTIFY) ? " else" : ""); } break; case SCR_CHARGING: @@ -1919,7 +2059,7 @@ do_class_genocide() return; class = name_to_monclass(buf, (int *) 0); - if (class == 0 && (i = name_to_mon(buf)) != NON_PM) + if (class == 0 && (i = name_to_mon(buf, (int *) 0)) != NON_PM) class = mons[i].mlet; immunecnt = gonecnt = goodcnt = 0; for (i = LOW_PM; i < NUMMONS; i++) { @@ -1961,7 +2101,7 @@ do_class_genocide() if (mons[i].mlet == class) { char nam[BUFSZ]; - Strcpy(nam, makeplural(mons[i].mname)); + Strcpy(nam, makeplural(mons[i].pmnames[NEUTRAL])); /* Although "genus" is Latin for race, the hero benefits * from both race and role; thus genocide affects either. */ @@ -2025,12 +2165,12 @@ do_class_genocide() named = type_is_pname(&mons[i]) ? TRUE : FALSE; uniq = (mons[i].geno & G_UNIQ) ? TRUE : FALSE; /* one special case */ - if (i == PM_HIGH_PRIEST) + if (i == PM_HIGH_CLERIC) uniq = FALSE; You("aren't permitted to genocide %s%s.", (uniq && !named) ? "the " : "", - (uniq || named) ? mons[i].mname : nam); + (uniq || named) ? mons[i].pmnames[NEUTRAL] : nam); } } } @@ -2065,7 +2205,7 @@ int how; if (how & PLAYER) { mndx = u.umonster; /* non-polymorphed mon num */ ptr = &mons[mndx]; - Strcpy(buf, ptr->mname); + Strcpy(buf, pmname(ptr, Ugender)); killplayer++; } else { for (i = 0;; i++) { @@ -2090,7 +2230,7 @@ int how; return; } - mndx = name_to_mon(buf); + mndx = name_to_mon(buf, (int *) 0); if (mndx == NON_PM || (g.mvitals[mndx].mvflags & G_GENOD)) { pline("Such creatures %s exist in this world.", (mndx == NON_PM) ? "do not" : "no longer"); @@ -2136,15 +2276,15 @@ int how; which = "all "; if (Hallucination) { if (Upolyd) - Strcpy(buf, g.youmonst.data->mname); + Strcpy(buf, pmname(g.youmonst.data, flags.female ? FEMALE : MALE)); else { Strcpy(buf, (flags.female && g.urole.name.f) ? g.urole.name.f : g.urole.name.m); buf[0] = lowc(buf[0]); } } else { - Strcpy(buf, ptr->mname); /* make sure we have standard singular */ - if ((ptr->geno & G_UNIQ) && ptr != &mons[PM_HIGH_PRIEST]) + Strcpy(buf, ptr->pmnames[NEUTRAL]); /* make sure we have standard singular */ + if ((ptr->geno & G_UNIQ) && ptr != &mons[PM_HIGH_CLERIC]) which = !type_is_pname(ptr) ? "the " : ""; } if (how & REALLY) { @@ -2285,7 +2425,7 @@ struct obj *from_obj; { /* SHOPKEEPERS can be revived now */ if (*mtype == PM_GUARD || (*mtype == PM_SHOPKEEPER && !revival) - || *mtype == PM_HIGH_PRIEST || *mtype == PM_ALIGNED_PRIEST + || *mtype == PM_HIGH_CLERIC || *mtype == PM_ALIGNED_CLERIC || *mtype == PM_ANGEL) { *mtype = PM_HUMAN_ZOMBIE; return TRUE; @@ -2307,13 +2447,15 @@ create_particular_parse(str, d) char *str; struct _create_particular_data *d; { + int gender_name_var = NEUTRAL; char *bufp = str; char *tmpp; d->quan = 1 + ((g.multi > 0) ? g.multi : 0); d->monclass = MAXMCLASSES; d->which = g.urole.malenum; /* an arbitrary index into mons[] */ - d->fem = -1; /* gender not specified */ + d->fem = -1; /* gender not specified */ + d->genderconf = -1; /* no confusion on which gender to assign */ d->randmonst = FALSE; d->maketame = d->makepeaceful = d->makehostile = FALSE; d->sleeping = d->saddled = d->invisible = d->hidden = FALSE; @@ -2376,7 +2518,23 @@ struct _create_particular_data *d; d->randmonst = TRUE; return TRUE; } - d->which = name_to_mon(bufp); + d->which = name_to_mon(bufp, &gender_name_var); + /* + * With the introduction of male and female monster names + * in 3.7, preserve that detail. + * + * If d->fem is already set to MALE or FEMALE at this juncture, it means + * one of those terms was explicitly specified. + */ + if (d->fem == MALE || d->fem == FEMALE) { /* explicity expressed */ + if ((gender_name_var != NEUTRAL) && (d->fem != gender_name_var)) { + /* apparent selection incompatibility */ + d->genderconf = gender_name_var; /* resolve later */ + } + /* otherwise keep the value of d->fem, as it's okay */ + } else { /* no explicit gender term was specified */ + d->fem = gender_name_var; + } if (d->which >= LOW_PM) return TRUE; /* got one */ d->monclass = name_to_monclass(bufp, &d->which); @@ -2416,18 +2574,49 @@ struct _create_particular_data *d; char buf[BUFSZ]; Sprintf(buf, "Creating %s instead; force %s?", - mons[d->which].mname, mons[firstchoice].mname); + mons[d->which].pmnames[NEUTRAL], + mons[firstchoice].pmnames[NEUTRAL]); if (yn(buf) == 'y') d->which = firstchoice; } whichpm = &mons[d->which]; } for (i = 0; i < d->quan; i++) { + long mmflags = NO_MM_FLAGS; + if (d->monclass != MAXMCLASSES) whichpm = mkclass(d->monclass, 0); else if (d->randmonst) whichpm = rndmonst(); - mtmp = makemon(whichpm, u.ux, u.uy, NO_MM_FLAGS); + if (d->genderconf == -1) { + /* no confict exists between explicit gender term and + the specified monster name */ + if (d->fem != -1 + && (!whichpm || (!is_male(whichpm) && !is_female(whichpm)))) + mmflags |= (d->fem == FEMALE) ? MM_FEMALE + : (d->fem == MALE) ? MM_MALE : 0; + } else { + /* conundrum alert: an explicit gender term conflicts with an + explicit gender-tied naming term (i.e. male cavewoman) */ + + /* option not gone with: name overrides the explicit gender as + commented out here */ + /* d->fem = d->genderconf; */ + + /* option chosen: let the explicit gender term (male or female) + override the gender-tied naming term, so leave d->fem as-is */ + + mmflags |= (d->fem == FEMALE) ? MM_FEMALE + : (d->fem == MALE) ? MM_MALE : 0; + + /* another option would be to consider it a faulty specification + and reject the request completely and produce a random monster + with a gender matching that specified instead (i.e. there is + no such thing as a male cavewoman) */ + /* whichpm = rndmonst(); */ + /* mmflags |= (d->fem == FEMALE) ? MM_FEMALE : MM_MALE; */ + } + mtmp = makemon(whichpm, u.ux, u.uy, mmflags); if (!mtmp) { /* quit trying if creation failed and is going to repeat */ if (d->monclass == MAXMCLASSES && !d->randmonst) @@ -2436,9 +2625,6 @@ struct _create_particular_data *d; continue; } mx = mtmp->mx, my = mtmp->my; - /* 'is_FOO()' ought to be called 'always_FOO()' */ - if (d->fem != -1 && !is_male(mtmp->data) && !is_female(mtmp->data)) - mtmp->female = d->fem; /* ignored for is_neuter() */ if (d->maketame) { (void) tamedog(mtmp, (struct obj *) 0); } else if (d->makepeaceful || d->makehostile) { @@ -2504,12 +2690,15 @@ struct _create_particular_data *d; boolean create_particular() { - char buf[BUFSZ] = DUMMY, *bufp; - int tryct = 5; +#define CP_TRYLIM 5 struct _create_particular_data d; + char *bufp, buf[BUFSZ], prompt[QBUFSZ]; + int tryct = CP_TRYLIM; + buf[0] = '\0'; /* for EDIT_GETLIN */ + Strcpy(prompt, "Create what kind of monster?"); do { - getlin("Create what kind of monster? [type the name or symbol]", buf); + getlin(prompt, buf); bufp = mungspaces(buf); if (*bufp == '\033') return FALSE; @@ -2519,6 +2708,9 @@ create_particular() /* no good; try again... */ pline("I've never heard of such monsters."); + /* when a second try is needed, expand the prompt */ + if (tryct == CP_TRYLIM) + Strcat(prompt, " [type name or symbol]"); } while (--tryct > 0); if (!tryct) diff --git a/src/rect.c b/src/rect.c index 9f462fcc6..1ae311898 100644 --- a/src/rect.c +++ b/src/rect.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 rect.c $NHDT-Date: 1432512774 2015/05/25 00:12:54 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ */ +/* NetHack 3.7 rect.c $NHDT-Date: 1596498203 2020/08/03 23:43:23 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.14 $ */ /* Copyright (c) 1990 by Jean-Christophe Collet */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/src/region.c b/src/region.c index 9dfe9150d..771217bd9 100644 --- a/src/region.c +++ b/src/region.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 region.c $NHDT-Date: 1579655029 2020/01/22 01:03:49 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.60 $ */ +/* NetHack 3.7 region.c $NHDT-Date: 1596498203 2020/08/03 23:43:23 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.65 $ */ /* Copyright (c) 1996 by Jean-Christophe Collet */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/src/restore.c b/src/restore.c index 3f4505e5e..935c54630 100644 --- a/src/restore.c +++ b/src/restore.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 restore.c $NHDT-Date: 1593953357 2020/07/05 12:49:17 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.166 $ */ +/* NetHack 3.7 restore.c $NHDT-Date: 1606765214 2020/11/30 19:40:14 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.173 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2009. */ /* NetHack may be freely redistributed. See license for details. */ @@ -294,27 +294,6 @@ boolean frozen; /* restore container back pointers */ for (otmp3 = otmp->cobj; otmp3; otmp3 = otmp3->nobj) otmp3->ocontainer = otmp; - } else if (SchroedingersBox(otmp)) { - struct obj *catcorpse; - - /* - * TODO: Remove this after 3.6.x save compatibility is dropped. - * - * As of 3.6.2, SchroedingersBox() always has a cat corpse in it. - * For 3.6.[01], it was empty and its weight was falsified - * to have the value it would have had if there was one inside. - * Put a non-rotting cat corpse in this box to convert to 3.6.2. - * - * [Note: after this fix up, future save/restore of this object - * will take the Has_contents() code path above.] - */ - if ((catcorpse = mksobj(CORPSE, TRUE, FALSE)) != 0) { - otmp->spe = 1; /* flag for special SchroedingersBox */ - set_corpsenm(catcorpse, PM_HOUSECAT); - (void) stop_timer(ROT_CORPSE, obj_to_any(catcorpse)); - add_to_container(otmp, catcorpse); - otmp->owt = weight(otmp); - } } if (otmp->bypass) otmp->bypass = 0; @@ -354,13 +333,13 @@ struct monst *mtmp; if (mtmp->mextra) { mtmp->mextra = newmextra(); - /* mname - monster's name */ + /* mgivenname - monster's name */ if (nhfp->structlevel) mread(nhfp->fd, (genericptr_t) &buflen, sizeof(buflen)); if (buflen > 0) { /* includes terminating '\0' */ - new_mname(mtmp, buflen); + new_mgivenname(mtmp, buflen); if (nhfp->structlevel) - mread(nhfp->fd, (genericptr_t) MNAME(mtmp), buflen); + mread(nhfp->fd, (genericptr_t) MGIVENNAME(mtmp), buflen); } /* egd - vault guard */ if (nhfp->structlevel) @@ -664,9 +643,9 @@ unsigned int *stuckid, *steedid; while (bc_obj) { struct obj *nobj = bc_obj->nobj; + bc_obj->nobj = (struct obj *) 0; if (bc_obj->owornmask) setworn(bc_obj, bc_obj->owornmask); - bc_obj->nobj = (struct obj *) 0; bc_obj = nobj; } g.migrating_objs = restobjchn(nhfp, FALSE); @@ -792,7 +771,7 @@ NHFILE *nhfp; int rtmp; struct obj *otmp; - g.restoring = TRUE; + g.program_state.restoring = 1; get_plname_from_file(nhfp, g.plname); getlev(nhfp, 0, (xchar) 0); if (!restgamestate(nhfp, &stuckid, &steedid)) { @@ -807,7 +786,7 @@ NHFILE *nhfp; is not really affiliated with an open file */ close_nhfile(nhfp); (void) delete_savefile(); - g.restoring = FALSE; + g.program_state.restoring = 0; return 0; } restlevelstate(stuckid, steedid); @@ -830,7 +809,7 @@ NHFILE *nhfp; #ifdef AMII_GRAPHICS { extern struct window_procs amii_procs; - if (WINDOWPORT("amii") { + if (WINDOWPORT("amii")) { extern winid WIN_BASE; clear_nhwindow(WIN_BASE); /* hack until there's a hook for this */ } @@ -916,8 +895,8 @@ NHFILE *nhfp; g.vision_full_recalc = 1; /* recompute vision (not saved) */ run_timers(); /* expire all timers that have gone off while away */ + g.program_state.restoring = 0; /* affects bot() so clear before docrt() */ docrt(); - g.restoring = FALSE; clear_nhwindow(WIN_MESSAGE); /* Success! */ @@ -926,6 +905,37 @@ NHFILE *nhfp; return 1; } +void +rest_stairs(nhfp) +NHFILE *nhfp; +{ + int buflen = 0; + stairway stway; + int len = 0; + + stairway_free_all(); + while (1) { + if (nhfp->structlevel) { + len += (int) sizeof(buflen); + mread(nhfp->fd, (genericptr_t) &buflen, sizeof buflen); + } + + if (buflen == -1) + break; + + len += (int) sizeof (stairway); + if (nhfp->structlevel) { + mread(nhfp->fd, (genericptr_t) &stway, sizeof (stairway)); + } + if (stway.tolev.dnum == u.uz.dnum) { + /* stairway dlevel is relative, make it absolute */ + stway.tolev.dlevel += u.uz.dlevel; + } + stairway_add(stway.sx, stway.sy, stway.up, stway.isladder, + &(stway.tolev)); + } +} + void restcemetery(nhfp, cemeteryaddr) NHFILE *nhfp; @@ -954,7 +964,11 @@ struct cemetery **cemeteryaddr; static void rest_levl(nhfp, rlecomp) NHFILE *nhfp; +#ifdef RLECOMP boolean rlecomp; +#else +boolean rlecomp UNUSED; +#endif { #ifdef RLECOMP short i, j; @@ -984,9 +998,7 @@ boolean rlecomp; } return; } -#else /* !RLECOMP */ - nhUse(rlecomp); -#endif /* ?RLECOMP */ +#endif /* RLECOMP */ if (nhfp->structlevel) { mread(nhfp->fd, (genericptr_t) levl, sizeof levl); } @@ -1069,11 +1081,7 @@ xchar lev; elapsed = g.monstermoves - g.omoves; if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t)&g.upstair, sizeof(stairway)); - mread(nhfp->fd, (genericptr_t)&g.dnstair, sizeof(stairway)); - mread(nhfp->fd, (genericptr_t)&g.upladder, sizeof(stairway)); - mread(nhfp->fd, (genericptr_t)&g.dnladder, sizeof(stairway)); - mread(nhfp->fd, (genericptr_t)&g.sstairs, sizeof(stairway)); + rest_stairs(nhfp); mread(nhfp->fd, (genericptr_t)&g.updest, sizeof(dest_area)); mread(nhfp->fd, (genericptr_t)&g.dndest, sizeof(dest_area)); mread(nhfp->fd, (genericptr_t)&g.level.flags, sizeof(g.level.flags)); @@ -1123,6 +1131,8 @@ xchar lev; place_monster(mtmp, mtmp->mx, mtmp->my); if (mtmp->wormno) place_wsegs(mtmp, NULL); + if (hides_under(mtmp->data) && mtmp->mundetected) + (void) hideunder(mtmp); /* regenerate monsters while on another level */ if (!u.uz.dlevel) @@ -1151,16 +1161,27 @@ xchar lev; rest_regions(nhfp); if (ghostly) { + stairway *stway = g.stairs; + while (stway) { + if (!stway->isladder && !stway->up + && stway->tolev.dnum == u.uz.dnum) + break; + stway = stway->next; + } + /* Now get rid of all the temp fruits... */ freefruitchn(g.oldfruit), g.oldfruit = 0; if (lev > ledger_no(&medusa_level) - && lev < ledger_no(&stronghold_level) && xdnstair == 0) { + && lev < ledger_no(&stronghold_level) && !stway) { coord cc; + d_level dest; + + dest.dnum = u.uz.dnum; + dest.dlevel = u.uz.dlevel + 1; mazexy(&cc); - xdnstair = cc.x; - ydnstair = cc.y; + stairway_add(cc.x, cc.y, FALSE, FALSE, &dest); levl[cc.x][cc.y].typ = STAIRS; } @@ -1176,8 +1197,15 @@ xchar lev; switch (br->type) { case BR_STAIR: case BR_NO_END1: - case BR_NO_END2: /* OK to assign to g.sstairs if it's not used */ - assign_level(&g.sstairs.tolev, <mp); + case BR_NO_END2: + stway = g.stairs; + while (stway) { + if (stway->tolev.dnum != u.uz.dnum) + break; + stway = stway->next; + } + if (stway) + assign_level(&(stway->tolev), <mp); break; case BR_PORTAL: /* max of 1 portal per level */ for (trap = g.ftrap; trap; trap = trap->ntrap) diff --git a/src/rip.c b/src/rip.c index 6b5fdb097..634d816d2 100644 --- a/src/rip.c +++ b/src/rip.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 rip.c $NHDT-Date: 1488788514 2017/03/06 08:21:54 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.23 $ */ +/* NetHack 3.7 rip.c $NHDT-Date: 1597967808 2020/08/20 23:56:48 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.33 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2017. */ /* NetHack may be freely redistributed. See license for details. */ @@ -6,7 +6,8 @@ #include "hack.h" #if defined(TTY_GRAPHICS) || defined(X11_GRAPHICS) || defined(GEM_GRAPHICS) \ - || defined(MSWIN_GRAPHICS) || defined(DUMPLOG) || defined(CURSES_GRAPHICS) + || defined(MSWIN_GRAPHICS) || defined(DUMPLOG) \ + || defined(CURSES_GRAPHICS) || defined(SHIM_GRAPHICS) #define TEXT_TOMBSTONE #endif #if defined(mac) || defined(__BEOS__) || defined(WIN32_GRAPHICS) @@ -60,12 +61,10 @@ static const char *rip_txt[] = { }; #define STONE_LINE_CENT 19 /* char[] element of center of stone face */ #endif /* NH320_DEDICATION */ -#define STONE_LINE_LEN \ - 16 /* # chars that fit on one line \ - * (note 1 ' ' border) \ - */ -#define NAME_LINE 6 /* *char[] line # for player name */ -#define GOLD_LINE 7 /* *char[] line # for amount of gold */ +#define STONE_LINE_LEN 16 /* # chars that fit on one line + * (note 1 ' ' border) */ +#define NAME_LINE 6 /* *char[] line # for player name */ +#define GOLD_LINE 7 /* *char[] line # for amount of gold */ #define DEATH_LINE 8 /* *char[] line # for death description */ #define YEAR_LINE 12 /* *char[] line # for year */ @@ -90,9 +89,9 @@ time_t when; register char **dp; register char *dpx; char buf[BUFSZ]; - long year; register int x; - int line; + int line, year; + long cash; g.rip = dp = (char **) alloc(sizeof(rip_txt)); for (x = 0; rip_txt[x]; ++x) @@ -100,13 +99,15 @@ time_t when; dp[x] = (char *) 0; /* Put name on stone */ - Sprintf(buf, "%s", g.plname); - buf[STONE_LINE_LEN] = 0; + Sprintf(buf, "%.*s", (int) STONE_LINE_LEN, g.plname); center(NAME_LINE, buf); /* Put $ on stone */ - Sprintf(buf, "%ld Au", g.done_money); - buf[STONE_LINE_LEN] = 0; /* It could be a *lot* of gold :-) */ + cash = max(g.done_money, 0L); + /* arbitrary upper limit; practical upper limit is quite a bit less */ + if (cash > 999999999L) + cash = 999999999L; + Sprintf(buf, "%ld Au", cash); center(GOLD_LINE, buf); /* Put together death description */ @@ -114,11 +115,11 @@ time_t when; /* Put death type on stone */ for (line = DEATH_LINE, dpx = buf; line < YEAR_LINE; line++) { - register int i, i0; char tmpchar; + int i, i0 = (int) strlen(dpx); - if ((i0 = strlen(dpx)) > STONE_LINE_LEN) { - for (i = STONE_LINE_LEN; ((i0 > STONE_LINE_LEN) && i); i--) + if (i0 > STONE_LINE_LEN) { + for (i = STONE_LINE_LEN; (i > 0) && (i0 > STONE_LINE_LEN); --i) if (dpx[i] == ' ') i0 = i; if (!i) @@ -135,8 +136,8 @@ time_t when; } /* Put year on stone */ - year = yyyymmdd(when) / 10000L; - Sprintf(buf, "%4ld", year); + year = (int) ((yyyymmdd(when) / 10000L) % 10000L); + Sprintf(buf, "%4d", year); center(YEAR_LINE, buf); #ifdef DUMPLOG diff --git a/src/rnd.c b/src/rnd.c index 2a1e92bcf..6b5d46006 100644 --- a/src/rnd.c +++ b/src/rnd.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 rnd.c $NHDT-Date: 1524689470 2018/04/25 20:51:10 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.18 $ */ +/* NetHack 3.7 rnd.c $NHDT-Date: 1596498205 2020/08/03 23:43:25 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.30 $ */ /* Copyright (c) 2004 by Robert Patrick Rankin */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/src/role.c b/src/role.c index a31700369..fe30684a1 100644 --- a/src/role.c +++ b/src/role.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 role.c $NHDT-Date: 1589326676 2020/05/12 23:37:56 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.70 $ */ +/* NetHack 3.7 role.c $NHDT-Date: 1596498206 2020/08/03 23:43:26 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.71 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985-1999. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -123,8 +123,8 @@ const struct Role roles[NUM_ROLES+1] = { "Cav", "the Caves of the Ancestors", "the Dragon's Lair", - PM_CAVEMAN, - PM_CAVEWOMAN, + PM_CAVE_DWELLER, + NON_PM, PM_LITTLE_DOG, PM_SHAMAN_KARNOV, PM_NEANDERTHAL, @@ -289,8 +289,8 @@ const struct Role roles[NUM_ROLES+1] = { "Pri", "the Great Temple", "the Temple of Nalzok", - PM_PRIEST, - PM_PRIESTESS, + PM_CLERIC, + NON_PM, NON_PM, PM_ARCH_PRIEST, PM_ACOLYTE, diff --git a/src/save.c b/src/save.c index 3e7964cd4..fe6001bbf 100644 --- a/src/save.c +++ b/src/save.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 save.c $NHDT-Date: 1593953359 2020/07/05 12:49:19 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.159 $ */ +/* NetHack 3.7 save.c $NHDT-Date: 1606949327 2020/12/02 22:48:47 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.164 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2009. */ /* NetHack may be freely redistributed. See license for details. */ @@ -21,14 +21,12 @@ int dotcnt, dotrow; /* also used in restore */ #endif static void FDECL(savelevchn, (NHFILE *)); -static void FDECL(savedamage, (NHFILE *)); -/* static void FDECL(saveobj, (NHFILE *,struct obj *)); */ -/* static void FDECL(savemon, (NHFILE *,struct monst *)); */ -/* static void FDECL(savelevl, (NHFILE *, BOOLEAN_P)); */ -static void FDECL(saveobj, (NHFILE *,struct obj *)); -static void FDECL(savemon, (NHFILE *,struct monst *)); static void FDECL(savelevl, (NHFILE *,BOOLEAN_P)); -static void FDECL(saveobjchn, (NHFILE *,struct obj *)); +static void FDECL(savedamage, (NHFILE *)); +static void FDECL(save_stairs, (NHFILE *)); +static void FDECL(saveobj, (NHFILE *,struct obj *)); +static void FDECL(saveobjchn, (NHFILE *,struct obj **)); +static void FDECL(savemon, (NHFILE *,struct monst *)); static void FDECL(savemonchn, (NHFILE *,struct monst *)); static void FDECL(savetrapchn, (NHFILE *,struct trap *)); static void FDECL(savegamestate, (NHFILE *)); @@ -85,7 +83,9 @@ dosave0() d_level uz_save; char whynot[BUFSZ]; NHFILE *nhfp, *onhfp; + int res = 0; + g.program_state.saving++; /* inhibit status and perm_invent updates */ /* we may get here via hangup signal, in which case we want to fix up a few of things before saving so that they won't be restored in an improper state; these will be no-ops for normal save sequence */ @@ -98,13 +98,13 @@ dosave0() u.uburied = 1, iflags.save_uburied = 0; if (!g.program_state.something_worth_saving || !g.SAVEF[0]) - return 0; - fq_save = fqname(g.SAVEF, SAVEPREFIX, 1); /* level files take 0 */ + goto done; + fq_save = fqname(g.SAVEF, SAVEPREFIX, 1); /* level files take 0 */ +#ifndef NO_SIGNAL #if defined(UNIX) || defined(VMS) sethanguphandler((void FDECL((*), (int) )) SIG_IGN); #endif -#ifndef NO_SIGNAL (void) signal(SIGINT, SIG_IGN); #endif @@ -117,7 +117,7 @@ dosave0() There("seems to be an old save file."); if (yn("Overwrite the old file?") == 'n') { nh_compress(fq_save); - return 0; + goto done; } } } @@ -128,7 +128,7 @@ dosave0() if (!nhfp) { HUP pline("Cannot open save file."); (void) delete_savefile(); /* ab@unido */ - return 0; + goto done; } vision_recalc(2); /* shut down vision to prevent problems @@ -157,6 +157,15 @@ dosave0() store_plname_in_file(nhfp); g.ustuck_id = (u.ustuck ? u.ustuck->m_id : 0); g.usteed_id = (u.usteed ? u.usteed->m_id : 0); + /* savelev() might save uball and uchain, releasing their memory if + FREEING, so we need to check their status now; if hero is swallowed, + uball and uchain will persist beyond saving map floor and inventory + so these copies of their pointers will be valid and savegamestate() + will know to save them separately (from floor and invent); when not + swallowed, uchain will be stale by then, and uball will be too if + ball is on the floor rather than carried */ + g.looseball = BALL_IN_MON ? uball : 0; + g.loosechain = CHAIN_IN_MON ? uchain : 0; savelev(nhfp, ledger_no(&u.uz)); savegamestate(nhfp); @@ -196,13 +205,13 @@ dosave0() (void) delete_savefile(); HUP Strcpy(g.killer.name, whynot); HUP done(TRICKED); - return 0; + goto done; } minit(); /* ZEROCOMP */ getlev(onhfp, g.hackpid, ltmp); close_nhfile(onhfp); if (nhfp->structlevel) - bwrite(nhfp->fd, (genericptr_t) <mp, sizeof ltmp); /* level number*/ + bwrite(nhfp->fd, (genericptr_t) <mp, sizeof ltmp); /* lvl no. */ savelev(nhfp, ltmp); /* actual level*/ delete_levelfile(ltmp); } @@ -216,7 +225,11 @@ dosave0() nh_compress(fq_save); /* this should probably come sooner... */ g.program_state.something_worth_saving = 0; - return 1; + res = 1; + + done: + g.program_state.saving--; + return res; } static void @@ -224,8 +237,9 @@ savegamestate(nhfp) NHFILE *nhfp; { unsigned long uid; - struct obj * bc_objs = (struct obj *)0; + struct obj *bc_objs = (struct obj *)0; + g.program_state.saving++; /* caller should/did already set this... */ uid = (unsigned long) getuid(); if (nhfp->structlevel) { bwrite(nhfp->fd, (genericptr_t) &uid, sizeof uid); @@ -250,27 +264,31 @@ NHFILE *nhfp; save_timers(nhfp, RANGE_GLOBAL); save_light_sources(nhfp, RANGE_GLOBAL); - saveobjchn(nhfp, g.invent); + /* when FREEING, deletes objects in invent and sets invent to Null; + pointers into invent (uwep, uarmg, uamul, &c) are set to Null too */ + saveobjchn(nhfp, &g.invent); - /* save ball and chain if they are currently dangling free (i.e. not on - floor or in inventory) */ - if (CHAIN_IN_MON) { - uchain->nobj = bc_objs; - bc_objs = uchain; + /* save ball and chain if they are currently dangling free (i.e. not + on floor or in inventory); 'looseball' and 'loosechain' have been + set up in caller because ball and chain will be gone by now if on + floor, or ball gone if carried; caveat: uball and uchain pointers + will be non-Null but stale (point to freed memory) in those cases */ + bc_objs = (struct obj *) 0; + if (g.loosechain) { + g.loosechain->nobj = bc_objs; /* uchain */ + bc_objs = g.loosechain; } - if (BALL_IN_MON) { - uball->nobj = bc_objs; - bc_objs = uball; + if (g.looseball) { + g.looseball->nobj = bc_objs; + bc_objs = g.looseball; } - saveobjchn(nhfp, bc_objs); + saveobjchn(nhfp, &bc_objs); /* frees objs in list, sets bc_objs to Null */ + g.looseball = g.loosechain = (struct obj *) 0; - saveobjchn(nhfp, g.migrating_objs); + saveobjchn(nhfp, &g.migrating_objs); /* frees objs and sets to Null */ savemonchn(nhfp, g.migrating_mons); - if (release_data(nhfp)) { - g.invent = 0; - g.migrating_objs = 0; - g.migrating_mons = 0; - } + if (release_data(nhfp)) + g.migrating_mons = (struct monst *) 0; if (nhfp->structlevel) bwrite(nhfp->fd, (genericptr_t) g.mvitals, sizeof g.mvitals); save_dungeon(nhfp, (boolean) !!perform_bwrite(nhfp), @@ -303,8 +321,11 @@ NHFILE *nhfp; save_msghistory(nhfp); if (nhfp->structlevel) bflush(nhfp->fd); + g.program_state.saving--; + return; } +/* potentially called from goto_level(do.c) as well as savestateinlock() */ boolean tricked_fileremoved(nhfp, whynot) NHFILE *nhfp; @@ -328,6 +349,7 @@ savestateinlock() char whynot[BUFSZ]; NHFILE *nhfp; + g.program_state.saving++; /* inhibit status and perm_invent updates */ /* When checkpointing is on, the full state needs to be written * on each checkpoint. When checkpointing is off, only the pid * needs to be in the level.0 file, so it does not need to be @@ -347,24 +369,31 @@ savestateinlock() * readable by an external utility */ nhfp = open_levelfile(0, whynot); - if (tricked_fileremoved(nhfp, whynot)) + if (tricked_fileremoved(nhfp, whynot)) { + g.program_state.saving--; return; + } if (nhfp->structlevel) (void) read(nhfp->fd, (genericptr_t) &hpid, sizeof hpid); if (g.hackpid != hpid) { Sprintf(whynot, "Level #0 pid (%d) doesn't match ours (%d)!", hpid, g.hackpid); - pline1(whynot); - Strcpy(g.killer.name, whynot); - done(TRICKED); + goto giveup; } close_nhfile(nhfp); nhfp = create_levelfile(0, whynot); if (!nhfp) { pline1(whynot); + giveup: Strcpy(g.killer.name, whynot); + /* done(TRICKED) will return when running in wizard mode; + clear the display-update-suppression flag before rather + than after so that screen updating behaves normally; + game data shouldn't be inconsistent yet, unlike it would + become midway through saving */ + g.program_state.saving--; done(TRICKED); return; } @@ -383,11 +412,15 @@ savestateinlock() g.ustuck_id = (u.ustuck ? u.ustuck->m_id : 0); g.usteed_id = (u.usteed ? u.usteed->m_id : 0); + g.looseball = BALL_IN_MON ? uball : 0; + g.loosechain = CHAIN_IN_MON ? uchain : 0; savegamestate(nhfp); } close_nhfile(nhfp); } + g.program_state.saving--; g.havestate = flags.ins_chkpt; + return; } #endif @@ -400,6 +433,7 @@ xchar lev; short tlev; #endif + g.program_state.saving++; /* even if current mode is FREEING */ /* * Level file contents: * version info (handled by caller); @@ -453,15 +487,12 @@ xchar lev; if (nhfp->mode == FREEING) /* see above */ goto skip_lots; - savelevl(nhfp, (boolean) ((sfsaveinfo.sfi1 & SFI1_RLECOMP) == SFI1_RLECOMP)); + savelevl(nhfp, + (boolean) ((sfsaveinfo.sfi1 & SFI1_RLECOMP) == SFI1_RLECOMP)); if (nhfp->structlevel) { bwrite(nhfp->fd, (genericptr_t) g.lastseentyp, sizeof g.lastseentyp); bwrite(nhfp->fd, (genericptr_t) &g.monstermoves, sizeof g.monstermoves); - bwrite(nhfp->fd, (genericptr_t) &g.upstair, sizeof (stairway)); - bwrite(nhfp->fd, (genericptr_t) &g.dnstair, sizeof (stairway)); - bwrite(nhfp->fd, (genericptr_t) &g.upladder, sizeof (stairway)); - bwrite(nhfp->fd, (genericptr_t) &g.dnladder, sizeof (stairway)); - bwrite(nhfp->fd, (genericptr_t) &g.sstairs, sizeof (stairway)); + save_stairs(nhfp); bwrite(nhfp->fd, (genericptr_t) &g.updest, sizeof (dest_area)); bwrite(nhfp->fd, (genericptr_t) &g.dndest, sizeof (dest_area)); bwrite(nhfp->fd, (genericptr_t) &g.level.flags, sizeof g.level.flags); @@ -478,9 +509,9 @@ xchar lev; savemonchn(nhfp, fmon); save_worm(nhfp); /* save worm information */ savetrapchn(nhfp, g.ftrap); - saveobjchn(nhfp, fobj); - saveobjchn(nhfp, g.level.buriedobjlist); - saveobjchn(nhfp, g.billobjs); + saveobjchn(nhfp, &fobj); + saveobjchn(nhfp, &g.level.buriedobjlist); + saveobjchn(nhfp, &g.billobjs); if (release_data(nhfp)) { int x,y; /* TODO: maybe use clear_level_structures() */ @@ -496,6 +527,7 @@ xchar lev; fobj = 0; g.level.buriedobjlist = 0; g.billobjs = 0; + stairway_free_all(); /* level.bonesinfo = 0; -- handled by savecemetery() */ } save_engravings(nhfp); @@ -505,6 +537,8 @@ xchar lev; if (nhfp->structlevel) bflush(nhfp->fd); } + g.program_state.saving--; + return; } static void @@ -566,6 +600,7 @@ boolean rlecomp; if (nhfp->structlevel) { bwrite(nhfp->fd, (genericptr_t) levl, sizeof levl); } + return; } /* used when saving a level and also when saving dungeon overview data */ @@ -624,6 +659,40 @@ NHFILE *nhfp; g.level.damagelist = 0; } +static void +save_stairs(nhfp) +NHFILE *nhfp; +{ + stairway *stway = g.stairs; + int buflen = (int) sizeof *stway; + + while (stway) { + if (perform_bwrite(nhfp)) { + if (stway->tolev.dnum == u.uz.dnum) { + /* 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); + } + if (stway->tolev.dnum == u.uz.dnum) { + /* reset staiway dlevel back to absolute */ + stway->tolev.dlevel += u.uz.dlevel; + } + } + stway = stway->next; + } + if (perform_bwrite(nhfp)) { + buflen = -1; + if (nhfp->structlevel) { + bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof buflen); + } + } +} + +/* save one object; + caveat: this is only for perform_bwrite(); caller handles release_data() */ static void saveobj(nhfp, otmp) NHFILE *nhfp; @@ -662,18 +731,22 @@ struct obj *otmp; } /* 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 oxtra components do */ + gets saved/restored whenever any other oextra components do */ if (nhfp->structlevel) bwrite(nhfp->fd, (genericptr_t) &OMID(otmp), sizeof OMID(otmp)); } } +/* save an object chain; sets head of list to Null when done; + handles release_data() for each object in the list */ static void -saveobjchn(nhfp, otmp) +saveobjchn(nhfp, obj_p) NHFILE *nhfp; -register struct obj *otmp; +struct obj **obj_p; { - register struct obj *otmp2; + register struct obj *otmp = *obj_p; + struct obj *otmp2; + boolean is_invent = (otmp && otmp == g.invent); int minusone = -1; while (otmp) { @@ -682,7 +755,7 @@ register struct obj *otmp; saveobj(nhfp, otmp); } if (Has_contents(otmp)) - saveobjchn(nhfp, otmp->cobj); + saveobjchn(nhfp, &otmp->cobj); if (release_data(nhfp)) { /* * If these are on the floor, the discarding could be @@ -707,6 +780,10 @@ register struct obj *otmp; otmp->cobj = NULL; /* contents handled above */ otmp->timed = 0; /* not timed any more */ otmp->lamplit = 0; /* caller handled lights */ + otmp->leashmon = 0; /* mon->mleashed could still be set; + * unfortunately, we can't clear that + * until after the monster is saved */ + otmp->owornmask = 0L; /* no longer care */ dealloc_obj(otmp); } otmp = otmp2; @@ -715,6 +792,11 @@ register struct obj *otmp; if (nhfp->structlevel) bwrite(nhfp->fd, (genericptr_t) &minusone, sizeof (int)); } + if (release_data(nhfp)) { + if (is_invent) + allunworn(); /* clear uwep, uarm, uball, &c pointers */ + *obj_p = (struct obj *) 0; + } } static void @@ -732,12 +814,12 @@ struct monst *mtmp; bwrite(nhfp->fd, (genericptr_t) mtmp, buflen); } if (mtmp->mextra) { - buflen = MNAME(mtmp) ? (int) strlen(MNAME(mtmp)) + 1 : 0; + buflen = MGIVENNAME(mtmp) ? (int) strlen(MGIVENNAME(mtmp)) + 1 : 0; if (nhfp->structlevel) bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof buflen); if (buflen > 0) { if (nhfp->structlevel) - bwrite(nhfp->fd, (genericptr_t) MNAME(mtmp), buflen); + bwrite(nhfp->fd, (genericptr_t) MGIVENNAME(mtmp), buflen); } buflen = EGD(mtmp) ? (int) sizeof (struct egd) : 0; if (nhfp->structlevel) @@ -799,7 +881,7 @@ register struct monst *mtmp; savemon(nhfp, mtmp); } if (mtmp->minvent) - saveobjchn(nhfp, mtmp->minvent); + saveobjchn(nhfp, &mtmp->minvent); if (release_data(nhfp)) { if (mtmp == g.context.polearm.hitmon) { g.context.polearm.m_id = mtmp->m_id; @@ -1007,7 +1089,7 @@ freedynamicdata() tmp_at(DISP_FREEMEM, 0); /* temporary display effects */ #ifdef FREE_ALL_MEMORY #define free_current_level() savelev(&tnhfp, -1) -#define freeobjchn(X) (saveobjchn(&tnhfp, X), X = 0) +#define freeobjchn(X) (saveobjchn(&tnhfp, &X), X = 0) #define freemonchn(X) (savemonchn(&tnhfp, X), X = 0) #define freefruitchn() savefruitchn(&tnhfp) #define freenames() savenames(&tnhfp) diff --git a/src/sfstruct.c b/src/sfstruct.c index ae9851987..d33841cea 100644 --- a/src/sfstruct.c +++ b/src/sfstruct.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 sfstruct.c $NHDT-Date: 1593953360 2020/07/05 12:49:20 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.3 $ */ +/* 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. */ /* NetHack may be freely redistributed. See license for details. */ @@ -75,8 +75,8 @@ static FILE *bw_FILE[MAXFD] = {0,0,0,0,0}; * Some notes: * * Once buffered IO (stdio) has been enabled on the file - * associated with a descriptor via fdopen(): - * + * associated with a descriptor via fdopen(): + * * 1. If you use bufoff and bufon to try and toggle the * use of write vs fwrite; the code just tracks which * routine is to be called through the tracking @@ -86,7 +86,7 @@ static FILE *bw_FILE[MAXFD] = {0,0,0,0,0}; * if it is a free slot. * bw_buffered[] - indicator that buffered IO routines * are available for use. - * bw_FILE[] - the non-zero FILE * for use in calling + * bw_FILE[] - the non-zero FILE * for use in calling * fwrite() when bw_buffered[] is also * non-zero. * @@ -265,7 +265,7 @@ register unsigned int len; return; } else { pline("Read %d instead of %u bytes.", rlen, len); - if (g.restoring) { + if (g.program_state.restoring) { (void) nhclose(fd); (void) delete_savefile(); error("Error restoring old game."); @@ -291,7 +291,7 @@ int fd; const char *fncname; int linenum; { - TRACE(fd); + TRACE(fd); bufon(fd); } @@ -301,7 +301,7 @@ int fd; const char *fncname; int linenum; { - TRACE(fd); + TRACE(fd); bufoff(fd); } @@ -311,7 +311,7 @@ int fd; const char *fncname; int linenum; { - TRACE(fd); + TRACE(fd); bflush(fd); } @@ -323,7 +323,7 @@ register unsigned num; const char *fncname; int linenum; { - TRACE(fd); + TRACE(fd); bwrite(fd, loc, num); } @@ -333,7 +333,7 @@ int fd; const char *fncname; int linenum; { - TRACE(fd); + TRACE(fd); bclose(fd); } @@ -354,7 +354,7 @@ register unsigned int len; const char *fncname; int linenum; { - TRACE(fd); + TRACE(fd); mread(fd, buf, len); } #endif diff --git a/src/shk.c b/src/shk.c index bd91495d4..e12937de2 100644 --- a/src/shk.c +++ b/src/shk.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 shk.c $NHDT-Date: 1571436007 2019/10/18 22:00:07 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.171 $ */ +/* NetHack 3.7 shk.c $NHDT-Date: 1607754748 2020/12/12 06:32:28 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.193 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -362,6 +362,13 @@ register boolean nearshop; { coord mm; + stairway *stway = g.stairs; + + while (stway) { + if (!stway->isladder && !stway->up && stway->tolev.dnum == u.uz.dnum) + break; + stway = stway->next; + } if (nearshop) { /* Create swarm around you, if you merely "stepped out" */ @@ -375,8 +382,8 @@ register boolean nearshop; if (flags.verbose) pline_The("Keystone Kops are after you!"); /* Create swarm near down staircase (hinders return to level) */ - mm.x = xdnstair; - mm.y = ydnstair; + mm.x = stway->sx; + mm.y = stway->sy; makekops(&mm); /* Create swarm near shopkeeper (hinders return to shop) */ mm.x = shkp->mx; @@ -832,8 +839,8 @@ char rmno; (int) rmno, (int) g.rooms[rmno - ROOMOFFSET].rtype, shkp->mnum, - /* [real shopkeeper name is kept in ESHK, not MNAME] */ - has_mname(shkp) ? MNAME(shkp) : "anonymous"); + /* [real shopkeeper name is kept in ESHK, not MGIVENNAME] */ + has_mgivenname(shkp) ? MGIVENNAME(shkp) : "anonymous"); /* not sure if this is appropriate, because it does nothing to correct the underlying g.rooms[].resident issue but... */ return (struct monst *) 0; @@ -1238,7 +1245,7 @@ dopay() long ltmp; long umoney; int pass, tmp, sk = 0, seensk = 0; - boolean paid = FALSE, stashed_gold = (hidden_gold() > 0L); + boolean paid = FALSE, stashed_gold = (hidden_gold(TRUE) > 0L); g.multi = 0; @@ -1588,7 +1595,8 @@ boolean itemize; long ltmp, quan, save_quan; long umoney = money_cnt(g.invent); int buy; - boolean stashed_gold = (hidden_gold() > 0L), consumed = (which == 0); + boolean stashed_gold = (hidden_gold(TRUE) > 0L), + consumed = (which == 0); if (!obj->unpaid && !bp->useup) { impossible("Paid object on bill??"); @@ -2219,8 +2227,9 @@ boolean unpaid_only; /* count amount of gold inside container 'obj' and any nested containers */ long -contained_gold(obj) +contained_gold(obj, even_if_unknown) struct obj *obj; +boolean even_if_unknown; /* True: all gold; False: limit to known contents */ { register struct obj *otmp; register long value = 0L; @@ -2229,8 +2238,8 @@ struct obj *obj; for (otmp = obj->cobj; otmp; otmp = otmp->nobj) if (otmp->oclass == COIN_CLASS) value += otmp->quan; - else if (Has_contents(otmp)) - value += contained_gold(otmp); + else if (Has_contents(otmp) && (otmp->cknown || even_if_unknown)) + value += contained_gold(otmp, even_if_unknown); return value; } @@ -2604,7 +2613,7 @@ boolean reset_nocharge; /* outer container might be marked no_charge but still have contents which should be charged for; clear no_charge when picking things up */ if (obj->no_charge) { - if (!Has_contents(obj) || (contained_gold(obj) == 0L + if (!Has_contents(obj) || (contained_gold(obj, TRUE) == 0L && contained_cost(obj, shkp, 0L, FALSE, !reset_nocharge) == 0L)) shkp = 0; /* not billable */ @@ -2654,7 +2663,7 @@ boolean ininv, dummy, silent; if (container) { cltmp = contained_cost(obj, shkp, cltmp, FALSE, FALSE); - gltmp = contained_gold(obj); + gltmp = contained_gold(obj, TRUE); if (ltmp) add_one_tobill(obj, dummy, shkp); @@ -2929,7 +2938,7 @@ boolean peaceful, silent; value += stolen_container(obj, shkp, 0L, ininv); if (!ininv) - gvalue += contained_gold(obj); + gvalue += contained_gold(obj, TRUE); } } @@ -2994,6 +3003,44 @@ boolean peaceful, silent; return value; } +/* opposite of costly_gold(); hero has dropped gold in a shop; + called from sellobj(); ought to be called from subfrombill() too */ +void +donate_gold(gltmp, shkp, selling) +long gltmp; +struct monst *shkp; +boolean selling; /* True: dropped in shop; False: kicked and landed in shop */ +{ + struct eshk *eshkp = ESHK(shkp); + + if (eshkp->debit >= gltmp) { + if (eshkp->loan) { /* you carry shop's gold */ + if (eshkp->loan > gltmp) + eshkp->loan -= gltmp; + else + eshkp->loan = 0L; + } + eshkp->debit -= gltmp; + Your("debt is %spaid off.", eshkp->debit ? "partially " : ""); + } else { + long delta = gltmp - eshkp->debit; + + eshkp->credit += delta; + if (eshkp->debit) { + eshkp->debit = 0L; + eshkp->loan = 0L; + Your("debt is paid off."); + } + if (eshkp->credit == delta) + You("have %sestablished %ld %s credit.", + !selling ? "re-" : "", delta, currency(delta)); + else + pline("%ld %s added%s to your credit; total is now %ld %s.", + delta, currency(delta), !selling ? " back" : "", + eshkp->credit, currency(eshkp->credit)); + } +} + void sellobj_state(deliberate) int deliberate; @@ -3036,7 +3083,7 @@ xchar x, y; /* find the price of content before subfrombill */ cltmp = contained_cost(obj, shkp, cltmp, TRUE, FALSE); /* find the value of contained gold */ - gltmp += contained_gold(obj); + gltmp += contained_gold(obj, TRUE); cgold = (gltmp > 0L); } @@ -3079,7 +3126,7 @@ xchar x, y; return; } - if (eshkp->robbed) { /* shkp is not angry? */ + if (eshkp->robbed) { /* bones; shop robbed by previous customer */ if (isgold) offer = obj->quan; else if (cgold) @@ -3097,32 +3144,7 @@ xchar x, y; if (!cgold) gltmp = obj->quan; - if (eshkp->debit >= gltmp) { - if (eshkp->loan) { /* you carry shop's gold */ - if (eshkp->loan >= gltmp) - eshkp->loan -= gltmp; - else - eshkp->loan = 0L; - } - eshkp->debit -= gltmp; - Your("debt is %spaid off.", eshkp->debit ? "partially " : ""); - } else { - long delta = gltmp - eshkp->debit; - - eshkp->credit += delta; - if (eshkp->debit) { - eshkp->debit = 0L; - eshkp->loan = 0L; - Your("debt is paid off."); - } - if (eshkp->credit == delta) - You("have established %ld %s credit.", delta, - currency(delta)); - else - pline("%ld %s added to your credit; total is now %ld %s.", - delta, currency(delta), eshkp->credit, - currency(eshkp->credit)); - } + donate_gold(gltmp, shkp, TRUE); if (!offer || g.sell_how == SELL_DONTSELL) { if (!isgold) { @@ -3170,13 +3192,14 @@ xchar x, y; c = 'n'; if (c == 'y') { - shk_names_obj( - shkp, obj, - (g.sell_how != SELL_NORMAL) - ? "traded %s for %ld zorkmid%s in %scredit." - : "relinquish %s and acquire %ld zorkmid%s in %scredit.", - tmpcr, (eshkp->credit > 0L) ? "additional " : ""); + shk_names_obj(shkp, obj, + ((g.sell_how != SELL_NORMAL) + ? "traded %s for %ld zorkmid%s in %scredit." + : "relinquish %s and acquire %ld zorkmid%s in %scredit."), + tmpcr, (eshkp->credit > 0L) ? "additional " : ""); eshkp->credit += tmpcr; + if (container) + dropped_container(obj, shkp, TRUE); subfrombill(obj, shkp); } else { if (c == 'q') diff --git a/src/shknam.c b/src/shknam.c index 7460eb8ba..b8a4386c4 100644 --- a/src/shknam.c +++ b/src/shknam.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 shknam.c $NHDT-Date: 1587024023 2020/04/16 08:00:23 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.54 $ */ +/* NetHack 3.7 shknam.c $NHDT-Date: 1596498209 2020/08/03 23:43:29 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.57 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2011. */ /* NetHack may be freely redistributed. See license for details. */ @@ -495,7 +495,7 @@ const char *const *nlp; int i, trycnt, names_avail; const char *shname = 0; struct monst *mtmp; - int name_wanted; + int name_wanted = shk->m_id; s_level *sptr; if (nlp == shklight && In_mines(&u.uz) @@ -510,7 +510,7 @@ const char *const *nlp; use ledger_no rather than depth to keep minetown distinct. */ int nseed = (int) ((long) ubirthday / 257L); - name_wanted = ledger_no(&u.uz) + (nseed % 13) - (nseed % 5); + name_wanted += ledger_no(&u.uz) + (nseed % 13) - (nseed % 5); if (name_wanted < 0) name_wanted += (13 + 5); shk->female = name_wanted & 1; @@ -518,6 +518,8 @@ const char *const *nlp; for (names_avail = 0; nlp[names_avail]; names_avail++) continue; + name_wanted = name_wanted % names_avail; + for (trycnt = 0; trycnt < 50; trycnt++) { if (nlp == shktools) { shname = shktools[rn2(names_avail)]; @@ -545,6 +547,7 @@ const char *const *nlp; continue; if (strcmp(ESHK(mtmp)->shknam, shname)) continue; + name_wanted = names_avail; /* try a random name */ break; } if (!mtmp) @@ -774,6 +777,12 @@ register struct mkroom *sroom; * monsters will sit on top of objects and not the other way around. */ + /* Hack for Orcus's level: it's a ghost town, get rid of shopkeepers */ + if (on_level(&u.uz, &orcus_level)) { + struct monst* mtmp = shop_keeper(rmno); + mongone(mtmp); + } + g.level.flags.has_shop = TRUE; } diff --git a/src/sit.c b/src/sit.c index 8d26e2db8..ee6e9679b 100644 --- a/src/sit.c +++ b/src/sit.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 sit.c $NHDT-Date: 1559670609 2019/06/04 17:50:09 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.61 $ */ +/* NetHack 3.7 sit.c $NHDT-Date: 1596498210 2020/08/03 23:43:30 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.70 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/src/sounds.c b/src/sounds.c index 2bdb8bbf1..6a4409b21 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 sounds.c $NHDT-Date: 1593651682 2020/07/02 01:01:22 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.98 $ */ +/* NetHack 3.7 sounds.c $NHDT-Date: 1600933442 2020/09/24 07:44:02 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.103 $ */ /* Copyright (c) 1989 Janet Walz, Mike Threepoint */ /* NetHack may be freely redistributed. See license for details. */ @@ -184,8 +184,8 @@ dosounds() continue; if (is_mercenary(mtmp->data) #if 0 /* don't bother excluding these */ - && !strstri(mtmp->data->mname, "watch") - && !strstri(mtmp->data->mname, "guard") + && !strstri(mtmp->data->pmnames[NEUTRAL], "watch") + && !strstri(mtmp->data->pmnames[NEUTRAL], "guard") #endif && mon_in_room(mtmp, BARRACKS) /* sleeping implies not-yet-disturbed (usually) */ @@ -369,6 +369,7 @@ register struct monst *mtmp; growl_verb = growl_sound(mtmp); if (growl_verb) { pline("%s %s!", Monnam(mtmp), vtense((char *) 0, growl_verb)); + iflags.last_msg = PLNMSG_GROWL; if (g.context.run) nomul(0); wake_nearto(mtmp->mx, mtmp->my, mtmp->data->mlevel * 18); @@ -479,6 +480,74 @@ register struct monst *mtmp; } } +/* hero has attacked a peaceful monster within 'mon's view */ +const char * +maybe_gasp(mon) +struct monst *mon; +{ + static const char *const Exclam[] = { + "Gasp!", "Uh-oh.", "Oh my!", "What?", "Why?", + }; + struct permonst *mptr = mon->data; + int msound = mptr->msound; + boolean dogasp = FALSE; + + /* other roles' guardians and cross-aligned priests don't gasp */ + if ((msound == MS_GUARDIAN && mptr != &mons[g.urole.guardnum]) + || (msound == MS_PRIEST && !p_coaligned(mon))) + msound = MS_SILENT; + /* co-aligned angels do gasp */ + else if (msound == MS_CUSS && has_emin(mon) + && (p_coaligned(mon) ? !EMIN(mon)->renegade : EMIN(mon)->renegade)) + msound = MS_HUMANOID; + + /* + * Only called for humanoids so animal noise handling is ignored. + */ + switch (msound) { + case MS_HUMANOID: + case MS_ARREST: /* Kops */ + case MS_SOLDIER: /* solider, watchman */ + case MS_GUARD: /* vault guard */ + case MS_NURSE: + case MS_SEDUCE: /* nymph, succubus/incubus */ + case MS_LEADER: /* quest leader */ + case MS_GUARDIAN: /* leader's guards */ + case MS_SELL: /* shopkeeper */ + case MS_ORACLE: + case MS_PRIEST: /* temple priest, roaming aligned priest (not mplayer) */ + case MS_BOAST: /* giants */ + case MS_IMITATE: /* doppelganger, leocrotta, Aleax */ + dogasp = TRUE; + break; + /* issue comprehensible word(s) if hero is similar type of creature */ + case MS_ORC: /* used to be synonym for MS_GRUNT */ + case MS_GRUNT: /* ogres, trolls, gargoyles, one or two others */ + case MS_LAUGH: /* leprechaun, gremlin */ + case MS_ROAR: /* dragon, xorn, owlbear */ + /* capable of speech but only do so if hero is similar type */ + case MS_DJINNI: + case MS_VAMPIRE: /* vampire in its own form */ + case MS_WERE: /* lycanthrope in human form */ + case MS_SPELL: /* titan, barrow wight, Nazgul, nalfeshnee */ + dogasp = (mptr->mlet == g.youmonst.data->mlet); + break; + /* capable of speech but don't care if you attack peacefuls */ + case MS_BRIBE: + case MS_CUSS: + case MS_RIDER: + case MS_NEMESIS: + /* can't speak */ + case MS_SILENT: + default: + break; + } + if (dogasp) { + return Exclam[rn2(SIZE(Exclam))]; /* [mon->m_id % SIZE(Exclam)]; */ + } + return (const char *) 0; +} + /* return True if mon is a gecko or seems to look like one (hallucination) */ static boolean mon_is_gecko(mon) @@ -565,7 +634,7 @@ register struct monst *mtmp; * night */ boolean isnight = night(); boolean kindred = (Upolyd && (u.umonnum == PM_VAMPIRE - || u.umonnum == PM_VAMPIRE_LORD)); + || u.umonnum == PM_VAMPIRE_LEADER)); boolean nightchild = (Upolyd && (u.umonnum == PM_WOLF || u.umonnum == PM_WINTER_WOLF || u.umonnum == PM_WINTER_WOLF_CUB)); @@ -627,7 +696,8 @@ register struct monst *mtmp; verbl_msg = verbuf; } else if (vampindex == 1) { Sprintf(verbuf, vampmsg[vampindex], - Upolyd ? an(mons[u.umonnum].mname) + Upolyd ? an(pmname(&mons[u.umonnum], + flags.female ? FEMALE : MALE)) : an(racenoun)); verbl_msg = verbuf; } else @@ -1017,7 +1087,8 @@ dochat() struct obj *otmp; if (is_silent(g.youmonst.data)) { - pline("As %s, you cannot speak.", an(g.youmonst.data->mname)); + pline("As %s, you cannot speak.", + an(pmname(g.youmonst.data, flags.female ? FEMALE : MALE))); return 0; } if (Strangled) { @@ -1317,7 +1388,6 @@ const char *mapping; char filename[256]; char filespec[256]; int volume, idx = -1; - boolean toolong = FALSE; if (sscanf(mapping, "MESG \"%255[^\"]\"%*[\t ]\"%255[^\"]\" %d %d", text, filename, &volume, &idx) == 4 diff --git a/src/sp_lev.c b/src/sp_lev.c index b85c4ab75..859945bbc 100755 --- a/src/sp_lev.c +++ b/src/sp_lev.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 sp_lev.c $NHDT-Date: 1585569501 2020/03/30 11:58:21 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.185 $ */ +/* NetHack 3.7 sp_lev.c $NHDT-Date: 1605779812 2020/11/19 09:56:52 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.216 $ */ /* Copyright (c) 1989 by Jean-Christophe Collet */ /* NetHack may be freely redistributed. See license for details. */ @@ -10,7 +10,7 @@ */ #define IN_SP_LEV_C - + #include "hack.h" #include "sp_lev.h" @@ -40,14 +40,13 @@ static void NDECL(remove_boundary_syms); static void FDECL(set_door_orientation, (int, int)); static void FDECL(maybe_add_door, (int, int, struct mkroom *)); static void NDECL(link_doors_rooms); -static void NDECL(fill_rooms); static int NDECL(rnddoor); static int NDECL(rndtrap); -static void FDECL(get_location, (schar *, schar *, int, struct mkroom *)); -static boolean FDECL(is_ok_location, (SCHAR_P, SCHAR_P, int)); +static void FDECL(get_location, (xchar *, xchar *, int, struct mkroom *)); +static boolean FDECL(is_ok_location, (XCHAR_P, XCHAR_P, int)); static unpacked_coord FDECL(get_unpacked_coord, (long, int)); -static void FDECL(get_room_loc, (schar *, schar *, struct mkroom *)); -static void FDECL(get_free_room_loc, (schar *, schar *, +static void FDECL(get_room_loc, (xchar *, xchar *, struct mkroom *)); +static void FDECL(get_free_room_loc, (xchar *, xchar *, struct mkroom *, packed_coord)); static boolean FDECL(create_subroom, (struct mkroom *, XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P)); @@ -61,11 +60,9 @@ static void FDECL(create_object, (object *, struct mkroom *)); static void FDECL(create_altar, (altar *, struct mkroom *)); static boolean FDECL(search_door, (struct mkroom *, xchar *, xchar *, XCHAR_P, int)); -static void NDECL(fix_stair_rooms); static void FDECL(create_corridor, (corridor *)); static struct mkroom *FDECL(build_room, (room *, struct mkroom *)); static void FDECL(light_region, (region *)); -static void FDECL(wallify_map, (int, int, int, int)); static void FDECL(maze1xy, (coord *, int)); static void NDECL(fill_empty_maze); static void FDECL(splev_initlev, (lev_init *)); @@ -198,6 +195,9 @@ static struct monst *invent_carrying_monster = (struct monst *) 0; * end of no 'g.' */ +#define TYP_CANNOT_MATCH(typ) \ + ((typ) == MAX_TYPE || (typ) == INVALID_TYPE) + /* Does typ match with levl[][].typ, considering special types MATCH_WALL and MAX_TYPE (aka transparency)? */ static boolean @@ -278,7 +278,7 @@ struct mapfragment *mf; else if (!mapfrag_canmatch(mf)) { mapfrag_free(&mf); return "mapfragment needs to have odd height and width"; - } else if (mapfrag_get(mf, (mf->wid/2), (mf->hei/2)) >= MAX_TYPE) { + } else if (TYP_CANNOT_MATCH(mapfrag_get(mf, (mf->wid/2), (mf->hei/2)))) { mapfrag_free(&mf); return "mapfragment center must be valid terrain"; } @@ -405,7 +405,7 @@ struct rm *lev; } } -/* for #wizlevelflip; not needed when flipping during level creation; +/* for #wizfliplevel; not needed when flipping during level creation; update seen vector for whole flip area and glyph for known walls */ static void flip_visuals(flp, minx, miny, maxx, maxy) @@ -482,7 +482,7 @@ flip_encoded_direction_bits(int flp, int val) } while (0) /* transpose top with bottom or left with right or both; sometimes called - for new special levels, or for any level via the #wizlevelflip command */ + for new special levels, or for any level via the #wizfliplevel command */ void flip_level(flp, extras) int flp; @@ -498,6 +498,7 @@ boolean extras; struct mkroom *sroom; timer_element *timer; boolean ball_active = FALSE, ball_fliparea = FALSE; + stairway *stway; /* nothing to do unless (flp & 1) or (flp & 2) or both */ if ((flp & 3) == 0) @@ -535,29 +536,11 @@ boolean extras; } /* stairs and ladders */ - if (flp & 1) { - if (xupstair) - yupstair = FlipY(yupstair); - if (xdnstair) - ydnstair = FlipY(ydnstair); - if (xupladder) - yupladder = FlipY(yupladder); - if (xdnladder) - ydnladder = FlipY(ydnladder); - if (g.sstairs.sx) - g.sstairs.sy = FlipY(g.sstairs.sy); - } - if (flp & 2) { - if (xupstair) - xupstair = FlipX(xupstair); - if (xdnstair) - xdnstair = FlipX(xdnstair); - if (xupladder) - xupladder = FlipX(xupladder); - if (xdnladder) - xdnladder = FlipX(xdnladder); - if (g.sstairs.sx) - g.sstairs.sx = FlipX(g.sstairs.sx); + for (stway = g.stairs; stway; stway = stway->next) { + if (flp & 1) + stway->sy = FlipY(stway->sy); + if (flp & 2) + stway->sx = FlipX(stway->sx); } /* traps */ @@ -824,7 +807,7 @@ boolean extras; } } - if (extras) { /* for #wizlevelflip rather than during level creation */ + if (extras) { /* for #wizfliplevel rather than during level creation */ /* flip hero location only if inside the flippable area */ if (inFlipArea(u.ux, u.uy)) { if (flp & 1) @@ -1035,30 +1018,15 @@ link_doors_rooms() } } -static void -fill_rooms() -{ - int tmpi, m; - - for (tmpi = 0; tmpi < g.nroom; tmpi++) { - if (g.rooms[tmpi].needfill) - fill_room(&g.rooms[tmpi], (g.rooms[tmpi].needfill == 2)); - for (m = 0; m < g.rooms[tmpi].nsubrooms; m++) - if (g.rooms[tmpi].sbrooms[m]->needfill) - fill_room(g.rooms[tmpi].sbrooms[m], FALSE); - } -} - /* * Choose randomly the state (nodoor, open, closed or locked) for a door */ static int rnddoor() { - int i = 1 << rn2(5); + static int state[] = { D_NODOOR, D_BROKEN, D_ISOPEN, D_CLOSED, D_LOCKED }; - i >>= 1; - return i; + return state[rn2(SIZE(state))]; } /* @@ -1105,7 +1073,7 @@ rndtrap() */ static void get_location(x, y, humidity, croom) -schar *x, *y; +xchar *x, *y; int humidity; struct mkroom *croom; { @@ -1175,7 +1143,7 @@ struct mkroom *croom; static boolean is_ok_location(x, y, humidity) -register schar x, y; +register xchar x, y; register int humidity; { register int typ; @@ -1237,7 +1205,7 @@ int defhumidity; void get_location_coord(x, y, humidity, croom, crd) -schar *x, *y; +xchar *x, *y; int humidity; struct mkroom *croom; long crd; @@ -1260,7 +1228,7 @@ long crd; static void get_room_loc(x, y, croom) -schar *x, *y; +xchar *x, *y; struct mkroom *croom; { coord c; @@ -1287,11 +1255,11 @@ struct mkroom *croom; */ static void get_free_room_loc(x, y, croom, pos) -schar *x, *y; +xchar *x, *y; struct mkroom *croom; packed_coord pos; { - schar try_x, try_y; + xchar try_x, try_y; register int trycnt = 0; get_location_coord(&try_x, &try_y, DRY, croom, pos); @@ -1771,7 +1739,7 @@ create_trap(t, croom) spltrap *t; struct mkroom *croom; { - schar x = -1, y = -1; + xchar x = -1, y = -1; coord tm; if (croom) { @@ -1855,7 +1823,7 @@ monster *m; struct mkroom *croom; { struct monst *mtmp; - schar x, y; + xchar x, y; char class; aligntyp amask; coord cc; @@ -1997,12 +1965,12 @@ struct mkroom *croom; break; case M_AP_MONSTER: { - int mndx; + int mndx, gender_name_var = NEUTRAL; if (!strcmpi(m->appear_as.str, "random")) mndx = select_newcham_form(mtmp); else - mndx = name_to_mon(m->appear_as.str); + mndx = name_to_mon(m->appear_as.str, &gender_name_var); if (mndx == NON_PM || (is_vampshifter(mtmp) && !validvamp(mtmp, &mndx, S_HUMAN))) { @@ -2030,6 +1998,8 @@ struct mkroom *croom; struct permonst *olddata = mtmp->data; mgender_from_permonst(mtmp, mdat); + if (gender_name_var != NEUTRAL) + mtmp->female = gender_name_var; set_mon_data(mtmp, mdat); if (emits_light(olddata) != emits_light(mtmp->data)) { /* used to give light, now doesn't, or vice versa, @@ -2118,7 +2088,7 @@ object *o; struct mkroom *croom; { struct obj *otmp; - schar x, y; + xchar x, y; char c; boolean named; /* has a name been supplied in level description? */ @@ -2354,7 +2324,8 @@ create_altar(a, croom) altar *a; struct mkroom *croom; { - schar sproom, x = -1, y = -1; + schar sproom; + xchar x = -1, y = -1; aligntyp amask; boolean croom_is_temple = TRUE; int oldtyp; @@ -2576,52 +2547,6 @@ schar ftyp, btyp; return TRUE; } -/* - * Disgusting hack: since special levels have their rooms filled before - * sorting the rooms, we have to re-arrange the speed values g.upstairs_room - * and g.dnstairs_room after the rooms have been sorted. On normal levels, - * stairs don't get created until _after_ sorting takes place. - */ -static void -fix_stair_rooms() -{ - int i; - struct mkroom *croom; - - if (xdnstair - && !((g.dnstairs_room->lx <= xdnstair - && xdnstair <= g.dnstairs_room->hx) - && (g.dnstairs_room->ly <= ydnstair - && ydnstair <= g.dnstairs_room->hy))) { - for (i = 0; i < g.nroom; i++) { - croom = &g.rooms[i]; - if ((croom->lx <= xdnstair && xdnstair <= croom->hx) - && (croom->ly <= ydnstair && ydnstair <= croom->hy)) { - g.dnstairs_room = croom; - break; - } - } - if (i == g.nroom) - panic("Couldn't find dnstair room in fix_stair_rooms!"); - } - if (xupstair - && !((g.upstairs_room->lx <= xupstair - && xupstair <= g.upstairs_room->hx) - && (g.upstairs_room->ly <= yupstair - && yupstair <= g.upstairs_room->hy))) { - for (i = 0; i < g.nroom; i++) { - croom = &g.rooms[i]; - if ((croom->lx <= xupstair && xupstair <= croom->hx) - && (croom->ly <= yupstair && yupstair <= croom->hy)) { - g.upstairs_room = croom; - break; - } - } - if (i == g.nroom) - panic("Couldn't find upstair room in fix_stair_rooms!"); - } -} - /* * Corridors always start from a door. But it can end anywhere... * Basically we search for door coordinates or for endpoints coordinates @@ -2634,7 +2559,6 @@ corridor *c; coord org, dest; if (c->src.room == -1) { - fix_stair_rooms(); makecorridors(); /*makecorridors(c->src.door);*/ return; } @@ -2682,14 +2606,23 @@ corridor *c; * Fill a room (shop, zoo, etc...) with appropriate stuff. */ void -fill_room(croom, prefilled) +fill_special_room(croom) struct mkroom *croom; -boolean prefilled; { - if (!croom || croom->rtype == OROOM) + int i; + + /* First recurse into subrooms. We don't want to block an ordinary room with + * a special subroom from having the subroom filled, or an unfilled outer + * room preventing a special subroom from being filled. */ + for (i = 0; i < croom->nsubrooms; ++i) { + fill_special_room(croom->sbrooms[i]); + } + + if (!croom || croom->rtype == OROOM || croom->rtype == THEMEROOM + || croom->needfill == FILL_NONE) return; - if (!prefilled) { + if (croom->needfill == FILL_NORMAL) { int x, y; /* Shop ? */ @@ -2770,7 +2703,7 @@ struct mkroom *mkr; #else topologize(aroom); /* set roomno */ #endif - aroom->needfill = r->filled; + aroom->needfill = r->needfill; aroom->needjoining = r->joined; return aroom; } @@ -2808,7 +2741,7 @@ region *tmpregion; } } -static void +void wallify_map(x1, y1, x2, y2) int x1, y1, x2, y2; { @@ -2860,7 +2793,7 @@ int humidity; if (--tryct < 0) break; /* give up */ } while (!(x % 2) || !(y % 2) || SpLev_Map[x][y] - || !is_ok_location((schar) x, (schar) y, humidity)); + || !is_ok_location((xchar) x, (xchar) y, humidity)); m->x = (xchar) x, m->y = (xchar) y; } @@ -3079,15 +3012,18 @@ lua_State *L; static int find_montype(L, s) -lua_State *L; +lua_State *L UNUSED; const char *s; { int i; for (i = LOW_PM; i < NUMMONS; i++) - if (!strcmpi(mons[i].mname, s)) + if (!strcmpi(mons[i].pmnames[NEUTRAL], s) + || (mons[i].pmnames[MALE] != 0 + && !strcmpi(mons[i].pmnames[MALE], s)) + || (mons[i].pmnames[FEMALE] != 0 + && !strcmpi(mons[i].pmnames[FEMALE], s))) return i; - nhUse(L); return NON_PM; } @@ -3498,7 +3434,11 @@ lua_State *L; pm = mkclass(def_char_to_monclass(*montype), G_NOGEN|G_IGNORE); } else { for (i = LOW_PM; i < NUMMONS; i++) - if (!strcmpi(mons[i].mname, montype)) { + if (!strcmpi(mons[i].pmnames[NEUTRAL], montype) + || (mons[i].pmnames[MALE] != 0 + && !strcmpi(mons[i].pmnames[MALE], montype)) + || (mons[i].pmnames[FEMALE] != 0 + && !strcmpi(mons[i].pmnames[FEMALE], montype))) { pm = &mons[i]; break; } @@ -3831,7 +3771,8 @@ lua_State *L; tmproom.rtype = get_table_roomtype_opt(L, "type", OROOM); tmproom.chance = get_table_int_opt(L, "chance", 100); tmproom.rlit = get_table_int_opt(L, "lit", -1); - tmproom.filled = get_table_int_opt(L, "filled", g.in_mk_themerooms ? 0 : 1); + /* theme rooms default to unfilled */ + tmproom.needfill = get_table_int_opt(L, "filled", g.in_mk_themerooms ? 0 : 1); tmproom.joined = get_table_int_opt(L, "joined", 1); if (!g.coder->failed_room[g.coder->n_subroom - 1]) { @@ -3844,7 +3785,8 @@ lua_State *L; lua_getfield(L, 1, "contents"); if (lua_type(L, -1) == LUA_TFUNCTION) { lua_remove(L, -2); - l_push_wid_hei_table(L, tmpcr->hx - tmpcr->lx, tmpcr->hy - tmpcr->ly); + l_push_wid_hei_table(L, 1 + tmpcr->hx - tmpcr->lx, + 1 + tmpcr->hy - tmpcr->ly); lua_call(L, 1, 0); } else lua_pop(L, 1); @@ -3935,12 +3877,18 @@ boolean using_ladder; if (using_ladder) { levl[x][y].typ = LADDER; if (up) { - xupladder = x; - yupladder = y; + d_level dest; + + dest.dnum = u.uz.dnum; + dest.dlevel = u.uz.dlevel - 1; + stairway_add(x, y, TRUE, TRUE, &dest); levl[x][y].ladder = LA_UP; } else { - xdnladder = x; - ydnladder = y; + d_level dest; + + dest.dnum = u.uz.dnum; + dest.dlevel = u.uz.dlevel + 1; + stairway_add(x, y, FALSE, TRUE, &dest); levl[x][y].ladder = LA_DOWN; } } else { @@ -3983,7 +3931,7 @@ lspo_grave(L) lua_State *L; { int argc = lua_gettop(L); - schar x, y; + xchar x, y; long scoord; int ax,ay; char *txt; @@ -4195,7 +4143,7 @@ lspo_gold(L) lua_State *L; { int argc = lua_gettop(L); - schar x, y; + xchar x, y; long amount; long gcoord; int gx, gy; @@ -4395,7 +4343,7 @@ int lit; break; case 0: case 1: - if (levl[x][y].lit == lit) + if (levl[x][y].lit == (unsigned int) lit) selection_setpoint(x, y, ret, 1); break; } @@ -4421,7 +4369,7 @@ int percent; int selection_rndcoord(ov, x, y, removeit) struct selectionvar *ov; -schar *x, *y; +xchar *x, *y; boolean removeit; { int idx = 0; @@ -4772,7 +4720,7 @@ long x, y, x2, y2, gtyp, mind, maxd, limit; /* bresenham line algo */ void selection_do_line(x1, y1, x2, y2, ov) -schar x1, y1, x2, y2; +xchar x1, y1, x2, y2; struct selectionvar *ov; { int d0, dx, dy, ai, bi, xi, yi; @@ -4826,7 +4774,8 @@ struct selectionvar *ov; void selection_do_randline(x1, y1, x2, y2, rough, rec, ov) -schar x1, y1, x2, y2, rough, rec; +xchar x1, y1, x2, y2; +schar rough, rec; struct selectionvar *ov; { int mx, my; @@ -4946,7 +4895,7 @@ lua_State *L; -1, D_ISOPEN, D_CLOSED, D_LOCKED, D_NODOOR, D_BROKEN, D_SECRET }; int msk; - schar x,y; + xchar x,y; xchar typ; int argc = lua_gettop(L); @@ -5027,7 +4976,7 @@ lua_State *L; "throne", "tree", NULL }; static const int features2i[] = { FOUNTAIN, SINK, POOL, THRONE, TREE, STONE }; - schar x,y; + xchar x,y; int typ; int argc = lua_gettop(L); boolean can_have_flags = FALSE; @@ -5089,12 +5038,15 @@ lua_State *L; return 0; } -/* terrain({ x=NN, y=NN, typ=MAPCHAR, lit=BOOL }); */ -/* terrain({ coord={X, Y}, typ=MAPCHAR, lit=BOOL }); */ -/* terrain({ selection=SELECTION, typ=MAPCHAR, lit=BOOL }); */ -/* terrain( SELECTION, MAPCHAR [, BOOL ] ); */ -/* terrain({x,y}, MAPCHAR); */ -/* terrain(x,y, MAPCHAR); */ +/* + * [lit_state: 1 On, 0 Off, -1 random, -2 leave as-is] + * terrain({ x=NN, y=NN, typ=MAPCHAR, lit=lit_state }); + * terrain({ coord={X, Y}, typ=MAPCHAR, lit=lit_state }); + * terrain({ selection=SELECTION, typ=MAPCHAR, lit=lit_state }); + * terrain( SELECTION, MAPCHAR [, lit_state ] ); + * terrain({x,y}, MAPCHAR); + * terrain(x,y, MAPCHAR); + */ int lspo_terrain(L) lua_State *L; @@ -5105,7 +5057,7 @@ lua_State *L; int argc = lua_gettop(L); create_des_coder(); - tmpterrain.tlit = 0; + tmpterrain.tlit = SET_LIT_NOCHANGE; tmpterrain.ter = INVALID_TYPE; if (argc == 1) { @@ -5120,7 +5072,7 @@ lua_State *L; lua_pop(L, 1); } tmpterrain.ter = get_table_mapchr(L, "typ"); - tmpterrain.tlit = get_table_int_opt(L, "lit", 0); + tmpterrain.tlit = get_table_int_opt(L, "lit", SET_LIT_NOCHANGE); } else if (argc == 2 && lua_type(L, 1) == LUA_TTABLE && lua_type(L, 2) == LUA_TSTRING) { int tx, ty; @@ -5154,10 +5106,16 @@ lua_State *L; return 0; } -/* replace_terrain({ x1=NN,y1=NN, x2=NN,y2=NN, fromterrain=MAPCHAR, toterrain=MAPCHAR, lit=N, chance=NN }); */ -/* replace_terrain({ region={x1,y1, x2,y2}, fromterrain=MAPCHAR, toterrain=MAPCHAR, lit=N, chance=NN }); */ -/* replace_terrain({ selection=selection.area(2,5, 40,10), fromterrain=MAPCHAR, toterrain=MAPCHAR }); */ -/* replace_terrain({ selection=SEL, mapfragment=[[...]], toterrain=MAPCHAR }); */ +/* + * replace_terrain({ x1=NN,y1=NN, x2=NN,y2=NN, fromterrain=MAPCHAR, + * toterrain=MAPCHAR, lit=N, chance=NN }); + * replace_terrain({ region={x1,y1, x2,y2}, fromterrain=MAPCHAR, + * toterrain=MAPCHAR, lit=N, chance=NN }); + * replace_terrain({ selection=selection.area(2,5, 40,10), + * fromterrain=MAPCHAR, toterrain=MAPCHAR }); + * replace_terrain({ selection=SEL, mapfragment=[[...]], + * toterrain=MAPCHAR }); + */ int lspo_replace_terrain(L) lua_State *L; @@ -5195,7 +5153,7 @@ lua_State *L; } chance = get_table_int_opt(L, "chance", 100); - tolit = get_table_int_opt(L, "lit", -2); + tolit = get_table_int_opt(L, "lit", SET_LIT_NOCHANGE); x1 = get_table_int_opt(L, "x1", -1); y1 = get_table_int_opt(L, "y1", -1); x2 = get_table_int_opt(L, "x2", -1); @@ -5219,7 +5177,7 @@ lua_State *L; if (x1 == -1 && y1 == -1 && x2 == -1 && y2 == -1) { (void) selection_not(sel); } else { - schar rx1, ry1, rx2, ry2; + xchar rx1, ry1, rx2, ry2; rx1 = x1, ry1 = y1, rx2 = x2, ry2 = x2; get_location(&rx1, &ry1, ANY_LOC, g.coder->croom); get_location(&rx2, &ry2, ANY_LOC, g.coder->croom); @@ -5259,7 +5217,7 @@ struct selectionvar *ov; WAN_TELEPORTATION, SCR_TELEPORTATION, RIN_TELEPORTATION }; struct selectionvar *ov2 = selection_new(), *ov3; - schar x, y; + xchar x, y; boolean res = TRUE; selection_floodfill(ov2, nx, ny, TRUE); @@ -5327,17 +5285,15 @@ ensure_way_out() struct trap *ttmp = g.ftrap; int x,y; boolean ret = TRUE; + stairway *stway = g.stairs; set_selection_floodfillchk(floodfillchk_match_accessible); - if (xupstair && !selection_getpoint(xupstair, yupstair, ov)) - selection_floodfill(ov, xupstair, yupstair, TRUE); - if (xdnstair && !selection_getpoint(xdnstair, ydnstair, ov)) - selection_floodfill(ov, xdnstair, ydnstair, TRUE); - if (xupladder && !selection_getpoint(xupladder, yupladder, ov)) - selection_floodfill(ov, xupladder, yupladder, TRUE); - if (xdnladder && !selection_getpoint(xdnladder, ydnladder, ov)) - selection_floodfill(ov, xdnladder, ydnladder, TRUE); + while (stway) { + if (stway->tolev.dnum == u.uz.dnum) + selection_floodfill(ov, stway->sx, stway->sy, TRUE); + stway = stway->next; + } while (ttmp) { if ((ttmp->ttyp == MAGIC_PORTAL || ttmp->ttyp == VIBRATING_SQUARE @@ -5589,7 +5545,7 @@ genericptr_t arg; } /* region(selection, lit); */ -/* region({ x1=NN, y1=NN, x2=NN, y2=NN, lit=BOOL, type=ROOMTYPE, joined=BOOL, irregular=BOOL, prefilled=BOOL [ , contents = FUNCTION ] }); */ +/* region({ x1=NN, y1=NN, x2=NN, y2=NN, lit=BOOL, type=ROOMTYPE, joined=BOOL, irregular=BOOL, filled=NN [ , contents = FUNCTION ] }); */ /* region({ region={x1,y1, x2,y2}, type="ordinary" }); */ int lspo_region(L) @@ -5597,9 +5553,9 @@ lua_State *L; { xchar dx1, dy1, dx2, dy2; register struct mkroom *troom; - boolean prefilled = FALSE, room_not_needed, + boolean do_arrival_room = FALSE, room_not_needed, irregular = FALSE, joined = TRUE; - int rtype = OROOM, rlit = 1; + int rtype = OROOM, rlit = 1, needfill = 0; int argc = lua_gettop(L); create_des_coder(); @@ -5607,13 +5563,12 @@ lua_State *L; if (argc <= 1) { lcheck_param_table(L); - /* TODO: check the prefilled, what was the default in lev_comp? */ - /* "unfilled" == 0, "filled" == 1, missing = "filled" */ - - /* TODO: "unfilled" ==> prefilled=1 */ - prefilled = get_table_boolean_opt(L, "prefilled", 0); + /* TODO: "unfilled" ==> filled=0, "filled" ==> filled=1, and + * "lvflags_only" ==> filled=2, probably in a get_table_needfill_opt */ + needfill = get_table_int_opt(L, "filled", 0); irregular = get_table_boolean_opt(L, "irregular", 0); joined = get_table_boolean_opt(L, "joined", 1); + do_arrival_room = get_table_boolean_opt(L, "arrival_room", 0); rtype = get_table_roomtype_opt(L, "type", OROOM); rlit = get_table_int_opt(L, "lit", -1); dx1 = get_table_int_opt(L, "x1", -1); /* TODO: area */ @@ -5658,10 +5613,16 @@ lua_State *L; get_location(&dx1, &dy1, ANY_LOC, (struct mkroom *) 0); get_location(&dx2, &dy2, ANY_LOC, (struct mkroom *) 0); - /* for an ordinary room, `prefilled' is a flag to force - an actual room to be created (such rooms are used to - control placement of migrating monster arrivals) */ - room_not_needed = (rtype == OROOM && !irregular && !prefilled && !g.in_mk_themerooms); + /* Many regions are simple, rectangular areas that just need to set lighting + * in an area. In that case, we don't need to do anything complicated by + * creating a room. The exceptions are: + * - Special rooms (which usually need to be filled). + * - Irregular regions (more convenient to use the room-making code). + * - Themed room regions (which often have contents). + * - When a room is desired to constrain the arrival of migrating monsters + * (see the mon_arrive function for details). + */ + room_not_needed = (rtype == OROOM && !irregular && !do_arrival_room && !g.in_mk_themerooms); if (room_not_needed || g.nroom >= MAXNROFROOMS) { region tmpregion; if (!room_not_needed) @@ -5679,8 +5640,7 @@ lua_State *L; troom = &g.rooms[g.nroom]; /* mark rooms that must be filled, but do it later */ - if (rtype != OROOM) - troom->needfill = (prefilled ? 2 : 1); + troom->needfill = needfill; troom->needjoining = joined; @@ -5701,9 +5661,6 @@ lua_State *L; #endif } - if (g.in_mk_themerooms && prefilled) - troom->needfill = 1; - if (!room_not_needed) { if (g.coder->n_subroom > 1) impossible("region as subroom"); @@ -5878,7 +5835,7 @@ lua_State *L; { static const char *const wprops[] = { "nondiggable", "nonpasswall", NULL }; static const int wprop2i[] = { W_NONDIGGABLE, W_NONPASSWALL, -1 }; - schar dx1 = -1, dy1 = -1, dx2 = -1, dy2 = -1; + xchar dx1 = -1, dy1 = -1, dx2 = -1, dy2 = -1; int wprop; create_des_coder(); @@ -6409,7 +6366,6 @@ const char *name; goto give_up; link_doors_rooms(); - fill_rooms(); remove_boundary_syms(); /* TODO: ensure_way_out() needs rewrite */ diff --git a/src/spell.c b/src/spell.c index b805dffbe..4c92437cc 100644 --- a/src/spell.c +++ b/src/spell.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 spell.c $NHDT-Date: 1593614134 2020/07/01 14:35:34 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.106 $ */ +/* NetHack 3.7 spell.c $NHDT-Date: 1607980325 2020/12/14 21:12:05 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.110 $ */ /* Copyright (c) M. Stephenson 1988 */ /* NetHack may be freely redistributed. See license for details. */ @@ -393,10 +393,7 @@ learn(VOID_ARGS) book->otyp = booktype = SPE_BLANK_PAPER; /* reset spestudied as if polymorph had taken place */ book->spestudied = rn2(book->spestudied); - } else if (spellknow(i) > KEEN / 10) { - You("know %s quite well already.", splname); - costly = FALSE; - } else { /* spellknow(i) <= KEEN/10 */ + } else { Your("knowledge of %s is %s.", splname, spellknow(i) ? "keener" : "restored"); incrnknow(i, 1); @@ -419,7 +416,12 @@ learn(VOID_ARGS) g.spl_book[i].sp_lev = objects[booktype].oc_level; incrnknow(i, 1); book->spestudied++; - You(i > 0 ? "add %s to your repertoire." : "learn %s.", splname); + if (!i) + /* first is always 'a', so no need to mention the letter */ + You("learn %s.", splname); + else + You("add %s to your repertoire, as '%c'.", + splname, spellet(i)); } makeknown((int) booktype); } @@ -443,13 +445,13 @@ int study_book(spellbook) register struct obj *spellbook; { - int booktype = spellbook->otyp; + int booktype = spellbook->otyp, i; boolean confused = (Confusion != 0); boolean too_hard = FALSE; /* attempting to read dull book may make hero fall asleep */ if (!confused && !Sleep_resistance - && !strcmp(OBJ_DESCR(objects[booktype]), "dull")) { + && objdescr_is(spellbook, "dull")) { const char *eyes; int dullbook = rnd(25) - ACURR(A_WIS); @@ -529,6 +531,16 @@ register struct obj *spellbook; return 0; } + /* check to see if we already know it and want to refresh our memory */ + for (i = 0; i < MAXSPELL; i++) + if (spellid(i) == booktype || spellid(i) == NO_SPELL) + break; + if (spellid(i) == booktype && spellknow(i) > KEEN / 10) { + You("know \"%s\" quite well already.", OBJ_NAME(objects[booktype])); + if (yn("Refresh your memory anyway?") == 'n') + return 0; + } + /* Books are often wiser than their readers (Rus.) */ spellbook->in_use = TRUE; if (!spellbook->blessed && spellbook->otyp != SPE_BOOK_OF_THE_DEAD) { diff --git a/src/steal.c b/src/steal.c index 4d4b2235e..790a08128 100644 --- a/src/steal.c +++ b/src/steal.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 steal.c $NHDT-Date: 1591196090 2020/06/03 14:54:50 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.83 $ */ +/* NetHack 3.7 steal.c $NHDT-Date: 1596498213 2020/08/03 23:43:33 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.84 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -508,11 +508,11 @@ register struct obj *otmp; if (!otmp) { impossible("monster (%s) taking or picking up nothing?", - mtmp->data->mname); + pmname(mtmp->data, Mgender(mtmp))); return 1; } else if (otmp == uball || otmp == uchain) { impossible("monster (%s) taking or picking up attached %s (%s)?", - mtmp->data->mname, + pmname(mtmp->data, Mgender(mtmp)), (otmp == uchain) ? "chain" : "ball", simpleonames(otmp)); return 0; } diff --git a/src/steed.c b/src/steed.c index 84e18aa63..44dd33e9f 100644 --- a/src/steed.c +++ b/src/steed.c @@ -40,7 +40,6 @@ struct obj *otmp; struct monst *mtmp; struct permonst *ptr; int chance; - const char *s; if (!u_handsy()) return 0; @@ -71,11 +70,12 @@ struct obj *otmp; You("touch %s.", mon_nam(mtmp)); if (!(poly_when_stoned(g.youmonst.data) && polymon(PM_STONE_GOLEM))) { - Sprintf(kbuf, "attempting to saddle %s", an(mtmp->data->mname)); + Sprintf(kbuf, "attempting to saddle %s", + an(pmname(mtmp->data, Mgender(mtmp)))); instapetrify(kbuf); } } - if (ptr == &mons[PM_INCUBUS] || ptr == &mons[PM_SUCCUBUS]) { + if (ptr == &mons[PM_AMOROUS_DEMON]) { pline("Shame on you!"); exercise(A_WIS, FALSE); return 1; @@ -114,12 +114,10 @@ struct obj *otmp; } if (Confusion || Fumbling || Glib) chance -= 20; - else if (uarmg && (s = OBJ_DESCR(objects[uarmg->otyp])) != (char *) 0 - && !strncmp(s, "riding ", 7)) + else if (uarmg && objdescr_is(uarmg, "riding gloves")) /* Bonus for wearing "riding" (but not fumbling) gloves */ chance += 10; - else if (uarmf && (s = OBJ_DESCR(objects[uarmf->otyp])) != (char *) 0 - && !strncmp(s, "riding ", 7)) + else if (uarmf && objdescr_is(uarmf, "riding boots")) /* ... or for "riding boots" */ chance += 10; if (otmp->cursed) @@ -278,7 +276,8 @@ boolean force; /* Quietly force this animal */ char kbuf[BUFSZ]; You("touch %s.", mon_nam(mtmp)); - Sprintf(kbuf, "attempting to ride %s", an(mtmp->data->mname)); + Sprintf(kbuf, "attempting to ride %s", + an(pmname(mtmp->data, Mgender(mtmp)))); instapetrify(kbuf); } if (!mtmp->mtame || mtmp->isminion) { @@ -538,9 +537,9 @@ int reason; /* Player was thrown off etc. */ You("can't. There isn't anywhere for you to stand."); return; } - if (!has_mname(mtmp)) { + if (!has_mgivenname(mtmp)) { pline("You've been through the dungeon on %s with no name.", - an(mtmp->data->mname)); + an(pmname(mtmp->data, Mgender(mtmp)))); if (Hallucination) pline("It felt good to get out of the rain."); } else diff --git a/src/symbols.c b/src/symbols.c index f8b0cf457..fccec4576 100644 --- a/src/symbols.c +++ b/src/symbols.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 symbols.c $NHDT-Date: 1588776075 2020/05/06 14:41:15 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.0 $ */ +/* NetHack 3.7 symbols.c $NHDT-Date: 1596498214 2020/08/03 23:43:34 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.77 $ */ /* Copyright (c) NetHack Development Team 2020. */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/src/sys.c b/src/sys.c index 63a48ab7d..650c20e08 100644 --- a/src/sys.c +++ b/src/sys.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 sys.c $NHDT-Date: 1575665952 2019/12/06 20:59:12 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.46 $ */ +/* NetHack 3.7 sys.c $NHDT-Date: 1596498215 2020/08/03 23:43:35 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.57 $ */ /* Copyright (c) Kenneth Lorber, Kensington, Maryland, 2008. */ /* NetHack may be freely redistributed. See license for details. */ @@ -130,9 +130,9 @@ extern const struct attack c_sa_no[NATTK]; void sysopt_seduce_set(val) +#if 0 int val; { -#if 0 /* * Attack substitution is now done on the fly in getmattk(mhitu.c). */ @@ -144,8 +144,9 @@ int val; mons[PM_SUCCUBUS].mattk[x] = setval[x]; } #else - nhUse(val); -#endif /*0*/ +int val UNUSED; +{ +#endif return; } diff --git a/src/teleport.c b/src/teleport.c index a29808b00..88bd395f7 100644 --- a/src/teleport.c +++ b/src/teleport.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 teleport.c $NHDT-Date: 1586384219 2020/04/08 22:16:59 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.122 $ */ +/* NetHack 3.7 teleport.c $NHDT-Date: 1605305493 2020/11/13 22:11:33 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.134 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2011. */ /* NetHack may be freely redistributed. See license for details. */ @@ -225,7 +225,8 @@ long entflags; if (allow_xx_yy && goodpos(xx, yy, &fakemon, entflags)) { return TRUE; /* 'cc' is set */ } else { - debugpline3("enexto(\"%s\",%d,%d) failed", mdat->mname, xx, yy); + debugpline3("enexto(\"%s\",%d,%d) failed", + mdat->pmnames[NEUTRAL], xx, yy); return FALSE; } } @@ -401,15 +402,6 @@ int teleds_flags; been updated for new location instead of right after u_on_newpos() */ if (levl[u.ux][u.uy].typ != levl[u.ux0][u.uy0].typ) switch_terrain(); - if (g.telescroll) { - /* when teleporting by scroll, we need to handle discovery - now before getting feedback about any objects at our - destination since we might land on another such scroll */ - if (distu(u.ux0, u.uy0) >= 16 || !couldsee(u.ux0, u.uy0)) - learnscroll(g.telescroll); - else - g.telescroll = 0; /* no discovery by scrolltele()'s caller */ - } /* sequencing issue: we want guard's alarm, if any, to occur before room entry message, if any, so need to check for vault exit prior to spoteffects; but spoteffects() sets up new value for u.urooms @@ -493,26 +485,22 @@ boolean force_it; void tele() { - (void) scrolltele((struct obj *) 0); + scrolltele((struct obj *) 0); } -/* teleport the hero; return true if scroll of teleportation should become - discovered; teleds() will usually do the actual discovery, since the - outcome sometimes depends upon destination and discovery needs to be - performed before arrival, in case we land on another teleport scroll */ -boolean +/* teleport the hero; usually discover scroll of teleporation if via scroll */ +void scrolltele(scroll) struct obj *scroll; { coord cc; - boolean result = FALSE; /* don't learn scroll */ /* Disable teleportation in stronghold && Vlad's Tower */ - if (noteleport_level(&g.youmonst)) { - if (!wizard) { - pline("A mysterious force prevents you from teleporting!"); - return TRUE; - } + if (noteleport_level(&g.youmonst) && !wizard) { + pline("A mysterious force prevents you from teleporting!"); + if (scroll) + learnscroll(scroll); /* this is obviously a teleport scroll */ + return; } /* don't show trap if "Sorry..." */ @@ -521,11 +509,13 @@ struct obj *scroll; if ((u.uhave.amulet || On_W_tower_level(&u.uz)) && !rn2(3)) { You_feel("disoriented for a moment."); + /* don't discover the scroll [at least not yet for wizard override]; + disorientation doesn't reveal that this is a teleport attempt */ if (!wizard || yn("Override?") != 'y') - return FALSE; + return; } - if ((Teleport_control && !Stunned) || (scroll && scroll->blessed) - || wizard) { + if (((Teleport_control || (scroll && scroll->blessed)) && !Stunned) + || wizard) { if (unconscious()) { pline("Being unconscious, you cannot control your teleport."); } else { @@ -535,32 +525,38 @@ struct obj *scroll; if (u.usteed) Sprintf(eos(whobuf), " and %s", mon_nam(u.usteed)); pline("Where do %s want to be teleported?", whobuf); + if (scroll) + learnscroll(scroll); cc.x = u.ux; cc.y = u.uy; + if (isok(iflags.travelcc.x, iflags.travelcc.y)) { + /* The player showed some interest in traveling here; + * pre-suggest this coordinate. */ + cc = iflags.travelcc; + } if (getpos(&cc, TRUE, "the desired position") < 0) - return TRUE; /* abort */ + return; /* abort */ /* possible extensions: introduce a small error if magic power is low; allow transfer to solid rock */ if (teleok(cc.x, cc.y, FALSE)) { /* for scroll, discover it regardless of destination */ - if (scroll) - learnscroll(scroll); teleds(cc.x, cc.y, TELEDS_TELEPORT); - return TRUE; + if (iflags.travelcc.x == u.ux && iflags.travelcc.y == u.uy) + iflags.travelcc.x = iflags.travelcc.y = 0; + return; } pline("Sorry..."); - result = TRUE; } } - g.telescroll = scroll; + /* we used to suppress discovery if hero teleported to a nearby + spot which was already within view, but now there is always a + "materialize" message regardless of how far you teleported so + discovery of scroll type is unconditional */ + if (scroll) + learnscroll(scroll); + (void) safe_teleds(TELEDS_TELEPORT); - /* teleds() will leave g.telescroll intact iff random destination - is far enough away for scroll discovery to be warranted */ - if (g.telescroll) - result = TRUE; - g.telescroll = 0; /* reset */ - return result; } /* ^T command; 'm ^T' == choose among several teleport modes */ @@ -946,7 +942,7 @@ level_tele() } newlevel.dnum = u.uz.dnum; newlevel.dlevel = llimit + newlev; - schedule_goto(&newlevel, FALSE, FALSE, 0, (char *) 0, (char *) 0); + schedule_goto(&newlevel, UTOTYPE_NONE, (char *) 0, (char *) 0); return; } @@ -1054,7 +1050,7 @@ level_tele() } } - schedule_goto(&newlevel, FALSE, FALSE, 0, (char *) 0, + schedule_goto(&newlevel, UTOTYPE_NONE, (char *) 0, flags.verbose ? "You materialize on a different level!" : (char *) 0); @@ -1095,7 +1091,7 @@ register struct trap *ttmp; } target_level = ttmp->dst; - schedule_goto(&target_level, FALSE, FALSE, 1, + schedule_goto(&target_level, UTOTYPE_PORTAL, "You feel dizzy for a moment, but the sensation passes.", (char *) 0); } @@ -1196,10 +1192,10 @@ struct monst *mtmp; sent out of his room (caller might resort to goodpos() if we report failure here, so this isn't full prevention) */ if (mtmp->isshk && inhishop(mtmp)) { - if (levl[x][y].roomno != ESHK(mtmp)->shoproom) + if (levl[x][y].roomno != (unsigned char) ESHK(mtmp)->shoproom) return FALSE; } else if (mtmp->ispriest && inhistemple(mtmp)) { - if (levl[x][y].roomno != EPRI(mtmp)->shroom) + if (levl[x][y].roomno != (unsigned char) EPRI(mtmp)->shroom) return FALSE; } /* current location is */ @@ -1255,6 +1251,7 @@ register int x, y; } } + maybe_unhide_at(x, y); newsym(x, y); /* update new location */ set_apparxy(mtmp); /* orient monster */ @@ -1263,6 +1260,22 @@ register int x, y; the latter only happens if you've attacked them with polymorph */ if (resident_shk && !inhishop(mtmp)) make_angry_shk(mtmp, oldx, oldy); + + /* trapped monster teleported away */ + if (mtmp->mtrapped && !mtmp->wormno) + (void) mintrap(mtmp); +} + +static stairway * +stairway_find_forwiz(isladder, up) +boolean isladder, up; +{ + stairway *stway = g.stairs; + + while (stway && !(stway->isladder == isladder + && stway->up == up && stway->tolev.dnum == u.uz.dnum)) + stway = stway->next; + return stway; } /* place a monster at a random location, typically due to teleport */ @@ -1280,12 +1293,19 @@ boolean suppress_impossible; } if (mtmp->iswiz && mtmp->mx) { /* Wizard, not just arriving */ - if (!In_W_tower(u.ux, u.uy, &u.uz)) - x = xupstair, y = yupstair; - else if (!xdnladder) /* bottom level of tower */ - x = xupladder, y = yupladder; - else - x = xdnladder, y = ydnladder; + stairway *stway; + + if (!In_W_tower(u.ux, u.uy, &u.uz)) { + stway = stairway_find_forwiz(FALSE, TRUE); + } else if (!stairway_find_forwiz(TRUE, FALSE)) { /* bottom level of tower */ + stway = stairway_find_forwiz(TRUE, TRUE); + } else { + stway = stairway_find_forwiz(TRUE, FALSE); + } + + x = stway ? stway->sx : 0; + y = stway ? stway->sy : 0; + /* if the wiz teleports away to heal, try the up staircase, to block the player's escaping before he's healed (deliberately use `goodpos' rather than `rloc_pos_ok' here) */ diff --git a/src/timeout.c b/src/timeout.c index d1494b73d..9f57fbf51 100644 --- a/src/timeout.c +++ b/src/timeout.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 timeout.c $NHDT-Date: 1582925432 2020/02/28 21:30:32 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.112 $ */ +/* NetHack 3.7 timeout.c $NHDT-Date: 1606243387 2020/11/24 18:43:07 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.122 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2018. */ /* NetHack may be freely redistributed. See license for details. */ @@ -46,9 +46,16 @@ const struct propname { { DETECT_MONSTERS, "monster detection" }, { SEE_INVIS, "see invisible" }, { INVIS, "invisible" }, - /* properties beyond here don't have timed values during normal play, - so there's not much point in trying to order them sensibly; - they're either on or off based on equipment, role, actions, &c */ + /* timed displacement is possible via eating a displacer beast corpse */ + { DISPLACED, "displaced" }, + /* timed pass-walls is a potential prayer result if surrounded by stone + with nowhere to be safely teleported to */ + { PASSES_WALLS, "pass thru walls" }, + /* + * Properties beyond here don't have timed values during normal play, + * so there's not much point in trying to order them sensibly. + * They're either on or off based on equipment, role, actions, &c. + */ { FIRE_RES, "fire resistance" }, { COLD_RES, "cold resistance" }, { SLEEP_RES, "sleep resistance" }, @@ -70,7 +77,6 @@ const struct propname { { SEARCHING, "searching" }, { INFRAVISION, "infravision" }, { ADORNED, "adorned (+/- Cha)" }, - { DISPLACED, "displaced" }, { STEALTH, "stealthy" }, { AGGRAVATE_MONSTER, "monster aggravation" }, { CONFLICT, "conflict" }, @@ -80,7 +86,6 @@ const struct propname { { WWALKING, "water walking" }, { SWIMMING, "swimming" }, { MAGICAL_BREATHING, "magical breathing" }, - { PASSES_WALLS, "pass thru walls" }, { SLOW_DIGESTION, "slow digestion" }, { HALF_SPDAM, "half spell damage" }, { HALF_PHDAM, "half physical damage" }, @@ -315,16 +320,20 @@ static NEARDATA const char *const slime_texts[] = { static void slime_dialogue() { - register long i = (Slimed & TIMEOUT) / 2L; + long t = (Slimed & TIMEOUT), i = t / 2L; - if (i == 1L) { + if (t == 1L) { /* display as green slime during "You have become green slime." but don't worry about not being able to see self; if already mimicking something else at the time, implicitly be revealed */ g.youmonst.m_ap_type = M_AP_MONSTER; g.youmonst.mappearance = PM_GREEN_SLIME; + /* no message given when 't' is odd, so no automatic update of + self; force one */ + newsym(u.ux, u.uy); } - if (((Slimed & TIMEOUT) % 2L) && i >= 0L && i < SIZE(slime_texts)) { + + if ((t % 2L) != 0L && i >= 0L && i < SIZE(slime_texts)) { char buf[BUFSZ]; Strcpy(buf, slime_texts[SIZE(slime_texts) - i - 1L]); @@ -593,7 +602,8 @@ nh_timeout() } dealloc_killer(kptr); - if ((m_idx = name_to_mon(g.killer.name)) >= LOW_PM) { + if ((m_idx = name_to_mon(g.killer.name, + (int *) 0)) >= LOW_PM) { if (type_is_pname(&mons[m_idx])) { g.killer.format = KILLED_BY; } else if (mons[m_idx].geno & G_UNIQ) { @@ -671,6 +681,12 @@ nh_timeout() } break; case LEVITATION: + /* timed Flying is via #wizintrinsic only; still, we want to + avoid float_down() reporting "you have stopped levitating + and are now flying" if both are timing out together; + relies on knowing that Lev timeout is handled before Fly */ + if ((HFlying & TIMEOUT) == 1L) + --HFlying; /* bypass pending 'case FLYING' */ (void) float_down(I_SPECIAL | TIMEOUT, 0L); break; case FLYING: @@ -691,7 +707,7 @@ nh_timeout() g.context.warntype.speciesidx = NON_PM; if (g.context.warntype.species) { You("are no longer warned about %s.", - makeplural(g.context.warntype.species->mname)); + makeplural(g.context.warntype.species->pmnames[NEUTRAL])); g.context.warntype.species = (struct permonst *) 0; } } @@ -980,6 +996,8 @@ long timeout; /* free egg here because we use it above */ obj_extract_self(egg); obfree(egg, (struct obj *) 0); + if ((mon = m_at(x,y)) && !hideunder(mon) && cansee(x, y)) + redraw = TRUE; } if (redraw) newsym(x, y); @@ -1058,15 +1076,15 @@ slip_or_trip() if (!uarmf && otmp->otyp == CORPSE && touch_petrifies(&mons[otmp->corpsenm]) && !Stone_resistance) { Sprintf(g.killer.name, "tripping over %s corpse", - an(mons[otmp->corpsenm].mname)); + an(mons[otmp->corpsenm].pmnames[NEUTRAL])); instapetrify(g.killer.name); } } else if (rn2(3) && is_ice(u.ux, u.uy)) { pline("%s %s%s on the ice.", u.usteed ? upstart(x_monnam(u.usteed, - (has_mname(u.usteed)) ? ARTICLE_NONE - : ARTICLE_THE, - (char *) 0, SUPPRESS_SADDLE, FALSE)) + (has_mgivenname(u.usteed)) ? ARTICLE_NONE + : ARTICLE_THE, + (char *) 0, SUPPRESS_SADDLE, FALSE)) : "You", rn2(2) ? "slip" : "slide", on_foot ? "" : "s"); } else { @@ -1740,6 +1758,7 @@ static const ttable timeout_funcs[NUM_TIME_FUNCS] = { TTAB(rot_organic, (timeout_proc) 0, "rot_organic"), TTAB(rot_corpse, (timeout_proc) 0, "rot_corpse"), TTAB(revive_mon, (timeout_proc) 0, "revive_mon"), + TTAB(zombify_mon, (timeout_proc) 0, "zombify_mon"), TTAB(burn_object, cleanup_burn, "burn_object"), TTAB(hatch_egg, (timeout_proc) 0, "hatch_egg"), TTAB(fig_transform, (timeout_proc) 0, "fig_transform"), @@ -2402,7 +2421,7 @@ long adjust; /* how much to adjust timeout */ /* restore elements */ if (nhfp->structlevel) mread(nhfp->fd, (genericptr_t) &count, sizeof count); - + while (count-- > 0) { curr = (timer_element *) alloc(sizeof(timer_element)); if (nhfp->structlevel) diff --git a/src/topten.c b/src/topten.c index da418bf69..db9208114 100644 --- a/src/topten.c +++ b/src/topten.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 topten.c $NHDT-Date: 1593771616 2020/07/03 10:20:16 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.71 $ */ +/* NetHack 3.7 topten.c $NHDT-Date: 1606009004 2020/11/22 01:36:44 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.74 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -374,7 +374,8 @@ int how; genders[flags.initgend].filecode, XLOG_SEP, aligns[1 - u.ualignbase[A_ORIGINAL]].filecode); Fprintf(rfile, "%cflags=0x%lx", XLOG_SEP, encodexlogflags()); - Fprintf(rfile, "%cgold=%ld", XLOG_SEP, money_cnt(g.invent) + hidden_gold()); + Fprintf(rfile, "%cgold=%ld", XLOG_SEP, + money_cnt(g.invent) + hidden_gold(TRUE)); Fprintf(rfile, "%cwish_cnt=%ld", XLOG_SEP, u.uconduct.wishes); Fprintf(rfile, "%carti_wish_cnt=%ld", XLOG_SEP, u.uconduct.wisharti); Fprintf(rfile, "\n"); diff --git a/src/track.c b/src/track.c index 8ac35c51a..ec6e8f565 100644 --- a/src/track.c +++ b/src/track.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 track.c $NHDT-Date: 1432512769 2015/05/25 00:12:49 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ */ +/* NetHack 3.7 track.c $NHDT-Date: 1596498219 2020/08/03 23:43:39 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.12 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Kenneth Lorber, Kensington, Maryland, 2015. */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/src/trap.c b/src/trap.c index 72fd27d59..6b20f2596 100644 --- a/src/trap.c +++ b/src/trap.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 trap.c $NHDT-Date: 1593768051 2020/07/03 09:20:51 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.361 $ */ +/* NetHack 3.7 trap.c $NHDT-Date: 1606558763 2020/11/28 10:19:23 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.367 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2013. */ /* NetHack may be freely redistributed. See license for details. */ @@ -12,6 +12,28 @@ static boolean FDECL(keep_saddle_with_steedcorpse, (unsigned, struct obj *, static boolean FDECL(mu_maybe_destroy_web, (struct monst *, BOOLEAN_P, struct trap *)); static struct obj *FDECL(t_missile, (int, struct trap *)); +static int FDECL(trapeffect_arrow_trap, (struct monst *, struct trap *, unsigned)); +static int FDECL(trapeffect_dart_trap, (struct monst *, struct trap *, unsigned)); +static int FDECL(trapeffect_rocktrap, (struct monst *, struct trap *, unsigned)); +static int FDECL(trapeffect_sqky_board, (struct monst *, struct trap *, unsigned)); +static int FDECL(trapeffect_bear_trap, (struct monst *, struct trap *, unsigned)); +static int FDECL(trapeffect_slp_gas_trap, (struct monst *, struct trap *, unsigned)); +static int FDECL(trapeffect_rust_trap, (struct monst *, struct trap *, unsigned)); +static int FDECL(trapeffect_fire_trap, (struct monst *, struct trap *, unsigned)); +static int FDECL(trapeffect_pit, (struct monst *, struct trap *, unsigned)); +static int FDECL(trapeffect_hole, (struct monst *, struct trap *, unsigned)); +static int FDECL(trapeffect_telep_trap, (struct monst *, struct trap *, unsigned)); +static int FDECL(trapeffect_level_telep, (struct monst *, struct trap *, unsigned)); +static int FDECL(trapeffect_web, (struct monst *, struct trap *, unsigned)); +static int FDECL(trapeffect_statue_trap, (struct monst *, struct trap *, unsigned)); +static int FDECL(trapeffect_magic_trap, (struct monst *, struct trap *, unsigned)); +static int FDECL(trapeffect_anti_magic, (struct monst *, struct trap *, unsigned)); +static int FDECL(trapeffect_poly_trap, (struct monst *, struct trap *, unsigned)); +static int FDECL(trapeffect_landmine, (struct monst *, struct trap *, unsigned)); +static int FDECL(trapeffect_rolling_boulder_trap, (struct monst *, struct trap *, unsigned)); +static int FDECL(trapeffect_magic_portal, (struct monst *, struct trap *, unsigned)); +static int FDECL(trapeffect_vibrating_square, (struct monst *, struct trap *, unsigned)); +static int FDECL(trapeffect_selector, (struct monst *, struct trap *, unsigned)); static char *FDECL(trapnote, (struct trap *, BOOLEAN_P)); static int FDECL(steedintrap, (struct trap *, struct obj *)); static void FDECL(launch_drop_spot, (struct obj *, XCHAR_P, XCHAR_P)); @@ -67,7 +89,7 @@ struct monst *victim; /* burning damage may dry wet towel */ item = hitting_u ? carrying(TOWEL) : m_carrying(victim, TOWEL); while (item) { - if (is_wet_towel(item)) { + if (is_wet_towel(item)) { /* True => (item->spe > 0) */ oldspe = item->spe; dry_a_towel(item, rn2(oldspe + 1), TRUE); if (item->spe != oldspe) @@ -536,7 +558,7 @@ unsigned ftflags; Sprintf(msgbuf, "The hole in the %s above you closes up.", ceiling(u.ux, u.uy)); - schedule_goto(&dtmp, FALSE, TRUE, 0, (char *) 0, + schedule_goto(&dtmp, UTOTYPE_FALLING, (char *) 0, !td ? msgbuf : (char *) 0); } @@ -902,82 +924,20 @@ boolean msg; } } -void -dotrap(trap, trflags) -register struct trap *trap; -unsigned trflags; +static int +trapeffect_arrow_trap(mtmp, trap, trflags) +struct monst *mtmp; +struct trap *trap; +unsigned trflags UNUSED; { - register int ttype = trap->ttyp; struct obj *otmp; - boolean already_seen = trap->tseen, - forcetrap = ((trflags & FORCETRAP) != 0 - || (trflags & FAILEDUNTRAP) != 0), - webmsgok = (trflags & NOWEBMSG) == 0, - forcebungle = (trflags & FORCEBUNGLE) != 0, - plunged = (trflags & TOOKPLUNGE) != 0, - viasitting = (trflags & VIASITTING) != 0, - conj_pit = conjoined_pits(trap, t_at(u.ux0, u.uy0), TRUE), - adj_pit = adj_nonconjoined_pit(trap); - int oldumort; - int steed_article = ARTICLE_THE; - nomul(0); - - /* KMH -- You can't escape the Sokoban level traps */ - if (Sokoban && (is_pit(ttype) || is_hole(ttype))) { - /* The "air currents" message is still appropriate -- even when - * the hero isn't flying or levitating -- because it conveys the - * reason why the player cannot escape the trap with a dexterity - * check, clinging to the ceiling, etc. - */ - pline("Air currents pull you down into %s %s!", - a_your[trap->madeby_u], - trapname(ttype, TRUE)); /* do force "pit" while hallucinating */ - /* then proceed to normal trap effect */ - } else if (already_seen && !forcetrap) { - if ((Levitation || (Flying && !plunged)) - && (is_pit(ttype) || ttype == HOLE || ttype == BEAR_TRAP)) { - You("%s over %s %s.", Levitation ? "float" : "fly", - a_your[trap->madeby_u], - trapname(ttype, FALSE)); - return; - } - if (!Fumbling && ttype != MAGIC_PORTAL && ttype != VIBRATING_SQUARE - && ttype != ANTI_MAGIC && !forcebungle && !plunged - && !conj_pit && !adj_pit - && (!rn2(5) || (is_pit(ttype) - && is_clinger(g.youmonst.data)))) { - You("escape %s %s.", (ttype == ARROW_TRAP && !trap->madeby_u) - ? "an" - : a_your[trap->madeby_u], - trapname(ttype, FALSE)); - return; - } - } - - if (u.usteed) { - u.usteed->mtrapseen |= (1 << (ttype - 1)); - /* suppress article in various steed messages when using its - name (which won't occur when hallucinating) */ - if (has_mname(u.usteed) && !Hallucination) - steed_article = ARTICLE_NONE; - } - - /* - * Note: - * Most references to trap types here don't use trapname() for - * hallucination. This could be considered to be a bug but doing - * that would hide the actual trap situation from the player which - * would be somewhat harsh for what's usually a minor impairment. - */ - - switch (ttype) { - case ARROW_TRAP: + if (mtmp == &g.youmonst) { if (trap->once && trap->tseen && !rn2(15)) { You_hear("a loud click!"); deltrap(trap); newsym(u.ux, u.uy); - break; + return 0; } trap->once = 1; seetrap(trap); @@ -995,14 +955,47 @@ unsigned trflags; stackobj(otmp); newsym(u.ux, u.uy); } - break; + } else { + boolean in_sight = canseemon(mtmp) || (mtmp == u.usteed); + boolean see_it = cansee(mtmp->mx, mtmp->my); + boolean trapkilled = FALSE; + + if (trap->once && trap->tseen && !rn2(15)) { + if (in_sight && see_it) + pline("%s triggers a trap but nothing happens.", + Monnam(mtmp)); + deltrap(trap); + newsym(mtmp->mx, mtmp->my); + return 0; + } + trap->once = 1; + otmp = t_missile(ARROW, trap); + if (in_sight) + seetrap(trap); + if (thitm(8, mtmp, otmp, 0, FALSE)) + trapkilled = TRUE; + + return trapkilled ? 2 : mtmp->mtrapped; + } + return 0; +} + +static int +trapeffect_dart_trap(mtmp, trap, trflags) +struct monst *mtmp; +struct trap *trap; +unsigned trflags UNUSED; +{ + struct obj *otmp; + + if (mtmp == &g.youmonst) { + int oldumort = u.umortality; - case DART_TRAP: if (trap->once && trap->tseen && !rn2(15)) { You_hear("a soft click."); deltrap(trap); newsym(u.ux, u.uy); - break; + return 0; } trap->once = 1; seetrap(trap); @@ -1010,7 +1003,6 @@ unsigned trflags; otmp = t_missile(DART, trap); if (!rn2(6)) otmp->opoisoned = 1; - oldumort = u.umortality; if (u.usteed && !rn2(2) && steedintrap(trap, otmp)) { ; /* nothing */ } else if (thitu(7, dmgval(otmp, &g.youmonst), &otmp, "little dart")) { @@ -1029,9 +1021,42 @@ unsigned trflags; stackobj(otmp); newsym(u.ux, u.uy); } - break; + } else { + boolean in_sight = canseemon(mtmp) || (mtmp == u.usteed); + boolean see_it = cansee(mtmp->mx, mtmp->my); + boolean trapkilled = FALSE; - case ROCKTRAP: + if (trap->once && trap->tseen && !rn2(15)) { + if (in_sight && see_it) + pline("%s triggers a trap but nothing happens.", + Monnam(mtmp)); + deltrap(trap); + newsym(mtmp->mx, mtmp->my); + return 0; + } + trap->once = 1; + otmp = t_missile(DART, trap); + if (!rn2(6)) + otmp->opoisoned = 1; + if (in_sight) + seetrap(trap); + if (thitm(7, mtmp, otmp, 0, FALSE)) + trapkilled = TRUE; + + return trapkilled ? 2 : mtmp->mtrapped; + } + return 0; +} + +static int +trapeffect_rocktrap(mtmp, trap, trflags) +struct monst *mtmp; +struct trap *trap; +unsigned trflags UNUSED; +{ + struct obj *otmp; + + if (mtmp == &g.youmonst) { if (trap->once && trap->tseen && !rn2(15)) { pline("A trap door in %s opens, but nothing falls out!", the(ceiling(u.ux, u.uy))); @@ -1063,9 +1088,41 @@ unsigned trflags; losehp(Maybe_Half_Phys(dmg), "falling rock", KILLED_BY_AN); exercise(A_STR, FALSE); } - break; + } else { + boolean in_sight = canseemon(mtmp) || (mtmp == u.usteed); + boolean see_it = cansee(mtmp->mx, mtmp->my); + boolean trapkilled = FALSE; - case SQKY_BOARD: /* stepped on a squeaky board */ + if (trap->once && trap->tseen && !rn2(15)) { + if (in_sight && see_it) + pline("A trap door above %s opens, but nothing falls out!", + mon_nam(mtmp)); + deltrap(trap); + newsym(mtmp->mx, mtmp->my); + return 0; + } + trap->once = 1; + otmp = t_missile(ROCK, trap); + if (in_sight) + seetrap(trap); + if (thitm(0, mtmp, otmp, d(2, 6), FALSE)) + trapkilled = TRUE; + + return trapkilled ? 2 : mtmp->mtrapped; + } + return 0; +} + +static int +trapeffect_sqky_board(mtmp, trap, trflags) +struct monst *mtmp; +struct trap *trap; +unsigned trflags; +{ + boolean forcetrap = ((trflags & FORCETRAP) != 0 + || (trflags & FAILEDUNTRAP) != 0); + + if (mtmp == &g.youmonst) { if ((Levitation || Flying) && !forcetrap) { if (!Blind) { seetrap(trap); @@ -1081,24 +1138,61 @@ unsigned trflags; Deaf ? "" : trapnote(trap, 0), Deaf ? "" : " loudly"); wake_nearby(); } - break; + } else { + boolean in_sight = canseemon(mtmp) || (mtmp == u.usteed); - case BEAR_TRAP: { + if (is_flyer(mtmp->data)) + return 0; + /* stepped on a squeaky board */ + if (in_sight) { + if (!Deaf) { + pline("A board beneath %s squeaks %s loudly.", + mon_nam(mtmp), trapnote(trap, 0)); + seetrap(trap); + } else { + pline("%s stops momentarily and appears to cringe.", + Monnam(mtmp)); + } + } else { + /* same near/far threshold as mzapmsg() */ + int range = couldsee(mtmp->mx, mtmp->my) /* 9 or 5 */ + ? (BOLT_LIM + 1) : (BOLT_LIM - 3); + + You_hear("a %s squeak %s.", trapnote(trap, 1), + (distu(mtmp->mx, mtmp->my) <= range * range) + ? "nearby" : "in the distance"); + } + /* wake up nearby monsters */ + wake_nearto(mtmp->mx, mtmp->my, 40); + } + return 0; +} + +static int +trapeffect_bear_trap(mtmp, trap, trflags) +struct monst *mtmp; +struct trap *trap; +unsigned trflags; +{ + boolean forcetrap = ((trflags & FORCETRAP) != 0 + || (trflags & FAILEDUNTRAP) != 0); + + if (mtmp == &g.youmonst) { int dmg = d(2, 4); if ((Levitation || Flying) && !forcetrap) - break; + return 0; feeltrap(trap); if (amorphous(g.youmonst.data) || is_whirly(g.youmonst.data) || unsolid(g.youmonst.data)) { pline("%s bear trap closes harmlessly through you.", A_Your[trap->madeby_u]); - break; + return 0; } if (!u.usteed && g.youmonst.data->msize <= MZ_SMALL) { pline("%s bear trap closes harmlessly over you.", A_Your[trap->madeby_u]); - break; + return 0; } set_utrap((unsigned) rn1(4, 4), TT_BEARTRAP); if (u.usteed) { @@ -1115,10 +1209,45 @@ unsigned trflags; losehp(Maybe_Half_Phys(dmg), "bear trap", KILLED_BY_AN); } exercise(A_DEX, FALSE); - break; - } + } else { + struct permonst *mptr = mtmp->data; + boolean in_sight = canseemon(mtmp) || (mtmp == u.usteed); + boolean trapkilled = FALSE; - case SLP_GAS_TRAP: + if (mptr->msize > MZ_SMALL && !amorphous(mptr) && !is_flyer(mptr) + && !is_whirly(mptr) && !unsolid(mptr)) { + mtmp->mtrapped = 1; + if (in_sight) { + pline("%s is caught in %s bear trap!", Monnam(mtmp), + a_your[trap->madeby_u]); + seetrap(trap); + } else { + if (mptr == &mons[PM_OWLBEAR] + || mptr == &mons[PM_BUGBEAR]) + You_hear("the roaring of an angry bear!"); + } + } else if (g.force_mintrap) { + if (in_sight) { + pline("%s evades %s bear trap!", Monnam(mtmp), + a_your[trap->madeby_u]); + seetrap(trap); + } + } + if (mtmp->mtrapped) + trapkilled = thitm(0, mtmp, (struct obj *) 0, d(2, 4), FALSE); + + return trapkilled ? 2 : mtmp->mtrapped; + } + return 0; +} + +static int +trapeffect_slp_gas_trap(mtmp, trap, trflags) +struct monst *mtmp; +struct trap *trap; +unsigned trflags UNUSED; +{ + if (mtmp == &g.youmonst) { seetrap(trap); if (Sleep_resistance || breathless(g.youmonst.data)) { You("are enveloped in a cloud of gas!"); @@ -1127,9 +1256,29 @@ unsigned trflags; fall_asleep(-rnd(25), TRUE); } (void) steedintrap(trap, (struct obj *) 0); - break; + } else { + boolean in_sight = canseemon(mtmp) || (mtmp == u.usteed); - case RUST_TRAP: + if (!resists_sleep(mtmp) && !breathless(mtmp->data) && !mtmp->msleeping + && mtmp->mcanmove) { + if (sleep_monst(mtmp, rnd(25), -1) && in_sight) { + pline("%s suddenly falls asleep!", Monnam(mtmp)); + seetrap(trap); + } + } + } + return 0; +} + +static int +trapeffect_rust_trap(mtmp, trap, trflags) +struct monst *mtmp; +struct trap *trap; +unsigned trflags UNUSED; +{ + struct obj *otmp; + + if (mtmp == &g.youmonst) { seetrap(trap); /* Unlike monsters, traps cannot aim their rust attacks at @@ -1148,22 +1297,21 @@ unsigned trflags; break; if (u.twoweap || (uwep && bimanual(uwep))) (void) water_damage(u.twoweap ? uswapwep : uwep, 0, TRUE); - glovecheck: - (void) water_damage(uarmg, "gauntlets", TRUE); - /* Not "metal gauntlets" since it gets called - * even if it's leather for the message - */ + uglovecheck: + (void) water_damage(uarmg, gloves_simple_name(uarmg), TRUE); break; case 2: pline("%s your right %s!", A_gush_of_water_hits, body_part(ARM)); (void) water_damage(uwep, 0, TRUE); - goto glovecheck; + goto uglovecheck; default: pline("%s you!", A_gush_of_water_hits); + /* note: exclude primary and seconary weapons from splashing + because cases 1 and 2 target them [via water_damage()] */ for (otmp = g.invent; otmp; otmp = otmp->nobj) if (otmp->lamplit && otmp != uwep && (otmp != uswapwep || !u.twoweap)) - (void) snuff_lit(otmp); + (void) splash_lit(otmp); if (uarmc) (void) water_damage(uarmc, cloak_simple_name(uarmc), TRUE); else if (uarm) @@ -1181,19 +1329,176 @@ unsigned trflags; } else if (u.umonnum == PM_GREMLIN && rn2(3)) { (void) split_mon(&g.youmonst, (struct monst *) 0); } + } else { + boolean in_sight = canseemon(mtmp) || (mtmp == u.usteed); + boolean trapkilled = FALSE; + struct permonst *mptr = mtmp->data; + struct obj *target; - break; + if (in_sight) + seetrap(trap); + switch (rn2(5)) { + case 0: + if (in_sight) + pline("%s %s on the %s!", A_gush_of_water_hits, + mon_nam(mtmp), mbodypart(mtmp, HEAD)); + target = which_armor(mtmp, W_ARMH); + (void) water_damage(target, helm_simple_name(target), TRUE); + break; + case 1: + if (in_sight) + pline("%s %s's left %s!", A_gush_of_water_hits, + mon_nam(mtmp), mbodypart(mtmp, ARM)); + target = which_armor(mtmp, W_ARMS); + if (water_damage(target, "shield", TRUE) != ER_NOTHING) + break; + target = MON_WEP(mtmp); + if (target && bimanual(target)) + (void) water_damage(target, 0, TRUE); + mglovecheck: + target = which_armor(mtmp, W_ARMG); + (void) water_damage(target, gloves_simple_name(target), TRUE); + break; + case 2: + if (in_sight) + pline("%s %s's right %s!", A_gush_of_water_hits, + mon_nam(mtmp), mbodypart(mtmp, ARM)); + (void) water_damage(MON_WEP(mtmp), 0, TRUE); + goto mglovecheck; + default: + if (in_sight) + pline("%s %s!", A_gush_of_water_hits, mon_nam(mtmp)); + for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj) + if (otmp->lamplit + /* exclude weapon(s) because cases 1 and 2 do them */ + && (otmp->owornmask & (W_WEP | W_SWAPWEP)) == 0) + (void) splash_lit(otmp); + if ((target = which_armor(mtmp, W_ARMC)) != 0) + (void) water_damage(target, cloak_simple_name(target), + TRUE); + else if ((target = which_armor(mtmp, W_ARM)) != 0) + (void) water_damage(target, suit_simple_name(target), + TRUE); + else if ((target = which_armor(mtmp, W_ARMU)) != 0) + (void) water_damage(target, "shirt", TRUE); + } - case FIRE_TRAP: + if (completelyrusts(mptr)) { + if (in_sight) + pline("%s %s to pieces!", Monnam(mtmp), + !mlifesaver(mtmp) ? "falls" : "starts to fall"); + monkilled(mtmp, (const char *) 0, AD_RUST); + if (DEADMONSTER(mtmp)) + trapkilled = TRUE; + } else if (mptr == &mons[PM_GREMLIN] && rn2(3)) { + (void) split_mon(mtmp, (struct monst *) 0); + } + + return trapkilled ? 2 : mtmp->mtrapped; + } + return 0; +} + +static int +trapeffect_fire_trap(mtmp, trap, trflags) +struct monst *mtmp; +struct trap *trap; +unsigned trflags UNUSED; +{ + if (mtmp == &g.youmonst) { seetrap(trap); dofiretrap((struct obj *) 0); - break; + } else { + boolean in_sight = canseemon(mtmp) || (mtmp == u.usteed); + boolean see_it = cansee(mtmp->mx, mtmp->my); + boolean trapkilled = FALSE; + struct permonst *mptr = mtmp->data; + + if (in_sight) + pline("A %s erupts from the %s under %s!", tower_of_flame, + surface(mtmp->mx, mtmp->my), mon_nam(mtmp)); + else if (see_it) /* evidently `mtmp' is invisible */ + You_see("a %s erupt from the %s!", tower_of_flame, + surface(mtmp->mx, mtmp->my)); + + if (resists_fire(mtmp)) { + if (in_sight) { + shieldeff(mtmp->mx, mtmp->my); + pline("%s is uninjured.", Monnam(mtmp)); + } + } else { + int num = d(2, 4), alt; + boolean immolate = FALSE; + + /* paper burns very fast, assume straw is tightly packed + and burns a bit slower + (note: this is inconsistent with mattackm()'s AD_FIRE + damage where completelyburns() includes straw golem) */ + switch (monsndx(mptr)) { + case PM_PAPER_GOLEM: + immolate = TRUE; + alt = mtmp->mhpmax; + break; + case PM_STRAW_GOLEM: + alt = mtmp->mhpmax / 2; + break; + case PM_WOOD_GOLEM: + alt = mtmp->mhpmax / 4; + break; + case PM_LEATHER_GOLEM: + alt = mtmp->mhpmax / 8; + break; + default: + alt = 0; + break; + } + if (alt > num) + num = alt; + + if (thitm(0, mtmp, (struct obj *) 0, num, immolate)) + trapkilled = TRUE; + else + /* we know mhp is at least `num' below mhpmax, + so no (mhp > mhpmax) check is needed here */ + mtmp->mhpmax -= rn2(num + 1); + } + if (burnarmor(mtmp) || rn2(3)) { + (void) destroy_mitem(mtmp, SCROLL_CLASS, AD_FIRE); + (void) destroy_mitem(mtmp, SPBOOK_CLASS, AD_FIRE); + (void) destroy_mitem(mtmp, POTION_CLASS, AD_FIRE); + ignite_items(mtmp->minvent); + } + if (burn_floor_objects(mtmp->mx, mtmp->my, see_it, FALSE) + && !see_it && distu(mtmp->mx, mtmp->my) <= 3 * 3) + You("smell smoke."); + if (is_ice(mtmp->mx, mtmp->my)) + melt_ice(mtmp->mx, mtmp->my, (char *) 0); + if (see_it && t_at(mtmp->mx, mtmp->my)) + seetrap(trap); + + return trapkilled ? 2 : mtmp->mtrapped; + } + return 0; +} + +static int +trapeffect_pit(mtmp, trap, trflags) +struct monst *mtmp; +struct trap *trap; +unsigned trflags; +{ + int ttype = trap->ttyp; + + if (mtmp == &g.youmonst) { + boolean plunged = (trflags & TOOKPLUNGE) != 0; + boolean conj_pit = conjoined_pits(trap, t_at(u.ux0, u.uy0), TRUE); + boolean adj_pit = adj_nonconjoined_pit(trap); + int steed_article = ARTICLE_THE; + int oldumort; - case PIT: - case SPIKED_PIT: /* KMH -- You can't escape the Sokoban level traps */ if (!Sokoban && (Levitation || (Flying && !plunged))) - break; + return 0; feeltrap(trap); if (!Sokoban && is_clinger(g.youmonst.data) && !plunged) { if (trap->tseen) { @@ -1204,7 +1509,7 @@ unsigned trflags; ttype == SPIKED_PIT ? "full of spikes " : ""); You("don't fall in!"); } - break; + return 0; } if (!Sokoban) { char verbbuf[BUFSZ]; @@ -1265,18 +1570,18 @@ unsigned trflags; death reason will be overridden with "killed while stuck in creature form" */ plunged - ? "deliberately plunged into a pit of iron spikes" - : conj_pit - ? "stepped into a pit of iron spikes" - : adj_pit - ? "stumbled into a pit of iron spikes" - : "fell into a pit of iron spikes", + ? "deliberately plunged into a pit of iron spikes" + : conj_pit + ? "stepped into a pit of iron spikes" + : adj_pit + ? "stumbled into a pit of iron spikes" + : "fell into a pit of iron spikes", NO_KILLER_PREFIX); if (!rn2(6)) poisoned("spikes", A_STR, (conj_pit || adj_pit) - ? "stepping on poison spikes" - : "fall onto poison spikes", + ? "stepping on poison spikes" + : "fall onto poison spikes", /* if damage triggered life-saving, poison is limited to attrib loss */ (u.umortality > oldumort) ? 0 : 8, FALSE); @@ -1286,7 +1591,7 @@ unsigned trflags; && !(plunged && (Flying || is_clinger(g.youmonst.data)))) losehp(Maybe_Half_Phys(rnd(adj_pit ? 3 : 6)), plunged ? "deliberately plunged into a pit" - : "fell into a pit", + : "fell into a pit", NO_KILLER_PREFIX); } if (Punished && !carried(uball)) { @@ -1300,38 +1605,173 @@ unsigned trflags; exercise(A_STR, FALSE); exercise(A_DEX, FALSE); } - break; + } else { + int tt = trap->ttyp; + boolean in_sight = canseemon(mtmp) || (mtmp == u.usteed); + boolean trapkilled = FALSE; + boolean inescapable = (g.force_mintrap + || ((tt == HOLE || tt == PIT) + && Sokoban && !trap->madeby_u)); + struct permonst *mptr = mtmp->data; + const char *fallverb; - case HOLE: - case TRAPDOOR: + fallverb = "falls"; + if (is_flyer(mptr) || is_floater(mptr) + || (mtmp->wormno && count_wsegs(mtmp) > 5) + || is_clinger(mptr)) { + if (g.force_mintrap && !Sokoban) { + /* openfallingtrap; not inescapable here */ + if (in_sight) { + seetrap(trap); + pline("%s doesn't fall into the pit.", Monnam(mtmp)); + } + return 0; + } + if (!inescapable) + return 0; /* avoids trap */ + fallverb = "is dragged"; /* sokoban pit */ + } + if (!passes_walls(mptr)) + mtmp->mtrapped = 1; + if (in_sight) { + pline("%s %s into %s pit!", Monnam(mtmp), fallverb, + a_your[trap->madeby_u]); + if (mptr == &mons[PM_PIT_VIPER] + || mptr == &mons[PM_PIT_FIEND]) + pline("How pitiful. Isn't that the pits?"); + seetrap(trap); + } + mselftouch(mtmp, "Falling, ", FALSE); + if (DEADMONSTER(mtmp) || thitm(0, mtmp, (struct obj *) 0, + rnd((tt == PIT) ? 6 : 10), FALSE)) + trapkilled = TRUE; + + return trapkilled ? 2 : mtmp->mtrapped; + } + return 0; +} + +static int +trapeffect_hole(mtmp, trap, trflags) +struct monst *mtmp; +struct trap *trap; +unsigned trflags; +{ + if (mtmp == &g.youmonst) { if (!Can_fall_thru(&u.uz)) { seetrap(trap); /* normally done in fall_through */ impossible("dotrap: %ss cannot exist on this level.", - trapname(ttype, TRUE)); - break; /* don't activate it after all */ + trapname(trap->ttyp, TRUE)); + return 0; /* don't activate it after all */ } fall_through(TRUE, (trflags & TOOKPLUNGE)); - break; + } else { + int tt = trap->ttyp; + struct permonst *mptr = mtmp->data; + boolean in_sight = canseemon(mtmp) || (mtmp == u.usteed); + boolean inescapable = (g.force_mintrap + || ((tt == HOLE || tt == PIT) + && Sokoban && !trap->madeby_u)); - case TELEP_TRAP: + if (!Can_fall_thru(&u.uz)) { + impossible("mintrap: %ss cannot exist on this level.", + trapname(tt, TRUE)); + return 0; /* don't activate it after all */ + } + if (is_flyer(mptr) || is_floater(mptr) || mptr == &mons[PM_WUMPUS] + || (mtmp->wormno && count_wsegs(mtmp) > 5) + || mptr->msize >= MZ_HUGE) { + if (g.force_mintrap && !Sokoban) { + /* openfallingtrap; not inescapable here */ + if (in_sight) { + seetrap(trap); + if (tt == TRAPDOOR) + pline( + "A trap door opens, but %s doesn't fall through.", + mon_nam(mtmp)); + else /* (tt == HOLE) */ + pline("%s doesn't fall through the hole.", + Monnam(mtmp)); + } + return 0; /* inescapable = FALSE; */ + } + if (inescapable) { /* sokoban hole */ + if (in_sight) { + pline("%s seems to be yanked down!", Monnam(mtmp)); + /* suppress message in mlevel_tele_trap() */ + in_sight = FALSE; + seetrap(trap); + } + } else + return 0; + } + return trapeffect_level_telep(mtmp, trap, trflags); + } + return 0; +} + +static int +trapeffect_telep_trap(mtmp, trap, trflags) +struct monst *mtmp; +struct trap *trap; +unsigned trflags UNUSED; +{ + if (mtmp == &g.youmonst) { seetrap(trap); tele_trap(trap); - break; + } else { + boolean in_sight = canseemon(mtmp) || (mtmp == u.usteed); - case LEVEL_TELEP: + mtele_trap(mtmp, trap, in_sight); + } + return 0; +} + +static int +trapeffect_level_telep(mtmp, trap, trflags) +struct monst *mtmp; +struct trap *trap; +unsigned trflags; +{ + if (mtmp == &g.youmonst) { seetrap(trap); level_tele_trap(trap, trflags); - break; + } else { + int mlev_res; + int tt = trap->ttyp; + boolean in_sight = canseemon(mtmp) || (mtmp == u.usteed); + boolean inescapable = (g.force_mintrap + || ((tt == HOLE || tt == PIT) + && Sokoban && !trap->madeby_u)); + + mlev_res = mlevel_tele_trap(mtmp, trap, inescapable, in_sight); + if (mlev_res) + return mlev_res; + } + return 0; +} + +static int +trapeffect_web(mtmp, trap, trflags) +struct monst *mtmp; +struct trap *trap; +unsigned trflags; +{ + if (mtmp == &g.youmonst) { + boolean webmsgok = (trflags & NOWEBMSG) == 0; + boolean forcetrap = ((trflags & FORCETRAP) != 0 + || (trflags & FAILEDUNTRAP) != 0); + boolean viasitting = (trflags & VIASITTING) != 0; + int steed_article = ARTICLE_THE; - case WEB: /* Our luckless player has stumbled into a web. */ feeltrap(trap); if (mu_maybe_destroy_web(&g.youmonst, webmsgok, trap)) - break; + return 0; if (webmaker(g.youmonst.data)) { if (webmsgok) pline(trap->madeby_u ? "You take a walk on your web." - : "There is a spider web here."); - break; + : "There is a spider web here."); + return 0; } if (webmsgok) { char verbbuf[BUFSZ]; @@ -1345,7 +1785,7 @@ unsigned trflags; } else { Sprintf(verbbuf, "%s into", Levitation ? (const char *) "float" - : locomotion(g.youmonst.data, "stumble")); + : locomotion(g.youmonst.data, "stumble")); } You("%s %s spider web!", verbbuf, a_your[trap->madeby_u]); } @@ -1378,7 +1818,7 @@ unsigned trflags; str = 17; } else { reset_utrap(FALSE); - break; + return 0; } webmsgok = FALSE; /* mintrap printed the messages */ @@ -1406,13 +1846,95 @@ unsigned trflags; } set_utrap((unsigned) tim, TT_WEB); } - break; + } else { + /* Monster in a web. */ + boolean tear_web; + boolean in_sight = canseemon(mtmp) || (mtmp == u.usteed); + struct permonst *mptr = mtmp->data; - case STATUE_TRAP: + if (webmaker(mptr)) + return 0; + if (mu_maybe_destroy_web(mtmp, in_sight, trap)) + return 0; + tear_web = FALSE; + switch (monsndx(mptr)) { + case PM_OWLBEAR: /* Eric Backus */ + case PM_BUGBEAR: + if (!in_sight) { + You_hear("the roaring of a confused bear!"); + mtmp->mtrapped = 1; + break; + } + /*FALLTHRU*/ + default: + if (mptr->mlet == S_GIANT + /* exclude baby dragons and relatively short worms */ + || (mptr->mlet == S_DRAGON && extra_nasty(mptr)) + || (mtmp->wormno && count_wsegs(mtmp) > 5)) { + tear_web = TRUE; + } else if (in_sight) { + pline("%s is caught in %s spider web.", Monnam(mtmp), + a_your[trap->madeby_u]); + seetrap(trap); + } + mtmp->mtrapped = tear_web ? 0 : 1; + break; + /* this list is fairly arbitrary; it deliberately + excludes wumpus & giant/ettin zombies/mummies */ + case PM_TITANOTHERE: + case PM_BALUCHITHERIUM: + case PM_PURPLE_WORM: + case PM_JABBERWOCK: + case PM_IRON_GOLEM: + case PM_BALROG: + case PM_KRAKEN: + case PM_MASTODON: + case PM_ORION: + case PM_NORN: + case PM_CYCLOPS: + case PM_LORD_SURTUR: + tear_web = TRUE; + break; + } + if (tear_web) { + if (in_sight) + pline("%s tears through %s spider web!", Monnam(mtmp), + a_your[trap->madeby_u]); + deltrap(trap); + newsym(mtmp->mx, mtmp->my); + } else if (g.force_mintrap && !mtmp->mtrapped) { + if (in_sight) { + pline("%s avoids %s spider web!", Monnam(mtmp), + a_your[trap->madeby_u]); + seetrap(trap); + } + } + return mtmp->mtrapped; + } + return 0; +} + +static int +trapeffect_statue_trap(mtmp, trap, trflags) +struct monst *mtmp; +struct trap *trap; +unsigned trflags UNUSED; +{ + if (mtmp == &g.youmonst) { (void) activate_statue_trap(trap, u.ux, u.uy, FALSE); - break; + } else { + /* monsters don't trigger statue traps */ + } + return 0; +} - case MAGIC_TRAP: /* A magic trap. */ +static int +trapeffect_magic_trap(mtmp, trap, trflags) +struct monst *mtmp; +struct trap *trap; +unsigned trflags; +{ + if (mtmp == &g.youmonst) { seetrap(trap); if (!rn2(30)) { deltrap(trap); @@ -1421,14 +1943,26 @@ unsigned trflags; losehp(rnd(10), "magical explosion", KILLED_BY_AN); Your("body absorbs some of the magical energy!"); u.uen = (u.uenmax += 2); - break; + return 0; } else { domagictrap(); } (void) steedintrap(trap, (struct obj *) 0); - break; + } else { + /* A magic trap. Monsters usually immune. */ + if (!rn2(21)) + return trapeffect_fire_trap(mtmp, trap, trflags); + } + return 0; +} - case ANTI_MAGIC: +static int +trapeffect_anti_magic(mtmp, trap, trflags) +struct monst *mtmp; +struct trap *trap; +unsigned trflags UNUSED; +{ + if (mtmp == &g.youmonst) { seetrap(trap); /* hero without magic resistance loses spell energy, hero with magic resistance takes damage instead; @@ -1436,6 +1970,7 @@ unsigned trflags; if (!Antimagic) { drain_en(rnd(u.ulevel) + 1); } else { + struct obj *otmp; int dmgval2 = rnd(4), hp = Upolyd ? u.mh : u.uhp; /* Half_XXX_damage has opposite its usual effect (approx) @@ -1458,14 +1993,71 @@ unsigned trflags; dmgval2 = (dmgval2 + 3) / 4; You_feel((dmgval2 >= hp) ? "unbearably torpid!" - : (dmgval2 >= hp / 4) ? "very lethargic." - : "sluggish."); + : (dmgval2 >= hp / 4) ? "very lethargic." + : "sluggish."); /* opposite of magical explosion */ losehp(dmgval2, "anti-magic implosion", KILLED_BY_AN); } - break; + } else { + boolean trapkilled = FALSE; + boolean in_sight = canseemon(mtmp) || (mtmp == u.usteed); + boolean see_it = cansee(mtmp->mx, mtmp->my); + struct permonst *mptr = mtmp->data; - case POLY_TRAP: { + /* similar to hero's case, more or less */ + if (!resists_magm(mtmp)) { /* lose spell energy */ + if (!mtmp->mcan && (attacktype(mptr, AT_MAGC) + || attacktype(mptr, AT_BREA))) { + mtmp->mspec_used += d(2, 2); + if (in_sight) { + seetrap(trap); + pline("%s seems lethargic.", Monnam(mtmp)); + } + } + } else { /* take some damage */ + struct obj *otmp; + int dmgval2 = rnd(4); + + if ((otmp = MON_WEP(mtmp)) != 0 + && otmp->oartifact == ART_MAGICBANE) + dmgval2 += rnd(4); + for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj) + if (otmp->oartifact + && defends_when_carried(AD_MAGM, otmp)) + break; + if (otmp) + dmgval2 += rnd(4); + if (passes_walls(mptr)) + dmgval2 = (dmgval2 + 3) / 4; + + if (in_sight) + seetrap(trap); + mtmp->mhp -= dmgval2; + if (DEADMONSTER(mtmp)) + monkilled(mtmp, + in_sight + ? "compression from an anti-magic field" + : (const char *) 0, + -AD_MAGM); + if (DEADMONSTER(mtmp)) + trapkilled = TRUE; + if (see_it) + newsym(trap->tx, trap->ty); + } + return trapkilled ? 2 : mtmp->mtrapped; + } + return 0; +} + +static int +trapeffect_poly_trap(mtmp, trap, trflags) +struct monst *mtmp; +struct trap *trap; +unsigned trflags; +{ + if (mtmp == &g.youmonst) { + boolean viasitting = (trflags & VIASITTING) != 0; + int steed_article = ARTICLE_THE; char verbbuf[BUFSZ]; seetrap(trap); @@ -1478,7 +2070,7 @@ unsigned trflags; else Sprintf(verbbuf, "%s onto", Levitation ? (const char *) "float" - : locomotion(g.youmonst.data, "step")); + : locomotion(g.youmonst.data, "step")); You("%s a polymorph trap!", verbbuf); if (Antimagic || Unchanging) { shieldeff(u.ux, u.uy); @@ -1491,24 +2083,46 @@ unsigned trflags; You_feel("a change coming over you."); polyself(0); } - break; + } else { + boolean in_sight = canseemon(mtmp) || (mtmp == u.usteed); + + if (resists_magm(mtmp)) { + shieldeff(mtmp->mx, mtmp->my); + } else if (!resist(mtmp, WAND_CLASS, 0, NOTELL)) { + (void) newcham(mtmp, (struct permonst *) 0, FALSE, FALSE); + if (in_sight) + seetrap(trap); + } } - case LANDMINE: { + return 0; +} + +static int +trapeffect_landmine(mtmp, trap, trflags) +struct monst *mtmp; +struct trap *trap; +unsigned trflags; +{ + if (mtmp == &g.youmonst) { + boolean already_seen = trap->tseen; + boolean forcetrap = ((trflags & FORCETRAP) != 0 + || (trflags & FAILEDUNTRAP) != 0); + boolean forcebungle = (trflags & FORCEBUNGLE) != 0; unsigned steed_mid = 0; struct obj *saddle = 0; if ((Levitation || Flying) && !forcetrap) { if (!already_seen && rn2(3)) - break; + return 0; feeltrap(trap); pline("%s %s in a pile of soil below you.", already_seen ? "There is" : "You discover", trap->madeby_u ? "the trigger of your mine" : "a trigger"); if (already_seen && rn2(3)) - break; + return 0; pline("KAABLAMM!!! %s %s%s off!", forcebungle ? "Your inept attempt sets" - : "The air currents set", + : "The air currents set", already_seen ? a_your[trap->madeby_u] : "", already_seen ? " land mine" : "it"); } else { @@ -1519,7 +2133,7 @@ unsigned trflags; static boolean recursive_mine = FALSE; if (recursive_mine) - break; + return 0; feeltrap(trap); pline("KAABLAMM!!! You triggered %s land mine!", a_your[trap->madeby_u]); @@ -1542,10 +2156,69 @@ unsigned trflags; if ((trap = t_at(u.ux, u.uy)) != 0) dotrap(trap, RECURSIVETRAP); fill_pit(u.ux, u.uy); - break; - } + } else { + boolean trapkilled = FALSE; + boolean in_sight = canseemon(mtmp) || (mtmp == u.usteed); + struct permonst *mptr = mtmp->data; + xchar tx = trap->tx, ty = trap->ty; - case ROLLING_BOULDER_TRAP: { + if (rn2(3)) + return 0; /* monsters usually don't set it off */ + if (is_flyer(mptr)) { + boolean already_seen = trap->tseen; + + if (in_sight && !already_seen) { + pline("A trigger appears in a pile of soil below %s.", + mon_nam(mtmp)); + seetrap(trap); + } + if (rn2(3)) + return 0; + if (in_sight) { + newsym(mtmp->mx, mtmp->my); + pline_The("air currents set %s off!", + already_seen ? "a land mine" : "it"); + } + } else if (in_sight) { + newsym(mtmp->mx, mtmp->my); + pline("%s%s triggers %s land mine!", + !Deaf ? "KAABLAMM!!! " : "", Monnam(mtmp), + a_your[trap->madeby_u]); + } + if (!in_sight && !Deaf) + pline("Kaablamm! %s an explosion in the distance!", + "You hear"); /* Deaf-aware */ + blow_up_landmine(trap); + /* explosion might have destroyed a drawbridge; don't + dish out more damage if monster is already dead */ + if (DEADMONSTER(mtmp) + || thitm(0, mtmp, (struct obj *) 0, rnd(16), FALSE)) { + trapkilled = TRUE; + } else { + /* monsters recursively fall into new pit */ + if (mintrap(mtmp) == 2) + trapkilled = TRUE; + } + /* a boulder may fill the new pit, crushing monster */ + fill_pit(tx, ty); /* thitm may have already destroyed the trap */ + if (DEADMONSTER(mtmp)) + trapkilled = TRUE; + if (unconscious()) { + g.multi = -1; + g.nomovemsg = "The explosion awakens you!"; + } + return trapkilled ? 2 : mtmp->mtrapped; + } + return 0; +} + +static int +trapeffect_rolling_boulder_trap(mtmp, trap, trflags) +struct monst *mtmp; +struct trap *trap; +unsigned trflags UNUSED; +{ + if (mtmp == &g.youmonst) { int style = ROLL | (trap->tseen ? LAUNCH_KNOWN : 0); feeltrap(trap); @@ -1556,24 +2229,217 @@ unsigned trflags; newsym(u.ux, u.uy); /* get rid of trap symbol */ pline("Fortunately for you, no boulder was released."); } - break; - } + } else { + struct permonst *mptr = mtmp->data; - case MAGIC_PORTAL: + if (!is_flyer(mptr)) { + boolean in_sight = canseemon(mtmp) || (mtmp == u.usteed); + int style = ROLL | (in_sight ? 0 : LAUNCH_UNSEEN); + boolean trapkilled = FALSE; + + newsym(mtmp->mx, mtmp->my); + if (in_sight) + pline("Click! %s triggers %s.", Monnam(mtmp), + trap->tseen ? "a rolling boulder trap" : something); + if (launch_obj(BOULDER, trap->launch.x, trap->launch.y, + trap->launch2.x, trap->launch2.y, style)) { + if (in_sight) + trap->tseen = TRUE; + if (DEADMONSTER(mtmp)) + trapkilled = TRUE; + } else { + deltrap(trap); + newsym(mtmp->mx, mtmp->my); + } + return trapkilled ? 2 : mtmp->mtrapped; + } + } + return 0; +} + +static int +trapeffect_magic_portal(mtmp, trap, trflags) +struct monst *mtmp; +struct trap *trap; +unsigned trflags; +{ + if (mtmp == &g.youmonst) { feeltrap(trap); domagicportal(trap); - break; + } else { + return trapeffect_level_telep(mtmp, trap, trflags); + } + return 0; +} - case VIBRATING_SQUARE: +static int +trapeffect_vibrating_square(mtmp, trap, trflags) +struct monst *mtmp; +struct trap *trap; +unsigned trflags UNUSED; +{ + if (mtmp == &g.youmonst) { feeltrap(trap); /* messages handled elsewhere; the trap symbol is merely to mark the * square for future reference */ - break; + } else { + boolean in_sight = canseemon(mtmp) || (mtmp == u.usteed); + boolean see_it = cansee(mtmp->mx, mtmp->my); - default: - feeltrap(trap); - impossible("You hit a trap of type %u", trap->ttyp); + if (see_it && !Blind) { + seetrap(trap); /* before messages */ + if (in_sight) { + char buf[BUFSZ], *p, *monnm = mon_nam(mtmp); + + if (nolimbs(mtmp->data) + || is_floater(mtmp->data) || is_flyer(mtmp->data)) { + /* just "beneath " */ + Strcpy(buf, monnm); + } else { + Strcpy(buf, s_suffix(monnm)); + p = eos(strcat(buf, " ")); + Strcpy(p, makeplural(mbodypart(mtmp, FOOT))); + /* avoid "beneath 'rear paws'" or 'rear hooves' */ + (void) strsubst(p, "rear ", ""); + } + You_see("a strange vibration beneath %s.", buf); + } else { + /* notice something (hearing uses a larger threshold + for 'nearby') */ + You_see("the ground vibrate %s.", + (distu(mtmp->mx, mtmp->my) <= 2 * 2) + ? "nearby" : "in the distance"); + } + } } + return 0; +} + +static int +trapeffect_selector(mtmp, trap, trflags) +struct monst *mtmp; +struct trap *trap; +unsigned trflags; +{ + switch (trap->ttyp) { + case ARROW_TRAP: + return trapeffect_arrow_trap(mtmp, trap, trflags); + case DART_TRAP: + return trapeffect_dart_trap(mtmp, trap, trflags); + case ROCKTRAP: + return trapeffect_rocktrap(mtmp, trap, trflags); + case SQKY_BOARD: + return trapeffect_sqky_board(mtmp, trap, trflags); + case BEAR_TRAP: + return trapeffect_bear_trap(mtmp, trap, trflags); + case SLP_GAS_TRAP: + return trapeffect_slp_gas_trap(mtmp, trap, trflags); + case RUST_TRAP: + return trapeffect_rust_trap(mtmp, trap, trflags); + case FIRE_TRAP: + return trapeffect_fire_trap(mtmp, trap, trflags); + case PIT: + case SPIKED_PIT: + return trapeffect_pit(mtmp, trap, trflags); + case HOLE: + case TRAPDOOR: + return trapeffect_hole(mtmp, trap, trflags); + case LEVEL_TELEP: + return trapeffect_level_telep(mtmp, trap, trflags); + case MAGIC_PORTAL: + return trapeffect_magic_portal(mtmp, trap, trflags); + case TELEP_TRAP: + return trapeffect_telep_trap(mtmp, trap, trflags); + case WEB: + return trapeffect_web(mtmp, trap, trflags); + case STATUE_TRAP: + return trapeffect_statue_trap(mtmp, trap, trflags); + case MAGIC_TRAP: + return trapeffect_magic_trap(mtmp, trap, trflags); + case ANTI_MAGIC: + return trapeffect_anti_magic(mtmp, trap, trflags); + case LANDMINE: + return trapeffect_landmine(mtmp, trap, trflags); + case POLY_TRAP: + return trapeffect_poly_trap(mtmp, trap, trflags); + case ROLLING_BOULDER_TRAP: + return trapeffect_rolling_boulder_trap(mtmp, trap, trflags); + case VIBRATING_SQUARE: + return trapeffect_vibrating_square(mtmp, trap, trflags); + default: + impossible("%s encountered a strange trap of type %d.", + (mtmp == &g.youmonst) ? "You" : "Some monster", + trap->ttyp); + } + return 0; +} + +void +dotrap(trap, trflags) +register struct trap *trap; +unsigned trflags; +{ + register int ttype = trap->ttyp; + boolean already_seen = trap->tseen, + forcetrap = ((trflags & FORCETRAP) != 0 + || (trflags & FAILEDUNTRAP) != 0), + forcebungle = (trflags & FORCEBUNGLE) != 0, + plunged = (trflags & TOOKPLUNGE) != 0, + conj_pit = conjoined_pits(trap, t_at(u.ux0, u.uy0), TRUE), + adj_pit = adj_nonconjoined_pit(trap); + int steed_article = ARTICLE_THE; + + nomul(0); + + /* KMH -- You can't escape the Sokoban level traps */ + if (Sokoban && (is_pit(ttype) || is_hole(ttype))) { + /* The "air currents" message is still appropriate -- even when + * the hero isn't flying or levitating -- because it conveys the + * reason why the player cannot escape the trap with a dexterity + * check, clinging to the ceiling, etc. + */ + pline("Air currents pull you down into %s %s!", + a_your[trap->madeby_u], + trapname(ttype, TRUE)); /* do force "pit" while hallucinating */ + /* then proceed to normal trap effect */ + } else if (already_seen && !forcetrap) { + if ((Levitation || (Flying && !plunged)) + && (is_pit(ttype) || ttype == HOLE || ttype == BEAR_TRAP)) { + You("%s over %s %s.", Levitation ? "float" : "fly", + a_your[trap->madeby_u], + trapname(ttype, FALSE)); + return; + } + if (!Fumbling && ttype != MAGIC_PORTAL && ttype != VIBRATING_SQUARE + && ttype != ANTI_MAGIC && !forcebungle && !plunged + && !conj_pit && !adj_pit + && (!rn2(5) || (is_pit(ttype) + && is_clinger(g.youmonst.data)))) { + You("escape %s %s.", (ttype == ARROW_TRAP && !trap->madeby_u) + ? "an" + : a_your[trap->madeby_u], + trapname(ttype, FALSE)); + return; + } + } + + if (u.usteed) { + u.usteed->mtrapseen |= (1 << (ttype - 1)); + /* suppress article in various steed messages when using its + name (which won't occur when hallucinating) */ + if (has_mgivenname(u.usteed) && !Hallucination) + steed_article = ARTICLE_NONE; + } + + /* + * Note: + * Most references to trap types here don't use trapname() for + * hallucination. This could be considered to be a bug but doing + * that would hide the actual trap situation from the player which + * would be somewhat harsh for what's usually a minor impairment. + */ + + (void) trapeffect_selector(&g.youmonst, trap, trflags); } static char * @@ -2139,7 +3005,6 @@ register struct monst *mtmp; register struct trap *trap = t_at(mtmp->mx, mtmp->my); boolean trapkilled = FALSE; struct permonst *mptr = mtmp->data; - struct obj *otmp; if (!trap) { mtmp->mtrapped = 0; /* perhaps teleported? */ @@ -2182,12 +3047,10 @@ register struct monst *mtmp; } } else { register int tt = trap->ttyp; - boolean in_sight, tear_web, see_it, + boolean in_sight, see_it, inescapable = (g.force_mintrap || ((tt == HOLE || tt == PIT) && Sokoban && !trap->madeby_u)); - const char *fallverb; - xchar tx = trap->tx, ty = trap->ty; /* true when called from dotrap, inescapable is not an option */ if (mtmp == u.usteed) @@ -2211,535 +3074,8 @@ register struct monst *mtmp; /* assume hero can tell what's going on for the steed */ if (mtmp == u.usteed) in_sight = TRUE; - switch (tt) { - case ARROW_TRAP: - if (trap->once && trap->tseen && !rn2(15)) { - if (in_sight && see_it) - pline("%s triggers a trap but nothing happens.", - Monnam(mtmp)); - deltrap(trap); - newsym(mtmp->mx, mtmp->my); - break; - } - trap->once = 1; - otmp = t_missile(ARROW, trap); - if (in_sight) - seetrap(trap); - if (thitm(8, mtmp, otmp, 0, FALSE)) - trapkilled = TRUE; - break; - case DART_TRAP: - if (trap->once && trap->tseen && !rn2(15)) { - if (in_sight && see_it) - pline("%s triggers a trap but nothing happens.", - Monnam(mtmp)); - deltrap(trap); - newsym(mtmp->mx, mtmp->my); - break; - } - trap->once = 1; - otmp = t_missile(DART, trap); - if (!rn2(6)) - otmp->opoisoned = 1; - if (in_sight) - seetrap(trap); - if (thitm(7, mtmp, otmp, 0, FALSE)) - trapkilled = TRUE; - break; - case ROCKTRAP: - if (trap->once && trap->tseen && !rn2(15)) { - if (in_sight && see_it) - pline("A trap door above %s opens, but nothing falls out!", - mon_nam(mtmp)); - deltrap(trap); - newsym(mtmp->mx, mtmp->my); - break; - } - trap->once = 1; - otmp = t_missile(ROCK, trap); - if (in_sight) - seetrap(trap); - if (thitm(0, mtmp, otmp, d(2, 6), FALSE)) - trapkilled = TRUE; - break; - case SQKY_BOARD: - if (is_flyer(mptr)) - break; - /* stepped on a squeaky board */ - if (in_sight) { - if (!Deaf) { - pline("A board beneath %s squeaks %s loudly.", - mon_nam(mtmp), trapnote(trap, 0)); - seetrap(trap); - } else { - pline("%s stops momentarily and appears to cringe.", - Monnam(mtmp)); - } - } else { - /* same near/far threshold as mzapmsg() */ - int range = couldsee(mtmp->mx, mtmp->my) /* 9 or 5 */ - ? (BOLT_LIM + 1) : (BOLT_LIM - 3); - You_hear("a %s squeak %s.", trapnote(trap, 1), - (distu(mtmp->mx, mtmp->my) <= range * range) - ? "nearby" : "in the distance"); - } - /* wake up nearby monsters */ - wake_nearto(mtmp->mx, mtmp->my, 40); - break; - case BEAR_TRAP: - if (mptr->msize > MZ_SMALL && !amorphous(mptr) && !is_flyer(mptr) - && !is_whirly(mptr) && !unsolid(mptr)) { - mtmp->mtrapped = 1; - if (in_sight) { - pline("%s is caught in %s bear trap!", Monnam(mtmp), - a_your[trap->madeby_u]); - seetrap(trap); - } else { - if (mptr == &mons[PM_OWLBEAR] - || mptr == &mons[PM_BUGBEAR]) - You_hear("the roaring of an angry bear!"); - } - } else if (g.force_mintrap) { - if (in_sight) { - pline("%s evades %s bear trap!", Monnam(mtmp), - a_your[trap->madeby_u]); - seetrap(trap); - } - } - if (mtmp->mtrapped) - trapkilled = thitm(0, mtmp, (struct obj *) 0, d(2, 4), FALSE); - break; - case SLP_GAS_TRAP: - if (!resists_sleep(mtmp) && !breathless(mptr) && !mtmp->msleeping - && mtmp->mcanmove) { - if (sleep_monst(mtmp, rnd(25), -1) && in_sight) { - pline("%s suddenly falls asleep!", Monnam(mtmp)); - seetrap(trap); - } - } - break; - case RUST_TRAP: { - struct obj *target; - - if (in_sight) - seetrap(trap); - switch (rn2(5)) { - case 0: - if (in_sight) - pline("%s %s on the %s!", A_gush_of_water_hits, - mon_nam(mtmp), mbodypart(mtmp, HEAD)); - target = which_armor(mtmp, W_ARMH); - (void) water_damage(target, helm_simple_name(target), TRUE); - break; - case 1: - if (in_sight) - pline("%s %s's left %s!", A_gush_of_water_hits, - mon_nam(mtmp), mbodypart(mtmp, ARM)); - target = which_armor(mtmp, W_ARMS); - if (water_damage(target, "shield", TRUE) != ER_NOTHING) - break; - target = MON_WEP(mtmp); - if (target && bimanual(target)) - (void) water_damage(target, 0, TRUE); - glovecheck: - target = which_armor(mtmp, W_ARMG); - (void) water_damage(target, "gauntlets", TRUE); - break; - case 2: - if (in_sight) - pline("%s %s's right %s!", A_gush_of_water_hits, - mon_nam(mtmp), mbodypart(mtmp, ARM)); - (void) water_damage(MON_WEP(mtmp), 0, TRUE); - goto glovecheck; - default: - if (in_sight) - pline("%s %s!", A_gush_of_water_hits, mon_nam(mtmp)); - for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj) - if (otmp->lamplit - && (otmp->owornmask & (W_WEP | W_SWAPWEP)) == 0) - (void) snuff_lit(otmp); - if ((target = which_armor(mtmp, W_ARMC)) != 0) - (void) water_damage(target, cloak_simple_name(target), - TRUE); - else if ((target = which_armor(mtmp, W_ARM)) != 0) - (void) water_damage(target, suit_simple_name(target), - TRUE); - else if ((target = which_armor(mtmp, W_ARMU)) != 0) - (void) water_damage(target, "shirt", TRUE); - } - - if (mptr == &mons[PM_IRON_GOLEM]) { - if (in_sight) - pline("%s falls to pieces!", Monnam(mtmp)); - else if (mtmp->mtame) - pline("May %s rust in peace.", mon_nam(mtmp)); - mondied(mtmp); - if (DEADMONSTER(mtmp)) - trapkilled = TRUE; - } else if (mptr == &mons[PM_GREMLIN] && rn2(3)) { - (void) split_mon(mtmp, (struct monst *) 0); - } - break; - } /* RUST_TRAP */ - case FIRE_TRAP: - mfiretrap: - if (in_sight) - pline("A %s erupts from the %s under %s!", tower_of_flame, - surface(mtmp->mx, mtmp->my), mon_nam(mtmp)); - else if (see_it) /* evidently `mtmp' is invisible */ - You_see("a %s erupt from the %s!", tower_of_flame, - surface(mtmp->mx, mtmp->my)); - - if (resists_fire(mtmp)) { - if (in_sight) { - shieldeff(mtmp->mx, mtmp->my); - pline("%s is uninjured.", Monnam(mtmp)); - } - } else { - int num = d(2, 4), alt; - boolean immolate = FALSE; - - /* paper burns very fast, assume straw is tightly - * packed and burns a bit slower */ - switch (monsndx(mptr)) { - case PM_PAPER_GOLEM: - immolate = TRUE; - alt = mtmp->mhpmax; - break; - case PM_STRAW_GOLEM: - alt = mtmp->mhpmax / 2; - break; - case PM_WOOD_GOLEM: - alt = mtmp->mhpmax / 4; - break; - case PM_LEATHER_GOLEM: - alt = mtmp->mhpmax / 8; - break; - default: - alt = 0; - break; - } - if (alt > num) - num = alt; - - if (thitm(0, mtmp, (struct obj *) 0, num, immolate)) - trapkilled = TRUE; - else - /* we know mhp is at least `num' below mhpmax, - so no (mhp > mhpmax) check is needed here */ - mtmp->mhpmax -= rn2(num + 1); - } - if (burnarmor(mtmp) || rn2(3)) { - (void) destroy_mitem(mtmp, SCROLL_CLASS, AD_FIRE); - (void) destroy_mitem(mtmp, SPBOOK_CLASS, AD_FIRE); - (void) destroy_mitem(mtmp, POTION_CLASS, AD_FIRE); - } - if (burn_floor_objects(mtmp->mx, mtmp->my, see_it, FALSE) - && !see_it && distu(mtmp->mx, mtmp->my) <= 3 * 3) - You("smell smoke."); - if (is_ice(mtmp->mx, mtmp->my)) - melt_ice(mtmp->mx, mtmp->my, (char *) 0); - if (see_it && t_at(mtmp->mx, mtmp->my)) - seetrap(trap); - break; - case PIT: - case SPIKED_PIT: - fallverb = "falls"; - if (is_flyer(mptr) || is_floater(mptr) - || (mtmp->wormno && count_wsegs(mtmp) > 5) - || is_clinger(mptr)) { - if (g.force_mintrap && !Sokoban) { - /* openfallingtrap; not inescapable here */ - if (in_sight) { - seetrap(trap); - pline("%s doesn't fall into the pit.", Monnam(mtmp)); - } - break; /* inescapable = FALSE; */ - } - if (!inescapable) - break; /* avoids trap */ - fallverb = "is dragged"; /* sokoban pit */ - } - if (!passes_walls(mptr)) - mtmp->mtrapped = 1; - if (in_sight) { - pline("%s %s into %s pit!", Monnam(mtmp), fallverb, - a_your[trap->madeby_u]); - if (mptr == &mons[PM_PIT_VIPER] - || mptr == &mons[PM_PIT_FIEND]) - pline("How pitiful. Isn't that the pits?"); - seetrap(trap); - } - mselftouch(mtmp, "Falling, ", FALSE); - if (DEADMONSTER(mtmp) || thitm(0, mtmp, (struct obj *) 0, - rnd((tt == PIT) ? 6 : 10), FALSE)) - trapkilled = TRUE; - break; - case HOLE: - case TRAPDOOR: - if (!Can_fall_thru(&u.uz)) { - impossible("mintrap: %ss cannot exist on this level.", - trapname(tt, TRUE)); - break; /* don't activate it after all */ - } - if (is_flyer(mptr) || is_floater(mptr) || mptr == &mons[PM_WUMPUS] - || (mtmp->wormno && count_wsegs(mtmp) > 5) - || mptr->msize >= MZ_HUGE) { - if (g.force_mintrap && !Sokoban) { - /* openfallingtrap; not inescapable here */ - if (in_sight) { - seetrap(trap); - if (tt == TRAPDOOR) - pline( - "A trap door opens, but %s doesn't fall through.", - mon_nam(mtmp)); - else /* (tt == HOLE) */ - pline("%s doesn't fall through the hole.", - Monnam(mtmp)); - } - break; /* inescapable = FALSE; */ - } - if (inescapable) { /* sokoban hole */ - if (in_sight) { - pline("%s seems to be yanked down!", Monnam(mtmp)); - /* suppress message in mlevel_tele_trap() */ - in_sight = FALSE; - seetrap(trap); - } - } else - break; - } - /*FALLTHRU*/ - case LEVEL_TELEP: - case MAGIC_PORTAL: { - int mlev_res; - - mlev_res = mlevel_tele_trap(mtmp, trap, inescapable, in_sight); - if (mlev_res) - return mlev_res; - break; - } - case TELEP_TRAP: - mtele_trap(mtmp, trap, in_sight); - break; - case WEB: - /* Monster in a web. */ - if (webmaker(mptr)) - break; - if (mu_maybe_destroy_web(mtmp, in_sight, trap)) - break; - tear_web = FALSE; - switch (monsndx(mptr)) { - case PM_OWLBEAR: /* Eric Backus */ - case PM_BUGBEAR: - if (!in_sight) { - You_hear("the roaring of a confused bear!"); - mtmp->mtrapped = 1; - break; - } - /*FALLTHRU*/ - default: - if (mptr->mlet == S_GIANT - /* exclude baby dragons and relatively short worms */ - || (mptr->mlet == S_DRAGON && extra_nasty(mptr)) - || (mtmp->wormno && count_wsegs(mtmp) > 5)) { - tear_web = TRUE; - } else if (in_sight) { - pline("%s is caught in %s spider web.", Monnam(mtmp), - a_your[trap->madeby_u]); - seetrap(trap); - } - mtmp->mtrapped = tear_web ? 0 : 1; - break; - /* this list is fairly arbitrary; it deliberately - excludes wumpus & giant/ettin zombies/mummies */ - case PM_TITANOTHERE: - case PM_BALUCHITHERIUM: - case PM_PURPLE_WORM: - case PM_JABBERWOCK: - case PM_IRON_GOLEM: - case PM_BALROG: - case PM_KRAKEN: - case PM_MASTODON: - case PM_ORION: - case PM_NORN: - case PM_CYCLOPS: - case PM_LORD_SURTUR: - tear_web = TRUE; - break; - } - if (tear_web) { - if (in_sight) - pline("%s tears through %s spider web!", Monnam(mtmp), - a_your[trap->madeby_u]); - deltrap(trap); - newsym(mtmp->mx, mtmp->my); - } else if (g.force_mintrap && !mtmp->mtrapped) { - if (in_sight) { - pline("%s avoids %s spider web!", Monnam(mtmp), - a_your[trap->madeby_u]); - seetrap(trap); - } - } - break; - case STATUE_TRAP: - break; - case MAGIC_TRAP: - /* A magic trap. Monsters usually immune. */ - if (!rn2(21)) - goto mfiretrap; - break; - case ANTI_MAGIC: - /* similar to hero's case, more or less */ - if (!resists_magm(mtmp)) { /* lose spell energy */ - if (!mtmp->mcan && (attacktype(mptr, AT_MAGC) - || attacktype(mptr, AT_BREA))) { - mtmp->mspec_used += d(2, 2); - if (in_sight) { - seetrap(trap); - pline("%s seems lethargic.", Monnam(mtmp)); - } - } - } else { /* take some damage */ - int dmgval2 = rnd(4); - - if ((otmp = MON_WEP(mtmp)) != 0 - && otmp->oartifact == ART_MAGICBANE) - dmgval2 += rnd(4); - for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj) - if (otmp->oartifact - && defends_when_carried(AD_MAGM, otmp)) - break; - if (otmp) - dmgval2 += rnd(4); - if (passes_walls(mptr)) - dmgval2 = (dmgval2 + 3) / 4; - - if (in_sight) - seetrap(trap); - mtmp->mhp -= dmgval2; - if (DEADMONSTER(mtmp)) - monkilled(mtmp, - in_sight - ? "compression from an anti-magic field" - : (const char *) 0, - -AD_MAGM); - if (DEADMONSTER(mtmp)) - trapkilled = TRUE; - if (see_it) - newsym(trap->tx, trap->ty); - } - break; - case LANDMINE: - if (rn2(3)) - break; /* monsters usually don't set it off */ - if (is_flyer(mptr)) { - boolean already_seen = trap->tseen; - - if (in_sight && !already_seen) { - pline("A trigger appears in a pile of soil below %s.", - mon_nam(mtmp)); - seetrap(trap); - } - if (rn2(3)) - break; - if (in_sight) { - newsym(mtmp->mx, mtmp->my); - pline_The("air currents set %s off!", - already_seen ? "a land mine" : "it"); - } - } else if (in_sight) { - newsym(mtmp->mx, mtmp->my); - pline("%s%s triggers %s land mine!", - !Deaf ? "KAABLAMM!!! " : "", Monnam(mtmp), - a_your[trap->madeby_u]); - } - if (!in_sight && !Deaf) - pline("Kaablamm! %s an explosion in the distance!", - "You hear"); /* Deaf-aware */ - blow_up_landmine(trap); - /* explosion might have destroyed a drawbridge; don't - dish out more damage if monster is already dead */ - if (DEADMONSTER(mtmp) - || thitm(0, mtmp, (struct obj *) 0, rnd(16), FALSE)) { - trapkilled = TRUE; - } else { - /* monsters recursively fall into new pit */ - if (mintrap(mtmp) == 2) - trapkilled = TRUE; - } - /* a boulder may fill the new pit, crushing monster */ - fill_pit(tx, ty); /* thitm may have already destroyed the trap */ - if (DEADMONSTER(mtmp)) - trapkilled = TRUE; - if (unconscious()) { - g.multi = -1; - g.nomovemsg = "The explosion awakens you!"; - } - break; - case POLY_TRAP: - if (resists_magm(mtmp)) { - shieldeff(mtmp->mx, mtmp->my); - } else if (!resist(mtmp, WAND_CLASS, 0, NOTELL)) { - if (newcham(mtmp, (struct permonst *) 0, FALSE, FALSE)) - /* we're done with mptr but keep it up to date */ - mptr = mtmp->data; - if (in_sight) - seetrap(trap); - } - break; - case ROLLING_BOULDER_TRAP: - if (!is_flyer(mptr)) { - int style = ROLL | (in_sight ? 0 : LAUNCH_UNSEEN); - - newsym(mtmp->mx, mtmp->my); - if (in_sight) - pline("Click! %s triggers %s.", Monnam(mtmp), - trap->tseen ? "a rolling boulder trap" : something); - if (launch_obj(BOULDER, trap->launch.x, trap->launch.y, - trap->launch2.x, trap->launch2.y, style)) { - if (in_sight) - trap->tseen = TRUE; - if (DEADMONSTER(mtmp)) - trapkilled = TRUE; - } else { - deltrap(trap); - newsym(mtmp->mx, mtmp->my); - } - } - break; - case VIBRATING_SQUARE: - if (see_it && !Blind) { - seetrap(trap); /* before messages */ - if (in_sight) { - char buf[BUFSZ], *p, *monnm = mon_nam(mtmp); - - if (nolimbs(mtmp->data) - || is_floater(mtmp->data) || is_flyer(mtmp->data)) { - /* just "beneath " */ - Strcpy(buf, monnm); - } else { - Strcpy(buf, s_suffix(monnm)); - p = eos(strcat(buf, " ")); - Strcpy(p, makeplural(mbodypart(mtmp, FOOT))); - /* avoid "beneath 'rear paws'" or 'rear hooves' */ - (void) strsubst(p, "rear ", ""); - } - You_see("a strange vibration beneath %s.", buf); - } else { - /* notice something (hearing uses a larger threshold - for 'nearby') */ - You_see("the ground vibrate %s.", - (distu(mtmp->mx, mtmp->my) <= 2 * 2) - ? "nearby" : "in the distance"); - } - } - break; - default: - impossible("Some monster encountered a strange trap of type %d.", - tt); - } + return trapeffect_selector(mtmp, trap, 0); } if (trapkilled) return 2; @@ -2797,8 +3133,10 @@ const char *arg; if (uwep && uwep->otyp == CORPSE && touch_petrifies(&mons[uwep->corpsenm]) && !Stone_resistance) { - pline("%s touch the %s corpse.", arg, mons[uwep->corpsenm].mname); - Sprintf(kbuf, "%s corpse", an(mons[uwep->corpsenm].mname)); + pline("%s touch the %s corpse.", arg, + mons[uwep->corpsenm].pmnames[NEUTRAL]); + Sprintf(kbuf, "%s corpse", + an(mons[uwep->corpsenm].pmnames[NEUTRAL])); instapetrify(kbuf); /* life-saved; unwield the corpse if we can't handle it */ if (!uarmg && !Stone_resistance) @@ -2808,8 +3146,10 @@ const char *arg; allow two-weapon combat when either weapon is a corpse] */ if (u.twoweap && uswapwep && uswapwep->otyp == CORPSE && touch_petrifies(&mons[uswapwep->corpsenm]) && !Stone_resistance) { - pline("%s touch the %s corpse.", arg, mons[uswapwep->corpsenm].mname); - Sprintf(kbuf, "%s corpse", an(mons[uswapwep->corpsenm].mname)); + pline("%s touch the %s corpse.", arg, + mons[uswapwep->corpsenm].pmnames[NEUTRAL]); + Sprintf(kbuf, "%s corpse", + an(mons[uswapwep->corpsenm].pmnames[NEUTRAL])); instapetrify(kbuf); /* life-saved; unwield the corpse */ if (!uarmg && !Stone_resistance) @@ -3196,6 +3536,7 @@ struct obj *box; /* null for floor trap */ destroy_item(SCROLL_CLASS, AD_FIRE); destroy_item(SPBOOK_CLASS, AD_FIRE); destroy_item(POTION_CLASS, AD_FIRE); + ignite_items(g.invent); } if (!box && burn_floor_objects(u.ux, u.uy, see_it, TRUE) && !see_it) You("smell paper burning."); @@ -3536,7 +3877,7 @@ boolean force; if (!obj) return ER_NOTHING; - if (snuff_lit(obj)) + if (splash_lit(obj)) return ER_DAMAGED; if (!ostr) @@ -3545,7 +3886,10 @@ boolean force; if (obj->otyp == CAN_OF_GREASE && obj->spe > 0) { return ER_NOTHING; } else if (obj->otyp == TOWEL && obj->spe < 7) { - wet_a_towel(obj, rnd(7), TRUE); + /* a negative change induces a reverse increment, adding abs(change); + spe starts 0..6, arg passed to rnd() is 1..7, change is -7..-1, + final spe is 1..7 and always greater than its starting value */ + wet_a_towel(obj, -rnd(7 - obj->spe), TRUE); return ER_NOTHING; } else if (obj->greased) { if (!rn2(2)) @@ -4332,7 +4676,8 @@ struct trap *ttmp; /* is it a cockatrice?... */ if (touch_petrifies(mtmp->data) && !uarmg && !Stone_resistance) { - You("grab the trapped %s using your bare %s.", mtmp->data->mname, + You("grab the trapped %s using your bare %s.", + pmname(mtmp->data, Mgender(mtmp)), makeplural(body_part(HAND))); if (poly_when_stoned(g.youmonst.data) && polymon(PM_STONE_GOLEM)) { @@ -4341,7 +4686,7 @@ struct trap *ttmp; char kbuf[BUFSZ]; Sprintf(kbuf, "trying to help %s out of a pit", - an(mtmp->data->mname)); + an(pmname(mtmp->data, Mgender(mtmp)))); instapetrify(kbuf); return 1; } @@ -5243,7 +5588,7 @@ boolean nocorpse; dam = 1; } mon->mhp -= dam; - if (DEADMONSTER(mon)) { + if (mon->mhp <= 0) { int xx = mon->mx, yy = mon->my; monkilled(mon, "", nocorpse ? -AD_RBRE : AD_PHYS); @@ -5400,6 +5745,7 @@ lava_effects() destroy_item(SCROLL_CLASS, AD_FIRE); destroy_item(SPBOOK_CLASS, AD_FIRE); destroy_item(POTION_CLASS, AD_FIRE); + ignite_items(g.invent); return FALSE; } @@ -5560,4 +5906,45 @@ boolean override; return defsyms[trap_to_defsym(ttyp)].explanation; } +/* Ignite ignitable items in the given object chain, due to some external + * source of fire. The object chain should be somewhere exposed, like + * someone's open inventory or the floor. + * This is modeled after destroy_item() somewhat and hopefully will be able to + * merge into it in the future. + */ +void +ignite_items(objchn) +struct obj *objchn; +{ + struct obj *obj; + boolean vis = FALSE; + if (!objchn) + return; + + if (objchn->where == OBJ_INVENT) + vis = TRUE; /* even when blind; lit-state can be seen in inventory */ + else if (objchn->where == OBJ_MINVENT) + vis = canseemon(objchn->ocarry); + else if (objchn->where == OBJ_FLOOR) + vis = cansee(objchn->ox, objchn->oy); + else { + impossible("igniting item in a weird location %d", objchn->where); + return; + } + + for (obj = objchn; obj; obj = obj->nobj) { + if (!ignitable(obj) + /* The Candelabrum requires intention to be lit */ + || obj->otyp == CANDELABRUM_OF_INVOCATION + || obj->otyp == BRASS_LANTERN /* doesn't ignite via fire */ + || obj->in_use /* not available */ + || obj->lamplit) { /* already burning */ + continue; + } + begin_burn(obj, FALSE); + if (vis) + pline("%s on fire!", Yobjnam2(obj, "catch")); + } +} + /*trap.c*/ diff --git a/src/u_init.c b/src/u_init.c index 4b0e9f74a..99be2a44d 100644 --- a/src/u_init.c +++ b/src/u_init.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 u_init.c $NHDT-Date: 1578855627 2020/01/12 19:00:27 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.67 $ */ +/* NetHack 3.7 u_init.c $NHDT-Date: 1606009005 2020/11/22 01:36:45 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.72 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2017. */ /* NetHack may be freely redistributed. See license for details. */ @@ -614,7 +614,7 @@ u_init() u.udg_cnt = 0; u.mh = u.mhmax = u.mtimedone = 0; u.uz.dnum = u.uz0.dnum = 0; - u.utotype = 0; + u.utotype = UTOTYPE_NONE; #endif /* 0 */ u.uz.dlevel = 1; @@ -688,7 +688,7 @@ u_init() knows_class(ARMOR_CLASS); skill_init(Skill_B); break; - case PM_CAVEMAN: + case PM_CAVE_DWELLER: Cave_man[C_AMMO].trquan = rn1(11, 10); /* 10..20 */ ini_inv(Cave_man); skill_init(Skill_C); @@ -724,7 +724,7 @@ u_init() skill_init(Skill_Mon); break; } - case PM_PRIEST: + case PM_CLERIC: ini_inv(Priest); if (!rn2(10)) ini_inv(Magicmarker); @@ -811,7 +811,7 @@ u_init() * Non-warriors get an instrument. We use a kludge to * get only non-magic instruments. */ - if (Role_if(PM_PRIEST) || Role_if(PM_WIZARD)) { + if (Role_if(PM_CLERIC) || Role_if(PM_WIZARD)) { static int trotyp[] = { WOODEN_FLUTE, TOOLED_HORN, WOODEN_HARP, BELL, BUGLE, LEATHER_DRUM }; Instrument[0].trotyp = trotyp[rn2(SIZE(trotyp))]; @@ -876,7 +876,7 @@ u_init() if (u.umoney0) ini_inv(Money); - u.umoney0 += hidden_gold(); /* in case sack has gold in it */ + u.umoney0 += hidden_gold(TRUE); /* in case sack has gold in it */ find_ac(); /* get initial ac value */ init_attr(75); /* init attribute values */ @@ -921,7 +921,7 @@ int otyp; case PM_BARBARIAN: skills = Skill_B; break; - case PM_CAVEMAN: + case PM_CAVE_DWELLER: skills = Skill_C; break; case PM_HEALER: @@ -933,7 +933,7 @@ int otyp; case PM_MONK: skills = Skill_Mon; break; - case PM_PRIEST: + case PM_CLERIC: skills = Skill_P; break; case PM_RANGER: diff --git a/src/uhitm.c b/src/uhitm.c index 59e32e61c..34896bdd0 100644 --- a/src/uhitm.c +++ b/src/uhitm.c @@ -1,18 +1,20 @@ -/* NetHack 3.6 uhitm.c $NHDT-Date: 1593306911 2020/06/28 01:15:11 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.237 $ */ +/* NetHack 3.7 uhitm.c $NHDT-Date: 1607076540 2020/12/04 10:09:00 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.288 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" +static const char brief_feeling[] = + "have a %s feeling for a moment, then it passes."; + static boolean FDECL(known_hitum, (struct monst *, struct obj *, int *, - int, int, struct attack *, int)); + int, int, struct attack *, int)); static boolean FDECL(theft_petrifies, (struct obj *)); static void FDECL(steal_it, (struct monst *, struct attack *)); static boolean FDECL(hitum_cleave, (struct monst *, struct attack *)); static boolean FDECL(hitum, (struct monst *, struct attack *)); -static boolean FDECL(hmon_hitmon, (struct monst *, struct obj *, int, - int)); +static boolean FDECL(hmon_hitmon, (struct monst *, struct obj *, int, int)); static int FDECL(joust, (struct monst *, struct obj *)); static void NDECL(demonpet); static boolean FDECL(m_slips_free, (struct monst *, struct attack *)); @@ -141,10 +143,10 @@ struct obj *wep; /* uwep for attack(), null for kick_monster() */ /* if it was an invisible mimic, treat it as if we stumbled * onto a visible mimic */ - if (M_AP_TYPE(mtmp) && !Protection_from_shape_changers - /* applied pole-arm attack is too far to get stuck */ - && distu(mtmp->mx, mtmp->my) <= 2) { - if (!u.ustuck && !mtmp->mflee && dmgtype(mtmp->data, AD_STCK)) + if (M_AP_TYPE(mtmp) && !Protection_from_shape_changers) { + if (!u.ustuck && !mtmp->mflee && dmgtype(mtmp->data, AD_STCK) + /* applied pole-arm attack is too far to get stuck */ + && distu(mtmp->mx, mtmp->my) <= 2) set_ustuck(mtmp); } /* #H7329 - if hero is on engraved "Elbereth", this will end up @@ -680,7 +682,7 @@ int dieroll; unpoisonmsg = FALSE; boolean silvermsg = FALSE, silverobj = FALSE; boolean lightobj = FALSE; - boolean valid_weapon_attack = FALSE; + boolean use_weapon_skill = FALSE, train_weapon_skill = FALSE; boolean unarmed = !uwep && !uarm && !uarms; boolean hand_to_hand = (thrown == HMON_MELEE /* not grapnels; applied implies uwep */ @@ -695,13 +697,16 @@ int dieroll; wakeup(mon, TRUE); if (!obj) { /* attack with bare hands */ - if (mdat == &mons[PM_SHADE]) + if (mdat == &mons[PM_SHADE]) { tmp = 0; - else if (martial_bonus()) - tmp = rnd(4); /* bonus for martial arts */ - else - tmp = rnd(2); - valid_weapon_attack = (tmp > 1); + } else { + /* note: 1..2 or 1..4 can be substantiallly increased by + strength bonus or skill bonus, usually both... */ + tmp = rnd(!martial_bonus() ? 2 : 4); + use_weapon_skill = TRUE; + train_weapon_skill = (tmp > 1); + } + /* Blessed gloves give bonuses when fighting 'bare-handed'. So do silver rings. Note: rings are worn under gloves, so you don't get both bonuses, and two silver rings don't give double bonus. */ @@ -711,6 +716,7 @@ int dieroll; + ((silverhit & W_RINGR) ? 1 : 0)); if (barehand_silver_rings > 0) silvermsg = TRUE; + } else { if (!(artifact_light(obj) && obj->lamplit)) Strcpy(saved_oname, cxname(obj)); @@ -728,7 +734,8 @@ int dieroll; /* or throw a missile without the proper bow... */ || (is_ammo(obj) && (thrown != HMON_THROWN || !ammo_and_launcher(obj, uwep)))) { - /* then do only 1-2 points of damage */ + /* then do only 1-2 points of damage and don't use or + train weapon's skill */ if (mdat == &mons[PM_SHADE] && !shade_glare(obj)) tmp = 0; else @@ -757,10 +764,13 @@ int dieroll; tmp++; } } else { + /* "normal" weapon usage */ + use_weapon_skill = TRUE; tmp = dmgval(obj, mon); /* a minimal hit doesn't exercise proficiency */ - valid_weapon_attack = (tmp > 1); - if (!valid_weapon_attack || mon == u.ustuck || u.twoweap + train_weapon_skill = (tmp > 1); + /* special attack actions */ + if (!train_weapon_skill || mon == u.ustuck || u.twoweap /* Cleaver can hit up to three targets at once so don't let it also hit from behind or shatter foes' weapons */ || (hand_to_hand && obj->oartifact == ART_CLEAVER)) { @@ -813,6 +823,7 @@ int dieroll; destroyed and they might do so */ if (DEADMONSTER(mon)) /* artifact killed monster */ return FALSE; + /* perhaps artifact tried to behead a headless monster */ if (tmp == 0) return TRUE; hittxt = TRUE; @@ -830,25 +841,27 @@ int dieroll; jousting = joust(mon, obj); /* exercise skill even for minimal damage hits */ if (jousting) - valid_weapon_attack = TRUE; + train_weapon_skill = TRUE; } if (thrown == HMON_THROWN && (is_ammo(obj) || is_missile(obj))) { if (ammo_and_launcher(obj, uwep)) { - /* Elves and Samurai do extra damage using - * their bows&arrows; they're highly trained. - */ + /* elves and samurai do extra damage using their own + bows with own arrows; they're highly trained */ if (Role_if(PM_SAMURAI) && obj->otyp == YA && uwep->otyp == YUMI) tmp++; else if (Race_if(PM_ELF) && obj->otyp == ELVEN_ARROW && uwep->otyp == ELVEN_BOW) tmp++; + train_weapon_skill = (tmp > 0); } if (obj->opoisoned && is_poisonable(obj)) ispoisoned = TRUE; } } + + /* attacking with non-weapons */ } else if (obj->oclass == POTION_CLASS) { if (obj->quan > 1L) obj = splitobj(obj, 1L); @@ -945,7 +958,7 @@ int dieroll; pline("Splat! You hit %s with %s %s egg%s!", mon_nam(mon), obj->known ? "the" : cnt > 1L ? "some" : "a", - obj->known ? mons[obj->corpsenm].mname + obj->known ? mons[obj->corpsenm].pmnames[NEUTRAL] : "petrifying", plur(cnt)); obj->known = 1; /* (not much point...) */ @@ -958,8 +971,8 @@ int dieroll; } else { /* ordinary egg(s) */ const char *eggp = (obj->corpsenm != NON_PM && obj->known) - ? the(mons[obj->corpsenm].mname) - : (cnt > 1L) ? "some" : "an"; + ? the(mons[obj->corpsenm].pmnames[NEUTRAL]) + : (cnt > 1L) ? "some" : "an"; You("hit %s with %s egg%s.", mon_nam(mon), eggp, plur(cnt)); @@ -1030,10 +1043,17 @@ int dieroll; pline(obj->otyp == CREAM_PIE ? "Splat!" : "Splash!"); setmangry(mon, TRUE); } - if (thrown) - obfree(obj, (struct obj *) 0); - else - useup(obj); + { + boolean more_than_1 = (obj->quan > 1L); + + if (thrown) + obfree(obj, (struct obj *) 0); + else + useup(obj); + + if (!more_than_1) + obj = (struct obj *) 0; + } hittxt = TRUE; get_dmg_bonus = FALSE; tmp = 0; @@ -1046,10 +1066,17 @@ int dieroll; Your("venom burns %s!", mon_nam(mon)); tmp = dmgval(obj, mon); } - if (thrown) - obfree(obj, (struct obj *) 0); - else - useup(obj); + { + boolean more_than_1 = (obj->quan > 1L); + + if (thrown) + obfree(obj, (struct obj *) 0); + else + useup(obj); + + if (!more_than_1) + obj = (struct obj *) 0; + } hittxt = TRUE; get_dmg_bonus = FALSE; break; @@ -1086,28 +1113,62 @@ int dieroll; } } - /****** NOTE: perhaps obj is undefined!! (if !thrown && BOOMERANG) - * *OR* if attacking bare-handed!! */ + /* + ***** NOTE: perhaps obj is undefined! (if !thrown && BOOMERANG) + * *OR* if attacking bare-handed! + * Note too: the cases where obj might get destroyed do not + * set 'use_weapon_skill', bare-handed does. + */ - if (get_dmg_bonus && tmp > 0) { - tmp += u.udaminc; - /* If you throw using a propellor, you don't get a strength - * bonus but you do get an increase-damage bonus. + if (tmp > 0) { + int dmgbonus = 0; + + /* + * Potential bonus (or penalty) from worn ring of increase damage + * (or intrinsic bonus from eating same) or from strength. */ - if (thrown != HMON_THROWN || !obj || !uwep - || !ammo_and_launcher(obj, uwep)) - tmp += dbon(); - } + if (get_dmg_bonus) { + dmgbonus = u.udaminc; + /* throwing using a propellor gets an increase-damage bonus + but not a strength one; other attacks get both */ + if (thrown != HMON_THROWN + || !obj || !uwep || !ammo_and_launcher(obj, uwep)) + dmgbonus += dbon(); + } - if (valid_weapon_attack) { - struct obj *wep; + /* + * Potential bonus (or penalty) from weapon skill. + * 'use_weapon_skill' is True for hand-to-hand ordinary weapon, + * applied or jousting polearm or lance, thrown missile (dart, + * shuriken, boomerang), or shot ammo (arrow, bolt, rock/gem when + * wielding corresponding launcher). + * It is False for hand-to-hand or thrown non-weapon, hand-to-hand + * polearm or lance when not mounted, hand-to-hand missile or ammo + * or launcher, thrown non-missile, or thrown ammo (including rocks) + * when not wielding corresponding launcher. + */ + if (use_weapon_skill) { + struct obj *skillwep = obj; - /* to be valid a projectile must have had the correct projector */ - wep = PROJECTILE(obj) ? uwep : obj; - tmp += weapon_dam_bonus(wep); - /* [this assumes that `!thrown' implies wielded...] */ - wtype = thrown ? weapon_type(wep) : uwep_skill_type(); - use_skill(wtype, 1); + if (PROJECTILE(obj) && ammo_and_launcher(obj, uwep)) + skillwep = uwep; + dmgbonus += weapon_dam_bonus(skillwep); + + /* hit for more than minimal damage (before being adjusted + for damage or skill bonus) trains the skill toward future + enhancement */ + if (train_weapon_skill) { + /* [this assumes that `!thrown' implies wielded...] */ + wtype = thrown ? weapon_type(skillwep) : uwep_skill_type(); + use_skill(wtype, 1); + } + } + + /* apply combined damage+strength and skill bonuses */ + tmp += dmgbonus; + /* don't let penalty, if bonus is negative, turn a hit into a miss */ + if (tmp < 1) + tmp = 1; } if (ispoisoned) { @@ -1152,12 +1213,13 @@ int dieroll; if (jousting < 0) { pline("%s shatters on impact!", Yname2(obj)); /* (must be either primary or secondary weapon to get here) */ - set_twoweap(FALSE); /* u.twoweap = FALSE; untwoweapon() is too verbose */ + set_twoweap(FALSE); /* sets u.twoweap = FALSE; + * untwoweapon() is too verbose here */ if (obj == uwep) uwepgone(); /* set g.unweapon */ /* minor side-effect: broken lance won't split puddings */ useup(obj); - obj = 0; + obj = (struct obj *) 0; } /* avoid migrating a dead monster */ if (mon->mhp > tmp) { @@ -1214,9 +1276,9 @@ int dieroll; && !(is_ammo(obj) || is_missile(obj))) && hand_to_hand) { struct monst *mclone; - if ((mclone = clone_mon(mon, 0, 0)) != 0) { - char withwhat[BUFSZ]; + char withwhat[BUFSZ]; + if ((mclone = clone_mon(mon, 0, 0)) != 0) { withwhat[0] = '\0'; if (u.twoweap && flags.verbose) Sprintf(withwhat, " with %s", yname(obj)); @@ -1629,112 +1691,400 @@ struct attack *mattk; mpickobj(mdef, gold); } -int -damageum(mdef, mattk, specialdmg) -register struct monst *mdef; -register struct attack *mattk; -int specialdmg; /* blessed and/or silver bonus against various things */ +void +mhitm_ad_rust(magr, mattk, mdef, mhm) +struct monst *magr; +struct attack *mattk; +struct monst *mdef; +struct mhitm_data *mhm; { - register struct permonst *pd = mdef->data; - int armpro, tmp = d((int) mattk->damn, (int) mattk->damd); - boolean negated; - struct obj *mongold; + struct permonst *pd = mdef->data; - armpro = magic_negation(mdef); - /* since hero can't be cancelled, only defender's armor applies */ - negated = !(rn2(10) >= 3 * armpro); - - if (is_demon(g.youmonst.data) && !rn2(13) && !uwep - && u.umonnum != PM_SUCCUBUS && u.umonnum != PM_INCUBUS - && u.umonnum != PM_BALROG) { - demonpet(); - return 0; - } - switch (mattk->adtyp) { - case AD_STUN: - if (!Blind) - pline("%s %s for a moment.", Monnam(mdef), - makeplural(stagger(pd, "stagger"))); - mdef->mstun = 1; - goto physical; - case AD_LEGS: -#if 0 - if (u.ucancelled) { - tmp = 0; - break; + if (magr == &g.youmonst) { + /* uhitm */ + if (completelyrusts(pd)) { /* iron golem */ + /* note: the life-saved case is hypothetical because + life-saving doesn't work for golems */ + pline("%s %s to pieces!", Monnam(mdef), + !mlifesaver(mdef) ? "falls" : "starts to fall"); + xkilled(mdef, XKILL_NOMSG); + mhm->hitflags |= MM_DEF_DIED; } -#endif - goto physical; - case AD_WERE: /* no special effect on monsters */ - case AD_HEAL: /* likewise */ - case AD_PHYS: - physical: - if (pd == &mons[PM_SHADE]) { - tmp = 0; - if (!specialdmg) - impossible("bad shade attack function flow?"); + erode_armor(mdef, ERODE_RUST); + mhm->damage = 0; /* damageum(), int tmp */ + } else if (mdef == &g.youmonst) { + /* mhitu */ + hitmsg(magr, mattk); + if (magr->mcan) { + return; } - tmp += specialdmg; - - if (mattk->aatyp == AT_WEAP) { - /* hmonas() uses known_hitum() to deal physical damage, - then also damageum() for non-AD_PHYS; don't inflict - extra physical damage for unusual damage types */ - tmp = 0; - } else if (mattk->aatyp == AT_KICK - || mattk->aatyp == AT_CLAW - || mattk->aatyp == AT_TUCH - || mattk->aatyp == AT_HUGS) { - if (thick_skinned(pd)) - tmp = (mattk->aatyp == AT_KICK) ? 0 : (tmp + 1) / 2; - /* add ring(s) of increase damage */ - if (u.udaminc > 0) { - /* applies even if damage was 0 */ - tmp += u.udaminc; - } else if (tmp > 0) { - /* ring(s) might be negative; avoid converting - 0 to non-0 or positive to non-positive */ - tmp += u.udaminc; - if (tmp < 1) - tmp = 1; + if (completelyrusts(pd)) { + You("rust!"); + /* KMH -- this is okay with unchanging */ + rehumanize(); + return; + } + erode_armor(&g.youmonst, ERODE_RUST); + } else { + /* mhitm */ + if (magr->mcan) + return; + if (completelyrusts(pd)) { /* PM_IRON_GOLEM */ + if (g.vis && canseemon(mdef)) + pline("%s %s to pieces!", Monnam(mdef), + !mlifesaver(mdef) ? "falls" : "starts to fall"); + monkilled(mdef, (char *) 0, AD_RUST); + if (!DEADMONSTER(mdef)) { + mhm->hitflags = MM_MISS; + mhm->done = TRUE; + return; } + mhm->hitflags = (MM_DEF_DIED | (grow_up(magr, mdef) ? 0 : MM_AGR_DIED)); + mhm->done = TRUE; + return; } - break; - case AD_FIRE: + erode_armor(mdef, ERODE_RUST); + mdef->mstrategy &= ~STRAT_WAITFORU; + mhm->damage = 0; /* mdamagem(), int tmp */ + } +} + +void +mhitm_ad_corr(magr, mattk, mdef, mhm) +struct monst *magr; +struct attack *mattk; +struct monst *mdef; +struct mhitm_data *mhm; +{ + if (magr == &g.youmonst) { + /* uhitm */ + erode_armor(mdef, ERODE_CORRODE); + mhm->damage = 0; + } else if (mdef == &g.youmonst) { + /* mhitu */ + hitmsg(magr, mattk); + if (magr->mcan) + return; + erode_armor(mdef, ERODE_CORRODE); + } else { + /* mhitm */ + if (magr->mcan) + return; + erode_armor(mdef, ERODE_CORRODE); + mdef->mstrategy &= ~STRAT_WAITFORU; + mhm->damage = 0; + } +} + +void +mhitm_ad_dcay(magr, mattk, mdef, mhm) +struct monst *magr; +struct attack *mattk; +struct monst *mdef; +struct mhitm_data *mhm; +{ + struct permonst *pd = mdef->data; + + if (magr == &g.youmonst) { + /* uhitm */ + if (completelyrots(pd)) { /* wood golem or leather golem */ + pline("%s %s to pieces!", Monnam(mdef), + !mlifesaver(mdef) ? "falls" : "starts to fall"); + xkilled(mdef, XKILL_NOMSG); + } + erode_armor(mdef, ERODE_ROT); + mhm->damage = 0; + } else if (mdef == &g.youmonst) { + /* mhitu */ + hitmsg(magr, mattk); + if (magr->mcan) + return; + if (completelyrots(pd)) { + You("rot!"); + /* KMH -- this is okay with unchanging */ + rehumanize(); + return; + } + erode_armor(mdef, ERODE_ROT); + } else { + /* mhitm */ + if (magr->mcan) + return; + if (completelyrots(pd)) { /* PM_WOOD_GOLEM || PM_LEATHER_GOLEM */ + /* note: the life-saved case is hypothetical because + life-saving doesn't work for golems */ + if (g.vis && canseemon(mdef)) + pline("%s %s to pieces!", Monnam(mdef), + !mlifesaver(mdef) ? "falls" : "starts to fall"); + monkilled(mdef, (char *) 0, AD_DCAY); + if (!DEADMONSTER(mdef)) { + mhm->done = TRUE; + mhm->hitflags = MM_MISS; + return; + } + mhm->done = TRUE; + mhm->hitflags = (MM_DEF_DIED | (grow_up(magr, mdef) ? 0 : MM_AGR_DIED)); + return; + } + erode_armor(mdef, ERODE_ROT); + mdef->mstrategy &= ~STRAT_WAITFORU; + mhm->damage = 0; + } +} + +void +mhitm_ad_dren(magr, mattk, mdef, mhm) +struct monst *magr; +struct attack *mattk; +struct monst *mdef; +struct mhitm_data *mhm; +{ + if (magr == &g.youmonst) { + /* uhitm */ + int armpro = magic_negation(mdef); + /* since hero can't be cancelled, only defender's armor applies */ + boolean negated = !(rn2(10) >= 3 * armpro); + + if (!negated && !rn2(4)) + xdrainenergym(mdef, TRUE); + mhm->damage = 0; + } else if (mdef == &g.youmonst) { + /* mhitu */ + int armpro = magic_negation(mdef); + boolean uncancelled = !magr->mcan && (rn2(10) >= 3 * armpro); + + hitmsg(magr, mattk); + if (uncancelled && !rn2(4)) /* 25% chance */ + drain_en(mhm->damage); + mhm->damage = 0; + } else { + /* mhitm */ + /* cancellation factor is the same as when attacking the hero */ + int armpro = magic_negation(mdef); + boolean cancelled = magr->mcan || !(rn2(10) >= 3 * armpro); + + if (!cancelled && !rn2(4)) + xdrainenergym(mdef, (boolean) (g.vis && canspotmon(mdef) + && mattk->aatyp != AT_ENGL)); + mhm->damage = 0; + } +} + +void +mhitm_ad_drli(magr, mattk, mdef, mhm) +struct monst *magr; +struct attack *mattk; +struct monst *mdef; +struct mhitm_data *mhm; +{ + if (magr == &g.youmonst) { + /* uhitm */ + int armpro = magic_negation(mdef); + /* since hero can't be cancelled, only defender's armor applies */ + boolean negated = !(rn2(10) >= 3 * armpro); + + if (!negated && !rn2(3) && !resists_drli(mdef)) { + mhm->damage = d(2, 6); /* Stormbringer uses monhp_per_lvl(usually 1d8) */ + pline("%s becomes weaker!", Monnam(mdef)); + if (mdef->mhpmax - mhm->damage > (int) mdef->m_lev) { + mdef->mhpmax -= mhm->damage; + } else { + /* limit floor of mhpmax reduction to current m_lev + 1; + avoid increasing it if somehow already less than that */ + if (mdef->mhpmax > (int) mdef->m_lev) + mdef->mhpmax = (int) mdef->m_lev + 1; + } + mdef->mhp -= mhm->damage; + /* !m_lev: level 0 monster is killed regardless of hit points + rather than drop to level -1; note: some non-living creatures + (golems, vortices) are subject to life-drain */ + if (DEADMONSTER(mdef) || !mdef->m_lev) { + pline("%s %s!", Monnam(mdef), + nonliving(mdef->data) ? "expires" : "dies"); + xkilled(mdef, XKILL_NOMSG); + } else + mdef->m_lev--; + mhm->damage = 0; /* damage has already been inflicted */ + + /* unlike hitting with Stormbringer, wounded hero doesn't + heal any from the drained life */ + } + } else if (mdef == &g.youmonst) { + /* mhitu */ + int armpro = magic_negation(mdef); + boolean uncancelled = !magr->mcan && (rn2(10) >= 3 * armpro); + + hitmsg(magr, mattk); + if (uncancelled && !rn2(3) && !Drain_resistance) { + losexp("life drainage"); + + /* unlike hitting with Stormbringer, wounded attacker doesn't + heal any from the drained life */ + } + } else { + /* mhitm */ + int armpro = magic_negation(mdef); + boolean cancelled = magr->mcan || !(rn2(10) >= 3 * armpro); + + if (!cancelled && !rn2(3) && !resists_drli(mdef)) { + mhm->damage = d(2, 6); /* Stormbringer uses monhp_per_lvl(usually 1d8) */ + if (g.vis && canspotmon(mdef)) + pline("%s becomes weaker!", Monnam(mdef)); + if (mdef->mhpmax - mhm->damage > (int) mdef->m_lev) { + mdef->mhpmax -= mhm->damage; + } else { + /* limit floor of mhpmax reduction to current m_lev + 1; + avoid increasing it if somehow already less than that */ + if (mdef->mhpmax > (int) mdef->m_lev) + mdef->mhpmax = (int) mdef->m_lev + 1; + } + if (mdef->m_lev == 0) /* automatic kill if drained past level 0 */ + mhm->damage = mdef->mhp; + else + mdef->m_lev--; + + /* unlike hitting with Stormbringer, wounded attacker doesn't + heal any from the drained life */ + } + } +} + +void +mhitm_ad_fire(magr, mattk, mdef, mhm) +struct monst *magr; +struct attack *mattk; +struct monst *mdef; +struct mhitm_data *mhm; +{ + struct permonst *pd = mdef->data; + + if (magr == &g.youmonst) { + /* uhitm */ + int armpro = magic_negation(mdef); + /* since hero can't be cancelled, only defender's armor applies */ + boolean negated = !(rn2(10) >= 3 * armpro); + if (negated) { - tmp = 0; - break; + mhm->damage = 0; + return; } if (!Blind) pline("%s is %s!", Monnam(mdef), on_fire(pd, mattk)); if (completelyburns(pd)) { /* paper golem or straw golem */ if (!Blind) - pline("%s burns completely!", Monnam(mdef)); + /* note: the life-saved case is hypothetical because + life-saving doesn't work for golems */ + pline("%s %s!", Monnam(mdef), + !mlifesaver(mdef) ? "burns completely" + : "is totally engulfed in flames"); else You("smell burning%s.", (pd == &mons[PM_PAPER_GOLEM]) ? " paper" : (pd == &mons[PM_STRAW_GOLEM]) ? " straw" : ""); xkilled(mdef, XKILL_NOMSG | XKILL_NOCORPSE); - tmp = 0; - break; - /* Don't return yet; keep hp<1 and tmp=0 for pet msg */ + mhm->damage = 0; + return; + /* Don't return yet; keep hp<1 and mhm.damage=0 for pet msg */ } - tmp += destroy_mitem(mdef, SCROLL_CLASS, AD_FIRE); - tmp += destroy_mitem(mdef, SPBOOK_CLASS, AD_FIRE); + mhm->damage += destroy_mitem(mdef, SCROLL_CLASS, AD_FIRE); + mhm->damage += destroy_mitem(mdef, SPBOOK_CLASS, AD_FIRE); if (resists_fire(mdef)) { if (!Blind) pline_The("fire doesn't heat %s!", mon_nam(mdef)); - golemeffects(mdef, AD_FIRE, tmp); + golemeffects(mdef, AD_FIRE, mhm->damage); shieldeff(mdef->mx, mdef->my); - tmp = 0; + mhm->damage = 0; } /* only potions damage resistant players in destroy_item */ - tmp += destroy_mitem(mdef, POTION_CLASS, AD_FIRE); - break; - case AD_COLD: + mhm->damage += destroy_mitem(mdef, POTION_CLASS, AD_FIRE); + ignite_items(mdef->minvent); + } else if (mdef == &g.youmonst) { + /* mhitu */ + int armpro = magic_negation(mdef); + boolean uncancelled = !magr->mcan && (rn2(10) >= 3 * armpro); + + hitmsg(magr, mattk); + if (uncancelled) { + pline("You're %s!", on_fire(pd, mattk)); + if (completelyburns(pd)) { /* paper or straw golem */ + You("go up in flames!"); + /* KMH -- this is okay with unchanging */ + rehumanize(); + return; + } else if (Fire_resistance) { + pline_The("fire doesn't feel hot!"); + mhm->damage = 0; + } + if ((int) magr->m_lev > rn2(20)) + destroy_item(SCROLL_CLASS, AD_FIRE); + if ((int) magr->m_lev > rn2(20)) + destroy_item(POTION_CLASS, AD_FIRE); + if ((int) magr->m_lev > rn2(25)) + destroy_item(SPBOOK_CLASS, AD_FIRE); + if ((int) magr->m_lev > rn2(20)) + ignite_items(g.invent); + burn_away_slime(); + } else + mhm->damage = 0; + } else { + /* mhitm */ + int armpro = magic_negation(mdef); + boolean cancelled = magr->mcan || !(rn2(10) >= 3 * armpro); + + if (cancelled) { + mhm->damage = 0; + return; + } + if (g.vis && canseemon(mdef)) + pline("%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 (g.vis && canseemon(mdef)) + pline("%s %s!", Monnam(mdef), + !mlifesaver(mdef) ? "burns completely" + : "is totally engulfed in flames"); + monkilled(mdef, (char *) 0, AD_FIRE); + if (!DEADMONSTER(mdef)) { + mhm->hitflags = MM_MISS; + mhm->done = TRUE; + return; + } + mhm->hitflags = (MM_DEF_DIED | (grow_up(magr, mdef) ? 0 : MM_AGR_DIED)); + mhm->done = TRUE; + return; + } + mhm->damage += destroy_mitem(mdef, SCROLL_CLASS, AD_FIRE); + mhm->damage += destroy_mitem(mdef, SPBOOK_CLASS, AD_FIRE); + if (resists_fire(mdef)) { + if (g.vis && canseemon(mdef)) + pline_The("fire doesn't seem to burn %s!", mon_nam(mdef)); + shieldeff(mdef->mx, mdef->my); + golemeffects(mdef, AD_FIRE, mhm->damage); + mhm->damage = 0; + } + /* only potions damage resistant players in destroy_item */ + mhm->damage += destroy_mitem(mdef, POTION_CLASS, AD_FIRE); + ignite_items(mdef->minvent); + } +} + +void +mhitm_ad_cold(magr, mattk, mdef, mhm) +struct monst *magr; +struct attack *mattk; +struct monst *mdef; +struct mhitm_data *mhm; +{ + if (magr == &g.youmonst) { + /* uhitm */ + int armpro = magic_negation(mdef); + /* since hero can't be cancelled, only defender's armor applies */ + boolean negated = !(rn2(10) >= 3 * armpro); + if (negated) { - tmp = 0; - break; + mhm->damage = 0; + return; } if (!Blind) pline("%s is covered in frost!", Monnam(mdef)); @@ -1742,48 +2092,180 @@ int specialdmg; /* blessed and/or silver bonus against various things */ shieldeff(mdef->mx, mdef->my); if (!Blind) pline_The("frost doesn't chill %s!", mon_nam(mdef)); - golemeffects(mdef, AD_COLD, tmp); - tmp = 0; + golemeffects(mdef, AD_COLD, mhm->damage); + mhm->damage = 0; } - tmp += destroy_mitem(mdef, POTION_CLASS, AD_COLD); - break; - case AD_ELEC: + mhm->damage += destroy_mitem(mdef, POTION_CLASS, AD_COLD); + } else if (mdef == &g.youmonst) { + /* mhitu */ + int armpro = magic_negation(mdef); + boolean uncancelled = !magr->mcan && (rn2(10) >= 3 * armpro); + + hitmsg(magr, mattk); + if (uncancelled) { + pline("You're covered in frost!"); + if (Cold_resistance) { + pline_The("frost doesn't seem cold!"); + mhm->damage = 0; + } + if ((int) magr->m_lev > rn2(20)) + destroy_item(POTION_CLASS, AD_COLD); + } else + mhm->damage = 0; + } else { + /* mhitm */ + int armpro = magic_negation(mdef); + boolean cancelled = magr->mcan || !(rn2(10) >= 3 * armpro); + + if (cancelled) { + mhm->damage = 0; + return; + } + if (g.vis && canseemon(mdef)) + pline("%s is covered in frost!", Monnam(mdef)); + if (resists_cold(mdef)) { + if (g.vis && canseemon(mdef)) + pline_The("frost doesn't seem to chill %s!", mon_nam(mdef)); + shieldeff(mdef->mx, mdef->my); + golemeffects(mdef, AD_COLD, mhm->damage); + mhm->damage = 0; + } + mhm->damage += destroy_mitem(mdef, POTION_CLASS, AD_COLD); + } +} + +void +mhitm_ad_elec(magr, mattk, mdef, mhm) +struct monst *magr; +struct attack *mattk; +struct monst *mdef; +struct mhitm_data *mhm; +{ + if (magr == &g.youmonst) { + /* uhitm */ + int armpro = magic_negation(mdef); + /* since hero can't be cancelled, only defender's armor applies */ + boolean negated = !(rn2(10) >= 3 * armpro); + if (negated) { - tmp = 0; - break; + mhm->damage = 0; + return; } if (!Blind) pline("%s is zapped!", Monnam(mdef)); - tmp += destroy_mitem(mdef, WAND_CLASS, AD_ELEC); + mhm->damage += destroy_mitem(mdef, WAND_CLASS, AD_ELEC); if (resists_elec(mdef)) { if (!Blind) pline_The("zap doesn't shock %s!", mon_nam(mdef)); - golemeffects(mdef, AD_ELEC, tmp); + golemeffects(mdef, AD_ELEC, mhm->damage); shieldeff(mdef->mx, mdef->my); - tmp = 0; + mhm->damage = 0; } /* only rings damage resistant players in destroy_item */ - tmp += destroy_mitem(mdef, RING_CLASS, AD_ELEC); - break; - case AD_ACID: + mhm->damage += destroy_mitem(mdef, RING_CLASS, AD_ELEC); + } else if (mdef == &g.youmonst) { + /* mhitu */ + int armpro = magic_negation(mdef); + boolean uncancelled = !magr->mcan && (rn2(10) >= 3 * armpro); + + hitmsg(magr, mattk); + if (uncancelled) { + You("get zapped!"); + if (Shock_resistance) { + pline_The("zap doesn't shock you!"); + mhm->damage = 0; + } + if ((int) magr->m_lev > rn2(20)) + destroy_item(WAND_CLASS, AD_ELEC); + if ((int) magr->m_lev > rn2(20)) + destroy_item(RING_CLASS, AD_ELEC); + } else + mhm->damage = 0; + } else { + /* mhitm */ + int armpro = magic_negation(mdef); + boolean cancelled = magr->mcan || !(rn2(10) >= 3 * armpro); + + if (cancelled) { + mhm->damage = 0; + return; + } + if (g.vis && canseemon(mdef)) + pline("%s gets zapped!", Monnam(mdef)); + mhm->damage += destroy_mitem(mdef, WAND_CLASS, AD_ELEC); + if (resists_elec(mdef)) { + if (g.vis && canseemon(mdef)) + pline_The("zap doesn't shock %s!", mon_nam(mdef)); + shieldeff(mdef->mx, mdef->my); + golemeffects(mdef, AD_ELEC, mhm->damage); + mhm->damage = 0; + } + /* only rings damage resistant players in destroy_item */ + mhm->damage += destroy_mitem(mdef, RING_CLASS, AD_ELEC); + } +} + +void +mhitm_ad_acid(magr, mattk, mdef, mhm) +struct monst *magr; +struct attack *mattk; +struct monst *mdef; +struct mhitm_data *mhm; +{ + if (magr == &g.youmonst) { + /* uhitm */ if (resists_acid(mdef)) - tmp = 0; - break; - case AD_STON: - if (!munstone(mdef, TRUE)) - minstapetrify(mdef, TRUE); - tmp = 0; - break; - case AD_SSEX: - case AD_SEDU: - case AD_SITM: - steal_it(mdef, mattk); - tmp = 0; - break; - case AD_SGLD: - /* This you as a leprechaun, so steal - real gold only, no lesser coins */ - mongold = findgold(mdef->minvent); + mhm->damage = 0; + } else if (mdef == &g.youmonst) { + /* mhitu */ + hitmsg(magr, mattk); + if (!magr->mcan && !rn2(3)) + if (Acid_resistance) { + pline("You're covered in %s, but it seems harmless.", + hliquid("acid")); + mhm->damage = 0; + } else { + pline("You're covered in %s! It burns!", hliquid("acid")); + exercise(A_STR, FALSE); + } + else + mhm->damage = 0; + } else { + /* mhitm */ + if (magr->mcan) { + mhm->damage = 0; + return; + } + if (resists_acid(mdef)) { + if (g.vis && canseemon(mdef)) + pline("%s is covered in %s, but it seems harmless.", + Monnam(mdef), hliquid("acid")); + mhm->damage = 0; + } else if (g.vis && canseemon(mdef)) { + pline("%s is covered in %s!", Monnam(mdef), hliquid("acid")); + pline("It burns %s!", mon_nam(mdef)); + } + if (!rn2(30)) + erode_armor(mdef, ERODE_CORRODE); + if (!rn2(6)) + acid_damage(MON_WEP(mdef)); + } +} + +void +mhitm_ad_sgld(magr, mattk, mdef, mhm) +struct monst *magr; +struct attack *mattk; +struct monst *mdef; +struct mhitm_data *mhm; +{ + struct permonst *pa = magr->data; + struct permonst *pd = mdef->data; + + if (magr == &g.youmonst) { + /* uhitm */ + struct obj *mongold = findgold(mdef->minvent); + if (mongold) { obj_extract_self(mongold); if (merge_choice(g.invent, mongold) || inv_cnt(FALSE) < 52) { @@ -1796,11 +2278,63 @@ int specialdmg; /* blessed and/or silver bonus against various things */ } } exercise(A_DEX, TRUE); - tmp = 0; - break; - case AD_TLPT: - if (tmp <= 0) - tmp = 1; + mhm->damage = 0; + } else if (mdef == &g.youmonst) { + /* mhitu */ + hitmsg(magr, mattk); + if (pd->mlet == pa->mlet) + return; + if (!magr->mcan) + stealgold(magr); + } else { + /* mhitm */ + char buf[BUFSZ]; + + mhm->damage = 0; + if (magr->mcan) + return; + /* technically incorrect; no check for stealing gold from + * between mdef's feet... + */ + { + struct obj *gold = findgold(mdef->minvent); + + if (!gold) + return; + obj_extract_self(gold); + add_to_minv(magr, gold); + } + mdef->mstrategy &= ~STRAT_WAITFORU; + if (g.vis && canseemon(mdef)) { + Strcpy(buf, Monnam(magr)); + pline("%s steals some gold from %s.", buf, mon_nam(mdef)); + } + if (!tele_restrict(magr)) { + boolean couldspot = canspotmon(magr); + + (void) rloc(magr, TRUE); + if (g.vis && couldspot && !canspotmon(magr)) + pline("%s suddenly disappears!", buf); + } + } +} + + +void +mhitm_ad_tlpt(magr, mattk, mdef, mhm) +struct monst *magr; +struct attack *mattk; +struct monst *mdef; +struct mhitm_data *mhm; +{ + if (magr == &g.youmonst) { + /* uhitm */ + int armpro = magic_negation(mdef); + /* since hero can't be cancelled, only defender's armor applies */ + boolean negated = !(rn2(10) >= 3 * armpro); + + if (mhm->damage <= 0) + mhm->damage = 1; if (!negated) { char nambuf[BUFSZ]; boolean u_saw_mon = (canseemon(mdef) @@ -1811,145 +2345,434 @@ int specialdmg; /* blessed and/or silver bonus against various things */ if (u_teleport_mon(mdef, FALSE) && u_saw_mon && !(canseemon(mdef) || (u.uswallow && u.ustuck == mdef))) pline("%s suddenly disappears!", nambuf); - if (tmp >= mdef->mhp) { /* see hitmu(mhitu.c) */ + if (mhm->damage >= mdef->mhp) { /* see hitmu(mhitu.c) */ if (mdef->mhp == 1) ++mdef->mhp; - tmp = mdef->mhp - 1; + mhm->damage = mdef->mhp - 1; } } - break; - case AD_BLND: - if (can_blnd(&g.youmonst, mdef, mattk->aatyp, (struct obj *) 0)) { + } else if (mdef == &g.youmonst) { + /* mhitu */ + int armpro = magic_negation(mdef); + boolean uncancelled = !magr->mcan && (rn2(10) >= 3 * armpro); + int tmphp; + + hitmsg(magr, mattk); + if (uncancelled) { + if (flags.verbose) + Your("position suddenly seems %suncertain!", + (Teleport_control && !Stunned && !unconscious()) ? "" + : "very "); + tele(); + /* As of 3.6.2: make sure damage isn't fatal; previously, it + was possible to be teleported and then drop dead at + the destination when QM's 1d4 damage gets applied below; + even though that wasn't "wrong", it seemed strange, + particularly if the teleportation had been controlled + [applying the damage first and not teleporting if fatal + is another alternative but it has its own complications] */ + if ((Half_physical_damage ? (mhm->damage - 1) / 2 : mhm->damage) + >= (tmphp = (Upolyd ? u.mh : u.uhp))) { + mhm->damage = tmphp - 1; + if (Half_physical_damage) + mhm->damage *= 2; /* doesn't actually increase damage; we only + * get here if half the original damage would + * would have been fatal, so double reduced + * damage will be less than original damage */ + if (mhm->damage < 1) { /* implies (tmphp <= 1) */ + mhm->damage = 1; + /* this might increase current HP beyond maximum HP but + it will be immediately reduced below, so that should + be indistinguishable from zero damage; we don't drop + damage all the way to zero because that inhibits any + passive counterattack if poly'd hero has one */ + if (Upolyd && u.mh == 1) + ++u.mh; + else if (!Upolyd && u.uhp == 1) + ++u.uhp; + /* [don't set context.botl here] */ + } + } + } + } else { + /* mhitm */ + int armpro = magic_negation(mdef); + boolean cancelled = magr->mcan || !(rn2(10) >= 3 * armpro); + + if (!cancelled && mhm->damage < mdef->mhp && !tele_restrict(mdef)) { + char mdef_Monnam[BUFSZ]; + boolean wasseen = canspotmon(mdef); + + /* save the name before monster teleports, otherwise + we'll get "it" in the suddenly disappears message */ + if (g.vis && wasseen) + Strcpy(mdef_Monnam, Monnam(mdef)); + mdef->mstrategy &= ~STRAT_WAITFORU; + (void) rloc(mdef, TRUE); + if (g.vis && wasseen && !canspotmon(mdef) && mdef != u.usteed) + pline("%s suddenly disappears!", mdef_Monnam); + if (mhm->damage >= mdef->mhp) { /* see hitmu(mhitu.c) */ + if (mdef->mhp == 1) + ++mdef->mhp; + mhm->damage = mdef->mhp - 1; + } + } + } +} + +void +mhitm_ad_blnd(magr, mattk, mdef, mhm) +struct monst *magr; +struct attack *mattk; +struct monst *mdef; +struct mhitm_data *mhm; +{ + if (magr == &g.youmonst) { + /* uhitm */ + if (can_blnd(magr, mdef, mattk->aatyp, (struct obj *) 0)) { if (!Blind && mdef->mcansee) pline("%s is blinded.", Monnam(mdef)); mdef->mcansee = 0; - tmp += mdef->mblinded; - if (tmp > 127) - tmp = 127; - mdef->mblinded = tmp; + mhm->damage += mdef->mblinded; + if (mhm->damage > 127) + mhm->damage = 127; + mdef->mblinded = mhm->damage; } - tmp = 0; - break; - case AD_CURS: + mhm->damage = 0; + } else if (mdef == &g.youmonst) { + /* mhitu */ + if (can_blnd(magr, mdef, mattk->aatyp, (struct obj *) 0)) { + if (!Blind) + pline("%s blinds you!", Monnam(magr)); + make_blinded(Blinded + (long) mhm->damage, FALSE); + if (!Blind) + Your1(vision_clears); + } + mhm->damage = 0; + } else { + /* mhitm */ + if (can_blnd(magr, mdef, mattk->aatyp, (struct obj *) 0)) { + register unsigned rnd_tmp; + + if (g.vis && mdef->mcansee && canspotmon(mdef)) + pline("%s is blinded.", Monnam(mdef)); + rnd_tmp = d((int) mattk->damn, (int) mattk->damd); + if ((rnd_tmp += mdef->mblinded) > 127) + rnd_tmp = 127; + mdef->mblinded = rnd_tmp; + mdef->mcansee = 0; + mdef->mstrategy &= ~STRAT_WAITFORU; + } + mhm->damage = 0; + } +} + +void +mhitm_ad_curs(magr, mattk, mdef, mhm) +struct monst *magr; +struct attack *mattk; +struct monst *mdef; +struct mhitm_data *mhm; +{ + struct permonst *pa = magr->data; + struct permonst *pd = mdef->data; + + if (magr == &g.youmonst) { + /* uhitm */ if (night() && !rn2(10) && !mdef->mcan) { if (pd == &mons[PM_CLAY_GOLEM]) { if (!Blind) pline("Some writing vanishes from %s head!", s_suffix(mon_nam(mdef))); xkilled(mdef, XKILL_NOMSG); - /* Don't return yet; keep hp<1 and tmp=0 for pet msg */ + /* Don't return yet; keep hp<1 and mhm.damage=0 for pet msg */ } else { mdef->mcan = 1; You("chuckle."); } } - tmp = 0; - break; - case AD_DRLI: /* drain life */ - if (!negated && !rn2(3) && !resists_drli(mdef)) { - tmp = d(2, 6); /* Stormbringer uses monhp_per_lvl(usually 1d8) */ - pline("%s becomes weaker!", Monnam(mdef)); - if (mdef->mhpmax - tmp > (int) mdef->m_lev) { - mdef->mhpmax -= tmp; - } else { - /* limit floor of mhpmax reduction to current m_lev + 1; - avoid increasing it if somehow already less than that */ - if (mdef->mhpmax > (int) mdef->m_lev) - mdef->mhpmax = (int) mdef->m_lev + 1; + mhm->damage = 0; + } else if (mdef == &g.youmonst) { + /* mhitu */ + hitmsg(magr, mattk); + if (!night() && pa == &mons[PM_GREMLIN]) + return; + if (!magr->mcan && !rn2(10)) { + if (!Deaf) { + if (Blind) + You_hear("laughter."); + else + pline("%s chuckles.", Monnam(magr)); } - mdef->mhp -= tmp; - /* !m_lev: level 0 monster is killed regardless of hit points - rather than drop to level -1; note: some non-living creatures - (golems, vortices) are subject to life-drain */ - if (DEADMONSTER(mdef) || !mdef->m_lev) { - pline("%s %s!", Monnam(mdef), - nonliving(mdef->data) ? "expires" : "dies"); - xkilled(mdef, XKILL_NOMSG); - } else - mdef->m_lev--; - tmp = 0; /* damage has already been inflicted */ + if (u.umonnum == PM_CLAY_GOLEM) { + pline("Some writing vanishes from your head!"); + /* KMH -- this is okay with unchanging */ + rehumanize(); + return; + } + attrcurse(); + } + } else { + /* mhitm */ + if (!night() && (pa == &mons[PM_GREMLIN])) + return; + if (!magr->mcan && !rn2(10)) { + mdef->mcan = 1; /* cancelled regardless of lifesave */ + mdef->mstrategy &= ~STRAT_WAITFORU; + if (is_were(pd) && pd->mlet != S_HUMAN) + were_change(mdef); + if (pd == &mons[PM_CLAY_GOLEM]) { + if (g.vis && canseemon(mdef)) { + pline("Some writing vanishes from %s head!", + s_suffix(mon_nam(mdef))); + pline("%s is destroyed!", Monnam(mdef)); + } + mondied(mdef); + if (!DEADMONSTER(mdef)) { + mhm->hitflags = MM_MISS; + mhm->done = TRUE; + return; + } else if (mdef->mtame && !g.vis) { + You(brief_feeling, "strangely sad"); + } + mhm->hitflags = (MM_DEF_DIED + | (grow_up(magr, mdef) ? 0 : MM_AGR_DIED)); + mhm->done = TRUE; + return; + } + if (!Deaf) { + if (!g.vis) + You_hear("laughter."); + else if (canseemon(magr)) + pline("%s chuckles.", Monnam(magr)); + } + } + } +} + +void +mhitm_ad_drst(magr, mattk, mdef, mhm) +struct monst *magr; +struct attack *mattk; +struct monst *mdef; +struct mhitm_data *mhm; +{ + struct permonst *pa = magr->data; + + if (magr == &g.youmonst) { + /* uhitm */ + int armpro = magic_negation(mdef); + /* since hero can't be cancelled, only defender's armor applies */ + boolean negated = !(rn2(10) >= 3 * armpro); - /* unlike hitting with Stormbringer, wounded hero doesn't - heal any from the drained life */ - } - break; - case AD_RUST: - if (pd == &mons[PM_IRON_GOLEM]) { - pline("%s falls to pieces!", Monnam(mdef)); - xkilled(mdef, XKILL_NOMSG); - } - erode_armor(mdef, ERODE_RUST); - tmp = 0; - break; - case AD_CORR: - erode_armor(mdef, ERODE_CORRODE); - tmp = 0; - break; - case AD_DCAY: - if (pd == &mons[PM_WOOD_GOLEM] || pd == &mons[PM_LEATHER_GOLEM]) { - pline("%s falls to pieces!", Monnam(mdef)); - xkilled(mdef, XKILL_NOMSG); - } - erode_armor(mdef, ERODE_ROT); - tmp = 0; - break; - case AD_DREN: - if (!negated && !rn2(4)) - xdrainenergym(mdef, TRUE); - tmp = 0; - break; - case AD_DRST: - case AD_DRDX: - case AD_DRCO: if (!negated && !rn2(8)) { - Your("%s was poisoned!", mpoisons_subj(&g.youmonst, mattk)); + Your("%s was poisoned!", mpoisons_subj(magr, mattk)); if (resists_poison(mdef)) { pline_The("poison doesn't seem to affect %s.", mon_nam(mdef)); } else { if (!rn2(10)) { Your("poison was deadly..."); - tmp = mdef->mhp; + mhm->damage = mdef->mhp; } else - tmp += rn1(10, 6); + mhm->damage += rn1(10, 6); } } - break; - case AD_DRIN: { + } else if (mdef == &g.youmonst) { + /* mhitu */ + int armpro = magic_negation(mdef); + boolean uncancelled = !magr->mcan && (rn2(10) >= 3 * armpro); + int ptmp = A_STR; /* A_STR == 0 */ + char buf[BUFSZ]; + + switch (mattk->adtyp) { + case AD_DRST: ptmp = A_STR; break; + case AD_DRDX: ptmp = A_DEX; break; + case AD_DRCO: ptmp = A_CON; break; + } + hitmsg(magr, mattk); + if (uncancelled && !rn2(8)) { + Sprintf(buf, "%s %s", s_suffix(Monnam(magr)), + mpoisons_subj(magr, mattk)); + poisoned(buf, ptmp, pmname(pa, Mgender(magr)), 30, FALSE); + } + } else { + /* mhitm */ + int armpro = magic_negation(mdef); + boolean cancelled = magr->mcan || !(rn2(10) >= 3 * armpro); + + if (!cancelled && !rn2(8)) { + if (g.vis && canspotmon(magr)) + pline("%s %s was poisoned!", s_suffix(Monnam(magr)), + mpoisons_subj(magr, mattk)); + if (resists_poison(mdef)) { + if (g.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 (g.vis && canspotmon(mdef)) + pline_The("poison was deadly..."); + mhm->damage = mdef->mhp; + } + } + } + } +} + +void +mhitm_ad_drin(magr, mattk, mdef, mhm) +struct monst *magr; +struct attack *mattk; +struct monst *mdef; +struct mhitm_data *mhm; +{ + struct permonst *pd = mdef->data; + + if (magr == &g.youmonst) { + /* uhitm */ struct obj *helmet; if (g.notonhead || !has_head(pd)) { pline("%s doesn't seem harmed.", Monnam(mdef)); - tmp = 0; + /* hero should skip remaining AT_TENT+AD_DRIN attacks + because they'll be just as harmless as this one (and also + to reduce verbosity) */ + g.skipdrin = TRUE; + mhm->damage = 0; if (!Unchanging && pd == &mons[PM_GREEN_SLIME]) { if (!Slimed) { You("suck in some slime and don't feel very well."); make_slimed(10L, (char *) 0); } } - break; + return; } if (m_slips_free(mdef, mattk)) - break; + return; if ((helmet = which_armor(mdef, W_ARMH)) != 0 && rn2(8)) { pline("%s %s blocks your attack to %s head.", s_suffix(Monnam(mdef)), helm_simple_name(helmet), mhis(mdef)); - break; + return; } - (void) eat_brains(&g.youmonst, mdef, TRUE, &tmp); - break; + (void) eat_brains(&g.youmonst, mdef, TRUE, &mhm->damage); + } else if (mdef == &g.youmonst) { + /* mhitu */ + hitmsg(magr, mattk); + if (defends(AD_DRIN, uwep) || !has_head(pd)) { + You("don't seem harmed."); + /* attacker should skip remaining AT_TENT+AD_DRIN attacks */ + g.skipdrin = TRUE; + /* Not clear what to do for green slimes */ + return; + } + if (u_slip_free(magr, mattk)) + return; + + if (uarmh && rn2(8)) { + /* not body_part(HEAD) */ + Your("%s blocks the attack to your head.", + helm_simple_name(uarmh)); + return; + } + /* negative armor class doesn't reduce this damage */ + if (Half_physical_damage) + mhm->damage = (mhm->damage + 1) / 2; + mdamageu(magr, mhm->damage); + mhm->damage = 0; /* don't inflict a second dose below */ + + if (!uarmh || uarmh->otyp != DUNCE_CAP) { + /* eat_brains() will miss if target is mindless (won't + happen here; hero is considered to retain his mind + regardless of current shape) or is noncorporeal + (can't happen here; no one can poly into a ghost + or shade) so this check for missing is academic */ + if (eat_brains(magr, mdef, TRUE, (int *) 0) == MM_MISS) + return; + } + /* adjattrib gives dunce cap message when appropriate */ + (void) adjattrib(A_INT, -rnd(2), FALSE); + } else { + /* mhitm */ + char buf[BUFSZ]; + + if (g.notonhead || !has_head(pd)) { + if (g.vis && canspotmon(mdef)) + pline("%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 + be able to hit target on head either */ + g.skipdrin = TRUE; /* affects mattackm()'s attack loop */ + return; + } + if ((mdef->misc_worn_check & W_ARMH) && rn2(8)) { + if (g.vis && canspotmon(magr) && canseemon(mdef)) { + Strcpy(buf, s_suffix(Monnam(mdef))); + pline("%s helmet blocks %s attack to %s head.", buf, + s_suffix(mon_nam(magr)), mhis(mdef)); + } + return; + } + mhm->hitflags = eat_brains(magr, mdef, g.vis, &mhm->damage); } - case AD_STCK: - if (!negated && !sticks(pd)) +} + +void +mhitm_ad_stck(magr, mattk, mdef, mhm) +struct monst *magr; +struct attack *mattk; +struct monst *mdef; +struct mhitm_data *mhm; +{ + struct permonst *pd = mdef->data; + + if (magr == &g.youmonst) { + /* uhitm */ + int armpro = magic_negation(mdef); + /* since hero can't be cancelled, only defender's armor applies */ + boolean negated = !(rn2(10) >= 3 * armpro); + + if (!negated && !sticks(pd) && distu(mdef->mx, mdef->my) <= 2) u.ustuck = mdef; /* it's now stuck to you */ - break; - case AD_WRAP: + } else if (mdef == &g.youmonst) { + /* mhitu */ + int armpro = magic_negation(mdef); + boolean uncancelled = !magr->mcan && (rn2(10) >= 3 * armpro); + + hitmsg(magr, mattk); + if (uncancelled && !u.ustuck && !sticks(pd)) { + set_ustuck(magr); + } + } else { + /* mhitm */ + int armpro = magic_negation(mdef); + boolean cancelled = magr->mcan || !(rn2(10) >= 3 * armpro); + + if (cancelled) + mhm->damage = 0; + } +} + +void +mhitm_ad_wrap(magr, mattk, mdef, mhm) +struct monst *magr; +struct attack *mattk; +struct monst *mdef; +struct mhitm_data *mhm; +{ + struct permonst *pd = mdef->data; + + if (magr == &g.youmonst) { + /* uhitm */ if (!sticks(pd)) { if (!u.ustuck && !rn2(10)) { if (m_slips_free(mdef, mattk)) { - tmp = 0; + mhm->damage = 0; } else { You("swing yourself around %s!", mon_nam(mdef)); set_ustuck(mdef); @@ -1959,35 +2782,182 @@ int specialdmg; /* blessed and/or silver bonus against various things */ if (is_pool(u.ux, u.uy) && !is_swimmer(pd) && !amphibious(pd)) { You("drown %s...", mon_nam(mdef)); - tmp = mdef->mhp; + mhm->damage = mdef->mhp; } else if (mattk->aatyp == AT_HUGS) pline("%s is being crushed.", Monnam(mdef)); } else { - tmp = 0; + mhm->damage = 0; if (flags.verbose) You("brush against %s %s.", s_suffix(mon_nam(mdef)), mbodypart(mdef, LEG)); } } else - tmp = 0; - break; - case AD_PLYS: - if (!negated && mdef->mcanmove && !rn2(3) && tmp < mdef->mhp) { + mhm->damage = 0; + } else if (mdef == &g.youmonst) { + /* mhitu */ + if ((!magr->mcan || u.ustuck == magr) && !sticks(pd)) { + if (!u.ustuck && !rn2(10)) { + if (u_slip_free(magr, mattk)) { + mhm->damage = 0; + } else { + set_ustuck(magr); /* before message, for botl update */ + pline("%s swings itself around you!", Monnam(magr)); + } + } else if (u.ustuck == magr) { + if (is_pool(magr->mx, magr->my) && !Swimming && !Amphibious) { + boolean moat = (levl[magr->mx][magr->my].typ != POOL) + && (levl[magr->mx][magr->my].typ != WATER) + && !Is_medusa_level(&u.uz) + && !Is_waterlevel(&u.uz); + + pline("%s drowns you...", Monnam(magr)); + g.killer.format = KILLED_BY_AN; + Sprintf(g.killer.name, "%s by %s", + moat ? "moat" : "pool of water", + an(pmname(magr->data, Mgender(magr)))); + done(DROWNING); + } else if (mattk->aatyp == AT_HUGS) { + You("are being crushed."); + } + } else { + mhm->damage = 0; + if (flags.verbose) + pline("%s brushes against your %s.", Monnam(magr), + body_part(LEG)); + } + } else + mhm->damage = 0; + } else { + /* mhitm */ + if (magr->mcan) + mhm->damage = 0; + } +} + +void +mhitm_ad_plys(magr, mattk, mdef, mhm) +struct monst *magr; +struct attack *mattk; +struct monst *mdef; +struct mhitm_data *mhm; +{ + if (magr == &g.youmonst) { + /* uhitm */ + int armpro = magic_negation(mdef); + /* since hero can't be cancelled, only defender's armor applies */ + boolean negated = !(rn2(10) >= 3 * armpro); + + if (!negated && mdef->mcanmove && !rn2(3) && mhm->damage < mdef->mhp) { if (!Blind) pline("%s is frozen by you!", Monnam(mdef)); paralyze_monst(mdef, rnd(10)); } - break; - case AD_SLEE: + } else if (mdef == &g.youmonst) { + /* mhitu */ + int armpro = magic_negation(mdef); + boolean uncancelled = !magr->mcan && (rn2(10) >= 3 * armpro); + + hitmsg(magr, mattk); + if (uncancelled && g.multi >= 0 && !rn2(3)) { + if (Free_action) { + You("momentarily stiffen."); + } else { + if (Blind) + You("are frozen!"); + else + You("are frozen by %s!", mon_nam(magr)); + g.nomovemsg = You_can_move_again; + nomul(-rnd(10)); + g.multi_reason = "paralyzed by a monster"; + exercise(A_DEX, FALSE); + } + } + } else { + /* mhitm */ + int armpro = magic_negation(mdef); + boolean cancelled = magr->mcan || !(rn2(10) >= 3 * armpro); + + if (!cancelled && mdef->mcanmove) { + if (g.vis && canspotmon(mdef)) { + char buf[BUFSZ]; + Strcpy(buf, Monnam(mdef)); + pline("%s is frozen by %s.", buf, mon_nam(magr)); + } + paralyze_monst(mdef, rnd(10)); + } + } +} + +void +mhitm_ad_slee(magr, mattk, mdef, mhm) +struct monst *magr; +struct attack *mattk; +struct monst *mdef; +struct mhitm_data *mhm; +{ + mhm->damage = 0; /* no HP damage */ + + if (magr == &g.youmonst) { + /* uhitm */ + int armpro = magic_negation(mdef); + /* since hero can't be cancelled, only defender's armor applies */ + boolean negated = !(rn2(10) >= 3 * armpro); + if (!negated && !mdef->msleeping && sleep_monst(mdef, rnd(10), -1)) { if (!Blind) pline("%s is put to sleep by you!", Monnam(mdef)); slept_monst(mdef); } - break; - case AD_SLIM: + } else if (mdef == &g.youmonst) { + /* mhitu */ + int armpro = magic_negation(mdef); + boolean uncancelled = !magr->mcan && (rn2(10) >= 3 * armpro); + + hitmsg(magr, mattk); + if (uncancelled && g.multi >= 0 && !rn2(5)) { + if (Sleep_resistance) + return; + fall_asleep(-rnd(10), TRUE); + if (Blind) + You("are put to sleep!"); + else + You("are put to sleep by %s!", mon_nam(magr)); + } + } else { + /* mhitm */ + int armpro = magic_negation(mdef); + boolean cancelled = magr->mcan || !(rn2(10) >= 3 * armpro); + + if (!cancelled && !mdef->msleeping + && sleep_monst(mdef, rnd(10), -1)) { + if (g.vis && canspotmon(mdef)) { + char buf[BUFSZ]; + Strcpy(buf, Monnam(mdef)); + pline("%s is put to sleep by %s.", buf, mon_nam(magr)); + } + mdef->mstrategy &= ~STRAT_WAITFORU; + slept_monst(mdef); + } + } +} + +void +mhitm_ad_slim(magr, mattk, mdef, mhm) +struct monst *magr; +struct attack *mattk; +struct monst *mdef; +struct mhitm_data *mhm; +{ + struct permonst *pd = mdef->data; + + if (magr == &g.youmonst) { + /* uhitm */ + int armpro = magic_negation(mdef); + /* since hero can't be cancelled, only defender's armor applies */ + boolean negated = !(rn2(10) >= 3 * armpro); + if (negated) - break; /* physical damage only */ + return; /* physical damage only */ if (!rn2(4) && !slimeproof(pd)) { if (!munslime(mdef, TRUE) && !DEADMONSTER(mdef)) { /* this assumes newcham() won't fail; since hero has @@ -1997,16 +2967,129 @@ int specialdmg; /* blessed and/or silver bonus against various things */ pd = mdef->data; } /* munslime attempt could have been fatal */ - if (DEADMONSTER(mdef)) - return 2; /* skip death message */ - tmp = 0; + if (DEADMONSTER(mdef)) { + mhm->hitflags = MM_DEF_DIED; /* skip death message */ + mhm->done = TRUE; + return; + } + mhm->damage = 0; } - break; - case AD_ENCH: /* KMH -- remove enchantment (disenchanter) */ + } else if (mdef == &g.youmonst) { + /* mhitu */ + int armpro = magic_negation(mdef); + boolean uncancelled = !magr->mcan && (rn2(10) >= 3 * armpro); + + hitmsg(magr, mattk); + if (!uncancelled) + return; + if (flaming(pd)) { + pline_The("slime burns away!"); + mhm->damage = 0; + } else if (Unchanging || noncorporeal(pd) + || pd == &mons[PM_GREEN_SLIME]) { + You("are unaffected."); + mhm->damage = 0; + } else if (!Slimed) { + You("don't feel very well."); + make_slimed(10L, (char *) 0); + delayed_killer(SLIMED, KILLED_BY_AN, + pmname(magr->data, Mgender(magr))); + } else + pline("Yuck!"); + } else { + /* mhitm */ + int armpro = magic_negation(mdef); + boolean cancelled = magr->mcan || !(rn2(10) >= 3 * armpro); + + if (cancelled) + return; /* physical damage only */ + if (!rn2(4) && !slimeproof(pd)) { + if (!munslime(mdef, FALSE) && !DEADMONSTER(mdef)) { + if (newcham(mdef, &mons[PM_GREEN_SLIME], FALSE, + (boolean) (g.vis && canseemon(mdef)))) + pd = mdef->data; + mdef->mstrategy &= ~STRAT_WAITFORU; + mhm->hitflags = MM_HIT; + } + /* munslime attempt could have been fatal, + potentially to multiple monsters (SCR_FIRE) */ + if (DEADMONSTER(magr)) + mhm->hitflags |= MM_AGR_DIED; + if (DEADMONSTER(mdef)) + mhm->hitflags |= MM_DEF_DIED; + mhm->damage = 0; + } + } +} + +void +mhitm_ad_ench(magr, mattk, mdef, mhm) +struct monst *magr; +struct attack *mattk; +struct monst *mdef; +struct mhitm_data *mhm; +{ + mhm->damage = 0; /* no HP damage */ + + if (magr == &g.youmonst) { + /* uhitm */ /* there's no msomearmor() function, so just do damage */ - /* if (negated) break; */ - break; - case AD_SLOW: + } else if (mdef == &g.youmonst) { + /* mhitu */ + int armpro = magic_negation(mdef); + boolean uncancelled = !magr->mcan && (rn2(10) >= 3 * armpro); + + hitmsg(magr, mattk); + /* uncancelled is sufficient enough; please + don't make this attack less frequent */ + if (uncancelled) { + struct obj *obj = some_armor(mdef); + + if (!obj) { + /* some rings are susceptible; + amulets and blindfolds aren't (at present) */ + switch (rn2(5)) { + case 0: + break; + case 1: + obj = uright; + break; + case 2: + obj = uleft; + break; + case 3: + obj = uamul; + break; + case 4: + obj = ublindf; + break; + } + } + if (drain_item(obj, FALSE)) { + pline("%s less effective.", Yobjnam2(obj, "seem")); + } + } + } else { + /* mhitm */ + /* there's no msomearmor() function, so just do damage */ + } +} + +void +mhitm_ad_slow(magr, mattk, mdef, mhm) +struct monst *magr; +struct attack *mattk; +struct monst *mdef; +struct mhitm_data *mhm; +{ + mhm->damage = 0; /* no HP damage */ + + if (magr == &g.youmonst) { + /* uhitm */ + int armpro = magic_negation(mdef); + /* since hero can't be cancelled, only defender's armor applies */ + boolean negated = !(rn2(10) >= 3 * armpro); + if (!negated && mdef->mspeed != MSLOW) { unsigned int oldspeed = mdef->mspeed; @@ -2014,39 +3097,1135 @@ int specialdmg; /* blessed and/or silver bonus against various things */ if (mdef->mspeed != oldspeed && canseemon(mdef)) pline("%s slows down.", Monnam(mdef)); } - break; - case AD_CONF: + } else if (mdef == &g.youmonst) { + /* mhitu */ + int armpro = magic_negation(mdef); + boolean uncancelled = !magr->mcan && (rn2(10) >= 3 * armpro); + + hitmsg(magr, mattk); + if (uncancelled && HFast && !defends(AD_SLOW, uwep) && !rn2(4)) + u_slow_down(); + } else { + /* mhitm */ + int armpro = magic_negation(mdef); + boolean cancelled = magr->mcan || !(rn2(10) >= 3 * armpro); + + if (!cancelled && mdef->mspeed != MSLOW) { + unsigned int oldspeed = mdef->mspeed; + + mon_adjust_speed(mdef, -1, (struct obj *) 0); + mdef->mstrategy &= ~STRAT_WAITFORU; + if (mdef->mspeed != oldspeed && g.vis && canspotmon(mdef)) + pline("%s slows down.", Monnam(mdef)); + } + } +} + +void +mhitm_ad_conf(magr, mattk, mdef, mhm) +struct monst *magr; +struct attack *mattk; +struct monst *mdef; +struct mhitm_data *mhm; +{ + if (magr == &g.youmonst) { + /* uhitm */ if (!mdef->mconf) { if (canseemon(mdef)) pline("%s looks confused.", Monnam(mdef)); mdef->mconf = 1; } - break; - case AD_POLY: - if (!negated && tmp < mdef->mhp) - tmp = mon_poly(&g.youmonst, mdef, tmp); - break; + } else if (mdef == &g.youmonst) { + /* mhitu */ + hitmsg(magr, mattk); + if (!magr->mcan && !rn2(4) && !magr->mspec_used) { + magr->mspec_used = magr->mspec_used + (mhm->damage + rn2(6)); + if (Confusion) + You("are getting even more confused."); + else + You("are getting confused."); + make_confused(HConfusion + mhm->damage, FALSE); + } + mhm->damage = 0; + } else { + /* mhitm */ + /* Since confusing another monster doesn't have a real time + * limit, setting spec_used would not really be right (though + * we still should check for it). + */ + if (!magr->mcan && !mdef->mconf && !magr->mspec_used) { + if (g.vis && canseemon(mdef)) + pline("%s looks confused.", Monnam(mdef)); + mdef->mconf = 1; + mdef->mstrategy &= ~STRAT_WAITFORU; + } + } +} + +void +mhitm_ad_poly(magr, mattk, mdef, mhm) +struct monst *magr; +struct attack *mattk UNUSED; /* implied */ +struct monst *mdef; +struct mhitm_data *mhm; +{ + if (magr == &g.youmonst) { + /* uhitm */ + int armpro = magic_negation(mdef); + /* since hero can't be cancelled, only defender's armor applies */ + boolean negated = !(rn2(10) >= 3 * armpro); + + if (!negated && mhm->damage < mdef->mhp) + mhm->damage = mon_poly(magr, mdef, mhm->damage); + } else if (mdef == &g.youmonst) { + /* mhitu */ + int armpro = magic_negation(mdef); + boolean uncancelled = !magr->mcan && (rn2(10) >= 3 * armpro); + + if (uncancelled + && Maybe_Half_Phys(mhm->damage) < (Upolyd ? u.mh : u.uhp)) + mhm->damage = mon_poly(magr, mdef, mhm->damage); + } else { + /* mhitm */ + if (!magr->mcan && mhm->damage < mdef->mhp) + mhm->damage = mon_poly(magr, mdef, mhm->damage); + } +} + +void +mhitm_ad_famn(magr, mattk, mdef, mhm) +struct monst *magr; +struct attack *mattk UNUSED; +struct monst *mdef; +struct mhitm_data *mhm; +{ + if (magr == &g.youmonst) { + /* uhitm */ + mhm->damage = 0; + } else if (mdef == &g.youmonst) { + /* mhitu */ + pline("%s reaches out, and your body shrivels.", Monnam(magr)); + exercise(A_CON, FALSE); + if (!is_fainted()) + morehungry(rn1(40, 40)); + /* plus the normal damage */ + } else { + /* mhitm */ + mhm->damage = 0; + } +} + +void +mhitm_ad_pest(magr, mattk, mdef, mhm) +struct monst *magr; +struct attack *mattk UNUSED; +struct monst *mdef; +struct mhitm_data *mhm; +{ + struct permonst *pa = magr->data; + + if (magr == &g.youmonst) { + /* uhitm */ + mhm->damage = 0; + } else if (mdef == &g.youmonst) { + /* mhitu */ + pline("%s reaches out, and you feel fever and chills.", Monnam(magr)); + (void) diseasemu(pa); + /* plus the normal damage */ + } else { + /* mhitm */ + mhm->damage = 0; + } +} + +void +mhitm_ad_deth(magr, mattk, mdef, mhm) +struct monst *magr; +struct attack *mattk UNUSED; +struct monst *mdef; +struct mhitm_data *mhm; +{ + struct permonst *pd = mdef->data; + + if (magr == &g.youmonst) { + /* uhitm */ + mhm->damage = 0; + } else if (mdef == &g.youmonst) { + /* mhitu */ + pline("%s reaches out with its deadly touch.", Monnam(magr)); + if (is_undead(pd)) { + /* Still does normal damage */ + pline("Was that the touch of death?"); + return; + } + switch (rn2(20)) { + case 19: + case 18: + case 17: + if (!Antimagic) { + g.killer.format = KILLED_BY_AN; + Strcpy(g.killer.name, "touch of death"); + done(DIED); + mhm->damage = 0; + return; + } + /*FALLTHRU*/ + default: /* case 16: ... case 5: */ + You_feel("your life force draining away..."); + mhm->permdmg = 1; /* actual damage done below */ + return; + case 4: + case 3: + case 2: + case 1: + case 0: + if (Antimagic) + shieldeff(u.ux, u.uy); + pline("Lucky for you, it didn't work!"); + mhm->damage = 0; + return; + } + } else { + /* mhitm */ + mhm->damage = 0; + } +} + +void +mhitm_ad_halu(magr, mattk, mdef, mhm) +struct monst *magr; +struct attack *mattk UNUSED; +struct monst *mdef; +struct mhitm_data *mhm; +{ + struct permonst *pd = mdef->data; + + if (magr == &g.youmonst) { + /* uhitm */ + mhm->damage = 0; + } else if (mdef == &g.youmonst) { + /* mhitu */ + mhm->damage = 0; + } else { + /* mhitm */ + if (!magr->mcan && haseyes(pd) && mdef->mcansee) { + if (g.vis && canseemon(mdef)) + pline("%s looks %sconfused.", Monnam(mdef), + mdef->mconf ? "more " : ""); + mdef->mconf = 1; + mdef->mstrategy &= ~STRAT_WAITFORU; + } + mhm->damage = 0; + } +} + +boolean +do_stone_u(mtmp) +struct monst *mtmp; +{ + if (!Stoned && !Stone_resistance + && !(poly_when_stoned(g.youmonst.data) + && polymon(PM_STONE_GOLEM))) { + int kformat = KILLED_BY_AN; + const char *kname = pmname(mtmp->data, Mgender(mtmp)); + + if (mtmp->data->geno & G_UNIQ) { + if (!type_is_pname(mtmp->data)) + kname = the(kname); + kformat = KILLED_BY; + } + make_stoned(5L, (char *) 0, kformat, kname); + return 1; + /* done_in_by(mtmp, STONING); */ + } + return 0; +} + +void +do_stone_mon(magr, mattk, mdef, mhm) +struct monst *magr; +struct attack *mattk UNUSED; +struct monst *mdef; +struct mhitm_data *mhm; +{ + struct permonst *pd = mdef->data; + + /* may die from the acid if it eats a stone-curing corpse */ + if (munstone(mdef, FALSE)) + goto post_stone; + if (poly_when_stoned(pd)) { + mon_to_stone(mdef); + mhm->damage = 0; + return; + } + if (!resists_ston(mdef)) { + if (g.vis && canseemon(mdef)) + pline("%s turns to stone!", Monnam(mdef)); + monstone(mdef); + post_stone: + if (!DEADMONSTER(mdef)) { + mhm->hitflags = MM_MISS; + mhm->done = TRUE; + return; + } else if (mdef->mtame && !g.vis) { + You(brief_feeling, "peculiarly sad"); + } + mhm->hitflags = (MM_DEF_DIED + | (grow_up(magr, mdef) ? 0 : MM_AGR_DIED)); + mhm->done = TRUE; + return; + } + mhm->damage = (mattk->adtyp == AD_STON ? 0 : 1); +} + +void +mhitm_ad_phys(magr, mattk, mdef, mhm) +struct monst *magr; +struct attack *mattk; +struct monst *mdef; +struct mhitm_data *mhm; +{ + struct permonst *pa = magr->data; + struct permonst *pd = mdef->data; + + if (magr == &g.youmonst) { + /* uhitm */ + if (pd == &mons[PM_SHADE]) { + mhm->damage = 0; + if (!mhm->specialdmg) + impossible("bad shade attack function flow?"); + } + mhm->damage += mhm->specialdmg; + + if (mattk->aatyp == AT_WEAP) { + /* hmonas() uses known_hitum() to deal physical damage, + then also damageum() for non-AD_PHYS; don't inflict + extra physical damage for unusual damage types */ + mhm->damage = 0; + } else if (mattk->aatyp == AT_KICK + || mattk->aatyp == AT_CLAW + || mattk->aatyp == AT_TUCH + || mattk->aatyp == AT_HUGS) { + if (thick_skinned(pd)) + mhm->damage = (mattk->aatyp == AT_KICK) ? 0 : (mhm->damage + 1) / 2; + /* add ring(s) of increase damage */ + if (u.udaminc > 0) { + /* applies even if damage was 0 */ + mhm->damage += u.udaminc; + } else if (mhm->damage > 0) { + /* ring(s) might be negative; avoid converting + 0 to non-0 or positive to non-positive */ + mhm->damage += u.udaminc; + if (mhm->damage < 1) + mhm->damage = 1; + } + } + } else if (mdef == &g.youmonst) { + /* mhitu */ + if (mattk->aatyp == AT_HUGS && !sticks(pd)) { + if (!u.ustuck && rn2(2)) { + if (u_slip_free(magr, mattk)) { + mhm->damage = 0; + } else { + set_ustuck(magr); + pline("%s grabs you!", Monnam(magr)); + } + } else if (u.ustuck == magr) { + exercise(A_STR, FALSE); + You("are being %s.", (magr->data == &mons[PM_ROPE_GOLEM]) + ? "choked" + : "crushed"); + } + } else { /* hand to hand weapon */ + struct obj *otmp = MON_WEP(magr); + + if (mattk->aatyp == AT_WEAP && otmp) { + struct obj *marmg; + int tmp; + + 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]); + if (!Stoned) { + if (do_stone_u(magr)) { + mhm->hitflags = MM_HIT; + mhm->done = 1; + return; + } + } + } + mhm->damage += dmgval(otmp, mdef); + if ((marmg = which_armor(magr, W_ARMG)) != 0 + && marmg->otyp == GAUNTLETS_OF_POWER) + mhm->damage += rn1(4, 3); /* 3..6 */ + if (mhm->damage <= 0) + mhm->damage = 1; + if (!(otmp->oartifact && artifact_hit(magr, mdef, otmp, + &mhm->damage, g.mhitu_dieroll))) + hitmsg(magr, mattk); + if (!mhm->damage) + return; + if (objects[otmp->otyp].oc_material == SILVER + && Hate_silver) { + pline_The("silver sears your flesh!"); + exercise(A_CON, FALSE); + } + /* this redundancy necessary because you have + to take the damage _before_ being cloned; + need to have at least 2 hp left to split */ + tmp = mhm->damage; + if (u.uac < 0) + tmp -= rnd(-u.uac); + if (tmp < 1) + tmp = 1; + if (u.mh - tmp > 1 + && (objects[otmp->otyp].oc_material == IRON + /* relevant 'metal' objects are scalpel and tsurugi */ + || objects[otmp->otyp].oc_material == METAL) + && (u.umonnum == PM_BLACK_PUDDING + || u.umonnum == PM_BROWN_PUDDING)) { + if (tmp > 1) + exercise(A_STR, FALSE); + /* inflict damage now; we know it can't be fatal */ + u.mh -= tmp; + g.context.botl = 1; + mhm->damage = 0; /* don't inflict more damage below */ + if (cloneu()) + You("divide as %s hits you!", mon_nam(magr)); + } + rustm(&g.youmonst, otmp); + } else if (mattk->aatyp != AT_TUCH || mhm->damage != 0 + || magr != u.ustuck) + hitmsg(magr, mattk); + } + } else { + /* mhitm */ + struct obj *mwep = MON_WEP(magr); + + if (mattk->aatyp != AT_WEAP && mattk->aatyp != AT_CLAW) + mwep = 0; + + if (shade_miss(magr, mdef, mwep, FALSE, TRUE)) { + mhm->damage = 0; + } else if (mattk->aatyp == AT_KICK && thick_skinned(pd)) { + /* [no 'kicking boots' check needed; monsters with kick attacks + can't wear boots and monsters that wear boots don't kick] */ + mhm->damage = 0; + } else if (mwep) { /* non-Null 'mwep' implies AT_WEAP || AT_CLAW */ + struct obj *marmg; + + if (mwep->otyp == CORPSE + && touch_petrifies(&mons[mwep->corpsenm])) { + do_stone_mon(magr, mattk, mdef, mhm); + if (mhm->done) + return; + } + + mhm->damage += dmgval(mwep, mdef); + if ((marmg = which_armor(magr, W_ARMG)) != 0 + && marmg->otyp == GAUNTLETS_OF_POWER) + mhm->damage += rn1(4, 3); /* 3..6 */ + if (mhm->damage < 1) /* is this necessary? mhitu.c has it... */ + mhm->damage = 1; + if (mwep->oartifact) { + /* when magr's weapon is an artifact, caller suppressed its + usual 'hit' message in case artifact_hit() delivers one; + now we'll know and might need to deliver skipped message + (note: if there's no message there'll be no auxilliary + damage so the message here isn't coming too late) */ + if (!artifact_hit(magr, mdef, mwep, &mhm->damage, mhm->dieroll)) { + if (g.vis) + pline("%s hits %s.", Monnam(magr), + mon_nam_too(mdef, magr)); + } + /* artifact_hit updates 'tmp' but doesn't inflict any + damage; however, it might cause carried items to be + destroyed and they might do so */ + if (DEADMONSTER(mdef)) { + mhm->hitflags = (MM_DEF_DIED | (grow_up(magr, mdef) ? 0 : MM_AGR_DIED)); + mhm->done = TRUE; + return; + } + } + if (mhm->damage) + rustm(mdef, mwep); + } 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 + won't swallow the corpse; but if the target survives, + the subsequent engulf attack should accomplish that */ + if (mhm->damage >= mdef->mhp && mdef->mhp > 1) + mhm->damage = mdef->mhp - 1; + } + } +} + +void +mhitm_ad_ston(magr, mattk, mdef, mhm) +struct monst *magr; +struct attack *mattk; +struct monst *mdef; +struct mhitm_data *mhm; +{ + if (magr == &g.youmonst) { + /* uhitm */ + if (!munstone(mdef, TRUE)) + minstapetrify(mdef, TRUE); + mhm->damage = 0; + } else if (mdef == &g.youmonst) { + /* mhitu */ + hitmsg(magr, mattk); + if (!rn2(3)) { + if (magr->mcan) { + if (!Deaf) + You_hear("a cough from %s!", mon_nam(magr)); + } else { + if (!Deaf) + You_hear("%s hissing!", s_suffix(mon_nam(magr))); + if (!rn2(10) + || (flags.moonphase == NEW_MOON && !have_lizard())) { + if (do_stone_u(magr)) { + mhm->hitflags = MM_HIT; + mhm->done = TRUE; + return; + } + } + } + } + } else { + /* mhitm */ + if (magr->mcan) + return; + do_stone_mon(magr, mattk, mdef, mhm); + if (mhm->done) + return; + } +} + +void +mhitm_ad_were(magr, mattk, mdef, mhm) +struct monst *magr; +struct attack *mattk; +struct monst *mdef; +struct mhitm_data *mhm; +{ + struct permonst *pa = magr->data; + + if (magr == &g.youmonst) { + /* uhitm */ + mhitm_ad_phys(magr, mattk, mdef, mhm); + if (mhm->done) + return; + } else if (mdef == &g.youmonst) { + /* mhitu */ + int armpro = magic_negation(mdef); + boolean uncancelled = !magr->mcan && (rn2(10) >= 3 * armpro); + + hitmsg(magr, mattk); + if (uncancelled && !rn2(4) && u.ulycn == NON_PM + && !Protection_from_shape_changers && !defends(AD_WERE, uwep)) { + You_feel("feverish."); + exercise(A_CON, FALSE); + set_ulycn(monsndx(pa)); + retouch_equipment(2); + } + } else { + /* mhitm */ + mhitm_ad_phys(magr, mattk, mdef, mhm); + if (mhm->done) + return; + } +} + +void +mhitm_ad_heal(magr, mattk, mdef, mhm) +struct monst *magr; +struct attack *mattk; +struct monst *mdef; +struct mhitm_data *mhm; +{ + struct permonst *pd = mdef->data; + + if (magr == &g.youmonst) { + /* uhitm */ + mhitm_ad_phys(magr, mattk, mdef, mhm); + if (mhm->done) + return; + } else if (mdef == &g.youmonst) { + /* mhitu */ + /* a cancelled nurse is just an ordinary monster, + * nurses don't heal those that cause petrification */ + if (magr->mcan || (Upolyd && touch_petrifies(pd))) { + hitmsg(magr, mattk); + return; + } + /* weapon check should match the one in sounds.c for MS_NURSE */ + if (!(uwep && (uwep->oclass == WEAPON_CLASS || is_weptool(uwep))) + && !uarmu && !uarm && !uarmc + && !uarms && !uarmg && !uarmf && !uarmh) { + boolean goaway = FALSE; + + pline("%s hits! (I hope you don't mind.)", Monnam(magr)); + if (Upolyd) { + u.mh += rnd(7); + if (!rn2(7)) { + /* no upper limit necessary; effect is temporary */ + u.mhmax++; + if (!rn2(13)) + goaway = TRUE; + } + if (u.mh > u.mhmax) + u.mh = u.mhmax; + } else { + u.uhp += rnd(7); + if (!rn2(7)) { + /* hard upper limit via nurse care: 25 * ulevel */ + if (u.uhpmax < 5 * u.ulevel + d(2 * u.ulevel, 10)) + u.uhpmax++; + if (!rn2(13)) + goaway = TRUE; + } + if (u.uhp > u.uhpmax) + u.uhp = u.uhpmax; + } + if (!rn2(3)) + exercise(A_STR, TRUE); + if (!rn2(3)) + exercise(A_CON, TRUE); + if (Sick) + make_sick(0L, (char *) 0, FALSE, SICK_ALL); + g.context.botl = 1; + if (goaway) { + mongone(magr); + mhm->done = TRUE; + mhm->hitflags = MM_DEF_DIED; /* return 2??? */ + return; + } else if (!rn2(33)) { + if (!tele_restrict(magr)) + (void) rloc(magr, TRUE); + monflee(magr, d(3, 6), TRUE, FALSE); + mhm->done = TRUE; + mhm->hitflags = MM_HIT | MM_DEF_DIED; /* return 3??? */ + return; + } + mhm->damage = 0; + } else { + if (Role_if(PM_HEALER)) { + if (!Deaf && !(g.moves % 5)) + verbalize("Doc, I can't help you unless you cooperate."); + mhm->damage = 0; + } else + hitmsg(magr, mattk); + } + } else { + /* mhitm */ + mhitm_ad_phys(magr, mattk, mdef, mhm); + if (mhm->done) + return; + } +} + +void +mhitm_ad_stun(magr, mattk, mdef, mhm) +struct monst *magr; +struct attack *mattk; +struct monst *mdef; +struct mhitm_data *mhm; +{ + struct permonst *pd = mdef->data; + + if (magr == &g.youmonst) { + /* uhitm */ + if (!Blind) + pline("%s %s for a moment.", Monnam(mdef), + makeplural(stagger(pd, "stagger"))); + mdef->mstun = 1; + mhitm_ad_phys(magr, mattk, mdef, mhm); + if (mhm->done) + return; + } else if (mdef == &g.youmonst) { + /* mhitu */ + hitmsg(magr, mattk); + if (!magr->mcan && !rn2(4)) { + make_stunned((HStun & TIMEOUT) + (long) mhm->damage, TRUE); + mhm->damage /= 2; + } + } else { + /* mhitm */ + if (magr->mcan) + return; + if (canseemon(mdef)) + pline("%s %s for a moment.", Monnam(mdef), + makeplural(stagger(pd, "stagger"))); + mdef->mstun = 1; + mhitm_ad_phys(magr, mattk, mdef, mhm); + if (mhm->done) + return; + } +} + +void +mhitm_ad_legs(magr, mattk, mdef, mhm) +struct monst *magr; +struct attack *mattk; +struct monst *mdef; +struct mhitm_data *mhm; +{ + if (magr == &g.youmonst) { + /* uhitm */ +#if 0 + if (u.ucancelled) { + mhm->damage = 0; + return; + } +#endif + mhitm_ad_phys(magr, mattk, mdef, mhm); + if (mhm->done) + return; + } else if (mdef == &g.youmonst) { + /* mhitu */ + long side = rn2(2) ? RIGHT_SIDE : LEFT_SIDE; + const char *sidestr = (side == RIGHT_SIDE) ? "right" : "left", + *Monst_name = Monnam(magr), *leg = body_part(LEG); + + /* This case is too obvious to ignore, but Nethack is not in + * general very good at considering height--most short monsters + * still _can_ attack you when you're flying or mounted. + */ + if ((u.usteed || Levitation || Flying) && !is_flyer(magr->data)) { + 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), + sidestr, leg); + mhm->damage = 0; + } else { + if (uarmf) { + if (rn2(2) && (uarmf->otyp == LOW_BOOTS + || uarmf->otyp == IRON_SHOES)) { + pline("%s pricks the exposed part of your %s %s!", + Monst_name, sidestr, leg); + } else if (!rn2(5)) { + pline("%s pricks through your %s boot!", Monst_name, + sidestr); + } else { + pline("%s scratches your %s boot!", Monst_name, + sidestr); + mhm->damage = 0; + return; + } + } else + pline("%s pricks your %s %s!", Monst_name, sidestr, leg); + + set_wounded_legs(side, rnd(60 - ACURR(A_DEX))); + exercise(A_STR, FALSE); + exercise(A_DEX, FALSE); + } + } else { + /* mhitm */ + if (magr->mcan) { + mhm->damage = 0; + return; + } + mhitm_ad_phys(magr, mattk, mdef, mhm); + if (mhm->done) + return; + } +} + +void +mhitm_ad_dgst(magr, mattk, mdef, mhm) +struct monst *magr; +struct attack *mattk UNUSED; +struct monst *mdef; +struct mhitm_data *mhm; +{ + struct permonst *pd = mdef->data; + + if (magr == &g.youmonst) { + /* uhitm */ + mhm->damage = 0; + } else if (mdef == &g.youmonst) { + /* mhitu */ + mhm->damage = 0; + } else { + /* mhitm */ + int num; + struct obj *obj; + + /* eating a Rider or its corpse is fatal */ + if (is_rider(pd)) { + if (g.vis && canseemon(magr)) + pline("%s %s!", Monnam(magr), + (pd == &mons[PM_FAMINE]) + ? "belches feebly, shrivels up and dies" + : (pd == &mons[PM_PESTILENCE]) + ? "coughs spasmodically and collapses" + : "vomits violently and drops dead"); + mondied(magr); + if (!DEADMONSTER(magr)) { + mhm->hitflags = MM_MISS; /* lifesaved */ + mhm->done = TRUE; + return; + } else if (magr->mtame && !g.vis) + You(brief_feeling, "queasy"); + mhm->hitflags = MM_AGR_DIED; + mhm->done = TRUE; + return; + } + if (flags.verbose && !Deaf) + verbalize("Burrrrp!"); + mhm->damage = mdef->mhp; + /* Use up amulet of life saving */ + if ((obj = mlifesaver(mdef)) != 0) + m_useup(mdef, obj); + + /* Is a corpse for nutrition possible? It may kill magr */ + if (!corpse_chance(mdef, magr, TRUE) || DEADMONSTER(magr)) + return; + + /* Pets get nutrition from swallowing monster whole. + * No nutrition from G_NOCORPSE monster, eg, undead. + * DGST monsters don't die from undead corpses + */ + num = monsndx(pd); + if (magr->mtame && !magr->isminion + && !(g.mvitals[num].mvflags & G_NOCORPSE)) { + struct obj *virtualcorpse = mksobj(CORPSE, FALSE, FALSE); + int nutrit; + + set_corpsenm(virtualcorpse, num); + nutrit = dog_nutrition(magr, virtualcorpse); + dealloc_obj(virtualcorpse); + + /* only 50% nutrition, 25% of normal eating time */ + if (magr->meating > 1) + magr->meating = (magr->meating + 3) / 4; + if (nutrit > 1) + nutrit /= 2; + EDOG(magr)->hungrytime += nutrit; + } + } +} + +void +mhitm_ad_samu(magr, mattk, mdef, mhm) +struct monst *magr; +struct attack *mattk; +struct monst *mdef; +struct mhitm_data *mhm; +{ + if (magr == &g.youmonst) { + /* uhitm */ + mhm->damage = 0; + } else if (mdef == &g.youmonst) { + /* mhitu */ + hitmsg(magr, mattk); + /* when the Wizard or quest nemesis hits, there's a 1/20 chance + to steal a quest artifact (any, not just the one for the hero's + own role) or the Amulet or one of the invocation tools */ + if (!rn2(20)) + stealamulet(magr); + } else { + /* mhitm */ + mhm->damage = 0; + } +} + +void +mhitm_ad_dise(magr, mattk, mdef, mhm) +struct monst *magr; +struct attack *mattk; +struct monst *mdef; +struct mhitm_data *mhm; +{ + struct permonst *pa = magr->data; + + if (magr == &g.youmonst) { + /* uhitm */ + mhm->damage = 0; + } else if (mdef == &g.youmonst) { + /* mhitu */ + hitmsg(magr, mattk); + if (!diseasemu(pa)) + mhm->damage = 0; + } else { + /* mhitm */ + mhm->damage = 0; + } +} + +void +mhitm_ad_sedu(magr, mattk, mdef, mhm) +struct monst *magr; +struct attack *mattk; +struct monst *mdef; +struct mhitm_data *mhm; +{ + struct permonst *pa = magr->data; + + if (magr == &g.youmonst) { + /* uhitm */ + steal_it(mdef, mattk); + mhm->damage = 0; + } else if (mdef == &g.youmonst) { + /* mhitu */ + char buf[BUFSZ]; + + if (is_animal(magr->data)) { + hitmsg(magr, mattk); + if (magr->mcan) + return; + /* Continue below */ + } else if (dmgtype(g.youmonst.data, AD_SEDU) + /* !SYSOPT_SEDUCE: when hero is attacking and AD_SSEX + is disabled, it would be changed to another damage + type, but when defending, it remains as-is */ + || dmgtype(g.youmonst.data, AD_SSEX)) { + pline("%s %s.", Monnam(magr), + Deaf ? "says something but you can't hear it" + : magr->minvent + ? "brags about the goods some dungeon explorer provided" + : "makes some remarks about how difficult theft is lately"); + if (!tele_restrict(magr)) + (void) rloc(magr, TRUE); + mhm->hitflags = MM_AGR_DONE; /* return 3??? */ + mhm->done = TRUE; + return; + } else if (magr->mcan) { + if (!Blind) + pline("%s tries to %s you, but you seem %s.", + Adjmonnam(magr, "plain"), + flags.female ? "charm" : "seduce", + flags.female ? "unaffected" : "uninterested"); + if (rn2(3)) { + if (!tele_restrict(magr)) + (void) rloc(magr, TRUE); + mhm->hitflags = MM_AGR_DONE; /* return 3??? */ + mhm->done = TRUE; + return; + } + return; + } + buf[0] = '\0'; + switch (steal(magr, buf)) { + case -1: + mhm->hitflags = MM_AGR_DIED; /* return 2??? */ + mhm->done = TRUE; + return; + case 0: + return; + default: + if (!is_animal(magr->data) && !tele_restrict(magr)) + (void) rloc(magr, TRUE); + if (is_animal(magr->data) && *buf) { + if (canseemon(magr)) + pline("%s tries to %s away with %s.", Monnam(magr), + locomotion(magr->data, "run"), buf); + } + monflee(magr, 0, FALSE, FALSE); + mhm->hitflags = MM_AGR_DONE; /* return 3??? */ + mhm->done = TRUE; + return; + } + } else { + /* mhitm */ + struct obj *obj; + + if (magr->mcan) + return; + /* find an object to steal, non-cursed if magr is tame */ + for (obj = mdef->minvent; obj; obj = obj->nobj) + if (!magr->mtame || !obj->cursed) + return; + + if (obj) { + char buf[BUFSZ]; + char onambuf[BUFSZ], mdefnambuf[BUFSZ]; + + /* make a special x_monnam() call that never omits + the saddle, and save it for later messages */ + Strcpy(mdefnambuf, + x_monnam(mdef, ARTICLE_THE, (char *) 0, 0, FALSE)); + + if (u.usteed == mdef && obj == which_armor(mdef, W_SADDLE)) + /* "You can no longer ride ." */ + dismount_steed(DISMOUNT_POLY); + obj_extract_self(obj); + if (obj->owornmask) { + mdef->misc_worn_check &= ~obj->owornmask; + if (obj->owornmask & W_WEP) + mwepgone(mdef); + obj->owornmask = 0L; + update_mon_intrinsics(mdef, obj, FALSE, FALSE); + /* give monster a chance to wear other equipment on its next + move instead of waiting until it picks something up */ + mdef->misc_worn_check |= I_SPECIAL; + } + /* add_to_minv() might free 'obj' [if it merges] */ + if (g.vis) + Strcpy(onambuf, doname(obj)); + (void) add_to_minv(magr, obj); + if (g.vis && canseemon(mdef)) { + Strcpy(buf, Monnam(magr)); + pline("%s steals %s from %s!", buf, onambuf, mdefnambuf); + } + possibly_unwield(mdef, FALSE); + mdef->mstrategy &= ~STRAT_WAITFORU; + mselftouch(mdef, (const char *) 0, FALSE); + if (DEADMONSTER(mdef)) { + mhm->hitflags = (MM_DEF_DIED | (grow_up(magr, mdef) ? 0 : MM_AGR_DIED)); + mhm->done = TRUE; + return; + } + if (pa->mlet == S_NYMPH && !tele_restrict(magr)) { + boolean couldspot = canspotmon(magr); + + (void) rloc(magr, TRUE); + if (g.vis && couldspot && !canspotmon(magr)) + pline("%s suddenly disappears!", buf); + } + } + mhm->damage = 0; + } +} + +void +mhitm_ad_ssex(magr, mattk, mdef, mhm) +struct monst *magr; +struct attack *mattk; +struct monst *mdef; +struct mhitm_data *mhm; +{ + if (magr == &g.youmonst) { + /* uhitm */ + mhitm_ad_sedu(magr, mattk, mdef, mhm); + if (mhm->done) + return; + } else if (mdef == &g.youmonst) { + /* mhitu */ + if (SYSOPT_SEDUCE) { + if (could_seduce(magr, mdef, mattk) == 1 && !magr->mcan) + if (doseduce(magr)) { + mhm->hitflags = MM_AGR_DONE; + mhm->done = TRUE; + return; + } + return; + } + mhitm_ad_sedu(magr, mattk, mdef, mhm); + if (mhm->done) + return; + } else { + /* mhitm */ + mhitm_ad_sedu(magr, mattk, mdef, mhm); + if (mhm->done) + return; + } +} + +void +mhitm_adtyping(magr, mattk, mdef, mhm) +struct monst *magr; +struct attack *mattk; +struct monst *mdef; +struct mhitm_data *mhm; +{ + switch (mattk->adtyp) { + case AD_STUN: mhitm_ad_stun(magr, mattk, mdef, mhm); break; + case AD_LEGS: mhitm_ad_legs(magr, mattk, mdef, mhm); break; + case AD_WERE: mhitm_ad_were(magr, mattk, mdef, mhm); break; + case AD_HEAL: mhitm_ad_heal(magr, mattk, mdef, mhm); break; + case AD_PHYS: mhitm_ad_phys(magr, mattk, mdef, mhm); break; + case AD_FIRE: mhitm_ad_fire(magr, mattk, mdef, mhm); break; + case AD_COLD: mhitm_ad_cold(magr, mattk, mdef, mhm); break; + case AD_ELEC: mhitm_ad_elec(magr, mattk, mdef, mhm); break; + case AD_ACID: mhitm_ad_acid(magr, mattk, mdef, mhm); break; + case AD_STON: mhitm_ad_ston(magr, mattk, mdef, mhm); break; + case AD_SSEX: mhitm_ad_ssex(magr, mattk, mdef, mhm); break; + case AD_SITM: + case AD_SEDU: mhitm_ad_sedu(magr, mattk, mdef, mhm); break; + case AD_SGLD: mhitm_ad_sgld(magr, mattk, mdef, mhm); break; + case AD_TLPT: mhitm_ad_tlpt(magr, mattk, mdef, mhm); break; + case AD_BLND: mhitm_ad_blnd(magr, mattk, mdef, mhm); break; + case AD_CURS: mhitm_ad_curs(magr, mattk, mdef, mhm); break; + case AD_DRLI: mhitm_ad_drli(magr, mattk, mdef, mhm); break; + case AD_RUST: mhitm_ad_rust(magr, mattk, mdef, mhm); break; + case AD_CORR: mhitm_ad_corr(magr, mattk, mdef, mhm); break; + case AD_DCAY: mhitm_ad_dcay(magr, mattk, mdef, mhm); break; + case AD_DREN: mhitm_ad_dren(magr, mattk, mdef, mhm); break; + case AD_DRST: + case AD_DRDX: + case AD_DRCO: mhitm_ad_drst(magr, mattk, mdef, mhm); break; + case AD_DRIN: mhitm_ad_drin(magr, mattk, mdef, mhm); break; + case AD_STCK: mhitm_ad_stck(magr, mattk, mdef, mhm); break; + case AD_WRAP: mhitm_ad_wrap(magr, mattk, mdef, mhm); break; + case AD_PLYS: mhitm_ad_plys(magr, mattk, mdef, mhm); break; + case AD_SLEE: mhitm_ad_slee(magr, mattk, mdef, mhm); break; + case AD_SLIM: mhitm_ad_slim(magr, mattk, mdef, mhm); break; + case AD_ENCH: mhitm_ad_ench(magr, mattk, mdef, mhm); break; + case AD_SLOW: mhitm_ad_slow(magr, mattk, mdef, mhm); break; + case AD_CONF: mhitm_ad_conf(magr, mattk, mdef, mhm); break; + case AD_POLY: mhitm_ad_poly(magr, mattk, mdef, mhm); break; + case AD_DISE: mhitm_ad_dise(magr, mattk, mdef, mhm); break; + case AD_SAMU: mhitm_ad_samu(magr, mattk, mdef, mhm); break; + case AD_DETH: mhitm_ad_deth(magr, mattk, mdef, mhm); break; + case AD_PEST: mhitm_ad_pest(magr, mattk, mdef, mhm); break; + case AD_FAMN: mhitm_ad_famn(magr, mattk, mdef, mhm); break; + case AD_DGST: mhitm_ad_dgst(magr, mattk, mdef, mhm); break; + case AD_HALU: mhitm_ad_halu(magr, mattk, mdef, mhm); break; default: - tmp = 0; - break; + mhm->damage = 0; + } +} + +int +damageum(mdef, mattk, specialdmg) +register struct monst *mdef; +register struct attack *mattk; +int specialdmg; /* blessed and/or silver bonus against various things */ +{ + int armpro; + boolean negated; + struct mhitm_data mhm; + mhm.damage = d((int) mattk->damn, (int) mattk->damd); + mhm.hitflags = MM_MISS; + mhm.permdmg = 0; + mhm.specialdmg = specialdmg; + mhm.done = FALSE; + + armpro = magic_negation(mdef); + /* since hero can't be cancelled, only defender's armor applies */ + negated = !(rn2(10) >= 3 * armpro); + + if (is_demon(g.youmonst.data) && !rn2(13) && !uwep + && u.umonnum != PM_AMOROUS_DEMON && u.umonnum != PM_BALROG) { + demonpet(); + return MM_MISS; } + mhitm_adtyping(&g.youmonst, mattk, mdef, &mhm); + if (mhm.done) + return mhm.hitflags; + mdef->mstrategy &= ~STRAT_WAITFORU; /* in case player is very fast */ - mdef->mhp -= tmp; + mdef->mhp -= mhm.damage; if (DEADMONSTER(mdef)) { if (mdef->mtame && !cansee(mdef->mx, mdef->my)) { You_feel("embarrassed for a moment."); - if (tmp) - xkilled(mdef, XKILL_NOMSG); /* !tmp but hp<1: already killed */ + if (mhm.damage) + xkilled(mdef, XKILL_NOMSG); /* !mhm.damage but hp<1: already killed */ } else if (!flags.verbose) { You("destroy it!"); - if (tmp) + if (mhm.damage) xkilled(mdef, XKILL_NOMSG); - } else if (tmp) + } else if (mhm.damage) killed(mdef); - return 2; + return MM_DEF_DIED; } - return 1; + return MM_HIT; } static int @@ -2086,7 +4265,7 @@ register struct attack *mattk; mdef->mhp -= tmp; if (DEADMONSTER(mdef)) { killed(mdef); - return 2; + return MM_DEF_DIED; } } else { shieldeff(mdef->mx, mdef->my); @@ -2099,7 +4278,7 @@ register struct attack *mattk; default: break; } - return 1; + return MM_HIT; } static void @@ -2150,7 +4329,7 @@ register struct attack *mattk; */ if (!engulf_target(&g.youmonst, mdef)) - return 0; + return MM_MISS; if (u.uhunger < 1500 && !u.uswallow) { for (otmp = mdef->minvent; otmp; otmp = otmp->nobj) @@ -2165,7 +4344,7 @@ register struct attack *mattk; pline("It turns into %s.", a_monnam(mdef)); else map_invisible(mdef->mx, mdef->my); - return 1; + return MM_HIT; } /* engulfing a cockatrice or digesting a Rider or Medusa */ @@ -2179,12 +4358,12 @@ register struct attack *mattk; if (fatal_gulp && !is_rider(pd)) { /* petrification */ char kbuf[BUFSZ]; - const char *mname = pd->mname; + const char *mnam = pmname(pd, Mgender(mdef)); if (!type_is_pname(pd)) - mname = an(mname); + mnam = an(mnam); You("englut %s.", mon_nam(mdef)); - Sprintf(kbuf, "swallowing %s whole", mname); + Sprintf(kbuf, "swallowing %s whole", mnam); instapetrify(kbuf); } else { start_engulf(mdef); @@ -2195,10 +4374,10 @@ register struct attack *mattk; pline("Unfortunately, digesting any of it is fatal."); end_engulf(); Sprintf(g.killer.name, "unwisely tried to eat %s", - pd->mname); + pmname(pd, Mgender(mdef))); g.killer.format = NO_KILLER_PREFIX; done(DIED); - return 0; /* lifesaved */ + return MM_MISS; /* lifesaved */ } if (Slow_digestion) { @@ -2246,7 +4425,7 @@ register struct attack *mattk; pline1(msgbuf); if (pd == &mons[PM_GREEN_SLIME]) { Sprintf(msgbuf, "%s isn't sitting well with you.", - The(pd->mname)); + The(pmname(pd, Mgender(mdef)))); if (!Unchanging) { make_slimed(5L, (char *) 0); } @@ -2254,7 +4433,7 @@ register struct attack *mattk; exercise(A_CON, TRUE); } end_engulf(); - return 2; + return MM_DEF_DIED; case AD_PHYS: if (g.youmonst.data == &mons[PM_FOG_CLOUD]) { pline("%s is laden with your moisture.", Monnam(mdef)); @@ -2330,7 +4509,7 @@ register struct attack *mattk; if (DEADMONSTER(mdef)) { killed(mdef); if (DEADMONSTER(mdef)) /* not lifesaved */ - return 2; + return MM_DEF_DIED; } You("%s %s!", is_animal(g.youmonst.data) ? "regurgitate" : "expel", mon_nam(mdef)); @@ -2340,7 +4519,7 @@ register struct attack *mattk; } } } - return 0; + return MM_MISS; } void @@ -2370,14 +4549,14 @@ register struct monst *mon; struct attack *mattk, alt_attk; struct obj *weapon, **originalweapon; boolean altwep = FALSE, weapon_used = FALSE, odd_claw = TRUE; - int i, tmp, armorpenalty, sum[NATTK], nsum = 0, dhit = 0, attknum = 0; + int i, tmp, armorpenalty, sum[NATTK], nsum = MM_MISS, dhit = 0, attknum = 0; int dieroll, multi_claw = 0; /* with just one touch/claw/weapon attack, both rings matter; with more than one, alternate right and left when checking whether silver ring causes successful hit */ for (i = 0; i < NATTK; i++) { - sum[i] = 0; + sum[i] = MM_MISS; mattk = getmattk(&g.youmonst, mon, i, sum, &alt_attk); if (mattk->aatyp == AT_WEAP || mattk->aatyp == AT_CLAW || mattk->aatyp == AT_TUCH) @@ -2385,9 +4564,13 @@ register struct monst *mon; } multi_claw = (multi_claw > 1); /* switch from count to yes/no */ + g.skipdrin = FALSE; /* [see mattackm(mhitm.c)] */ + for (i = 0; i < NATTK; i++) { - /* sum[i] = 0; -- now done above */ + /* sum[i] = MM_MISS; -- now done above */ mattk = getmattk(&g.youmonst, mon, i, sum, &alt_attk); + if (g.skipdrin && mattk->aatyp == AT_TENT && mattk->adtyp == AD_DRIN) + continue; weapon = 0; switch (mattk->aatyp) { case AT_WEAP: @@ -2398,7 +4581,7 @@ register struct monst *mon; get to make another weapon attack (note: monsters who use weapons do not have this restriction, but they also never have the opportunity to use two weapons) */ - if (weapon_used && sum[i - 1] && uwep && bimanual(uwep)) + if (weapon_used && (sum[i - 1] > MM_MISS) && uwep && bimanual(uwep)) continue; /* Certain monsters don't use weapons when encountered as enemies, * but players who polymorph into them have hands or claws and @@ -2447,10 +4630,10 @@ register struct monst *mon; if (!known_hitum(mon, weapon, &dhit, tmp, armorpenalty, mattk, dieroll)) { /* enemy dead, before any special abilities used */ - sum[i] = 2; + sum[i] = MM_DEF_DIED; break; } else - sum[i] = dhit; + sum[i] = dhit ? MM_HIT : MM_MISS; /* originalweapon points to an equipment slot which might now be empty if the weapon was destroyed during the hit; passive(,weapon,...) won't call passive_obj() in that case */ @@ -2647,7 +4830,7 @@ register struct monst *mon; if (silverhit && flags.verbose) silver_sears(&g.youmonst, mon, silverhit); sum[i] = damageum(mon, mattk, specialdmg); - } else if (i >= 2 && sum[i - 1] && sum[i - 2]) { + } else if (i >= 2 && (sum[i - 1] > MM_MISS) && (sum[i - 2] > MM_MISS)) { /* in case we're hugging a new target while already holding something else; yields feedback " is no longer in your clutches" */ @@ -2673,11 +4856,11 @@ register struct monst *mon; &attknum, &armorpenalty); if ((dhit = (tmp > rnd(20 + i)))) { wakeup(mon, TRUE); - if (mon->data == &mons[PM_SHADE]) + if (mon->data == &mons[PM_SHADE]) { Your("attempt to surround %s is harmless.", mon_nam(mon)); - else { + } else { sum[i] = gulpum(mon, mattk); - if (sum[i] == 2 && (mon->data->mlet == S_ZOMBIE + if (sum[i] == MM_DEF_DIED && (mon->data->mlet == S_ZOMBIE || mon->data->mlet == S_MUMMY) && rn2(5) && !Sick_resistance) { You_feel("%ssick.", (Sick) ? "very " : ""); @@ -2717,12 +4900,12 @@ register struct monst *mon; u.mh = -1; /* dead in the current form */ rehumanize(); } - if (sum[i] == 2) { + if (sum[i] == MM_DEF_DIED) { /* defender dead */ (void) passive(mon, weapon, 1, 0, mattk->aatyp, FALSE); - nsum = 0; /* return value below used to be 'nsum > 0' */ + nsum = MM_MISS; /* return value below used to be 'nsum > 0' */ } else { - (void) passive(mon, weapon, sum[i], 1, mattk->aatyp, FALSE); + (void) passive(mon, weapon, (sum[i] != MM_MISS), 1, mattk->aatyp, FALSE); nsum |= sum[i]; } @@ -2752,16 +4935,18 @@ register struct monst *mon; /* Special (passive) attacks on you by monsters done here. */ int -passive(mon, weapon, mhit, malive, aatyp, wep_was_destroyed) +passive(mon, weapon, mhitb, maliveb, aatyp, wep_was_destroyed) struct monst *mon; struct obj *weapon; /* uwep or uswapwep or uarmg or uarmf or Null */ -boolean mhit; -int malive; +boolean mhitb; +boolean maliveb; uchar aatyp; boolean wep_was_destroyed; { register struct permonst *ptr = mon->data; register int i, tmp; + int mhit = mhitb ? MM_HIT : MM_MISS; + int malive = maliveb ? MM_HIT : MM_MISS; for (i = 0;; i++) { if (i >= NATTK) @@ -2781,7 +4966,7 @@ boolean wep_was_destroyed; */ switch (ptr->mattk[i].adtyp) { case AD_FIRE: - if (mhit && !mon->mcan && weapon) { + if (mhitb && !mon->mcan && weapon) { if (aatyp == AT_KICK) { if (uarmf && !rn2(6)) (void) erode_obj(uarmf, xname(uarmf), ERODE_BURN, @@ -2792,7 +4977,7 @@ boolean wep_was_destroyed; } break; case AD_ACID: - if (mhit && rn2(2)) { + if (mhitb && rn2(2)) { if (Blind || !flags.verbose) You("are splashed!"); else @@ -2804,7 +4989,7 @@ boolean wep_was_destroyed; if (!rn2(30)) erode_armor(&g.youmonst, ERODE_CORRODE); } - if (mhit && weapon) { + if (mhitb && weapon) { if (aatyp == AT_KICK) { if (uarmf && !rn2(6)) (void) erode_obj(uarmf, xname(uarmf), ERODE_CORRODE, @@ -2816,7 +5001,7 @@ boolean wep_was_destroyed; exercise(A_STR, FALSE); break; case AD_STON: - if (mhit) { /* successful attack */ + if (mhitb) { /* successful attack */ long protector = attk_protection((int) aatyp); /* hero using monsters' AT_MAGC attack is hitting hand to @@ -2834,13 +5019,13 @@ boolean wep_was_destroyed; && !(poly_when_stoned(g.youmonst.data) && polymon(PM_STONE_GOLEM))) { done_in_by(mon, STONING); /* "You turn to stone..." */ - return 2; + return MM_DEF_DIED; } } } break; case AD_RUST: - if (mhit && !mon->mcan && weapon) { + if (mhitb && !mon->mcan && weapon) { if (aatyp == AT_KICK) { if (uarmf) (void) erode_obj(uarmf, xname(uarmf), ERODE_RUST, @@ -2851,7 +5036,7 @@ boolean wep_was_destroyed; } break; case AD_CORR: - if (mhit && !mon->mcan && weapon) { + if (mhitb && !mon->mcan && weapon) { if (aatyp == AT_KICK) { if (uarmf) (void) erode_obj(uarmf, xname(uarmf), ERODE_CORRODE, @@ -2872,7 +5057,7 @@ boolean wep_was_destroyed; } break; case AD_ENCH: /* KMH -- remove enchantment (disenchanter) */ - if (mhit) { + if (mhitb) { if (aatyp == AT_KICK) { if (!weapon) break; @@ -3064,7 +5249,9 @@ struct monst *mtmp; { const char *fmt = "Wait! That's %s!", *generic = "a monster", *what = 0; - if (!u.ustuck && !mtmp->mflee && dmgtype(mtmp->data, AD_STCK)) + if (!u.ustuck && !mtmp->mflee && dmgtype(mtmp->data, AD_STCK) + /* must be adjacent; attack via polearm could be from farther away */ + && distu(mtmp->mx, mtmp->my) <= 2) set_ustuck(mtmp); if (Blind) { diff --git a/src/vault.c b/src/vault.c index 129177f31..8fb059a9e 100644 --- a/src/vault.c +++ b/src/vault.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 vault.c $NHDT-Date: 1549921171 2019/02/11 21:39:31 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.62 $ */ +/* NetHack 3.7 vault.c $NHDT-Date: 1606009006 2020/11/22 01:36:46 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.77 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2011. */ /* NetHack may be freely redistributed. See license for details. */ @@ -249,7 +249,7 @@ struct monst *grd; } /* if carrying gold and arriving anywhere other than next to the guard, set the guard loose */ - if ((money_cnt(g.invent) || hidden_gold()) + if ((money_cnt(g.invent) || hidden_gold(TRUE)) && um_dist(grd->mx, grd->my, 1)) { if (grd->mpeaceful) { if (canspotmon(grd)) /* see or sense via telepathy */ @@ -397,7 +397,7 @@ invault() gsensed = !canspotmon(guard); if (!gsensed) pline("Suddenly one of the Vault's %s enters!", - makeplural(guard->data->mname)); + makeplural(pmname(guard->data, Mgender(guard)))); else pline("Someone else has entered the Vault."); newsym(guard->mx, guard->my); @@ -487,7 +487,7 @@ invault() else verbalize("I don't know you."); umoney = money_cnt(g.invent); - if (!umoney && !hidden_gold()) { + if (!umoney && !hidden_gold(TRUE)) { if (Deaf) pline("%s stomps%s.", noit_Monnam(guard), (Blind) ? "" : " and beckons"); @@ -795,7 +795,7 @@ register struct monst *grd; } umoney = money_cnt(g.invent); - u_carry_gold = umoney > 0L || hidden_gold() > 0L; + u_carry_gold = (umoney > 0L || hidden_gold(TRUE) > 0L); if (egrd->fcend == 1) { if (u_in_vault && (u_carry_gold || um_dist(grd->mx, grd->my, 1))) { if (egrd->warncnt == 3 && !Deaf) @@ -1091,7 +1091,8 @@ boolean silently; gx = g.rooms[EGD(grd)->vroom].lx + rn2(2); gy = g.rooms[EGD(grd)->vroom].ly + rn2(2); Sprintf(buf, "To Croesus: here's the gold recovered from %s the %s.", - g.plname, mons[u.umonster].mname); + g.plname, + pmname(&mons[u.umonster], flags.female ? FEMALE : MALE)); make_grave(gx, gy, buf); } for (coins = g.invent; coins; coins = nextcoins) { @@ -1107,15 +1108,17 @@ boolean silently; return; } +/* amount of gold in carried containers */ long -hidden_gold() +hidden_gold(even_if_unknown) +boolean even_if_unknown; /* True: all gold; False: limit to known contents */ { long value = 0L; struct obj *obj; for (obj = g.invent; obj; obj = obj->nobj) - if (Has_contents(obj)) - value += contained_gold(obj); + if (Has_contents(obj) && (obj->cknown || even_if_unknown)) + value += contained_gold(obj, even_if_unknown); /* unknown gold stuck inside statues may cause some consternation... */ return value; diff --git a/src/version.c b/src/version.c index 3d3ae6999..f8fd308d1 100644 --- a/src/version.c +++ b/src/version.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 version.c $NHDT-Date: 1575161965 2019/12/01 00:59:25 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.69 $ */ +/* NetHack 3.7 version.c $NHDT-Date: 1596498224 2020/08/03 23:43:44 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.74 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2018. */ /* NetHack may be freely redistributed. See license for details. */ @@ -29,7 +29,7 @@ struct cross_target_s cross_target = { #if defined(NETHACK_GIT_SHA) const char *NetHack_git_sha -#if !defined(CROSSCOMPILE) || (defined(CROSSCOMPILE) && defined(CROSSCOMPILE_HOST)) +#if !defined(CROSSCOMPILE) || !defined(CROSSCOMPILE_TARGET) = NETHACK_GIT_SHA #else #ifdef NETHACK_HOST_GIT_SHA @@ -41,7 +41,7 @@ const char *NetHack_git_sha #if defined(NETHACK_GIT_BRANCH) const char *NetHack_git_branch -#if !defined(CROSSCOMPILE) || (defined(CROSSCOMPILE) && defined(CROSSCOMPILE_HOST)) +#if !defined(CROSSCOMPILE) || !defined(CROSSCOMPILE_TARGET) = NETHACK_GIT_BRANCH #else #ifdef NETHACK_HOST_GIT_BRANCH @@ -247,7 +247,8 @@ doextversion() return 0; } -void early_version_info(pastebuf) +void +early_version_info(pastebuf) boolean pastebuf; { char buf[BUFSZ], buf2[BUFSZ]; @@ -265,7 +266,7 @@ boolean pastebuf; raw_printf("%s", buf2); if (pastebuf) { -#ifdef RUNTIME_PASTEBUF_SUPPORT +#if defined(RUNTIME_PASTEBUF_SUPPORT) && !defined(LIBNH) /* * Call a platform/port-specific routine to insert the * version information into a paste buffer. Useful for @@ -429,7 +430,7 @@ void store_version(nhfp) NHFILE *nhfp; { -#if !defined(CROSSCOMPILE) || defined(CROSSCOMPILE_HOST) +#if !defined(CROSSCOMPILE) || !defined(CROSSCOMPILE_TARGET) static const struct version_info version_data = { VERSION_NUMBER, VERSION_FEATURES, VERSION_SANITY1, VERSION_SANITY2, VERSION_SANITY3 @@ -439,7 +440,7 @@ NHFILE *nhfp; #endif }; -#if defined(CROSSCOMPILE) && !defined(CROSSCOMPILE_HOST) +#if defined(CROSSCOMPILE) && defined(CROSSCOMPILE_TARGET) version_data.incarnation = VERSION_NUMBER; /* actual version number */ version_data.feature_set = VERSION_FEATURES; /* bitmask of config settings */ version_data.entity_count = VERSION_SANITY1; /* # of monsters and objects */ diff --git a/src/vision.c b/src/vision.c index 2d9f8bd24..9d291ae40 100644 --- a/src/vision.c +++ b/src/vision.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 vision.c $NHDT-Date: 1448013598 2015/11/20 09:59:58 $ $NHDT-Branch: master $:$NHDT-Revision: 1.27 $ */ +/* NetHack 3.7 vision.c $NHDT-Date: 1596498225 2020/08/03 23:43:45 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.38 $ */ /* Copyright (c) Dean Luick, with acknowledgements to Dave Cohrs, 1990. */ /* NetHack may be freely redistributed. See license for details. */ @@ -23,7 +23,7 @@ * @...X +4 * */ -const char circle_data[] = { +const xchar circle_data[] = { /* 0*/ 0, /* 1*/ 1, 1, /* 3*/ 2, 2, 1, @@ -49,7 +49,7 @@ const char circle_data[] = { * used for a single point: temporary light source of a camera flash * as it traverses its path. */ -const char circle_start[] = { +const xchar circle_start[] = { /* 0*/ 0, /* 1*/ 1, /* 2*/ 3, @@ -74,26 +74,26 @@ const char circle_start[] = { /*------ local variables ------*/ -static char could_see[2][ROWNO][COLNO]; /* vision work space */ -static char *cs_rows0[ROWNO], *cs_rows1[ROWNO]; -static char cs_rmin0[ROWNO], cs_rmax0[ROWNO]; -static char cs_rmin1[ROWNO], cs_rmax1[ROWNO]; +static xchar could_see[2][ROWNO][COLNO]; /* vision work space */ +static xchar *cs_rows0[ROWNO], *cs_rows1[ROWNO]; +static xchar cs_rmin0[ROWNO], cs_rmax0[ROWNO]; +static xchar cs_rmin1[ROWNO], cs_rmax1[ROWNO]; static char viz_clear[ROWNO][COLNO]; /* vision clear/blocked map */ static char *viz_clear_rows[ROWNO]; -static char left_ptrs[ROWNO][COLNO]; /* LOS algorithm helpers */ -static char right_ptrs[ROWNO][COLNO]; +static xchar left_ptrs[ROWNO][COLNO]; /* LOS algorithm helpers */ +static xchar right_ptrs[ROWNO][COLNO]; /* Forward declarations. */ static void FDECL(fill_point, (int, int)); static void FDECL(dig_point, (int, int)); static void NDECL(view_init); -static void FDECL(view_from, (int, int, char **, char *, char *, int, +static void FDECL(view_from, (int, int, xchar **, xchar *, xchar *, int, void (*)(int, int, genericptr_t), genericptr_t)); -static void FDECL(get_unused_cs, (char ***, char **, char **)); -static void FDECL(rogue_vision, (char **, char *, char *)); +static void FDECL(get_unused_cs, (xchar ***, xchar **, xchar **)); +static void FDECL(rogue_vision, (xchar **, xchar *, xchar *)); /* Macro definitions that I can't find anywhere. */ #define sign(z) ((z) < 0 ? -1 : ((z) ? 1 : 0)) @@ -127,15 +127,8 @@ vision_init() g.vision_full_recalc = 0; (void) memset((genericptr_t) could_see, 0, sizeof(could_see)); - /* Initialize the vision algorithm (currently C or D). */ + /* Initialize the vision algorithm (currently C). */ view_init(); - -#ifdef VISION_TABLES - /* Note: this initializer doesn't do anything except guarantee that - * we're linked properly. - */ - vis_tab_init(); -#endif } /* @@ -246,11 +239,11 @@ vision_reset() */ static void get_unused_cs(rows, rmin, rmax) -char ***rows; -char **rmin, **rmax; +xchar ***rows; +xchar **rmin, **rmax; { register int row; - register char *nrmin, *nrmax; + register xchar *nrmin, *nrmax; if (g.viz_array == cs_rows0) { *rows = cs_rows1; @@ -287,8 +280,8 @@ char **rmin, **rmax; */ static void rogue_vision(next, rmin, rmax) -char **next; /* could_see array pointers */ -char *rmin, *rmax; +xchar **next; /* could_see array pointers */ +xchar *rmin, *rmax; { int rnum = levl[u.ux][u.uy].roomno - ROOMOFFSET; /* no SHARED... */ int start, stop, in_door, xhi, xlo, yhi, ylo; @@ -494,13 +487,13 @@ int control; { extern unsigned char seenv_matrix[3][3]; /* from display.c */ static unsigned char colbump[COLNO + 1]; /* cols to bump sv */ - char **temp_array; /* points to the old vision array */ - char **next_array; /* points to the new vision array */ - char *next_row; /* row pointer for the new array */ - char *old_row; /* row pointer for the old array */ - char *next_rmin; /* min pointer for the new array */ - char *next_rmax; /* max pointer for the new array */ - const char *ranges; /* circle ranges -- used for xray & night vision */ + xchar **temp_array; /* points to the old vision array */ + xchar **next_array; /* points to the new vision array */ + xchar *next_row; /* row pointer for the new array */ + xchar *old_row; /* row pointer for the old array */ + xchar *next_rmin; /* min pointer for the new array */ + xchar *next_rmax; /* max pointer for the new array */ + const xchar *ranges; /* circle ranges -- used for xray & night vision */ int row = 0; /* row counter (outer loop) */ int start, stop; /* inner loop starting/stopping index */ int dx, dy; /* one step from a lit door or lit wall (see below) */ @@ -1083,24 +1076,22 @@ int row, col; /*==========================================================================*/ /*==========================================================================*/ -/* Use either algorithm C or D. See the config.h for more details. - * =========*/ /* - * Variables local to both Algorithms C and D. + * Variables local to Algorithm C. */ static int start_row; static int start_col; static int step; -static char **cs_rows; -static char *cs_left; -static char *cs_right; +static xchar **cs_rows; +static xchar *cs_left; +static xchar *cs_right; static void FDECL((*vis_func), (int, int, genericptr_t)); static genericptr_t varg; /* - * Both Algorithms C and D use the following macros. + * Algorithm C uses the following macros: * * good_row(z) - Return TRUE if the argument is a legal row. * set_cs(rowp,col) - Set the local could see array. @@ -1583,704 +1574,6 @@ cleardone: return (boolean) result; } -#ifdef VISION_TABLES -/*==========================================================================*\ - GENERAL LINE OF SIGHT - Algorithm D -\*==========================================================================*/ - -/* - * Indicate caller for the shadow routines. - */ -#define FROM_RIGHT 0 -#define FROM_LEFT 1 - -/* - * Include the table definitions. - */ -#include "vis_tab.h" - -/* 3D table pointers. */ -static close2d *close_dy[CLOSE_MAX_BC_DY]; -static far2d *far_dy[FAR_MAX_BC_DY]; - -static void FDECL(right_side, (int, int, int, int, int, - int, int, const char *)); -static void FDECL(left_side, (int, int, int, int, int, int, int, - const char *)); -static int FDECL(close_shadow, (int, int, int, int)); -static int FDECL(far_shadow, (int, int, int, int)); - -/* - * Initialize algorithm D's table pointers. If we don't have these, - * then we do 3D table lookups. Verrrry slow. - */ -static void -view_init() -{ - int i; - - for (i = 0; i < CLOSE_MAX_BC_DY; i++) - close_dy[i] = &close_table[i]; - - for (i = 0; i < FAR_MAX_BC_DY; i++) - far_dy[i] = &far_table[i]; -} - -/* - * If the far table has an entry of OFF_TABLE, then the far block prevents - * us from seeing the location just above/below it. I.e. the first visible - * location is one *before* the block. - */ -#define OFF_TABLE 0xff - -static int -close_shadow(side, this_row, block_row, block_col) -int side, this_row, block_row, block_col; -{ - register int sdy, sdx, pdy, offset; - - /* - * If on the same column (block_row = -1), then we can see it. - */ - if (block_row < 0) - return block_col; - - /* Take explicit absolute values. Adjust. */ - if ((sdy = (start_row - block_row)) < 0) - sdy = -sdy; - --sdy; /* src dy */ - if ((sdx = (start_col - block_col)) < 0) - sdx = -sdx; /* src dx */ - if ((pdy = (block_row - this_row)) < 0) - pdy = -pdy; /* point dy */ - - if (sdy < 0 || sdy >= CLOSE_MAX_SB_DY || sdx >= CLOSE_MAX_SB_DX - || pdy >= CLOSE_MAX_BC_DY) { - impossible("close_shadow: bad value"); - return block_col; - } - offset = close_dy[sdy]->close[sdx][pdy]; - if (side == FROM_RIGHT) - return block_col + offset; - - return block_col - offset; -} - -static int -far_shadow(side, this_row, block_row, block_col) -int side, this_row, block_row, block_col; -{ - register int sdy, sdx, pdy, offset; - - /* - * Take care of a bug that shows up only on the borders. - * - * If the block is beyond the border, then the row is negative. Return - * the block's column number (should be 0 or COLNO-1). - * - * Could easily have the column be -1, but then wouldn't know if it was - * the left or right border. - */ - if (block_row < 0) - return block_col; - - /* Take explicit absolute values. Adjust. */ - if ((sdy = (start_row - block_row)) < 0) - sdy = -sdy; /* src dy */ - if ((sdx = (start_col - block_col)) < 0) - sdx = -sdx; - --sdx; /* src dx */ - if ((pdy = (block_row - this_row)) < 0) - pdy = -pdy; - --pdy; /* point dy */ - - if (sdy >= FAR_MAX_SB_DY || sdx < 0 || sdx >= FAR_MAX_SB_DX || pdy < 0 - || pdy >= FAR_MAX_BC_DY) { - impossible("far_shadow: bad value"); - return block_col; - } - if ((offset = far_dy[sdy]->far_q[sdx][pdy]) == OFF_TABLE) - offset = -1; - if (side == FROM_RIGHT) - return block_col + offset; - - return block_col - offset; -} - -/* - * right_side() - * - * Figure out what could be seen on the right side of the source. - */ -static void -right_side(row, cb_row, cb_col, fb_row, fb_col, left, right_mark, limits) -int row; /* current row */ -int cb_row, cb_col; /* close block row and col */ -int fb_row, fb_col; /* far block row and col */ -int left; /* left mark of the previous row */ -int right_mark; /* right mark of previous row */ -char *limits; /* points at range limit for current row, or NULL */ -{ - register int i; - register char *rowp = NULL; - int hit_stone = 0; - int left_shadow, right_shadow, loc_right; - int lblock_col; /* local block column (current row) */ - int nrow, deeper; - char *row_min = NULL; /* left most */ - char *row_max = NULL; /* right most */ - int lim_max; /* right most limit of circle */ - - nrow = row + step; - deeper = good_row(nrow) && (!limits || (*limits >= *(limits + 1))); - if (!vis_func) { - rowp = cs_rows[row]; - row_min = &cs_left[row]; - row_max = &cs_right[row]; - } - if (limits) { - lim_max = start_col + *limits; - if (lim_max > COLNO - 1) - lim_max = COLNO - 1; - if (right_mark > lim_max) - right_mark = lim_max; - limits++; /* prepare for next row */ - } else - lim_max = COLNO - 1; - - /* - * Get the left shadow from the close block. This value could be - * illegal. - */ - left_shadow = close_shadow(FROM_RIGHT, row, cb_row, cb_col); - - /* - * Mark all stone walls as seen before the left shadow. All this work - * for a special case. - * - * NOTE. With the addition of this code in here, it is now *required* - * for the algorithm to work correctly. If this is commented out, - * change the above assignment so that left and not left_shadow is the - * variable that gets the shadow. - */ - while (left <= right_mark) { - loc_right = right_ptrs[row][left]; - if (loc_right > lim_max) - loc_right = lim_max; - if (viz_clear_rows[row][left]) { - if (loc_right >= left_shadow) { - left = left_shadow; /* opening ends beyond shadow */ - break; - } - left = loc_right; - loc_right = right_ptrs[row][left]; - if (loc_right > lim_max) - loc_right = lim_max; - if (left == loc_right) - return; /* boundary */ - - /* Shadow covers opening, beyond right mark */ - if (left == right_mark && left_shadow > right_mark) - return; - } - - if (loc_right > right_mark) /* can't see stone beyond the mark */ - loc_right = right_mark; - - if (vis_func) { - for (i = left; i <= loc_right; i++) - (*vis_func)(i, row, varg); - } else { - for (i = left; i <= loc_right; i++) - set_cs(rowp, i); - set_min(left); - set_max(loc_right); - } - - if (loc_right == right_mark) - return; /* all stone */ - if (loc_right >= left_shadow) - hit_stone = 1; - left = loc_right + 1; - } - - /* - * At this point we are at the first visible clear spot on or beyond - * the left shadow, unless the left shadow is an illegal value. If we - * have "hit stone" then we have a stone wall just to our left. - */ - - /* - * Get the right shadow. Make sure that it is a legal value. - */ - if ((right_shadow = far_shadow(FROM_RIGHT, row, fb_row, fb_col)) >= COLNO) - right_shadow = COLNO - 1; - /* - * Make vertical walls work the way we want them. In this case, we - * note when the close block blocks the column just above/beneath - * it (right_shadow < fb_col [actually right_shadow == fb_col-1]). If - * the location is filled, then we want to see it, so we put the - * right shadow back (same as fb_col). - */ - if (right_shadow < fb_col && !viz_clear_rows[row][fb_col]) - right_shadow = fb_col; - if (right_shadow > lim_max) - right_shadow = lim_max; - - /* - * Main loop. Within the range of sight of the previous row, mark all - * stone walls as seen. Follow open areas recursively. - */ - while (left <= right_mark) { - /* Get the far right of the opening or wall */ - loc_right = right_ptrs[row][left]; - if (loc_right > lim_max) - loc_right = lim_max; - - if (!viz_clear_rows[row][left]) { - hit_stone = 1; /* use stone on this row as close block */ - /* - * We can see all of the wall until the next open spot or the - * start of the shadow caused by the far block (right). - * - * Can't see stone beyond the right mark. - */ - if (loc_right > right_mark) - loc_right = right_mark; - - if (vis_func) { - for (i = left; i <= loc_right; i++) - (*vis_func)(i, row, varg); - } else { - for (i = left; i <= loc_right; i++) - set_cs(rowp, i); - set_min(left); - set_max(loc_right); - } - - if (loc_right == right_mark) - return; /* hit the end */ - left = loc_right + 1; - loc_right = right_ptrs[row][left]; - if (loc_right > lim_max) - loc_right = lim_max; - /* fall through... we know at least one position is visible */ - } - - /* - * We are in an opening. - * - * If this is the first open spot since the could see area (this is - * true if we have hit stone), get the shadow generated by the wall - * just to our left. - */ - if (hit_stone) { - lblock_col = left - 1; /* local block column */ - left = close_shadow(FROM_RIGHT, row, row, lblock_col); - if (left > lim_max) - break; /* off the end */ - } - - /* - * Check if the shadow covers the opening. If it does, then - * move to end of the opening. A shadow generated on from a - * wall on this row does *not* cover the wall on the right - * of the opening. - */ - if (left >= loc_right) { - if (loc_right == lim_max) { /* boundary */ - if (left == lim_max) { - if (vis_func) - (*vis_func)(lim_max, row, varg); - else { - set_cs(rowp, lim_max); /* last pos */ - set_max(lim_max); - } - } - return; /* done */ - } - left = loc_right; - continue; - } - - /* - * If the far wall of the opening (loc_right) is closer than the - * shadow limit imposed by the far block (right) then use the far - * wall as our new far block when we recurse. - * - * If the limits are the same, and the far block really exists - * (fb_row >= 0) then do the same as above. - * - * Normally, the check would be for the far wall being closer OR EQUAL - * to the shadow limit. However, there is a bug that arises from the - * fact that the clear area pointers end in an open space (if it - * exists) on a boundary. This then makes a far block exist where it - * shouldn't --- on a boundary. To get around that, I had to - * introduce the concept of a non-existent far block (when the - * row < 0). Next I have to check for it. Here is where that check - * exists. - */ - if ((loc_right < right_shadow) - || (fb_row >= 0 && loc_right == right_shadow)) { - if (vis_func) { - for (i = left; i <= loc_right; i++) - (*vis_func)(i, row, varg); - } else { - for (i = left; i <= loc_right; i++) - set_cs(rowp, i); - set_min(left); - set_max(loc_right); - } - - if (deeper) { - if (hit_stone) - right_side(nrow, row, lblock_col, row, loc_right, left, - loc_right, limits); - else - right_side(nrow, cb_row, cb_col, row, loc_right, left, - loc_right, limits); - } - - /* - * The following line, setting hit_stone, is needed for those - * walls that are only 1 wide. If hit stone is *not* set and - * the stone is only one wide, then the close block is the old - * one instead one on the current row. A way around having to - * set it here is to make left = loc_right (not loc_right+1) and - * let the outer loop take care of it. However, if we do that - * then we then have to check for boundary conditions here as - * well. - */ - hit_stone = 1; - - left = loc_right + 1; - - /* - * The opening extends beyond the right mark. This means that - * the next far block is the current far block. - */ - } else { - if (vis_func) { - for (i = left; i <= right_shadow; i++) - (*vis_func)(i, row, varg); - } else { - for (i = left; i <= right_shadow; i++) - set_cs(rowp, i); - set_min(left); - set_max(right_shadow); - } - - if (deeper) { - if (hit_stone) - right_side(nrow, row, lblock_col, fb_row, fb_col, left, - right_shadow, limits); - else - right_side(nrow, cb_row, cb_col, fb_row, fb_col, left, - right_shadow, limits); - } - - return; /* we're outta here */ - } - } -} - -/* - * left_side() - * - * This routine is the mirror image of right_side(). Please see right_side() - * for blow by blow comments. - */ -static void -left_side(row, cb_row, cb_col, fb_row, fb_col, left_mark, right, limits) -int row; /* the current row */ -int cb_row, cb_col; /* close block row and col */ -int fb_row, fb_col; /* far block row and col */ -int left_mark; /* left mark of previous row */ -int right; /* right mark of the previous row */ -const char *limits; -{ - register int i; - register char *rowp = NULL; - int hit_stone = 0; - int left_shadow, right_shadow, loc_left; - int lblock_col; /* local block column (current row) */ - int nrow, deeper; - char *row_min = NULL; /* left most */ - char *row_max = NULL; /* right most */ - int lim_min; - - nrow = row + step; - deeper = good_row(nrow) && (!limits || (*limits >= *(limits + 1))); - if (!vis_func) { - rowp = cs_rows[row]; - row_min = &cs_left[row]; - row_max = &cs_right[row]; - } - if (limits) { - lim_min = start_col - *limits; - if (lim_min < 0) - lim_min = 0; - if (left_mark < lim_min) - left_mark = lim_min; - limits++; /* prepare for next row */ - } else - lim_min = 0; - - /* This value could be illegal. */ - right_shadow = close_shadow(FROM_LEFT, row, cb_row, cb_col); - - while (right >= left_mark) { - loc_left = left_ptrs[row][right]; - if (loc_left < lim_min) - loc_left = lim_min; - if (viz_clear_rows[row][right]) { - if (loc_left <= right_shadow) { - right = right_shadow; /* opening ends beyond shadow */ - break; - } - right = loc_left; - loc_left = left_ptrs[row][right]; - if (loc_left < lim_min) - loc_left = lim_min; - if (right == loc_left) - return; /* boundary */ - } - - if (loc_left < left_mark) /* can't see beyond the left mark */ - loc_left = left_mark; - - if (vis_func) { - for (i = loc_left; i <= right; i++) - (*vis_func)(i, row, varg); - } else { - for (i = loc_left; i <= right; i++) - set_cs(rowp, i); - set_min(loc_left); - set_max(right); - } - - if (loc_left == left_mark) - return; /* all stone */ - if (loc_left <= right_shadow) - hit_stone = 1; - right = loc_left - 1; - } - - /* At first visible clear spot on or beyond the right shadow. */ - - if ((left_shadow = far_shadow(FROM_LEFT, row, fb_row, fb_col)) < 0) - left_shadow = 0; - - /* Do vertical walls as we want. */ - if (left_shadow > fb_col && !viz_clear_rows[row][fb_col]) - left_shadow = fb_col; - if (left_shadow < lim_min) - left_shadow = lim_min; - - while (right >= left_mark) { - loc_left = left_ptrs[row][right]; - - if (!viz_clear_rows[row][right]) { - hit_stone = 1; /* use stone on this row as close block */ - - /* We can only see walls until the left mark */ - if (loc_left < left_mark) - loc_left = left_mark; - - if (vis_func) { - for (i = loc_left; i <= right; i++) - (*vis_func)(i, row, varg); - } else { - for (i = loc_left; i <= right; i++) - set_cs(rowp, i); - set_min(loc_left); - set_max(right); - } - - if (loc_left == left_mark) - return; /* hit end */ - right = loc_left - 1; - loc_left = left_ptrs[row][right]; - if (loc_left < lim_min) - loc_left = lim_min; - /* fall through...*/ - } - - /* We are in an opening. */ - if (hit_stone) { - lblock_col = right + 1; /* stone block (local) */ - right = close_shadow(FROM_LEFT, row, row, lblock_col); - if (right < lim_min) - return; /* off the end */ - } - - /* Check if the shadow covers the opening. */ - if (right <= loc_left) { - /* Make a boundary condition work. */ - if (loc_left == lim_min) { /* at boundary */ - if (right == lim_min) { - if (vis_func) - (*vis_func)(lim_min, row, varg); - else { - set_cs(rowp, lim_min); /* caught the last pos */ - set_min(lim_min); - } - } - return; /* and break out the loop */ - } - - right = loc_left; - continue; - } - - /* If the far wall of the opening is closer than the shadow limit. */ - if ((loc_left > left_shadow) - || (fb_row >= 0 && loc_left == left_shadow)) { - if (vis_func) { - for (i = loc_left; i <= right; i++) - (*vis_func)(i, row, varg); - } else { - for (i = loc_left; i <= right; i++) - set_cs(rowp, i); - set_min(loc_left); - set_max(right); - } - - if (deeper) { - if (hit_stone) - left_side(nrow, row, lblock_col, row, loc_left, loc_left, - right, limits); - else - left_side(nrow, cb_row, cb_col, row, loc_left, loc_left, - right, limits); - } - - hit_stone = 1; /* needed for walls of width 1 */ - right = loc_left - 1; - - /* The opening extends beyond the left mark. */ - } else { - if (vis_func) { - for (i = left_shadow; i <= right; i++) - (*vis_func)(i, row, varg); - } else { - for (i = left_shadow; i <= right; i++) - set_cs(rowp, i); - set_min(left_shadow); - set_max(right); - } - - if (deeper) { - if (hit_stone) - left_side(nrow, row, lblock_col, fb_row, fb_col, - left_shadow, right, limits); - else - left_side(nrow, cb_row, cb_col, fb_row, fb_col, - left_shadow, right, limits); - } - - return; /* we're outta here */ - } - } -} - -/* - * view_from - * - * Calculate a view from the given location. Initialize and fill a - * ROWNOxCOLNO array (could_see) with all the locations that could be - * seen from the source location. Initialize and fill the left most - * and right most boundaries of what could be seen. - */ -static void -view_from(srow, scol, loc_cs_rows, left_most, right_most, range, func, arg) -int srow, scol; /* source row and column */ -char **loc_cs_rows; /* could_see array (row pointers) */ -char *left_most, *right_most; /* limits of what could be seen */ -int range; /* 0 if unlimited */ -void FDECL((*func), (int, int, genericptr_t)); -genericptr_t arg; -{ - register int i; - char *rowp; - int nrow, left, right, left_row, right_row; - char *limits; - - /* Set globals for near_shadow(), far_shadow(), etc. to use. */ - start_col = scol; - start_row = srow; - cs_rows = loc_cs_rows; - cs_left = left_most; - cs_right = right_most; - vis_func = func; - varg = arg; - - /* Find the left and right limits of sight on the starting row. */ - if (viz_clear_rows[srow][scol]) { - left = left_ptrs[srow][scol]; - right = right_ptrs[srow][scol]; - } else { - left = (!scol) ? 0 : (viz_clear_rows[srow][scol - 1] - ? left_ptrs[srow][scol - 1] - : scol - 1); - right = (scol == COLNO - 1) ? COLNO - 1 - : (viz_clear_rows[srow][scol + 1] - ? right_ptrs[srow][scol + 1] - : scol + 1); - } - - if (range) { - if (range > MAX_RADIUS || range < 1) - panic("view_from called with range %d", range); - limits = circle_ptr(range) + 1; /* start at next row */ - if (left < scol - range) - left = scol - range; - if (right > scol + range) - right = scol + range; - } else - limits = (char *) 0; - - if (func) { - for (i = left; i <= right; i++) - (*func)(i, srow, arg); - } else { - /* Row optimization */ - rowp = cs_rows[srow]; - - /* We know that we can see our row. */ - for (i = left; i <= right; i++) - set_cs(rowp, i); - cs_left[srow] = left; - cs_right[srow] = right; - } - - /* The far block has a row number of -1 if we are on an edge. */ - right_row = (right == COLNO - 1) ? -1 : srow; - left_row = (!left) ? -1 : srow; - - /* - * Check what could be seen in quadrants. - */ - if ((nrow = srow + 1) < ROWNO) { - step = 1; /* move down */ - if (scol < COLNO - 1) - right_side(nrow, -1, scol, right_row, right, scol, right, limits); - if (scol) - left_side(nrow, -1, scol, left_row, left, left, scol, limits); - } - - if ((nrow = srow - 1) >= 0) { - step = -1; /* move up */ - if (scol < COLNO - 1) - right_side(nrow, -1, scol, right_row, right, scol, right, limits); - if (scol) - left_side(nrow, -1, scol, left_row, left, left, scol, limits); - } -} - -#else /*===== End of algorithm D =====*/ - /*==========================================================================*\ GENERAL LINE OF SIGHT Algorithm C @@ -2289,8 +1582,8 @@ genericptr_t arg; /* * Defines local to Algorithm C. */ -static void FDECL(right_side, (int, int, int, const char *)); -static void FDECL(left_side, (int, int, int, const char *)); +static void FDECL(right_side, (int, int, int, const xchar *)); +static void FDECL(left_side, (int, int, int, const xchar *)); /* Initialize algorithm C (nothing). */ static void @@ -2307,7 +1600,7 @@ right_side(row, left, right_mark, limits) int row; /* current row */ int left; /* first (left side) visible spot on prev row */ int right_mark; /* last (right side) visible spot on prev row */ -const char *limits; /* points at range limit for current row, or NULL */ +const xchar *limits; /* points at range limit for current row, or NULL */ { int right; /* right limit of "could see" */ int right_edge; /* right edge of an opening */ @@ -2315,9 +1608,9 @@ const char *limits; /* points at range limit for current row, or NULL */ int deeper; /* if TRUE, call self as needed */ int result; /* set by q?_path() */ register int i; /* loop counter */ - register char *rowp = NULL; /* row optimization */ - char *row_min = NULL; /* left most [used by macro set_min()] */ - char *row_max = NULL; /* right most [used by macro set_max()] */ + register xchar *rowp = NULL; /* row optimization */ + xchar *row_min = NULL; /* left most [used by macro set_min()] */ + xchar *row_max = NULL; /* right most [used by macro set_max()] */ int lim_max; /* right most limit of circle */ nrow = row + step; @@ -2497,13 +1790,13 @@ const char *limits; /* points at range limit for current row, or NULL */ static void left_side(row, left_mark, right, limits) int row, left_mark, right; -const char *limits; +const xchar *limits; { int left, left_edge, nrow, deeper, result; register int i; - register char *rowp = NULL; - char *row_min = NULL; - char *row_max = NULL; + register xchar *rowp = NULL; + xchar *row_min = NULL; + xchar *row_max = NULL; int lim_min; #ifdef GCC_WARN @@ -2633,19 +1926,19 @@ const char *limits; static void view_from(srow, scol, loc_cs_rows, left_most, right_most, range, func, arg) int srow, scol; /* starting row and column */ -char **loc_cs_rows; /* pointers to the rows of the could_see array */ -char *left_most; /* min mark on each row */ -char *right_most; /* max mark on each row */ +xchar **loc_cs_rows; /* pointers to the rows of the could_see array */ +xchar *left_most; /* min mark on each row */ +xchar *right_most; /* max mark on each row */ int range; /* 0 if unlimited */ void FDECL((*func), (int, int, genericptr_t)); genericptr_t arg; { register int i; /* loop counter */ - char *rowp; /* optimization for setting could_see */ + xchar *rowp; /* optimization for setting could_see */ int nrow; /* the next row */ int left; /* the left-most visible column */ int right; /* the right-most visible column */ - const char *limits; /* range limit for next row */ + const xchar *limits; /* range limit for next row */ /* Set globals for q?_path(), left_side(), and right_side() to use. */ start_col = scol; @@ -2685,7 +1978,7 @@ genericptr_t arg; if (right > scol + range) right = scol + range; } else - limits = (char *) 0; + limits = (xchar *) 0; if (func) { for (i = left; i <= right; i++) @@ -2723,7 +2016,7 @@ genericptr_t arg; } } -#endif /*===== End of algorithm C =====*/ +/*===== End of algorithm C =====*/ /* * AREA OF EFFECT "ENGINE" @@ -2744,12 +2037,12 @@ genericptr_t arg; { /* If not centered on hero, do the hard work of figuring the area */ if (scol != u.ux || srow != u.uy) { - view_from(srow, scol, (char **) 0, (char *) 0, (char *) 0, range, + view_from(srow, scol, (xchar **) 0, (xchar *) 0, (xchar *) 0, range, func, arg); } else { register int x; int y, min_x, max_x, max_y, offset; - const char *limits; + const xchar *limits; boolean override_vision; /* vision doesn't pass through water or clouds, detection should diff --git a/src/weapon.c b/src/weapon.c index faaadc0b9..0ccefdf8c 100644 --- a/src/weapon.c +++ b/src/weapon.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 weapon.c $NHDT-Date: 1579648295 2020/01/21 23:11:35 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.82 $ */ +/* NetHack 3.7 weapon.c $NHDT-Date: 1607811730 2020/12/12 22:22:10 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.89 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2011. */ /* NetHack may be freely redistributed. See license for details. */ @@ -11,6 +11,7 @@ #include "hack.h" static void FDECL(give_may_advance_msg, (int)); +static void FDECL(finish_towel_change, (struct obj *obj, int)); static boolean FDECL(could_advance, (int)); static boolean FDECL(peaked_skill, (int)); static int FDECL(slots_required, (int)); @@ -954,6 +955,26 @@ dbon() return 6; } +/* called when wet_a_towel() or dry_a_towel() is changing a towel's wetness */ +static void +finish_towel_change(obj, newspe) +struct obj *obj; +int newspe; +{ + /* towel wetness is always between 0 (dry) and 7, inclusive */ + newspe = min(newspe, 7); + obj->spe = max(newspe, 0); + + /* if hero is wielding this towel, don't give "you begin bashing with + your [wet] towel" message if it's wet, do give one if it's dry */ + if (obj == uwep) + g.unweapon = !is_wet_towel(obj); + + /* description might change: "towel" vs "moist towel" vs "wet towel" */ + if (carried(obj)) + update_inventory(); +} + /* increase a towel's wetness */ void wet_a_towel(obj, amt, verbose) @@ -978,22 +999,19 @@ boolean verbose; xname(obj), wetness); } } - obj->spe = min(newspe, 7); - /* if hero is wielding this towel, don't give "you begin bashing - with your wet towel" message on next attack with it */ - if (obj == uwep) - g.unweapon = !is_wet_towel(obj); + if (newspe != obj->spe) + finish_towel_change(obj, newspe); } -/* decrease a towel's wetness */ +/* decrease a towel's wetness; unlike when wetting, 0 is not a no-op */ void dry_a_towel(obj, amt, verbose) struct obj *obj; -int amt; /* positive: new value; negative: decrement by -amt; zero: no-op */ +int amt; /* positive or zero: new value; negative: decrement by abs(amt) */ boolean verbose; { - int newspe = (amt <= 0) ? obj->spe + amt : amt; + int newspe = (amt < 0) ? obj->spe + amt : amt; /* new state is only reported if it's a decrease */ if (newspe < obj->spe) { @@ -1006,13 +1024,9 @@ boolean verbose; xname(obj), !newspe ? " out" : ""); } } - newspe = min(newspe, 7); - obj->spe = max(newspe, 0); - /* if hero is wielding this towel and it is now dry, give "you begin - bashing with your towel" message on next attack with it */ - if (obj == uwep) - g.unweapon = !is_wet_towel(obj); + if (newspe != obj->spe) + finish_towel_change(obj, newspe); } /* copy the skill level name into the given buffer */ @@ -1658,7 +1672,7 @@ const struct def_skill *class_skill; /* set skills for magic */ if (Role_if(PM_HEALER) || Role_if(PM_MONK)) { P_SKILL(P_HEALING_SPELL) = P_BASIC; - } else if (Role_if(PM_PRIEST)) { + } else if (Role_if(PM_CLERIC)) { P_SKILL(P_CLERIC_SPELL) = P_BASIC; } else if (Role_if(PM_WIZARD)) { P_SKILL(P_ATTACK_SPELL) = P_BASIC; diff --git a/src/were.c b/src/were.c index 8b1350a8e..e0e208151 100644 --- a/src/were.c +++ b/src/were.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 were.c $NHDT-Date: 1550524568 2019/02/18 21:16:08 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.23 $ */ +/* NetHack 3.7 were.c $NHDT-Date: 1596498227 2020/08/03 23:43:47 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.25 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2011. */ /* NetHack may be freely redistributed. See license for details. */ @@ -99,13 +99,15 @@ register struct monst *mon; pm = counter_were(monsndx(mon->data)); if (pm < LOW_PM) { - impossible("unknown lycanthrope %s.", mon->data->mname); + impossible("unknown lycanthrope %s.", + mon->data->pmnames[NEUTRAL]); return; } if (canseemon(mon) && !Hallucination) pline("%s changes into a %s.", Monnam(mon), - is_human(&mons[pm]) ? "human" : mons[pm].mname + 4); + is_human(&mons[pm]) ? "human" + : pmname(&mons[pm], Mgender(mon)) + 4); set_mon_data(mon, &mons[pm]); if (mon->msleeping || !mon->mcanmove) { @@ -183,7 +185,7 @@ you_were() if (controllable_poly) { /* `+4' => skip "were" prefix to get name of beast */ Sprintf(qbuf, "Do you want to change into %s?", - an(mons[u.ulycn].mname + 4)); + an(mons[u.ulycn].pmnames[NEUTRAL] + 4)); if (!paranoid_query(ParanoidWerechange, qbuf)) return; } diff --git a/src/wield.c b/src/wield.c index 2382a0e3c..b5f2dbac8 100644 --- a/src/wield.c +++ b/src/wield.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 wield.c $NHDT-Date: 1586178709 2020/04/06 13:11:49 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.75 $ */ +/* NetHack 3.7 wield.c $NHDT-Date: 1607200367 2020/12/05 20:32:47 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.78 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2009. */ /* NetHack may be freely redistributed. See license for details. */ @@ -275,7 +275,7 @@ static NEARDATA const char wield_objs[] = { static NEARDATA const char ready_objs[] = { ALLOW_COUNT, COIN_CLASS, ALL_CLASSES, ALLOW_NONE, WEAPON_CLASS, 0 }; -static NEARDATA const char bullets[] = { /* (note: different from dothrow.c) */ +static NEARDATA const char w_bullets[] = { /* (different from dothrow.c) */ ALLOW_COUNT, COIN_CLASS, ALL_CLASSES, ALLOW_NONE, GEM_CLASS, WEAPON_CLASS, 0 }; @@ -455,7 +455,7 @@ dowieldquiver() quivee_types = (uslinging() || (uswapwep && objects[uswapwep->otyp].oc_skill == P_SLING)) - ? bullets + ? w_bullets : ready_objs; newquiver = getobj(quivee_types, "ready"); diff --git a/src/windows.c b/src/windows.c index 0632a09b3..1b95009cf 100644 --- a/src/windows.c +++ b/src/windows.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 windows.c $NHDT-Date: 1575245096 2019/12/02 00:04:56 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.60 $ */ +/* NetHack 3.7 windows.c $NHDT-Date: 1596498228 2020/08/03 23:43:48 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.75 $ */ /* Copyright (c) D. Cohrs, 1993. */ /* NetHack may be freely redistributed. See license for details. */ @@ -44,6 +44,9 @@ extern struct window_procs Gnome_procs; #ifdef MSWIN_GRAPHICS extern struct window_procs mswin_procs; #endif +#ifdef SHIM_GRAPHICS +extern struct window_procs shim_procs; +#endif #ifdef WINCHAIN extern struct window_procs chainin_procs; extern void FDECL(chainin_procs_init, (int)); @@ -128,6 +131,9 @@ static struct win_choices { #ifdef MSWIN_GRAPHICS { &mswin_procs, 0 CHAINR(0) }, #endif +#ifdef SHIM_GRAPHICS + { &shim_procs, 0 CHAINR(0) }, +#endif #ifdef WINCHAIN { &chainin_procs, chainin_procs_init, chainin_procs_chain }, { (struct window_procs *) &chainout_procs, chainout_procs_init, @@ -514,7 +520,7 @@ static void FDECL(hup_add_menu, (winid, int, const anything *, CHAR_P, CHAR_P, int, const char *, unsigned int)); static void FDECL(hup_end_menu, (winid, const char *)); static void FDECL(hup_putstr, (winid, int, const char *)); -static void FDECL(hup_print_glyph, (winid, XCHAR_P, XCHAR_P, int, int)); +static void FDECL(hup_print_glyph, (winid, XCHAR_P, XCHAR_P, int, int, unsigned *)); static void FDECL(hup_outrip, (winid, int, time_t)); static void FDECL(hup_curs, (winid, int, int)); static void FDECL(hup_display_nhwindow, (winid, BOOLEAN_P)); @@ -730,11 +736,12 @@ const char *text UNUSED; /*ARGSUSED*/ static void -hup_print_glyph(window, x, y, glyph, bkglyph) +hup_print_glyph(window, x, y, glyph, bkglyph, glyphmod) winid window UNUSED; xchar x UNUSED, y UNUSED; int glyph UNUSED; int bkglyph UNUSED; +unsigned *glyphmod UNUSED; { return; } diff --git a/src/wizard.c b/src/wizard.c index a2b5d4f31..4f1891566 100644 --- a/src/wizard.c +++ b/src/wizard.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 wizard.c $NHDT-Date: 1585361057 2020/03/28 02:04:17 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.64 $ */ +/* NetHack 3.7 wizard.c $NHDT-Date: 1596498229 2020/08/03 23:43:49 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.68 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2016. */ /* NetHack may be freely redistributed. See license for details. */ @@ -35,10 +35,10 @@ static NEARDATA const int nasties[] = { PM_IRON_GOLEM, PM_OCHRE_JELLY, PM_GREEN_SLIME, PM_DISPLACER_BEAST, PM_GENETIC_ENGINEER, /* chaotic */ - PM_BLACK_DRAGON, PM_RED_DRAGON, PM_ARCH_LICH, PM_VAMPIRE_LORD, + PM_BLACK_DRAGON, PM_RED_DRAGON, PM_ARCH_LICH, PM_VAMPIRE_LEADER, PM_MASTER_MIND_FLAYER, PM_DISENCHANTER, PM_WINGED_GARGOYLE, - PM_STORM_GIANT, PM_OLOG_HAI, PM_ELF_LORD, PM_ELVENKING, - PM_OGRE_KING, PM_CAPTAIN, PM_GREMLIN, + PM_STORM_GIANT, PM_OLOG_HAI, PM_ELF_NOBLE, PM_ELVEN_MONARCH, + PM_OGRE_TYRANT, PM_CAPTAIN, PM_GREMLIN, /* lawful */ PM_SILVER_DRAGON, PM_ORANGE_DRAGON, PM_GREEN_DRAGON, PM_YELLOW_DRAGON, PM_GUARDIAN_NAGA, PM_FIRE_GIANT, @@ -329,30 +329,26 @@ xchar *sx; xchar *sy; { xchar x = 0, y = 0; + stairway *stway = g.stairs; + boolean stdir = !builds_up(&u.uz); - if (builds_up(&u.uz)) { - if (xdnstair) { - x = xdnstair; - y = ydnstair; - } else if (xdnladder) { - x = xdnladder; - y = ydnladder; - } + if ((stway = stairway_find_type_dir(FALSE, stdir)) != 0) { + x = stway->sx; + y = stway->sy; + } else if ((stway = stairway_find_type_dir(TRUE, stdir)) != 0) { + x = stway->sx; + y = stway->sy; } else { - if (xupstair) { - x = xupstair; - y = yupstair; - } else if (xupladder) { - x = xupladder; - y = yupladder; + while (stway) { + if (stway->tolev.dnum != u.uz.dnum) { + x = stway->sx; + y = stway->sy; + break; + } + stway = stway->next; } } - if (!x && g.sstairs.sx) { - x = g.sstairs.sx; - y = g.sstairs.sy; - } - if (x && y) { *sx = x; *sy = y; @@ -547,11 +543,11 @@ int difcap; /* if non-zero, try to make difficulty be lower than this */ || (mons[res].geno & (Inhell ? G_NOHELL : G_HELL)) != 0) alt = big_to_little(res); if (alt != res && (g.mvitals[alt].mvflags & G_GENOD) == 0) { - const char *mname = mons[alt].mname, - *lastspace = rindex(mname, ' '); + const char *mnam = mons[alt].pmnames[NEUTRAL], + *lastspace = rindex(mnam, ' '); /* only non-juveniles can become alternate choice */ - if (strncmp(mname, "baby ", 5) + if (strncmp(mnam, "baby ", 5) && (!lastspace || (strcmp(lastspace, " hatchling") && strcmp(lastspace, " pup") diff --git a/src/worm.c b/src/worm.c index dab10f926..9081a9919 100644 --- a/src/worm.c +++ b/src/worm.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 worm.c $NHDT-Date: 1591178400 2020/06/03 10:00:00 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.45 $ */ +/* NetHack 3.7 worm.c $NHDT-Date: 1608236444 2020/12/17 20:20:44 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.49 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2009. */ /* NetHack may be freely redistributed. See license for details. */ @@ -16,7 +16,9 @@ struct wseg { static void FDECL(toss_wsegs, (struct wseg *, BOOLEAN_P)); static void FDECL(shrink_worm, (int)); -static void FDECL(random_dir, (XCHAR_P, XCHAR_P, xchar *, xchar *)); +#if 0 +static void FDECL(random_dir, (int, int, int *, int *)); +#endif static struct wseg *FDECL(create_worm_tail, (int)); /* Description of long worm implementation. @@ -680,6 +682,31 @@ struct monst *worm; } } +/* called from mon_sanity_check(mon.c) */ +void +wormno_sanity_check() +{ +#ifdef EXTRA_SANITY_CHECKS + struct wseg *seg; + int wh = 0, wt = 0; + + /* checking tail management, not a particular monster; since wormno==0 + means 'not a worm', wheads[0] and wtails[0] should always be empty; + note: if erroneously non-Null, tail segment count will include the + extra segment for the worm's head that isn't shown on the map */ + for (seg = wheads[0]; seg; seg = seg->nseg) + ++wh; + for (seg = wtails[0]; seg; seg = seg->nseg) + ++wt; + if (wh || wt) { + impossible( + "phantom worm tail #0 [head=%s, %d segment%s; tail=%s, %d segment%s]", + fmt_ptr(wheads[0]), wh, plur(wh), + fmt_ptr(wtails[0]), wt, plur(wt)); + } +#endif /* EXTRA_SANITY_CHECKS */ +} + /* * remove_worm() * @@ -721,12 +748,30 @@ xchar x, y; int wnum = worm->wormno; struct wseg *curr = wtails[wnum]; struct wseg *new_tail; - xchar ox = x, oy = y; + int ox = x, oy = y; if (wnum && (!wtails[wnum] || !wheads[wnum])) { impossible("place_worm_tail_randomly: wormno is set without a tail!"); return; } + if (wtails[wnum] == wheads[wnum]) { + /* single segment, co-located with worm; + should either have same coordinates or have seg->wx==0 + to indicate that it is not currently on the map */ + if (curr->wx && (curr->wx != worm->mx || curr->wy != worm->my)) { + impossible( + "place_worm_tail_randomly: tail segment at <%d,%d>, worm at <%d,%d>", + curr->wx, curr->wy, worm->mx, worm->my); + if (m_at(curr->wx, curr->wy) == worm) + remove_monster(curr->wx, curr->wy); + } + curr->wx = worm->mx, curr->wy = worm->my; + return; + } + /* remove head segment from map in case we end up calling toss_wsegs(); + if it doesn't get tossed, it will become the final tail segment and + get new coordinates */ + wheads[wnum]->wx = wheads[wnum]->wy = 0; wheads[wnum] = new_tail = curr; curr = curr->nseg; @@ -735,30 +780,56 @@ xchar x, y; new_tail->wy = y; while (curr) { - xchar nx, ny; - char tryct = 0; + int nx = 0, ny = 0; +#if 0 /* old code */ + int trycnt = 0; - /* pick a random direction from x, y and search for goodpos() */ + /* pick a random direction from x, y and test for goodpos() */ do { random_dir(ox, oy, &nx, &ny); - } while (!goodpos(nx, ny, worm, 0) && (tryct++ < 50)); + } while (!goodpos(nx, ny, worm, 0) && ++tryct <= 50); - if (tryct < 50) { + if (tryct <= 50) +#else /* new code */ + int i, j, k, dirs[8]; + + /* instead of picking a random direction up to 50 times, try each + of the eight directions at most once after shuffling their order */ + for (i = 0; i < 8; ++i) + dirs[i] = i; + for (i = 8; i > 0; --i) { + j = rn2(i); + k = dirs[j]; + dirs[j] = dirs[i - 1]; + dirs[i - 1] = k; + } + for (i = 0; i < 8; ++i) { + nx = ox + xdir[dirs[i]]; + ny = oy + ydir[dirs[i]]; + if (goodpos(nx, ny, worm, 0)) /* includes an isok() check */ + break; + } + + if (i < 8) +#endif + { place_worm_seg(worm, nx, ny); - curr->wx = ox = nx; - curr->wy = oy = ny; + curr->wx = (xchar) (ox = nx); + curr->wy = (xchar) (oy = ny); wtails[wnum] = curr; curr = curr->nseg; wtails[wnum]->nseg = new_tail; new_tail = wtails[wnum]; newsym(nx, ny); - } else { /* Oops. Truncate because there was */ - toss_wsegs(curr, FALSE); /* no place for the rest of it */ + } else { + /* Oops. Truncate because there is no place for rest of it. */ + toss_wsegs(curr, FALSE); curr = (struct wseg *) 0; } } } +#if 0 /* * Given a coordinate x, y. * return in *nx, *ny, the coordinates of one of the <= 8 squares adjoining. @@ -769,8 +840,8 @@ xchar x, y; static void random_dir(x, y, nx, ny) -xchar x, y; -xchar *nx, *ny; +int x, y; +int *nx, *ny; { *nx = x + (x > 1 /* extreme left ? */ ? (x < COLNO - 1 /* extreme right ? */ @@ -790,6 +861,7 @@ xchar *nx, *ny; : -1) /* bottom, use -1 */ : 1); /* top, use +1 */ } +#endif /* for size_monst(cmd.c) to support #stats */ int diff --git a/src/worn.c b/src/worn.c index 231df0961..7da309a02 100644 --- a/src/worn.c +++ b/src/worn.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 worn.c $NHDT-Date: 1550524569 2019/02/18 21:16:09 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.56 $ */ +/* NetHack 3.7 worn.c $NHDT-Date: 1606919259 2020/12/02 14:27:39 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.70 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2013. */ /* NetHack may be freely redistributed. See license for details. */ @@ -57,9 +57,7 @@ long mask; uskin = obj; /* assert( !uarm ); */ } else { - if ((mask & W_ARMOR)) - u.uroleplay.nudist = FALSE; - for (wp = worn; wp->w_mask; wp++) + for (wp = worn; wp->w_mask; wp++) { if (wp->w_mask & mask) { oobj = *(wp->w_obj); if (oobj && !(oobj->owornmask & wp->w_mask)) @@ -105,6 +103,11 @@ long mask; } } } + } + if (obj && (obj->owornmask & W_ARMOR) != 0L) + u.uroleplay.nudist = FALSE; + /* tux -> tuxedo -> "monkey suit" -> monk's suit */ + iflags.tux_penalty = (uarm && Role_if(PM_MONK) && g.urole.spelarmr); } update_inventory(); } @@ -128,7 +131,7 @@ register struct obj *obj; is pending (via 'A' command for multiple items) */ cancel_doff(obj, wp->w_mask); - *(wp->w_obj) = 0; + *(wp->w_obj) = (struct obj *) 0; p = objects[obj->otyp].oc_oprop; u.uprops[p].extrinsic = u.uprops[p].extrinsic & ~wp->w_mask; obj->owornmask &= ~wp->w_mask; @@ -137,9 +140,29 @@ register struct obj *obj; if ((p = w_blocks(obj, wp->w_mask)) != 0) u.uprops[p].blocked &= ~wp->w_mask; } + if (!uarm) + iflags.tux_penalty = FALSE; update_inventory(); } +/* called when saving with FREEING flag set has just discarded inventory */ +void +allunworn() +{ + const struct worn *wp; + + u.twoweap = 0; /* uwep and uswapwep are going away */ + /* remove stale pointers; called after the objects have been freed + (without first being unworn) while saving invent during game save; + note: uball and uchain might not be freed yet but we clear them + here anyway (savegamestate() and its callers deal with them) */ + for (wp = worn; wp->w_mask; wp++) { + /* object is already gone so we don't/can't update is owornmask */ + *(wp->w_obj) = (struct obj *) 0; + } +} + + /* return item worn in slot indiciated by wornmask; needed by poly_obj() */ struct obj * wearmask_to_obj(wornmask) @@ -449,6 +472,9 @@ register struct monst *mon; /* since ARM_BONUS is positive, subtracting it increases AC */ } } + /* same cap as for hero [find_ac(do_wear.c)] */ + if (abs(base) > AC_MAX) + base = sgn(base) * AC_MAX; return base; } @@ -887,6 +913,9 @@ boolean polyspot; m_useup(mon, otmp); } } else if (sliparm(mdat)) { + /* sliparm checks whirly, noncorporeal, and small or under */ + boolean passes_thru_clothes = !(mdat->msize <= MZ_SMALL); + if ((otmp = which_armor(mon, W_ARM)) != 0) { if (vis) pline("%s armor falls around %s!", s_suffix(Monnam(mon)), @@ -912,7 +941,7 @@ boolean polyspot; } if ((otmp = which_armor(mon, W_ARMU)) != 0) { if (vis) { - if (sliparm(mon->data)) + if (passes_thru_clothes) pline("%s seeps right through %s shirt!", Monnam(mon), ppronoun); else @@ -990,7 +1019,8 @@ boolean polyspot; char buf[BUFSZ]; You("touch %s.", mon_nam(u.usteed)); - Sprintf(buf, "falling off %s", an(u.usteed->data->mname)); + Sprintf(buf, "falling off %s", + an(pmname(u.usteed->data, Mgender(u.usteed)))); instapetrify(buf); } dismount_steed(DISMOUNT_FELL); diff --git a/src/write.c b/src/write.c index 28d916f48..326713886 100644 --- a/src/write.c +++ b/src/write.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 write.c $NHDT-Date: 1573346194 2019/11/10 00:36:34 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.20 $ */ +/* NetHack 3.7 write.c $NHDT-Date: 1596498232 2020/08/03 23:43:52 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.26 $ */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" diff --git a/src/zap.c b/src/zap.c index 35bdfd6bb..04ebb8181 100644 --- a/src/zap.c +++ b/src/zap.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 zap.c $NHDT-Date: 1593772051 2020/07/03 10:27:31 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.344 $ */ +/* NetHack 3.7 zap.c $NHDT-Date: 1596498233 2020/08/03 23:43:53 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.346 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2013. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1022,7 +1022,7 @@ struct monst *mon; pline("%s%s suddenly %s%s%s!", owner, corpse, nonliving(mtmp2->data) ? "reanimates" : "comes alive", different_type ? " as " : "", - different_type ? an(mtmp2->data->mname) : ""); + different_type ? an(pmname(mtmp2->data, Mgender(mtmp2))) : ""); else if (canseemon(mtmp2)) pline("%s suddenly appears!", Amonnam(mtmp2)); } @@ -1152,6 +1152,19 @@ register struct obj *obj; break; } } + /* cancelling a troll's corpse prevents it from reviving (on its own; + does not affect undead turning induced revival) */ + if (obj->otyp == CORPSE && obj->timed + && !is_rider(&mons[obj->corpsenm])) { + anything a = *obj_to_any(obj); + long timout = peek_timer(REVIVE_MON, &a); + + if (timout) { + (void) stop_timer(REVIVE_MON, &a); + (void) start_timer(timout, TIMER_OBJECT, ROT_CORPSE, &a); + } + } + unbless(obj); uncurse(obj); return; @@ -1463,6 +1476,16 @@ struct obj *obj; delobj(obj); } +/* Returns TRUE if obj resists polymorphing */ +boolean +obj_unpolyable(obj) +struct obj *obj; +{ + return (unpolyable(obj) + || obj == uball || obj == uskin + || obj_resists(obj, 5, 95)); +} + /* classes of items whose current charge count carries over across polymorph */ static const char charged_objs[] = { WAND_CLASS, WEAPON_CLASS, ARMOR_CLASS, @@ -1951,8 +1974,7 @@ struct obj *obj, *otmp; switch (otmp->otyp) { case WAN_POLYMORPH: case SPE_POLYMORPH: - if (obj->otyp == WAN_POLYMORPH || obj->otyp == SPE_POLYMORPH - || obj->otyp == POT_POLYMORPH || obj_resists(obj, 5, 95)) { + if (obj_unpolyable(obj)) { res = 0; break; } @@ -2205,6 +2227,16 @@ register struct obj *wand; return 1; } +void +do_enlightenment_effect() +{ + You_feel("self-knowledgeable..."); + display_nhwindow(WIN_MESSAGE, FALSE); + enlightenment(MAGICENLIGHTENMENT, ENL_GAMEINPROGRESS); + pline_The("feeling subsides."); + exercise(A_WIS, TRUE); +} + /* * zapnodir - zaps a NODIR wand/spell. * added by GAN 11/03/86 @@ -2245,11 +2277,7 @@ register struct obj *obj; break; case WAN_ENLIGHTENMENT: known = TRUE; - You_feel("self-knowledgeable..."); - display_nhwindow(WIN_MESSAGE, FALSE); - enlightenment(MAGICENLIGHTENMENT, ENL_GAMEINPROGRESS); - pline_The("feeling subsides."); - exercise(A_WIS, TRUE); + do_enlightenment_effect(); break; } if (known) { @@ -2415,6 +2443,7 @@ boolean ordinary; destroy_item(POTION_CLASS, AD_FIRE); destroy_item(SPBOOK_CLASS, AD_FIRE); destroy_item(FOOD_CLASS, AD_FIRE); /* only slime for now */ + ignite_items(g.invent); break; case WAN_COLD: @@ -2877,6 +2906,7 @@ struct obj *obj; /* wand or spell */ struct engr *e; struct trap *ttmp; char buf[BUFSZ]; + stairway *stway = g.stairs; /* some wands have special effects other than normal bhitpile */ /* drawbridge might change */ @@ -2899,11 +2929,16 @@ struct obj *obj; /* wand or spell */ return TRUE; /* we've done our own bhitpile */ case WAN_OPENING: case SPE_KNOCK: + while (stway) { + if (!stway->isladder && !stway->up && stway->tolev.dnum == u.uz.dnum) + break; + stway = stway->next; + } /* up or down, but at closed portcullis only */ if (is_db_wall(x, y) && find_drawbridge(&xx, &yy)) { open_drawbridge(xx, yy); disclose = TRUE; - } else if (u.dz > 0 && (x == xdnstair && y == ydnstair) + } else if (u.dz > 0 && stway && stway->sx == x && stway->sy == y /* can't use the stairs down to quest level 2 until leader "unlocks" them; give feedback if you try */ && on_level(&u.uz, &qstart_level) && !ok_to_quest()) { @@ -3704,6 +3739,8 @@ struct obj **ootmp; /* to return worn armor for caller to disintegrate */ (void) destroy_mitem(mon, SCROLL_CLASS, AD_FIRE); if (!rn2(5)) (void) destroy_mitem(mon, SPBOOK_CLASS, AD_FIRE); + if (!rn2(3)) + ignite_items(mon->minvent); destroy_mitem(mon, FOOD_CLASS, AD_FIRE); /* carried slime */ } break; @@ -3861,6 +3898,8 @@ xchar sx, sy; destroy_item(SCROLL_CLASS, AD_FIRE); if (!rn2(5)) destroy_item(SPBOOK_CLASS, AD_FIRE); + if (!rn2(3)) + ignite_items(g.invent); destroy_item(FOOD_CLASS, AD_FIRE); } break; @@ -4022,6 +4061,9 @@ boolean u_caused; } } } + /* This also ignites floor items, but does not change cnt + because they weren't consumed. */ + ignite_items(g.level.objects[x][y]); return cnt; } diff --git a/submodules/lua b/submodules/lua new file mode 160000 index 000000000..e2ea3b31c --- /dev/null +++ b/submodules/lua @@ -0,0 +1 @@ +Subproject commit e2ea3b31c94bb3e1da27c233661cb2a16699c685 diff --git a/submodules/pdcurses b/submodules/pdcurses new file mode 160000 index 000000000..618e0aaa3 --- /dev/null +++ b/submodules/pdcurses @@ -0,0 +1 @@ +Subproject commit 618e0aaa31b4728eb4df78ec4de6c2b873908eda diff --git a/sys/libnh/README.md b/sys/libnh/README.md new file mode 100644 index 000000000..8258323b7 --- /dev/null +++ b/sys/libnh/README.md @@ -0,0 +1,110 @@ +# About +This creates a library for NetHack that can be incorporated into other programs. There are two different libraries that are currently available: +* libnethack.a - a binary Unix library +* nethack.js / nethack.wasm - a [WebAssembly / WASM](https://webassembly.org/) library for use in JavaScript programs (both nodejs and browser) + +## Build +This library has only been built on MacOS, but should work on Linux and other unix-ish platforms. If you have problems, start by stealing hints files from the `sys/unix/hints` for your platform. Contributions for other platforms are happily accepted. + +Building the WASM module requires that you have the [emscripten toolchain / sdk installed](https://emscripten.org/docs/getting_started/downloads.html). + +Generally the build is the same as the unix build: + +[Edit Oct 4, 2020: Use the existing Makefile and hints, hints/include system for cross-compiles] +1. `cd sys/unix` +2. `./setup.sh hints/macOS.2020` +3. `cd ../..` +4. For `libnethack.a`: `make WANT_LIBNH=1 all` +5. For `nethack.js`: `make CROSS_TO_WASM=1 all` + +[Original text was:] +1. `cd sys/lib` +2. For `libnethack.a`: `./setup.sh hints/macOS.2020`; for `nethack.js`: `./setup.sh hints/wasm` +3. `cd ../..` +4. `make` + + +[Edit Oct 4, 2020:] +Resulting libaries will be in the `targets/wasm` directory for `CROSS_TO_WASM=1`. +Resulting libaries will be in the `src` directory for `WANT_LIBNH=1`. + +[Original text:] +Resulting libaries will be in the `src` directory. + +WASM also has a npm module that can be published out of `sys/lib/npm-library`. After building the `nethack.js` it can be published by: +1. `cd sys/lib/npm-library` +2. `npm publish` + +## API: libnethack.a +The API is two functions: +* `nhmain(int argc, char *argv[])` - The main function for NetHack that configures the program and runs the `moveloop()` until the game is over. The arguments to this function are the [command line arguments](https://nethackwiki.com/wiki/Options) to NetHack. +* `shim_graphics_set_callback(shim_callback_t cb)` - A single function that sets a callback to gather graphics events: write a string to screen, get user input, etc. Your job is to pass in a callback and handle all the requested rendering events to show NetHack on the scrren. The callback is `void shim_callback_t(const char *name, void *ret_ptr, const char *fmt, ...)` + * `name` is the name of the [window function](https://github.com/NetHack/NetHack/blob/NetHack-3.7/doc/window.doc) that needs to be handled + * `ret_ptr` is a pointer to a memory space for the return value. The type expected to be returned in this pointer is described by the first character of the `fmt` string. + * `fmt` is a string that describes the signature of the callback. The first character in the string is the return type and any additional characters describe the variable arguments: `i` for integer, `s` for string, `p` for pointer, `c` for character, `v` for void. For example, if format is "vis" the callback will have no return (void), the first argument will be an integer, and the second argument will be a string. If format is "iii" the callback must return an integer, and both the arguments passed in will be integers. + * [Variadic arguments](https://www.gnu.org/software/libc/manual/html_node/Variadic-Example.html): a variable number and type of arguments depending on the `window function` that is being called. The arguments associated with each `name` are described in the [NetHack window.doc](https://github.com/NetHack/NetHack/blob/NetHack-3.7/doc/window.doc). + +Where is the header file for the API you ask? There isn't one. It's three functions, just drop the forward declarations at the top of your file (or create your own header). It's more work figuring out how to install and copy around header files than it's worth for such a small API. If you disagree, feel free to sumbit a PR to fix it. :) + +## API: nethack.js +The WebAssembly API has a similar signature to `libnethack.a` with minor syntactic differences: +* `main(int argc, char argv[])` - The main function for NetHack +* `shim_graphics_set_callback(char *cbName)` - A `String` representing a name of a callback function. The callback function be registered as `globalThis[cbName] = function yourCallback(name, ... args) { /* your stuff */ }`. Note that [globalThis](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/globalThis) points to `window` in browsers and `global` in node.js. + * `name` is the name of the [window function](https://github.com/NetHack/NetHack/blob/NetHack-3.7/doc/window.doc) that needs to be handled + * `... args` is a variable number and type of arguments depending on the `window function` that is being called. The arguments associated with each `name` are described in the [NetHack window.doc](https://github.com/NetHack/NetHack/blob/NetHack-3.7/doc/window.doc) + * The function must return the value expected for the specified `name` + + +## API Stability +The "shim graphics" API should generally be stable. I aspire to replace the command line arguments (argc / argv) with a structure of options, so the `nhmain()` and `main()` functions may change at some point. + +## libnethack.a example +``` c +#include + +int nhmain(int argc, char *argv[]); +typedef void(*shim_callback_t)(const char *name, void *ret_ptr, const char *fmt, ...); +void shim_graphics_set_callback(shim_callback_t cb); + +void window_cb(const char *name, void *ret_ptr, const char *fmt, ...) { + /* TODO */ +} + +int main(int argc, char *argv[]) { + shim_graphics_set_callback(window_cb); + nhmain(argc, argv); +} +``` + +## nethack.js example +``` js +const path = require("path"); + +// starts nethack +function nethackStart(cb, inputModule = {}) { + // set callback + let cbName = cb.name; + if (cbName === "") cbName = "__anonymousNetHackCallback"; + let userCallback = globalThis[cbName] = cb; + + // Emscripten Module config + let Module = inputModule; + savedOnRuntimeInitialized = Module.onRuntimeInitialized; + Module.onRuntimeInitialized = function (... args) { + // after the WASM is loaded, add the shim graphics callback function + Module.ccall( + "shim_graphics_set_callback", // C function name + null, // return type + ["string"], // arg types + [cbName], // arg values + {async: true} // options + ); + }; + + // load and run the module + var factory = require(path.join(__dirname, "../build/nethack.js")); + factory(Module); +} + +nethackStart(yourCallbackFunction); +``` diff --git a/sys/libnh/libnhmain.c b/sys/libnh/libnhmain.c new file mode 100644 index 000000000..bbd16482f --- /dev/null +++ b/sys/libnh/libnhmain.c @@ -0,0 +1,1126 @@ +/* NetHack 3.7 libnhmain.c $NHDT-Date: 1596498297 2020/08/03 23:44:57 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.87 $ */ +/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ +/*-Copyright (c) Robert Patrick Rankin, 2011. */ +/* NetHack may be freely redistributed. See license for details. */ + +/* main.c - Unix NetHack */ + +#include "hack.h" +#include "dlb.h" + +#include +#include +#include +#include +#ifndef O_RDONLY +#include +#endif + +/* for cross-compiling to WebAssembly (WASM) */ +#ifdef __EMSCRIPTEN__ +#include +void js_helpers_init(); +void js_constants_init(); +void js_globals_init(); +#endif + +#if !defined(_BULL_SOURCE) && !defined(__sgi) && !defined(_M_UNIX) +#if !defined(SUNOS4) && !(defined(ULTRIX) && defined(__GNUC__)) +#if defined(POSIX_TYPES) || defined(SVR4) || defined(HPUX) +extern struct passwd *FDECL(getpwuid, (uid_t)); +#else +extern struct passwd *FDECL(getpwuid, (int)); +#endif +#endif +#endif +extern struct passwd *FDECL(getpwnam, (const char *)); +#ifdef CHDIR +static void FDECL(chdirx, (const char *, BOOLEAN_P)); +#endif /* CHDIR */ +static boolean NDECL(whoami); +static void FDECL(process_options, (int, char **)); + +#ifdef _M_UNIX +extern void NDECL(check_sco_console); +extern void NDECL(init_sco_cons); +#endif +#ifdef __linux__ +extern void NDECL(check_linux_console); +extern void NDECL(init_linux_cons); +#endif + +static void NDECL(wd_message); +static boolean wiz_error_flag = FALSE; +static struct passwd *NDECL(get_unix_pw); + +#ifdef __EMSCRIPTEN__ +/* if WebAssembly, export this API and don't optimize it out */ +EMSCRIPTEN_KEEPALIVE +int +main(argc, argv) +int argc; +char *argv[]; + +#else /* !__EMSCRIPTEN__ */ + +int +nhmain(argc, argv) +int argc; +char *argv[]; + +#endif /* __EMSCRIPTEN__ */ +{ +#ifdef CHDIR + register char *dir; +#endif + NHFILE *nhfp; + boolean exact_username; + boolean resuming = FALSE; /* assume new game */ + boolean plsel_once = FALSE; + // int i; + // for (i = 0; i < argc; i++) { + // printf ("argv[%d]: %s\n", i, argv[i]); + // } + + early_init(); + + g.hname = argv[0]; + g.hackpid = getpid(); + (void) umask(0777 & ~FCMASK); + + choose_windows(DEFAULT_WINDOW_SYS); + +#ifdef CHDIR /* otherwise no chdir() */ + /* + * See if we must change directory to the playground. + * (Perhaps hack runs suid and playground is inaccessible + * for the player.) + * The environment variable HACKDIR is overridden by a + * -d command line option (must be the first option given). + */ + dir = nh_getenv("NETHACKDIR"); + if (!dir) + dir = nh_getenv("HACKDIR"); + + if (argc > 1) { + if (argcheck(argc, argv, ARG_VERSION) == 2) + 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); + } + if (argcheck(argc, argv, ARG_DEBUG) == 1) { + argc--; + argv++; + } + if (argc > 1 && !strncmp(argv[1], "-d", 2) && argv[1][2] != 'e') { + /* avoid matching "-dec" for DECgraphics; since the man page + * says -d directory, hope nobody's using -desomething_else + */ + argc--; + argv++; + dir = argv[0] + 2; + if (*dir == '=' || *dir == ':') + dir++; + if (!*dir && argc > 1) { + argc--; + argv++; + dir = argv[0]; + } + if (!*dir) + error("Flag -d must be followed by a directory name."); + } + } +#endif /* CHDIR */ + + if (argc > 1) { + /* + * Now we know the directory containing 'record' and + * may do a prscore(). Exclude `-style' - it's a Qt option. + */ + if (!strncmp(argv[1], "-s", 2) && strncmp(argv[1], "-style", 6)) { +#ifdef CHDIR + chdirx(dir, 0); +#endif +#ifdef SYSCF + initoptions(); +#endif +#ifdef PANICTRACE + ARGV0 = g.hname; /* save for possible stack trace */ +#ifndef NO_SIGNAL + panictrace_setsignals(TRUE); +#endif +#endif + prscore(argc, argv); + /* FIXME: shouldn't this be using nh_terminate() to free + up any memory allocated by initoptions() */ + exit(EXIT_SUCCESS); + } + } /* argc > 1 */ + +/* + * Change directories before we initialize the window system so + * we can find the tile file. + */ +#ifdef CHDIR + chdirx(dir, 1); +#endif + +#ifdef _M_UNIX + check_sco_console(); +#endif +#ifdef __linux__ + check_linux_console(); +#endif + initoptions(); +#ifdef PANICTRACE + ARGV0 = g.hname; /* save for possible stack trace */ +#ifndef NO_SIGNAL + panictrace_setsignals(TRUE); +#endif +#endif + exact_username = whoami(); + + /* + * It seems you really want to play. + */ + u.uhp = 1; /* prevent RIP on early quits */ + g.program_state.preserve_locks = 1; +#ifndef NO_SIGNAL + sethanguphandler((SIG_RET_TYPE) hangup); +#endif + + 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 + init_sco_cons(); +#endif +#ifdef __linux__ + init_linux_cons(); +#endif + +#ifdef DEF_PAGER + if (!(g.catmore = nh_getenv("HACKPAGER")) + && !(g.catmore = nh_getenv("PAGER"))) + g.catmore = DEF_PAGER; +#endif +#ifdef MAIL + getmailstatus(); +#endif + + /* wizard mode access is deferred until here */ + set_playmode(); /* sets plname to "wizard" for wizard mode */ + /* hide any hyphens from plnamesuffix() */ + g.plnamelen = exact_username ? (int) strlen(g.plname) : 0; + /* strip role,race,&c suffix; calls askname() if plname[] is empty + or holds a generic user name like "player" or "games" */ + plnamesuffix(); + + if (wizard) { + /* use character name rather than lock letter for file names */ + g.locknum = 0; + } else { +#ifndef NO_SIGNAL + /* suppress interrupts while processing lock file */ + (void) signal(SIGQUIT, SIG_IGN); + (void) signal(SIGINT, SIG_IGN); +#endif + } + + dlb_init(); /* must be before newgame() */ + + /* + * Initialize the vision system. This must be before mklev() on a + * new game or before a level restore on a saved game. + */ + vision_init(); + + display_gamewindows(); + + /* + * First, try to find and restore a save file for specified character. + * We'll return here if new game player_selection() renames the hero. + */ + attempt_restore: + + /* + * getlock() complains and quits if there is already a game + * in progress for current character name (when g.locknum == 0) + * or if there are too many active games (when g.locknum > 0). + * When proceeding, it creates an empty .0 file to + * designate the current game. + * getlock() constructs based on the character + * name (for !g.locknum) or on first available of alock, block, + * clock, &c not currently in use in the playground directory + * (for g.locknum > 0). + */ + if (*g.plname) { + getlock(); + g.program_state.preserve_locks = 0; /* after getlock() */ + } + + if (*g.plname && (nhfp = restore_saved_game()) != 0) { + const char *fq_save = fqname(g.SAVEF, SAVEPREFIX, 1); + + (void) chmod(fq_save, 0); /* disallow parallel restores */ +#ifndef NO_SIGNAL + (void) signal(SIGINT, (SIG_RET_TYPE) done1); +#endif +#ifdef NEWS + if (iflags.news) { + display_file(NEWS, FALSE); + iflags.news = FALSE; /* in case dorecover() fails */ + } +#endif + pline("Restoring save file..."); + mark_synch(); /* flush output */ + if (dorecover(nhfp)) { + resuming = TRUE; /* not starting new game */ + wd_message(); + if (discover || wizard) { + /* this seems like a candidate for paranoid_confirmation... */ + if (yn("Do you want to keep the save file?") == 'n') { + (void) delete_savefile(); + } else { + (void) chmod(fq_save, FCMASK); /* back to readable */ + nh_compress(fq_save); + } + } + } + } + + if (!resuming) { + boolean neednewlock = (!*g.plname); + /* new game: start by choosing role, race, etc; + player might change the hero's name while doing that, + in which case we try to restore under the new name + and skip selection this time if that didn't succeed */ + if (!iflags.renameinprogress || iflags.defer_plname || neednewlock) { + if (!plsel_once) + player_selection(); + plsel_once = TRUE; + if (neednewlock && *g.plname) + goto attempt_restore; + if (iflags.renameinprogress) { + /* player has renamed the hero while selecting role; + if locking alphabetically, the existing lock file + can still be used; otherwise, discard current one + and create another for the new character name */ + if (!g.locknum) { + delete_levelfile(0); /* remove empty lock file */ + getlock(); + } + goto attempt_restore; + } + } + newgame(); + wd_message(); + } + + /* moveloop() never returns but isn't flagged NORETURN */ + moveloop(resuming); + + exit(EXIT_SUCCESS); + /*NOTREACHED*/ + return 0; +} + +/* caveat: argv elements might be arbitrary long */ +static void +process_options(argc, argv) +int argc; +char *argv[]; +{ + int i, l; + + /* + * Process options. + */ + while (argc > 1 && argv[1][0] == '-') { + argv++; + argc--; + l = (int) strlen(*argv); + /* must supply at least 4 chars to match "-XXXgraphics" */ + if (l < 4) + l = 4; + + switch (argv[0][1]) { + case 'D': + case 'd': + if ((argv[0][1] == 'D' && !argv[0][2]) + || !strcmpi(*argv, "-debug")) { + wizard = TRUE, discover = FALSE; + } else if (!strncmpi(*argv, "-DECgraphics", l)) { + load_symset("DECGraphics", PRIMARY); + switch_symbols(TRUE); + } else { + raw_printf("Unknown option: %.60s", *argv); + } + break; + case 'X': + discover = TRUE, wizard = FALSE; + break; +#ifdef NEWS + case 'n': + iflags.news = FALSE; + break; +#endif + case 'u': + if (argv[0][2]) { + (void) strncpy(g.plname, argv[0] + 2, sizeof g.plname - 1); + g.plnamelen = 0; /* plname[] might have -role-race attached */ + } else if (argc > 1) { + argc--; + argv++; + (void) strncpy(g.plname, argv[0], sizeof g.plname - 1); + g.plnamelen = 0; + } else { + raw_print("Player name expected after -u"); + } + break; + case 'I': + case 'i': + if (!strncmpi(*argv, "-IBMgraphics", l)) { + load_symset("IBMGraphics", PRIMARY); + load_symset("RogueIBM", ROGUESET); + switch_symbols(TRUE); + } else { + raw_printf("Unknown option: %.60s", *argv); + } + break; + case 'p': /* profession (role) */ + if (argv[0][2]) { + if ((i = str2role(&argv[0][2])) >= 0) + flags.initrole = i; + } else if (argc > 1) { + argc--; + argv++; + if ((i = str2role(argv[0])) >= 0) + flags.initrole = i; + } + break; + case 'r': /* race */ + if (argv[0][2]) { + if ((i = str2race(&argv[0][2])) >= 0) + flags.initrace = i; + } else if (argc > 1) { + argc--; + argv++; + if ((i = str2race(argv[0])) >= 0) + flags.initrace = i; + } + break; + case 'w': /* windowtype */ + config_error_init(FALSE, "command line", FALSE); + choose_windows(&argv[0][2]); + config_error_done(); + break; + case '@': + flags.randomall = 1; + break; + default: + if ((i = str2role(&argv[0][1])) >= 0) { + flags.initrole = i; + break; + } + /* else raw_printf("Unknown option: %.60s", *argv); */ + } + } + +#ifdef SYSCF + if (argc > 1) + raw_printf("MAXPLAYERS are set in sysconf file.\n"); +#else + /* XXX This is deprecated in favor of SYSCF with MAXPLAYERS */ + if (argc > 1) + g.locknum = atoi(argv[1]); +#endif +#ifdef MAX_NR_OF_PLAYERS + /* limit to compile-time limit */ + if (!g.locknum || g.locknum > MAX_NR_OF_PLAYERS) + g.locknum = MAX_NR_OF_PLAYERS; +#endif +#ifdef SYSCF + /* let syscf override compile-time limit */ + if (!g.locknum || (sysopt.maxplayers && g.locknum > sysopt.maxplayers)) + g.locknum = sysopt.maxplayers; +#endif +} + +#ifdef CHDIR +static void +chdirx(dir, wr) +const char *dir; +boolean wr; +{ + if (dir /* User specified directory? */ +#ifdef HACKDIR + && strcmp(dir, HACKDIR) /* and not the default? */ +#endif + ) { +#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); + + g.fqn_prefix[SCOREPREFIX] = (char *) alloc(len + 2); + Strcpy(g.fqn_prefix[SCOREPREFIX], VAR_PLAYGROUND); + if (g.fqn_prefix[SCOREPREFIX][len - 1] != '/') { + g.fqn_prefix[SCOREPREFIX][len] = '/'; + g.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); + } + + /* warn the player if we can't write the record file + * perhaps we should also test whether . is writable + * unfortunately the access system-call is worthless. + */ + if (wr) { +#ifdef VAR_PLAYGROUND + g.fqn_prefix[LEVELPREFIX] = g.fqn_prefix[SCOREPREFIX]; + g.fqn_prefix[SAVEPREFIX] = g.fqn_prefix[SCOREPREFIX]; + g.fqn_prefix[BONESPREFIX] = g.fqn_prefix[SCOREPREFIX]; + g.fqn_prefix[LOCKPREFIX] = g.fqn_prefix[SCOREPREFIX]; + g.fqn_prefix[TROUBLEPREFIX] = g.fqn_prefix[SCOREPREFIX]; +#endif + check_recordfile(dir); + } +} +#endif /* CHDIR */ + +/* returns True iff we set plname[] to username which contains a hyphen */ +static boolean +whoami() +{ + /* + * Who am i? Algorithm: 1. Use name as specified in NETHACKOPTIONS + * 2. Use $USER or $LOGNAME (if 1. fails) + * 3. Use getlogin() (if 2. fails) + * The resulting name is overridden by command line options. + * If everything fails, or if the resulting name is some generic + * account like "games", "play", "player", "hack" then eventually + * we'll ask him. + * Note that we trust the user here; it is possible to play under + * somebody else's name. + */ + if (!*g.plname) { + register const char *s; + + s = nh_getenv("USER"); + if (!s || !*s) + s = nh_getenv("LOGNAME"); + if (!s || !*s) + s = getlogin(); + + if (s && *s) { + (void) strncpy(g.plname, s, sizeof g.plname - 1); + if (index(g.plname, '-')) + return TRUE; + } + } + return FALSE; +} + +#ifndef NO_SIGNAL +void +sethanguphandler(handler) +void FDECL((*handler), (int)); +{ +#ifdef SA_RESTART + /* don't want reads to restart. If SA_RESTART is defined, we know + * sigaction exists and can be used to ensure reads won't restart. + * If it's not defined, assume reads do not restart. If reads restart + * and a signal occurs, the game won't do anything until the read + * succeeds (or the stream returns EOF, which might not happen if + * reading from, say, a window manager). */ + struct sigaction sact; + + (void) memset((genericptr_t) &sact, 0, sizeof sact); + sact.sa_handler = (SIG_RET_TYPE) handler; + (void) sigaction(SIGHUP, &sact, (struct sigaction *) 0); +#ifdef SIGXCPU + (void) sigaction(SIGXCPU, &sact, (struct sigaction *) 0); +#endif +#else /* !SA_RESTART */ + (void) signal(SIGHUP, (SIG_RET_TYPE) handler); +#ifdef SIGXCPU + (void) signal(SIGXCPU, (SIG_RET_TYPE) handler); +#endif +#endif /* ?SA_RESTART */ +} +#endif /* !NO_SIGNAL */ + +#ifdef PORT_HELP +void +port_help() +{ + /* + * Display unix-specific help. Just show contents of the helpfile + * named by PORT_HELP. + */ + display_file(PORT_HELP, TRUE); +} +#endif + +/* validate wizard mode if player has requested access to it */ +boolean +authorize_wizard_mode() +{ + struct passwd *pw = get_unix_pw(); + + if (pw && sysopt.wizards && sysopt.wizards[0]) { + if (check_user_string(sysopt.wizards)) + return TRUE; + } + wiz_error_flag = TRUE; /* not being allowed into wizard mode */ + return FALSE; +} + +static void +wd_message() +{ + if (wiz_error_flag) { + if (sysopt.wizards && sysopt.wizards[0]) { + char *tmp = build_english_list(sysopt.wizards); + pline("Only user%s %s may access debug (wizard) mode.", + index(sysopt.wizards, ' ') ? "s" : "", tmp); + free(tmp); + } else + pline("Entering explore/discovery mode instead."); + wizard = 0, discover = 1; /* (paranoia) */ + } else if (discover) + You("are in non-scoring explore/discovery mode."); +} + +/* + * Add a slash to any name not ending in /. There must + * be room for the / + */ +void +append_slash(name) +char *name; +{ + char *ptr; + + if (!*name) + return; + ptr = name + (strlen(name) - 1); + if (*ptr != '/') { + *++ptr = '/'; + *++ptr = '\0'; + } + return; +} + +boolean +check_user_string(optstr) +const char *optstr; +{ + struct passwd *pw; + int pwlen; + const char *eop, *w; + char *pwname = 0; + + if (optstr[0] == '*') + return TRUE; /* allow any user */ + if (sysopt.check_plname) + pwname = g.plname; + else if ((pw = get_unix_pw()) != 0) + pwname = pw->pw_name; + if (!pwname || !*pwname) + return FALSE; + pwlen = (int) strlen(pwname); + eop = eos((char *)optstr); + w = optstr; + while (w + pwlen <= eop) { + if (!*w) + break; + if (isspace(*w)) { + w++; + continue; + } + if (!strncmp(w, pwname, pwlen)) { + if (!w[pwlen] || isspace(w[pwlen])) + return TRUE; + } + while (*w && !isspace(*w)) + w++; + } + return FALSE; +} + +static struct passwd * +get_unix_pw() +{ + char *user; + unsigned uid; + static struct passwd *pw = (struct passwd *) 0; + + if (pw) + return pw; /* cache answer */ + + uid = (unsigned) getuid(); + user = getlogin(); + if (user) { + pw = getpwnam(user); + if (pw && ((unsigned) pw->pw_uid != uid)) + pw = 0; + } + if (pw == 0) { + user = nh_getenv("USER"); + if (user) { + pw = getpwnam(user); + if (pw && ((unsigned) pw->pw_uid != uid)) + pw = 0; + } + if (pw == 0) { + pw = getpwuid(uid); + } + } + return pw; +} + +char * +get_login_name() +{ + static char buf[BUFSZ]; + struct passwd *pw = get_unix_pw(); + + buf[0] = '\0'; + if (pw) + (void)strcpy(buf, pw->pw_name); + + return buf; +} + +unsigned long +sys_random_seed() +{ + unsigned long seed = 0L; + unsigned long pid = (unsigned long) getpid(); + boolean no_seed = TRUE; +#ifdef DEV_RANDOM + FILE *fptr; + + fptr = fopen(DEV_RANDOM, "r"); + if (fptr) { + fread(&seed, sizeof (long), 1, fptr); + has_strong_rngseed = TRUE; /* decl.c */ + no_seed = FALSE; + (void) fclose(fptr); + } else { + /* leaves clue, doesn't exit */ + paniclog("sys_random_seed", "falling back to weak seed"); + } +#endif + if (no_seed) { + seed = (unsigned long) getnow(); /* time((TIME_type) 0) */ + /* Quick dirty band-aid to prevent PRNG prediction */ + if (pid) { + if (!(pid & 3L)) + pid -= 1L; + seed *= pid; + } + } + return seed; +} + +#ifdef __EMSCRIPTEN__ +/*** + * Helpers + ***/ +EM_JS(void, js_helpers_init, (), { + globalThis.nethackGlobal = globalThis.nethackGlobal || {}; + globalThis.nethackGlobal.helpers = globalThis.nethackGlobal.helpers || {}; + + installHelper(mapglyphHelper); + installHelper(displayInventory); + installHelper(getPointerValue); + installHelper(setPointerValue); + + // used by print_glyph + function mapglyphHelper(glyph, x, y, mgflags) { + let ochar = _malloc(4); + let ocolor = _malloc(4); + let ospecial = _malloc(4); + + _mapglyph(glyph, ochar, ocolor, ospecial, x, y, mgflags); + + let ch = getValue(ochar, "i32"); + let color = getValue(ocolor, "i32"); + let special = getValue(ospecial, "i32"); + + _free (ochar); + _free (ocolor); + _free (ospecial); + + return { + glyph, + ch, + color, + special, + x, + y, + mgflags + }; + } + + // used by update_inventory + function displayInventory() { + // Asyncify.handleAsync(async () => { + return _display_inventory(0, 0); + // }); + } + + // convert 'ptr' to the type indicated by 'type' + function getPointerValue(name, ptr, type) { + // console.log("getPointerValue", name, "0x" + ptr.toString(16), type); + switch(type) { + case "s": // string + // var value = UTF8ToString(getValue(ptr, "*")); + return UTF8ToString(ptr); + case "p": // pointer + if(!ptr) return 0; // null pointer + return getValue(ptr, "*"); + case "c": // char + return String.fromCharCode(getValue(ptr, "i8")); + case "0": /* 2^0 = 1 byte */ + return getValue(ptr, "i8"); + case "1": /* 2^1 = 2 bytes */ + return getValue(ptr, "i16"); + case "2": /* 2^2 = 4 bytes */ + case "i": // integer + case "n": // number + return getValue(ptr, "i32"); + case "f": // float + return getValue(ptr, "float"); + case "d": // double + return getValue(ptr, "double"); + case "o": // overloaded: multiple types + return ptr; + default: + throw new TypeError ("unknown type:" + type); + } + } + + // sets the return value of the function to the type expected + function setPointerValue(name, ptr, type, value = 0) { + // console.log("setPointerValue", name, "0x" + ptr.toString(16), type, value); + switch (type) { + case "p": + throw new Error("not implemented"); + case "s": + if(typeof value !== "string") + throw new TypeError(`expected ${name} return type to be string`); + // value=value?value:"(no value)"; + // var strPtr = getValue(ptr, "i32"); + stringToUTF8(value, ptr, 1024); // TODO: uhh... danger will robinson + break; + case "i": + if(typeof value !== "number" || !Number.isInteger(value)) + throw new TypeError(`expected ${name} return type to be integer`); + setValue(ptr, value, "i32"); + 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`); + setValue(ptr, value, "i8"); + break; + case "f": + if(typeof value !== "number" || isFloat(value)) + throw new TypeError(`expected ${name} return type to be float`); + // XXX: I'm not sure why 'double' works and 'float' doesn't + setValue(ptr, value, "double"); + break; + case "d": + if(typeof value !== "number" || isFloat(value)) + throw new TypeError(`expected ${name} return type to be double`); + setValue(ptr, value, "double"); + break; + case "v": + break; + default: + throw new Error("unknown type"); + } + + function isFloat(n){ + return n === +n && n !== (n|0) && !Number.isInteger(n); + } + } + + + function installHelper(fn, name) { + name = name || fn.name; + globalThis.nethackGlobal.helpers[name] = fn; + } +}) + +/*** + * Constants + ***/ +#define SET_CONSTANT(scope, name) set_const(scope, #name, name); +EM_JS(void, set_const, (char *scope_str, char *name_str, int num), { + let scope = UTF8ToString(scope_str); + let name = UTF8ToString(name_str); + + globalThis.nethackGlobal.constants[scope] = globalThis.nethackGlobal.constants[scope] || {}; + globalThis.nethackGlobal.constants[scope][name] = num; + globalThis.nethackGlobal.constants[scope][num] = name; +}); +#define SET_CONSTANT_STRING(scope, name) set_const_str(scope, #name, name); +EM_JS(void, set_const_str, (char *scope_str, char *name_str, char *input_str), { + let scope = UTF8ToString(scope_str); + let name = UTF8ToString(name_str); + let str = UTF8ToString(input_str); + + globalThis.nethackGlobal.constants[scope] = globalThis.nethackGlobal.constants[scope] || {}; + globalThis.nethackGlobal.constants[scope][name] = str; +}); + +void js_constants_init() { + EM_ASM({ + globalThis.nethackGlobal = globalThis.nethackGlobal || {}; + globalThis.nethackGlobal.constants = globalThis.nethackGlobal.constants || {}; + }); + + // create_nhwindow + SET_CONSTANT("WIN_TYPE", NHW_MESSAGE) + SET_CONSTANT("WIN_TYPE", NHW_STATUS) + SET_CONSTANT("WIN_TYPE", NHW_MAP) + SET_CONSTANT("WIN_TYPE", NHW_MENU) + SET_CONSTANT("WIN_TYPE", NHW_TEXT) + + // status_update + SET_CONSTANT("STATUS_FIELD", BL_CHARACTERISTICS) + SET_CONSTANT("STATUS_FIELD", BL_RESET) + SET_CONSTANT("STATUS_FIELD", BL_FLUSH) + SET_CONSTANT("STATUS_FIELD", BL_TITLE) + SET_CONSTANT("STATUS_FIELD", BL_STR) + SET_CONSTANT("STATUS_FIELD", BL_DX) + SET_CONSTANT("STATUS_FIELD", BL_CO) + SET_CONSTANT("STATUS_FIELD", BL_IN) + SET_CONSTANT("STATUS_FIELD", BL_WI) + SET_CONSTANT("STATUS_FIELD", BL_CH) + SET_CONSTANT("STATUS_FIELD", BL_ALIGN) + SET_CONSTANT("STATUS_FIELD", BL_SCORE) + SET_CONSTANT("STATUS_FIELD", BL_CAP) + SET_CONSTANT("STATUS_FIELD", BL_GOLD) + SET_CONSTANT("STATUS_FIELD", BL_ENE) + SET_CONSTANT("STATUS_FIELD", BL_ENEMAX) + SET_CONSTANT("STATUS_FIELD", BL_XP) + SET_CONSTANT("STATUS_FIELD", BL_AC) + SET_CONSTANT("STATUS_FIELD", BL_HD) + SET_CONSTANT("STATUS_FIELD", BL_TIME) + SET_CONSTANT("STATUS_FIELD", BL_HUNGER) + SET_CONSTANT("STATUS_FIELD", BL_HP) + SET_CONSTANT("STATUS_FIELD", BL_HPMAX) + SET_CONSTANT("STATUS_FIELD", BL_LEVELDESC) + SET_CONSTANT("STATUS_FIELD", BL_EXP) + SET_CONSTANT("STATUS_FIELD", BL_CONDITION) + SET_CONSTANT("STATUS_FIELD", MAXBLSTATS) + + // text attributes + SET_CONSTANT("ATTR", ATR_NONE); + SET_CONSTANT("ATTR", ATR_BOLD); + SET_CONSTANT("ATTR", ATR_DIM); + SET_CONSTANT("ATTR", ATR_ULINE); + SET_CONSTANT("ATTR", ATR_BLINK); + SET_CONSTANT("ATTR", ATR_INVERSE); + SET_CONSTANT("ATTR", ATR_URGENT); + SET_CONSTANT("ATTR", ATR_NOHISTORY); + + // conditions + SET_CONSTANT("CONDITION", BL_MASK_BAREH); + SET_CONSTANT("CONDITION", BL_MASK_BLIND); + SET_CONSTANT("CONDITION", BL_MASK_BUSY); + SET_CONSTANT("CONDITION", BL_MASK_CONF); + SET_CONSTANT("CONDITION", BL_MASK_DEAF); + SET_CONSTANT("CONDITION", BL_MASK_ELF_IRON); + SET_CONSTANT("CONDITION", BL_MASK_FLY); + SET_CONSTANT("CONDITION", BL_MASK_FOODPOIS); + SET_CONSTANT("CONDITION", BL_MASK_GLOWHANDS); + SET_CONSTANT("CONDITION", BL_MASK_GRAB); + SET_CONSTANT("CONDITION", BL_MASK_HALLU); + SET_CONSTANT("CONDITION", BL_MASK_HELD); + SET_CONSTANT("CONDITION", BL_MASK_ICY); + SET_CONSTANT("CONDITION", BL_MASK_INLAVA); + SET_CONSTANT("CONDITION", BL_MASK_LEV); + SET_CONSTANT("CONDITION", BL_MASK_PARLYZ); + SET_CONSTANT("CONDITION", BL_MASK_RIDE); + SET_CONSTANT("CONDITION", BL_MASK_SLEEPING); + SET_CONSTANT("CONDITION", BL_MASK_SLIME); + SET_CONSTANT("CONDITION", BL_MASK_SLIPPERY); + SET_CONSTANT("CONDITION", BL_MASK_STONE); + SET_CONSTANT("CONDITION", BL_MASK_STRNGL); + SET_CONSTANT("CONDITION", BL_MASK_STUN); + SET_CONSTANT("CONDITION", BL_MASK_SUBMERGED); + SET_CONSTANT("CONDITION", BL_MASK_TERMILL); + SET_CONSTANT("CONDITION", BL_MASK_TETHERED); + SET_CONSTANT("CONDITION", BL_MASK_TRAPPED); + SET_CONSTANT("CONDITION", BL_MASK_UNCONSC); + SET_CONSTANT("CONDITION", BL_MASK_WOUNDEDL); + SET_CONSTANT("CONDITION", BL_MASK_HOLDING); + + // menu + SET_CONSTANT("MENU_SELECT", PICK_NONE); + SET_CONSTANT("MENU_SELECT", PICK_ONE); + SET_CONSTANT("MENU_SELECT", PICK_ANY); + + // 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_CONSTANT_STRING("COPYRIGHT", COPYRIGHT_BANNER_D); + + // glyphs + SET_CONSTANT("GLYPH", GLYPH_MON_OFF); + SET_CONSTANT("GLYPH", GLYPH_PET_OFF); + SET_CONSTANT("GLYPH", GLYPH_INVIS_OFF); + SET_CONSTANT("GLYPH", GLYPH_DETECT_OFF); + SET_CONSTANT("GLYPH", GLYPH_BODY_OFF); + SET_CONSTANT("GLYPH", GLYPH_RIDDEN_OFF); + SET_CONSTANT("GLYPH", GLYPH_OBJ_OFF); + SET_CONSTANT("GLYPH", GLYPH_CMAP_OFF); + SET_CONSTANT("GLYPH", GLYPH_EXPLODE_OFF); + SET_CONSTANT("GLYPH", GLYPH_ZAP_OFF); + SET_CONSTANT("GLYPH", GLYPH_SWALLOW_OFF); + SET_CONSTANT("GLYPH", GLYPH_WARNING_OFF); + SET_CONSTANT("GLYPH", GLYPH_STATUE_OFF); + SET_CONSTANT("GLYPH", GLYPH_UNEXPLORED_OFF); + SET_CONSTANT("GLYPH", GLYPH_NOTHING_OFF); + SET_CONSTANT("GLYPH", MAX_GLYPH); + SET_CONSTANT("GLYPH", NO_GLYPH); + SET_CONSTANT("GLYPH", GLYPH_INVISIBLE); + SET_CONSTANT("GLYPH", GLYPH_UNEXPLORED); + SET_CONSTANT("GLYPH", GLYPH_NOTHING); + + // colors + SET_CONSTANT("COLORS", CLR_BLACK); + SET_CONSTANT("COLORS", CLR_RED); + SET_CONSTANT("COLORS", CLR_GREEN); + SET_CONSTANT("COLORS", CLR_BROWN); + SET_CONSTANT("COLORS", CLR_BLUE); + SET_CONSTANT("COLORS", CLR_MAGENTA); + SET_CONSTANT("COLORS", CLR_CYAN); + SET_CONSTANT("COLORS", CLR_GRAY); + SET_CONSTANT("COLORS", NO_COLOR); + SET_CONSTANT("COLORS", CLR_ORANGE); + SET_CONSTANT("COLORS", CLR_BRIGHT_GREEN); + SET_CONSTANT("COLORS", CLR_YELLOW); + SET_CONSTANT("COLORS", CLR_BRIGHT_BLUE); + SET_CONSTANT("COLORS", CLR_BRIGHT_MAGENTA); + SET_CONSTANT("COLORS", CLR_BRIGHT_CYAN); + SET_CONSTANT("COLORS", CLR_WHITE); + SET_CONSTANT("COLORS", CLR_MAX); + + // color attributes (?) + SET_CONSTANT("COLOR_ATTR", HL_ATTCLR_DIM); + SET_CONSTANT("COLOR_ATTR", HL_ATTCLR_BLINK); + SET_CONSTANT("COLOR_ATTR", HL_ATTCLR_ULINE); + SET_CONSTANT("COLOR_ATTR", HL_ATTCLR_INVERSE); + SET_CONSTANT("COLOR_ATTR", HL_ATTCLR_BOLD); + SET_CONSTANT("COLOR_ATTR", BL_ATTCLR_MAX); +} + +/*** + * Globals + ***/ +#define CREATE_GLOBAL(var, type) create_global(#var, (void *)&var, type); +#define CREATE_GLOBAL_FROM_ARRAY(base, iter, path, end_expr, type) \ + for(iter = 0; end_expr; iter++) { \ + snprintf(buf, BUFSZ, #base ".%d." #path, iter); \ + create_global(buf, (void *)(&(base[iter].path)), type); \ + } + +void create_global (char *name, void *ptr, char *type); + +void js_globals_init() { + // int i; + // char buf[BUFSZ]; + + EM_ASM({ + globalThis.nethackGlobal = globalThis.nethackGlobal || {}; + globalThis.nethackGlobal.globals = globalThis.nethackGlobal.globals || {}; + }); + + /* globals */ + CREATE_GLOBAL(g.plname, "s"); + + /* window globals */ + CREATE_GLOBAL(WIN_MAP, "i"); + CREATE_GLOBAL(WIN_MESSAGE, "i"); + CREATE_GLOBAL(WIN_INVEN, "i"); + CREATE_GLOBAL(WIN_STATUS, "i"); +} + +EM_JS(void, create_global, (char *name_str, void *ptr, char *type_str), { + let name = UTF8ToString(name_str); + let type = UTF8ToString(type_str); + + // get helpers + let getPointerValue = globalThis.nethackGlobal.helpers.getPointerValue; + let setPointerValue = globalThis.nethackGlobal.helpers.setPointerValue; + + let { obj, prop } = createPath(globalThis.nethackGlobal.globals, name); + + // setters / getters with bound pointers + Object.defineProperty(obj, prop, { + get: getPointerValue.bind(null, name, ptr, type), + set: setPointerValue.bind(null, name, ptr, type), + configurable: true, + enumerable: true + }); + + function createPath(obj, path) { + path = path.split("."); + let i; + for (i = 0; i < path.length - 1; i++) { + // obj[path[i]] = obj[path[i]] || {}; + if (obj[path[i]] === undefined) { + obj[path[i]] = {}; + } + obj = obj[path[i]]; + } + + return { obj, prop: path[i] }; + } +}) + +#endif + +/*libnhmain.c*/ diff --git a/sys/libnh/sysconf b/sys/libnh/sysconf new file mode 100644 index 000000000..2e1b66e12 --- /dev/null +++ b/sys/libnh/sysconf @@ -0,0 +1,151 @@ +# NetHack 3.7 sysconf $NHDT-Date: 1596498296 2020/08/03 23:44:56 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.39 $ +# Copyright (c) 2015 by Kenneth Lorber, Kensington, Maryland +# NetHack may be freely redistributed. See license for details. +# +# Sample sysconf file. +# The sysconf file is only used if NetHack is compiled with SYSCF defined. +# It can be used to augment or override certain settings compiled into the +# program. +# +# This file can also be used to set local system defaults for run-time +# options, using the same syntax as an individual user's ./nethackrc file. + +# Which users can use debug mode (aka wizard mode; accessed via '-D' command +# line flag or OPTIONS=playmode:debug in the runtime options config file). +# A value of * allows anyone to enter debugging mode. +WIZARDS=root games + +# Which users can use explore mode (aka discover mode; accessed via '-X' +# command line flag or OPTIONS=playmode:explore in runtime options file or +# via '#exploremode' command during normal play). Same syntax as WIZARDS. +EXPLORERS=* + +# Users allowed to use the '!' (shell escape) and '^Z' (suspend process) +# commands to temporarily leave the game and enter a shell process. +# (To resume play, use the shell command 'exit' (for most shells) to +# return from '!' or the shell command 'fg' to return from '^Z'. +# For the typical multi-user system where players have access to a shell +# prompt when logged in and run the game from their own username, a value +# of 'SHELLERS=*' is appropriate. However, some inexperienced players +# occasionally get stuck outside the game by accidentally typing '!' or +# '^Z' during play and not knowing how to go back.) +# Uses the same syntax as the WIZARDS and EXPLORERS options above. +#SHELLERS= + +# 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. +# ["ec2-user" is the default user name on Amazon Linux] +GENERICUSERS=play player game games nethack nethacker ec2-user + +# Use the player name for matching WIZARDS, EXPLORERS and SHELLERS, +# instead of the user's login name. +#CHECK_PLNAME=1 + +# Limit the number of simultaneous games (see also nethack.sh). +# Valid values are 0-25. +# Commenting this out or setting the value to 0 constructs lock files +# with UID and playername, so each user may have one game at a time, +# but number of different players is not limited. +# Setting this to any other value constructs the lock files with +# letter and "lock" (eg. alock, block, ...) +MAXPLAYERS=10 + +# If not null, added to string "To get local support, " in the support +# information help. +#SUPPORT=call Izchak at extension 42. + +# If not null, displayed at the end of a panic-save sequence. +#RECOVER=Run the recover program. + +# Uncomment the next line to disable the SEDUCE option, causing succubi and +# incubi to use nymphs' charm behavior rather than their own seduce behavior. +#SEDUCE=0 + +# Uncomment the next line to enable some accessibility features such +# as S_hero_override and S_pet_override symbols for screen readers +# in the user config file. +#ACCESSIBILITY=1 + +# Uncomment to disable savefile UID checking. +#CHECK_SAVE_UID=0 + +# Record (high score) file options. +# CAUTION: changing these after people have started playing games can +# lead to lost high scores! +# Maximum entries for one person. +#PERSMAX=10 +# Maximum entries in the record file. +#ENTRYMAX=100 +# Minimum points to get an entry. +#POINTSMIN=1 +# Determine identity of "person" in the score file with name (0) or +# numeric (1) user id. +#PERS_IS_UID=1 + +# Maximum number of score file entries to use for random statue names +#MAX_STATUENAME_RANK=10 + +# 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, and can be +# overridden via DEBUGFILES environment variable. +#DEBUGFILES=* + +# Save end of game dump log to this file. +# Only available if NetHack was compiled with DUMPLOG +# Allows following placeholders: +# %% literal '%' +# %v version (eg. "3.7.0-0") +# %u game UID +# %t game start time, UNIX timestamp format +# %T current time, UNIX timestamp format +# %d game start time, YYYYMMDDhhmmss format +# %D current time, YYYYMMDDhhmmss format +# %n player name +# %N first character of player name +#DUMPLOGFILE=/tmp/nethack.%n.%d.log + +# Number of bones file pools. +# The pool you belong to is determined at game start. You will +# load and save bones only from that pool. Generally useful +# for public servers only. +# Changing this might make existing bones inaccessible. +# Disabled by setting to 0, or commenting out. +#BONES_POOLS=10 + +# Try to get more info in case of a program bug or crash. Only used +# if the program is built with the PANICTRACE compile-time option enabled. +# By default PANICTRACE is enabled if (NH_DEVEL_STATUS != NH_STATUS_RELEASED), +# otherwise disabled. +# Using GDB can get more information and works on more systems but requires +# 'gdb' be available; using LIBC only works if NetHack is linked with a +# libc that supports the backtrace(3) API. Both require certain compilation +# options. See src/end.c and sys/unix/hints/* for more information. +#GDBPATH=/usr/bin/gdb +#GREPPATH=/bin/grep +# Values are priorities: 0 - do not use this method, 1 - low priority, +# 2 - high priority. Non-zero priority methods are tried in order. +PANICTRACE_GDB=0 +PANICTRACE_LIBC=0 + +# 'portable_device_paths' is only supported for Windows. Starting with +# 3.6.3, nethack on Windows treats the folder containing nethack.exe and +# nethackW.exe as read-only and puts data files which are generated or +# modified during play or by the user in assorted folders derived from +# user name. 3.6.4 added PORTABLE_DEVICE_PATHS to allow reverting to +# the old behavior of having the run-time configuration file and other +# data in the same directory as the executable so that the whole thing +# can be moved from one machine to another (flash drive or perhaps cloud) +# without updating folder paths. +#PORTABLE_DEVICE_PATHS=0 + +# Ordinary run-time options can be set here to override the builtin-in +# default values. Unlike all the SYSCF values above, individual users +# can override the overridden options set here by choosing their own +# option settings via NETHACKOPTIONS in their environment or via +# ~/.nethackrc run-time configuration file. +#OPTIONS=!autopickup,fruit:tomato,symset:DECgraphics +OPTIONS=perm_invent + +#eof diff --git a/sys/libnh/test/README.md b/sys/libnh/test/README.md new file mode 100644 index 000000000..c9cfed377 --- /dev/null +++ b/sys/libnh/test/README.md @@ -0,0 +1,8 @@ +Development helpers and tests for libnethack.a and nethack.js. + +Copy these files to the NetHack root directory. Commands include: +* run.sh wasm - rebuild makefiles and build nethack.js +* run.sh runwasm - simple testing of nethack.js +* run.sh lib - rebuild makefiles and build libnethack.a +* run.sh runlib - simple testing of libnethack.a +* run.sh bin - build the MacOS binary \ No newline at end of file diff --git a/sys/libnh/test/libtest.c b/sys/libnh/test/libtest.c new file mode 100644 index 000000000..31ca10e71 --- /dev/null +++ b/sys/libnh/test/libtest.c @@ -0,0 +1,115 @@ +#include +#include + +/* external functions */ +int nhmain(int argc, char *argv[]); +typedef void(*stub_callback_t)(const char *name, void *ret_ptr, const char *fmt, ...); +void shim_graphics_set_callback(stub_callback_t cb); + +/* forward declarations */ +void window_cb(const char *name, void *ret_ptr, const char *fmt, ...); +void *yourFunctionToRenderGraphics(const char *name, va_list args); + +int main(int argc, char *argv[]) { + shim_graphics_set_callback(window_cb); + nhmain(argc, argv); +} + +void *yourFunctionToRenderGraphics(const char *name, va_list args) { + printf("yourFunctionToRenderGraphics name %s\n", name); + /* DO SOMETHING HERE */ + return NULL; +} + +void window_cb(const char *name, void *ret_ptr, const char *fmt, ...) { + void *ret; + va_list args; + /* TODO -- see windowCallback below for hints */ + va_start(args, fmt); + + ret = yourFunctionToRenderGraphics(name, args); + // *((int *)ret_ptr = *((int *)ret); // e.g. yourFunctionToRenderGraphics returns an int + + va_end(args); +} + +#if 0 +function variadicCallback(name, retPtr, fmt, args) { + // console.log ("variadicCallback called..."); + // console.log("typeof name", typeof name); + // console.log("typeof fmt", typeof fmt); + // console.log("typeof args", typeof args); + name = Module.UTF8ToString(name); + fmt = Module.UTF8ToString(fmt); + // console.log ("name:", name); + // console.log ("fmt:", fmt); + let argTypes = fmt.split(""); + let retType = argTypes.shift(); + // console.log ("arg count:", argTypes.length); + // console.log ("arg types:", argTypes); + // console.log ("ret type:", retType); + + let jsArgs = []; + for (let i = 0; i < argTypes.length; i++) { + let ptr = args + (4*i); + let val = typeLookup(argTypes[i], ptr); + jsArgs.push(val); + } + console.log(`graphics callback: ${name} [${jsArgs}]`); + setReturn(retPtr, retType); +} + +function setReturn(ptr, type, value = 0) { + switch (type) { + case "p": + throw new Error("not implemented"); + case "s": + value=value?value:"(no value)"; + var strPtr = Module.getValue(ptr, "i32"); + Module.stringToUTF8(value, strPtr, 1024); + break; + case "i": + Module.setValue(ptr, value, "i32"); + break; + case "c": + Module.setValue(ptr, value, "i8"); // 'Z' + break; + case "f": + // XXX: I'm not sure why 'double' works and 'float' doesn't + Module.setValue(ptr, value, "double"); + break; + case "d": + Module.setValue(ptr, value, "double"); + break; + case "v": + break; + default: + throw new Error("unknown type"); + } +} + +function typeLookup(type, ptr) { + switch(type) { + case "s": // string + return Module.UTF8ToString(Module.getValue(ptr, "*")); + case "p": // pointer + return Module.getValue(Module.getValue(ptr, "*"), "*"); + case "c": // char + return String.fromCharCode(Module.getValue(Module.getValue(ptr, "*"), "i8")); + case "0": /* 2^0 = 1 byte */ + return Module.getValue(Module.getValue(ptr, "*"), "i8"); + case "1": /* 2^1 = 2 bytes */ + return Module.getValue(Module.getValue(ptr, "*"), "i16"); + case "2": /* 2^2 = 4 bytes */ + case "i": // integer + case "n": // number + return Module.getValue(Module.getValue(ptr, "*"), "i32"); + case "f": // float + return Module.getValue(Module.getValue(ptr, "*"), "float"); + case "d": // double + return Module.getValue(Module.getValue(ptr, "*"), "double"); + default: + throw new TypeError ("unknown type:" + type); + } +} +#endif /* 0 */ \ No newline at end of file diff --git a/sys/libnh/test/run.sh b/sys/libnh/test/run.sh new file mode 100755 index 000000000..e930684c4 --- /dev/null +++ b/sys/libnh/test/run.sh @@ -0,0 +1,45 @@ +#!/bin/bash -x + +if [ x$1 == "xlib" ]; then + echo Doing lib... + if [ -f Makefile ]; then + make spotless + fi + cd sys/unix + ./setup.sh hints/macOS.2020 + cd ../.. + make WANT_LIBNH=1 +fi + +if [ x$1 == "xrunlib" ]; then + LIBS="-Lsrc -lnethack -Llib/lua -llua -lm" + BADLIBS="-lncurses" + rm nhlibtest + gcc -o nhlibtest libtest.c $LIBS $BADLIBS + ./nhlibtest +fi + +if [ x$1 == "xwasm" ]; then + echo Doing wasm... + if [ -f Makefile ]; then + make spotless + fi + cd sys/unix + ./setup.sh hints/macOS.2020 + cd ../.. + make CROSS_TO_WASM=1 +fi + +if [ x$1 == "xrunwasm" ]; then + cd sys/lib/npm-package && npm run build && node test/test.js +fi + +if [ x$1 == "xbin" ]; then + echo Doing bin... + make spotless + cd sys/unix + ./setup.sh hints/macOS.2020 + cd ../.. + make +fi + diff --git a/sys/msdos/Install.dos b/sys/msdos/Install.dos index b3ac0abd7..bf981f734 100644 --- a/sys/msdos/Install.dos +++ b/sys/msdos/Install.dos @@ -1,30 +1,25 @@ - Copyright (c) NetHack PC Development Team 1990-2002. + Copyright (c) NetHack PC Development Team 1990-2020. NetHack may be freely redistributed. See license for details. ============================================================== Instructions for compiling and installing - NetHack 3.6 on a DOS system + NetHack 3.7 on a DOS system ====================================================== - (or, How to make PC NetHack 3.6) - Last revision: $NHDT-Date: 1432512791 2015/05/25 00:13:11 $ + (or, How to make PC NetHack 3.7) + Last revision: $NHDT-Date: 1596508786 2020/08/04 02:39:46 $ -Credit for a runnable full PC NetHack 3.6 goes to the PC Development team -of Paul Winner, Kevin Smolkowski, Michael Allison, Yitzhak Sapir, Bill Dyer, -Timo Hakulinen, Yamamoto Keizo, Mike Threepoint, Mike Stephenson, +Credit for a runnable full PC NetHack 3.7 goes to the PC Development team +of Paul Winner, Kevin Smolkowski, Michael Allison, Yitzhak Sapir, Bill Dyer, +Timo Hakulinen, Yamamoto Keizo, Mike Threepoint, Mike Stephenson, Stephen White, Ken Washikita and Janet Walz. The present port is based on the previous effort of Pierre Martineau, Stephen Spackman, Steve Creps, Mike Threepoint, Mike Stephenson, Norm Meluch and Don Kneller. -There has been very little port-specific maintenance for NetHack on DOS since -NetHack 3.3.0. - CONTENTS: - I. Dispelling the Myths - II. Compiling on a DOS machine - Appendix A - Building the "official binary" - Appendix B - DJGPP Compiler (gcc ported to msdos) notes - Appendix C - Additional Notes + I. Dispelling the Myths + II. Compiling on Linux or macOS via cross-compiler + Appendix A - Additional Notes Appendix D - Contacting Us I. Dispelling the Myths: @@ -33,233 +28,86 @@ I. Dispelling the Myths: however it will behoove you to read this entire file through before beginning the task. - We have provided a proper Makefile for building NetHack using the - following compilers: - djgpp V2.03 or later - For specific details concerning the djgpp compiler, please see the - appendix B. +II. There once was a time when people built NetHack right on their DOS machine. + The arcane recipe often involved flat cylinders known as "floppy disks", + much gnashing of teeth, squeezing large things into small spaces, and + required the sacrifice of copious amounts of time and coffee. - The makefile named Makefile.GCC is for use with GNU Make that - accompanies djgpp. + These days, to compile your copy of NetHack on Linux or macOS machine using + Andrew Wu's djgpp cross-compiler from: + https://github.com/andrewwutw/build-djgpp + downloaded from: + https://github.com/andrewwutw/build-djgpp/releases/download/v3.0/ + a DOS-extender (for including in msdos packaging) from: + http://sandmann.dotster.com/cwsdpmi/csdpmi7b.zip + and pdcurses from: + https://github.com/wmcbrine/PDCurses.git + and Lua from: + http://www.lua.org/ftp/lua-5.4.1.tar.gz - If you want to build a copy of NetHack that is identical to the - "official binary", please see appendix A. + - A shell 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 - The unsupported sys/msdos/Makefile.MSC was for the old 16 bit - Microsoft Visual C 1.52c compiler and has not been made compliant - with 3.5.x. + That script won't install anything, it just does file fetches and stores + them in subfolders of lib. The linux.2020 and macOS.2020 hints files are + configured to find the cross-compiler there if you add + CROSS_TO_MSDOS=1 + on your make command line. - You may find it useful to obtain copies of lex (flex) and yacc (bison - or byacc). While not strictly necessary to compile nethack, they are - required should you desire to make any changes to the level and dungeon - compilers. Flex and Bison are included with the DJGPP distribution and - are also available on many archive sites. + Note: Both the fetch-cross-compiler.sh script and and the msdos + cross-compile and package procedures require unzip and zip to be available + on your host build system. - Also be sure to pick up djgpp v2gnu/fil41b.zip to get ls.exe and - touch.exe, since the Makefile uses them by default. + On your linux host: -II. To compile your copy of NetHack on a DOS machine: - (or "just follow these few 'simple' steps outlined below.") + cd sys/unix ; sh setup.sh hints/linux.2020 ; cd ../.. + make fetch-lua -1. It almost goes without saying that you should make sure that your tools - are set up and running correctly. + On your macOS host: -2. Make sure all the NetHack files are in the appropriate directory - structure. You should have a main directory with subdirectories - dat, doc, include, src, sys\share, sys\msdos, util, win\tty and - win\share. Other subdirectories may also be included in your - distribution, but they are not necessary for use with DOS. You can - delete them to save space. + cd sys/unix ; sh setup.sh hints/macOS.2020 ; cd ../.. + make fetch-lua - Required Source Directories for DOS NetHack: + The MSDOS cross-compile can then be carried out by specifying + CROSS_TO_MSDOS=1 on the make command line: - (top) - | - ------------------------------------------------- - | | | | | | | - util dat doc include src sys win - | | - ------ ----- - | | | | - share msdos tty share + make CROSS_TO_MSDOS=1 all + make CROSS_TO_MSDOS=1 package - Check the file "Files" in your top level directory for an exact - listing of what files are in which directory. In order for the - Makefiles to work, all the source files must be in the proper - locations. + You can explicitly include tty and curses support if desired. The default + you'll end up with is a tty-only cross-compile build: - If you downloaded or ftp'd the sources from a UNIX system, the lines - will probably end in UNIX-style newlines, instead of the carriage - return and line feed pairs used by DOS. Some programs have trouble - with them, so you may need to convert them (with a utility like - Rahul Dhesi's "flip"). + make WANT_WIN_TTY=1 WANT_WIN_CURSES=1 CROSS_TO_MSDOS=1 all + make WANT_WIN_TTY=1 WANT_WIN_CURSES=1 CROSS_TO_MSDOS=1 package -3. Go to the sys/msdos directory and ensure that the file setup.bat - has MSDOS style end-of-line characters rather than UNIX style - end-of-line characters. You can do that using a utility like - Rahul Dhesi's "flip", or by invoking the MSDOS edit utility on - setup.bat and saving the file without making any changes. Failure to - do this will prevent the bat file from executing completely, yet no - warning message will be given. + Result: The "make package" target will bundle all of the necessary + components to run NetHack on msdos into a folder: + targets/msdos/pkg + and then it zips the contents of that folder into: + targets/msdos/nh370dos.zip - Run the setup.bat batch file with the following as the argument: + Also note that building the msdos targets using the make command + above, does not preclude you from building local linux or macOS + targets as well. Just drop the CROSS_TO_MSDOS=1 from the make + command line. That's because the cross-compiler hints additions are + enclosed inside ifdef sections and won't interfere with the + non-cross-compile build in that case. - GCC For djgpp and GNU MAKE. +Appendix A - Additional Notes - The appropriate and necessary Makefile movement will be accomplished - for you, as well as verifying a few files and fixing a few file names - on FAT systems with long file name support. - -4. Now go to the include subdirectory to check a couple of the header - files there. Things *should* work as they are, but since you have - probably set up your system in some sort of custom configuration - it doesn't hurt to check out the following: - - First check config.h according to the comments to match your system and - desired set of features. Mostly you need to check the WIZARD option, - and check TERMLIB and COMPRESS. Also be sure to leave DLB support - commented out in config.h. MSDOS has support for DLB, but it must be - done through the Makefile, rather than config.h, to ensure that the - necessary packaging steps are done. - - We've managed to enable all the special features. You may include all - or as few of them as you wish. To conserve disk space, you may wish - to disable LOGFILE and NEWS. - - Also check pcconf.h, which should not need much editing (if you are - including random.c, and if you do not require termcap for screen - management). If you are not including random.c you will need to - comment out RANDOM. - - If using DJGPP, you can choose between SCREEN_BIOS - and SCREEN_DJGPPFAST. Never, never, ever choose both. Bad things - will happen. We are not kidding. - -5. If you want to change the high score list behavior, examine the top of - topten.c, in the src directory. You may want to change the definitions of - PERSMAX, POINTSMIN, and ENTRYMAX. We set POINTSMIN to 51 and ENTRYMAX to - 50 to keep the size of the score list down. - -6. Go to the src directory and edit the top of your Makefile. Be sure the - directory you want the game installed in (GAMEDIR) actually exists. - -7. Now that everything is set up, - - Go to the src directory, and using the GNU Make utility, - "make install". - - Depending on your particular machine and compiler, you can either - grab a cup of coffee or go home for the day. Your computer will be - occupied for quite some time. If all goes well, you will get an - NetHack executable. - -9. If you chose DLB support (recommended), make sure that the file nhdat - got copied into the game directory. - - If you didn't choose DLB support, make sure the support files -- - data, rumors, cmdhelp, opthelp, help, hh,history, guidebook.txt - license, and all the *.lev files -- were copied to the game directory. - If not, move them there from the dat directory yourself. rumors can - be created manually be entering "makedefs -r", data by entering - "makedefs -d". - - Make sure the files NetHack1.tib and NetHacko.tib made it to your game - directory. Copy them from src to the game directory yourself if - necessary. - - Make sure the files defaults.nh and termcap made it to your game - directory. If not, go to sys\share and copy NetHack.cnf to - your game directory as defaults.nh. The name in previous versions was - nethack.cnf, but the CNF extension conflicted with the MS Windows - speed-dialer, making the file hidden on many machines. - - If you changed your build settings to include TERMCAP support, copy - termcap to your game directory. - - Also, make sure the file msdoshlp.txt made it to your game directory. - If it didn't, move it from sys\msdos to your game directory - yourself. - -10. In your game directory, review the settings in defaults.nh and adjust +1. In your game directory, review the settings in defaults.nh and adjust them according to your style of play. -11. Play NetHack. If it works, you're done! - -Appendix A - Building the "official binary" - - If you wish to build a copy of NetHack identical to the one that - the pc team distributes, simply do the following: - - The 32-bit Protected Mode DPMI version built with 32-bit djgpp - compiler V2.03 or greater, make no changes to any of the defines and use - the Makefile.GCC as distributed, and as moved in step 3. - - Paths below are relative to the top of your unpacked - NetHack source distribution: - - md \nethack\binary (must match Makefile) - cd sys\msdos - setup GCC - cd ..\..\src - make install - - - Make sure the following files have been converted from the - unix style "^J" end of line, to the msdos style "^M^J": - license, defaults.nh. - - Place all the files in a clean directory and test. - -Appendix B - DJGPP Compiler (gcc ported to msdos) - - If you have a 386 or better machine, you are in luck. You can compile - NetHack without spending money on a compiler. DJGPP is available free - from many archive sites. - At the time of this release in April 2002, the URL - http://www.delorie.com/djgpp/zip-picker.html/ - had information on how to obtain djgpp and what pieces to get. - Be sure to pick up djgpp v2gnu/fil41b.zip to get ls.exe and - touch.exe, since the Makefile uses them by default (or change - the Makefile to use alternatives). - - Special note for Windows 2000 / Windows XP users: You must have a - recent djgpp distribution for the build process, and the generated - executables to work properly on those platforms. - - Setting up DJGPP is more than adequately explained in the documentation - that comes with it. Be sure to pick up the yacc and flex built with - DJGPP if you intend to do any modification of the special levels or - dungeon compilers. They should be available at the same place you got - djgpp. - - The latest version of djgpp, V2.03 with the most recent refresh - will produce a binary that will run under Microsoft Windows, or any - other DPMI provider. djgpp also comes with a DPMI provider called CWSDPMI. - Place CWSDPMI.EXE in your path and it will be used in the absence of any - other DPMI provider. - - If you want to use the built-in DJGPP screen routines, uncomment - SCREEN_DJGPPFAST in pcconf.h (the default for djgpp). - -Appendix C - Additional Notes - -1) Save files and bones files from versions of NetHack prior to 3.5.0 will not - work with this NetHack. Don't bother trying to keep them. - -2) To install an update of NetHack after changing something, type 'make' - for DJGPP from the src directory. If you add, delete, or reorder monsters or - objects, or you change the format of saved level files, delete any save - and bones files. (Trying to use such files sometimes produces amusing - confusions on the game's part, but usually crashes.) - +2. Play NetHack. If it works, you're done! Appendix D - Contacting the Development Team If you discover a bug and wish to report it, or if you have comments or suggestions we recommend using our "Contact Us" web page at: - http://www.nethack.org/common/contact.html + https://www.nethack.org/common/contact.html If you don't have access to the web, or you want to send us a patch to the NetHack source code feel free to drop us a line c/o: diff --git a/sys/msdos/Makefile.GCC b/sys/msdos/Makefile.GCC index 57e1f0c93..f1d3f7e6f 100644 --- a/sys/msdos/Makefile.GCC +++ b/sys/msdos/Makefile.GCC @@ -1,6 +1,6 @@ -# NetHack 3.6 Makefile.GCC $NHDT-Date: 1594155873 2020/07/07 21:04:33 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.51 $ +# NetHack 3.7 Makefile.GCC $NHDT-Date: 1596498268 2020/08/03 23:44:28 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.53 $ # Copyright (c) NetHack PC Development Team 1996-2019. -# PC NetHack 3.6 Makefile for djgpp V2 +# PC NetHack 3.7 Makefile for djgpp V2 # # Gnu gcc compiler for msdos (djgpp) # Requires Gnu Make utility (V3.79.1 or greater) supplied with djgpp @@ -42,13 +42,13 @@ PDCURSES_TOP=../../pdcurses ifeq "$(LUA_VERSION)" "5.3.5" LUAVER=5.3.5 else -LUAVER=5.4.0 +LUAVER=5.4.2 endif #--------------------------------------------------------------- # Location of LUA # # Original source needs to be obtained from: -# http://www.lua.org/ftp/lua-5.4.0.tar.gz +# http://www.lua.org/ftp/lua-5.4.2.tar.gz # # This build assumes that the LUA sources are located # at the specified location. If they are actually elsewhere @@ -273,7 +273,7 @@ VOBJ16 = $(O)role.o $(O)rumors.o $(O)save.o $(O)sfstruct.o $(O)shk.o VOBJ17 = $(O)shknam.o $(O)sit.o $(O)sounds.o $(O)sp_lev.o $(O)spell.o VOBJ18 = $(O)steal.o $(O)steed.o $(O)symbols.o $(O)sys.o $(O)termcap.o VOBJ19 = $(O)timeout.o $(O)topl.o $(O)topten.o $(O)track.o $(O)trap.o -VOBJ20 = $(O)u_init.o $(O)uhitm.o $(O)vault.o $(O)vision.o $(O)vis_tab.o +VOBJ20 = $(O)u_init.o $(O)uhitm.o $(O)vault.o $(O)vision.o VOBJ21 = $(O)weapon.o $(O)were.o $(O)wield.o $(O)windows.o $(O)wintty.o VOBJ22 = $(O)wizard.o $(O)worm.o $(O)worn.o $(O)write.o $(O)zap.o VOBJ23 = $(O)light.o $(O)dlb.o $(O)dig.o $(O)teleport.o $(O)region.o @@ -305,7 +305,7 @@ ALLOBJ = $(VOBJ) $(SOBJ) $(TILOBJ) $(TILOBJ2) $(VVOBJ) #===============-================================================= # LUA library -# Source from http://www.lua.org/ftp/lua-5.4.0.tar.gz +# Source from http://www.lua.org/ftp/lua-5.4.2.tar.gz #================================================================= LUASRC = $(LUATOP)/src @@ -400,7 +400,7 @@ HACK_H = $(CONFIG_H) $(INCL)/context.h $(DUNGEON_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)/trampoli.h $(INCL)/hack.h $(REGION_H) \ + $(INCL)/hack.h $(REGION_H) \ $(INCL)/sys.h DLB_H = $(INCL)/dlb.h @@ -548,7 +548,7 @@ default: $(GAMEFILE) util: $(O)utility.tag $(O)utility.tag: $(INCL)/date.h $(INCL)/trap.h $(INCL)/onames.h \ - $(INCL)/pm.h vis_tab.c $(TILEUTIL) + $(INCL)/pm.h $(TILEUTIL) $(subst /,\,echo utilities made > $@) tileutil: $(U)gif2txt.exe $(U)txt2ppm.exe @@ -653,12 +653,6 @@ $(INCL)/onames.h: $(U)makedefs.exe $(INCL)/pm.h: $(U)makedefs.exe -$(subst /,\,$(U)makedefs -p) -$(INCL)/vis_tab.h: $(U)makedefs.exe - -$(subst /,\,$(U)makedefs -z) - -vis_tab.c: $(U)makedefs.exe - -$(subst /,\,$(U)makedefs -z) - #========================================== # Makedefs Stuff #========================================== @@ -913,12 +907,10 @@ spotless: clean $(subst /,\,if exist $(U)til2bin2.exe del $(U)til2bin2.exe) $(subst /,\,if exist $(U)thintile.exe del $(U)thintile.exe) $(subst /,\,if exist $(U)dlb_main.exe del $(U)dlb_main.exe) - $(subst /,\,if exist $(INCL)/vis_tab.h del $(INCL)/vis_tab.h) $(subst /,\,if exist $(INCL)/onames.h del $(INCL)/onames.h) $(subst /,\,if exist $(INCL)/pm.h del $(INCL)/pm.h) $(subst /,\,if exist $(INCL)/date.h del $(INCL)/date.h) $(subst /,\,if exist $(SRC)/monstr.c del $(SRC)/monstr.c) - $(subst /,\,if exist $(SRC)/vis_tab.c del $(SRC)/vis_tab.c) $(subst /,\,if exist $(SRC)/tile.c del $(SRC)/tile.c) $(subst /,\,if exist $(DAT)/options del $(DAT)/options) $(subst /,\,if exist $(DAT)/data del $(DAT)/data) @@ -996,11 +988,9 @@ spotless: clean $(subst /,\,if exist $(U)til2bin2.exe del $(U)til2bin2.exe) $(subst /,\,if exist $(U)thintile.exe del $(U)thintile.exe) $(subst /,\,if exist $(U)dlb_main.exe del $(U)dlb_main.exe) - $(subst /,\,if exist $(INCL)/vis_tab.h del $(INCL)/vis_tab.h) $(subst /,\,if exist $(INCL)/onames.h del $(INCL)/onames.h) $(subst /,\,if exist $(INCL)/pm.h del $(INCL)/pm.h) $(subst /,\,if exist $(INCL)/date.h del $(INCL)/date.h) - $(subst /,\,if exist $(SRC)/vis_tab.c del $(SRC)/vis_tab.c) $(subst /,\,if exist $(SRC)/tile.c del $(SRC)/tile.c) $(subst /,\,if exist $(DAT)/options del $(DAT)/options) $(subst /,\,if exist $(DAT)/data del $(DAT)/data) @@ -1218,7 +1208,6 @@ $(O)qt_clust.o: ../win/Qt/qt_clust.cpp $(INCL)/qt_clust.h $(O)qttableview.o: ../win/Qt/qttableview.cpp $(INCL)/qttableview.h $(CXX) $(CXXFLAGS) -o$@ ../win/Qt/qttableview.cpp $(O)monstr.o: monstr.c $(CONFIG_H) -$(O)vis_tab.o: vis_tab.c $(CONFIG_H) $(INCL)/vis_tab.h $(O)allmain.o: allmain.c $(HACK_H) $(O)alloc.o: alloc.c $(CONFIG_H) $(O)apply.o: apply.c $(HACK_H) @@ -1325,7 +1314,7 @@ $(O)u_init.o: u_init.c $(HACK_H) $(O)uhitm.o: uhitm.c $(HACK_H) $(O)vault.o: vault.c $(HACK_H) $(O)version.o: version.c $(HACK_H) $(INCL)/date.h -$(O)vision.o: vision.c $(HACK_H) $(INCL)/vis_tab.h +$(O)vision.o: vision.c $(HACK_H) $(O)weapon.o: weapon.c $(HACK_H) $(O)were.o: were.c $(HACK_H) $(O)wield.o: wield.c $(HACK_H) diff --git a/sys/msdos/Makefile1.cross b/sys/msdos/Makefile1.cross deleted file mode 100644 index ae7e3fe19..000000000 --- a/sys/msdos/Makefile1.cross +++ /dev/null @@ -1,639 +0,0 @@ -# NetHack 3.7 Makefile1.cross -# Cross-compile msdos version of NetHack using a -# linux-hosted djgpp cross-compiler. -# -# Makefile1.cross (this file) is for the host-side obj files and -# utilities that will run on the host platform only. -# -# Makefile2.cross is for the target platform obj files -# and utilities. -# -# Makefile2 utilizes the djgpp cross-compiler from Andrew Wu: -# https://github.com/andrewwutw/build-djgpp -# -# Currently, in NetHack 3.7, it is now feasible to cross-compile -# the game in a 2-stage process. Makefile1.cross (this file) carries -# out the 1st stage. -# -# The GNU Make has a problem if you include a drive spec below. -GAMEDIR =../msdos-binary - -# -#============================================================================== -# This marks the end of the BUILD DECISIONS section. -#============================================================================== -# -# Directories, gcc likes unix style directory specs -# - -OBJ = o -HOBJ = host_o -DAT = ../dat -DOC = ../doc -INCL = ../include -LIB = ../lib -MSYS = ../sys/msdos -SRC = ../src -SSHR = ../sys/share -UTIL = ../util -WIN = ../win/tty -WCURSES = ../win/curses -WSHR = ../win/share - -# -# Executables. -# -HOST_CC = gcc -HOST_LINK = gcc -MAKEBIN = make - -# -# Special libraries and how to link them in. -# -LIBS = -lpc -LIBRARIES = $(LIBS) - -# -# Yacc/Lex off -# -YACC_LEX = N - -# -# Uncomment the line below if you want to store all the level files, -# help files, etc. in a single library file. -# -USE_DLB = Y - -#=============================================== -#======= End of Modification Section =========== -#=============================================== -################################################ -# # -# Nothing below here should have to be changed.# -# # -################################################ - -# Changing this conditional block is not recommended -ifeq "$(USE_DLB)" "Y" -DLBFLG = -DDLB -else -DLBFLG = -endif - -TERMLIB = - -#========================================== -#================ MACROS ================== -#========================================== -# This section creates shorthand macros for many objects -# referenced later on in the Makefile. -# -# Have windows path styles available for use in commands -# -W_OBJ =$(subst /,\, $(OBJ)) -W_INCL =$(subst /,\, $(INCL)) -W_DAT =$(subst /,\, $(DAT)) -W_DOC =$(subst /,\, $(DOC)) -W_UTIL =$(subst /,\, $(UTIL)) -W_SRC =$(subst /,\, $(SRC)) -W_SSYS =$(subst /,\, $(SSYS)) -W_MSWSYS =$(subst /,\, $(MSWSYS)) -W_TTY =$(subst /,\, $(TTY)) -W_MSWIN =$(subst /,\, $(MSWIN)) -ifeq "$(ADD_CURSES)" "Y" -W_WCURSES =$(subst /,\, $(WCURSES)) -endif -W_WSHR =$(subst /,\, $(WSHR)) -W_GAMEDIR =$(subst /,\, $(GAMEDIR)) - -# -# Shorten up the location for some files -# - -O = $(OBJ)/ -HOST_O = $(HOBJ)/ -U = $(UTIL)/ - -#========================================== -# Utility Objects. -#========================================== - -MAKESRC = makedefs.c - -MAKEDEFSOBJS = $(HOST_O)makedefs.o $(HOST_O)monst.o $(HOST_O)objects.o - -LUA_QTEXT_FILE = "quest.lua" - -#========================================== -# Tile related object files. -#========================================== - -TILOBJ2 = $(HOST_O)tileset.o $(HOST_O)bmptiles.o $(HOST_O)giftiles.o - -TEXTIO = $(HOST_O)tiletext.o $(HOST_O)tiletxt.o $(HOST_O)drawing.o $(HOST_O)monst.o \ - $(HOST_O)objects.o - -TEXTIO2 = $(HOST_O)tiletex2.o $(HOST_O)tiletxt2.o $(HOST_O)drawing.o $(HOST_O)monst.o \ - $(HOST_O)objects.o - -TILE_BMP = $(DAT)/NHTILES.BMP - -TILEUTIL = $(TILE_BMP) - -TILEFILES = $(WSHR)/monsters.txt $(WSHR)/objects.txt $(WSHR)/other.txt - -TILEFILES2 = $(WSHR)/monthin.txt $(WSHR)/objthin.txt $(WSHR)/oththin.txt - -GIFREADERS = $(HOST_O)gifread.o $(HOST_O)alloc.o $(HOST_O)panic.o - -GIFREAD2 = $(HOST_O)gifread2.o $(HOST_O)alloc.o $(HOST_O)panic.o - -PPMWRITERS = $(HOST_O)ppmwrite.o $(HOST_O)alloc.o $(HOST_O)panic.o - -PPMWRIT2 = $(HOST_O)ppmwrit2.o $(HOST_O)alloc.o $(HOST_O)panic.o - -#========================================== -# Object files. -#========================================== - -DLBOBJ = $(HOST_O)dlb.o - -ALLOBJ = $(MAKEDEFSOBJS) $(TILOBJ) $(TILOBJ2) $(TEXTIO) $(TEXTIO2) - -#========================================== -# Header file macros -#========================================== - -PATCHLEV_H = $(INCL)/patchlev.h -DGN_FILE_H = $(INCL)/align.h $(INCL)/dgn_file.h -DUNGEON_H = $(INCL)/align.h $(INCL)/dungeon.h -MONDATA_H = $(INCL)/align.h $(INCL)/mondata.h -MONST_H = $(INCL)/align.h $(INCL)/monst.h $(INCL)/mextra.h -PERMONST_H = $(INCL)/monattk.h $(INCL)/monflag.h $(INCL)/align.h \ - $(INCL)/permonst.h -REGION_H = $(INCL)/region.h -RM_H = $(INCL)/align.h $(INCL)/rm.h -SKILLS_H = $(INCL)/skills.h -SP_LEV_H = $(INCL)/align.h $(INCL)/sp_lev.h -YOUPROP_H = $(PERMONST_H) $(MONDATA_H) $(INCL)/prop.h \ - $(INCL)/pm.h $(INCL)/youprop.h -YOU_H = $(MONST_H) $(YOUPROP_H) $(INCL)/align.h \ - $(INCL)/attrib.h $(INCL)/you.h -DISPLAY_H = $(MONDATA_H) $(INCL)/vision.h $(INCL)/display.h -PCCONF_H = $(INCL)/micro.h $(INCL)/system.h $(INCL)/pcconf.h \ - $(MSYS)/pcvideo.h -DECL_H = $(YOU_H) $(INCL)/spell.h $(INCL)/color.h \ - $(INCL)/obj.h $(INCL)/onames.h $(INCL)/pm.h \ - $(INCL)/decl.h -GLOBAL_H = $(PCCONF_H) $(INCL)/coord.h $(INCL)/global.h - -CONFIG_H = $(INCL)/config.h $(INCL)/config1.h $(INCL)/tradstdc.h \ - $(INCL)/global.h $(INCL)/coord.h $(INCL)/vmsconf.h \ - $(INCL)/system.h $(INCL)/nhlua.h $(INCL)/unixconf.h \ - $(INCL)/micro.h $(INCL)/pcconf.h $(INCL)/ntconf.h - -HACK_H = $(INCL)/hack.h $(CONFIG_H) $(INCL)/lint.h $(INCL)/align.h \ - $(INCL)/dungeon.h $(INCL)/monsym.h $(INCL)/mkroom.h \ - $(INCL)/objclass.h $(INCL)/youprop.h $(INCL)/prop.h \ - $(INCL)/permonst.h $(INCL)/monattk.h \ - $(INCL)/monflag.h $(INCL)/mondata.h $(INCL)/pm.h \ - $(INCL)/wintype.h $(INCL)/context.h $(INCL)/rm.h \ - $(INCL)/botl.h $(INCL)/rect.h \ - $(INCL)/region.h $(INCL)/decl.h $(INCL)/quest.h \ - $(INCL)/spell.h $(INCL)/color.h $(INCL)/obj.h \ - $(INCL)/you.h $(INCL)/attrib.h $(INCL)/monst.h \ - $(INCL)/mextra.h $(INCL)/skills.h $(INCL)/onames.h \ - $(INCL)/timeout.h $(INCL)/trap.h $(INCL)/flag.h \ - $(INCL)/vision.h $(INCL)/display.h $(INCL)/engrave.h \ - $(INCL)/winprocs.h $(INCL)/sys.h $(INCL)/wintty.h \ - $(INCL)/trampoli.h - -DLB_H = $(INCL)/dlb.h - -ifeq ($(SUPPRESS_GRAPHICS),Y) -TILE_H = -else -TILE_H = $(WSHR)/tile.h $(INCL)/tileset.h -endif - -ifeq ($(USE_DLB),Y) -DLB = dlb -DLBOBJS = $(HOST_O)dlb_main.o $(HOST_O)dlb.o $(HOST_O)alloc.o $(HOST_O)panic.o -else -DLB = -DLBOBJS = -endif - -#========================================== -# More compiler setup macros -#========================================== -# -CURSESDEF= -CURSESLIB= -INCLDIR=-I../include -I../sys/msdos -# Debugging -#cflags = -pg -c $(INCLDIR) $(DLBFLG) $(CURSESDEF) -DSUPPRESS_GRAPHICS -DCROSSCOMPILE -CROSSCOMPILE_HOST -#LFLAGS = -pg -# -#cflags = -c -O $(INCLDIR) $(DLBFLG) $(CURSESDEF) -DSUPPRESS_GRAPHICS -DCROSSCOMPILE -DCROSSCOMPILE_HOST -#LFLAGS = -# -# Debugging -#cflags = -g -c $(INCLDIR) $(DLBFLG) $(CURSESDEF) -DUSE_TILES -DCROSSCOMPILE -DCROSSCOMPILE_HOST -#LFLAGS = -g -# -# Normal -cflags = -c -O $(INCLDIR) $(DLBFLG) $(CURSESDEF) -DUSE_TILES -DCROSSCOMPILE -DCROSSCOMPILE_HOST -LFLAGS = - -#========================================== -#================ RULES ================== -#========================================== - -.SUFFIXES: .o .til .uu .c .y .l - -#========================================== -# Rules for host files in src -#========================================== - -$(HOST_O)%.o : $(SRC)/%.c - $(HOST_CC) $(cflags) -o$@ $< - -#========================================== -# Rules for host files in sys/msdos -#========================================== - -$(HOST_O)%.o : $(MSYS)/%.c - $(HOST_CC) $(cflags) -I../sys/msdos -o$@ $< - -#========================================== -# Rules for host files in util -#========================================== - -$(HOST_O)%.o : $(SRC)/%.c - $(HOST_CC) $(cflags) -o$@ $< - -$(HOST_O)%.o : $(UTIL)/%.c - $(HOST_CC) $(cflags) -o$@ $< - -$(HOST_O)%.o : %.c - $(HOST_CC) $(cflags) -o$@ $< - -#========================================== -# Rules for host files in win/share -#========================================== - -$(HOST_O)%.o : $(WSHR)/%.c - $(HOST_CC) $(cflags) -I../win/share -o$@ $< - -#========================================== -# Primary Targets. -#========================================== - -# The default target. - -all : prereq - -prereq: $(HOST_O)prereq.tag - @echo Done. - -default: prereq - -util: $(HOST_O)utility.tag - -$(HOST_O)utility.tag: $(INCL)/date.h $(INCL)/trap.h $(INCL)/onames.h \ - $(INCL)/pm.h vis_tab.c $(TILEUTIL) $(SRC)/tile.c - echo host utilities made > $@ - -tileutil: $(U)gif2txt $(U)txt2ppm - @echo Optional tile development utilities are up to date. - -$(HOST_O)prereq.tag: $(INCL)/nhlua.h hobj.tag $(U)makedefs \ - $(HOST_O)utility.tag $(DAT)/nhdat - echo prereq done >$@ - -ifeq "$(LUA_VERSION)" "5.3.5" -LUAVER=5.3.5 -else -LUAVER=5.4.0 -endif - -$(INCL)/nhlua.h: - cd $(INCL); \ - echo '/* nhlua.h - generated by Makefile1.cross */' > $@; \ - echo '#include "../lib/lua-$(LUAVER)/src/lua.h"' >> $@; \ - sed -e '/(lua_error)/!d' -e '/(lua_error)/s/;/ NORETURN;/1' < $(LIB)/lua-$(LUAVER)/src/lua.h >> $@; \ - echo '#include "../lib/lua-$(LUAVER)/src/lualib.h"' >> $@; \ - echo '#include "../lib/lua-$(LUAVER)/src/lauxlib.h"' >> $@; \ - echo '/*nhlua.h*/' >> $@; \ - cd $(SRC) - -#========================================== -# Other host targets. -#========================================== - -#note that dir below assumes bin/dir from djgpp distribution -# -$(DAT)/nhdat: $(U)dlb_main $(DAT)/data $(DAT)/rumors \ - $(DAT)/oracles \ - $(DAT)/bogusmon $(DAT)/engrave $(DAT)/epitaph $(DAT)/tribute - cd $(DAT); \ - pwd; \ - cp $(MSYS)/msdoshlp.txt .; \ - ls -1 data oracles options rumors help hh >dlb.lst; \ - ls -1 cmdhelp history opthelp wizhelp license >>dlb.lst; \ - ls -1 bogusmon engrave epitaph tribute msdoshlp.txt >>dlb.lst; \ - ls -1 *.lua >>dlb.lst; \ - $(U)dlb_main cvIf dlb.lst nhdat; \ - cd $(SRC) - -$(U)dlb_main: $(DLBOBJS) - $(HOST_LINK) $(LFLAGS) -o$@ $(DLBOBJS) - -$(HOST_O)dlb_main.o: $(U)dlb_main.c $(INCL)/config.h $(DLB_H) - $(HOST_CC) $(cflags) -o$@ $(U)dlb_main.c - - -$(INCL)/date.h : $(U)makedefs - -$(U)makedefs -v - -$(INCL)/onames.h: $(U)makedefs - -$(U)makedefs -o - -$(INCL)/pm.h: $(U)makedefs - -$(U)makedefs -p - -#monstr.c: $(U)makedefs -# -$(U)makedefs -m - -$(INCL)/vis_tab.h: $(U)makedefs - -$(U)makedefs -z - -vis_tab.c: $(U)makedefs - -$(U)makedefs -z - -# make data.base an 8.3 filename to prevent an make warning -DATABASE = $(DAT)/data.bas - -$(DAT)/data: $(HOST_O)utility.tag $(DATABASE) - $(U)makedefs -d - -$(DAT)/rumors: $(HOST_O)utility.tag $(DAT)/rumors.tru $(DAT)/rumors.fal - $(U)makedefs -r - -$(DAT)/oracles: $(HOST_O)utility.tag $(DAT)/oracles.txt - $(U)makedefs -h - -$(DAT)/bogusmon: $(HOST_O)utility.tag $(DAT)/bogusmon.txt - $(U)makedefs -s - -$(DAT)/engrave: $(HOST_O)utility.tag $(DAT)/engrave.txt - $(U)makedefs -s - -$(DAT)/epitaph: $(HOST_O)utility.tag $(DAT)/epitaph.txt - $(U)makedefs -s - -#=============================================== -# Create directory for holding host object files -#=============================================== - -hobj.tag: - mkdir -p ./$(HOBJ) - echo directory ready ./$(HOBJ) - -#========================================== -# Makedefs Stuff -#========================================== - -$(U)makedefs: $(MAKEDEFSOBJS) - $(HOST_LINK) $(LFLAGS) -o$@ $(MAKEDEFSOBJS) - -$(HOST_O)makedefs.o: $(U)makedefs.c $(SRC)/mdlib.c $(CONFIG_H) $(INCL)/permonst.h \ - $(INCL)/objclass.h $(INCL)/monsym.h \ - $(INCL)/artilist.h $(INCL)/dungeon.h $(INCL)/obj.h \ - $(INCL)/monst.h $(INCL)/you.h $(INCL)/flag.h \ - $(INCL)/dlb.h $(INCL)/patchlevel.h - -#============================================= -# Header file moves required for tile support -#============================================= - -ifeq ($(SUPPRESS_GRAPHICS),Y) - -else -# -# Tile Mapping -# - -$(SRC)/tile.c: $(U)tilemap - @$(U)tilemap - @echo A new $@ has been created - -$(U)tilemap: $(HOST_O)tilemap.o - $(HOST_LINK) $(LFLAGS) -o$@ $(HOST_O)tilemap.o - -$(HOST_O)tilemap.o: $(WSHR)/tilemap.c $(HACK_H) $(TILE_H) - $(HOST_CC) $(cflags) -I$(WSHR) -I$(MSYS) -DSTATUES_LOOK_LIKE_MONSTERS -o$@ $(WSHR)/tilemap.c - - -#========================================== -# Tile Utilities -# Required for tile support -#========================================== - -#$(DAT)/NetHack1.tib: $(TILEFILES) $(U)tile2bin -# @echo Creating binary tile files -# cd $(DAT) -# $(U)tile2bin -# cd $(SRC) - -#$(DAT)/NetHacko.tib: $(HOST_O)thintile.tag $(TILEFILES2) $(U)til2bin2 -# @echo Creating overview binary tile files -# cd $(DAT) -# $(U)til2bin2 -# cd $(SRC) - -$(DAT)/NHTILES.BMP: $(TILEFILES) $(U)tile2bmp - @echo Creating binary tile files which may take some time - @cd $(DAT) - @$(U)tile2bmp $@ - @cd $(SRC) - -$(U)tile2bmp: $(HOST_O)tile2bmp.o $(TEXTIO) - -rm -f temp.a - ar r temp.a $(TEXTIO) - $(HOST_LINK) $(LFLAGS) -o$@ $(HOST_O)tile2bmp.o temp.a - -#$(U)tile2bin: $(HOST_O)tile2bin.o $(TEXTIO) -# -rm -f temp.a -# ar r temp.a $(TEXTIO) -# $(HOST_LINK) $(LFLAGS) -o$@ $(HOST_O)tile2bin.o temp.a - -#$(U)til2bin2: $(HOST_O)til2bin2.o $(TEXTIO2) -# -rm -f temp.a -# ar r temp.a $(TEXTIO2) -# $(HOST_LINK) $(LFLAGS) -o$@ $(HOST_O)til2bin2.o temp.a - -#$(U)thintile: $(HOST_O)thintile.o -# $(HOST_LINK) $(LFLAGS) -o$@ $(HOST_O)thintile.o - -#$(HOST_O)thintile.o: $(HACK_H) $(WSHR)/tile.h $(WSHR)/thintile.c -# -rm -f temp.a -# ar r temp.a $(TEXTIO) -# $(HOST_LINK) $(LFLAGS) -o$@ $(HOST_O)tile2bmp.o temp.a - -#$(HOST_O)thintile.o: $(HACK_H) $(WSHR)/tile.h $(WSHR)/thintile.c -# $(HOST_CC) $(cflags) -I$(MSYS) -I$(WSHR) -DTILE -DOVERVIEW_FILE -o$@ $(WSHR)/thintile.c - -#$(HOST_O)thintile.tag: $(U)thintile $(TILEFILES) -# $(U)thintile -# echo thintiles created >$@ - -$(HOST_O)tile2bmp.o: $(HACK_H) $(TILE_H) $(WSHR)/tile2bmp.c - $(HOST_CC) $(cflags) -I$(MSYS) -I$(WSHR) -o$@ $(WSHR)/tile2bmp.c - -#$(HOST_O)tile2bin.o: $(HACK_H) $(TILE_H) $(MSYS)/pctiles.h $(MSYS)/pcvideo.h $(MSYS)/tile2bin.c -# $(HOST_CC) $(cflags) -I$(MSYS) -I$(WSHR) -o$@ $(MSYS)/tile2bin.c - -#$(HOST_O)til2bin2.o: $(HACK_H) $(TILE_H) $(MSYS)/pctiles.h $(MSYS)/pcvideo.h $(MSYS)/tile2bin.c -# $(HOST_CC) $(cflags) -I$(MSYS) -I$(WSHR) -DTILE_X=8 -DOVERVIEW_FILE -o$@ $(MSYS)/tile2bin.c - -$(HOST_O)tiletext.o: $(CONFIG_H) $(TILE_H) $(WSHR)/tiletext.c - $(HOST_CC) $(cflags) -I$(MSYS) -I$(WSHR) -o$@ $(WSHR)/tiletext.c - -$(HOST_O)tiletex2.o: $(CONFIG_H) $(TILE_H) $(WSHR)/tiletext.c - $(HOST_CC) $(cflags) -I$(MSYS) -I$(WSHR) -DTILE_X=8 -o$@ $(WSHR)/tiletext.c - -$(HOST_O)tiletxt.o: $(CONFIG_H) $(TILE_H) $(WSHR)/tilemap.c - $(HOST_CC) $(cflags) -I$(MSYS) -I$(WSHR) -DTILETEXT -o$@ $(WSHR)/tilemap.c - -$(HOST_O)tiletxt2.o: $(CONFIG_H) $(TILE_H) $(WSHR)/tilemap.c - $(HOST_CC) $(cflags) -I$(MSYS) -I$(WSHR) -DTILETEXT -DTILE_X=8 -o$@ $(WSHR)/tilemap.c -# -# Optional GIF Utilities (for development) -# - -$(U)gif2txt: $(GIFREADERS) $(TEXTIO) - $(HOST_LINK) $(LFLAGS) -o$@ $(GIFREADERS) $(TEXTIO) - -$(U)gif2txt2: $(GIFREAD2) $(TEXTIO2) - $(HOST_LINK) $(LFLAGS) -o$@ $(GIFREAD2) $(TEXTIO2) - -$(U)txt2ppm: $(PPMWRITERS) $(TEXTIO) - $(HOST_LINK) $(LFLAGS) -o$@ $(PPMWRITERS) $(TEXTIO) - -$(U)txt2ppm2: $(PPMWRIT2) $(TEXTIO2) - $(HOST_LINK) $(LFLAGS) -o$@ $(PPMWRIT2) $(TEXTIO2) - -$(HOST_O)gifread.o: $(CONFIG_H) $(WSHR)/tile.h $(WSHR)/gifread.c - -$(HOST_O)gifread2.o: $(CONFIG_H) $(WSHR)/tile.h $(WSHR)/gifread.c - $(HOST_CC) $(cflags) -DTILE_X=8 -o$@ $(WSHR)/gifread.c - -ppmwrite.c: $(WSHR)/ppmwrite.c - cp $(WSHR)/ppmwrite.c . - -$(HOST_O)ppmwrite.o: $(CONFIG_H) $(WSHR)/tile.h - -$(HOST_O)ppmwrit2.o: $(CONFIG_H) $(WSHR)/tile.h ppmwrite.c - $(HOST_CC) $(cflags) -DTILE_X=8 -o$@ ppmwrite.c - -# -# Optional tile viewer (development sources only) -# - -$(U)viewtib: $(HOST_O)viewtib.o - $(HOST_LINK) $(LFLAGS) -o$@ $(HOST_O)viewtib.o $(LIBRARIES) - -$(HOST_O)viewtib.o: $(MSYS)/viewtib.c - -endif - -#========================================== -# Other host Util Dependencies. -#========================================== - -$(HOST_O)monst.o: $(CONFIG_H) $(PERMONST_H) $(INCL)/monsym.h \ - $(INCL)/color.h monst.c - $(HOST_CC) $(cflags) -o$@ monst.c - -$(HOST_O)objects.o: $(CONFIG_H) $(INCL)/obj.h $(INCL)/objclass.h \ - $(INCL)/prop.h $(INCL)/color.h objects.c - $(HOST_CC) $(cflags) -o$@ objects.c - -$(HOST_O)panic.o: $(CONFIG_H) $(U)panic.c - $(HOST_CC) $(cflags) -o$@ $(U)panic.c - -#========================================== -# Housekeeping for host side. -#========================================== - -clean: - rm ./host_o/*.o - if [ -f $(HOST_O)prereq.tag ]; then rm $(HOST_O)prereq.tag; fi; - if [ -f hobj.tag ]; then rm hobj.tag; fi; - if [ -f $(HOST_O)utility.tag ]; then rm $(HOST_O)utility.tag; fi; - if [ -f temp.a ]; then rm temp.a; fi; - -spotless: clean - - if [ -f $(INCL)/pm.h ]; then rm $(INCL)/pm.h; fi; -## if [ -f $(U)dgn_flex.c ]; then rm $(U)dgn_flex.c; fi; -## if [ -f $(U)dgn_lex.c ]; then rm $(U)dgn_lex.c; fi; -# if [ -f $(U)makedefs ]; then rm $(U)makedefs; fi; -## if [ -f $(U)dgn_comp ]; then rm $(U)dgn_comp; fi; -# if [ -f $(U)recover.exe ]; then rm $(U)recover.exe; fi; -# if [ -f $(U)tilemap ]; then rm $(U)tilemap; fi; -# if [ -f $(U)tile2bmp ]; then rm $(U)tile2bmp; fi; -## if [ -f $(U)tile2bin ]; then rm $(U)tile2bin; fi; -## if [ -f $(U)til2bin2 ]; then rm $(U)til2bin2; fi; -## if [ -f $(U)thintile ]; then rm $(U)thintile; fi; -# if [ -f $(U)dlb_main ]; then rm $(U)dlb_main; fi; -# if [ -f $(INCL)/vis_tab.h ]; then rm $(INCL)/vis_tab.h; fi; -# if [ -f $(INCL)/onames.h ]; then rm $(INCL)/onames.h; fi; -# if [ -f $(INCL)/pm.h ]; then rm $(INCL)/pm.h; fi; -# if [ -f $(INCL)/date.h ]; then rm $(INCL)/date.h; fi; -## if [ -f $(INCL)/dgn_comp.h ]; then rm $(INCL)/dgn_comp.h; fi; -## if [ -f $(INCL)/lev_comp.h ]; then rm $(INCL)/lev_comp.h; fi; -# if [ -f $(SRC)/vis_tab.c ]; then rm $(SRC)/vis_tab.c; fi; -# if [ -f $(SRC)/tile.c ]; then rm $(SRC)/tile.c; fi; -# if [ -f $(DAT)/options ]; then rm $(DAT)/options; fi; -# if [ -f $(DAT)/data ]; then rm $(DAT)/data; fi; -# if [ -f $(DAT)/rumors ]; then rm $(DAT)/rumors; fi; -## if [ -f $(DAT)/dungeon.pdf ]; then rm $(DAT)/dungeon.pdf; fi; -## if [ -f $(DAT)/dungeon ]; then rm $(DAT)/dungeon; fi; -# if [ -f $(DAT)/oracles ]; then rm $(DAT)/oracles; fi; -## if [ -f $(DAT)/quest.dat ]; then rm $(DAT)/quest.dat; fi; -# if [ -f $(DAT)/bogusmon ]; then rm $(DAT)/bogusmon; fi; -# if [ -f $(DAT)/engrave ]; then rm $(DAT)/engrave; fi; -# if [ -f $(DAT)/epitaph ]; then rm $(DAT)/epitaph; fi; -# if [ -f $(DAT)/dlb.lst ]; then rm $(DAT)/dlb.lst; fi; -# if [ -f $(DAT)/nhdat ]; then rm $(DAT)/nhdat; fi; -# if [ -f $(DAT)/*.lev ]; then rm $(DAT)/*.lev; fi; -# if [ -f $(TILE_BMP) ]; then rm $(TILE_BMP); fi; -# if [ -f $(WSHR)/monthin.txt ]; then rm $(WSHR)/monthin.txt; fi; -# if [ -f $(WSHR)/objthin.txt ]; then rm $(WSHR)/objthin.txt; fi; -# if [ -f $(WSHR)/oththin.txt ]; then rm $(WSHR)/oththin.txt; fi; - -#========================================== -# Host Utility Dependencies -#========================================== - -# src dependencies - -$(HOST_O)drawing.o: $(CONFIG_H) -$(HOST_O)vis_tab.o: vis_tab.c $(CONFIG_H) $(INCL)/vis_tab.h -$(HOST_O)alloc.o: alloc.c $(CONFIG_H) -$(HOST_O)dlb.o: dlb.c $(CONFIG_H) $(INCL)/dlb.h - $(HOST_CC) $(cflags) -I../sys/msdos -o$@ dlb.c -$(HOST_O)monst.o: monst.c $(CONFIG_H) $(INCL)/permonst.h $(INCL)/align.h \ - $(INCL)/monattk.h $(INCL)/monflag.h $(INCL)/monsym.h \ - $(INCL)/color.h -$(HOST_O)objects.o: objects.c $(CONFIG_H) $(INCL)/obj.h $(INCL)/objclass.h \ - $(INCL)/prop.h $(INCL)/skills.h $(INCL)/color.h -$(HOST_O)tileset.o: $(WSHR)/tileset.c $(HACK_H) -$(HOST_O)bmptiles.o: $(WSHR)/bmptiles.c $(INCL)/config.h $(INCL)/tileset.h $(INCL)/integer.h -$(HOST_O)giftiles.o: $(WSHR)/giftiles.c $(INCL)/config.h $(INCL)/tileset.h $(INCL)/integer.h - -# end of file - diff --git a/sys/msdos/Makefile2.cross b/sys/msdos/Makefile2.cross deleted file mode 100644 index ac1b12a35..000000000 --- a/sys/msdos/Makefile2.cross +++ /dev/null @@ -1,1145 +0,0 @@ -# NetHack 3.7 Makefile2.cross -# Cross-compile msdos version of NetHack using a -# linux-hosted djgpp cross-compiler. -# -# Makefile1.cross is for the host-side obj files and utilities that -# will run on the host platform only. -# -# Makefile2.cross (this file) is for the target platform obj files -# and utilities. -# -# Makefile2 utilizes the djgpp cross-compiler from Andrew Wu: -# https://github.com/andrewwutw/build-djgpp -# -# Currently, in NetHack 3.7, it is now feasible to cross-compile -# the game in a 2-stage process. Makefile2.cross (this file) carries -# out the 2nd stage. -# -# A proof-of-concept to cross-compile NetHack 3.7 was achieved on -# November 22, 2019 using the msdos set of Makefiles. -# -# - -# Game Installation Variables -# NOTE: Make sure GAMEDIR exists before make is started. - -GAME = NETHACK -# The GNU Make has a problem if you include a drive spec below (unfortunately). -GAMEDIR =../msdos-binary - -# Optional PDCurses support -# Uncomment these and set them appropriately if you want to -# include curses port support alongside TTY support in your -# NetHack.exe binary. -# -# You'll have to set PDCURSES_H to the correct location of the -# PDCurses header (.h) files and PDCURSES_C to the location -# of your PDCurses C files which must already be resident on -# your machine. -# -ADD_CURSES=Y -PDCURSES_TOP=../lib/pdcurses - -# Set top of djgpp if not specified through ENV variables prior to make: -#DJGPP_TOP = $(HOME)/lib/djgpp - -#--------------------------------------------------------------- -ifeq "$(LUA_VERSION)" "5.3.5" -LUAVER=5.3.5 -else -LUAVER=5.4.0 -endif -#--------------------------------------------------------------- -# Location of LUA -# -# Original source needs to be obtained from: -# http://www.lua.org/ftp/lua-5.4.0.tar.gz -# -# This build assumes that the LUA sources are located -# at the specified location. If they are actually elsewhere -# you'll need to specify the correct spot below in order to -# successfully build NetHack-3.7. -# -ADD_LUA=Y -LUATOP=../lib/lua-$(LUAVER) -# -# -#============================================================================== -# This marks the end of the BUILD DECISIONS section. -#============================================================================== -# -# Directories, gcc likes unix style directory specs -# - -TARGET = msdos -OBJ = $(TARGET)_o -HOBJ = host_o -DAT = ../dat -DOC = ../doc -INCL = ../include -LIB = ../lib -MSYS = ../sys/msdos -SRC = ../src -SSHR = ../sys/share -UTIL = ../util -WIN = ../win/tty -WCURSES = ../win/curses -WSHR = ../win/share - -# -# Executables. -ifndef DJGPP_TOP -ifdef TRAVIS_BUILD_DIR -DJGPP_TOP = TRAVIS_BUILD_DIR/lib/djgpp -else -DJGPP_TOP = $(HOME)/lib/djgpp -endif -endif - -TARGET_CC = $(DJGPP_TOP)/i586-pc-msdosdjgpp/bin/gcc -TARGET_LINK = $(DJGPP_TOP)/i586-pc-msdosdjgpp/bin/gcc -TARGET_STUBEDIT = $(DJGPP_TOP)/i586-pc-msdosdjgpp/bin/stubedit -TARGET_AR = $(DJGPP_TOP)/i586-pc-msdosdjgpp/bin/ar -MAKEBIN = make - -# -# Special libraries and how to link them in. - -LIBS = -lpc - -# If TERMLIB is defined in pcconf.h, comment out the upper line and -# uncomment the lower. Note that you must build the termc library -# and place it in djgpp's lib directory. See termcap.zip for details - -TERMLIB = -#TERMLIB = -ltermc - -LIBRARIES = $(LIBS) $(TERMLIB) - -# -# Yacc/Lex ... if you got 'em. -# -# If you have yacc/lex or a work-alike set YACC_LEX to Y -# -YACC_LEX = N - -ifeq "$(YACC_LEX)" "Y" -DO_YACC = YACC_ACT -DO_LEX = LEX_ACT -endif - -# If YACC_LEX is Y above, set the following to values appropriate for -# your tools. -# -YACC = bison -y -LEX = lex -# -# If your flex and bison port mess with the output names directly -# you must set the file names to the appropriate output file names -# here -#YTABC = y_tab.c -#YTABH = y_tab.h -#LEXYYC = lexyy.c -# -# If your flex and bison are able to produce files named -# y.tab.c, y.tab.h or lex.yy.c you might have to set these -# to the short file name equivalent (DIR /X to reveal them): -YTABC = ytab~1.c -YTABH = ytab~1.h -LEXYYC = lexyy~1.c - -# -# Uncomment the line below if you want to store all the level files, -# help files, etc. in a single library file. - -USE_DLB = Y - -# djgpp includes ls.exe and touch.exe in fil41b.zip from the v2gnu -# folder so be sure to include that when downloading djgpp. Doing -# so will make changing this unnecessary. - -LS = ls -1 # ls.exe from djgpp distribution -#LS = dir /l/b # DOS command - -# To build a binary without any graphics -# suitable for blind players, -# set SUPPRESS_GRAPHICS to Y -# (Note: binary will require ANSI.SYS driver or equivalent loaded) -# SUPPRESS_GRAPHICS = Y -SUPPRESS_GRAPHICS = - -# ZLIB Support -# To support zlib compression in bones and save files, you must -# define ZLIB_COMP in include/config.h. -# You must also have a zlib library to link NetHack with, and -# for the djgpp build, you need one compatible with djgpp. -# At the time that this was written (post-NetHack 3.4.3) the -# following URL was a valid place to get a pre-built djgpp library -# to add to your djgpp tools directory tree. -# http://www.delorie.com/pub/djgpp/current/v2tk/zlib114b.zip -# -# If you defined ZLIB_COMP in include/config.h to build in support -# for ZLIB compression, you need to uncomment the line below. -#ZLIB= -lz - -#=============================================== -#======= End of Modification Section =========== -#=============================================== -################################################ -# # -# Nothing below here should have to be changed.# -# # -################################################ - -GAMEFILE = $(GAMEDIR)/$(GAME).EXE - -# Changing this conditional block is not recommended -ifeq "$(USE_DLB)" "Y" -DLBFLG = -DDLB -else -DLBFLG = -endif - -TERMLIB = -# Build NetHack suitable for blind players - -#========================================== -#================ MACROS ================== -#========================================== -# This section creates shorthand macros for many objects -# referenced later on in the Makefile. -# -# Have windows path styles available for use in commands -# -W_OBJ =$(subst /,\, $(OBJ)) -W_INCL =$(subst /,\, $(INCL)) -W_DAT =$(subst /,\, $(DAT)) -W_DOC =$(subst /,\, $(DOC)) -W_UTIL =$(subst /,\, $(UTIL)) -W_SRC =$(subst /,\, $(SRC)) -W_SSYS =$(subst /,\, $(SSYS)) -W_MSWSYS =$(subst /,\, $(MSWSYS)) -W_TTY =$(subst /,\, $(TTY)) -W_MSWIN =$(subst /,\, $(MSWIN)) -ifeq "$(ADD_CURSES)" "Y" -W_WCURSES =$(subst /,\, $(WCURSES)) -endif -W_WSHR =$(subst /,\, $(WSHR)) -W_GAMEDIR =$(subst /,\, $(GAMEDIR)) - -# -# Shorten up the location for some files -# - -O = $(OBJ)/ -HOST_O = $(HOBJ)/ -U = $(UTIL)/ - -#========================================== -# Tile related object files. -#========================================== - -PLANAR_TIB = $(DAT)/NETHACK1.tib -OVERVIEW_TIB = $(DAT)/NETHACKO.tib -TILE_BMP = $(DAT)/NHTILES.BMP - -##REGEX = $(O)pmatchregex.o -##REGEX = $(O)cppregex.o -REGEX = $(O)posixreg.o -DLBOBJ = $(O)dlb.o -VIDEO_OBJ = $(O)vidvga.o $(O)vidvesa.o $(O)tile.o $(O)tileset.o $(O)bmptiles.o $(O)giftiles.o -RECOVOBJS = $(O)recover.o - -# Object files for the game itself. - -VOBJ01 = $(O)allmain.o $(O)alloc.o $(O)apply.o $(O)artifact.o -VOBJ02 = $(O)attrib.o $(O)ball.o $(O)bones.o $(O)botl.o -VOBJ03 = $(O)cmd.o $(O)dbridge.o $(O)decl.o $(O)detect.o -VOBJ04 = $(O)display.o $(O)dlb.o $(O)dig.o $(O)do.o -VOBJ05 = $(O)do_name.o $(O)do_wear.o $(O)dog.o $(O)dogmove.o -VOBJ06 = $(O)dokick.o $(O)dothrow.o $(O)drawing.o $(O)dungeon.o -VOBJ07 = $(O)eat.o $(O)end.o $(O)engrave.o $(O)exper.o -VOBJ08 = $(O)explode.o $(O)extralev.o $(O)files.o $(O)fountain.o -VOBJ09 = $(O)getline.o $(O)hack.o $(O)hacklib.o $(O)insight.o -VOBJ10 = $(O)invent.o $(O)isaac64.o $(O)light.o $(O)lock.o -VOBJ11 = $(O)mail.o $(O)main.o $(O)makemon.o $(O)mapglyph.o -VOBJ12 = $(O)mcastu.o $(O)mhitm.o $(O)mhitu.o $(O)minion.o -VOBJ13 = $(O)mkmap.o $(O)mklev.o $(O)mkmaze.o $(O)mkobj.o -VOBJ14 = $(O)mkroom.o $(O)mon.o $(O)mondata.o $(O)monmove.o -VOBJ15 = $(O)monst.o $(O)mplayer.o $(O)mthrowu.o $(O)muse.o -VOBJ16 = $(O)music.o $(O)o_init.o $(O)objects.o $(O)objnam.o -VOBJ17 = $(O)options.o $(O)pickup.o $(O)pline.o $(O)polyself.o -VOBJ18 = $(O)potion.o $(O)quest.o $(O)questpgr.o $(O)pager.o -VOBJ19 = $(O)pray.o $(O)priest.o $(O)read.o $(O)rect.o -VOBJ20 = $(O)region.o $(O)restore.o $(O)rip.o $(O)rnd.o -VOBJ21 = $(O)role.o $(O)rumors.o $(O)save.o $(O)sfstruct.o -VOBJ22 = $(O)shk.o $(O)shknam.o $(O)sit.o $(O)sounds.o -VOBJ23 = $(O)sp_lev.o $(O)spell.o $(O)steal.o $(O)steed.o -VOBJ24 = $(O)symbols.o $(O)sys.o $(O)teleport.o $(O)termcap.o -VOBJ25 = $(O)timeout.o $(O)topl.o $(O)topten.o $(O)track.o -VOBJ26 = $(O)trap.o $(O)u_init.o $(O)uhitm.o $(O)vault.o -VOBJ27 = $(O)vision.o $(O)vis_tab.o $(O)weapon.o $(O)were.o -VOBJ28 = $(O)wield.o $(O)windows.o $(O)wintty.o $(O)wizard.o -VOBJ29 = $(O)worm.o $(O)worn.o $(O)write.o $(O)zap.o -VOBJ30 = $(REGEX) $(VIDEO_OBJ) - -SOBJ = $(O)msdos.o $(O)pcsys.o $(O)tty.o $(O)unix.o \ - $(O)video.o $(O)vidtxt.o $(O)pckeys.o - -VVOBJ = $(O)version.o - -MDLIB = $(O)mdlib.o - -ifeq "$(ADD_LUA)" "Y" -LUAOBJ = $(O)nhlua.o $(O)nhlsel.o $(O)nhlobj.o -endif - -ifeq "$(ADD_CURSES)" "Y" -CURSESOBJ= $(O)cursdial.o $(O)cursinit.o $(O)cursinvt.o $(O)cursmain.o \ - $(O)cursmesg.o $(O)cursmisc.o $(O)cursstat.o $(O)curswins.o -else -CURSESOBJ= -endif - -VOBJ = $(VOBJ01) $(VOBJ02) $(VOBJ03) $(VOBJ04) $(VOBJ05) \ - $(VOBJ06) $(VOBJ07) $(VOBJ08) $(VOBJ09) $(VOBJ10) \ - $(VOBJ11) $(VOBJ12) $(VOBJ13) $(VOBJ14) $(VOBJ15) \ - $(VOBJ16) $(VOBJ17) $(VOBJ18) $(VOBJ19) $(VOBJ20) \ - $(VOBJ21) $(VOBJ22) $(VOBJ23) $(VOBJ24) $(VOBJ25) \ - $(VOBJ26) $(VOBJ27) $(VOBJ28) $(VOBJ29) $(VOBJ30) \ - $(LUAOBJ) $(CURSESOBJ) $(MDLIB) - -ALLOBJ = $(VOBJ) $(SOBJ) $(TILOBJ) $(TILOBJ2) $(VVOBJ) - -ifeq "$(ADD_LUA)" "Y" -#===============-================================================= -# LUA library -# Source from http://www.lua.org/ftp/lua-5.4.0.tar.gz -#================================================================= - -LUASRC = $(LUATOP)/src -LUALIB = $(O)lua$(subst .,, $(LUAVER))s.a -#LUADLL = $(O)lua$(subst .,, $(LUAVER)).a -LUAINCL = -I$(LUASRC) -#LUAFLAGS = unix added -lm here? -LUATARGETS = lua.exe luac.exe $(LUALIB) -#LUATARGETS = $(LUADLL) $(LUALIB) - -LUASRCFILES = lapi.c lauxlib.c lbaselib.c lcode.c \ - lcorolib.c lctype.c ldblib.c ldebug.c ldo.c \ - ldump.c lfunc.c lgc.c linit.c liolib.c llex.c \ - lmathlib.c lmem.c loadlib.c lobject.c lopcodes.c \ - loslib.c lparser.c lstate.c lstring.c lstrlib.c \ - ltable.c ltablib.c ltm.c lundump.c lutf8lib.c \ - lvm.c lzio.c - -LUAOBJFILES1 = $(O)lapi.o $(O)lauxlib.o $(O)lbaselib.o \ - $(O)lcode.o $(O)lcorolib.o $(O)lctype.o $(O)ldblib.o -LUAOBJFILES2 = $(O)ldebug.o $(O)ldo.o $(O)ldump.o $(O)lfunc.o \ - $(O)lgc.o $(O)linit.o $(O)liolib.o $(O)llex.o -LUAOBJFILES3 = $(O)lmathlib.o $(O)lmem.o $(O)loadlib.o $(O)lobject.o \ - $(O)lopcodes.o $(O)loslib.o $(O)lparser.o $(O)lstate.o -LUAOBJFILES4 = $(O)lstring.o $(O)lstrlib.o $(O)ltable.o $(O)ltablib.o \ - $(O)ltm.o $(O)lundump.o $(O)lutf8lib.o $(O)lvm.o $(O)lzio.o - -#LUAOBJFILES = $(O)lapi.o $(O)lauxlib.o $(O)lbaselib.o \ -# $(O)lcode.o $(O)lcorolib.o $(O)lctype.o $(O)ldblib.o \ -# $(O)ldebug.o $(O)ldo.o $(O)ldump.o $(O)lfunc.o \ -# $(O)lgc.o $(O)linit.o $(O)liolib.o $(O)llex.o \ -# $(O)lmathlib.o $(O)lmem.o $(O)loadlib.o $(O)lobject.o \ -# $(O)lopcodes.o $(O)loslib.o $(O)lparser.o $(O)lstate.o \ -# $(O)lstring.o $(O)lstrlib.o $(O)ltable.o $(O)ltablib.o \ -# $(O)ltm.o $(O)lundump.o $(O)lutf8lib.o $(O)lvm.o $(O)lzio.o - -ifeq "$(LUAVER)" "5.3.5" -LUASRCFILES = $(LUASRCFILES) lbitlib.c -LUAOBJFILES1 = $(LUAOBJFILES1) $(O)lbitlib.o -endif -LUALIBOBJS = $(LUAOBJFILES1) $(LUAOBJFILES2) $(LUAOBJFILES3) $(LUAOBJFILES4) - -endif -ifeq "$(ADD_CURSES)" "Y" -#========================================== -# PDCurses build macros -#========================================== -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 -PDCDOS = $(PDCURSES_TOP)/dos -PDCLIBOBJS1 = $(O)addch.o $(O)addchstr.o $(O)addstr.o $(O)attr.o $(O)beep.o \ - $(O)bkgd.o $(O)border.o $(O)clear.o $(O)color.o $(O)delch.o $(O)deleteln.o \ - $(O)getch.o -PDCLIBOBJS2 = $(O)getstr.o $(O)getyx.o $(O)inch.o $(O)inchstr.o $(O)initscr.o \ - $(O)inopts.o $(O)insch.o $(O)insstr.o $(O)instr.o $(O)kernel.o \ - $(O)keyname.o $(O)mouse.o -PDCLIBOBJS3 = $(O)move.o $(O)outopts.o $(O)overlay.o $(O)pad.o $(O)panel.o \ - $(O)printw.o $(O)refresh.o $(O)scanw.o $(O)scr_dump.o $(O)scroll.o \ - $(O)slk.o $(O)termattr.o -PDCLIBOBJS4 = $(O)touch.o $(O)util.o $(O)window.o $(O)debug.o -PDCLIBOBJS = $(PDCLIBOBJS1) $(PDCLIBOBJS2) $(PDCLIBOBJS3) $(PDCLIBOBJS4) - -PDCOBJS = $(O)pdcclip.o $(O)pdcdisp.o $(O)pdcgetsc.o $(O)pdckbd.o \ - $(O)pdcscrn.o $(O)pdcsetsc.o $(O)pdcutil.o - -#PDCOBJS = $(O)pdcclip.o $(O)pdcdisp.o $(O)pdcgetsc.o $(O)pdckbd.o $(O)pdcscrn.o \ -# $(O)pdcsetsc.o $(O)pdcutil.o - -PDCLIB = $(O)pdcurses.a - -#PDCINCL = -I$(PDCURSES_TOP) -I$(PDCSRC) -I$(PDCDOS) -PDCINCL = -I$(PDCURSES_TOP) -I$(PDCDOS) -else -PDCLIB = -endif - -#========================================== -# Header file macros -#========================================== - -PATCHLEV_H = $(INCL)/patchlev.h -DGN_FILE_H = $(INCL)/align.h $(INCL)/dgn_file.h -DUNGEON_H = $(INCL)/align.h $(INCL)/dungeon.h -MONDATA_H = $(INCL)/align.h $(INCL)/mondata.h -MONST_H = $(INCL)/align.h $(INCL)/monst.h $(INCL)/mextra.h -PERMONST_H = $(INCL)/monattk.h $(INCL)/monflag.h $(INCL)/align.h \ - $(INCL)/permonst.h -REGION_H = $(INCL)/region.h -RM_H = $(INCL)/align.h $(INCL)/rm.h -SKILLS_H = $(INCL)/skills.h -SP_LEV_H = $(INCL)/align.h $(INCL)/sp_lev.h -YOUPROP_H = $(PERMONST_H) $(MONDATA_H) $(INCL)/prop.h \ - $(INCL)/pm.h $(INCL)/youprop.h -YOU_H = $(MONST_H) $(YOUPROP_H) $(INCL)/align.h \ - $(INCL)/attrib.h $(INCL)/you.h -DISPLAY_H = $(MONDATA_H) $(INCL)/vision.h $(INCL)/display.h -PCCONF_H = $(INCL)/micro.h $(INCL)/system.h $(INCL)/pcconf.h \ - $(MSYS)/pcvideo.h -DECL_H = $(YOU_H) $(INCL)/spell.h $(INCL)/color.h \ - $(INCL)/obj.h $(INCL)/onames.h $(INCL)/pm.h \ - $(INCL)/decl.h -GLOBAL_H = $(PCCONF_H) $(INCL)/coord.h $(INCL)/global.h - -CONFIG_H = $(INCL)/config.h $(INCL)/config1.h $(INCL)/tradstdc.h \ - $(INCL)/global.h $(INCL)/coord.h $(INCL)/vmsconf.h \ - $(INCL)/system.h $(INCL)/nhlua.h $(INCL)/unixconf.h \ - $(INCL)/micro.h $(INCL)/pcconf.h $(INCL)/ntconf.h - -HACK_H = $(INCL)/hack.h $(CONFIG_H) $(INCL)/lint.h $(INCL)/align.h \ - $(INCL)/dungeon.h $(INCL)/monsym.h $(INCL)/mkroom.h \ - $(INCL)/objclass.h $(INCL)/youprop.h $(INCL)/prop.h \ - $(INCL)/permonst.h $(INCL)/monattk.h \ - $(INCL)/monflag.h $(INCL)/mondata.h $(INCL)/pm.h \ - $(INCL)/wintype.h $(INCL)/context.h $(INCL)/rm.h \ - $(INCL)/botl.h $(INCL)/rect.h \ - $(INCL)/region.h $(INCL)/decl.h $(INCL)/quest.h \ - $(INCL)/spell.h $(INCL)/color.h $(INCL)/obj.h \ - $(INCL)/you.h $(INCL)/attrib.h $(INCL)/monst.h \ - $(INCL)/mextra.h $(INCL)/skills.h $(INCL)/onames.h \ - $(INCL)/timeout.h $(INCL)/trap.h $(INCL)/flag.h \ - $(INCL)/vision.h $(INCL)/display.h $(INCL)/engrave.h \ - $(INCL)/winprocs.h $(INCL)/sys.h $(INCL)/wintty.h \ - $(INCL)/trampoli.h - -DLB_H = $(INCL)/dlb.h - -ifeq ($(SUPPRESS_GRAPHICS),Y) -TILE_H = -else -TILE_H = $(WSHR)/tile.h $(INCL)/tileset.h -endif - -ifeq ($(USE_DLB),Y) -DLB = dlb -DLBOBJS = $(O)dlb_main.o $(O)dlb.o $(O)alloc.o $(O)panic.o -else -DLB = -DLBOBJS = -endif - -#========================================== -# More compiler setup macros -#========================================== -# -ifeq "$(ADD_CURSES)" "Y" -CURSESDEF=-D"CURSES_GRAPHICS" -D"CURSES_BRIEF_INCLUDE" -else -CURSESDEF= -CURSESLIB= -endif - -INCLDIR=-I../include -I../sys/msdos $(LUAINCL) - -# Debugging -#cflags = -pg -c $(INCLDIR) $(DLBFLG) $(CURSESDEF) -DSUPPRESS_GRAPHICS -DCROSSCOMPILE -DCROSSCOMPILE_TARGET -#LFLAGS = -pg - -#cflags = -c -O $(INCLDIR) $(DLBFLG) $(CURSESDEF) -DSUPPRESS_GRAPHICS -DCROSSCOMPILE-DCROSSCOMPILE_TARGET -#LFLAGS = - -# Debugging -#cflags = -g -c $(INCLDIR) $(DLBFLG) $(CURSESDEF) -DUSE_TILES -DCROSSCOMPILE -DCROSSCOMPILE_TARGET -#LFLAGS = -g - -# Normal -cflags = -c -O $(INCLDIR) $(DLBFLG) $(CURSESDEF) -DUSE_TILES -DCROSSCOMPILE -DCROSSCOMPILE_TARGET -LFLAGS = - -#========================================== -#================ RULES ================== -#========================================== - -.SUFFIXES: .o .til .uu .c .y .l - -#========================================== -# Rules for files in src -#========================================== - -$(OBJ)/%.o : %.c - $(TARGET_CC) $(cflags) -o$@ $< - -$(OBJ)/%.o : $(SRC)/%.c - $(TARGET_CC) $(cflags) -o$@ $< - -#========================================== -# Rules for files in sys/share -#========================================== - -$(OBJ)/%.o : $(SSHR)/%.c - $(TARGET_CC) $(cflags) -o$@ $< - -#========================================== -# Rules for files in sys/msdos -#========================================== - -$(OBJ)/%.o : $(MSYS)/%.c - $(TARGET_CC) $(cflags) -I../sys/msdos -o$@ $< - -#========================================== -# Rules for files in util -#========================================== - -$(OBJ)/%.o : $(UTIL)/%.c - $(TARGET_CC) $(cflags) -o$@ $< - -#========================================== -# Rules for files in win/share -#========================================== - -$(OBJ)/%.o : $(WSHR)/%.c - $(TARGET_CC) $(cflags) -I../win/share -o$@ $< - -#========================================== -# Rules for files in win/tty -#========================================== - -$(OBJ)/%.o : $(TTY)/%.c - $(TARGET_CC) $(cflags) -o$@ $< - -#========================================== -# Rules for files in win/curses -#========================================== - -$(OBJ)/%.o : $(WCURSES)/%.c - $(TARGET_CC) -DPDC_NCMOUSE $(PDCINCL) $(cflags) -o$@ $< - -#========================================== -# Rules for files in PDCurses -#========================================== - -$(OBJ)/%.o : $(PDCURSES_TOP)/%.c - $(TARGET_CC) $(PDCINCL) $(cflags) -o$@ $< - -$(OBJ)/%.o : $(PDCSRC)/%.c - $(TARGET_CC) $(PDCINCL) $(cflags) -o$@ $< - -$(OBJ)/%.o : $(PDCDOS)/%.c - $(TARGET_CC) $(PDCINCL) $(cflags) -o$@ $< - -ifeq "$(ADD_LUA)" "Y" -#========================================== -# Rules for LUA files -#========================================== - -$(OBJ)/%.o : $(LUASRC)/%.c - $(TARGET_CC) $(cflags) -o$@ $< -endif - -#========================================== -# Primary Targets. -#========================================== - -# The default target. - -all : install - -install: $(GAMEFILE) $(O)install.tag - @echo Done. - -default: $(GAMEFILE) - -tileutil: $(U)gif2txt $(U)txt2ppm - @echo Optional tile development utilities are up to date. - -recover.exe: $(U)recover -# @$(subst /,\,if exist $(U)recover copy $(U)recover $(GAMEDIR)) -# @$(subst /,\,if exist $(DOC)/recover.txt copy $(DOC)/recover.txt $(GAMEDIR)) - -$(O)install.tag: $(DAT)/nhdat $(GAMEFILE) -ifeq ($(USE_DLB),Y) - cp $(DAT)/nhdat $(GAMEDIR)/NHDAT - cp $(DAT)/license $(GAMEDIR)/LICENSE -else - cp $(DAT)/*. $(GAMEDIR) - cp $(DAT)/*.dat $(GAMEDIR) - cp $(MSYS)/msdoshlp.txt $(GAMEDIR)) -ifeq "$(ADD_LUA)" "Y" - cp $(DAT)/*.lua $(GAMEDIR) -endif -endif -ifdef TERMLIB - cp $(SSHR)/termcap $(GAMEDIR)/TERMCAP) -endif -# if [ -f $(TILE_BMP) ]; then rm $(TILE_BMP); fi; - if [ -f $(TILE_BMP) ]; then cp $(TILE_BMP) $(GAMEDIR)/NHTILES.BMP; fi; - if [ -f $(DAT)/symbols ]; then cp $(DAT)/symbols $(GAMEDIR)/SYMBOLS; fi; - if [ -f $(SSHR)/NetHack.cnf ]; then cp $(SSHR)/NetHack.cnf $(GAMEDIR)/NETHACK.CNF; fi; - -touch $(GAMEDIR)/RECORD - if [ -f ../sys/msdos/sysconf ]; then cp ../sys/msdos/sysconf $(GAMEDIR)/SYSCONF; fi; - if [ -f $(DOC)/nethack.txt ]; then cp $(DOC)/nethack.txt $(GAMEDIR)/NETHACK.TXT; fi; - @echo install done > $@ - -#========================================== -# The main target. -#========================================== - -$(GAMEFILE): $(O)obj.tag $(PDCLIB) $(LUALIB) \ - $(ALLOBJ) $(O)$(GAME).lnk - if [ -f temp.a ]; then rm temp.a; fi; - @$(TARGET_AR) r temp.a $(VOBJ01) - @$(TARGET_AR) r temp.a $(VOBJ02) - @$(TARGET_AR) r temp.a $(VOBJ03) - @$(TARGET_AR) r temp.a $(VOBJ04) - @$(TARGET_AR) r temp.a $(VOBJ05) - @$(TARGET_AR) r temp.a $(VOBJ06) - @$(TARGET_AR) r temp.a $(VOBJ07) - @$(TARGET_AR) r temp.a $(VOBJ08) - @$(TARGET_AR) r temp.a $(VOBJ09) - @$(TARGET_AR) r temp.a $(VOBJ10) - @$(TARGET_AR) r temp.a $(VOBJ11) - @$(TARGET_AR) r temp.a $(VOBJ12) - @$(TARGET_AR) r temp.a $(VOBJ13) - @$(TARGET_AR) r temp.a $(VOBJ14) - @$(TARGET_AR) r temp.a $(VOBJ15) - @$(TARGET_AR) r temp.a $(VOBJ16) - @$(TARGET_AR) r temp.a $(VOBJ17) - @$(TARGET_AR) r temp.a $(VOBJ18) - @$(TARGET_AR) r temp.a $(VOBJ19) - @$(TARGET_AR) r temp.a $(VOBJ20) - @$(TARGET_AR) r temp.a $(VOBJ21) - @$(TARGET_AR) r temp.a $(VOBJ22) - @$(TARGET_AR) r temp.a $(VOBJ23) - @$(TARGET_AR) r temp.a $(VOBJ24) - @$(TARGET_AR) r temp.a $(VOBJ25) - @$(TARGET_AR) r temp.a $(VOBJ26) - @$(TARGET_AR) r temp.a $(VOBJ27) - @$(TARGET_AR) r temp.a $(VOBJ28) - @$(TARGET_AR) r temp.a $(VOBJ29) - @$(TARGET_AR) r temp.a $(VOBJ30) - @$(TARGET_AR) r temp.a $(VIDEO_OBJ) - @$(TARGET_AR) r temp.a $(SOBJ) - @$(TARGET_AR) r temp.a $(TILOBJ) - @$(TARGET_AR) r temp.a $(TILOBJ2) -ifeq "$(ADD_LUA)" "Y" - @$(TARGET_AR) r temp.a $(LUAOBJ) -endif - @$(TARGET_AR) r temp.a $(VVOBJ) -ifeq "$(ADD_CURSES)" "Y" - @$(TARGET_AR) r temp.a $(CURSESOBJ) -endif - @$(TARGET_AR) r temp.a $(MDLIB) - $(TARGET_LINK) $(LFLAGS) -o$(GAME).exe temp.a $(PDCLIB) $(LUALIB) $(LIBRARIES) $(ZLIB) - $(TARGET_STUBEDIT) $(GAME).exe minstack=2048K - cp $(GAME).exe $(GAMEFILE) - rm $(GAME).exe - -$(O)$(GAME).lnk: $(ALLOBJ) - echo $(VOBJ01) > $@ - echo $(VOBJ02) >> $@ - echo $(VOBJ03) >> $@ - echo $(VOBJ04) >> $@ - echo $(VOBJ05) >> $@ - echo $(VOBJ06) >> $@ - echo $(VOBJ07) >> $@ - echo $(VOBJ08) >> $@ - echo $(VOBJ09) >> $@ - echo $(VOBJ10) >> $@ - echo $(VOBJ11) >> $@ - echo $(VOBJ12) >> $@ - echo $(VOBJ13) >> $@ - echo $(VOBJ14) >> $@ - echo $(VOBJ15) >> $@ - echo $(VOBJ16) >> $@ - echo $(VOBJ17) >> $@ - echo $(VOBJ18) >> $@ - echo $(VOBJ19) >> $@ - echo $(VOBJ20) >> $@ - echo $(VOBJ21) >> $@ - echo $(VOBJ22) >> $@ - echo $(VOBJ23) >> $@ - echo $(VOBJ24) >> $@ - echo $(VOBJ25) >> $@ - echo $(VOBJ26) >> $@ - echo $(VOBJ27) >> $@ - echo $(VOBJ28) >> $@ - echo $(VOBJ29) >> $@ - echo $(VOBJ30) >> $@ - echo $(SOBJ) >> $@ - echo $(TILOBJ) >> $@ - echo $(TILOBJ2) >> $@ -ifeq "$(ADD_LUA)" "Y" - echo $(LUAOBJ) >> $@ -endif - echo $(VVOBJ) >> $@ -ifeq "$(ADD_CURSES)" "Y" - echo $(CURSESOBJ) >> $@ -endif - -#========================================== -#=========== SECONDARY TARGETS ============ -#========================================== -# -#========================================== -# Recover Utility -#========================================== - -$(U)recover.exe: $(RECOVOBJS) - $(TARGET_LINK) $(LFLAGS) -o$@ $(O)recover.o - -$(O)recover.o: $(CONFIG_H) $(U)recover.c - $(TARGET_CC) $(cflags) -o$@ $(U)recover.c - -#========================================== -# Header file moves required for tile support -#========================================== - -ifeq ($(SUPPRESS_GRAPHICS),Y) - -else -# -# Tile Mapping -# - -#$(SRC)/tile.c: $(U)tilemap -# @$(U)tilemap -# @echo A new $@ has been created - -endif - -#========================================== -# PDCurses Library -#========================================== - -$(O)pdcurses.a : $(PDCLIBOBJS) $(PDCOBJS) - if [ -f $@ ]; then rm $@; fi; - $(TARGET_AR) rcS $@ $(PDCLIBOBJS1) - $(TARGET_AR) rcS $@ $(PDCLIBOBJS2) - $(TARGET_AR) rcS $@ $(PDCLIBOBJS3) - $(TARGET_AR) rcS $@ $(PDCLIBOBJS4) - $(TARGET_AR) rcs $@ $(PDCOBJS) - -#========================================== -# Other Util Dependencies. -#========================================== - -$(O)alloc.o: $(CONFIG_H) alloc.c - $(TARGET_CC) $(cflags) -o$@ alloc.c - -$(O)drawing.o: $(CONFIG_H) drawing.c $(MSYS)/pcvideo.h - $(TARGET_CC) $(cflags) -I$(MSYS) -o$@ drawing.c - -$(O)decl.o: $(CONFIG_H) decl.c - $(TARGET_CC) $(cflags) -o$@ decl.c - -$(O)monst.o: $(CONFIG_H) $(PERMONST_H) $(INCL)/monsym.h \ - $(INCL)/color.h monst.c - $(TARGET_CC) $(cflags) -o$@ monst.c - -$(O)objects.o: $(CONFIG_H) $(INCL)/obj.h $(INCL)/objclass.h \ - $(INCL)/prop.h $(INCL)/color.h objects.c - $(TARGET_CC) $(cflags) -o$@ objects.c - -$(O)dat.tag: $(DAT)/nhdat - @echo dat done >$@ - -#============================================================= -# Lua -#============================================================= - -lua.exe: $(O)lua.o $(LUALIB) - $(TARGET_LINK) $(LFLAGS) -o$@ $(O)lua.o $(LUALIB) - -luac.exe: $(O)luac.o $(LUALIB) - $(TARGET_LINK) $(LFLAGSU) -o$@ $(O)luac.o $(LUALIB) - -$(O)lua.o: $(LUASRC)/lua.c -$(O)luac.o: $(LUASRC)/luac.c - -#========================================== -# Lua lib -#========================================== - -$(LUALIB): $(LUALIBOBJS) - if [ -f $@ ]; then rm $@; fi; - $(TARGET_AR) rcS $@ $(LUAOBJFILES1) - $(TARGET_AR) rcS $@ $(LUAOBJFILES2) - $(TARGET_AR) rcS $@ $(LUAOBJFILES3) - $(TARGET_AR) rcs $@ $(LUAOBJFILES4) - -#$(LUADLL): $(LUALIBOBJS) -# $(TARGET_CC) -shared -Wl,--export-all-symbols \ -# -Wl,--add-stdcall-alias -o $@ $< - -#========================================== -# Housekeeping. -#========================================== - -clean: - rm ./o/*.o - if [ -f $(O)install.tag ]; then rm $(O)install.tag; fi; - if [ -f $(O)obj.tag ]; then rm $(O)obj.tag; fi; - if [ -f $(O)$(GAME).lnk ]; then rm temp.a; fi; - if [ -f temp.a ]; then rm temp.a; fi; - -spotless: clean - - if [ -f $(U)recover.exe ]; then rm $(U)recover.exe; fi; - if [ -f $(INCL)/vis_tab.h ]; then rm $(INCL)/vis_tab.h; fi; - if [ -f $(INCL)/onames.h ]; then rm $(INCL)/onames.h; fi; - if [ -f $(INCL)/pm.h ]; then rm $(INCL)/pm.h; fi; - if [ -f $(INCL)/date.h ]; then rm $(INCL)/date.h; fi; -# if [ -f $(SRC)/monstr.c ]; then rm $(SRC)/monstr.c; fi; - if [ -f $(SRC)/vis_tab.c ]; then rm $(SRC)/vis_tab.c; fi; - if [ -f $(SRC)/tile.c ]; then rm $(SRC)/tile.c; fi; - if [ -f $(DAT)/options ]; then rm $(DAT)/options; fi; - if [ -f $(DAT)/data ]; then rm $(DAT)/data; fi; - if [ -f $(DAT)/rumors ]; then rm $(DAT)/rumors; fi; - if [ -f $(DAT)/oracles ]; then rm $(DAT)/oracles; fi; - if [ -f $(DAT)/bogusmon ]; then rm $(DAT)/bogusmon; fi; - if [ -f $(DAT)/engrave ]; then rm $(DAT)/engrave; fi; - if [ -f $(DAT)/epitaph ]; then rm $(DAT)/epitaph; fi; - if [ -f $(DAT)/dlb.lst ]; then rm $(DAT)/dlb.lst; fi; - if [ -f $(TILE_BMP) ]; then rm $(TILE_BMP); fi; - if [ -f $(PLANAR_TIB) ]; then rm $(PLANAR_TIB); fi; - if [ -f $(OVERVIEW_TIB) ]; then rm $(OVERVIEW_TIB); fi; - if [ -f $(WSHR)/monthin.txt ]; then rm $(WSHR)/monthin.txt; fi; - if [ -f $(WSHR)/objthin.txt ]; then rm $(WSHR)/objthin.txt; fi; - if [ -f $(WSHR)/oththin.txt ]; then rm $(WSHR)/oththin.txt; fi; - -#========================================== -# Create directory for holding object files -#========================================== - -$(O)obj.tag: - -mkdir -p $(OBJ) - @echo directory ready $(OBJ) - -#========================================== -# Game Dependencies -#========================================== - -# sys/share -$(O)main.o: $(HACK_H) $(DLB_H) $(SSHR)/pcmain.c - $(TARGET_CC) $(cflags) -o$@ $(SSHR)/pcmain.c - -$(O)tty.o: $(HACK_H) $(INCL)/wintty.h $(SSHR)/pctty.c - $(TARGET_CC) $(cflags) -o$@ $(SSHR)/pctty.c - -$(O)unix.o: $(HACK_H) $(SSHR)/pcunix.c - $(TARGET_CC) $(cflags) -o$@ $(SSHR)/pcunix.c - -$(O)pcsys.o : $(HACK_H) $(SSHR)/pcsys.c - $(TARGET_CC) $(cflags) -o$@ $(SSHR)/pcsys.c - -$(O)posixreg.o : $(HACK_H) $(SSHR)/posixreg.c - $(TARGET_CC) $(cflags) -o$@ $(SSHR)/posixreg.c - -$(O)cppregex.o : $(HACK_H) $(SSHR)/cppregex.cpp - gpp $(cflags) -std=c++11 -o$@ $(SSHR)/cppregex.cpp - -$(O)pmatchre.o : $(HACK_H) $(SSHR)/pmatchre.c - $(TARGET_CC) $(cflags) -o$@ $(SSHR)/pmatchre.c - -# sys/msdos -$(O)tile.o : $(HACK_H) $(SRC)/tile.c -$(O)msdos.o : $(HACK_H) $(MSYS)/msdos.c -$(O)pckeys.o : $(HACK_H) $(MSYS)/pckeys.c -$(O)pctiles.o : $(HACK_H) $(MSYS)/pctiles.c $(MSYS)/portio.h - $(TARGET_CC) $(cflags) -I$(MSYS) -I$(WSHR) -o$@ $(MSYS)/pctiles.c -$(O)sound.o : $(HACK_H) $(MSYS)/sound.c $(MSYS)/portio.h -$(O)video.o : $(HACK_H) $(MSYS)/pcvideo.h $(MSYS)/portio.h $(MSYS)/video.c -$(O)vidvga.o : $(HACK_H) $(MSYS)/pcvideo.h $(MSYS)/portio.h $(TILE_H) $(MSYS)/vidvga.c - $(TARGET_CC) $(cflags) -I$(MSYS) -I$(WSHR) -o$@ $(MSYS)/vidvga.c -$(O)vidvesa.o : $(HACK_H) $(MSYS)/pcvideo.h $(MSYS)/portio.h $(TILE_H) $(MSYS)/vidvesa.c - $(TARGET_CC) $(cflags) -I$(MSYS) -I$(WSHR) -o$@ $(MSYS)/vidvesa.c -$(O)vidtxt.o : $(HACK_H) $(MSYS)/pcvideo.h $(MSYS)/portio.h $(TILE_H) $(MSYS)/vidtxt.c -$(O)stubvid.o : $(HACK_H) $(MSYS)/pcvideo.h $(MSYS)/video.c - $(TARGET_CC) $(cflags) -I$(MSYS) -DSTUBVIDEO -o$@ $(MSYS)/video.c -# -# The rest are stolen from sys/unix/Makefile.src, -# with the following changes: -# o -c (which is included in cflags) substituted with -o$@ , -# o an explicit build instruction for dlb.o because it requires -# a .h file in ../sys/msdos. -# o $(CFLAGS) changed to $(cflags) -# Other than that, these dependencies are untouched. -# That means that there is some irrelevant stuff -# in here, but maintenance should be easier. -# -# -# src dependencies -#$(O)tos.o: ../sys/atari/tos.c $(HACK_H) $(INCL)/tcap.h - $(TARGET_CC) $(cflags) -o$@ ../sys/atari/tos.c -$(O)pcmain.o: ../sys/share/pcmain.c $(HACK_H) $(INCL)/dlb.h \ - #$(INCL)/win32api.h - $(TARGET_CC) $(cflags) -o$@ ../sys/share/pcmain.c -$(O)pctty.o: ../sys/share/pctty.c $(HACK_H) - $(TARGET_CC) $(cflags) -o$@ ../sys/share/pctty.c -$(O)pcunix.o: ../sys/share/pcunix.c $(HACK_H) - $(TARGET_CC) $(cflags) -o$@ ../sys/share/pcunix.c -$(O)random.o: ../sys/share/random.c $(HACK_H) - $(TARGET_CC) $(cflags) -o$@ ../sys/share/random.c -$(O)ioctl.o: ../sys/share/ioctl.c $(HACK_H) $(INCL)/tcap.h - $(TARGET_CC) $(cflags) -o$@ ../sys/share/ioctl.c -$(O)unixtty.o: ../sys/share/unixtty.c $(HACK_H) - $(TARGET_CC) $(cflags) -o$@ ../sys/share/unixtty.c -$(O)unixmain.o: ../sys/unix/unixmain.c $(HACK_H) $(INCL)/dlb.h - $(TARGET_CC) $(cflags) -o$@ ../sys/unix/unixmain.c -$(O)unixunix.o: ../sys/unix/unixunix.c $(HACK_H) - $(TARGET_CC) $(cflags) -o$@ ../sys/unix/unixunix.c -$(O)unixres.o: ../sys/unix/unixres.c $(CONFIG_H) - $(TARGET_CC) $(cflags) -o$@ ../sys/unix/unixres.c -$(O)bemain.o: ../sys/be/bemain.c $(HACK_H) $(INCL)/dlb.h - $(TARGET_CC) $(cflags) -o$@ ../sys/be/bemain.c -$(O)getline.o: ../win/tty/getline.c $(HACK_H) $(INCL)/func_tab.h - $(TARGET_CC) $(cflags) -o$@ ../win/tty/getline.c -$(O)termcap.o: ../win/tty/termcap.c $(HACK_H) $(INCL)/tcap.h - $(TARGET_CC) $(cflags) -o$@ ../win/tty/termcap.c -$(O)topl.o: ../win/tty/topl.c $(HACK_H) $(INCL)/tcap.h - $(TARGET_CC) $(cflags) -o$@ ../win/tty/topl.c -$(O)wintty.o: ../win/tty/wintty.c $(HACK_H) $(INCL)/dlb.h \ - $(INCL)/date.h $(INCL)/tcap.h - $(TARGET_CC) $(cflags) -o$@ ../win/tty/wintty.c -$(O)Window.o: ../win/X11/Window.c $(INCL)/xwindowp.h $(INCL)/xwindow.h \ - $(CONFIG_H) - $(TARGET_CC) $(cflags) -o$@ ../win/X11/Window.c -$(O)dialogs.o: ../win/X11/dialogs.c $(CONFIG_H) - $(TARGET_CC) $(cflags) -o$@ ../win/X11/dialogs.c -$(O)winX.o: ../win/X11/winX.c $(HACK_H) $(INCL)/winX.h $(INCL)/dlb.h \ - ../win/X11/nh72icon \ - ../win/X11/nh56icon ../win/X11/nh32icon - $(TARGET_CC) $(cflags) -o$@ ../win/X11/winX.c -$(O)winmap.o: ../win/X11/winmap.c $(INCL)/xwindow.h $(HACK_H) $(INCL)/dlb.h \ - $(INCL)/winX.h $(INCL)/tile2x11.h - $(TARGET_CC) $(cflags) -o$@ ../win/X11/winmap.c -$(O)winmenu.o: ../win/X11/winmenu.c $(HACK_H) $(INCL)/winX.h - $(TARGET_CC) $(cflags) -o$@ ../win/X11/winmenu.c -$(O)winmesg.o: ../win/X11/winmesg.c $(INCL)/xwindow.h $(HACK_H) $(INCL)/winX.h - $(TARGET_CC) $(cflags) -o$@ ../win/X11/winmesg.c -$(O)winmisc.o: ../win/X11/winmisc.c $(HACK_H) $(INCL)/func_tab.h \ - $(INCL)/winX.h - $(TARGET_CC) $(cflags) -o$@ ../win/X11/winmisc.c -$(O)winstat.o: ../win/X11/winstat.c $(HACK_H) $(INCL)/winX.h - $(TARGET_CC) $(cflags) -o$@ ../win/X11/winstat.c -$(O)wintext.o: ../win/X11/wintext.c $(HACK_H) $(INCL)/winX.h $(INCL)/xwindow.h - $(TARGET_CC) $(cflags) -o$@ ../win/X11/wintext.c -$(O)winval.o: ../win/X11/winval.c $(HACK_H) $(INCL)/winX.h - $(TARGET_CC) $(cflags) -o$@ ../win/X11/winval.c -#$(O)tile.o: tile.c $(HACK_H) -#$(HOST_O)tile.o: tile.c $(HACK_H) -$(O)gnaskstr.o: ../win/gnome/gnaskstr.c ../win/gnome/gnaskstr.h \ - ../win/gnome/gnmain.h - $(TARGET_CC) $(cflags) $(GNOMEINC) -o$@ ../win/gnome/gnaskstr.c -$(O)gnbind.o: ../win/gnome/gnbind.c ../win/gnome/gnbind.h ../win/gnome/gnmain.h \ - ../win/gnome/gnaskstr.h ../win/gnome/gnyesno.h - $(TARGET_CC) $(cflags) $(GNOMEINC) -o$@ ../win/gnome/gnbind.c -$(O)gnglyph.o: ../win/gnome/gnglyph.c ../win/gnome/gnglyph.h $(INCL)/tile2x11.h - $(TARGET_CC) $(cflags) $(GNOMEINC) -o$@ ../win/gnome/gnglyph.c -$(O)gnmain.o: ../win/gnome/gnmain.c ../win/gnome/gnmain.h ../win/gnome/gnsignal.h \ - ../win/gnome/gnbind.h ../win/gnome/gnopts.h $(HACK_H) \ - $(INCL)/date.h - $(TARGET_CC) $(cflags) $(GNOMEINC) -o$@ ../win/gnome/gnmain.c -$(O)gnmap.o: ../win/gnome/gnmap.c ../win/gnome/gnmap.h ../win/gnome/gnglyph.h \ - ../win/gnome/gnsignal.h $(HACK_H) - $(TARGET_CC) $(cflags) $(GNOMEINC) -o$@ ../win/gnome/gnmap.c -$(O)gnmenu.o: ../win/gnome/gnmenu.c ../win/gnome/gnmenu.h ../win/gnome/gnmain.h \ - ../win/gnome/gnbind.h - $(TARGET_CC) $(cflags) $(GNOMEINC) -o$@ ../win/gnome/gnmenu.c -$(O)gnmesg.o: ../win/gnome/gnmesg.c ../win/gnome/gnmesg.h ../win/gnome/gnsignal.h - $(TARGET_CC) $(cflags) $(GNOMEINC) -o$@ ../win/gnome/gnmesg.c -$(O)gnopts.o: ../win/gnome/gnopts.c ../win/gnome/gnopts.h ../win/gnome/gnglyph.h \ - ../win/gnome/gnmain.h ../win/gnome/gnmap.h $(HACK_H) - $(TARGET_CC) $(cflags) $(GNOMEINC) -o$@ ../win/gnome/gnopts.c -$(O)gnplayer.o: ../win/gnome/gnplayer.c ../win/gnome/gnplayer.h \ - ../win/gnome/gnmain.h $(HACK_H) - $(TARGET_CC) $(cflags) $(GNOMEINC) -o$@ ../win/gnome/gnplayer.c -$(O)gnsignal.o: ../win/gnome/gnsignal.c ../win/gnome/gnsignal.h \ - ../win/gnome/gnmain.h - $(TARGET_CC) $(cflags) $(GNOMEINC) -o$@ ../win/gnome/gnsignal.c -$(O)gnstatus.o: ../win/gnome/gnstatus.c ../win/gnome/gnstatus.h \ - ../win/gnome/gnsignal.h ../win/gnome/gn_xpms.h \ - ../win/gnome/gnomeprv.h - $(TARGET_CC) $(cflags) $(GNOMEINC) -o$@ ../win/gnome/gnstatus.c -$(O)gntext.o: ../win/gnome/gntext.c ../win/gnome/gntext.h ../win/gnome/gnmain.h \ - ../win/gnome/gn_rip.h - $(TARGET_CC) $(cflags) $(GNOMEINC) -o$@ ../win/gnome/gntext.c -$(O)gnworn.o: ../win/gnome/gnworn.c ../win/gnome/gnworn.h ../win/gnome/gnglyph.h \ - ../win/gnome/gnsignal.h ../win/gnome/gnomeprv.h - $(TARGET_CC) $(cflags) $(GNOMEINC) -o$@ ../win/gnome/gnworn.c -$(O)gnyesno.o: ../win/gnome/gnyesno.c ../win/gnome/gnbind.h ../win/gnome/gnyesno.h - $(TARGET_CC) $(cflags) $(GNOMEINC) -o$@ ../win/gnome/gnyesno.c -$(O)wingem.o: ../win/gem/wingem.c $(HACK_H) $(INCL)/func_tab.h $(INCL)/dlb.h \ - $(INCL)/wingem.h - $(TARGET_CC) $(cflags) -o$@ ../win/gem/wingem.c -$(O)wingem1.o: ../win/gem/wingem1.c $(INCL)/gem_rsc.h $(INCL)/load_img.h \ - $(INCL)/gr_rect.h $(INCL)/wintype.h $(INCL)/wingem.h - $(TARGET_CC) $(cflags) -o$@ ../win/gem/wingem1.c -$(O)load_img.o: ../win/gem/load_img.c $(INCL)/load_img.h - $(TARGET_CC) $(cflags) -o$@ ../win/gem/load_img.c -$(O)gr_rect.o: ../win/gem/gr_rect.c $(INCL)/gr_rect.h - $(TARGET_CC) $(cflags) -o$@ ../win/gem/gr_rect.c -$(O)qt_win.o: ../win/Qt/qt_win.cpp $(HACK_H) $(INCL)/func_tab.h \ - $(INCL)/dlb.h $(INCL)/tile2x11.h \ - $(INCL)/qt_win.h $(INCL)/qt_clust.h $(INCL)/qt_kde0.h \ - $(INCL)/qt_xpms.h qt_win.moc qt_kde0.moc qttableview.moc - $(CXX) $(CXXFLAGS) -o$@ ../win/Qt/qt_win.cpp -$(O)qt_clust.o: ../win/Qt/qt_clust.cpp $(INCL)/qt_clust.h - $(CXX) $(CXXFLAGS) -o$@ ../win/Qt/qt_clust.cpp -$(O)qttableview.o: ../win/Qt/qttableview.cpp $(INCL)/qttableview.h - $(CXX) $(CXXFLAGS) -o$@ ../win/Qt/qttableview.cpp -#$(O)monstr.o: monstr.c $(CONFIG_H) -$(O)vis_tab.o: vis_tab.c $(CONFIG_H) $(INCL)/vis_tab.h -$(O)allmain.o: allmain.c $(HACK_H) -$(O)alloc.o: alloc.c $(CONFIG_H) -$(O)apply.o: apply.c $(HACK_H) -$(O)artifact.o: artifact.c $(HACK_H) $(INCL)/artifact.h $(INCL)/artilist.h -$(O)attrib.o: attrib.c $(HACK_H) -$(O)ball.o: ball.c $(HACK_H) -$(O)bones.o: bones.c $(HACK_H) -$(O)botl.o: botl.c $(HACK_H) -$(O)cmd.o: cmd.c $(HACK_H) $(INCL)/func_tab.h -$(O)dbridge.o: dbridge.c $(HACK_H) -$(O)decl.o: decl.c $(HACK_H) -$(O)detect.o: detect.c $(HACK_H) $(INCL)/artifact.h -$(O)dig.o: dig.c $(HACK_H) -$(O)display.o: display.c $(HACK_H) -$(O)dlb.o: dlb.c $(CONFIG_H) $(INCL)/dlb.h - $(TARGET_CC) $(cflags) -I../sys/msdos -o$@ dlb.c -$(O)do.o: do.c $(HACK_H) -$(O)do_name.o: do_name.c $(HACK_H) -$(O)do_wear.o: do_wear.c $(HACK_H) -$(O)dog.o: dog.c $(HACK_H) -$(O)dogmove.o: dogmove.c $(HACK_H) $(INCL)/mfndpos.h -$(O)dokick.o: dokick.c $(HACK_H) -$(O)dothrow.o: dothrow.c $(HACK_H) -$(O)drawing.o: drawing.c $(CONFIG_H) -$(O)dungeon.o: dungeon.c $(HACK_H) $(INCL)/dgn_file.h $(INCL)/dlb.h -$(O)eat.o: eat.c $(HACK_H) -$(O)end.o: end.c $(HACK_H) $(INCL)/dlb.h -$(O)engrave.o: engrave.c $(HACK_H) -$(O)exper.o: exper.c $(HACK_H) -$(O)explode.o: explode.c $(HACK_H) -$(O)extralev.o: extralev.c $(HACK_H) -$(O)files.o: files.c $(HACK_H) $(INCL)/dlb.h -$(O)fountain.o: fountain.c $(HACK_H) -$(O)hack.o: hack.c $(HACK_H) -$(O)hacklib.o: hacklib.c $(HACK_H) -$(O)insight.o: insight.c $(HACK_H) -$(O)invent.o: invent.c $(HACK_H) -$(O)light.o: light.c $(HACK_H) -$(O)lock.o: lock.c $(HACK_H) -$(O)mail.o: mail.c $(HACK_H) $(INCL)/mail.h -$(O)makemon.o: makemon.c $(HACK_H) -$(O)mapglyph.o: mapglyph.c $(HACK_H) -$(O)mcastu.o: mcastu.c $(HACK_H) -$(O)mhitm.o: mhitm.c $(HACK_H) $(INCL)/artifact.h -$(O)mhitu.o: mhitu.c $(HACK_H) $(INCL)/artifact.h -$(O)minion.o: minion.c $(HACK_H) -$(O)mklev.o: mklev.c $(HACK_H) -$(O)mkmap.o: mkmap.c $(HACK_H) $(INCL)/sp_lev.h -$(O)mkmaze.o: mkmaze.c $(HACK_H) $(INCL)/sp_lev.h -$(O)mkobj.o: mkobj.c $(HACK_H) -$(O)mkroom.o: mkroom.c $(HACK_H) -$(O)mon.o: mon.c $(HACK_H) $(INCL)/mfndpos.h -$(O)mondata.o: mondata.c $(HACK_H) -$(O)monmove.o: monmove.c $(HACK_H) $(INCL)/mfndpos.h $(INCL)/artifact.h -$(O)monst.o: monst.c $(CONFIG_H) $(INCL)/permonst.h $(INCL)/align.h \ - $(INCL)/monattk.h $(INCL)/monflag.h $(INCL)/monsym.h \ - $(INCL)/color.h -$(O)mplayer.o: mplayer.c $(HACK_H) -$(O)mthrowu.o: mthrowu.c $(HACK_H) -$(O)muse.o: muse.c $(HACK_H) -$(O)music.o: music.c $(HACK_H) #interp.c -$(O)nhlua.o: nhlua.c $(HACK_H) -$(O)nhlsel.o: nhlsel.c $(HACK_H) -$(O)nhlobj.o: nhlobj.c $(HACK_H) -$(O)o_init.o: o_init.c $(HACK_H) -$(O)objects.o: objects.c $(CONFIG_H) $(INCL)/obj.h $(INCL)/objclass.h \ - $(INCL)/prop.h $(INCL)/skills.h $(INCL)/color.h -$(O)objnam.o: objnam.c $(HACK_H) -$(O)options.o: options.c $(CONFIG_H) $(INCL)/objclass.h $(INCL)/flag.h \ - $(HACK_H) $(INCL)/tcap.h -$(O)pager.o: pager.c $(HACK_H) $(INCL)/dlb.h -$(O)pickup.o: pickup.c $(HACK_H) -$(O)pline.o: pline.c $(HACK_H) -$(O)polyself.o: polyself.c $(HACK_H) -$(O)potion.o: potion.c $(HACK_H) -$(O)pray.o: pray.c $(HACK_H) -$(O)priest.o: priest.c $(HACK_H) $(INCL)/mfndpos.h -$(O)quest.o: quest.c $(HACK_H) -$(O)questpgr.o: questpgr.c $(HACK_H) $(INCL)/dlb.h -$(O)read.o: read.c $(HACK_H) -$(O)rect.o: rect.c $(HACK_H) -$(O)region.o: region.c $(HACK_H) -$(O)restore.o: restore.c $(HACK_H) $(INCL)/tcap.h -$(O)rip.o: rip.c $(HACK_H) -$(O)rnd.o: rnd.c $(HACK_H) -$(O)role.o: role.c $(HACK_H) -$(O)rumors.o: rumors.c $(HACK_H) $(INCL)/dlb.h -$(O)save.o: save.c $(HACK_H) -$(O)shk.o: shk.c $(HACK_H) -$(O)shknam.o: shknam.c $(HACK_H) -$(O)sit.o: sit.c $(HACK_H) $(INCL)/artifact.h -$(O)sounds.o: sounds.c $(HACK_H) -$(O)sp_lev.o: sp_lev.c $(HACK_H) $(INCL)/dlb.h $(INCL)/sp_lev.h -$(O)spell.o: spell.c $(HACK_H) -$(O)steal.o: steal.c $(HACK_H) -$(O)steed.o: steed.c $(HACK_H) -$(O)symbols.o: symbols.c $(HACK_H) $(INCL)/tcap.h -$(O)sys.o: sys.c $(HACK_H) -$(O)teleport.o: teleport.c $(HACK_H) -$(O)timeout.o: timeout.c $(HACK_H) -$(O)topten.o: topten.c $(HACK_H) $(INCL)/dlb.h -$(O)track.o: track.c $(HACK_H) -$(O)trap.o: trap.c $(HACK_H) -$(O)u_init.o: u_init.c $(HACK_H) -$(O)uhitm.o: uhitm.c $(HACK_H) -$(O)vault.o: vault.c $(HACK_H) -$(O)version.o: version.c $(HACK_H) $(INCL)/date.h -$(O)vision.o: vision.c $(HACK_H) $(INCL)/vis_tab.h -$(O)weapon.o: weapon.c $(HACK_H) -$(O)were.o: were.c $(HACK_H) -$(O)wield.o: wield.c $(HACK_H) -$(O)windows.o: windows.c $(HACK_H) $(INCL)/wingem.h $(INCL)/winGnome.h -$(O)wizard.o: wizard.c $(HACK_H) -$(O)worm.o: worm.c $(HACK_H) -$(O)worn.o: worn.c $(HACK_H) -$(O)write.o: write.c $(HACK_H) -$(O)zap.o: zap.c $(HACK_H) -$(O)pmatchre.o: $(SSHR)/pmatchre.c $(HACK_H) -$(O)tileset.o: $(WSHR)/tileset.c $(HACK_H) -$(O)bmptiles.o: $(WSHR)/bmptiles.c $(INCL)/config.h $(INCL)/tileset.h $(INCL)/integer.h -$(O)giftiles.o: $(WSHR)/giftiles.c $(INCL)/config.h $(INCL)/tileset.h $(INCL)/integer.h - -#end of file - diff --git a/sys/msdos/msdos-cross-compile.sh b/sys/msdos/fetch-cross-compiler.sh similarity index 65% rename from sys/msdos/msdos-cross-compile.sh rename to sys/msdos/fetch-cross-compiler.sh index 3de2b701b..fc78feae7 100644 --- a/sys/msdos/msdos-cross-compile.sh +++ b/sys/msdos/fetch-cross-compiler.sh @@ -7,21 +7,36 @@ else export DJGPP_TOP="$TRAVIS_BUILD_DIR/lib/djgpp" fi +if [ -z "$GCCVER" ]; then + export GCCVER=gcc1010 +fi + +if [ -z "$LUA_VERSION" ]; then + export LUA_VERSION=5.4.2 +fi + if [ ! -d "$(pwd)/lib" ]; then echo "Set up for Unix build and 'make fetch-lua' first." exit 1 fi -DJGPP_URL="https://github.com/andrewwutw/build-djgpp/releases/download/v2.9/" +#DJGPP_URL="https://github.com/andrewwutw/build-djgpp/releases/download/v2.9/" +DJGPP_URL="https://github.com/andrewwutw/build-djgpp/releases/download/v3.0/" if [ "$(uname)" = "Darwin" ]; then #Mac - DJGPP_FILE="djgpp-osx-gcc550.tar.bz2" + DJGPP_FILE="djgpp-osx-$GCCVER.tar.bz2" + if [ -z "HINTS" ]; then + export HINTS=macOS.2020 + fi elif [ "$(expr substr $(uname -s) 1 5)" = "Linux" ]; then #Linux - DJGPP_FILE="djgpp-linux64-gcc550.tar.bz2" + DJGPP_FILE="djgpp-linux64-$GCCVER.tar.bz2" + if [ -z "$HINTS" ]; then + export HINTS=linux.2020 + fi elif [ "$(expr substr $(uname -s) 1 10)" = "MINGW32_NT" ]; then #mingw - DJGPP_FILE="djgpp-mingw-gcc550-standalone.zip" + DJGPP_FILE="djgpp-mingw-$GCCVER-standalone.zip" else echo "No DJGPP release for you, sorry." exit 1 @@ -80,35 +95,3 @@ if [ ! -d "lib/lua-$LUA_VERSION/src" ]; then exit 0 fi -#echo after dos extender - -cd src - -mkdir -p ../msdos-binary -cp ../dat/data.base ../dat/data.bas -cp ../include/patchlevel.h ../include/patchlev.h -cp ../doc/Guidebook.txt ../doc/guidebk.txt -cp ../sys/share/posixregex.c ../sys/share/posixreg.c -#cp ../sys/msdos/Makefile1.cross ../src/Makefile1 -#cp ../sys/msdos/Makefile2.cross ../src/Makefile2 -make -f ../sys/msdos/Makefile1.cross -#cat ../include/date.h -export GCC_EXEC_PREFIX=$DJGPP_TOP/lib/gcc/ -# export - -#pwd - -make -f ../sys/msdos/Makefile2.cross -unset GCC_EXEC_PREFIX -#pwd - -if [ -f ../lib/djgpp/cwsdpmi/bin/CWSDPMI.EXE ]; then - cp ../lib/djgpp/cwsdpmi/bin/CWSDPMI.EXE ../msdos-binary/CWSDPMI.EXE; -fi - -# ls -l ../msdos-binary -cd ../msdos-binary -zip -9 ../lib/NH370DOS.ZIP * -cd ../ -ls -l lib/NH370DOS.ZIP - diff --git a/sys/msdos/msdos.c b/sys/msdos/msdos.c index c3230140e..0892566b9 100644 --- a/sys/msdos/msdos.c +++ b/sys/msdos/msdos.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 msdos.c $NHDT-Date: 1432512792 2015/05/25 00:13:12 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ */ +/* NetHack 3.7 msdos.c $NHDT-Date: 1596498269 2020/08/03 23:44:29 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.15 $ */ /* Copyright (c) NetHack PC Development Team 1990 */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/sys/msdos/msdoshlp.txt b/sys/msdos/msdoshlp.txt index cad9a17fb..441f3bb61 100644 --- a/sys/msdos/msdoshlp.txt +++ b/sys/msdos/msdoshlp.txt @@ -1,4 +1,4 @@ - MSDOS specific help file for NetHack 3.6 + MSDOS specific help file for NetHack 3.7 (Last Revision: December 4, 1999) Copyright (c) NetHack PC Development Team 1993-1999. diff --git a/sys/msdos/pckeys.c b/sys/msdos/pckeys.c index f07acd0c6..224c031d6 100644 --- a/sys/msdos/pckeys.c +++ b/sys/msdos/pckeys.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 pckeys.c $NHDT-Date: 1501465420 2017/07/31 01:43:40 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.12 $ */ +/* NetHack 3.7 pckeys.c $NHDT-Date: 1596498270 2020/08/03 23:44:30 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.14 $ */ /* Copyright (c) NetHack PC Development Team 1996 */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/sys/msdos/pctiles.c b/sys/msdos/pctiles.c index 7df6d9881..b7c7d7e4f 100644 --- a/sys/msdos/pctiles.c +++ b/sys/msdos/pctiles.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 pctiles.c $NHDT-Date: 1432512791 2015/05/25 00:13:11 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ */ +/* NetHack 3.7 pctiles.c $NHDT-Date: 1596498271 2020/08/03 23:44:31 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.13 $ */ /* Copyright (c) NetHack PC Development Team 1993, 1994 */ /* NetHack may be freely redistributed. See license for details. */ /* */ diff --git a/sys/msdos/pctiles.h b/sys/msdos/pctiles.h index e56812371..7fb7f7e3b 100644 --- a/sys/msdos/pctiles.h +++ b/sys/msdos/pctiles.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 pctiles.h $NHDT-Date: 1457207040 2016/03/05 19:44:00 $ $NHDT-Branch: chasonr $:$NHDT-Revision: 1.9 $ */ +/* NetHack 3.7 pctiles.h $NHDT-Date: 1596498272 2020/08/03 23:44:32 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.10 $ */ /* Copyright (c) NetHack PC Development Team 1993, 1994 */ /* NetHack may be freely redistributed. See license for details. */ /* */ diff --git a/sys/msdos/pcvideo.h b/sys/msdos/pcvideo.h index cfe45c1eb..1b21c652f 100644 --- a/sys/msdos/pcvideo.h +++ b/sys/msdos/pcvideo.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 pcvideo.h $NHDT-Date: 1457207040 2016/03/05 19:44:00 $ $NHDT-Branch: chasonr $:$NHDT-Revision: 1.9 $ */ +/* NetHack 3.7 pcvideo.h $NHDT-Date: 1596498273 2020/08/03 23:44:33 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.11 $ */ /* Copyright (c) NetHack PC Development Team 1993, 1994 */ /* NetHack may be freely redistributed. See license for details. */ /* */ diff --git a/sys/msdos/portio.h b/sys/msdos/portio.h index 97e023b6e..8907278b2 100644 --- a/sys/msdos/portio.h +++ b/sys/msdos/portio.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 portio.h $NHDT-Date: 1432512791 2015/05/25 00:13:11 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ +/* NetHack 3.7 portio.h $NHDT-Date: 1596498273 2020/08/03 23:44:33 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.10 $ */ /* Copyright (c) NetHack PC Development Team 1995 */ /* NetHack may be freely redistributed. See license for details. */ /* */ diff --git a/sys/msdos/setup.bat b/sys/msdos/setup.bat index 8c16863ae..41e213587 100755 --- a/sys/msdos/setup.bat +++ b/sys/msdos/setup.bat @@ -1,5 +1,5 @@ @echo off -REM NetHack 3.6 setup.bat $NHDT-Date: 1432512792 2015/05/25 00:13:12 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ +REM NetHack 3.7 setup.bat $NHDT-Date: 1596498274 2020/08/03 23:44:34 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.18 $ REM Copyright (c) NetHack PC Development Team 1990 - 2019 REM NetHack may be freely redistributed. See license for details. diff --git a/sys/msdos/tile2bin.c b/sys/msdos/tile2bin.c index 5d10248e4..a0b415291 100644 --- a/sys/msdos/tile2bin.c +++ b/sys/msdos/tile2bin.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 tile2bin.c $NHDT-Date: 1457207041 2016/03/05 19:44:01 $ $NHDT-Branch: chasonr $:$NHDT-Revision: 1.9 $ */ +/* NetHack 3.7 tile2bin.c $NHDT-Date: 1596498275 2020/08/03 23:44:35 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.11 $ */ /* Copyright (c) NetHack PC Development Team 1993, 1994, 1995 */ /* NetHack may be freely redistributed. See license for details. */ @@ -191,7 +191,7 @@ char *argv[]; tibheader.compiler = OTHER_COMP; #endif - strncpy(tibheader.ident, "NetHack 3.6 MSDOS Port binary tile file", 80); + strncpy(tibheader.ident, "NetHack 3.7 MSDOS Port binary tile file", 80); strncpy(tibheader.timestamp, asctime(newtime), 24); tibheader.timestamp[25] = '\0'; tibheader.tilecount = tilecount; diff --git a/sys/msdos/vesa.h b/sys/msdos/vesa.h index 1184a42ca..3056b07a0 100644 --- a/sys/msdos/vesa.h +++ b/sys/msdos/vesa.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 vesa.h $NHDT-Date: 1507161296 2017/10/04 23:54:56 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.0 $ */ +/* NetHack 3.7 vesa.h $NHDT-Date: 1596498276 2020/08/03 23:44:36 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.0 $ */ /* VESA structures from the VESA BIOS Specification, retrieved 15 Jan 2016 * from http://flint.cs.yale.edu/cs422/readings/hardware/vbe3.pdf diff --git a/sys/msdos/video.c b/sys/msdos/video.c index 21b400152..0ab576f14 100644 --- a/sys/msdos/video.c +++ b/sys/msdos/video.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 video.c $NHDT-Date: 1554215931 2019/04/02 14:38:51 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.12 $ */ +/* NetHack 3.7 video.c $NHDT-Date: 1596498277 2020/08/03 23:44:37 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.16 $ */ /* Copyright (c) NetHack PC Development Team 1993, 1994, 2001 */ /* NetHack may be freely redistributed. See license for details. */ /* */ diff --git a/sys/msdos/vidtxt.c b/sys/msdos/vidtxt.c index 6dd23832b..90c4cc44e 100644 --- a/sys/msdos/vidtxt.c +++ b/sys/msdos/vidtxt.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 vidtxt.c $NHDT-Date: 1457207043 2016/03/05 19:44:03 $ $NHDT-Branch: chasonr $:$NHDT-Revision: 1.11 $ */ +/* NetHack 3.7 vidtxt.c $NHDT-Date: 1596498278 2020/08/03 23:44:38 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.12 $ */ /* Copyright (c) NetHack PC Development Team 1993 */ /* NetHack may be freely redistributed. See license for details. */ /* */ diff --git a/sys/msdos/vidvesa.c b/sys/msdos/vidvesa.c index a631dc2e8..125cf712d 100644 --- a/sys/msdos/vidvesa.c +++ b/sys/msdos/vidvesa.c @@ -76,7 +76,6 @@ extern int attrib_text_normal; /* text mode normal attribute */ extern int attrib_gr_normal; /* graphics mode normal attribute */ extern int attrib_gr_intense; /* graphics mode intense attribute */ extern boolean inmap; /* in the map window */ -/* extern boolean g.restoring; */ /* * Global Variables @@ -701,6 +700,7 @@ unsigned special; /* special feature: corpse, invis, detected, pet, ridden - int col, row; int attr; int ry; + int tilenum = 0; row = currow; col = curcol; @@ -722,7 +722,10 @@ unsigned special; /* special feature: corpse, invis, detected, pet, ridden - if (!iflags.over_view && map[ry][col].special) decal_packed(packcell, special); #endif - vesa_DisplayCell(glyph2tile[glyphnum], col - clipx, ry - clipy); + tilenum = glyph2tile[glyphnum]; + if (map[ry][col].special & MG_FEMALE) + tilenum++; + vesa_DisplayCell(tilenum, col - clipx, ry - clipy); } } if (col < (CO - 1)) @@ -786,7 +789,7 @@ int x, y; clipymax = ROWNO - 1; } if (clipx != oldx || clipy != oldy) { - if (on_level(&u.uz0, &u.uz) && !g.restoring) + if (on_level(&u.uz0, &u.uz) && !g.program_state.restoring) /* (void) doredraw(); */ vesa_redrawmap(); } diff --git a/sys/msdos/vidvga.c b/sys/msdos/vidvga.c index 768f8d619..621cf1d9a 100644 --- a/sys/msdos/vidvga.c +++ b/sys/msdos/vidvga.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 vidvga.c $NHDT-Date: 1457207044 2016/03/05 19:44:04 $ $NHDT-Branch: chasonr $:$NHDT-Revision: 1.18 $ */ +/* NetHack 3.7 vidvga.c $NHDT-Date: 1606765216 2020/11/30 19:40:16 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.26 $ */ /* Copyright (c) NetHack PC Development Team 1995 */ /* NetHack may be freely redistributed. See license for details. */ /* @@ -430,7 +430,6 @@ static void vga_cliparound(x, y) int x, y; { -/* extern boolean g.restoring; */ int oldx = clipx; if (!iflags.tile_view || iflags.over_view || iflags.traditional_view) @@ -444,7 +443,7 @@ int x, y; clipx = clipxmax - (viewport_size - 1); } if (clipx != oldx) { - if (on_level(&u.uz0, &u.uz) && !g.restoring) + if (on_level(&u.uz0, &u.uz) && !g.program_state.restoring) /* (void) doredraw(); */ vga_redrawmap(1); } @@ -689,6 +688,7 @@ unsigned char (*indexes)[TILE_X]; { const struct TileImage *tile; unsigned x, y; + int row, col, ry, tilenum = 0; /* We don't have enough colors to show the statues */ if (glyph >= GLYPH_STATUE_OFF) { @@ -696,7 +696,16 @@ unsigned char (*indexes)[TILE_X]; } /* Get the tile from the image */ - tile = get_tile(glyph2tile[glyph]); + tilenum = glyph2tile[glyph]; + row = currow; + col = curcol; + if ((col < 0 || col >= COLNO) + || (row < TOP_MAP_ROW || row >= (ROWNO + TOP_MAP_ROW))) + return; + ry = row - TOP_MAP_ROW; + if (map[ry][col].special & MG_FEMALE) + tilenum++; + tile = get_tile(tilenum); /* Map to a 16 bit palette; assume colors laid out as in default tileset */ memset(indexes, 0, sizeof(indexes)); diff --git a/sys/share/Makefile.lib b/sys/share/Makefile.lib index 1774a45ba..8118a1af7 100644 --- a/sys/share/Makefile.lib +++ b/sys/share/Makefile.lib @@ -1,4 +1,4 @@ -# NetHack 3.6 Makefile.lib $NHDT-Date: 1432512788 2015/05/25 00:13:08 $ $NHDT-Branch: master $:$NHDT-Revision: 1.7 $ +# NetHack 3.7 Makefile.lib $NHDT-Date: 1596498281 2020/08/03 23:44:41 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.8 $ # Nethack makefile for Fred fish termlib -- Norman Meluch # CC = cl /c diff --git a/sys/share/cppregex.cpp b/sys/share/cppregex.cpp index cba44b88a..c3ce58ced 100644 --- a/sys/share/cppregex.cpp +++ b/sys/share/cppregex.cpp @@ -1,5 +1,5 @@ -/* NetHack 3.6 cppregex.cpp */ -/* $NHDT-Date: 1524684157 2018/04/25 19:22:37 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.8 $ */ +/* NetHack 3.7 cppregex.cpp */ +/* $NHDT-Date: 1596498279 2020/08/03 23:44:39 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.9 $ */ /* Copyright (c) Sean Hunt 2015. */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/sys/share/ioctl.c b/sys/share/ioctl.c index 8b2c91712..b391c1f07 100644 --- a/sys/share/ioctl.c +++ b/sys/share/ioctl.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 ioctl.c $NHDT-Date: 1520099308 2018/03/03 17:48:28 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.13 $ */ +/* NetHack 3.7 ioctl.c $NHDT-Date: 1596498280 2020/08/03 23:44:40 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.15 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Kenneth Lorber, Kensington, Maryland, 2015. */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/sys/share/nhlan.c b/sys/share/nhlan.c index 970c35fbc..f3e75e360 100644 --- a/sys/share/nhlan.c +++ b/sys/share/nhlan.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 nhlan.c $NHDT-Date: 1432512786 2015/05/25 00:13:06 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ */ +/* NetHack 3.7 nhlan.c $NHDT-Date: 1596498282 2020/08/03 23:44:42 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.11 $ */ /* Copyright (c) Michael Allison, 1997 */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/sys/share/pcmain.c b/sys/share/pcmain.c index e73a2427b..2367c84ea 100644 --- a/sys/share/pcmain.c +++ b/sys/share/pcmain.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 pcmain.c $NHDT-Date: 1593953369 2020/07/05 12:49:29 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.120 $ */ +/* NetHack 3.7 pcmain.c $NHDT-Date: 1596498282 2020/08/03 23:44:42 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.121 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Derek S. Ray, 2015. */ /* NetHack may be freely redistributed. See license for details. */ @@ -268,7 +268,7 @@ _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);*/ if (argc == 0) chdirx(HACKDIR, 1); #endif - ami_wininit_data(); + ami_wininit_data(WININIT); #endif initoptions(); @@ -754,4 +754,40 @@ char *str; } #endif /* EXEPATH */ +#ifdef CROSS_TO_AMIGA +void msmsg +VA_DECL(const char *, fmt) +{ + VA_START(fmt); + VA_INIT(fmt, const char *); + Vprintf(fmt, VA_ARGS); + flushout(); + VA_END(); + return; +} + +unsigned long +sys_random_seed() +{ + unsigned long seed = 0L; + unsigned long pid = (unsigned long) getpid(); + boolean no_seed = TRUE; + +#ifdef AMIGA_STRONG_RANDOM_SEED_HERE + /* hypothetical - strong seed code is required */ + /* then has_strong_seed could be set */ +#endif + if (no_seed) { + seed = (unsigned long) getnow(); /* time((TIME_type) 0) */ + /* Quick dirty band-aid to prevent PRNG prediction */ + if (pid) { + if (!(pid & 3L)) + pid -= 1L; + seed *= pid; + } + } + return seed; +} +#endif + /*pcmain.c*/ diff --git a/sys/share/pcsys.c b/sys/share/pcsys.c index f191d1f25..af30e4423 100644 --- a/sys/share/pcsys.c +++ b/sys/share/pcsys.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 pcsys.c $NHDT-Date: 1593953370 2020/07/05 12:49:30 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.41 $ */ +/* NetHack 3.7 pcsys.c $NHDT-Date: 1596498283 2020/08/03 23:44:43 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.42 $ */ /* Copyright (c) 2012 by Michael Allison */ /* NetHack may be freely redistributed. See license for details. */ @@ -12,10 +12,10 @@ #include #include -#if !defined(MSDOS) && !defined(WIN_CE) /* already done */ +#if !defined(MSDOS) && !defined(WIN_CE) && !defined(CROSS_TO_AMIGA) #include #endif -#ifdef __GO32__ +#if defined(__GO32__) || defined(CROSS_TO_AMIGA) #define P_WAIT 0 #define P_NOWAIT 1 #endif @@ -153,8 +153,12 @@ const char *str; { #ifdef TOS msmsg("Hit %s.", str); +#else +#ifdef CROSS_TO_AMIGA + (void) printf("Hit %s.", str); #else msmsg("Hit %s.", str); +#endif #endif while (pgetchar() != '\n') ; diff --git a/sys/share/pctty.c b/sys/share/pctty.c index cd7d65588..75e38e9ab 100644 --- a/sys/share/pctty.c +++ b/sys/share/pctty.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 pctty.c $NHDT-Date: 1432512787 2015/05/25 00:13:07 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ */ +/* NetHack 3.7 pctty.c $NHDT-Date: 1596498284 2020/08/03 23:44:44 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.13 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2005. */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/sys/share/pcunix.c b/sys/share/pcunix.c index 8956ba3bc..2ea4e38dd 100644 --- a/sys/share/pcunix.c +++ b/sys/share/pcunix.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 pcunix.c $NHDT-Date: 1432512787 2015/05/25 00:13:07 $ $NHDT-Branch: master $:$NHDT-Revision: 1.34 $ */ +/* NetHack 3.7 pcunix.c $NHDT-Date: 1596498285 2020/08/03 23:44:45 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.42 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2006. */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/sys/share/pmatchregex.c b/sys/share/pmatchregex.c index cb3d58455..0d688d330 100644 --- a/sys/share/pmatchregex.c +++ b/sys/share/pmatchregex.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 pmatchregex.c $NHDT-Date: 1544482890 2018/12/10 23:01:30 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.2 $ */ +/* NetHack 3.7 pmatchregex.c $NHDT-Date: 1596498285 2020/08/03 23:44:45 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.4 $ */ /* Copyright (c) Sean Hunt 2015. */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/sys/share/posixregex.c b/sys/share/posixregex.c index 0b4ba218d..d681a5b9a 100644 --- a/sys/share/posixregex.c +++ b/sys/share/posixregex.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 posixregex.c $NHDT-Date: 1434446947 2015/06/16 09:29:07 $ $NHDT-Branch: master $:$NHDT-Revision: 1.5 $ */ +/* NetHack 3.7 posixregex.c $NHDT-Date: 1596498286 2020/08/03 23:44:46 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.7 $ */ /* Copyright (c) Sean Hunt 2015. */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/sys/share/tclib.c b/sys/share/tclib.c index b47f41815..75ce78151 100644 --- a/sys/share/tclib.c +++ b/sys/share/tclib.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 tclib.c $NHDT-Date: 1432512788 2015/05/25 00:13:08 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ +/* NetHack 3.7 tclib.c $NHDT-Date: 1596498287 2020/08/03 23:44:47 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.10 $ */ /* Copyright (c) Robert Patrick Rankin, 1995 */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/sys/share/unixtty.c b/sys/share/unixtty.c index 3196f3b3d..cc6a088ca 100644 --- a/sys/share/unixtty.c +++ b/sys/share/unixtty.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 unixtty.c $NHDT-Date: 1570652308 2019/10/09 20:18:28 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.26 $ */ +/* NetHack 3.7 unixtty.c $NHDT-Date: 1596498288 2020/08/03 23:44:48 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.27 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2006. */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/sys/unix/Makefile.dat b/sys/unix/Makefile.dat index 0508974e9..a264242ae 100644 --- a/sys/unix/Makefile.dat +++ b/sys/unix/Makefile.dat @@ -1,4 +1,4 @@ -# NetHack Datafiles Makefile.dat $NHDT-Date: 1447844574 2018/04/25 19:25:54 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.22 $ +# NetHack Datafiles Makefile.dat $NHDT-Date: 1596486993 2020/08/03 20:36:33 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.32 $ # Copyright (c) 2018 by Pasi Kallinen # NetHack may be freely redistributed. See license for details. @@ -116,18 +116,21 @@ bogusmon: bogusmon.txt ../util/makedefs options: ../util/makedefs ../util/makedefs -v - +# these don't actually do anything useful now that levcomp and dngcomp are gone spec_levs: touch spec_levs - quest_levs: touch quest_levs # gitinfo.txt is optionally made by src/Makefile when creating date.h +# spec_levs and quest_levs are empty marker files to control 'make' actions clean: - -rm -f gitinfo.txt + -rm -f spec_levs quest_levs gitinfo.txt spotless: clean - -rm -f nhdat x11tiles beostiles pet_mark.xbm pilemark.xbm rip.xpm mapbg.xpm - -rm -f rip.img GEM_RSC.RSC title.img nh16.img NetHack.ad - -rm -f nhsplash.xpm nhtiles.bmp + -rm -f nhdat $(VARDAT) \ + x11tiles pet_mark.xbm pilemark.xbm rip.xpm mapbg.xpm \ + rip.img GEM_RSC.RSC title.img nh16.img NetHack.ad \ + nhsplash.xpm nhtiles.bmp beostiles + +#eof# diff --git a/sys/unix/Makefile.doc b/sys/unix/Makefile.doc index 35666a5cc..d1c3c1831 100644 --- a/sys/unix/Makefile.doc +++ b/sys/unix/Makefile.doc @@ -1,5 +1,5 @@ # NetHack Documentation Makefile. -# NetHack 3.6 Makefile.doc $NHDT-Date: 1581732920 2020/02/15 02:15:20 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.20 $ +# NetHack 3.7 Makefile.doc $NHDT-Date: 1596498290 2020/08/03 23:44:50 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.21 $ # Copyright (c) 2015 by Kenneth Lorber, Kensington, Maryland # NetHack may be freely redistributed. See license for details. diff --git a/sys/unix/Makefile.src b/sys/unix/Makefile.src index c7c955888..315d7dd28 100644 --- a/sys/unix/Makefile.src +++ b/sys/unix/Makefile.src @@ -1,5 +1,5 @@ # NetHack Makefile. -# NetHack 3.6 Makefile.src $NHDT-Date: 1588776919 2020/05/06 14:55:19 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.97 $ +# NetHack 3.7 Makefile.src $NHDT-Date: 1601854487 2020/10/04 23:34:47 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.111 $ # Copyright (c) 2018 by Pasi Kallinen # NetHack may be freely redistributed. See license for details. @@ -43,22 +43,29 @@ SHELL=/bin/sh # Usually, the C compiler driver is used for linking: #LINK=$(CC) +# If we're cross-compiling, a hints file will override this +# to a uniq target directory, but otherwise it just goes in +# ../src +TARGETPFX= + # Pick the SYSSRC and SYSOBJ lines corresponding to your desired operating # system. # # for UNIX systems SYSSRC = ../sys/share/ioctl.c ../sys/share/unixtty.c ../sys/unix/unixmain.c \ ../sys/unix/unixunix.c ../sys/unix/unixres.c -SYSOBJ = ioctl.o unixmain.o unixtty.o unixunix.o unixres.o ../lib/lua/liblua.a +SYSOBJ = $(TARGETPFX)ioctl.o $(TARGETPFX)unixmain.o $(TARGETPFX)unixtty.o \ + $(TARGETPFX)unixunix.o $(TARGETPFX)unixres.o # # for Systos # SYSSRC = ../sys/atari/tos.c ../sys/share/pcmain.c ../sys/share/pcsys.c \ # ../sys/share/pctty.c ../sys/share/pcunix.c -# SYSOBJ = tos.o pcmain.o pcsys.o pctty.o pcunix.o +# SYSOBJ = $(TARGETPFX)tos.o $(TARGETPFX)pcmain.o $(TARGETPFX)pcsys.o \ +# $(TARGETPFX)pctty.o $(TARGETPFX)pcunix.o # # for BeOS #SYSSRC = ../sys/be/bemain.c ../sys/share/unixtty.c ../sys/share/ioctl.c -#SYSOBJ = bemain.o unixtty.o ioctl.o +#SYSOBJ = $(TARGETPFX)bemain.o $(TARGETPFX)unixtty.o $(TARGETPFX)ioctl.o # if you are using gcc as your compiler: @@ -153,7 +160,7 @@ SYSOBJ = ioctl.o unixmain.o unixtty.o unixunix.o unixres.o ../lib/lua/liblua.a #CFLAGS = -O -DXCURSES -I../include -I/usr/local/include/pdcurses # Compile against system curses library, such as ncurses #CFLAGS = -O -I../include - +# # files in ../win/X11 (relative to src) are passed $(CFLAGS) $(X11CFLAGS) # and by default will find in /usr/include/X11/foo.h; # can be overridden via hints; post-10.7 OSX with XQuartz uses @@ -165,7 +172,7 @@ SYSOBJ = ioctl.o unixmain.o unixtty.o unixunix.o unixres.o ../lib/lua/liblua.a # directories. The ones given below is the usual spot for linux systems. # The paths are for glibconfig.h and gnomesupport.h respectively. # -GNOMEINC=-I/usr/lib/glib/include -I/usr/lib/gnome-libs/include -I../win/gnome +#GNOMEINC=-I/usr/lib/glib/include -I/usr/lib/gnome-libs/include -I../win/gnome # flags for debugging: # CFLAGS = -g -I../include @@ -173,19 +180,24 @@ GNOMEINC=-I/usr/lib/glib/include -I/usr/lib/gnome-libs/include -I../win/gnome #CFLAGS = -O -I../include #LFLAGS = -# -lm required by lua -LIBS += -lm - # The Qt and Be window systems are written in C++, while the rest of # NetHack is standard C. If using Qt, uncomment the LINK line here to get # the C++ libraries linked in. -CXXFLAGS = $(CFLAGS) -I. -I$(QTDIR)/include +CXXFLAGS = $(CFLAGS) -I. -I$(QTDIR)/include $(QTCXXFLAGS) CXX ?= g++ MOC ?= moc #LINK=g++ -# For cross-compiling, eg. with gcc on Linux (see also CC further up): -#CXX=arm-linux-g++ -#LINK=arm-linux-gcc + +# The default is for the TARGET_* variables to match the defaults. +# If we're cross-compiling these will get overridden elsewhere, likely via +# a hints file. TARGETPFX was set above earlier. +TARGET_CC = $(CC) +TARGET_CFLAGS = $(CFLAGS) +TARGET_LINK = $(LINK) +TARGET_LFLAGS = $(LFLAGS) +TARGET_CXX = $(CXX) +TARGET_CXXFLAGS = $(CXXFLAGS) +TARGET_LIBS = $(LIBS) # we specify C preprocessor flags via CFLAGS; files built with default rules # might include $(CPPFLAGS) which could get a value from user's environment; @@ -193,9 +205,9 @@ MOC ?= moc CPPFLAGS = # file for regular expression matching -REGEXOBJ = posixregex.o -#REGEXOBJ = pmatchregex.o -#REGEXOBJ = cppregex.o +REGEXOBJ = $(TARGETPFX)posixregex.o +#REGEXOBJ = $(TARGETPFX)pmatchregex.o +#REGEXOBJ = $(TARGETPFX)cppregex.o # Set the WINSRC, WINOBJ, and WINLIB lines to correspond to your desired # combination of windowing systems. Also set windowing systems in config.h. @@ -205,15 +217,18 @@ REGEXOBJ = posixregex.o # files for a straight tty port using no native windowing system WINTTYSRC = ../win/tty/getline.c ../win/tty/termcap.c ../win/tty/topl.c \ ../win/tty/wintty.c -WINTTYOBJ = getline.o termcap.o topl.o wintty.o +WINTTYOBJ = $(TARGETPFX)getline.o $(TARGETPFX)termcap.o $(TARGETPFX)topl.o \ + $(TARGETPFX)wintty.o # # Files for curses interface WINCURSESSRC = ../win/curses/cursmain.c ../win/curses/curswins.c \ ../win/curses/cursmisc.c ../win/curses/cursdial.c \ ../win/curses/cursstat.c ../win/curses/cursinit.c \ ../win/curses/cursmesg.c ../win/curses/cursinvt.c -WINCURSESOBJ = cursmain.o curswins.o cursmisc.o cursdial.o cursstat.o \ - cursinit.o cursmesg.o cursinvt.o +WINCURSESOBJ = $(TARGETPFX)cursmain.o $(TARGETPFX)curswins.o \ + $(TARGETPFX)cursmisc.o $(TARGETPFX)cursdial.o \ + $(TARGETPFX)cursstat.o $(TARGETPFX)cursinit.o \ + $(TARGETPFX)cursmesg.o $(TARGETPFX)cursinvt.o # # files for an X11 port # (tile.c is a generated source file) @@ -221,14 +236,21 @@ WINX11SRC = ../win/X11/Window.c ../win/X11/dialogs.c ../win/X11/winX.c \ ../win/X11/winmap.c ../win/X11/winmenu.c ../win/X11/winmesg.c \ ../win/X11/winmisc.c ../win/X11/winstat.c ../win/X11/wintext.c \ ../win/X11/winval.c tile.c -WINX11OBJ = Window.o dialogs.o winX.o winmap.o winmenu.o winmesg.o \ - winmisc.o winstat.o wintext.o winval.o tile.o +WINX11OBJ = $(TARGETPFX)Window.o $(TARGETPFX)dialogs.o $(TARGETPFX)winX.o \ + $(TARGETPFX)winmap.o $(TARGETPFX)winmenu.o $(TARGETPFX)winmesg.o \ + $(TARGETPFX)winmisc.o $(TARGETPFX)winstat.o $(TARGETPFX)wintext.o \ + $(TARGETPFX)winval.o $(TARGETPFX)tile.o # # Files for a Qt 3 port (renamed since nethack 3.6.x) # -WINQT3SRC = ../win/Qt3/qt3_win.cpp ../win/Qt3/qt3_clust.cpp \ - ../win/Qt3/qt3tableview.cpp -WINQT3OBJ = qt3_win.o qt3_clust.o qt3tableview.o tile.o +#WINQT3SRC = ../win/Qt3/qt3_win.cpp ../win/Qt3/qt3_clust.cpp \ +# ../win/Qt3/qt3tableview.cpp +#WINQT3OBJ = $(TARGETPFX)qt3_win.o $(TARGETPFX)qt3_clust.o \ + $(TARGETPFX)qt3tableview.o $(TARGETPFX)tile.o +# empty values for 'make depend' +WINQT3SRC = +WINQT3OBJ = + # # Files for a Qt 4 or 5 port # @@ -241,34 +263,58 @@ WINQTSRC = ../win/Qt/qt_bind.cpp ../win/Qt/qt_click.cpp \ ../win/Qt/qt_stat.cpp ../win/Qt/qt_str.cpp ../win/Qt/qt_streq.cpp \ ../win/Qt/qt_svsel.cpp ../win/Qt/qt_win.cpp ../win/Qt/qt_xcmd.cpp \ ../win/Qt/qt_yndlg.cpp -WINQTOBJ = qt_bind.o qt_click.o qt_clust.o qt_delay.o qt_glyph.o qt_icon.o \ - qt_inv.o qt_key.o qt_line.o qt_main.o qt_map.o qt_menu.o qt_msg.o \ - qt_plsel.o qt_rip.o qt_set.o qt_stat.o qt_str.o qt_streq.o qt_svsel.o \ - qt_win.o qt_xcmd.o qt_yndlg.o tile.o +WINQTOBJ = $(TARGETPFX)qt_bind.o $(TARGETPFX)qt_click.o \ + $(TARGETPFX)qt_clust.o $(TARGETPFX)qt_delay.o \ + $(TARGETPFX)qt_glyph.o $(TARGETPFX)qt_icon.o \ + $(TARGETPFX)qt_inv.o $(TARGETPFX)qt_key.o $(TARGETPFX)qt_line.o \ + $(TARGETPFX)qt_main.o $(TARGETPFX)qt_map.o $(TARGETPFX)qt_menu.o \ + $(TARGETPFX)qt_msg.o $(TARGETPFX)qt_plsel.o $(TARGETPFX)qt_rip.o \ + $(TARGETPFX)qt_set.o $(TARGETPFX)qt_stat.o $(TARGETPFX)qt_str.o \ + $(TARGETPFX)qt_streq.o $(TARGETPFX)qt_svsel.o $(TARGETPFX)qt_win.o \ + $(TARGETPFX)qt_xcmd.o $(TARGETPFX)qt_yndlg.o $(TARGETPFX)tile.o # # Files for a Gnome port # -WINGNOMESRC = ../win/gnome/gnaskstr.c ../win/gnome/gnbind.c \ - ../win/gnome/gnglyph.c ../win/gnome/gnmain.c ../win/gnome/gnmap.c \ - ../win/gnome/gnmenu.c ../win/gnome/gnmesg.c ../win/gnome/gnopts.c \ - ../win/gnome/gnplayer.c ../win/gnome/gnsignal.c \ - ../win/gnome/gnstatus.c ../win/gnome/gntext.c ../win/gnome/gnyesno.c \ - ../win/gnome/gnworn.c -WINGNOMEOBJ = gnaskstr.o gnbind.o gnglyph.o gnmain.o gnmap.o gnmenu.o \ - gnmesg.o gnopts.o gnplayer.o gnsignal.o gnstatus.o gntext.o \ - gnyesno.o gnworn.o tile.o +#WINGNOMESRC = ../win/gnome/gnaskstr.c ../win/gnome/gnbind.c \ +# ../win/gnome/gnglyph.c ../win/gnome/gnmain.c ../win/gnome/gnmap.c \ +# ../win/gnome/gnmenu.c ../win/gnome/gnmesg.c ../win/gnome/gnopts.c \ +# ../win/gnome/gnplayer.c ../win/gnome/gnsignal.c \ +# ../win/gnome/gnstatus.c ../win/gnome/gntext.c ../win/gnome/gnyesno.c \ +# ../win/gnome/gnworn.c +#WINGNOMEOBJ = $(TARGETPFX)gnaskstr.o $(TARGETPFX)gnbind.o $(TARGETPFX)gnglyph.o \ +# $(TARGETPFX)gnmain.o $(TARGETPFX)gnmap.o $(TARGETPFX)gnmenu.o \ +# $(TARGETPFX)gnmesg.o $(TARGETPFX)gnopts.o $(TARGETPFX)gnplayer.o \ +# $(TARGETPFX)gnsignal.o $(TARGETPFX)gnstatus.o $(TARGETPFX)gntext.o \ +# $(TARGETPFX)gnyesno.o $(TARGETPFX)gnworn.o $(TARGETPFX)tile.o +# empty values for 'make depend' +WINGNOMESRC = +WINGNOMEOBJ = + # # Files for a Gem port -WINGEMSRC = ../win/gem/wingem.c ../win/gem/wingem1.c ../win/gem/load_img.c \ - ../win/gem/gr_rect.c tile.c -WINGEMOBJ = wingem.o wingem1.o load_img.o gr_rect.o tile.o +#WINGEMSRC = ../win/gem/wingem.c ../win/gem/wingem1.c ../win/gem/load_img.c \ +# ../win/gem/gr_rect.c tile.c +#WINGEMOBJ = $(TARGETPFX)wingem.o $(TARGETPFX)wingem1.o \ +# $(TARGETPFX)load_img.o $(TARGETPFX)gr_rect.o $(TARGETPFX)tile.o +# empty values for 'make depend' +WINGEMSRC = +WINGEMOBJ = + +# Files for Shim windowing interface for libnh -- doesn't do anything, +# just passes along the API calls to the library +# +WINSHIMSRC = ../win/shim/winshim.c +WINSHIMOBJ = winshim.o + # # Files for a BeOS InterfaceKit port -- not ready for prime time WINBESRC = WINBEOBJ = #WINBESRC = ../win/BeOS/winbe.cpp ../win/BeOS/NHWindow.cpp \ # ../win/BeOS/NHMenuWindow.cpp ../win/BeOS/NHMapWindow.cpp tile.c -#WINBEOBJ = winbe.o NHWindow.o NHMenuWindow.o NHMapWindow.o tile.o +#WINBEOBJ = $(TARGETPFX)winbe.o $(TARGETPFX)NHWindow.o \ +# $(TARGETPFX)NHMenuWindow.o $(TARGETPFX)NHMapWindow.o \ +# $(TARGETPFX)tile.o # # #WINSRC = $(WINTTYSRC) @@ -336,6 +382,9 @@ WINCURSESLIB = -lncurses # For Curses #WINLIB = $(WINCURSESLIB) # +# some platforms need to build the support libraries +# BUILDMORE = $(TARGETPFX)pdcurses.a + # any other strange libraries your system needs (for Sysunix only -- the more # specialized targets should already be right) # @@ -369,15 +418,16 @@ WINCURSESLIB = -lncurses # make NetHack GAME = nethack # GAME = nethack.prg +GAMEBIN = $(GAME) # if you defined RANDOM in unixconf.h since your system did not come # with a reasonable random number generator -# RANDOBJ = random.o +# RANDOBJ = $(TARGETPFX)random.o RANDOBJ = - # used by `make depend' to reconstruct this Makefile; you shouldn't need this -AWK = nawk +# at all but can override with 'make AWK=nawk' or 'make AWK=gawk' if necessary +AWK = awk # when using 'makedefs -v', also force dat/gitinfo.txt to be up to date; # changing this to 0 will change the behavior to only make that file if @@ -403,6 +453,10 @@ QUIETCC=0 # Other things that have to be reconfigured are in config.h, # {unixconf.h, pcconf.h}, and possibly system.h +# Add rule for possible cross-compiler +$(TARGETPFX)%.o : %.c + $(TARGET_CC) $(TARGET_CFLAGS) -c -o $@ $< + # Verbosity definitions, begin # Set QUIETCC=1 above to output less feedback while building. # CC and CXX obey verbosity, LD and LINK don't. @@ -433,8 +487,18 @@ AT_V1 := @ AT = $(AT_V$(QUIETCC)) # Verbosity, end +# verbosity-adjacent; these will already have 'real' values if hints have +# set up cross-compiling, in which case these assignments will be no-ops +PREGAME=@true +CLEANMORE=@true +PACKAGE=@true + + MAKEDEFS = ../util/makedefs +# -lm required by lua +LUALIB = ../lib/lua/liblua.a -lm + # timestamp files to reduce `make' overhead and shorten .o dependency lists CONFIG_H = ../src/config.h-t HACK_H = ../src/hack.h-t @@ -461,26 +525,27 @@ HACKCSRC = allmain.c alloc.c apply.c artifact.c attrib.c ball.c bones.c \ windows.c wizard.c worm.c worn.c write.c zap.c # all operating-system-dependent .c (for dependencies and such) -SYSCSRC = ../sys/atari/tos.c ../sys/share/pcmain.c ../sys/share/pcsys.c \ +SYSCSRC = ../sys/share/pcmain.c ../sys/share/pcsys.c \ ../sys/share/pctty.c ../sys/share/pcunix.c \ ../sys/share/pmatchregex.c ../sys/share/posixregex.c \ ../sys/share/random.c \ ../sys/share/ioctl.c ../sys/share/unixtty.c ../sys/unix/unixmain.c \ - ../sys/unix/unixunix.c ../sys/unix/unixres.c ../sys/be/bemain.c + ../sys/unix/unixunix.c ../sys/unix/unixres.c SYSCXXSRC = ../sys/share/cppregex.cpp # generated source files (tile.c is handled separately via WINxxxSRC) -GENCSRC = vis_tab.c #tile.c +GENCSRC = #tile.c # all windowing-system-dependent .c (for dependencies and such) -WINCSRC = $(WINTTYSRC) $(WINCURSESSRC) $(WINX11SRC) $(WINGNOMESRC) $(WINGEMSRC) +WINCSRC = $(WINTTYSRC) $(WINCURSESSRC) $(WINX11SRC) $(WINGNOMESRC) $(WINGEMSRC) $(WINSHIMSRC) # all windowing-system-dependent .cpp (for dependencies and such) WINCXXSRC = $(WINQTSRC) $(WINQT3SRC) $(WINBESRC) # Files for window system chaining. Requires SYSCF; include via HINTSRC/HINTOBJ CHAINSRC = ../win/chain/wc_chainin.c ../win/chain/wc_chainout.c \ ../win/chain/wc_trace.c -CHAINOBJ = wc_chainin.o wc_chainout.o wc_trace.o +CHAINOBJ = $(TARGETPFX)wc_chainin.o $(TARGETPFX)wc_chainout.o \ + $(TARGETPFX)wc_trace.o # .c files for this version (for date.h) VERSOURCES = $(HACKCSRC) $(SYSSRC) $(WINSRC) $(CHAINSRC) $(GENCSRC) @@ -489,7 +554,7 @@ VERSOURCES = $(HACKCSRC) $(SYSSRC) $(WINSRC) $(CHAINSRC) $(GENCSRC) CSOURCES = $(HACKCSRC) $(SYSCSRC) $(WINCSRC) $(CHAINSRC) $(GENCSRC) -# all .h files except date.h, onames.h, pm.h, and vis_tab.h which would +# all .h files except date.h, onames.h, and pm.h which would # cause dependency loops if run through "make depend" # and dgn_file.h, special level & dungeon files. # @@ -501,69 +566,102 @@ HACKINCL = align.h artifact.h artilist.h attrib.h botl.h \ monattk.h mondata.h monflag.h monst.h monsym.h obj.h objclass.h \ optlist.h patchlevel.h pcconf.h permonst.h prop.h rect.h \ region.h rm.h sp_lev.h spell.h sys.h system.h tcap.h timeout.h \ - tradstdc.h trampoli.h trap.h unixconf.h vision.h vmsconf.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 -HSOURCES = $(HACKINCL) date.h onames.h pm.h vis_tab.h dgn_file.h +HSOURCES = $(HACKINCL) date.h onames.h pm.h dgn_file.h # the following .o's _must_ be made before any others (for makedefs) FIRSTOBJ = monst.o objects.o +HOSTOBJ = $(FIRSTOBJ) alloc.o drawing.o -HOBJ = $(FIRSTOBJ) allmain.o alloc.o apply.o artifact.o attrib.o ball.o \ - bones.o botl.o cmd.o dbridge.o decl.o detect.o dig.o display.o dlb.o \ - do.o do_name.o do_wear.o dog.o dogmove.o dokick.o dothrow.o \ - drawing.o dungeon.o eat.o end.o engrave.o exper.o explode.o \ - extralev.o files.o fountain.o hack.o hacklib.o \ - insight.o invent.o isaac64.o \ - light.o lock.o mail.o makemon.o mapglyph.o mcastu.o mdlib.o mhitm.o \ - mhitu.o minion.o mklev.o mkmap.o mkmaze.o mkobj.o mkroom.o mon.o \ - mondata.o monmove.o mplayer.o mthrowu.o muse.o music.o \ - nhlua.o nhlsel.o nhlobj.o o_init.o objnam.o options.o \ - pager.o pickup.o pline.o polyself.o potion.o pray.o priest.o \ - quest.o questpgr.o read.o rect.o region.o restore.o rip.o rnd.o \ - role.o rumors.o save.o sfstruct.o \ - shk.o shknam.o sit.o sounds.o sp_lev.o spell.o symbols.o sys.o \ - steal.o steed.o teleport.o timeout.o topten.o track.o trap.o u_init.o \ - uhitm.o vault.o vision.o vis_tab.o weapon.o were.o wield.o windows.o \ - wizard.o worm.o worn.o write.o zap.o \ - $(REGEXOBJ) $(RANDOBJ) $(SYSOBJ) $(WINOBJ) $(HINTOBJ) version.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)cmd.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 \ + $(TARGETPFX)do_wear.o $(TARGETPFX)dog.o $(TARGETPFX)dogmove.o \ + $(TARGETPFX)dokick.o $(TARGETPFX)dothrow.o $(TARGETPFX)drawing.o \ + $(TARGETPFX)dungeon.o $(TARGETPFX)eat.o $(TARGETPFX)end.o \ + $(TARGETPFX)engrave.o $(TARGETPFX)exper.o $(TARGETPFX)explode.o \ + $(TARGETPFX)extralev.o $(TARGETPFX)files.o $(TARGETPFX)fountain.o \ + $(TARGETPFX)hack.o $(TARGETPFX)hacklib.o $(TARGETPFX)insight.o \ + $(TARGETPFX)invent.o $(TARGETPFX)isaac64.o $(TARGETPFX)light.o \ + $(TARGETPFX)lock.o $(TARGETPFX)mail.o $(TARGETPFX)makemon.o \ + $(TARGETPFX)mapglyph.o $(TARGETPFX)mcastu.o $(TARGETPFX)mdlib.o \ + $(TARGETPFX)mhitm.o $(TARGETPFX)mhitu.o $(TARGETPFX)minion.o \ + $(TARGETPFX)mklev.o $(TARGETPFX)mkmap.o $(TARGETPFX)mkmaze.o \ + $(TARGETPFX)mkobj.o $(TARGETPFX)mkroom.o $(TARGETPFX)mon.o \ + $(TARGETPFX)mondata.o $(TARGETPFX)monmove.o $(TARGETPFX)monst.o \ + $(TARGETPFX)mplayer.o $(TARGETPFX)mthrowu.o $(TARGETPFX)muse.o \ + $(TARGETPFX)music.o $(TARGETPFX)nhlua.o $(TARGETPFX)nhlsel.o \ + $(TARGETPFX)nhlobj.o $(TARGETPFX)objects.o $(TARGETPFX)o_init.o \ + $(TARGETPFX)objnam.o $(TARGETPFX)options.o $(TARGETPFX)pager.o \ + $(TARGETPFX)pickup.o $(TARGETPFX)pline.o $(TARGETPFX)polyself.o \ + $(TARGETPFX)potion.o $(TARGETPFX)pray.o $(TARGETPFX)priest.o \ + $(TARGETPFX)quest.o $(TARGETPFX)questpgr.o $(TARGETPFX)read.o \ + $(TARGETPFX)rect.o $(TARGETPFX)region.o $(TARGETPFX)restore.o \ + $(TARGETPFX)rip.o $(TARGETPFX)rnd.o $(TARGETPFX)role.o \ + $(TARGETPFX)rumors.o $(TARGETPFX)save.o $(TARGETPFX)sfstruct.o \ + $(TARGETPFX)shk.o $(TARGETPFX)shknam.o $(TARGETPFX)sit.o \ + $(TARGETPFX)sounds.o $(TARGETPFX)sp_lev.o $(TARGETPFX)spell.o \ + $(TARGETPFX)symbols.o $(TARGETPFX)sys.o $(TARGETPFX)steal.o \ + $(TARGETPFX)steed.o $(TARGETPFX)teleport.o $(TARGETPFX)timeout.o \ + $(TARGETPFX)topten.o $(TARGETPFX)track.o $(TARGETPFX)trap.o \ + $(TARGETPFX)u_init.o $(TARGETPFX)uhitm.o $(TARGETPFX)vault.o \ + $(TARGETPFX)vision.o $(TARGETPFX)weapon.o \ + $(TARGETPFX)were.o $(TARGETPFX)wield.o $(TARGETPFX)windows.o \ + $(TARGETPFX)wizard.o $(TARGETPFX)worm.o $(TARGETPFX)worn.o \ + $(TARGETPFX)write.o $(TARGETPFX)zap.o \ + $(REGEXOBJ) $(RANDOBJ) $(SYSOBJ) $(WINOBJ) $(HINTOBJ) \ + $(TARGETPFX)version.o # the .o files from the HACKCSRC, SYSSRC, and WINSRC lists # first target is also the default target for 'make' without any arguments all: $(GAME) @echo "" -$(GAME): $(SYSTEM) +pregame: + $(PREGAME) + +$(GAME): pregame $(SYSTEM) @echo "$(GAME) is up to date." -Sysunix: $(HOBJ) Makefile +Sysunix: $(HOSTOBJ) $(HOBJ) $(BUILDMORE) Makefile @echo "Linking $(GAME)." - $(AT)$(LINK) $(LFLAGS) -o $(GAME) $(HOBJ) $(WINLIB) $(LIBS) + $(AT)$(TARGET_LINK) $(TARGET_LFLAGS) -o $(GAMEBIN) \ + $(HOBJ) $(WINLIB) $(TARGET_LIBS) $(LUALIB) @touch Sysunix -Sys3B2: $(HOBJ) Makefile +Sys3B2: $(HOSTOBJ) $(HOBJ) $(BUILDMORE) Makefile @echo "Linking $(GAME)." - $(AT)$(LINK) $(LFLAGS) -o $(GAME) $(HOBJ) $(WINLIB) -lmalloc + $(AT)$(TARGET_LINK) $(TARGET_LFLAGS) -o $(GAMEBIN) \ + $(HOBJ) $(WINLIB) $(LUALIB) -lmalloc @touch Sys3B2 -Sysatt: $(HOBJ) Makefile +Sysatt: $(HOSTOBJ) $(HOBJ) $(BUILDMORE) Makefile @echo "Loading $(GAME)." - $(AT)$(LD) $(LFLAGS) /lib/crt0s.o /lib/shlib.ifile -o $(GAME) $(HOBJ) + $(AT)$(LD) $(TARGET_LFLAGS) /lib/crt0s.o /lib/shlib.ifile -o $(GAMEBIN) \ + $(HOSTOBJ) $(HOBJ) $(LUALIB) @touch Sysatt -Systos: $(HOBJ) Makefile +Systos: $(HOSTOBJ) $(HOBJ) $(BUILDMORE) Makefile @echo "Linking $(GAME)." - $(AT)$(LINK) $(LFLAGS) -o $(GAME) $(HOBJ) $(WINLIB) + $(AT)$(TARGET_LINK) $(TARGET_LFLAGS) -o $(GAMEBIN) \ + $(HOBJ) $(WINLIB) $(LUALIB) @touch Systos -SysV-AT: DUMB.Setup $(HOBJ) Makefile +SysV-AT: DUMB.Setup $(HOSTOBJ) $(HOBJ) $(BUILDMORE) Makefile @echo "Linking $(GAME)." - $(AT)$(LINK) $(LFLAGS) -o $(GAME) $(HOBJ) $(WINLIB) + $(AT)$(TARGET_LINK) $(TARGET_LFLAGS) -o $(GAMEBIN) \ + $(HOBJ) $(WINLIB) $(LUALIB) @touch SysV-AT -SysBe: $(HOBJ) Makefile +SysBe: $(HOSTOBJ) $(HOBJ) $(BUILDMORE) Makefile @echo "Linking $(GAME)." - $(AT)$(LINK) $(LFLAGS) -o $(GAME) $(HOBJ) $(WINLIB) $(LIBS) + $(AT)$(TARGET_LINK) $(TARGET_LFLAGS) -o $(GAME) \ + $(HOBJ) $(WINLIB) $(TARGET_LIBS) $(LUALIB) @xres -o $(GAME) ../win/BeOS/nethack.rsrc @mimeset -f $(GAME) @touch SysBe @@ -598,11 +696,11 @@ DUMB.Setup: ../include/extern.h # special rules, to force update of makedefs, real dependencies should be # below in the 'make depend' output. monst.o: - $(CC) $(CFLAGS) -c monst.c + $(CC) $(CFLAGS) -c -o $@ monst.c @rm -f $(MAKEDEFS) objects.o: - $(CC) $(CFLAGS) -c objects.c + $(CC) $(CFLAGS) -c -o $@ objects.c @rm -f $(MAKEDEFS) # Qt 3 windowport meta-object-compiler output @@ -655,10 +753,6 @@ $(MAKEDEFS): $(FIRSTOBJ) \ @( cd ../util ; $(MAKE) ../include/onames.h ) ../include/pm.h: $(MAKEDEFS) ../include/onames.h @( cd ../util ; $(MAKE) ../include/pm.h ) -../include/vis_tab.h: $(MAKEDEFS) ../include/pm.h - @( cd ../util ; $(MAKE) ../include/vis_tab.h ) -# makedefs -z makes both vis_tab.h and vis_tab.c, but writes the .h first -vis_tab.c: ../include/vis_tab.h # Created at build time for configurations which support tiles, # but not by makedefs so not connected to the others. tile.c: ../win/share/tilemap.c $(HACK_H) @@ -667,7 +761,7 @@ tile.c: ../win/share/tilemap.c $(HACK_H) ../win/gnome/gn_rip.h: ../win/X11/rip.xpm cp ../win/X11/rip.xpm ../win/gnome/gn_rip.h -sfstruct.o: sfstruct.c $(HACK_H) +$(TARGETPFX)sfstruct.o: sfstruct.c $(HACK_H) # date.h should be remade any time any of the source or include code # is modified. Unfortunately, this would make the contents of this @@ -700,14 +794,18 @@ tags: $(CSOURCES) clean: -rm -f *.o $(HACK_H) $(CONFIG_H) + $(CLEANMORE) spotless: clean - -rm -f a.out core $(GAME) Sys* + -rm -f a.out core $(GAMEBIN) Sys* -rm -f ../lib/lua/liblua.a ../include/nhlua.h -rm -f ../include/date.h ../include/onames.h ../include/pm.h - -rm -f ../include/vis_tab.h vis_tab.c tile.c *.moc + -rm -f tile.c *.moc -rm -f ../win/gnome/gn_rip.h +package: + $(PACKAGE) + @echo packaging complete. depend: ../sys/unix/depend.awk \ $(SYSCSRC) $(WINCSRC) $(SYSCXXSRC) $(WINCXXSRC) \ @@ -730,10 +828,10 @@ depend: ../sys/unix/depend.awk \ # DO NOT DELETE THIS LINE OR CHANGE ANYTHING BEYOND IT # config.h timestamp -$(CONFIG_H): ../include/config.h ../include/patchlevel.h ../include/config1.h \ +$(CONFIG_H): ../include/config.h ../include/config1.h ../include/patchlevel.h \ ../include/tradstdc.h ../include/global.h ../include/coord.h \ ../include/vmsconf.h ../include/system.h ../include/nhlua.h \ - ../include/unixconf.h ../include/micro.h ../include/pcconf.h \ + ../include/unixconf.h ../include/pcconf.h ../include/micro.h \ ../include/ntconf.h ../include/fnamesiz.h touch $(CONFIG_H) # hack.h timestamp @@ -745,423 +843,356 @@ $(HACK_H): ../include/hack.h $(CONFIG_H) ../include/lint.h ../include/align.h \ ../include/wintype.h ../include/context.h ../include/rm.h \ ../include/botl.h ../include/rect.h ../include/region.h \ ../include/decl.h ../include/quest.h ../include/spell.h \ - ../include/color.h ../include/obj.h ../include/you.h \ - ../include/attrib.h ../include/monst.h ../include/mextra.h \ - ../include/skills.h ../include/onames.h ../include/timeout.h \ - ../include/trap.h ../include/flag.h ../include/vision.h \ - ../include/display.h ../include/engrave.h \ - ../include/winprocs.h ../include/sys.h ../include/wintty.h \ - ../include/trampoli.h + ../include/color.h ../include/obj.h ../include/engrave.h \ + ../include/you.h ../include/attrib.h ../include/monst.h \ + ../include/mextra.h ../include/skills.h ../include/onames.h \ + ../include/timeout.h ../include/trap.h ../include/flag.h \ + ../include/vision.h ../include/display.h ../include/winprocs.h \ + ../include/sys.h ../include/wintty.h touch $(HACK_H) # -tos.o: ../sys/atari/tos.c $(HACK_H) ../include/tcap.h - $(CC) $(CFLAGS) -c -o $@ ../sys/atari/tos.c -pcmain.o: ../sys/share/pcmain.c $(HACK_H) ../include/dlb.h - $(CC) $(CFLAGS) -c -o $@ ../sys/share/pcmain.c -pcsys.o: ../sys/share/pcsys.c $(HACK_H) - $(CC) $(CFLAGS) -c -o $@ ../sys/share/pcsys.c -pctty.o: ../sys/share/pctty.c $(HACK_H) - $(CC) $(CFLAGS) -c -o $@ ../sys/share/pctty.c -pcunix.o: ../sys/share/pcunix.c $(HACK_H) - $(CC) $(CFLAGS) -c -o $@ ../sys/share/pcunix.c -pmatchregex.o: ../sys/share/pmatchregex.c $(HACK_H) - $(CC) $(CFLAGS) -c -o $@ ../sys/share/pmatchregex.c -posixregex.o: ../sys/share/posixregex.c $(HACK_H) - $(CC) $(CFLAGS) -c -o $@ ../sys/share/posixregex.c -random.o: ../sys/share/random.c $(HACK_H) - $(CC) $(CFLAGS) -c -o $@ ../sys/share/random.c -ioctl.o: ../sys/share/ioctl.c $(HACK_H) ../include/tcap.h - $(CC) $(CFLAGS) -c -o $@ ../sys/share/ioctl.c -unixtty.o: ../sys/share/unixtty.c $(HACK_H) - $(CC) $(CFLAGS) -c -o $@ ../sys/share/unixtty.c -unixmain.o: ../sys/unix/unixmain.c $(HACK_H) ../include/dlb.h - $(CC) $(CFLAGS) -c -o $@ ../sys/unix/unixmain.c -unixunix.o: ../sys/unix/unixunix.c $(HACK_H) - $(CC) $(CFLAGS) -c -o $@ ../sys/unix/unixunix.c -unixres.o: ../sys/unix/unixres.c $(CONFIG_H) - $(CC) $(CFLAGS) -c -o $@ ../sys/unix/unixres.c -bemain.o: ../sys/be/bemain.c $(HACK_H) ../include/dlb.h - $(CC) $(CFLAGS) -c -o $@ ../sys/be/bemain.c -getline.o: ../win/tty/getline.c $(HACK_H) ../include/func_tab.h - $(CC) $(CFLAGS) -c -o $@ ../win/tty/getline.c -termcap.o: ../win/tty/termcap.c $(HACK_H) ../include/tcap.h - $(CC) $(CFLAGS) -c -o $@ ../win/tty/termcap.c -topl.o: ../win/tty/topl.c $(HACK_H) ../include/tcap.h - $(CC) $(CFLAGS) -c -o $@ ../win/tty/topl.c -wintty.o: ../win/tty/wintty.c $(HACK_H) ../include/dlb.h ../include/tcap.h - $(CC) $(CFLAGS) -c -o $@ ../win/tty/wintty.c -cursmain.o: ../win/curses/cursmain.c $(HACK_H) ../include/wincurs.h - $(CC) $(CFLAGS) -c -o $@ ../win/curses/cursmain.c -curswins.o: ../win/curses/curswins.c $(HACK_H) ../include/wincurs.h \ - ../win/curses/curswins.h - $(CC) $(CFLAGS) -c -o $@ ../win/curses/curswins.c -cursmisc.o: ../win/curses/cursmisc.c $(HACK_H) ../include/wincurs.h \ - ../win/curses/cursmisc.h ../include/func_tab.h ../include/dlb.h - $(CC) $(CFLAGS) -c -o $@ ../win/curses/cursmisc.c -cursdial.o: ../win/curses/cursdial.c $(HACK_H) ../include/wincurs.h \ - ../win/curses/cursdial.h ../include/func_tab.h - $(CC) $(CFLAGS) -c -o $@ ../win/curses/cursdial.c -cursstat.o: ../win/curses/cursstat.c $(HACK_H) ../include/wincurs.h \ - ../win/curses/cursstat.h - $(CC) $(CFLAGS) -c -o $@ ../win/curses/cursstat.c -cursinit.o: ../win/curses/cursinit.c $(HACK_H) ../include/wincurs.h \ - ../win/curses/cursinit.h - $(CC) $(CFLAGS) -c -o $@ ../win/curses/cursinit.c -cursmesg.o: ../win/curses/cursmesg.c $(HACK_H) ../include/wincurs.h \ - ../win/curses/cursmesg.h - $(CC) $(CFLAGS) -c -o $@ ../win/curses/cursmesg.c -cursinvt.o: ../win/curses/cursinvt.c $(HACK_H) ../include/wincurs.h \ - ../win/curses/cursinvt.h - $(CC) $(CFLAGS) -c -o $@ ../win/curses/cursinvt.c -Window.o: ../win/X11/Window.c ../include/xwindowp.h ../include/xwindow.h \ - $(CONFIG_H) ../include/lint.h ../include/winX.h \ - ../include/color.h ../include/wintype.h - $(CC) $(CFLAGS) $(X11CFLAGS) -c -o $@ ../win/X11/Window.c -dialogs.o: ../win/X11/dialogs.c $(CONFIG_H) ../include/lint.h \ - ../include/winX.h ../include/color.h ../include/wintype.h - $(CC) $(CFLAGS) $(X11CFLAGS) -c -o $@ ../win/X11/dialogs.c -winX.o: ../win/X11/winX.c $(HACK_H) ../include/winX.h ../include/dlb.h \ - ../include/xwindow.h ../win/X11/nh72icon ../win/X11/nh56icon \ - ../win/X11/nh32icon - $(CC) $(CFLAGS) $(X11CFLAGS) -c -o $@ ../win/X11/winX.c -winmap.o: ../win/X11/winmap.c ../include/xwindow.h $(HACK_H) ../include/dlb.h \ - ../include/winX.h ../include/tile2x11.h - $(CC) $(CFLAGS) $(X11CFLAGS) -c -o $@ ../win/X11/winmap.c -winmenu.o: ../win/X11/winmenu.c $(HACK_H) ../include/winX.h - $(CC) $(CFLAGS) $(X11CFLAGS) -c -o $@ ../win/X11/winmenu.c -winmesg.o: ../win/X11/winmesg.c ../include/xwindow.h $(HACK_H) ../include/winX.h - $(CC) $(CFLAGS) $(X11CFLAGS) -c -o $@ ../win/X11/winmesg.c -winmisc.o: ../win/X11/winmisc.c $(HACK_H) ../include/func_tab.h \ - ../include/winX.h - $(CC) $(CFLAGS) $(X11CFLAGS) -c -o $@ ../win/X11/winmisc.c -winstat.o: ../win/X11/winstat.c $(HACK_H) ../include/winX.h ../include/xwindow.h - $(CC) $(CFLAGS) $(X11CFLAGS) -c -o $@ ../win/X11/winstat.c -wintext.o: ../win/X11/wintext.c $(HACK_H) ../include/winX.h ../include/xwindow.h - $(CC) $(CFLAGS) $(X11CFLAGS) -c -o $@ ../win/X11/wintext.c -winval.o: ../win/X11/winval.c $(HACK_H) ../include/winX.h - $(CC) $(CFLAGS) $(X11CFLAGS) -c -o $@ ../win/X11/winval.c -tile.o: tile.c $(HACK_H) -gnaskstr.o: ../win/gnome/gnaskstr.c ../win/gnome/gnaskstr.h \ - ../win/gnome/gnmain.h - $(CC) $(CFLAGS) $(GNOMEINC) -c -o $@ ../win/gnome/gnaskstr.c -gnbind.o: ../win/gnome/gnbind.c ../win/gnome/gnbind.h ../win/gnome/gnomeprv.h \ - $(HACK_H) ../include/dlb.h \ - ../include/winGnome.h ../win/gnome/gnmain.h \ - ../win/gnome/gnmap.h ../win/gnome/gnmenu.h \ - ../win/gnome/gnplayer.h ../win/gnome/gnsignal.h \ - ../win/gnome/gnglyph.h ../win/gnome/gnstatus.h \ - ../win/gnome/gntext.h ../win/gnome/gnmesg.h \ - ../win/gnome/gnyesno.h ../win/gnome/gnworn.h \ - ../win/gnome/gnaskstr.h - $(CC) $(CFLAGS) $(GNOMEINC) -c -o $@ ../win/gnome/gnbind.c -gnglyph.o: ../win/gnome/gnglyph.c ../win/gnome/gnglyph.h $(CONFIG_H) \ - ../include/tile2x11.h - $(CC) $(CFLAGS) $(GNOMEINC) -c -o $@ ../win/gnome/gnglyph.c -gnmain.o: ../win/gnome/gnmain.c ../win/gnome/gnmain.h ../win/gnome/gnsignal.h \ - ../win/gnome/gnomeprv.h $(HACK_H) ../include/dlb.h \ - ../include/winGnome.h ../win/gnome/gnglyph.h \ - ../win/gnome/gnbind.h ../win/gnome/gnmap.h \ - ../win/gnome/gnmenu.h ../win/gnome/gnplayer.h \ - ../win/gnome/gnstatus.h ../win/gnome/gntext.h \ - ../win/gnome/gnmesg.h ../win/gnome/gnyesno.h \ - ../win/gnome/gnworn.h ../win/gnome/gnopts.h ../include/date.h - $(CC) $(CFLAGS) $(GNOMEINC) -c -o $@ ../win/gnome/gnmain.c -gnmap.o: ../win/gnome/gnmap.c ../win/gnome/gnmap.h $(CONFIG_H) \ - ../win/gnome/gnglyph.h ../win/gnome/gnsignal.h \ - ../win/gnome/gnomeprv.h $(HACK_H) ../include/dlb.h \ - ../include/winGnome.h - $(CC) $(CFLAGS) $(GNOMEINC) -c -o $@ ../win/gnome/gnmap.c -gnmenu.o: ../win/gnome/gnmenu.c ../win/gnome/gnmenu.h $(CONFIG_H) \ - ../win/gnome/gnomeprv.h $(HACK_H) ../include/dlb.h \ - ../include/winGnome.h ../win/gnome/gnmain.h \ - ../win/gnome/gnbind.h ../win/gnome/gnmap.h \ - ../win/gnome/gnplayer.h ../win/gnome/gnsignal.h \ - ../win/gnome/gnglyph.h ../win/gnome/gnstatus.h \ - ../win/gnome/gntext.h ../win/gnome/gnmesg.h \ - ../win/gnome/gnyesno.h ../win/gnome/gnworn.h \ +$(TARGETPFX)pcmain.o: ../sys/share/pcmain.c $(HACK_H) ../include/dlb.h + $(TARGET_CC) $(TARGET_CFLAGS) -c -o $@ ../sys/share/pcmain.c +$(TARGETPFX)pcsys.o: ../sys/share/pcsys.c $(HACK_H) + $(TARGET_CC) $(TARGET_CFLAGS) -c -o $@ ../sys/share/pcsys.c +$(TARGETPFX)pctty.o: ../sys/share/pctty.c $(HACK_H) + $(TARGET_CC) $(TARGET_CFLAGS) -c -o $@ ../sys/share/pctty.c +$(TARGETPFX)pcunix.o: ../sys/share/pcunix.c $(HACK_H) + $(TARGET_CC) $(TARGET_CFLAGS) -c -o $@ ../sys/share/pcunix.c +$(TARGETPFX)pmatchregex.o: ../sys/share/pmatchregex.c $(HACK_H) + $(TARGET_CC) $(TARGET_CFLAGS) -c -o $@ ../sys/share/pmatchregex.c +$(TARGETPFX)posixregex.o: ../sys/share/posixregex.c $(HACK_H) + $(TARGET_CC) $(TARGET_CFLAGS) -c -o $@ ../sys/share/posixregex.c +$(TARGETPFX)random.o: ../sys/share/random.c $(HACK_H) + $(TARGET_CC) $(TARGET_CFLAGS) -c -o $@ ../sys/share/random.c +$(TARGETPFX)ioctl.o: ../sys/share/ioctl.c $(HACK_H) ../include/tcap.h + $(TARGET_CC) $(TARGET_CFLAGS) -c -o $@ ../sys/share/ioctl.c +$(TARGETPFX)unixtty.o: ../sys/share/unixtty.c $(HACK_H) + $(TARGET_CC) $(TARGET_CFLAGS) -c -o $@ ../sys/share/unixtty.c +$(TARGETPFX)unixmain.o: ../sys/unix/unixmain.c $(HACK_H) ../include/dlb.h + $(TARGET_CC) $(TARGET_CFLAGS) -c -o $@ ../sys/unix/unixmain.c +$(TARGETPFX)unixunix.o: ../sys/unix/unixunix.c $(HACK_H) + $(TARGET_CC) $(TARGET_CFLAGS) -c -o $@ ../sys/unix/unixunix.c +$(TARGETPFX)unixres.o: ../sys/unix/unixres.c $(CONFIG_H) + $(TARGET_CC) $(TARGET_CFLAGS) -c -o $@ ../sys/unix/unixres.c +$(TARGETPFX)getline.o: ../win/tty/getline.c $(HACK_H) ../include/func_tab.h + $(TARGET_CC) $(TARGET_CFLAGS) -c -o $@ ../win/tty/getline.c +$(TARGETPFX)termcap.o: ../win/tty/termcap.c $(HACK_H) ../include/tcap.h + $(TARGET_CC) $(TARGET_CFLAGS) -c -o $@ ../win/tty/termcap.c +$(TARGETPFX)topl.o: ../win/tty/topl.c $(HACK_H) ../include/tcap.h + $(TARGET_CC) $(TARGET_CFLAGS) -c -o $@ ../win/tty/topl.c +$(TARGETPFX)wintty.o: ../win/tty/wintty.c $(HACK_H) ../include/dlb.h \ + ../include/tcap.h + $(TARGET_CC) $(TARGET_CFLAGS) -c -o $@ ../win/tty/wintty.c +$(TARGETPFX)cursmain.o: ../win/curses/cursmain.c $(HACK_H) ../include/wincurs.h + $(TARGET_CC) $(TARGET_CFLAGS) -c -o $@ ../win/curses/cursmain.c +$(TARGETPFX)curswins.o: ../win/curses/curswins.c $(HACK_H) \ + ../include/wincurs.h ../win/curses/curswins.h + $(TARGET_CC) $(TARGET_CFLAGS) -c -o $@ ../win/curses/curswins.c +$(TARGETPFX)cursmisc.o: ../win/curses/cursmisc.c $(HACK_H) \ + ../include/wincurs.h ../win/curses/cursmisc.h \ + ../include/func_tab.h ../include/dlb.h + $(TARGET_CC) $(TARGET_CFLAGS) -c -o $@ ../win/curses/cursmisc.c +$(TARGETPFX)cursdial.o: ../win/curses/cursdial.c $(HACK_H) \ + ../include/wincurs.h ../win/curses/cursdial.h \ ../include/func_tab.h - $(CC) $(CFLAGS) $(GNOMEINC) -c -o $@ ../win/gnome/gnmenu.c -gnmesg.o: ../win/gnome/gnmesg.c ../win/gnome/gnmesg.h $(CONFIG_H) \ - ../win/gnome/gnsignal.h ../win/gnome/gnomeprv.h $(HACK_H) \ - ../include/dlb.h ../include/winGnome.h ../win/gnome/gnglyph.h - $(CC) $(CFLAGS) $(GNOMEINC) -c -o $@ ../win/gnome/gnmesg.c -gnopts.o: ../win/gnome/gnopts.c ../win/gnome/gnopts.h ../win/gnome/gnglyph.h \ - $(CONFIG_H) ../win/gnome/gnmain.h ../win/gnome/gnmap.h $(HACK_H) - $(CC) $(CFLAGS) $(GNOMEINC) -c -o $@ ../win/gnome/gnopts.c -gnplayer.o: ../win/gnome/gnplayer.c ../win/gnome/gnplayer.h \ - ../win/gnome/gnmain.h $(HACK_H) - $(CC) $(CFLAGS) $(GNOMEINC) -c -o $@ ../win/gnome/gnplayer.c -gnsignal.o: ../win/gnome/gnsignal.c ../win/gnome/gnsignal.h \ - ../win/gnome/gnomeprv.h $(HACK_H) ../include/dlb.h \ - ../include/winGnome.h ../win/gnome/gnglyph.h \ - ../win/gnome/gnmain.h - $(CC) $(CFLAGS) $(GNOMEINC) -c -o $@ ../win/gnome/gnsignal.c -gnstatus.o: ../win/gnome/gnstatus.c ../win/gnome/gnstatus.h $(CONFIG_H) \ - ../win/gnome/gnsignal.h ../win/gnome/gnomeprv.h $(HACK_H) \ - ../include/dlb.h ../include/winGnome.h \ - ../win/gnome/gnglyph.h ../win/gnome/gn_xpms.h - $(CC) $(CFLAGS) $(GNOMEINC) -c -o $@ ../win/gnome/gnstatus.c -gntext.o: ../win/gnome/gntext.c ../win/gnome/gntext.h $(CONFIG_H) \ - ../win/gnome/gnmain.h ../win/gnome/gn_rip.h - $(CC) $(CFLAGS) $(GNOMEINC) -c -o $@ ../win/gnome/gntext.c -gnyesno.o: ../win/gnome/gnyesno.c ../win/gnome/gnbind.h \ - ../win/gnome/gnomeprv.h $(HACK_H) ../include/dlb.h \ - ../include/winGnome.h ../win/gnome/gnmain.h \ - ../win/gnome/gnmap.h ../win/gnome/gnmenu.h \ - ../win/gnome/gnplayer.h ../win/gnome/gnsignal.h \ - ../win/gnome/gnglyph.h ../win/gnome/gnstatus.h \ - ../win/gnome/gntext.h ../win/gnome/gnmesg.h \ - ../win/gnome/gnyesno.h ../win/gnome/gnworn.h - $(CC) $(CFLAGS) $(GNOMEINC) -c -o $@ ../win/gnome/gnyesno.c -gnworn.o: ../win/gnome/gnworn.c ../win/gnome/gnworn.h $(CONFIG_H) \ - ../win/gnome/gnglyph.h ../win/gnome/gnsignal.h \ - ../win/gnome/gnomeprv.h $(HACK_H) ../include/dlb.h \ - ../include/winGnome.h - $(CC) $(CFLAGS) $(GNOMEINC) -c -o $@ ../win/gnome/gnworn.c -wingem.o: ../win/gem/wingem.c $(HACK_H) ../include/func_tab.h ../include/dlb.h \ - ../include/wingem.h - $(CC) $(CFLAGS) -c -o $@ ../win/gem/wingem.c -wingem1.o: ../win/gem/wingem1.c ../include/gem_rsc.h ../include/load_img.h \ - ../include/gr_rect.h ../include/wintype.h ../include/wingem.h - $(CC) $(CFLAGS) -c -o $@ ../win/gem/wingem1.c -load_img.o: ../win/gem/load_img.c ../include/load_img.h - $(CC) $(CFLAGS) -c -o $@ ../win/gem/load_img.c -gr_rect.o: ../win/gem/gr_rect.c ../include/gr_rect.h - $(CC) $(CFLAGS) -c -o $@ ../win/gem/gr_rect.c -tile.o: tile.c $(HACK_H) -cppregex.o: ../sys/share/cppregex.cpp - $(CXX) $(CXXFLAGS) -c -o $@ ../sys/share/cppregex.cpp -qt_bind.o: ../win/Qt/qt_bind.cpp $(HACK_H) ../win/Qt/qt_bind.h \ - ../win/Qt/qt_main.h ../win/Qt/qt_kde0.h ../win/Qt/qt_click.h \ - ../win/Qt/qt_delay.h ../win/Qt/qt_xcmd.h ../win/Qt/qt_key.h \ + $(TARGET_CC) $(TARGET_CFLAGS) -c -o $@ ../win/curses/cursdial.c +$(TARGETPFX)cursstat.o: ../win/curses/cursstat.c $(HACK_H) \ + ../include/wincurs.h ../win/curses/cursstat.h + $(TARGET_CC) $(TARGET_CFLAGS) -c -o $@ ../win/curses/cursstat.c +$(TARGETPFX)cursinit.o: ../win/curses/cursinit.c $(HACK_H) \ + ../include/wincurs.h ../win/curses/cursinit.h + $(TARGET_CC) $(TARGET_CFLAGS) -c -o $@ ../win/curses/cursinit.c +$(TARGETPFX)cursmesg.o: ../win/curses/cursmesg.c $(HACK_H) \ + ../include/wincurs.h ../win/curses/cursmesg.h + $(TARGET_CC) $(TARGET_CFLAGS) -c -o $@ ../win/curses/cursmesg.c +$(TARGETPFX)cursinvt.o: ../win/curses/cursinvt.c $(HACK_H) \ + ../include/wincurs.h ../win/curses/cursinvt.h + $(TARGET_CC) $(TARGET_CFLAGS) -c -o $@ ../win/curses/cursinvt.c +$(TARGETPFX)Window.o: ../win/X11/Window.c ../include/xwindowp.h \ + ../include/xwindow.h $(CONFIG_H) ../include/lint.h \ + ../include/winX.h ../include/color.h ../include/wintype.h + $(TARGET_CC) $(TARGET_CFLAGS) $(X11CFLAGS) -c -o $@ ../win/X11/Window.c +$(TARGETPFX)dialogs.o: ../win/X11/dialogs.c $(CONFIG_H) ../include/lint.h \ + ../include/winX.h ../include/color.h ../include/wintype.h + $(TARGET_CC) $(TARGET_CFLAGS) $(X11CFLAGS) -c -o $@ ../win/X11/dialogs.c +$(TARGETPFX)winX.o: ../win/X11/winX.c $(HACK_H) ../include/winX.h \ + ../include/dlb.h ../include/xwindow.h ../win/X11/nh72icon \ + ../win/X11/nh56icon ../win/X11/nh32icon + $(TARGET_CC) $(TARGET_CFLAGS) $(X11CFLAGS) -c -o $@ ../win/X11/winX.c +$(TARGETPFX)winmap.o: ../win/X11/winmap.c ../include/xwindow.h $(HACK_H) \ + ../include/dlb.h ../include/winX.h ../include/tile2x11.h + $(TARGET_CC) $(TARGET_CFLAGS) $(X11CFLAGS) -c -o $@ ../win/X11/winmap.c +$(TARGETPFX)winmenu.o: ../win/X11/winmenu.c $(HACK_H) ../include/winX.h + $(TARGET_CC) $(TARGET_CFLAGS) $(X11CFLAGS) -c -o $@ ../win/X11/winmenu.c +$(TARGETPFX)winmesg.o: ../win/X11/winmesg.c ../include/xwindow.h $(HACK_H) \ + ../include/winX.h + $(TARGET_CC) $(TARGET_CFLAGS) $(X11CFLAGS) -c -o $@ ../win/X11/winmesg.c +$(TARGETPFX)winmisc.o: ../win/X11/winmisc.c $(HACK_H) ../include/func_tab.h \ + ../include/winX.h + $(TARGET_CC) $(TARGET_CFLAGS) $(X11CFLAGS) -c -o $@ ../win/X11/winmisc.c +$(TARGETPFX)winstat.o: ../win/X11/winstat.c $(HACK_H) ../include/winX.h \ + ../include/xwindow.h + $(TARGET_CC) $(TARGET_CFLAGS) $(X11CFLAGS) -c -o $@ ../win/X11/winstat.c +$(TARGETPFX)wintext.o: ../win/X11/wintext.c $(HACK_H) ../include/winX.h \ + ../include/xwindow.h + $(TARGET_CC) $(TARGET_CFLAGS) $(X11CFLAGS) -c -o $@ ../win/X11/wintext.c +$(TARGETPFX)winval.o: ../win/X11/winval.c $(HACK_H) ../include/winX.h + $(TARGET_CC) $(TARGET_CFLAGS) $(X11CFLAGS) -c -o $@ ../win/X11/winval.c +$(TARGETPFX)tile.o: tile.c $(HACK_H) +$(TARGETPFX)cppregex.o: ../sys/share/cppregex.cpp + $(TARGET_CXX) $(TARGET_CXXFLAGS) -c -o $@ ../sys/share/cppregex.cpp +$(TARGETPFX)qt_bind.o: ../win/Qt/qt_bind.cpp $(HACK_H) ../win/Qt/qt_pre.h \ + ../win/Qt/qt_post.h ../win/Qt/qt_bind.h ../win/Qt/qt_main.h \ + ../win/Qt/qt_kde0.h ../win/Qt/qt_click.h ../win/Qt/qt_delay.h \ + ../win/Qt/qt_xcmd.h ../win/Qt/qt_key.h ../win/Qt/qt_map.h \ + ../win/Qt/qt_win.h ../win/Qt/qt_clust.h ../win/Qt/qt_menu.h \ + ../win/Qt/qt_rip.h ../win/Qt/qt_msg.h ../win/Qt/qt_plsel.h \ + ../win/Qt/qt_svsel.h ../win/Qt/qt_set.h ../win/Qt/qt_stat.h \ + ../win/Qt/qt_icon.h ../win/Qt/qt_streq.h ../win/Qt/qt_line.h \ + ../win/Qt/qt_yndlg.h ../win/Qt/qt_str.h ../include/dlb.h + $(TARGET_CXX) $(TARGET_CXXFLAGS) -c -o $@ ../win/Qt/qt_bind.cpp +$(TARGETPFX)qt_click.o: ../win/Qt/qt_click.cpp $(HACK_H) ../win/Qt/qt_pre.h \ + ../win/Qt/qt_post.h ../win/Qt/qt_click.h + $(TARGET_CXX) $(TARGET_CXXFLAGS) -c -o $@ ../win/Qt/qt_click.cpp +$(TARGETPFX)qt_clust.o: ../win/Qt/qt_clust.cpp ../win/Qt/qt_clust.h + $(TARGET_CXX) $(TARGET_CXXFLAGS) -c -o $@ ../win/Qt/qt_clust.cpp +$(TARGETPFX)qt_delay.o: ../win/Qt/qt_delay.cpp $(HACK_H) ../win/Qt/qt_pre.h \ + ../win/Qt/qt_post.h ../win/Qt/qt_delay.h + $(TARGET_CXX) $(TARGET_CXXFLAGS) -c -o $@ ../win/Qt/qt_delay.cpp +$(TARGETPFX)qt_glyph.o: ../win/Qt/qt_glyph.cpp $(HACK_H) \ + ../include/tile2x11.h ../win/Qt/qt_pre.h ../win/Qt/qt_post.h \ + ../win/Qt/qt_glyph.h ../win/Qt/qt_bind.h ../win/Qt/qt_main.h \ + ../win/Qt/qt_kde0.h ../win/Qt/qt_set.h ../win/Qt/qt_inv.h \ ../win/Qt/qt_map.h ../win/Qt/qt_win.h ../win/Qt/qt_clust.h \ - ../win/Qt/qt_menu.h ../win/Qt/qt_rip.h ../win/Qt/qt_msg.h \ - ../win/Qt/qt_plsel.h ../win/Qt/qt_svsel.h ../win/Qt/qt_set.h \ - ../win/Qt/qt_stat.h ../win/Qt/qt_icon.h ../win/Qt/qt_streq.h \ - ../win/Qt/qt_line.h ../win/Qt/qt_yndlg.h ../win/Qt/qt_str.h \ - ../include/dlb.h - $(CXX) $(CXXFLAGS) -c -o $@ ../win/Qt/qt_bind.cpp -qt_click.o: ../win/Qt/qt_click.cpp $(HACK_H) ../win/Qt/qt_click.h - $(CXX) $(CXXFLAGS) -c -o $@ ../win/Qt/qt_click.cpp -qt_clust.o: ../win/Qt/qt_clust.cpp ../win/Qt/qt_clust.h - $(CXX) $(CXXFLAGS) -c -o $@ ../win/Qt/qt_clust.cpp -qt_delay.o: ../win/Qt/qt_delay.cpp $(HACK_H) ../win/Qt/qt_delay.h - $(CXX) $(CXXFLAGS) -c -o $@ ../win/Qt/qt_delay.cpp -qt_glyph.o: ../win/Qt/qt_glyph.cpp $(HACK_H) ../include/tile2x11.h \ - ../win/Qt/qt_glyph.h ../win/Qt/qt_set.h ../win/Qt/qt_str.h - $(CXX) $(CXXFLAGS) -c -o $@ ../win/Qt/qt_glyph.cpp -qt_icon.o: ../win/Qt/qt_icon.cpp $(HACK_H) ../win/Qt/qt_icon.h - $(CXX) $(CXXFLAGS) -c -o $@ ../win/Qt/qt_icon.cpp -qt_inv.o: ../win/Qt/qt_inv.cpp $(HACK_H) ../win/Qt/qt_inv.h \ - ../win/Qt/qt_glyph.h ../win/Qt/qt_set.h - $(CXX) $(CXXFLAGS) -c -o $@ ../win/Qt/qt_inv.cpp -qt_key.o: ../win/Qt/qt_key.cpp $(HACK_H) ../win/Qt/qt_key.h - $(CXX) $(CXXFLAGS) -c -o $@ ../win/Qt/qt_key.cpp -qt_line.o: ../win/Qt/qt_line.cpp $(HACK_H) ../win/Qt/qt_line.h - $(CXX) $(CXXFLAGS) -c -o $@ ../win/Qt/qt_line.cpp -qt_main.o: ../win/Qt/qt_main.cpp $(HACK_H) \ - ../win/Qt/qt_main.h ../win/Qt/qt_kde0.h qt_main.moc \ - ../win/Qt/qt_bind.h ../win/Qt/qt_glyph.h ../win/Qt/qt_inv.h \ - ../win/Qt/qt_key.h ../win/Qt/qt_map.h ../win/Qt/qt_win.h \ - ../win/Qt/qt_clust.h ../win/Qt/qt_msg.h ../win/Qt/qt_set.h \ - ../win/Qt/qt_stat.h ../win/Qt/qt_icon.h ../win/Qt/qt_str.h \ - qt_kde0.moc - $(CXX) $(CXXFLAGS) -c -o $@ ../win/Qt/qt_main.cpp -qt_map.o: ../win/Qt/qt_map.cpp $(HACK_H) ../win/Qt/qt_map.h ../win/Qt/qt_win.h \ + ../win/Qt/qt_str.h + $(TARGET_CXX) $(TARGET_CXXFLAGS) -c -o $@ ../win/Qt/qt_glyph.cpp +$(TARGETPFX)qt_icon.o: ../win/Qt/qt_icon.cpp $(HACK_H) ../win/Qt/qt_pre.h \ + ../win/Qt/qt_post.h ../win/Qt/qt_icon.h + $(TARGET_CXX) $(TARGET_CXXFLAGS) -c -o $@ ../win/Qt/qt_icon.cpp +$(TARGETPFX)qt_inv.o: ../win/Qt/qt_inv.cpp $(HACK_H) ../win/Qt/qt_pre.h \ + ../win/Qt/qt_post.h ../win/Qt/qt_inv.h ../win/Qt/qt_glyph.h \ + ../win/Qt/qt_set.h ../win/Qt/qt_bind.h ../win/Qt/qt_main.h \ + ../win/Qt/qt_kde0.h + $(TARGET_CXX) $(TARGET_CXXFLAGS) -c -o $@ ../win/Qt/qt_inv.cpp +$(TARGETPFX)qt_key.o: ../win/Qt/qt_key.cpp $(HACK_H) ../win/Qt/qt_pre.h \ + ../win/Qt/qt_post.h ../win/Qt/qt_key.h + $(TARGET_CXX) $(TARGET_CXXFLAGS) -c -o $@ ../win/Qt/qt_key.cpp +$(TARGETPFX)qt_line.o: ../win/Qt/qt_line.cpp $(HACK_H) ../win/Qt/qt_pre.h \ + ../win/Qt/qt_post.h ../win/Qt/qt_line.h + $(TARGET_CXX) $(TARGET_CXXFLAGS) -c -o $@ ../win/Qt/qt_line.cpp +$(TARGETPFX)qt_main.o: ../win/Qt/qt_main.cpp $(HACK_H) ../win/Qt/qt_pre.h \ + ../win/Qt/qt_post.h ../win/Qt/qt_main.h ../win/Qt/qt_kde0.h \ + qt_main.moc ../win/Qt/qt_bind.h ../win/Qt/qt_glyph.h \ + ../win/Qt/qt_inv.h ../win/Qt/qt_key.h ../win/Qt/qt_map.h \ + ../win/Qt/qt_win.h ../win/Qt/qt_clust.h ../win/Qt/qt_msg.h \ + ../win/Qt/qt_set.h ../win/Qt/qt_stat.h ../win/Qt/qt_icon.h \ + ../win/Qt/qt_str.h qt_kde0.moc + $(TARGET_CXX) $(TARGET_CXXFLAGS) -c -o $@ ../win/Qt/qt_main.cpp +$(TARGETPFX)qt_map.o: ../win/Qt/qt_map.cpp $(HACK_H) ../win/Qt/qt_pre.h \ + ../win/Qt/qt_post.h ../win/Qt/qt_map.h ../win/Qt/qt_win.h \ ../win/Qt/qt_clust.h qt_map.moc ../win/Qt/qt_click.h \ - ../win/Qt/qt_glyph.h ../win/Qt/qt_xpms.h ../win/Qt/qt_set.h \ + ../win/Qt/qt_glyph.h ../win/Qt/qt_set.h ../win/Qt/qt_bind.h \ + ../win/Qt/qt_main.h ../win/Qt/qt_kde0.h ../win/Qt/qt_str.h + $(TARGET_CXX) $(TARGET_CXXFLAGS) -c -o $@ ../win/Qt/qt_map.cpp +$(TARGETPFX)qt_menu.o: ../win/Qt/qt_menu.cpp $(HACK_H) ../win/Qt/qt_pre.h \ + ../win/Qt/qt_post.h ../win/Qt/qt_menu.h ../win/Qt/qt_win.h \ + ../win/Qt/qt_rip.h qt_menu.moc ../win/Qt/qt_glyph.h \ + ../win/Qt/qt_set.h ../win/Qt/qt_bind.h ../win/Qt/qt_main.h \ + ../win/Qt/qt_kde0.h ../win/Qt/qt_streq.h ../win/Qt/qt_line.h \ ../win/Qt/qt_str.h - $(CXX) $(CXXFLAGS) -c -o $@ ../win/Qt/qt_map.cpp -qt_menu.o: ../win/Qt/qt_menu.cpp $(HACK_H) ../win/Qt/qt_menu.h \ - ../win/Qt/qt_win.h ../win/Qt/qt_rip.h qt_menu.moc \ - ../win/Qt/qt_glyph.h ../win/Qt/qt_set.h ../win/Qt/qt_streq.h \ - ../win/Qt/qt_line.h ../win/Qt/qt_str.h - $(CXX) $(CXXFLAGS) -c -o $@ ../win/Qt/qt_menu.cpp -qt_msg.o: ../win/Qt/qt_msg.cpp $(HACK_H) ../win/Qt/qt_msg.h ../win/Qt/qt_win.h \ + $(TARGET_CXX) $(TARGET_CXXFLAGS) -c -o $@ ../win/Qt/qt_menu.cpp +$(TARGETPFX)qt_msg.o: ../win/Qt/qt_msg.cpp $(HACK_H) ../win/Qt/qt_pre.h \ + ../win/Qt/qt_post.h ../win/Qt/qt_msg.h ../win/Qt/qt_win.h \ qt_msg.moc ../win/Qt/qt_map.h ../win/Qt/qt_clust.h \ - ../win/Qt/qt_set.h ../win/Qt/qt_str.h - $(CXX) $(CXXFLAGS) -c -o $@ ../win/Qt/qt_msg.cpp -qt_plsel.o: ../win/Qt/qt_plsel.cpp $(HACK_H) ../win/Qt/qt_plsel.h qt_plsel.moc \ + ../win/Qt/qt_set.h ../win/Qt/qt_bind.h ../win/Qt/qt_main.h \ + ../win/Qt/qt_kde0.h ../win/Qt/qt_str.h + $(TARGET_CXX) $(TARGET_CXXFLAGS) -c -o $@ ../win/Qt/qt_msg.cpp +$(TARGETPFX)qt_plsel.o: ../win/Qt/qt_plsel.cpp $(HACK_H) ../win/Qt/qt_pre.h \ + ../win/Qt/qt_post.h ../win/Qt/qt_plsel.h qt_plsel.moc \ ../win/Qt/qt_bind.h ../win/Qt/qt_main.h ../win/Qt/qt_kde0.h \ ../win/Qt/qt_glyph.h ../win/Qt/qt_set.h ../win/Qt/qt_str.h - $(CXX) $(CXXFLAGS) -c -o $@ ../win/Qt/qt_plsel.cpp -qt_rip.o: ../win/Qt/qt_rip.cpp $(HACK_H) ../win/Qt/qt_rip.h \ - ../win/Qt/qt_bind.h ../win/Qt/qt_main.h ../win/Qt/qt_kde0.h \ - ../win/Qt/qt_str.h - $(CXX) $(CXXFLAGS) -c -o $@ ../win/Qt/qt_rip.cpp -qt_set.o: ../win/Qt/qt_set.cpp $(HACK_H) ../win/Qt/qt_set.h qt_set.moc \ + $(TARGET_CXX) $(TARGET_CXXFLAGS) -c -o $@ ../win/Qt/qt_plsel.cpp +$(TARGETPFX)qt_rip.o: ../win/Qt/qt_rip.cpp $(HACK_H) ../win/Qt/qt_pre.h \ + ../win/Qt/qt_post.h ../win/Qt/qt_rip.h ../win/Qt/qt_bind.h \ + ../win/Qt/qt_main.h ../win/Qt/qt_kde0.h ../win/Qt/qt_str.h + $(TARGET_CXX) $(TARGET_CXXFLAGS) -c -o $@ ../win/Qt/qt_rip.cpp +$(TARGETPFX)qt_set.o: ../win/Qt/qt_set.cpp $(HACK_H) ../win/Qt/qt_pre.h \ + ../win/Qt/qt_post.h ../win/Qt/qt_set.h ../win/Qt/qt_bind.h \ + ../win/Qt/qt_main.h ../win/Qt/qt_kde0.h qt_set.moc \ ../win/Qt/qt_glyph.h ../win/Qt/qt_str.h - $(CXX) $(CXXFLAGS) -c -o $@ ../win/Qt/qt_set.cpp -qt_stat.o: ../win/Qt/qt_stat.cpp $(HACK_H) ../win/Qt/qt_stat.h \ - ../win/Qt/qt_win.h ../win/Qt/qt_icon.h qt_stat.moc \ - ../win/Qt/qt_set.h ../win/Qt/qt_str.h ../win/Qt/qt_xpms.h - $(CXX) $(CXXFLAGS) -c -o $@ ../win/Qt/qt_stat.cpp -qt_str.o: ../win/Qt/qt_str.cpp ../win/Qt/qt_str.h - $(CXX) $(CXXFLAGS) -c -o $@ ../win/Qt/qt_str.cpp -qt_streq.o: ../win/Qt/qt_streq.cpp $(HACK_H) ../win/Qt/qt_streq.h \ - ../win/Qt/qt_line.h ../win/Qt/qt_str.h - $(CXX) $(CXXFLAGS) -c -o $@ ../win/Qt/qt_streq.cpp -qt_svsel.o: ../win/Qt/qt_svsel.cpp $(HACK_H) ../win/Qt/qt_svsel.h \ + $(TARGET_CXX) $(TARGET_CXXFLAGS) -c -o $@ ../win/Qt/qt_set.cpp +$(TARGETPFX)qt_stat.o: ../win/Qt/qt_stat.cpp $(HACK_H) ../win/Qt/qt_pre.h \ + ../win/Qt/qt_post.h ../win/Qt/qt_stat.h ../win/Qt/qt_win.h \ + ../win/Qt/qt_icon.h qt_stat.moc ../win/Qt/qt_set.h \ ../win/Qt/qt_bind.h ../win/Qt/qt_main.h ../win/Qt/qt_kde0.h \ + ../win/Qt/qt_str.h ../win/Qt/qt_xpms.h + $(TARGET_CXX) $(TARGET_CXXFLAGS) -c -o $@ ../win/Qt/qt_stat.cpp +$(TARGETPFX)qt_str.o: ../win/Qt/qt_str.cpp ../win/Qt/qt_str.h + $(TARGET_CXX) $(TARGET_CXXFLAGS) -c -o $@ ../win/Qt/qt_str.cpp +$(TARGETPFX)qt_streq.o: ../win/Qt/qt_streq.cpp $(HACK_H) ../win/Qt/qt_pre.h \ + ../win/Qt/qt_post.h ../win/Qt/qt_streq.h ../win/Qt/qt_line.h \ ../win/Qt/qt_str.h - $(CXX) $(CXXFLAGS) -c -o $@ ../win/Qt/qt_svsel.cpp -qt_win.o: ../win/Qt/qt_win.cpp $(HACK_H) ../win/Qt/qt_win.h \ - ../win/Qt/qt_bind.h ../win/Qt/qt_main.h ../win/Qt/qt_kde0.h \ - ../win/Qt/qt_click.h ../win/Qt/qt_glyph.h ../win/Qt/qt_inv.h \ - ../win/Qt/qt_key.h ../win/Qt/qt_icon.h ../win/Qt/qt_map.h \ - ../win/Qt/qt_clust.h ../win/Qt/qt_menu.h ../win/Qt/qt_rip.h \ - ../win/Qt/qt_msg.h ../win/Qt/qt_set.h - $(CXX) $(CXXFLAGS) -c -o $@ ../win/Qt/qt_win.cpp -qt_xcmd.o: ../win/Qt/qt_xcmd.cpp $(HACK_H) ../include/func_tab.h \ - ../win/Qt/qt_xcmd.h qt_xcmd.moc ../win/Qt/qt_bind.h \ - ../win/Qt/qt_main.h ../win/Qt/qt_kde0.h ../win/Qt/qt_set.h \ + $(TARGET_CXX) $(TARGET_CXXFLAGS) -c -o $@ ../win/Qt/qt_streq.cpp +$(TARGETPFX)qt_svsel.o: ../win/Qt/qt_svsel.cpp $(HACK_H) ../win/Qt/qt_pre.h \ + ../win/Qt/qt_post.h ../win/Qt/qt_svsel.h ../win/Qt/qt_bind.h \ + ../win/Qt/qt_main.h ../win/Qt/qt_kde0.h ../win/Qt/qt_str.h + $(TARGET_CXX) $(TARGET_CXXFLAGS) -c -o $@ ../win/Qt/qt_svsel.cpp +$(TARGETPFX)qt_win.o: ../win/Qt/qt_win.cpp $(HACK_H) ../win/Qt/qt_pre.h \ + ../win/Qt/qt_post.h ../win/Qt/qt_win.h ../win/Qt/qt_bind.h \ + ../win/Qt/qt_main.h ../win/Qt/qt_kde0.h ../win/Qt/qt_click.h \ + ../win/Qt/qt_glyph.h ../win/Qt/qt_inv.h ../win/Qt/qt_key.h \ + ../win/Qt/qt_icon.h ../win/Qt/qt_map.h ../win/Qt/qt_clust.h \ + ../win/Qt/qt_menu.h ../win/Qt/qt_rip.h ../win/Qt/qt_msg.h \ + ../win/Qt/qt_set.h + $(TARGET_CXX) $(TARGET_CXXFLAGS) -c -o $@ ../win/Qt/qt_win.cpp +$(TARGETPFX)qt_xcmd.o: ../win/Qt/qt_xcmd.cpp $(HACK_H) ../include/func_tab.h \ + ../win/Qt/qt_pre.h ../win/Qt/qt_post.h ../win/Qt/qt_xcmd.h \ + qt_xcmd.moc ../win/Qt/qt_bind.h ../win/Qt/qt_main.h \ + ../win/Qt/qt_kde0.h ../win/Qt/qt_set.h ../win/Qt/qt_str.h + $(TARGET_CXX) $(TARGET_CXXFLAGS) -c -o $@ ../win/Qt/qt_xcmd.cpp +$(TARGETPFX)qt_yndlg.o: ../win/Qt/qt_yndlg.cpp $(HACK_H) ../win/Qt/qt_pre.h \ + ../win/Qt/qt_post.h ../win/Qt/qt_yndlg.h qt_yndlg.moc \ ../win/Qt/qt_str.h - $(CXX) $(CXXFLAGS) -c -o $@ ../win/Qt/qt_xcmd.cpp -qt_yndlg.o: ../win/Qt/qt_yndlg.cpp $(HACK_H) ../win/Qt/qt_yndlg.h qt_yndlg.moc \ - ../win/Qt/qt_str.h - $(CXX) $(CXXFLAGS) -c -o $@ ../win/Qt/qt_yndlg.cpp -qt3_win.o: ../win/Qt3/qt3_win.cpp $(HACK_H) ../include/func_tab.h \ - ../include/dlb.h ../include/tile2x11.h \ - ../win/Qt3/qt3_win.h ../win/Qt3/qt3_clust.h \ - ../win/Qt3/qt3_kde0.h ../win/Qt3/qt3_xpms.h qt3_win.moc \ - qt3_kde0.moc qt3tableview.moc - $(CXX) $(CXXFLAGS) -c -o $@ ../win/Qt3/qt3_win.cpp -qt3_clust.o: ../win/Qt3/qt3_clust.cpp ../win/Qt3/qt3_clust.h - $(CXX) $(CXXFLAGS) -c -o $@ ../win/Qt3/qt3_clust.cpp -qt3tableview.o: ../win/Qt3/qt3tableview.cpp ../win/Qt3/qt3tableview.h - $(CXX) $(CXXFLAGS) -c -o $@ ../win/Qt3/qt3tableview.cpp -wc_chainin.o: ../win/chain/wc_chainin.c $(HACK_H) - $(CC) $(CFLAGS) -c -o $@ ../win/chain/wc_chainin.c -wc_chainout.o: ../win/chain/wc_chainout.c $(HACK_H) - $(CC) $(CFLAGS) -c -o $@ ../win/chain/wc_chainout.c -wc_trace.o: ../win/chain/wc_trace.c $(HACK_H) ../include/func_tab.h - $(CC) $(CFLAGS) -c -o $@ ../win/chain/wc_trace.c -vis_tab.o: vis_tab.c $(CONFIG_H) ../include/vis_tab.h -allmain.o: allmain.c $(HACK_H) -alloc.o: alloc.c $(CONFIG_H) -apply.o: apply.c $(HACK_H) -artifact.o: artifact.c $(HACK_H) ../include/artifact.h ../include/artilist.h -attrib.o: attrib.c $(HACK_H) -ball.o: ball.c $(HACK_H) -bones.o: bones.c $(HACK_H) -botl.o: botl.c $(HACK_H) -cmd.o: cmd.c $(HACK_H) ../include/func_tab.h -dbridge.o: dbridge.c $(HACK_H) -decl.o: decl.c $(HACK_H) -detect.o: detect.c $(HACK_H) ../include/artifact.h -dig.o: dig.c $(HACK_H) -display.o: display.c $(HACK_H) -dlb.o: dlb.c $(CONFIG_H) ../include/dlb.h -do.o: do.c $(HACK_H) -do_name.o: do_name.c $(HACK_H) -do_wear.o: do_wear.c $(HACK_H) -dog.o: dog.c $(HACK_H) -dogmove.o: dogmove.c $(HACK_H) ../include/mfndpos.h -dokick.o: dokick.c $(HACK_H) -dothrow.o: dothrow.c $(HACK_H) -drawing.o: drawing.c $(CONFIG_H) -dungeon.o: dungeon.c $(HACK_H) ../include/dgn_file.h ../include/dlb.h -eat.o: eat.c $(HACK_H) -end.o: end.c $(HACK_H) ../include/dlb.h -engrave.o: engrave.c $(HACK_H) -exper.o: exper.c $(HACK_H) -explode.o: explode.c $(HACK_H) -extralev.o: extralev.c $(HACK_H) -files.o: files.c $(HACK_H) ../include/dlb.h #zlib.h -fountain.o: fountain.c $(HACK_H) -hack.o: hack.c $(HACK_H) -hacklib.o: hacklib.c $(HACK_H) -insight.o: insight.c $(HACK_H) -invent.o: invent.c $(HACK_H) -isaac64.o: isaac64.c $(CONFIG_H) ../include/isaac64.h -light.o: light.c $(HACK_H) -lock.o: lock.c $(HACK_H) -mail.o: mail.c $(HACK_H) ../include/mail.h -makemon.o: makemon.c $(HACK_H) -mapglyph.o: mapglyph.c $(HACK_H) -mcastu.o: mcastu.c $(HACK_H) -mdlib.o: mdlib.c $(CONFIG_H) ../include/permonst.h ../include/align.h \ - ../include/monattk.h ../include/monflag.h \ + $(TARGET_CXX) $(TARGET_CXXFLAGS) -c -o $@ ../win/Qt/qt_yndlg.cpp +$(TARGETPFX)wc_chainin.o: ../win/chain/wc_chainin.c $(HACK_H) + $(TARGET_CC) $(TARGET_CFLAGS) -c -o $@ ../win/chain/wc_chainin.c +$(TARGETPFX)wc_chainout.o: ../win/chain/wc_chainout.c $(HACK_H) + $(TARGET_CC) $(TARGET_CFLAGS) -c -o $@ ../win/chain/wc_chainout.c +$(TARGETPFX)wc_trace.o: ../win/chain/wc_trace.c $(HACK_H) ../include/func_tab.h + $(TARGET_CC) $(TARGET_CFLAGS) -c -o $@ ../win/chain/wc_trace.c +$(TARGETPFX)allmain.o: allmain.c $(HACK_H) +$(TARGETPFX)alloc.o: alloc.c $(CONFIG_H) +$(TARGETPFX)apply.o: apply.c $(HACK_H) +$(TARGETPFX)artifact.o: artifact.c $(HACK_H) ../include/artifact.h \ + ../include/artilist.h +$(TARGETPFX)attrib.o: attrib.c $(HACK_H) +$(TARGETPFX)ball.o: ball.c $(HACK_H) +$(TARGETPFX)bones.o: bones.c $(HACK_H) +$(TARGETPFX)botl.o: botl.c $(HACK_H) +$(TARGETPFX)cmd.o: cmd.c $(HACK_H) ../include/func_tab.h +$(TARGETPFX)dbridge.o: dbridge.c $(HACK_H) +$(TARGETPFX)decl.o: decl.c $(HACK_H) +$(TARGETPFX)detect.o: detect.c $(HACK_H) ../include/artifact.h +$(TARGETPFX)dig.o: dig.c $(HACK_H) +$(TARGETPFX)display.o: display.c $(HACK_H) +$(TARGETPFX)dlb.o: dlb.c $(CONFIG_H) ../include/dlb.h +$(TARGETPFX)do.o: do.c $(HACK_H) +$(TARGETPFX)do_name.o: do_name.c $(HACK_H) +$(TARGETPFX)do_wear.o: do_wear.c $(HACK_H) +$(TARGETPFX)dog.o: dog.c $(HACK_H) +$(TARGETPFX)dogmove.o: dogmove.c $(HACK_H) ../include/mfndpos.h +$(TARGETPFX)dokick.o: dokick.c $(HACK_H) +$(TARGETPFX)dothrow.o: dothrow.c $(HACK_H) +$(TARGETPFX)drawing.o: drawing.c $(CONFIG_H) ../include/color.h \ + ../include/rm.h ../include/objclass.h ../include/monsym.h +$(TARGETPFX)dungeon.o: dungeon.c $(HACK_H) ../include/dgn_file.h \ + ../include/dlb.h +$(TARGETPFX)eat.o: eat.c $(HACK_H) +$(TARGETPFX)end.o: end.c $(HACK_H) ../include/dlb.h +$(TARGETPFX)engrave.o: engrave.c $(HACK_H) +$(TARGETPFX)exper.o: exper.c $(HACK_H) +$(TARGETPFX)explode.o: explode.c $(HACK_H) +$(TARGETPFX)extralev.o: extralev.c $(HACK_H) +$(TARGETPFX)files.o: files.c $(HACK_H) ../include/dlb.h #zlib.h +$(TARGETPFX)fountain.o: fountain.c $(HACK_H) +$(TARGETPFX)hack.o: hack.c $(HACK_H) +$(TARGETPFX)hacklib.o: hacklib.c $(HACK_H) +$(TARGETPFX)insight.o: insight.c $(HACK_H) +$(TARGETPFX)invent.o: invent.c $(HACK_H) +$(TARGETPFX)isaac64.o: isaac64.c $(CONFIG_H) ../include/isaac64.h +$(TARGETPFX)light.o: light.c $(HACK_H) +$(TARGETPFX)lock.o: lock.c $(HACK_H) +$(TARGETPFX)mail.o: mail.c $(HACK_H) ../include/mail.h +$(TARGETPFX)makemon.o: makemon.c $(HACK_H) +$(TARGETPFX)mapglyph.o: mapglyph.c $(HACK_H) +$(TARGETPFX)mcastu.o: mcastu.c $(HACK_H) +$(TARGETPFX)mdlib.o: mdlib.c $(CONFIG_H) ../include/permonst.h \ + ../include/align.h ../include/monattk.h ../include/monflag.h \ ../include/objclass.h ../include/monsym.h \ ../include/artilist.h ../include/dungeon.h ../include/obj.h \ ../include/monst.h ../include/mextra.h ../include/you.h \ ../include/attrib.h ../include/prop.h ../include/skills.h \ ../include/context.h ../include/flag.h ../include/dlb.h -mhitm.o: mhitm.c $(HACK_H) ../include/artifact.h -mhitu.o: mhitu.c $(HACK_H) ../include/artifact.h -minion.o: minion.c $(HACK_H) -mklev.o: mklev.c $(HACK_H) -mkmap.o: mkmap.c $(HACK_H) ../include/sp_lev.h -mkmaze.o: mkmaze.c $(HACK_H) ../include/sp_lev.h -mkobj.o: mkobj.c $(HACK_H) -mkroom.o: mkroom.c $(HACK_H) -mon.o: mon.c $(HACK_H) ../include/mfndpos.h -mondata.o: mondata.c $(HACK_H) -monmove.o: monmove.c $(HACK_H) ../include/mfndpos.h ../include/artifact.h -monst.o: monst.c $(CONFIG_H) ../include/permonst.h ../include/align.h \ - ../include/monattk.h ../include/monflag.h ../include/monsym.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) +$(TARGETPFX)mklev.o: mklev.c $(HACK_H) +$(TARGETPFX)mkmap.o: mkmap.c $(HACK_H) ../include/sp_lev.h +$(TARGETPFX)mkmaze.o: mkmaze.c $(HACK_H) ../include/sp_lev.h +$(TARGETPFX)mkobj.o: mkobj.c $(HACK_H) +$(TARGETPFX)mkroom.o: mkroom.c $(HACK_H) +$(TARGETPFX)mon.o: mon.c $(HACK_H) ../include/mfndpos.h +$(TARGETPFX)mondata.o: mondata.c $(HACK_H) +$(TARGETPFX)monmove.o: monmove.c $(HACK_H) ../include/mfndpos.h \ + ../include/artifact.h +$(TARGETPFX)monst.o: monst.c $(CONFIG_H) ../include/permonst.h \ + ../include/align.h ../include/monattk.h ../include/monflag.h \ + ../include/monsym.h ../include/color.h +$(TARGETPFX)mplayer.o: mplayer.c $(HACK_H) +$(TARGETPFX)mthrowu.o: mthrowu.c $(HACK_H) +$(TARGETPFX)muse.o: muse.c $(HACK_H) +$(TARGETPFX)music.o: music.c $(HACK_H) +$(TARGETPFX)nhlua.o: nhlua.c $(HACK_H) ../include/dlb.h +$(TARGETPFX)nhlsel.o: nhlsel.c $(HACK_H) ../include/sp_lev.h +$(TARGETPFX)nhlobj.o: nhlobj.c $(HACK_H) ../include/sp_lev.h +$(TARGETPFX)o_init.o: o_init.c $(HACK_H) +$(TARGETPFX)objects.o: objects.c $(CONFIG_H) ../include/obj.h \ + ../include/objclass.h ../include/prop.h ../include/skills.h \ ../include/color.h -mplayer.o: mplayer.c $(HACK_H) -mthrowu.o: mthrowu.c $(HACK_H) -muse.o: muse.c $(HACK_H) -music.o: music.c $(HACK_H) -nhlua.o: nhlua.c $(HACK_H) ../include/dlb.h -nhlsel.o: nhlsel.c $(HACK_H) ../include/sp_lev.h -nhlobj.o: nhlobj.c $(HACK_H) ../include/sp_lev.h -o_init.o: o_init.c $(HACK_H) -objects.o: objects.c $(CONFIG_H) ../include/obj.h ../include/objclass.h \ - ../include/prop.h ../include/skills.h ../include/color.h -objnam.o: objnam.c $(HACK_H) -options.o: options.c $(CONFIG_H) ../include/objclass.h ../include/flag.h \ - $(HACK_H) ../include/tcap.h ../include/optlist.h -pager.o: pager.c $(HACK_H) ../include/dlb.h -pickup.o: pickup.c $(HACK_H) -pline.o: pline.c $(HACK_H) -polyself.o: polyself.c $(HACK_H) -potion.o: potion.c $(HACK_H) -pray.o: pray.c $(HACK_H) -priest.o: priest.c $(HACK_H) ../include/mfndpos.h -quest.o: quest.c $(HACK_H) -questpgr.o: questpgr.c $(HACK_H) ../include/dlb.h -read.o: read.c $(HACK_H) -rect.o: rect.c $(HACK_H) -region.o: region.c $(HACK_H) -restore.o: restore.c $(HACK_H) ../include/tcap.h -rip.o: rip.c $(HACK_H) -rnd.o: rnd.c $(HACK_H) ../include/isaac64.h -role.o: role.c $(HACK_H) -rumors.o: rumors.c $(HACK_H) ../include/dlb.h -save.o: save.c $(HACK_H) -sfstruct.o: sfstruct.c $(HACK_H) -shk.o: shk.c $(HACK_H) -shknam.o: shknam.c $(HACK_H) -sit.o: sit.c $(HACK_H) ../include/artifact.h -sounds.o: sounds.c $(HACK_H) -sp_lev.o: sp_lev.c $(HACK_H) ../include/sp_lev.h -spell.o: spell.c $(HACK_H) -steal.o: steal.c $(HACK_H) -steed.o: steed.c $(HACK_H) -symbols.o: symbols.c $(HACK_H) ../include/tcap.h -sys.o: sys.c $(HACK_H) -teleport.o: teleport.c $(HACK_H) -timeout.o: timeout.c $(HACK_H) -topten.o: topten.c $(HACK_H) ../include/dlb.h -track.o: track.c $(HACK_H) -trap.o: trap.c $(HACK_H) -u_init.o: u_init.c $(HACK_H) -uhitm.o: uhitm.c $(HACK_H) -vault.o: vault.c $(HACK_H) -version.o: version.c $(HACK_H) ../include/dlb.h ../include/date.h -vision.o: vision.c $(HACK_H) ../include/vis_tab.h -weapon.o: weapon.c $(HACK_H) -were.o: were.c $(HACK_H) -wield.o: wield.c $(HACK_H) -windows.o: windows.c $(HACK_H) ../include/wingem.h ../include/winGnome.h -wizard.o: wizard.c $(HACK_H) -worm.o: worm.c $(HACK_H) -worn.o: worn.c $(HACK_H) -write.o: write.c $(HACK_H) -zap.o: zap.c $(HACK_H) +$(TARGETPFX)objnam.o: objnam.c $(HACK_H) +$(TARGETPFX)options.o: options.c $(CONFIG_H) ../include/objclass.h \ + ../include/flag.h $(HACK_H) ../include/tcap.h \ + ../include/optlist.h +$(TARGETPFX)pager.o: pager.c $(HACK_H) ../include/dlb.h +$(TARGETPFX)pickup.o: pickup.c $(HACK_H) +$(TARGETPFX)pline.o: pline.c $(HACK_H) +$(TARGETPFX)polyself.o: polyself.c $(HACK_H) +$(TARGETPFX)potion.o: potion.c $(HACK_H) +$(TARGETPFX)pray.o: pray.c $(HACK_H) +$(TARGETPFX)priest.o: priest.c $(HACK_H) ../include/mfndpos.h +$(TARGETPFX)quest.o: quest.c $(HACK_H) +$(TARGETPFX)questpgr.o: questpgr.c $(HACK_H) ../include/dlb.h +$(TARGETPFX)read.o: read.c $(HACK_H) +$(TARGETPFX)rect.o: rect.c $(HACK_H) +$(TARGETPFX)region.o: region.c $(HACK_H) +$(TARGETPFX)restore.o: restore.c $(HACK_H) ../include/tcap.h +$(TARGETPFX)rip.o: rip.c $(HACK_H) +$(TARGETPFX)rnd.o: rnd.c $(HACK_H) ../include/isaac64.h +$(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)sfstruct.o: sfstruct.c $(HACK_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 +$(TARGETPFX)sounds.o: sounds.c $(HACK_H) +$(TARGETPFX)sp_lev.o: sp_lev.c $(HACK_H) ../include/sp_lev.h +$(TARGETPFX)spell.o: spell.c $(HACK_H) +$(TARGETPFX)steal.o: steal.c $(HACK_H) +$(TARGETPFX)steed.o: steed.c $(HACK_H) +$(TARGETPFX)symbols.o: symbols.c $(HACK_H) ../include/tcap.h +$(TARGETPFX)sys.o: sys.c $(HACK_H) +$(TARGETPFX)teleport.o: teleport.c $(HACK_H) +$(TARGETPFX)timeout.o: timeout.c $(HACK_H) +$(TARGETPFX)topten.o: topten.c $(HACK_H) ../include/dlb.h +$(TARGETPFX)track.o: track.c $(HACK_H) +$(TARGETPFX)trap.o: trap.c $(HACK_H) +$(TARGETPFX)u_init.o: u_init.c $(HACK_H) +$(TARGETPFX)uhitm.o: uhitm.c $(HACK_H) +$(TARGETPFX)vault.o: vault.c $(HACK_H) +$(TARGETPFX)version.o: version.c $(HACK_H) ../include/dlb.h ../include/date.h +$(TARGETPFX)vision.o: vision.c $(HACK_H) +$(TARGETPFX)weapon.o: weapon.c $(HACK_H) +$(TARGETPFX)were.o: were.c $(HACK_H) +$(TARGETPFX)wield.o: wield.c $(HACK_H) +$(TARGETPFX)windows.o: windows.c $(HACK_H) ../include/wingem.h \ + ../include/winGnome.h +$(TARGETPFX)wizard.o: wizard.c $(HACK_H) +$(TARGETPFX)worm.o: worm.c $(HACK_H) +$(TARGETPFX)worn.o: worn.c $(HACK_H) +$(TARGETPFX)write.o: write.c $(HACK_H) +$(TARGETPFX)zap.o: zap.c $(HACK_H) # DEPENDENCIES MUST END AT END OF FILE # IF YOU PUT STUFF HERE IT WILL GO AWAY # see make depend above diff --git a/sys/unix/Makefile.top b/sys/unix/Makefile.top index 9070d60e8..75fd32370 100644 --- a/sys/unix/Makefile.top +++ b/sys/unix/Makefile.top @@ -1,5 +1,5 @@ # NetHack Top-level Makefile. -# NetHack 3.6 Makefile.top $NHDT-Date: 1594155882 2020/07/07 21:04:42 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.50 $ +# NetHack 3.7 Makefile.top $NHDT-Date: 1609074072 2020/12/27 13:01:12 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.65 $ # Copyright (c) 2015 by Kenneth Lorber, Kensington, Maryland # NetHack may be freely redistributed. See license for details. @@ -47,7 +47,7 @@ DIRPERM = 0755 #SHELLDIR = $(PREFIX)/games # per discussion in Install.X11 and Install.Qt -#VARDATND = +#VARDATND = # VARDATND = x11tiles NetHack.ad pet_mark.xbm pilemark.xbm # VARDATND = x11tiles NetHack.ad pet_mark.xbm pilemark.xbm rip.xpm # for Atari/Gem @@ -75,7 +75,7 @@ VARDAT = $(VARDATD) $(VARDATND) #CHGRP = chgrp # Lua version -LUA_VERSION = 5.4.0 +LUA_VERSION = 5.4.2 # # end of configuration @@ -94,23 +94,26 @@ DATNODLB = $(VARDATND) license symbols DATDLB = $(DATHELP) dungeon.lua tribute $(SPEC_LEVS) $(QUEST_LEVS) $(VARDATD) DAT = $(DATNODLB) $(DATDLB) +TOPLUALIB = lib/lua/liblua.a +ALLDEP = $(GAME) recover Guidebook $(VARDAT) spec_levs check-dlb + # first target is also the default target for 'make' without any arguments -all: $(GAME) recover Guidebook $(VARDAT) spec_levs check-dlb +all: $(ALLDEP) true; $(MOREALL) @echo "Done." $(GAME): lua_support ( cd src ; $(MAKE) $(GAME) ) -lua_support: lib/lua/liblua.a include/nhlua.h +lua_support: $(TOPLUALIB) include/nhlua.h @true lib/lua-$(LUA_VERSION)/src/liblua.a: lib/lua-$(LUA_VERSION)/src/lua.h ( cd lib/lua-$(LUA_VERSION)/src \ - && make SYSCFLAGS='$(SYSCFLAGS)' a && cd ../../.. ) + && make CC='$(CC)' SYSCFLAGS='$(SYSCFLAGS)' a && cd ../../.. ) lib/lua/liblua.a: lib/lua-$(LUA_VERSION)/src/liblua.a @( if [ ! -d lib/lua ] ; then mkdir -p lib/lua ; fi ) cp lib/lua-$(LUA_VERSION)/src/liblua.a $@ -include/nhlua.h: lib/lua/liblua.a +include/nhlua.h: $(TOPLUALIB) echo '/* nhlua.h - generated by top Makefile */' > $@ @echo '#include "../lib/lua-$(LUA_VERSION)/src/lua.h"' >> $@ @sed -e '/(lua_error)/!d' -e '/(lua_error)/s/;/ NORETURN;/1' \ @@ -157,6 +160,7 @@ spec_levs: ( cd dat ; $(MAKE) quest_levs ) nhtiles.bmp: $(GAME) + ( cd util ; $(MAKE) tile2bmp ) ( cd dat ; $(MAKE) nhtiles.bmp ) x11tiles: $(GAME) @@ -205,6 +209,12 @@ dlb: ( cd util ; $(MAKE) dlb ) ( cd dat ; LC_ALL=C ; ../util/dlb cf nhdat $(DATDLB) ) +wasm: + ( cd src ; $(MAKE) CROSS_TO_WASM=1 ../targets/wasm/nethack.js ) + +package: $(GAME) recover $(VARDAT) spec_levs + ( cd src ; $(MAKE) $(PACKAGE) ) + # recover can be used when INSURANCE is defined in include/config.h # and the checkpoint option is true recover: $(GAME) @@ -261,6 +271,8 @@ fetch-Lua: ( mkdir -p lib && cd lib && \ curl -R -O http://www.lua.org/ftp/lua-$(LUA_VERSION).tar.gz && \ tar zxf lua-$(LUA_VERSION).tar.gz && rm -f lua-$(LUA_VERSION).tar.gz ) +#if we just fetched lua, force include/nhlua.h to be built based on it + -rm include/nhlua.h update: $(GAME) recover $(VARDAT) spec_levs # (don't yank the old version out from under people who're playing it) @@ -311,11 +323,11 @@ clean: ( cd util ; $(MAKE) clean ) ( cd dat ; $(MAKE) clean ) ( cd doc ; $(MAKE) clean ) - ( cd lib/lua-$(LUA_VERSION)/src && $(MAKE) clean ) + -( cd lib/lua-$(LUA_VERSION)/src && $(MAKE) clean ) # 'make spotless' returns the source tree to near-distribution condition. # it removes .o files, executables, and compiled data files -spotless:: +spotless:: clean ( cd src ; $(MAKE) spotless ) ( cd util ; $(MAKE) spotless ) ( cd dat ; $(MAKE) spotless ) diff --git a/sys/unix/Makefile.utl b/sys/unix/Makefile.utl index 987e4d447..38ef8bebf 100644 --- a/sys/unix/Makefile.utl +++ b/sys/unix/Makefile.utl @@ -1,5 +1,5 @@ # Makefile for NetHack's utility programs. -# NetHack 3.6 Makefile.utl $NHDT-Date: 1588776926 2020/05/06 14:55:26 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.50 $ +# NetHack 3.7 Makefile.utl $NHDT-Date: 1602258295 2020/10/09 15:44:55 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.53 $ # Copyright (c) 2018 by Robert Patrick Rankin # NetHack may be freely redistributed. See license for details. @@ -106,9 +106,6 @@ CPPFLAGS = LIBS = -# If you are cross-compiling, you must use this: -#OBJDIR = . -# otherwise, you can save a little bit of disk space with this: OBJDIR = ../src # if you change this to 1, feedback while building will omit -Dthis -Wthat @@ -123,6 +120,10 @@ QUIETCC=0 # in Makefile.src; these use '$(CC) $(LFLAGS)' and ought to be changed to use # $(LD) or $(LINK) as appropriate [quiet mode echoes a misleading $< value] +# [LINK might be defined to use $(CXX); we don't want that here.] +CLINK=$(CC) +CXXLINK=$(CXX) + # ---------------------------------------- # # Nothing below this line should have to be changed. @@ -134,7 +135,7 @@ QUIETCC=0 ACTUAL_CC := $(CC) ACTUAL_CXX := $(CXX) ACTUAL_LD := $(LD) -ACTUAL_LINK := $(LINK) +ACTUAL_CLINK := $(CLINK) CC_V0 = $(ACTUAL_CC) CC_V = $(CC_V0) @@ -149,7 +150,7 @@ CXX = $(CXX_V$(QUIETCC)) # LD and LINK might be based on invoking CC and may not be able to substitute # for QUIETCC, so feedback from them is handled differently (via $AT) LD = $(ACTUAL_LD) -LINK = $(ACTUAL_LINK) +CLINK = $(ACTUAL_CLINK) AT_V0 := AT_V := $(AT_V0) @@ -165,7 +166,7 @@ HACK_H = ../src/hack.h-t MAKESRC = makedefs.c ../src/mdlib.c RECOVSRC = recover.c DLBSRC = dlb_main.c -UTILSRCS = $(MAKESRC) panic.c $(DGNCOMPSRC) $(RECOVSRC) $(DLBSRC) +UTILSRCS = $(MAKESRC) panic.c $(RECOVSRC) $(DLBSRC) # files that define all monsters and objects CMONOBJ = ../src/monst.c ../src/objects.c @@ -186,17 +187,31 @@ RECOVOBJS = recover.o # object files for the data librarian DLBOBJS = dlb_main.o $(OBJDIR)/dlb.o $(OALLOC) +# Distinguish between the build tools for the native host +# and the build tools for the target environment in commands. +# This allows the same set of Makefiles to be used for native +# builds and for cross-compiles by overriding these in hints +# files or on the command line. + +TARGETPFX= +TARGET_CC = $(CC) +TARGET_CFLAGS = $(CFLAGS) +TARGET_CLINK = $(CLINK) +TARGET_LFLAGS = $(LFLAGS) +TARGET_CXX = $(CXX) +TARGET_CXXFLAGS = $(CXXFLAGS) # dependencies for makedefs # makedefs: $(MAKEOBJS) mdgrep.h - $(CC) $(LFLAGS) -o makedefs $(MAKEOBJS) + $(CLINK) $(LFLAGS) -o makedefs $(MAKEOBJS) makedefs.o: makedefs.c ../src/mdlib.c $(CONFIG_H) ../include/permonst.h \ ../include/objclass.h ../include/monsym.h \ ../include/artilist.h ../include/dungeon.h ../include/obj.h \ ../include/monst.h ../include/you.h ../include/flag.h \ ../include/dlb.h ../include/patchlevel.h + $(CC) $(CFLAGS) -c makedefs.c -o $@ # Don't require perl to build; that is why mdgrep.h is spelled wrong below. mdgreph: mdgrep.pl @@ -206,10 +221,6 @@ mdgreph: mdgrep.pl ./makedefs -o ../include/pm.h: makedefs ./makedefs -p -../include/vis_tab.h: makedefs - ./makedefs -z -# makedefs -z makes both vis_tab.h and vis_tab.c, but writes the .h first -../src/vis_tab.c: ../include/vis_tab.h lintdefs: @lint -axbh -I../include -DLINT $(MAKESRC) $(CMONOBJ) | sed '/_flsbuf/d' @@ -222,18 +233,20 @@ lintdefs: # support code used by several of the utility programs (but not makedefs) panic.o: panic.c $(CONFIG_H) + $(CC) $(CFLAGS) -c panic.c -o $@ # with all of extern.h's functions to complain about, we drown in # 'defined but not used' without -u lintdgn: - @lint -axhu -I../include -DLINT $(DGNCOMPSRC) $(CALLOC) | sed '/_flsbuf/d' + @lint -axhu -I../include -DLINT $(UTILSRCS) $(CALLOC) \ + | sed '/_flsbuf/d' # dependencies for recover # recover: $(RECOVOBJS) - $(CC) $(LFLAGS) -o recover $(RECOVOBJS) $(LIBS) + $(CLINK) $(LFLAGS) -o recover $(RECOVOBJS) $(LIBS) recover.o: recover.c $(CONFIG_H) ../include/date.h @@ -241,11 +254,10 @@ recover.o: recover.c $(CONFIG_H) ../include/date.h # dependencies for dlb # dlb: $(DLBOBJS) - $(CC) $(LFLAGS) -o dlb $(DLBOBJS) $(LIBS) + $(CLINK) $(LFLAGS) -o dlb $(DLBOBJS) $(LIBS) dlb_main.o: dlb_main.c $(CONFIG_H) ../include/dlb.h ../include/date.h - $(CC) $(CFLAGS) -c dlb_main.c - + $(CC) $(CFLAGS) -c dlb_main.c -o $@ # dependencies for tile utilities @@ -257,24 +269,25 @@ PPMWRITERS = ppmwrite.o tileutils: tilemap gif2txt txt2ppm tile2x11 gif2txt: $(GIFREADERS) $(TEXT_IO) - $(CC) $(LFLAGS) -o gif2txt $(GIFREADERS) $(TEXT_IO) $(LIBS) + $(CLINK) $(LFLAGS) -o gif2txt $(GIFREADERS) $(TEXT_IO) $(LIBS) txt2ppm: $(PPMWRITERS) $(TEXT_IO) - $(CC) $(LFLAGS) -o txt2ppm $(PPMWRITERS) $(TEXT_IO) $(LIBS) + $(CLINK) $(LFLAGS) -o txt2ppm $(PPMWRITERS) $(TEXT_IO) $(LIBS) tile2x11: tile2x11.o $(TEXT_IO) - $(CC) $(LFLAGS) -o tile2x11 tile2x11.o $(TEXT_IO) $(LIBS) + $(CLINK) $(LFLAGS) -o tile2x11 tile2x11.o $(TEXT_IO) $(LIBS) tile2img.ttp: tile2img.o bitmfile.o $(TEXT_IO) - $(CC) $(LFLAGS) -o tile2img.ttp tile2img.o bitmfile.o $(TEXT_IO) $(LIBS) + $(CLINK) $(LFLAGS) -o tile2img.ttp tile2img.o bitmfile.o \ + $(TEXT_IO) $(LIBS) tile2bmp: tile2bmp.o $(TEXT_IO) - $(CC) $(LFLAGS) -o tile2bmp tile2bmp.o $(TEXT_IO) + $(CLINK) $(LFLAGS) -o tile2bmp tile2bmp.o $(TEXT_IO) xpm2img.ttp: xpm2img.o bitmfile.o - $(CC) $(LFLAGS) -o xpm2img.ttp xpm2img.o bitmfile.o $(LIBS) + $(CLINK) $(LFLAGS) -o xpm2img.ttp xpm2img.o bitmfile.o $(LIBS) tile2beos: tile2beos.o $(TEXT_IO) - $(CC) $(LFLAGS) -o tile2beos tile2beos.o $(TEXT_IO) -lbe + $(CXXLINK) $(LFLAGS) -o tile2beos tile2beos.o $(TEXT_IO) -lbe #--compiling and linking in one step leaves extra debugging files (in their # own subdirectories!) on OSX; compile and link separately to suppress @@ -282,14 +295,14 @@ tile2beos: tile2beos.o $(TEXT_IO) #tilemap: ../win/share/tilemap.c $(HACK_H) # $(CC) $(CFLAGS) $(LFLAGS) -o tilemap ../win/share/tilemap.c $(LIBS) tilemap: tilemap.o - $(CC) $(LFLAGS) -o tilemap tilemap.o $(LIBS) + $(CLINK) $(LFLAGS) -o tilemap tilemap.o $(LIBS) ../src/tile.c: tilemap ./tilemap ../include/tile.h: ../win/share/tile.h cp ../win/share/tile.h ../include/tile.h tiletext.o: ../win/share/tiletext.c $(CONFIG_H) ../include/tile.h - $(CC) $(CFLAGS) -c ../win/share/tiletext.c + $(CC) $(CFLAGS) -c ../win/share/tiletext.c -o $@ tiletxt.c: ./Makefile @echo '/* alternate compilation for tilemap.c to create tiletxt.o' > tiletxt.c @echo ' that does not rely on "cc -c -o tiletxt.o tilemap.c"' >> tiletxt.c @@ -298,37 +311,39 @@ tiletxt.c: ./Makefile echo '#include "../win/share/tilemap.c"' >> tiletxt.c @echo '/*tiletxt.c*/' >> tiletxt.c tiletxt.o: tiletxt.c ../win/share/tilemap.c $(HACK_H) - $(CC) $(CFLAGS) -c tiletxt.c + $(CC) $(CFLAGS) -c tiletxt.c -o $@ tilemap.o: ../win/share/tilemap.c $(HACK_H) - $(CC) $(CFLAGS) -c ../win/share/tilemap.c + $(CC) $(CFLAGS) -c ../win/share/tilemap.c -o $@ gifread.o: ../win/share/gifread.c $(CONFIG_H) ../include/tile.h - $(CC) $(CFLAGS) -c ../win/share/gifread.c + $(CC) $(CFLAGS) -c ../win/share/gifread.c -o $@ ppmwrite.o: ../win/share/ppmwrite.c $(CONFIG_H) ../include/tile.h - $(CC) $(CFLAGS) -c ../win/share/ppmwrite.c + $(CC) $(CFLAGS) -c ../win/share/ppmwrite.c -o $@ tile2bmp.o: ../win/share/tile2bmp.c $(HACK_H) ../include/tile.h - $(CC) $(CFLAGS) -c ../win/share/tile2bmp.c + $(CC) $(CFLAGS) -c ../win/share/tile2bmp.c -o $@ tile2x11.o: ../win/X11/tile2x11.c $(HACK_H) ../include/tile.h \ ../include/tile2x11.h - $(CC) $(CFLAGS) -c ../win/X11/tile2x11.c + $(CC) $(CFLAGS) -c ../win/X11/tile2x11.c -o $@ tile2img.o: ../win/gem/tile2img.c $(HACK_H) ../include/tile.h \ ../include/bitmfile.h - $(CC) $(CFLAGS) -c ../win/gem/tile2img.c + $(CC) $(CFLAGS) -c ../win/gem/tile2img.c -o $@ xpm2img.o: ../win/gem/xpm2img.c $(HACK_H) ../include/bitmfile.h - $(CC) $(CFLAGS) -c ../win/gem/xpm2img.c + $(CC) $(CFLAGS) -c ../win/gem/xpm2img.c -o $@ bitmfile.o: ../win/gem/bitmfile.c ../include/bitmfile.h - $(CC) $(CFLAGS) -c ../win/gem/bitmfile.c + $(CC) $(CFLAGS) -c ../win/gem/bitmfile.c -o $@ tile2beos.o: ../win/BeOS/tile2beos.cpp $(HACK_H) ../include/tile.h - $(CXX) $(CFLAGS) -c ../win/BeOS/tile2beos.cpp + $(CXX) $(CFLAGS) -c ../win/BeOS/tile2beos.cpp -o $@ -tileedit: tileedit.cpp $(TEXT_IO) +# note: tileedit.cpp was developed for Qt2 and will not compile using Qt5 +tileedit.o: ../win/Qt/tileedit.cpp + $(CXX) -I../include -I$(QTDIR)/include ../win/Qt/tileedit.cpp +tileedit: tileedit.o $(TEXT_IO) $(QTDIR)/bin/moc -o tileedit.moc tileedit.h - $(CC) -o tileedit -I../include -I$(QTDIR)/include -L$(QTDIR)/lib \ - tileedit.cpp $(TEXT_IO) -lqt + $(CXXLINK) -o tileedit -L$(QTDIR)/lib tileedit.o $(TEXT_IO) -lqt # using dependencies like # ../src/foo:: @@ -341,8 +356,7 @@ tileedit: tileedit.cpp $(TEXT_IO) # to improvise things not in the instructions, like 'make makedefs' here # in util... -# make sure object files from src are available when needed -# +# make sure host object files from src are available when needed $(OBJDIR)/alloc.o: ../src/alloc.c $(CONFIG_H) $(CC) $(CFLAGS) -c ../src/alloc.c -o $@ $(OBJDIR)/drawing.o: ../src/drawing.c $(CONFIG_H) diff --git a/sys/unix/NetHack.xcodeproj/project.pbxproj b/sys/unix/NetHack.xcodeproj/project.pbxproj index 78a8a4b3b..0632530ea 100644 --- a/sys/unix/NetHack.xcodeproj/project.pbxproj +++ b/sys/unix/NetHack.xcodeproj/project.pbxproj @@ -237,13 +237,11 @@ 3186A36F21A4B0FA0052BF02 /* winprocs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = winprocs.h; path = ../../include/winprocs.h; sourceTree = ""; }; 3186A37021A4B0FA0052BF02 /* extern.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = extern.h; path = ../../include/extern.h; sourceTree = ""; }; 3186A37121A4B0FA0052BF02 /* context.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = context.h; path = ../../include/context.h; sourceTree = ""; }; - 3186A37221A4B0FA0052BF02 /* mac-term.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "mac-term.h"; path = "../../include/mac-term.h"; sourceTree = ""; }; 3186A37321A4B0FA0052BF02 /* func_tab.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = func_tab.h; path = ../../include/func_tab.h; sourceTree = ""; }; 3186A37421A4B0FA0052BF02 /* attrib.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = attrib.h; path = ../../include/attrib.h; sourceTree = ""; }; 3186A37521A4B0FA0052BF02 /* patchlevel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = patchlevel.h; path = ../../include/patchlevel.h; sourceTree = ""; }; 3186A37621A4B0FA0052BF02 /* wincurs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = wincurs.h; path = ../../include/wincurs.h; sourceTree = ""; }; 3186A37721A4B0FA0052BF02 /* pm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = pm.h; path = ../../include/pm.h; sourceTree = ""; }; - 3186A37821A4B0FA0052BF02 /* qt_kde0.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = qt_kde0.h; path = ../../include/qt_kde0.h; sourceTree = ""; }; 3186A37921A4B0FA0052BF02 /* monattk.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = monattk.h; path = ../../include/monattk.h; sourceTree = ""; }; 3186A37A21A4B0FA0052BF02 /* integer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = integer.h; path = ../../include/integer.h; sourceTree = ""; }; 3186A37B21A4B0FA0052BF02 /* region.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = region.h; path = ../../include/region.h; sourceTree = ""; }; @@ -258,10 +256,8 @@ 3186A38521A4B0FB0052BF02 /* mextra.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mextra.h; path = ../../include/mextra.h; sourceTree = ""; }; 3186A38721A4B0FB0052BF02 /* color.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = color.h; path = ../../include/color.h; sourceTree = ""; }; 3186A38821A4B0FB0052BF02 /* artifact.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = artifact.h; path = ../../include/artifact.h; sourceTree = ""; }; - 3186A38921A4B0FB0052BF02 /* mttypriv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mttypriv.h; path = ../../include/mttypriv.h; sourceTree = ""; }; 3186A38A21A4B0FB0052BF02 /* system.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = system.h; path = ../../include/system.h; sourceTree = ""; }; 3186A38B21A4B0FC0052BF02 /* onames.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = onames.h; path = ../../include/onames.h; sourceTree = ""; }; - 3186A38C21A4B0FC0052BF02 /* trampoli.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = trampoli.h; path = ../../include/trampoli.h; sourceTree = ""; }; 3186A38D21A4B0FC0052BF02 /* vis_tab.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = vis_tab.h; path = ../../include/vis_tab.h; sourceTree = ""; }; 3186A38E21A4B0FC0052BF02 /* dlb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dlb.h; path = ../../include/dlb.h; sourceTree = ""; }; 3186A38F21A4B0FC0052BF02 /* monflag.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = monflag.h; path = ../../include/monflag.h; sourceTree = ""; }; @@ -270,19 +266,15 @@ 3186A39421A4B0FC0052BF02 /* tileset.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = tileset.h; path = ../../include/tileset.h; sourceTree = ""; }; 3186A39521A4B0FC0052BF02 /* obj.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = obj.h; path = ../../include/obj.h; sourceTree = ""; }; 3186A39721A4B0FC0052BF02 /* rm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = rm.h; path = ../../include/rm.h; sourceTree = ""; }; - 3186A39821A4B0FC0052BF02 /* qt_clust.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = qt_clust.h; path = ../../include/qt_clust.h; sourceTree = ""; }; 3186A39921A4B0FD0052BF02 /* load_img.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = load_img.h; path = ../../include/load_img.h; sourceTree = ""; }; 3186A39A21A4B0FD0052BF02 /* wintty.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = wintty.h; path = ../../include/wintty.h; sourceTree = ""; }; 3186A39B21A4B0FD0052BF02 /* ntconf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ntconf.h; path = ../../include/ntconf.h; sourceTree = ""; }; 3186A39C21A4B0FD0052BF02 /* mkroom.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mkroom.h; path = ../../include/mkroom.h; sourceTree = ""; }; - 3186A39D21A4B0FD0052BF02 /* macpopup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = macpopup.h; path = ../../include/macpopup.h; sourceTree = ""; }; 3186A39E21A4B0FD0052BF02 /* quest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = quest.h; path = ../../include/quest.h; sourceTree = ""; }; - 3186A39F21A4B0FD0052BF02 /* mac-qt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "mac-qt.h"; path = "../../include/mac-qt.h"; sourceTree = ""; }; 3186A3A021A4B0FD0052BF02 /* dgn_file.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dgn_file.h; path = ../../include/dgn_file.h; sourceTree = ""; }; 3186A3A121A4B0FD0052BF02 /* tile2x11.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = tile2x11.h; path = ../../include/tile2x11.h; sourceTree = ""; }; 3186A3A221A4B0FD0052BF02 /* engrave.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = engrave.h; path = ../../include/engrave.h; sourceTree = ""; }; 3186A3A321A4B0FD0052BF02 /* spell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = spell.h; path = ../../include/spell.h; sourceTree = ""; }; - 3186A3A421A4B0FD0052BF02 /* mac-carbon.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "mac-carbon.h"; path = "../../include/mac-carbon.h"; sourceTree = ""; }; 3186A3A521A4B0FD0052BF02 /* hack.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = hack.h; path = ../../include/hack.h; sourceTree = ""; }; 3186A3A721A4B0FD0052BF02 /* youprop.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = youprop.h; path = ../../include/youprop.h; sourceTree = ""; }; 3186A3A821A4B0FD0052BF02 /* objclass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = objclass.h; path = ../../include/objclass.h; sourceTree = ""; }; @@ -291,30 +283,25 @@ 3186A3AB21A4B0FD0052BF02 /* artilist.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = artilist.h; path = ../../include/artilist.h; sourceTree = ""; }; 3186A3AC21A4B0FD0052BF02 /* dungeon.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dungeon.h; path = ../../include/dungeon.h; sourceTree = ""; }; 3186A3AD21A4B0FD0052BF02 /* unixconf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = unixconf.h; path = ../../include/unixconf.h; sourceTree = ""; }; - 3186A3AE21A4B0FD0052BF02 /* mactty.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mactty.h; path = ../../include/mactty.h; sourceTree = ""; }; 3186A3B021A4B0FD0052BF02 /* date.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = date.h; path = ../../include/date.h; sourceTree = ""; }; 3186A3B121A4B0FD0052BF02 /* bitmfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = bitmfile.h; path = ../../include/bitmfile.h; sourceTree = ""; }; 3186A3B321A4B0FD0052BF02 /* mfndpos.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mfndpos.h; path = ../../include/mfndpos.h; sourceTree = ""; }; - 3186A3B421A4B0FD0052BF02 /* qt_win.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = qt_win.h; path = ../../include/qt_win.h; sourceTree = ""; }; 3186A3B521A4B0FD0052BF02 /* flag.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = flag.h; path = ../../include/flag.h; sourceTree = ""; }; 3186A3B621A4B0FD0052BF02 /* sp_lev.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sp_lev.h; path = ../../include/sp_lev.h; sourceTree = ""; }; 3186A3B721A4B0FD0052BF02 /* align.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = align.h; path = ../../include/align.h; sourceTree = ""; }; 3186A3B821A4B0FD0052BF02 /* mail.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mail.h; path = ../../include/mail.h; sourceTree = ""; }; 3186A3BB21A4B0FD0052BF02 /* monst.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = monst.h; path = ../../include/monst.h; sourceTree = ""; }; 3186A3BC21A4B0FD0052BF02 /* lint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = lint.h; path = ../../include/lint.h; sourceTree = ""; }; - 3186A3BD21A4B0FD0052BF02 /* qt_xpms.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = qt_xpms.h; path = ../../include/qt_xpms.h; sourceTree = ""; }; 3186A3BE21A4B0FD0052BF02 /* vmsconf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = vmsconf.h; path = ../../include/vmsconf.h; sourceTree = ""; }; 3186A3BF21A4B0FD0052BF02 /* you.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = you.h; path = ../../include/you.h; sourceTree = ""; }; 3186A3C021A4B0FD0052BF02 /* wintype.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = wintype.h; path = ../../include/wintype.h; sourceTree = ""; }; 3186A3C121A4B0FD0052BF02 /* global.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = global.h; path = ../../include/global.h; sourceTree = ""; }; 3186A3C221A4B0FE0052BF02 /* winX.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = winX.h; path = ../../include/winX.h; sourceTree = ""; }; 3186A3C321A4B0FE0052BF02 /* tcap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = tcap.h; path = ../../include/tcap.h; sourceTree = ""; }; - 3186A3C421A4B0FE0052BF02 /* qttableview.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = qttableview.h; path = ../../include/qttableview.h; sourceTree = ""; }; 3186A3C521A4B0FE0052BF02 /* coord.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = coord.h; path = ../../include/coord.h; sourceTree = ""; }; 3186A3C621A4B0FE0052BF02 /* config1.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = config1.h; path = ../../include/config1.h; sourceTree = ""; }; 3186A3C721A4B0FE0052BF02 /* tradstdc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = tradstdc.h; path = ../../include/tradstdc.h; sourceTree = ""; }; 3186A3C821A4B0FE0052BF02 /* mondata.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mondata.h; path = ../../include/mondata.h; sourceTree = ""; }; - 3186A3C921A4B0FE0052BF02 /* macwin.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = macwin.h; path = ../../include/macwin.h; sourceTree = ""; }; 3186A3CA21A4B0FE0052BF02 /* timeout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = timeout.h; path = ../../include/timeout.h; sourceTree = ""; }; 3186A3CB21A4B0FE0052BF02 /* sys.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sys.h; path = ../../include/sys.h; sourceTree = ""; }; 3186A3CC21A4B0FE0052BF02 /* gem_rsc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = gem_rsc.h; path = ../../include/gem_rsc.h; sourceTree = ""; }; @@ -702,12 +689,6 @@ 3186A37A21A4B0FA0052BF02 /* integer.h */, 3186A3BC21A4B0FD0052BF02 /* lint.h */, 3186A39921A4B0FD0052BF02 /* load_img.h */, - 3186A3A421A4B0FD0052BF02 /* mac-carbon.h */, - 3186A39F21A4B0FD0052BF02 /* mac-qt.h */, - 3186A37221A4B0FA0052BF02 /* mac-term.h */, - 3186A39D21A4B0FD0052BF02 /* macpopup.h */, - 3186A3AE21A4B0FD0052BF02 /* mactty.h */, - 3186A3C921A4B0FE0052BF02 /* macwin.h */, 3186A3B821A4B0FD0052BF02 /* mail.h */, 3186A38521A4B0FB0052BF02 /* mextra.h */, 3186A3B321A4B0FD0052BF02 /* mfndpos.h */, @@ -718,7 +699,6 @@ 3186A38F21A4B0FC0052BF02 /* monflag.h */, 3186A3BB21A4B0FD0052BF02 /* monst.h */, 3186A38421A4B0FB0052BF02 /* monsym.h */, - 3186A38921A4B0FB0052BF02 /* mttypriv.h */, 3186A39B21A4B0FD0052BF02 /* ntconf.h */, 3186A39521A4B0FC0052BF02 /* obj.h */, 3186A3A821A4B0FD0052BF02 /* objclass.h */, @@ -728,11 +708,6 @@ 3186A38321A4B0FB0052BF02 /* permonst.h */, 3186A37721A4B0FA0052BF02 /* pm.h */, 3186A37F21A4B0FA0052BF02 /* prop.h */, - 3186A39821A4B0FC0052BF02 /* qt_clust.h */, - 3186A37821A4B0FA0052BF02 /* qt_kde0.h */, - 3186A3B421A4B0FD0052BF02 /* qt_win.h */, - 3186A3BD21A4B0FD0052BF02 /* qt_xpms.h */, - 3186A3C421A4B0FE0052BF02 /* qttableview.h */, 3186A39E21A4B0FD0052BF02 /* quest.h */, 3186A37C21A4B0FA0052BF02 /* rect.h */, 3186A37B21A4B0FA0052BF02 /* region.h */, @@ -747,7 +722,6 @@ 3186A39421A4B0FC0052BF02 /* tileset.h */, 3186A3CA21A4B0FE0052BF02 /* timeout.h */, 3186A3C721A4B0FE0052BF02 /* tradstdc.h */, - 3186A38C21A4B0FC0052BF02 /* trampoli.h */, 3186A3CD21A4B0FE0052BF02 /* trap.h */, 3186A3AD21A4B0FD0052BF02 /* unixconf.h */, 3186A38D21A4B0FC0052BF02 /* vis_tab.h */, @@ -944,7 +918,7 @@ 3189576921A1FCC100FB2ABE /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1130; + LastUpgradeCheck = 1220; ORGANIZATIONNAME = "Bart House"; TargetAttributes = { 3189577021A1FCC100FB2ABE = { @@ -1381,7 +1355,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "# Type a script or drag a script file from your workspace to insert its path.\ncd ${NH_INC_DIR}\necho '/* nhlua.h - generated by Xcode script */' > nhlua.h\necho '#include \"../lib/lua-5.4.0/src/lua.h\"' >> nhlua.h\nsed -e '/(lua_error)/!d' -e '/(lua_error)/s/;/ NORETURN;/1' < ${NH_LIB_DIR}/lua-5.4.0/src/lua.h >> nhlua.h\necho '#include \"../lib/lua-5.4.0/src/lualib.h\"' >> nhlua.h\necho '#include \"../lib/lua-5.4.0/src/lauxlib.h\"' >> nhlua.h\necho '/*nhlua.h*/' >> nhlua.h\n"; + shellScript = "# Type a script or drag a script file from your workspace to insert its path.\ncd ${NH_INC_DIR}\necho '/* nhlua.h - generated by Xcode script */' > nhlua.h\necho '#include \"../lib/lua-5.4.2/src/lua.h\"' >> nhlua.h\nsed -e '/(lua_error)/!d' -e '/(lua_error)/s/;/ NORETURN;/1' < ${NH_LIB_DIR}/lua-5.4.2/src/lua.h >> nhlua.h\necho '#include \"../lib/lua-5.4.2/src/lualib.h\"' >> nhlua.h\necho '#include \"../lib/lua-5.4.2/src/lauxlib.h\"' >> nhlua.h\necho '/*nhlua.h*/' >> nhlua.h\n"; }; 544768B8239954B9004B9739 /* Build Lua library */ = { isa = PBXShellScriptBuildPhase; @@ -1400,7 +1374,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "# Type a script or drag a script file from your workspace to insert its path.\ncd ${NH_LIB_DIR}\nmkdir -p lua\ncd ${NH_LIB_DIR}/lua-5.4.0/src\nmake a\ncp liblua.a ../../lua\ncd ../../..\n\n"; + shellScript = "# Type a script or drag a script file from your workspace to insert its path.\ncd ${NH_LIB_DIR}\nmkdir -p lua\ncd ${NH_LIB_DIR}/lua-5.4.2/src\nmake a\ncp liblua.a ../../lua\ncd ../../..\n\n"; }; /* End PBXShellScriptBuildPhase section */ @@ -1633,6 +1607,7 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = NO; CLANG_WARN_SUSPICIOUS_MOVE = YES; @@ -1716,6 +1691,7 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = NO; CLANG_WARN_SUSPICIOUS_MOVE = YES; diff --git a/sys/unix/NetHack.xcodeproj/xcshareddata/xcschemes/NetHack.xcscheme b/sys/unix/NetHack.xcodeproj/xcshareddata/xcschemes/NetHack.xcscheme index 7abc16af5..f8a152db6 100644 --- a/sys/unix/NetHack.xcodeproj/xcshareddata/xcschemes/NetHack.xcscheme +++ b/sys/unix/NetHack.xcodeproj/xcshareddata/xcschemes/NetHack.xcscheme @@ -1,6 +1,6 @@ Preferences). +Launch XCode and open the preferences dialog (XCode Menu->Preferences). Select the "Accounts" tab. Add an account (usually this should just be -your apple ID accoung you used to setup the Mac). After adding the account, +your apple ID account you used to setup the Mac). After adding the account, select the account and then add a team (usually this will be just a personal team for Mac Development). diff --git a/sys/unix/depend.awk b/sys/unix/depend.awk index ac4416230..a488c5457 100644 --- a/sys/unix/depend.awk +++ b/sys/unix/depend.awk @@ -113,8 +113,13 @@ function output_specials( i, sp, alt_sp) # function format_dep(target, source, col, n, i, list) { + if (substr(target,1,1) == "$") { + prefix = "" + } else { + prefix = "$(TARGETPFX)" + } split("", done) #``for (x in done) delete done[x]'' - printf("%s:", target); col = length(target) + 1 + printf("%s%s:", prefix, target); col = length(target) + 1 + length(prefix) #- printf("\t"); col += 8 - (col % 8); #- if (col == 8) { printf("\t"); col += 8 } source = depend("", source, 0) @@ -132,13 +137,13 @@ function format_dep(target, source, col, n, i, list) source = list[2] if (source ~ /\// && substr(source, 1, 11) != "../include/") { if (source ~ /\.cpp$/ ) - print "\t$(CXX) $(CXXFLAGS) -c -o $@ " source + print "\t$(TARGET_CXX) $(TARGET_CXXFLAGS) -c -o $@ " source else if (source ~ /\/X11\//) # "../win/X11/foo.c" - print "\t$(CC) $(CFLAGS) $(X11CFLAGS) -c -o $@ " source + print "\t$(TARGET_CC) $(TARGET_CFLAGS) $(X11CFLAGS) -c -o $@ " source else if (source ~ /\/gnome\//) # "../win/gnome/foo.c" - print "\t$(CC) $(CFLAGS) $(GNOMEINC) -c -o $@ " source + print "\t$(TARGET_CC) $(TARGET_CFLAGS) $(GNOMEINC) -c -o $@ " source else - print "\t$(CC) $(CFLAGS) -c -o $@ " source + print "\t$(TARGET_CC) $(TARGET_CFLAGS) -c -o $@ " source } } diff --git a/sys/unix/gitinfo.sh b/sys/unix/gitinfo.sh index 9ab309f84..d087272a2 100755 --- a/sys/unix/gitinfo.sh +++ b/sys/unix/gitinfo.sh @@ -1,5 +1,5 @@ #!/bin/sh -# NetHack 3.6 gitinfo.sh $NHDT-Date: 1524689450 2018/04/25 20:50:50 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.2 $ +# NetHack 3.7 gitinfo.sh $NHDT-Date: 1596498289 2020/08/03 23:44:49 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.3 $ # Copyright (c) 2018 by Robert Patrick Rankin # NetHack may be freely redistributed. See license for details. diff --git a/sys/unix/hints/include/cross-post.2020 b/sys/unix/hints/include/cross-post.2020 new file mode 100644 index 000000000..b87824a54 --- /dev/null +++ b/sys/unix/hints/include/cross-post.2020 @@ -0,0 +1,269 @@ +#===============-================================================= +# NetHack 3.7 include/cross-post $NHDT-Date: 1597332785 2020/08/13 15:33:05 $ $NHDT-Branch: NetHack-3.7 $ +# +# Cross-compiling -POST section + +ifdef CROSS_TO_MSDOS +# +$(TARGETPFX)msdos.o : ../sys/msdos/msdos.c $(HACK_H) +$(TARGETPFX)pckeys.o : ../sys/msdos/pckeys.c $(HACK_H) +$(TARGETPFX)pctiles.o : ../sys/msdos/pctiles.c ../sys/msdos/portio.h $(HACK_H) +$(TARGETPFX)video.o : ../sys/msdos/video.c ../sys/msdos/portio.h $(HACK_H) +$(TARGETPFX)vidtxt.o : ../sys/msdos/vidtxt.c ../sys/msdos/portio.h \ + ../win/share/tile.h ../include/tileset.h $(HACK_H) +$(TARGETPFX)vidvga.o : ../sys/msdos/vidvga.c ../sys/msdos/portio.h \ + ../win/share/tile.h ../include/tileset.h $(HACK_H) +$(TARGETPFX)vidvesa.o : ../sys/msdos/vidvesa.c ../sys/msdos/portio.h \ + ../win/share/tile.h ../include/tileset.h $(HACK_H) +$(TARGETPFX)vidstub.o : ../sys/msdos/vidvesa.c ../sys/msdos/portio.h \ + $(HACK_H) +$(TARGETPFX)tile.o : tile.c +$(GAMEBIN) : $(HOBJ) $(LUACROSSLIB) + $(TARGET_LINK) $(TARGET_LFLAGS) -o $(GAMEBIN) \ + $(HOBJ) $(WINLIB) $(TARGET_LIBS) +# +.PHONY: dospkg +dospkg: $(GAMEBIN) $(TARGETPFX)recover.exe ../dat/nhtiles.bmp + $(TARGET_STUBEDIT) $(GAMEBIN) minstack=2048K + mkdir -p $(TARGETPFX)pkg + cp $(GAMEBIN) $(TARGETPFX)pkg/NETHACK.EXE + cp $(TARGETPFX)recover.exe $(TARGETPFX)pkg/RECOVER.EXE + cp ../dat/nhdat $(TARGETPFX)pkg/NHDAT + cp ../dat/license $(TARGETPFX)pkg/LICENSE + cp ../dat/nhtiles.bmp $(TARGETPFX)pkg/NHTILES.BMP + cp ../dat/symbols $(TARGETPFX)pkg/SYMBOLS + cp ../sys/share/NetHack.cnf $(TARGETPFX)pkg/NETHACK.CNF + cp ../sys/msdos/sysconf $(TARGETPFX)pkg/SYSCONF + cp ../doc/nethack.txt $(TARGETPFX)pkg/NETHACK.TXT + cp ../lib/djgpp/cwsdpmi/bin/CWSDPMI.EXE $(TARGETPFX)pkg/CWSDPMI.EXE + -touch $(TARGETPFX)pkg/RECORD + zip -9 $(TARGETPFX)NH370DOS.ZIP $(TARGETPFX)pkg/* + @echo msdos package zip file $(TARGETPFX)NH370DOS.ZIP +endif # CROSS_TO_MSDOS + +ifdef CROSS_TO_AMIGA +$(TARGETPFX)amidos.o : ../outdated/sys/amiga/amidos.c $(HACK_H) +$(TARGETPFX)amigst.o : ../outdated/sys/amiga/amigst.c $(HACK_H) +$(TARGETPFX)amirip.o : ../outdated/sys/amiga/amirip.c $(HACK_H) +$(TARGETPFX)amistack.o : ../outdated/sys/amiga/amistack.c $(HACK_H) +$(TARGETPFX)amitty.o : ../outdated/sys/amiga/amitty.c $(HACK_H) +$(TARGETPFX)amiwind.o : ../outdated/sys/amiga/amiwind.c \ + ../outdated/sys/amiga/amimenu.c $(HACK_H) +$(TARGETPFX)winami.o : ../outdated/sys/amiga/winami.c $(HACK_H) +$(TARGETPFX)winchar.o : ../outdated/sys/amiga/winchar.c tile.c $(HACK_H) +$(TARGETPFX)winfuncs.o : ../outdated/sys/amiga/winfuncs.c $(HACK_H) +$(TARGETPFX)winkey.o : ../outdated/sys/amiga/winkey.c $(HACK_H) +$(TARGETPFX)winamenu.o : ../outdated/sys/amiga/winamenu.c $(HACK_H) +$(TARGETPFX)winreq.o : ../outdated/sys/amiga/winreq.c \ + ../outdated/sys/amiga/colorwin.c \ + ../outdated/sys/amiga/clipwin.c $(HACK_H) +$(TARGETPFX)winstr.o : ../outdated/sys/amiga/winstr.c $(HACK_H) +$(TARGETPFX)tomb.iff : ../util/xpm2iff ../outdated/sys/amiga/gave16.xpm +../util/tiletext.o : ../win/share/tiletext.c + $(CC) $(CFLAGS) -c \ + -o $@ ../win/share/tiletext.c +../util/txt2iff : ../util/txt2iff.o ../util/tiletext.o \ + ../util/tiletxt.o + $(LINK) $(LFLAGS) -L../lib -o $@ ../util/txt2iff.o ../util/tiletext.o \ + ../util/tiletxt.o -lriffl +../util/txt2iff.o : ../outdated/sys/amiga/txt2iff.c $(HACK_H) + $(CC) $(CFLAGS) -c \ + -I../lib/riffl-0.2/include \ + -I/opt/amiga/m68k-amigaos/ndk13-include \ + -o $@ ../outdated/sys/amiga/txt2iff.c +../util/xpm2iff : ../util/xpm2iff.o + $(LINK) $(LFLAGS) -L../lib -o $@ ../util/txt2iff.o -lriffl +../util/xpm2iff.o : ../outdated/sys/amiga/xpm2iff.c $(HACK_H) + $(CC) $(CFLAGS) -o $@ ../outdated/sys/amiga/xpm2iff.c +$(TARGETPFX)objects.iff: ../win/share/objects.txt ../util/txt2iff + ../util/txt2iff ../win/share/objects.txt $@ +$(TARGETPFX)monsters.iff: ../win/share/monsters.txt ../util/txt2iff + ../util/txt2iff ../win/share/monsters.txt $@ +$(TARGETPFX)other.iff: ../win/share/other.txt ../util/txt2iff + ../util/txt2iff ../win/share/other.txt $@ +$(GAMEBIN) : $(HOBJ) $(LUACROSSLIB) + $(TARGET_LINK) $(TARGET_LFLAGS) -o $(GAMEBIN) \ + $(HOBJ) $(WINLIB) $(TARGET_LIBS) +# +.PHONY: amigapkg +amigapkg: $(GAMEBIN) $(TARGETPFX)recover.exe ../dat/nhtiles.bmp + mkdir -p $(TARGETPFX)pkg + cp $(GAMEBIN) $(TARGETPFX)pkg/nethack + cp ../dat/nhdat $(TARGETPFX)pkg/nhdat + cp ../dat/license $(TARGETPFX)pkg/license + cp ../dat/nhtiles.bmp $(TARGETPFX)pkg/nhtiles.bmp + cp $(TARGETPFX)tomb.iff $(TARGETPFX)pkg/tomb.iff + cp $(TARGETPFX)monsters.iff $(TARGETPFX)pkg/monsters.iff + cp $(TARGETPFX)objects.iff $(TARGETPFX)pkg/objects.iff + cp $(TARGETPFX)other.iff $(TARGETPFX)pkg/other.iff + cp ../dat/symbols $(TARGETPFX)pkg/symbols + cp ../sys/share/NetHack.cnf $(TARGETPFX)pkg/nethack.cnf + cp ../sys/msdos/sysconf $(TARGETPFX)pkg/sysconf + cp ../outdated/sys/amiga/amii.hlp $(TARGETPFX)pkg/amii.hlp + cp ../sys/msdos/sysconf $(TARGETPFX)pkg/sysconf + cp ../doc/nethack.txt $(TARGETPFX)pkg/nethack.txt + ../util/uudecode ../outdated/sys/amiga/amifont8.uu + cp 8 $(TARGETPFX)pkg/8 + ../util/uudecode ../outdated/sys/amiga/amifont.uu + cp hack.font $(TARGETPFX)pkg/hack.font + ../util/uudecode ../outdated/sys/amiga/dflticon.uu + cp default.icon $(TARGETPFX)pkg/default.icon + ../util/uudecode ../outdated/sys/amiga/NHinfo.uu + cp NetHack.info $(TARGETPFX)pkg/NetHack.info + ../util/uudecode ../outdated/sys/amiga/NewGame.uu + cp NewGame.info $(TARGETPFX)pkg/NewGame.info + ../util/uudecode ../outdated/sys/amiga/HackWB.uu + cp HackWB.info $(TARGETPFX)pkg/HackWB.info + -touch $(TARGETPFX)pkg/record + zip -9 $(TARGETPFX)NH370AMI.ZIP $(TARGETPFX)pkg/* + @echo amiga package zip file $(TARGETPFX)NH370AMI.ZIP +endif # CROSS_TO_AMIGA + +ifdef CROSS_TO_WASM +$(WASM_TARGET): pregame $(HOSTOBJ) $(HOBJ) $(LUACROSSLIB) $(WASM_DATA_DIR) + -rm $@ + $(TARGET_CC) $(TARGET_LFLAGS) $(TARGET_CFLAGS) -o $@ \ + $(HOBJ) $(TARGET_LIBS) + +$(WASM_DATA_DIR): $(WASM_DATA_DIR)/nhdat + touch $(WASM_DATA_DIR)/perm + touch $(WASM_DATA_DIR)/record + touch $(WASM_DATA_DIR)/logfile + touch $(WASM_DATA_DIR)/xlogfile + cp ../sys/libnh/sysconf $(WASM_DATA_DIR)/sysconf + +$(WASM_DATA_DIR)/nhdat: + ( cd ..; $(MAKE) INSTDIR='$(WASM_DATA_DIR)' $(WASMDEP) dofiles-dlb ) + +# +$(TARGETPFX)unixmain.o : ../sys/unix/unixmain.c $(HACK_H) +$(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) +$(TARGETPFX)winshim.o : ../win/shim/winshim.c $(HACK_H) +$(TARGETPFX)libnhmain.o : ../sys/libnh/libnhmain.c $(HACK_H) +endif # CROSS_TO_WASM +# + +ifdef CROSS_SHARED +# shared file dependencies +$(TARGETPFX)pcmain.o : ../sys/share/pcmain.c $(HACK_H) +$(TARGETPFX)pcsys.o : ../sys/share/pcsys.c $(HACK_H) +$(TARGETPFX)pctty.o : ../sys/share/pctty.c $(HACK_H) +$(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 +$(TARGETPFX)recover.exe : $(TARGETPFX)recover.o + $(TARGET_LINK) $(TARGET_LFLAGS) $(TARGETPFX)recover.o -o $@ +endif # CROSS_SHARED +# +ifdef BUILD_TARGET_LUA +# Lua lib +$(LUACROSSLIB): $(LUALIBOBJS) + if [ -f $@ ]; then rm $@; fi; + $(TARGET_AR) rcS $@ $(LUAOBJFILES1) + $(TARGET_AR) rcS $@ $(LUAOBJFILES2) + $(TARGET_AR) rcS $@ $(LUAOBJFILES3) + $(TARGET_AR) rcs $@ $(LUAOBJFILES4) + +# $(TARGET_AR) rcs $@ $(LUALIBOBJS) + +# Lua src +$(TARGETPFX)lapi.o : $(LUATOP)/src/lapi.c +$(TARGETPFX)lauxlib.o : $(LUATOP)/src/lauxlib.c +$(TARGETPFX)lbaselib.o : $(LUATOP)/src/lbaselib.c +$(TARGETPFX)lbitlib.o : $(LUATOP)/src/lbitlib.c +$(TARGETPFX)lcode.o : $(LUATOP)/src/lcode.c +$(TARGETPFX)lcorolib.o : $(LUATOP)/src/lcorolib.c +$(TARGETPFX)lctype.o : $(LUATOP)/src/lctype.c +$(TARGETPFX)ldblib.o : $(LUATOP)/src/ldblib.c +$(TARGETPFX)ldebug.o : $(LUATOP)/src/ldebug.c +$(TARGETPFX)ldo.o : $(LUATOP)/src/ldo.c +$(TARGETPFX)ldump.o : $(LUATOP)/src/ldump.c +$(TARGETPFX)lfunc.o : $(LUATOP)/src/lfunc.c +$(TARGETPFX)lgc.o : $(LUATOP)/src/lgc.c +$(TARGETPFX)linit.o : $(LUATOP)/src/linit.c +$(TARGETPFX)liolib.o : $(LUATOP)/src/liolib.c +$(TARGETPFX)llex.o : $(LUATOP)/src/llex.c +$(TARGETPFX)lmathlib.o : $(LUATOP)/src/lmathlib.c +$(TARGETPFX)lmem.o : $(LUATOP)/src/lmem.c +$(TARGETPFX)loadlib.o : $(LUATOP)/src/loadlib.c +$(TARGETPFX)lobject.o : $(LUATOP)/src/lobject.c +$(TARGETPFX)lopcodes.o : $(LUATOP)/src/lopcodes.c +$(TARGETPFX)loslib.o : $(LUATOP)/src/loslib.c +$(TARGETPFX)lparser.o : $(LUATOP)/src/lparser.c +$(TARGETPFX)lstate.o : $(LUATOP)/src/lstate.c +$(TARGETPFX)lstring.o : $(LUATOP)/src/lstring.c +$(TARGETPFX)lstrlib.o : $(LUATOP)/src/lstrlib.c +$(TARGETPFX)ltable.o : $(LUATOP)/src/ltable.c +$(TARGETPFX)ltablib.o : $(LUATOP)/src/ltablib.c +$(TARGETPFX)ltm.o : $(LUATOP)/src/ltm.c +$(TARGETPFX)lundump.o : $(LUATOP)/src/lundump.c +$(TARGETPFX)lutf8lib.o : $(LUATOP)/src/lutf8lib.c +$(TARGETPFX)lvm.o : $(LUATOP)/src/lvm.c +$(TARGETPFX)lzio.o : $(LUATOP)/src/lzio.c +endif # BUILD_TARGET_LUA + +ifdef BUILD_PDCURSES +ifdef WANT_WIN_CURSES +$(TARGETPFX)pdclib.a : $(PDCLIBOBJS) $(PDCOBJS) + if [ -f $@ ]; then rm $@; fi; + $(TARGET_AR) rcs $@ $(PDCLIBOBJS) $(PDCOBJS) +endif +# PDCurses src +$(TARGETPFX)addch.o : $(PDCTOP)/pdcurses/addch.c +$(TARGETPFX)addchstr.o : $(PDCTOP)/pdcurses/addchstr.c +$(TARGETPFX)addstr.o : $(PDCTOP)/pdcurses/addstr.c +$(TARGETPFX)attr.o : $(PDCTOP)/pdcurses/attr.c +$(TARGETPFX)beep.o : $(PDCTOP)/pdcurses/beep.c +$(TARGETPFX)bkgd.o : $(PDCTOP)/pdcurses/bkgd.c +$(TARGETPFX)border.o : $(PDCTOP)/pdcurses/border.c +$(TARGETPFX)clear.o : $(PDCTOP)/pdcurses/clear.c +$(TARGETPFX)color.o : $(PDCTOP)/pdcurses/color.c +$(TARGETPFX)delch.o : $(PDCTOP)/pdcurses/delch.c +$(TARGETPFX)deleteln.o : $(PDCTOP)/pdcurses/deleteln.c +$(TARGETPFX)getch.o : $(PDCTOP)/pdcurses/getch.c +$(TARGETPFX)getstr.o : $(PDCTOP)/pdcurses/getstr.c +$(TARGETPFX)getyx.o : $(PDCTOP)/pdcurses/getyx.c +$(TARGETPFX)inch.o : $(PDCTOP)/pdcurses/inch.c +$(TARGETPFX)inchstr.o : $(PDCTOP)/pdcurses/inchstr.c +$(TARGETPFX)initscr.o : $(PDCTOP)/pdcurses/initscr.c +$(TARGETPFX)inopts.o : $(PDCTOP)/pdcurses/inopts.c +$(TARGETPFX)insch.o : $(PDCTOP)/pdcurses/insch.c +$(TARGETPFX)insstr.o : $(PDCTOP)/pdcurses/insstr.c +$(TARGETPFX)instr.o : $(PDCTOP)/pdcurses/instr.c +$(TARGETPFX)kernel.o : $(PDCTOP)/pdcurses/kernel.c +$(TARGETPFX)keyname.o : $(PDCTOP)/pdcurses/keyname.c +$(TARGETPFX)mouse.o : $(PDCTOP)/pdcurses/mouse.c +$(TARGETPFX)move.o : $(PDCTOP)/pdcurses/move.c +$(TARGETPFX)outopts.o : $(PDCTOP)/pdcurses/outopts.c +$(TARGETPFX)overlay.o : $(PDCTOP)/pdcurses/overlay.c +$(TARGETPFX)pad.o : $(PDCTOP)/pdcurses/pad.c +$(TARGETPFX)panel.o : $(PDCTOP)/pdcurses/panel.c +$(TARGETPFX)printw.o : $(PDCTOP)/pdcurses/printw.c +$(TARGETPFX)refresh.o : $(PDCTOP)/pdcurses/refresh.c +$(TARGETPFX)scanw.o : $(PDCTOP)/pdcurses/scanw.c +$(TARGETPFX)scr_dump.o : $(PDCTOP)/pdcurses/scr_dump.c +$(TARGETPFX)scroll.o : $(PDCTOP)/pdcurses/scroll.c +$(TARGETPFX)slk.o : $(PDCTOP)/pdcurses/slk.c +$(TARGETPFX)termattr.o : $(PDCTOP)/pdcurses/termattr.c +$(TARGETPFX)touch.o : $(PDCTOP)/pdcurses/touch.c +$(TARGETPFX)util.o : $(PDCTOP)/pdcurses/util.c +$(TARGETPFX)window.o : $(PDCTOP)/pdcurses/window.c +$(TARGETPFX)debug.o : $(PDCTOP)/pdcurses/debug.c +$(TARGETPFX)pdcclip.o : $(PDCTOP)/dos/pdcclip.c +$(TARGETPFX)pdcdisp.o : $(PDCTOP)/dos/pdcdisp.c +$(TARGETPFX)pdcgetsc.o : $(PDCTOP)/dos/pdcgetsc.c +$(TARGETPFX)pdckbd.o : $(PDCTOP)/dos/pdckbd.c +$(TARGETPFX)pdcscrn.o : $(PDCTOP)/dos/pdcscrn.c +$(TARGETPFX)pdcsetsc.o : $(PDCTOP)/dos/pdcsetsc.c +$(TARGETPFX)pdcutil.o : $(PDCTOP)/dos/pdcutil.c +endif # BUILD_PDCURSES +# +# End of cross-compiling -POST section +#===============-================================================= + + diff --git a/sys/unix/hints/include/cross-pre.2020 b/sys/unix/hints/include/cross-pre.2020 new file mode 100644 index 000000000..99de7f559 --- /dev/null +++ b/sys/unix/hints/include/cross-pre.2020 @@ -0,0 +1,439 @@ +#===============-================================================= +# NetHack 3.7 include/cross-pre $NHDT-Date: 1597332785 2020/08/13 15:33:05 $ $NHDT-Branch: NetHack-3.7 $ +# +# Cross-compiling -PRE section +# + +ifdef CROSS_TO_MSDOS +CROSS=1 +BUILD_TARGET_LUA=1 +BUILD_PDCURSES=1 +CROSS_SHARED=1 +override TARGET = msdos +override TARGETDIR=../targets/$(TARGET) +override TARGETPFX = $(TARGETDIR)/ +override TARGET_LIBS= +endif + +ifdef CROSS_TO_AMIGA +CROSS=1 +BUILD_TARGET_LUA=1 +BUILD_PDCURSES=1 +CROSS_SHARED=1 +override TARGET = amiga +override TARGETDIR=../targets/$(TARGET) +override TARGETPFX = $(TARGETDIR)/ +override TARGET_LIBS= +endif + +ifdef CROSS_TO_WASM +CROSS=1 +BUILD_TARGET_LUA=1 +HACKDIR=/ +PREFIX= +override TARGET = wasm +override TARGETDIR=../targets/$(TARGET) +override TARGETPFX = $(TARGETDIR)/ +override TARGET_LIBS= +endif + +ifdef CROSS +override PREGAME= +override BUILDMORE= +override CLEANMORE= +override PACKAGE= +endif + +ifdef BUILD_TARGET_LUA +#===============-================================================= +# LUA library +# Source from http://www.lua.org/ftp/lua-5.4.2.tar.gz +#================================================================= +LUA_VERSION ?=5.4.2 +LUATOP ?= ../lib/lua-$(LUA_VERSION) +LUASRCDIR ?= $(LUATOP)/src +LUAOBJFILES1 = $(TARGETPFX)lapi.o $(TARGETPFX)lauxlib.o \ + $(TARGETPFX)lbaselib.o $(TARGETPFX)lcode.o \ + $(TARGETPFX)lcorolib.o $(TARGETPFX)lctype.o \ + $(TARGETPFX)ldblib.o +ifeq "$(LUA_VERSION)" "5.3.5" +LUAOBJFILES1 += $(TARGETPFX)lbitlib.o +endif +LUAOBJFILES2 = $(TARGETPFX)ldebug.o $(TARGETPFX)ldo.o $(TARGETPFX)ldump.o \ + $(TARGETPFX)lfunc.o $(TARGETPFX)lgc.o $(TARGETPFX)linit.o \ + $(TARGETPFX)liolib.o $(TARGETPFX)llex.o +LUAOBJFILES3 = $(TARGETPFX)lmathlib.o $(TARGETPFX)lmem.o \ + $(TARGETPFX)loadlib.o $(TARGETPFX)lobject.o \ + $(TARGETPFX)lopcodes.o $(TARGETPFX)loslib.o \ + $(TARGETPFX)lparser.o $(TARGETPFX)lstate.o +LUAOBJFILES4 = $(TARGETPFX)lstring.o $(TARGETPFX)lstrlib.o \ + $(TARGETPFX)ltable.o $(TARGETPFX)ltablib.o \ + $(TARGETPFX)ltm.o $(TARGETPFX)lundump.o \ + $(TARGETPFX)lutf8lib.o $(TARGETPFX)lvm.o $(TARGETPFX)lzio.o +LUALIBOBJS = $(LUAOBJFILES1) $(LUAOBJFILES2) $(LUAOBJFILES3) $(LUAOBJFILES4) +LUACROSSLIB = $(TARGETPFX)lua$(subst .,,$(LUA_VERSION)).a +LUAINCL = -I$(LUASRCDIR) +override BUILDMORE += $(LUACROSSLIB) +override CLEANMORE += rm -f $(LUACROSSLIB) ; +override TARGET_LIBS += $(LUACROSSLIB) -lm +else +LUAINCL= +endif # BUILD_TARGET_LUA + +ifdef BUILD_PDCURSES +#===============-================================================= +# PD Curses library +#===============-================================================= +ifdef WANT_WIN_CURSES +PDCTOP = ../lib/pdcurses +PDCURSESDEF= -I../lib/pdcurses -I../lib/pdcurses/dos \ + -D"CURSES_GRAPHICS" -D"CURSES_BRIEF_INCLUDE" +PDCLIBOBJ1= $(TARGETPFX)addch.o $(TARGETPFX)addchstr.o \ + $(TARGETPFX)addstr.o $(TARGETPFX)attr.o \ + $(TARGETPFX)beep.o $(TARGETPFX)bkgd.o \ + $(TARGETPFX)border.o $(TARGETPFX)clear.o \ + $(TARGETPFX)color.o $(TARGETPFX)delch.o \ + $(TARGETPFX)deleteln.o $(TARGETPFX)getch.o \ + $(TARGETPFX)getstr.o $(TARGETPFX)getyx.o \ + $(TARGETPFX)inch.o +PDCLIBOBJ2= $(TARGETPFX)inchstr.o $(TARGETPFX)initscr.o \ + $(TARGETPFX)inopts.o $(TARGETPFX)insch.o \ + $(TARGETPFX)insstr.o $(TARGETPFX)instr.o \ + $(TARGETPFX)kernel.o $(TARGETPFX)keyname.o \ + $(TARGETPFX)mouse.o $(TARGETPFX)move.o \ + $(TARGETPFX)outopts.o $(TARGETPFX)overlay.o +PDCLIBOBJ3= $(TARGETPFX)pad.o $(TARGETPFX)panel.o $(TARGETPFX)printw.o \ + $(TARGETPFX)refresh.o $(TARGETPFX)scanw.o \ + $(TARGETPFX)scr_dump.o $(TARGETPFX)scroll.o \ + $(TARGETPFX)slk.o $(TARGETPFX)termattr.o +PDCLIBOBJ4= $(TARGETPFX)touch.o $(TARGETPFX)util.o $(TARGETPFX)window.o \ + $(TARGETPFX)debug.o +PDCLIBOBJS = $(PDCLIBOBJ1) $(PDCLIBOBJ2) $(PDCLIBOBJ3) $(PDCLIBOBJ4) +PDCLIB = $(TARGETPFX)pdclib.a +PDCINCL = -I$(PDCTOP) -I$(PDCTOP)/pdcurses +PDCOBJS = $(TARGETPFX)pdcclip.o $(TARGETPFX)pdcdisp.o \ + $(TARGETPFX)pdcgetsc.o $(TARGETPFX)pdckbd.o \ + $(TARGETPFX)pdcscrn.o $(TARGETPFX)pdcsetsc.o \ + $(TARGETPFX)pdcutil.o +override TARGET_LIBS += $(PDCLIB) +ifdef CROSS_TO_MSDOS +PDCINCL += -I$(PDCTOP)/dos +endif +ifdef CROSS_TO_AMIGA +PDCINCL += -I$(PDCTOP)/sdl1 -I/opt/amiga/m68k-amigaos/include/SDL +override TARGET_LIBS += -lSDL +endif +override BUILDMORE += $(PDCLIB) +override CLEANMORE += rm -f $(PDCLIB) ; +# Rules for PDCurses files +$(TARGETPFX)%.o : $(PDCTOP)/pdcurses/%.c + $(TARGET_CC) $(PDCINCL) $(TARGET_CFLAGS) -o$@ $< +else #WANT_WIN_CURSES +PDCURSESDEF= +PDCLIBOBJS= +PDCOBJS= +PDCLIB= +PDCINCL= +endif # WANT_WIN_CURSES +endif # BUILD_PDCURSES + +ifdef CROSS_TO_MSDOS +#===============-================================================= +# MSDOS cross-compile recipe +#===============-================================================= +# Uses an MSDOS djgpp cross-compiler on linux or macos. +# +# 1. You can obtain the cross-compiler for your system via: +# sys/msdos/fetch-cross.sh +# 2. Then +# make CROSS_TO_MSDOS=1 WANT_WIN_TTY=1 WANT_WIN_CURSES=1 all +# +# Source from http://www.lua.org/ftp/lua-5.4.2.tar.gz +#================================================================= + +CFLAGS += -DCROSSCOMPILE + +# +# Override the build tools and some obj files to +# reflect the msdos djgpp cross-compiler. +# +TOOLTOP1 = ../lib/djgpp/bin +TOOLTOP2 = ../lib/djgpp/i586-pc-msdosdjgpp/bin +override TARGET_CC = $(TOOLTOP1)/i586-pc-msdosdjgpp-gcc +override TARGET_CXX = $(TOOLTOP2)/g++ +override TARGET_AR = $(TOOLTOP1)/i586-pc-msdosdjgpp-gcc-ar +override TARGET_STUBEDIT = ../lib/djgpp/i586-pc-msdosdjgpp/bin/stubedit +override TARGET_CFLAGS = -c -O -I../include -I../sys/msdos -I../win/share \ + $(LUAINCL) -DDLB $(PDCURSESDEF) \ + -DUSE_TILES -DCROSSCOMPILE -DCROSSCOMPILE_TARGET -DCROSS_TO_MSDOS +override TARGET_CXXFLAGS = $(TARGET_CFLAGS) +override TARGET_LINK = $(TOOLTOP1)/i586-pc-msdosdjgpp-gcc +override TARGET_LFLAGS= +override TARGET_LIBS += -lpc +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 \ + ../sys/msdos/vidtxt.c ../sys/msdos/pckeys.c \ + ../sys/msdos/vidvga.c ../sys/msdos/vidvesa.c \ + ../win/share/bmptiles.c ../win/share/giftiles.c \ + ../win/share/tileset.c +override SYSOBJ= $(TARGETPFX)pcmain.o $(TARGETPFX)msdos.o \ + $(TARGETPFX)pcsys.o $(TARGETPFX)pctty.o \ + $(TARGETPFX)pcunix.o $(TARGETPFX)video.o \ + $(TARGETPFX)vidtxt.o $(TARGETPFX)pckeys.o \ + $(TARGETPFX)vidvga.o $(TARGETPFX)vidvesa.o \ + $(TARGETPFX)bmptiles.o $(TARGETPFX)giftiles.o \ + $(TARGETPFX)tileset.o $(TARGETPFX)tile.o +override WINLIB= +override LUALIB= +override TOPLUALIB= +override GAMEBIN = $(TARGETPFX)nethack.exe +override PACKAGE = dospkg +override PREGAME += mkdir -p $(TARGETDIR) ; +override CLEANMORE += rm -f -r $(TARGETDIR) ; +VARDATND += nhtiles.bmp +# +ifdef WANT_WIN_CURSES +# rules for pdcurses dos-specific files +$(TARGETPFX)%.o : $(PDCTOP)/dos/%.c + $(TARGET_CC) $(PDCINCL) $(TARGET_CFLAGS) -o$@ $< +endif # WANT_WIN_CURSES +# +# Rule for files in sys/msdos +$(TARGETPFX)%.o : ../sys/msdos/%.c + $(TARGET_CC) $(TARGET_CFLAGS) -o$@ $< +endif # CROSS_TO_MSDOS +#================================================================= + +ifdef CROSS_TO_AMIGA +#===============-================================================= +# AmigaOS m68k cross-compile recipe +#===============-================================================= +# Uses an Amiga M68K cross-compiler on linux or macOS. +# +# 1. You can obtain the cross-compiler for your system via: +# sys/amiga/fetch-cross.sh +# 2. Then +# make CROSS_TO_AMIGAOS=1 WANT_WIN_TTY=1 WANT_WIN_CURSES=1 all +# +# Amiga m68k from https://github.com/bebbo/amiga-gcc +#================================================================= + +CFLAGS += -DCROSSCOMPILE + +# +# Override the build tools and some obj files to +# reflect the amiga-gccs cross-compiler. +# +TOOLTOP = /opt/amiga/bin +#TOOLARCH = -m68020 -mcrt=clib2 +#TOOLARCH = -m68020 #newlib +TOOLARCH = -m68020 -noixemul +override REGEXOBJ = $(TARGETPFX)cppregex.o +override TARGET_CC = $(TOOLTOP)/m68k-amigaos-gcc +override TARGET_CXX = $(TOOLTOP)/m68k-amigaos-c++ +override TARGET_AR = $(TOOLTOP)/m68k-amigaos-ar +override TARGET_STUBEDIT= +#override TARGET_CFLAGS = -c -O $(TOOLARCH) -I../include -I../outdated/include +override TARGET_CFLAGS = -c -O $(TOOLARCH) \ + -I../include -I../outdated/include \ + -I../outdated/sys/amiga -I../win/share \ + $(LUAINCL) -DAMIGA -DUSE_TILES $(PDCURSESDEF) \ + -DCROSSCOMPILE -DCROSSCOMPILE_TARGET -DCROSS_TO_AMIGA \ + -DAMIGA_VERSION_STRING=\""VER: NetHack 3.7.0\"" +override TARGET_CXXFLAGS = $(TARGET_CFLAGS) +ifeq "$(REGEXOBJ)" "$(TARGETPFX)cppregex.o" +override TARGET_LINK = $(TARGET_CXX) +else +override TARGET_LINK = $(TARGET_CC) +endif +override TARGET_LFLAGS= $(TOOLARCH) +#override TARGET_LIBS += +VARDATND += nhtiles.bmp +override SYSSRC = ../outdated/sys/amiga/amidos.c ../outdated/sys/amiga/amigst.c \ + ../outdated/sys/amiga/amimenu.c ../outdated/sys/amiga/amirip.c \ + ../outdated/sys/amiga/amistack.c ../outdated/sys/amiga/amitty.c \ + ../outdated/sys/amiga/amiwind.c ../outdated/sys/amiga/clipwin.c \ + ../outdated/sys/amiga/colorwin.c \ + ../outdated/sys/amiga/winami.c ../outdated/sys/amiga/winchar.c \ + ../outdated/sys/amiga/winfuncs.c ../outdated/sys/amiga/winkey.c \ + ../outdated/sys/amiga/winamenu.c ../outdated/sys/amiga/winreq.c \ + ../outdated/sys/amiga/winstr.c ../sys/share/pcmain.c \ + ../win/share/bmptiles.c ../win/share/giftiles.c \ + ../win/share/tileset.c +# ../outdated/sys/amiga/xpm2iff.c +# ../outdated/sys/amiga/txt2iff.c +override SYSOBJ = $(TARGETPFX)amidos.o $(TARGETPFX)amigst.o \ + $(TARGETPFX)amirip.o $(TARGETPFX)amistack.o \ + $(TARGETPFX)amitty.o $(TARGETPFX)amiwind.o \ + $(TARGETPFX)winami.o $(TARGETPFX)winchar.o \ + $(TARGETPFX)winfuncs.o $(TARGETPFX)winkey.o \ + $(TARGETPFX)winamenu.o $(TARGETPFX)winreq.o \ + $(TARGETPFX)winstr.o $(TARGETPFX)pcmain.o \ + $(TARGETPFX)bmptiles.o $(TARGETPFX)giftiles.o \ + $(TARGETPFX)tileset.o +# $(TARGETPFX)xpm2iff.o +# ../util/txt2iff.o +override WINLIB= +override LUALIB= +override TOPLUALIB= +override GAMEBIN = $(TARGETPFX)nethack +override PACKAGE = amigapkg +override PREGAME += mkdir -p $(TARGETDIR) ; +override CLEANMORE += rm -r $(TARGETDIR) ; +# ../util/txt2iff +# +ifdef WANT_WIN_CURSES +# rules for pdcurses sdl1-specific files +$(TARGETPFX)%.o : $(PDCTOP)/sdl1/%.c + $(TARGET_CC) $(PDCINCL) $(TARGET_CFLAGS) -o$@ $< +endif # WANT_WIN_CURSES +# Rule for files in sys/amiga +$(TARGETPFX)%.o : ../outdated/sys/amiga/%.c + $(TARGET_CC) $(TARGET_CFLAGS) -o$@ $< +endif # CROSS_TO_AMIGA +#================================================================= + +ifdef CROSS_TO_WASM +#===============-================================================= +# WASM +# originally from https://github.com/NetHack/NetHack/pull/385 +#===============-================================================= +# +WASM_DEBUG = 1 +WASM_DATA_DIR = $(TARGETPFX)wasm-data +WASM_TARGET = $(TARGETPFX)nethack.js +EMCC_LFLAGS = +#EMCC_LFLAGS += -s SINGLE_FILE=1 +EMCC_LFLAGS += -DHACKDIR=\"$(HACKDIR)\" +EMCC_LFLAGS += -s WASM=1 +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", "_mapglyph", "_display_inventory"]' +EMCC_LFLAGS += -s EXPORTED_RUNTIME_METHODS='["cwrap", "ccall", "addFunction", \ + "removeFunction", "UTF8ToString", "getValue", "setValue"]' +EMCC_LFLAGS += -s ERROR_ON_UNDEFINED_SYMBOLS=0 +# 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)@/ +# For a list of EMCC settings: +# https://github.com/emscripten-core/emscripten/blob/master/src/settings.js +# +# WASM C flags +EMCC_CFLAGS = +EMCC_CFLAGS += -Wall +EMCC_CFLAGS += -Werror +EMCC_CFLAGS += -DNO_SIGNAL +#EMCC_CFLAGS += -s DISABLE_EXCEPTION_CATCHING=0 +#EMCC_DEBUG_CFLAGS += -s ASSERTIONS=1 +EMCC_DEBUG_CFLAGS += -s ASSERTIONS=2 +EMCC_DEBUG_CFLAGS += -s STACK_OVERFLOW_CHECK=2 +EMCC_DEBUG_CFLAGS += -s SAFE_HEAP=1 +EMCC_DEBUG_CFLAGS += -s LLD_REPORT_UNDEFINED=1 +EMCC_DEBUG_CFLAGS += -s EXCEPTION_DEBUG=1 +#EMCC_DEBUG_CFLAGS += -fsanitize=undefined -fsanitize=address -fsanitize=leak +EMCC_DEBUG_CFLAGS += -s NO_EXIT_RUNTIME +# XXX: if --profiling isn't included then any error dumps 10MB of WASM to the screen rather than a useful message +EMCC_DEBUG_CFLAGS += --profiling +EMCC_PROD_CFLAGS += -O3 +ifdef WASM_DEBUG +EMCC_CFLAGS += $(EMCC_DEBUG_CFLAGS) +else +EMCC_CFLAGS += $(EMCC_PROD_CFLAGS) +endif +# +# Override the build tools and some obj files to +# reflect emscripten +override TARGET_CC = emcc +override TARGET_CXX = emcc +override TARGET_AR = emar +WASM_CFLAGS = -Wall -Wextra -Wno-missing-field-initializers +WASM_CFLAGS += -Wimplicit -Wreturn-type -Wunused -Wformat -Wswitch +WASM_CFLAGS += -Wshadow +# WASM_CFLAGS += -Wwrite-strings +# WASM_CFLAGS += -Werror +# Nethack C flags +WASM_CFLAGS += $(WINCFLAGS) #WINCFLAGS set from multiw-2.2020 +WASM_CFLAGS += -DSYSCF -DSYSCF_FILE=\"/sysconf\" -DSECURE +WASM_CFLAGS += -g -I../include -DNOTPARMDECL +WASM_CFLAGS += -DGCC_WARN +# NetHack sources control +WASM_CFLAGS += -DDLB +WASM_CFLAGS += -DHACKDIR=\"$(HACKDIR)\" +WASM_CFLAGS += -DDEFAULT_WINDOW_SYS=\"shim\" \ +#override TARGET_CFLAGS += -DGREPPATH=\"/usr/bin/grep\" +WASM_CFLAGS += -DNOMAIL +WASM_CFLAGS += $(LUAINCL) +WASM_CFLAGS += -DNOTTYGRAPHICS -DSHIM_GRAPHICS -DLIBNH +WASM_CFLAGS += -DCROSSCOMPILE +WASM_TARGET_CFLAGS = -DCROSSCOMPILE_TARGET -DCROSS_TO_WASM +# For src Makefile +override CFLAGS = $(WASM_CFLAGS) +override TARGET_CFLAGS = $(EMCC_CFLAGS) $(WASM_CFLAGS) $(WASM_TARGET_CFLAGS) +# +override TARGET_CXXFLAGS = $(TARGET_CFLAGS) +override TARGET_LINK = $(TARGET_CC) +override TARGET_LFLAGS= $(EMCC_LFLAGS) +override SYSSRC = ../sys/libnh/libnhmain.c \ + ../sys/share/ioctl.c ../sys/share/unixtty.c \ + ../sys/unix/unixunix.c ../sys/unix/unixres.c \ + ../win/shim/winshim.c +override SYSOBJ= $(TARGETPFX)libnhmain.o \ + $(TARGETPFX)ioctl.o $(TARGETPFX)unixtty.o \ + $(TARGETPFX)unixunix.o $(TARGETPFX)unixres.o \ + $(TARGETPFX)winshim.o +override WINLIB = emranlib +override LUALIB= +override TOPLUALIB= +override REGEXOBJ = $(TARGETPFX)posixregex.o +override WINOBJ= +# don't bother Making regular NetHack executable +override GAME= +# the real VARDAT hasn't been defined yet for use in ALLDEP override +WASM_DAT = bogusmon data engrave epitaph oracles options quest.lua rumors +WASMDEP = include/nhlua.h $(WASM_DAT) spec_levs check-dlb +override ALLDEP = $(WASMDEP) wasm +override PREGAME += mkdir -p $(TARGETDIR)/wasm-data ; +override CLEANMORE += rm -rf $(TARGETDIR) ; +RANLIB=$(EMRANLIB) +#VARDATND += nhtiles.bmp +# Rule for file in sys/unix +$(TARGETPFX)%.o : ../sys/unix/%.c + $(TARGET_CC) $(TARGET_CFLAGS) -c -o$@ $< +# Rule for file in sys/libnh +$(TARGETPFX)%.o : ../sys/libnh/%.c + $(TARGET_CC) $(TARGET_CFLAGS) -c -o$@ $< +# Rule for files in win/shim +$(TARGETPFX)%.o : ../win/shim/%.c + $(TARGET_CC) $(TARGET_CFLAGS) -c -o$@ $< +endif # CROSS_TO_WASM +#================================================================= + +ifdef WANT_WIN_CURSES +ifdef BUILD_PDCURSES +# Rules for PDCurses files +$(TARGETPFX)%.o : $(PDCTOP)/pdcurses/%.c + $(TARGET_CC) $(PDCINCL) $(TARGET_CFLAGS) -c -o$@ $< +endif # BUILD_PDCURSES +endif # WANT_WIN_CURSES + +ifdef CROSS_SHARED +# Rules for win/share files +$(TARGETPFX)%.o : ../win/share/%.c + $(TARGET_CC) $(TARGET_CFLAGS) -c -o$@ $< +# Rules for util files heading for target +$(TARGETPFX)%.o : ../util/%.c + $(TARGET_CC) $(TARGET_CFLAGS) -c -o$@ $< +endif # CROSS_SHARED + +ifdef BUILD_TARGET_LUA +# Rule for LUA files +$(TARGETPFX)%.o : $(LUATOP)/src/%.c + $(TARGET_CC) $(TARGET_CFLAGS) -c $(LUA_FLAGS) -o$@ $< +endif # BUILD_TARGET_LUA +# +# End of cross-compiling -PRE section +#===============-================================================= + diff --git a/sys/unix/hints/include/multiw-1.2020 b/sys/unix/hints/include/multiw-1.2020 new file mode 100644 index 000000000..3fb550882 --- /dev/null +++ b/sys/unix/hints/include/multiw-1.2020 @@ -0,0 +1,37 @@ +#------------------------------------------------------------------------------ +# NetHack 3.7 multiw-1.2020 $NHDT-Date: 1597332785 2020/08/13 15:33:05 $ $NHDT-Branch: NetHack-3.7 $ + +# 1. Which windowing interface(s) should be included in this binary? +# One or more of these can be manually uncommented and/or can be specified +# on the 'make' command line. If none are enabled, tty will be used. +#WANT_WIN_TTY=1 +#WANT_WIN_CURSES=1 +#WANT_WIN_X11=1 +#WANT_WIN_QT=1 + +# 2. What is the default window system? +# Exactly one of these can be manually uncommented and/or can be specified +# on the 'make' command line. If none is enabled, the first among +# WANT_WIN_{tty,curses,X11,Qt} that is enabled will become default. +#WANT_DEFAULT=tty +#WANT_DEFAULT=curses +#WANT_DEFAULT=Qt +#WANT_DEFAULT=X11 + +# 3. compiler detection or optional override +CCISCLANG := $(shell echo `$(CC) --version` | grep clang) +ifeq "$(CCISCLANG)" "" +CXX=g++ -std=gnu++11 +else +CXX=clang++ -std=gnu++11 +endif +# if you want to override the compiler detection just carried out +# uncomment one of the following pairs as desired. +#CC= gcc +#CXX= g++ -std-gnu++11 +# +#CC= clang +#CXX=clang++ -std=gnu++11 + +#end of multiw-1.2020 +#------------------------------------------------------------------------------ diff --git a/sys/unix/hints/include/multiw-2.2020 b/sys/unix/hints/include/multiw-2.2020 new file mode 100644 index 000000000..7c956acb5 --- /dev/null +++ b/sys/unix/hints/include/multiw-2.2020 @@ -0,0 +1,109 @@ +#------------------------------------------------------------------------------ +# NetHack 3.7 multiw-2.2020 $NHDT-Date: 1599337709 2020/09/05 20:28:29 $ $NHDT-Branch: NetHack-3.7 $ +# +# Sorts out support for multiple window ports (interfaces) to included in the build. +# +# Included from: +# hints/linux.2020 +# hints/macOS.2020 +# +# The following will be set appropriately following this: +# - WANT_WIN_XXX (at least one will be set; default is TTY) +# - WANT_DEFAULT (set to match one of the enabled WANT_WIN_XXX) +# - WINCFLAGS +# - WINSRC +# - WINOBJ0 +#--- +# User selections could be specified as combinations of any of the following: +# WIN_WANT_TTY=1, WIN_WANT_CURSES=1, WIN_WANT_QT=1, WIN_WANT_X11=1 +# The selections will all be linked into the same binary. +# +# Assuming you have the prerequisite packages mentioned above, you can +# specify, right on the make command line, which window ports (or interfaces) +# to include in your build. Doing it via the make command line means that won't +# have to edit the Makefile. +# +# make WANT_WIN_QT=1 WANT_WIN_X11=1 WANT_WIN_CURSES=1 WANT_WIN_TTY=1 install +# +# Add WANT_DEFAULT=Qt (or other interface) if you want nethack to use +# something other than tty as the default interface. +# + +ifdef WANT_WIN_ALL +WANT_WIN_TTY=1 +WANT_WIN_CURSES=1 +WANT_WIN_X11=1 +WANT_WIN_QT=1 +else +# Make sure that at least one interface is enabled. +ifndef WANT_WIN_TTY +ifndef WANT_WIN_CURSES +ifndef WANT_WIN_X11 +ifndef WANT_WIN_QT +WANT_WIN_TTY=1 +endif +endif +endif +endif +endif + +ifdef WANT_LIBNH +WANT_DEFAULT=shim +endif + +# Make sure that a default interface is specified; this doesn't guarantee +# sanity for something like 'make WANT_WIN_CURSES=1 WANT_DEFAULT=X11' but +# 'makedefs -v' would notice, complain, and quit causing 'make' to quit. +ifndef WANT_DEFAULT +# pick the first one enabled among { tty, curses, X11, Qt } +ifdef WANT_WIN_TTY +WANT_DEFAULT=tty +else +ifdef WANT_WIN_CURSES +WANT_DEFAULT=curses +else +ifdef WANT_WIN_X11 +WANT_DEFAULT=X11 +else +ifdef WANT_WIN_QT +WANT_DEFAULT=Qt +else +# ? shouldn't be able to get here... +endif +endif +endif +endif +endif + +WINCFLAGS= +WINSRC = +WINOBJ0 = + +ifdef WANT_WIN_TTY +WINSRC += $(WINTTYSRC) +WINOBJ0 += $(WINTTYOBJ) +else +WINCFLAGS += -DNOTTYGRAPHICS +endif + +ifdef WANT_WIN_CURSES +WINCFLAGS += -DCURSES_GRAPHICS +WINSRC += $(WINCURSESSRC) +WINOBJ0 += $(WINCURSESOBJ) +endif + +ifdef WANT_WIN_X11 +WINCFLAGS += -DX11_GRAPHICS +WINSRC += $(WIINX11SRC) +WINOBJ0 += $(WINX11OBJ) +endif + +ifdef WANT_WIN_QT +WINCFLAGS += -DQT_GRAPHICS +WINSRC += $(WINQTSRC) +WINOBJ0 += $(WINQTOBJ) +endif + +#end of hints/include/multiw-2.2020 +#------------------------------------------------------------------------------ + diff --git a/sys/unix/hints/linux b/sys/unix/hints/linux index 47260f78c..48ab631c1 100644 --- a/sys/unix/hints/linux +++ b/sys/unix/hints/linux @@ -1,5 +1,5 @@ # -# NetHack 3.6 linux $NHDT-Date: 1589828478 2020/05/18 19:01:18 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.31 $ +# NetHack 3.7 linux $NHDT-Date: 1596498415 2020/08/03 23:46:55 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.32 $ # Copyright (c) Kenneth Lorber, Kensington, Maryland, 2007. # NetHack may be freely redistributed. See license for details. # diff --git a/sys/unix/hints/linux-minimal b/sys/unix/hints/linux-minimal index 0582792d9..003d69fe1 100644 --- a/sys/unix/hints/linux-minimal +++ b/sys/unix/hints/linux-minimal @@ -1,5 +1,5 @@ # -# NetHack 3.6 linux $NHDT-Date: 1589828479 2020/05/18 19:01:19 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.1 $ +# NetHack 3.7 linux $NHDT-Date: 1596498416 2020/08/03 23:46:56 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.2 $ # Copyright (c) Patric Mueller # NetHack may be freely redistributed. See license for details. # diff --git a/sys/unix/hints/linux-qt4 b/sys/unix/hints/linux-qt4 index 33abfbc84..3ef04923d 100644 --- a/sys/unix/hints/linux-qt4 +++ b/sys/unix/hints/linux-qt4 @@ -1,5 +1,5 @@ # -# NetHack 3.6 linux-qt4 $NHDT-Date: 1589828479 2020/05/18 19:01:19 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.28 $ +# NetHack 3.7 linux-qt4 $NHDT-Date: 1596498416 2020/08/03 23:46:56 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.29 $ # Copyright (c) Kenneth Lorber, Kensington, Maryland, 2007. # NetHack may be freely redistributed. See license for details. # diff --git a/sys/unix/hints/linux-qt5 b/sys/unix/hints/linux-qt5 index 1ee188568..945384baf 100644 --- a/sys/unix/hints/linux-qt5 +++ b/sys/unix/hints/linux-qt5 @@ -1,5 +1,5 @@ # -# NetHack 3.6 linux-qt5 $NHDT-Date: 1589828480 2020/05/18 19:01:20 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.29 $ +# NetHack 3.7 linux-qt5 $NHDT-Date: 1596498417 2020/08/03 23:46:57 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.30 $ # Copyright (c) Kenneth Lorber, Kensington, Maryland, 2007. # NetHack may be freely redistributed. See license for details. # diff --git a/sys/unix/hints/linux-x11 b/sys/unix/hints/linux-x11 index 0f186e3f0..64dc9c235 100644 --- a/sys/unix/hints/linux-x11 +++ b/sys/unix/hints/linux-x11 @@ -1,5 +1,5 @@ # -# NetHack 3.6 linux-x11 $NHDT-Date: 1589828480 2020/05/18 19:01:20 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.25 $ +# NetHack 3.7 linux-x11 $NHDT-Date: 1596498418 2020/08/03 23:46:58 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.26 $ # Copyright (c) Kenneth Lorber, Kensington, Maryland, 2007. # NetHack may be freely redistributed. See license for details. # diff --git a/sys/unix/hints/linux.2020 b/sys/unix/hints/linux.2020 new file mode 100755 index 000000000..a9aeef494 --- /dev/null +++ b/sys/unix/hints/linux.2020 @@ -0,0 +1,236 @@ +# NetHack 3.7 linux.2020 $NHDT-Date: 1599687610 2020/09/09 21:40:10 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.11 $ +# Copyright (c) Kenneth Lorber, Kensington, Maryland, 2007. +# NetHack may be freely redistributed. See license for details. +# +#--------------------------------------------------------------------- +# Linux hints file with support for multiple window ports (interfaces) +# Tested on: +# - Ubuntu focal +# +# If this doesn't work for your distribution, consider making a new +# hints file for it, rather than changing this one. +# And let us know about it. +# + +#-PRE +# linux.2020 hints file provides a single-user build for Linux (such +# as Ubuntu focal). + +# compiler flags: CCFLAGS is used to construct a value for CFLAGS with +# various -I, -D, and -W settings appended below; +# these are the settings of most interest for an end-user build +# (clang doesn't support '-Og', gcc needs 4.x or later) +CCFLAGS = -g +#CCFLAGS = -g -Og +#CCFLAGS = -O2 +# Note: this is not the usual 'CFLAGS' which is used in default +# rules for compiling C code; specifying a value for that on the +# 'make' command line should be avoided. + +# note: '#-INCLUDE' is not just a comment; multiw-1 contains sections 1 to 3 +#-INCLUDE multiw-1.2020 + +# 4. If you set WANT_WIN_QT, you need to +# A) set QTDIR either here or in the environment to point to the Qt5 +# Library installation root. +# B) set XPMLIB to point to the Xpm library +ifndef WANT_WIN_QT +ifdef WANT_WIN_ALL +WANT_WIN_QT=1 +endif +endif +ifdef WANT_WIN_QT +QTDIR=/usr +endif # WANT_WIN_QT +ifndef LIBXPM +LIBXPM= -L/opt/X11/lib -lXpm +endif + +#5. Other +GAMEUID = $(USER) +GAMEGRP = games + +#----------------------------------------------------------------------------- +# You shouldn't need to change anything below here (in the hints file; if +# you're reading this in Makefile augmented by hints, that may not be true). +# + +#-INCLUDE multiw-2.2020 + +CFLAGS=$(CCFLAGS) -I../include -DNOTPARMDECL + +ifeq "$(CCISCLANG)" "" +# get the version of gcc +GCCGTEQ9 := $(shell expr `$(CC) -dumpversion | cut -f1 -d.` \>= 9) +ifeq "$(GCCGTEQ9)" "1" +CFLAGS+=-Wno-format-overflow +endif #gcc version greater than or equal to 9 +endif #not clang +# As of LLVM build 2336.1.00, this gives dozens of spurious messages, so +# leave it out by default. +#CFLAGS+=-Wunreachable-code +#CFLAGS+=-Wall -Wextra -Wno-missing-field-initializers -Wimplicit \ +# -Wreturn-type -Wunused -Wformat -Wswitch -Wshadow -Wwrite-strings +#CFLAGS+=-DGCC_WARN + +# NetHack sources control +CFLAGS+=-DDLB +CFLAGS+=-DHACKDIR=\"$(HACKDIR)\" +CFLAGS+=-DDEFAULT_WINDOW_SYS=\"$(WANT_DEFAULT)\" +CFLAGS+=-DSYSCF -DSYSCF_FILE=\"$(HACKDIR)/sysconf\" -DSECURE +CFLAGS+=-DTIMED_DELAY +CFLAGS+=-DDUMPLOG +CFLAGS+=-DCONFIG_ERROR_SECURE=FALSE +#CFLAGS+=-DGREPPATH=\"/usr/bin/grep\" +CFLAGS+=-DCOMPRESS=\"/bin/gzip\" -DCOMPRESS_EXTENSION=\".gz\" +#CFLAGS+=-DNOMAIL +#CFLAGS+=-DEXTRA_SANITY_CHECKS +#CFLAGS+=-DEDIT_GETLIN +#CFLAGS+=-DSCORE_ON_BOTL +#CFLAGS+=-DMSGHANDLER +#CFLAGS+=-DTTY_TILES_ESCCODES +#CFLAGS+=-DTTY_SOUND_ESCCODES + +CFLAGS+= $(WINCFLAGS) #WINCFLAGS set from multiw-2.2020 + +VARDATND = +VARDATND0 = +CURSESLIB = + +#ifdef WANT_WIN_CHAIN +#HINTSRC=$(CHAINSRC) +#HINTOBJ=$(CHAINOBJ) +#endif # WANT_WIN_CHAIN + +ifdef WANT_WIN_TTY +CURSESLIB = -lncurses -ltinfo +endif + +ifdef WANT_WIN_CURSES +CURSESLIB = -lncurses -ltinfo +endif + +ifdef CURSESLIB +WINLIB += $(CURSESLIB) +endif + +ifdef WANT_WIN_X11 +USE_XPM=1 +WINX11LIB = -lXaw -lXmu -lXext -lXt -lX11 +VARDATND0 += x11tiles NetHack.ad pet_mark.xbm pilemark.xbm +# -x: if built without dlb, some versions of mkfontdir think *.lev are fonts +POSTINSTALL += bdftopcf win/X11/nh10.bdf > $(HACKDIR)/nh10.pcf; ( cd $(HACKDIR); mkfontdir -x .lev ); +# separate from CFLAGS so that we don't pass it to every file +X11CFLAGS = -I/opt/X11/include +# avoid repeated complaints about _X_NONNULL(args...) in +X11CFLAGS += -Wno-variadic-macros +ifdef USE_XPM +CFLAGS += -DUSE_XPM +WINX11LIB += -lXpm +VARDATND0 += rip.xpm +endif +WINLIB += $(WINX11LIB) +LFLAGS=-L/opt/X11/lib +endif # WANT_WIN_X11 + +ifdef WANT_WIN_QT +# Qt5 requires C++11 +LINK = $(CXX) +QTCXXFLAGS += -Wno-deprecated-declarations +ifeq "$(CCISCLANG)" "" +# get the version of g++ +GPPGTEQ9 := $(shell expr `$(CXX) -dumpversion | cut -f1 -d.` \>= 9) +ifeq "$(GPPGTEQ9)" "1" +QTCXXFLAGS+= -Wno-format-truncation +endif #g++ version greater than or equal to 9 +endif #not clang +QTCXXFLAGS += $(sort $(shell PKG_CONFIG_PATH=$(QTDIR)/lib/pkgconfig pkg-config Qt5Gui Qt5Widgets Qt5Multimedia --cflags)) +QTCXXFLAGS += -fPIC +WINLIB += $(shell PKG_CONFIG_PATH=$(QTDIR)/lib/pkgconfig pkg-config Qt5Gui Qt5Widgets Qt5Multimedia --libs) +VARDATND0 += nhtiles.bmp rip.xpm nhsplash.xpm +# XXX if /Developer/qt exists and QTDIR not set, use that +ifndef QTDIR +$(error QTDIR not defined in the environment or Makefile) +endif # QTDIR +# XXX make sure QTDIR points to something reasonable +POSTINSTALL+= bdftopcf win/X11/nh10.bdf > $(INSTDIR)/nh10.pcf; \ + ( cd $(INSTDIR); mkfontdir -x .lev ); +else +LINK = $(CC) +endif # !WANT_WIN_QT + +# prevent duplicate tile.o in WINOBJ +WINOBJ = $(sort $(WINOBJ0)) +# prevent duplicates in VARDATND if both X11 and Qt are being supported +VARDATND += $(sort $(VARDATND0)) + +ifdef WANT_LIBNH +CFLAGS += -DSHIM_GRAPHICS -DNOTTYGRAPHICS -DNOSHELL -DLIBNH +LIBNHSYSSRC = ../sys/libnh/libnhmain.c \ + ../sys/share/ioctl.c ../sys/share/unixtty.c \ + ../sys/unix/unixunix.c ../sys/unix/unixres.c \ + ../win/shim/winshim.c +LIBNHSYSOBJ= libnhmain.o ioctl.o unixtty.o unixunix.o \ + unixres.o winshim.o +#don't bother building the game executable as it will fail +#without winshim +override GAME= +MOREALL += ( cd src ; $(MAKE) pregame ; $(MAKE) libnh.a ) +endif # WANT_LIBNH + +#PREFIX=/usr +PREFIX=$(wildcard ~)/nh/install +HACKDIR=$(PREFIX)/games/lib/$(GAME)dir +SHELLDIR = $(PREFIX)/games +INSTDIR=$(HACKDIR) +VARDIR = $(HACKDIR) + +POSTINSTALL+= cp -n sys/unix/sysconf $(INSTDIR)/sysconf; \ + $(CHOWN) $(GAMEUID) $(INSTDIR)/sysconf; \ + $(CHGRP) $(GAMEGRP) $(INSTDIR)/sysconf; \ + chmod $(VARFILEPERM) $(INSTDIR)/sysconf; + +ifneq "$(CCISCLANG)" "" +# gdb may not be installed if clang is chosen compiler so the game +# won't start in that case due to a sysconf error. Comment out +# relevant lines in sysconf. +POSTINSTALL+= sed -i -e 's;^GDBPATH=/usr/bin/gdb;\#GDBPATH=/usr/bin/gdb;' \ + -e 's;PANICTRACE_GDB=1;PANICTRACE_GDB=0;' $(INSTDIR)/sysconf; +endif + +# when building liblua.a, avoid warning that use of tmpnam() should be +# replaced by mkstemp(); the lua code doesn't use nethack's config.h so +# this needs to be passed via make rather than defined in unixconf.h +SYSCFLAGS=-DLUA_USE_POSIX + +# Only needed for GLIBC stack trace: +LFLAGS=-rdynamic + +# if TTY_TILES_ESCCODES +#WINSRC += tile.c +#WINOBJ += tile.o +# endif + +CHOWN=true +CHGRP=true + +VARDIRPERM = 0755 +VARFILEPERM = 0600 +GAMEPERM = 0755 +# +#-INCLUDE cross-pre.2020 +# +#-POST +# +#-INCLUDE cross-post.2020 +# +ifdef WANT_LIBNH +libnh.a: $(HOBJ) $(LIBNHSYSOBJ) ../lib/lua/liblua.a + $(AR) rcs $@ $(HOBJ) $(LIBNHSYSOBJ) ../lib/lua/liblua.a + @echo "$@ built." +libnhmain.o : ../sys/libnh/libnhmain.c $(HACK_H) + $(CC) $(CFLAGS) -c -o$@ $< +winshim.o : ../win/shim/winshim.c $(HACK_H) + $(CC) $(CFLAGS) -c -o$@ $< +endif # WANT_LIBNH +# diff --git a/sys/unix/hints/macOS.2020 b/sys/unix/hints/macOS.2020 new file mode 100755 index 000000000..283f1a779 --- /dev/null +++ b/sys/unix/hints/macOS.2020 @@ -0,0 +1,490 @@ +# NetHack 3.7 macOS.2020 $NHDT-Date: 1599687615 2020/09/09 21:40:15 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.73 $ +# Copyright (c) Kenneth Lorber, Kensington, Maryland, 2015. +# NetHack may be freely redistributed. See license for details. +# +#--------------------------------------------------------------------- +# MacOS hints file with support for multiple window ports (interfaces) +# Tested on: +# - MacOS Catalina 10.15 +# +# If this doesn't work for some other version of Mac OS X, consider +# making a new hints file it, rather than changing this one. +# And let us know about it. +# Useful info: http://www.opensource.apple.com/darwinsource/index.html + +#-PRE xxxx +# macOS X hints file +# + +# compiler flags: CCFLAGS is used to construct a value for CFLAGS with +# various -I, -D, and -W settings appended below; +# these are the settings of most interest for an end-user build +# (clang doesn't support '-Og', gcc needs 4.x or later) +CCFLAGS = -g +#CCFLAGS = -g -Og +#CCFLAGS = -O2 +# Note: this is not the usual 'CFLAGS' which is used in default +# rules for compiling C code; specifying a value for that on the +# 'make' command line should be avoided. + +# note: '#-INCLUDE' is not just a comment; multiw-1 contains sections 1 to 3 +#-INCLUDE multiw-1.2020 + +# 4. If you set WANT_WIN_QT, you need to +# A) set QTDIR either here or in the environment to point to the Qt5 +# library installation root. (Qt2, Qt3, Qt4 will not work) +# B) set XPMLIB to point to the Xpm library +ifndef WANT_WIN_QT +ifdef WANT_WIN_ALL +WANT_WIN_QT=1 +endif +endif +ifdef WANT_WIN_QT +#QTDIR=/Developer/Qt +# Qt installed via homebrew +QTDIR=$(shell brew --prefix)/opt/qt +# Qt installed via macports +#QTDIR=/opt/local/libexec/qt5 +endif # WANT_WIN_QT +ifndef LIBXPM +LIBXPM= -L/opt/X11/lib -lXpm +endif + +# 5. Other + +#----------------------------------------------------------------------------- +# You shouldn't need to change anything below here (in the hints file; if +# you're reading this in Makefile augmented by hints, that may not be true). +# + +#-INCLUDE multiw-2.2020 + +CFLAGS=$(CCFLAGS) -I../include -DNOTPARMDECL + +ifndef WANT_WIN_QT +ifndef WANT_LIBNH +# these are normally used when compiling nethack's core +CFLAGS+=-ansi -pedantic -Wno-long-long +# but -ansi forces -std=c90 for C or -std=c++98 for C++; +# win/Qt/qt_*.cpp compiled with C++98 semantics trigger +#In file included from .../qt5/include/QtCore/qglobal.h:105: +#.../qt5/include/QtCore/qcompilerdetection.h:561:6: +# error Qt requires a C++11 compiler and yours does not seem to be that. +# so we suppress -ansi when the build includes Qt +#LIBNH's winshim requires C99 for the way it is currently coded +endif +endif +# As of LLVM build 2336.1.00, this gives dozens of spurious messages, so +# leave it out by default. +#CFLAGS+=-Wunreachable-code +CFLAGS+=-Wall -Wextra -Wno-missing-field-initializers -Wimplicit \ + -Wreturn-type -Wunused -Wformat -Wswitch -Wshadow -Wwrite-strings +CFLAGS+=-DGCC_WARN + +# NetHack sources control +CFLAGS+=-DDLB +CFLAGS+=-DHACKDIR=\"$(HACKDIR)\" +CFLAGS+=-DDEFAULT_WINDOW_SYS=\"$(WANT_DEFAULT)\" -DDLB +CFLAGS+=-DSYSCF -DSYSCF_FILE=\"$(HACKDIR)/sysconf\" -DSECURE +#CFLAGS+=-DTIMED_DELAY +#CFLAGS+=-DDUMPLOG +#CFLAGS+=-DCONFIG_ERROR_SECURE=FALSE +CFLAGS+=-DGREPPATH=\"/usr/bin/grep\" +#CFLAGS+=-DCOMPRESS=\"/bin/gzip\" -DCOMPRESS_EXTENSION=\".gz\" +CFLAGS+=-DNOMAIL +#CFLAGS+=-DEXTRA_SANITY_CHECKS +#CFLAGS+=-DEDIT_GETLIN +#CFLAGS+=-DSCORE_ON_BOTL +#CFLAGS+=-DMSGHANDLER +#CFLAGS+=-DTTY_TILES_ESCCODES +#CFLAGS+=-DTTY_SOUND_ESCCODES + +CFLAGS+= $(WINCFLAGS) #WINCFLAGS set from multiw-2.2020 + +VARDATND = +VARDATND0 = +CURSESLIB = + +ifdef WANT_WIN_CHAIN +HINTSRC=$(CHAINSRC) +HINTOBJ=$(CHAINOBJ) +endif # WANT_WIN_CHAIN + +ifdef WANT_WIN_TTY +CURSESLIB = -lncurses +endif + +ifdef WANT_WIN_CURSES +CURSESLIB = -lncurses +endif + +ifdef CURSESLIB +WINLIB += $(CURSESLIB) +endif + +ifdef WANT_WIN_X11 +USE_XPM=1 +WINX11LIB = -lXaw -lXmu -lXext -lXt -lX11 +VARDATND0 += x11tiles NetHack.ad pet_mark.xbm pilemark.xbm +# -x: if built without dlb, some versions of mkfontdir think *.lev are fonts +POSTINSTALL += bdftopcf win/X11/nh10.bdf > $(HACKDIR)/nh10.pcf; ( cd $(HACKDIR); mkfontdir -x .lev ); +# separate from CFLAGS so that we don't pass it to every file +X11CFLAGS = -I/opt/X11/include +# avoid repeated complaints about _X_NONNULL(args...) in +X11CFLAGS += -Wno-variadic-macros +ifdef USE_XPM +CFLAGS += -DUSE_XPM +WINX11LIB += -lXpm +VARDATND0 += rip.xpm +endif +WINLIB += $(WINX11LIB) +LFLAGS=-L/opt/X11/lib +endif # WANT_WIN_X11 + +ifdef WANT_WIN_QT +# Qt5 requires C++11 +LINK = $(CXX) +QTCXXFLAGS += -Wno-deprecated-declarations +ifeq "$(CCISCLANG)" "" +# get the version of g++ +GPPGTEQ9 := $(shell expr `$(CXX) -dumpversion | cut -f1 -d.` \>= 9) +ifeq "$(GPPGTEQ9)" "1" +QTCXXFLAGS+= -Wno-format-truncation +endif #g++ version greater than or equal to 9 +endif #not clang +QTCXXFLAGS += $(sort $(shell PKG_CONFIG_PATH=$(QTDIR)/lib/pkgconfig pkg-config Qt5Gui Qt5Widgets Qt5Multimedia --cflags)) +WINLIB += $(shell PKG_CONFIG_PATH=$(QTDIR)/lib/pkgconfig pkg-config Qt5Gui Qt5Widgets Qt5Multimedia --libs) +WINSRC += $(WINQTSRC) +WINOBJ0 += $(WINQTOBJ) +VARDATND0 += nhtiles.bmp rip.xpm nhsplash.xpm +# XXX if /Developer/qt exists and QTDIR not set, use that +ifndef QTDIR +$(error QTDIR not defined in the environment or Makefile) +endif # QTDIR +# XXX make sure QTDIR points to something reasonable +else # !WANT_WIN_QT +LINK=$(CC) +endif # !WANT_WIN_QT + +# prevent duplicate tile.o in WINOBJ +WINOBJ = $(sort $(WINOBJ0)) +# prevent duplicates in VARDATND if both X11 and Qt are being supported +VARDATND += $(sort $(VARDATND0)) + +ifdef WANT_LIBNH +CFLAGS += -DSHIM_GRAPHICS -DNOTTYGRAPHICS -DNOSHELL -DLIBNH +LIBNHSYSSRC = ../sys/libnh/libnhmain.c \ + ../sys/share/ioctl.c ../sys/share/unixtty.c \ + ../sys/unix/unixunix.c ../sys/unix/unixres.c \ + ../win/shim/winshim.c +LIBNHSYSOBJ= libnhmain.o ioctl.o unixtty.o unixunix.o \ + unixres.o winshim.o +#don't bother building the game executable as it will fail +#without winshim +override GAME= +MOREALL += ( cd src ; $(MAKE) pregame ; $(MAKE) libnh.a ) +endif # WANT_LIBNH + +WANT_BUNDLE=1 +ifdef WANT_SHARE_INSTALL +# if $GAMEUID is root, we install into roughly proper Mac locations, otherwise +# we install into ~/nethackdir +ifeq ($(GAMEUID),root) +PREFIX:=/Library/NetHack +SHELLDIR=/usr/local/bin +HACKDIR=$(PREFIX)/nethackdir +CHOWN=chown +CHGRP=chgrp +# We run sgid so the game has access to both HACKDIR and user preferences. +GAMEPERM = 02755 +else # ! root +PREFIX:=/Users/$(GAMEUID) +SHELLDIR=$(PREFIX)/bin +HACKDIR=$(PREFIX)/Library/NetHack/nethackdir +CHOWN=/usr/bin/true +CHGRP=/usr/bin/true +GAMEPERM = 0500 +endif # ! root +VARFILEPERM = 0664 +VARDIRPERM = 0775 +ROOTCHECK= [[ `id -u` == 0 ]] || ( echo "Must run install with sudo."; exit 1) +# XXX it's nice we don't write over sysconf, but we've already erased it +# make sure we have group GAMEUID and group GAMEGRP +PREINSTALL= . sys/unix/hints/macosx.sh user2 $(GAMEUID); \ + . sys/unix/hints/macosx.sh group2 $(GAMEGRP); \ + mkdir $(SHELLDIR); chown $(GAMEUID) $(SHELLDIR) +POSTINSTALL+= sys/unix/hints/macosx.sh editsysconf sys/unix/sysconf $(HACKDIR)/sysconf; \ + $(CHOWN) $(GAMEUID) $(HACKDIR)/sysconf; \ + $(CHGRP) $(GAMEGRP) $(HACKDIR)/sysconf; \ + chmod $(VARFILEPERM) $(HACKDIR)/sysconf; + +else ifdef WANT_SOURCE_INSTALL + +PREFIX=$(abspath $(NHSROOT)) +# suppress nethack.sh +#SHELLDIR= +HACKDIR=$(PREFIX)/playground +CHOWN=/usr/bin/true +CHGRP=/usr/bin/true +GAMEPERM = 0700 +VARFILEPERM = 0600 +VARDIRPERM = 0700 +POSTINSTALL+= sys/unix/hints/macosx.sh editsysconf sys/unix/sysconf $(HACKDIR)/sysconf; +# We can use "make all" to build the whole thing - but it misses some things: +MOREALL=$(MAKE) install +CFLAGS+=-DSYSCF -DSYSCF_FILE=\"$(HACKDIR)/sysconf\" -DSECURE + +else # !WANT_SOURCE_INSTALL + +PREFIX:=$(wildcard ~) +SHELLDIR=$(PREFIX)/bin +HACKDIR=$(PREFIX)/nethackdir +CHOWN=/usr/bin/true +CHGRP=/usr/bin/true +GAMEPERM = 0700 +VARFILEPERM = 0600 +VARDIRPERM = 0700 +ifdef ($(WANT_DEFAULT),X11) +# install nethack.rc as ~/.nethackrc if no ~/.nethackrc exists +PREINSTALL= cp -n win/X11/nethack.rc ~/.nethackrc || true +endif # WANT_DEFAULT X11 + +POSTINSTALL+= sys/unix/hints/macosx.sh editsysconf sys/unix/sysconf $(HACKDIR)/sysconf; \ + $(CHOWN) $(GAMEUID) $(HACKDIR)/sysconf; \ + $(CHGRP) $(GAMEGRP) $(HACKDIR)/sysconf; \ + chmod $(VARFILEPERM) $(HACKDIR)/sysconf; +ifdef WANT_BUNDLE +# +# Bundle +# +# $(HACKDIR)/$(GAME).app/ +# Contents/ +# Frameworks/ +# Info.plist +# MacOS/ +# $(GAME) +# PkgInfo/ +# PlugIns/ +# Resources/ +# SharedFrameWorks/ +# +BUNDLE = mkdir -p $(HACKDIR)/nethack.app/Contents/MacOS; \ + sys/unix/hints/macosx.sh infoplist > $(HACKDIR)/nethack.app/Contents/Info.plist; \ + mv $(HACKDIR)/nethack $(HACKDIR)/nethack.app/Contents/MacOS/nethack; +ifdef WANT_SHARE_INSTALL +BUNDLE+= chmod $(GAMEPERM) $(HACKDIR)/nethack.app/Contents/MacOS/nethack; +endif + +POSTINSTALL+= $(BUNDLE) +POSTINSTALL+= if test -f $(SHELLDIR)/$(GAME); then \ + sed -i '' 's;HACKDIR/$(GAME);HACKDIR/$(GAME).app/Contents/MacOS/$(GAME);' $(SHELLDIR)/$(GAME) ; fi; +endif # WANT_BUNDLE +endif # !WANT_SHARE_INSTALL + +INSTDIR=$(HACKDIR) +VARDIR=$(HACKDIR) + +# ~/Library/Preferences/NetHack Defaults +# OPTIONS=name:player,number_pad,menustyle:partial,!time,showexp +# OPTIONS=hilite_pet,toptenwin,msghistory:200,windowtype:Qt +# +# Install.Qt mentions a patch for macos - it's not there (it seems to be in the Qt binary +# package under the docs directory). +# +#-INCLUDE cross-pre.2020 +# +#-POST + +ifdef WANT_LIBNH +libnh.a: $(HOBJ) $(LIBNHSYSOBJ) ../lib/lua/liblua.a + $(AR) rcs $@ $(HOBJ) $(LIBNHSYSOBJ) ../lib/lua/liblua.a + @echo "$@ built." +libnhmain.o : ../sys/libnh/libnhmain.c $(HACK_H) + $(CC) $(CFLAGS) -c -o$@ $< +winshim.o : ../win/shim/winshim.c $(HACK_H) + $(CC) $(CFLAGS) -c -o$@ $< +endif # WANT_LIBNH + +ifdef MAKEFILE_TOP +### +### Packaging +### +# Notes: +# 1) The Apple developer utilities must be installed in the default location. +# 2) Do a normal build before trying to package the game. +# 3) This matches the 3.4.3 Term package, but there are some things that +# should be changed. +# +# Packages that are being distributed must be signed by a Developer ID +# Installer certificate. Set DEVELOPER_CERT to the name of the certificate +# if you wish for your package to be signed for distribution. +# +# If building a package for signing, you must use sudo approriately. +# the binaries and package using sudo but you DO NOT use sudo to sign the +# package. If you use sudo to sign the package, it will fail. +# +# sudo make all +# sudo make build_tty_pkg +# make sign_tty_pkg +# + +ifdef WANT_WIN_TTY +DEVUTIL=/Developer/Applications/Utilities +SVS=$(shell $(NHSROOT)/util/makedefs --svs) +SVSDOT=$(shell $(NHSROOT)/util/makedefs --svs .) + +PKGROOT_UG = PKGROOT/$(PREFIX) +PKGROOT_UGLN = PKGROOT/$(HACKDIR) +PKGROOT_BIN = PKGROOT/$(SHELLDIR) + +#DEVELOPER_CERT = Developer ID Installer: Bart House +DEVELOPER_CERT = NONE + +spotless:: + rm -rf RESOURCES + rm -rf PKG + rm -rf PKGSCRIPTS + rm -rf PKGROOT + rm -f Info.plist + rm -f Distribution.xml + rm -f NetHack-*-mac-Term* + +build_tty_pkg: +ifneq (,$(WANT_WIN_X11)$(WANT_WIN_QT)) + -echo build_tty_pkg only works for a tty-only build + exit 1 +else + rm -rf NetHack-$(SVS)-mac-Term.pkg NetHack-$(SVS)-mac-Term.dmg + $(MAKE) build_package_root + rm -rf RESOURCES + mkdir RESOURCES + #enscript --language=rtf -o - < dat/license >RESOURCES/License.rtf + sys/unix/hints/macosx.sh descplist > RESOURCES/Description.plist + sys/unix/hints/macosx.sh infoplist > Info.plist + + mkdir PKGROOT/Applications + #osacompile -o NetHackQt/NetHackQt.app/nethackdir/NetHackRecover.app \ + # win/macosx/NetHackRecover.applescript + #cp win/macosx/recover.pl NetHackQt/NetHackQt.app/nethackdir + osacompile -o PKGROOT/Applications/NetHackRecover.app \ + win/macosx/NetHackRecover.applescript + cp win/macosx/recover.pl $(PKGROOT_UGLN) + + osacompile -o PKGROOT/Applications/NetHackTerm.app \ + win/macosx/NetHackTerm.applescript + + # XXX integrate into Makefile.doc + (cd doc; cat Guidebook.mn | ../util/makedefs --grep --input - --output - \ + | tbl tmac.n - | groff | pstopdf -i -o Guidebook.pdf) + cp doc/Guidebook.pdf $(PKGROOT_UG)/doc/NetHackGuidebook.pdf + + osacompile -o PKGROOT/Applications/NetHackGuidebook.app \ + win/macosx/NetHackGuidebook.applescript + + mkdir -p PKG + pkgbuild --root PKGROOT --identifier org.nethack.term --scripts PKGSCRIPTS PKG/NH-Term.pkg + productbuild --synthesize --product Info.plist --package PKG/NH-Term.pkg Distribution.xml + productbuild --distribution Distribution.xml --resources RESOURCES --package-path PKG NetHack-$(SVS)-mac-Term-unsigned.pkg +ifeq ($(DEVELOPER_CERT),NONE) + cp NetHack-$(SVS)-mac-Term-unsigned.pkg NetHack-$(SVS)-mac-Term.pkg + hdiutil create -verbose -srcfolder NetHack-$(SVS)-mac-Term-unsigned.pkg NetHack-$(SVS)-mac-Term-unsigned.dmg + @echo ------------------------------------------- + @echo PACKAGE IS NOT SIGNED FOR DISTRIBUTION!!!!! + @echo =========================================== +else + @echo "run 'make sign_tty_pkg' to complete package" +endif + +sign_tty_pkg: + productsign --timestamp=none --sign "$(DEVELOPER_CERT)" NetHack-$(SVS)-mac-Term-unsigned.pkg NetHack-$(SVS)-mac-Term.pkg || (echo "Package signing failed"; exit 1) + spctl -a -v --type install NetHack-$(SVS)-mac-Term.pkg || (echo "Package not signed properly"; exit 1) + hdiutil create -verbose -srcfolder NetHack-$(SVS)-mac-Term.pkg NetHack-$(SVS)-mac-Term.dmg + +build_package_root: + cd src/.. # make sure we are at TOP + rm -rf PKGROOT + mkdir -p $(PKGROOT_UG)/lib $(PKGROOT_BIN) $(PKGROOT_UG)/man/man6 $(PKGROOT_UG)/doc $(PKGROOT_UGLN) + install -p src/nethack $(PKGROOT_BIN) + # XXX should this be called nethackrecover? + install -p util/recover $(PKGROOT_BIN) + install -p doc/nethack.6 $(PKGROOT_UG)/man/man6 + install -p doc/recover.6 $(PKGROOT_UG)/man/man6 + install -p doc/Guidebook $(PKGROOT_UG)/doc + install -p dat/nhdat $(PKGROOT_UGLN) + sys/unix/hints/macosx.sh editsysconf sys/unix/sysconf $(PKGROOT_UGLN)/sysconf + cd dat; install -p $(DATNODLB) ../$(PKGROOT_UGLN) +# XXX these files should be somewhere else for good Mac form + touch $(PKGROOT_UGLN)/perm $(PKGROOT_UGLN)/record $(PKGROOT_UGLN)/logfile $(PKGROOT_UGLN)/xlogfile + mkdir $(PKGROOT_UGLN)/save +# XXX what about a news file? + + mkdir -p PKGSCRIPTS + echo '#!/bin/sh' > PKGSCRIPTS/postinstall + echo dseditgroup -o create -r '"Games Group"' -s 3600 $(GAMEGRP) >> PKGSCRIPTS/postinstall + echo $(CHOWN) $(GAMEUID) $(HACKDIR) >> PKGSCRIPTS/postinstall + echo $(CHOWN) $(GAMEUID) $(HACKDIR)/* >> PKGSCRIPTS/postinstall + echo $(CHGRP) $(GAMEGRP) $(HACKDIR) >> PKGSCRIPTS/postinstall + echo $(CHGRP) $(GAMEGRP) $(HACKDIR)/* >> PKGSCRIPTS/postinstall + echo $(CHOWN) $(GAMEUID) $(SHELLDIR)/nethack >> PKGSCRIPTS/postinstall + echo $(CHGRP) $(GAMEGRP) $(SHELLDIR)/nethack >> PKGSCRIPTS/postinstall + echo $(CHOWN) $(GAMEUID) $(SHELLDIR)/recover >> PKGSCRIPTS/postinstall + echo $(CHGRP) $(GAMEGRP) $(SHELLDIR)/recover >> PKGSCRIPTS/postinstall + echo chmod $(VARDIRPERM) $(HACKDIR) >> PKGSCRIPTS/postinstall + echo chmod $(VARDIRPERM) $(HACKDIR)/save >> PKGSCRIPTS/postinstall + echo chmod $(FILEPERM) $(HACKDIR)/license >> PKGSCRIPTS/postinstall + echo chmod $(FILEPERM) $(HACKDIR)/nhdat >> PKGSCRIPTS/postinstall + echo chmod $(FILEPERM) $(HACKDIR)/symbols >> PKGSCRIPTS/postinstall + echo chmod $(VARFILEPERM) $(HACKDIR)/perm >> PKGSCRIPTS/postinstall + echo chmod $(VARFILEPERM) $(HACKDIR)/record >> PKGSCRIPTS/postinstall + echo chmod $(VARFILEPERM) $(HACKDIR)/logfile >> PKGSCRIPTS/postinstall + echo chmod $(VARFILEPERM) $(HACKDIR)/xlogfile >> PKGSCRIPTS/postinstall + echo chmod $(VARFILEPERM) $(HACKDIR)/sysconf >> PKGSCRIPTS/postinstall + echo chmod $(GAMEPERM) $(SHELLDIR)/nethack >> PKGSCRIPTS/postinstall + echo chmod $(EXEPERM) $(SHELLDIR)/recover >> PKGSCRIPTS/postinstall + chmod 0775 PKGSCRIPTS/postinstall + +endif # end of build_tty_pkg +endif # WANT_WIN_TTY for packaging + +ifdef WANT_WIN_QT +# XXX untested and incomplete (see below) +build_qt_pkg: +ifneq (,$(WANT_WIN_X11)$(WANT_WIN_TTY)) + -echo build_qt_pkg only works for a qt-only build + exit 1 +else + $(MAKE) build_package_root + rm -rf NetHackQt + mkdir -p NetHackQt/NetHackQt.app/nethackdir/save + mkdir NetHackQt/Documentation + cp doc/Guidebook.txt doc/nethack.txt doc/recover.txt NetHackQt/Documentation + + osacompile -o NetHackQt/NetHackQt.app/nethackdir/NetHackRecover.app \ + win/macosx/NetHackRecover.applescript + cp win/macosx/recover.pl NetHackQt/NetHackQt.app/nethackdir + + mkdir -p NetHackQt/NetHackQt.app/Contents/Frameworks + cp $(QTDIR)/libqt-mt.3.dylib NetHackQt/NetHackQt.app/Contents/Frameworks + + mkdir NetHackQt/NetHackQt.app/Contents/MacOS + mv PKGROOT/nethack NetHackQt/NetHackQt.app/Contents/MacOS + + mv PKGROOT/lib/nethackdir NetHackQt/NetHackQt.app/nethackdir + +# XXX still missing: +#NetHackQt/NetHackQt.app +# /Contents +# Info.plist +# Resources/nethack.icns +#NetHackQt/Documentation +#NetHackQtRecover.txt +#NetHack Defaults.txt +#changes.patch XXX is this still needed? why isn't it part of the tree? +# doesn't go here + hdiutil create -verbose -srcfolder NetHackQt NetHack-$(SVS)-macosx-qt.dmg +endif # end of build_qt_pkg +endif # WANT_WIN_QT for packaging +endif # MAKEFILE_TOP +# +#-INCLUDE cross-post.2020 +# diff --git a/sys/unix/hints/macosx b/sys/unix/hints/macosx index 573473249..c74742396 100644 --- a/sys/unix/hints/macosx +++ b/sys/unix/hints/macosx @@ -1,5 +1,5 @@ # -# NetHack 3.6 macosx $NHDT-Date: 1566346603 2019/08/21 00:16:43 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.20 $ +# NetHack 3.7 macosx $NHDT-Date: 1596498419 2020/08/03 23:46:59 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.21 $ # Copyright (c) Kenneth Lorber, Kensington, Maryland, 2007. # NetHack may be freely redistributed. See license for details. # diff --git a/sys/unix/hints/macosx.sh b/sys/unix/hints/macosx.sh index c6cf10c31..544eefbd1 100755 --- a/sys/unix/hints/macosx.sh +++ b/sys/unix/hints/macosx.sh @@ -1,5 +1,5 @@ #!/bin/sh -# NetHack 3.6 macosx.sh $NHDT-Date: 1517231957 2018/01/29 13:19:17 $ $NHDT-Branch: githash $:$NHDT-Revision: 1.20 $ +# NetHack 3.7 macosx.sh $NHDT-Date: 1597332920 2020/08/13 15:35:20 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.24 $ # Copyright (c) Kenneth Lorber, Kensington, Maryland, 2007. # NetHack may be freely redistributed. See license for details. # @@ -151,7 +151,7 @@ xdescplist) SVSDOT=`util/makedefs --svs .` IFPkgDescriptionDeleteWarning IFPkgDescriptionDescription - NetHack $SVSDOT for the MacOS X Terminal + NetHack $SVSDOT for MacOS IFPkgDescriptionTitle NetHack @@ -169,9 +169,9 @@ xinfoplist) SVSDOT=`util/makedefs --svs .` CFBundleGetInfoString - NetHack $SVSDOT for the MacOS X Terminal + NetHack $SVSDOT for MacOS CFBundleIdentifier - org.nethack.term + org.nethack.macos CFBundleName NetHack CFBundleShortVersionString diff --git a/sys/unix/hints/macosx10.10 b/sys/unix/hints/macosx10.10 index 279a15ec3..262a8af33 100644 --- a/sys/unix/hints/macosx10.10 +++ b/sys/unix/hints/macosx10.10 @@ -1,5 +1,5 @@ # -# NetHack 3.6 macosx10.11 $NHDT-Date: 1566346603 2019/08/21 00:16:43 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.53 $ +# NetHack 3.7 macosx10.11 $NHDT-Date: 1596498420 2020/08/03 23:47:00 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.58 $ # Copyright (c) Kenneth Lorber, Kensington, Maryland, 2015. # NetHack may be freely redistributed. See license for details. # @@ -59,6 +59,7 @@ GAMEGRP = games #WANT_SOURCE_INSTALL=1 CC=gcc +CXX=g++ # At the moment this is just for debugging, but in the future it could be # useful for other things. Requires SYSCF and an ANSI compiler. @@ -68,8 +69,23 @@ CC=gcc # You shouldn't need to change anything below here. # +ifdef WANT_WIN_QT +LINK = $(CXX) +else +LINK = $(CC) +endif + #CFLAGS+=-W -Wimplicit -Wreturn-type -Wunused -Wformat -Wswitch -Wshadow -Wcast-qual -Wwrite-strings -DGCC_WARN -CFLAGS+=-Wall -Wextra -Wno-missing-field-initializers -Wimplicit -Wreturn-type -Wunused -Wformat -Wswitch -Wshadow -Wwrite-strings -DGCC_WARN -ansi -pedantic -Wno-long-long +CFLAGS+=-Wall -Wextra -Wno-missing-field-initializers -Wimplicit -Wreturn-type -Wunused -Wformat -Wswitch -Wshadow -Wwrite-strings -DGCC_WARN +ifndef WANT_WIN_QT +# these are normally used when compiling nethack's core +CFLAGS+=-ansi -pedantic -Wno-long-long +# but -ansi -pendantic forces C90 sematics and win/Qt/qt_*.cpp trigger +#In file included from .../qt5/include/QtCore/qglobal.h:105: +#.../qt5/include/QtCore/qcompilerdetection.h:561:6: +# error Qt requires a C++11 compiler and yours does not seem to be that. +# so we suppress them when the build includes Qt +endif # As of LLVM build 2336.1.00, this gives dozens of spurious messages, so # leave it out by default. #CFLAGS+=-Wunreachable-code @@ -110,9 +126,9 @@ WINX11LIB = -lXaw -lXmu -lXext -lXt -lX11 VARDATND = x11tiles NetHack.ad pet_mark.xbm pilemark.xbm # -x: if built without dlb, some versions of mkfontdir think *.lev are fonts POSTINSTALL+= bdftopcf win/X11/nh10.bdf > $(HACKDIR)/nh10.pcf; ( cd $(HACKDIR); mkfontdir -x .lev ); +CFLAGS += -DX11_GRAPHICS # separate from CFLAGS so that we don't pass it to every file X11CFLAGS = -I/opt/X11/include -CFLAGS += -DX11_GRAPHICS # avoid repeated complaints about _X_NONNULL(args...) in X11CFLAGS += -Wno-variadic-macros ifdef USE_XPM @@ -129,7 +145,6 @@ endif # WANT_WIN_X11 ifdef WANT_WIN_QT CFLAGS += -DQT_GRAPHICS -DNOUSER_SOUNDS CFLAGS += -isysroot /Developer/SDKs/MacOSX10.4u.sdk -mmacosx-version-min=10.4 -LINK=g++ WINSRC += $(WINQTSRC) WINLIB += $(WINQTLIB) $(LIBXPM) WINLIB += -framework Carbon -framework QuickTime -lz -framework OpenGL @@ -149,8 +164,6 @@ ifndef QTDIR $(error QTDIR not defined in the environment or Makefile) endif # QTDIR # XXX make sure QTDIR points to something reasonable -else # !WANT_WIN_QT -LINK=$(CC) endif # !WANT_WIN_QT ifdef WANT_SHARE_INSTALL diff --git a/sys/unix/hints/macosx10.10-qt b/sys/unix/hints/macosx10.10-qt index 865c2d20a..35b83213b 100644 --- a/sys/unix/hints/macosx10.10-qt +++ b/sys/unix/hints/macosx10.10-qt @@ -1,5 +1,5 @@ # -# NetHack 3.6 macosx10.11 $NHDT-Date: 1566346604 2019/08/21 00:16:44 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.51 $ +# NetHack 3.7 macosx10.10-qt $NHDT-Date: 1597704795 2020/08/17 22:53:15 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.63 $ # Copyright (c) Kenneth Lorber, Kensington, Maryland, 2015. # NetHack may be freely redistributed. See license for details. # @@ -24,14 +24,17 @@ WANT_WIN_QT=1 # 1a. What is the default window system? #WANT_DEFAULT=tty -#WANT_DEFAULT=x11 +#WANT_DEFAULT=X11 WANT_DEFAULT=Qt # 1b. If you set WANT_WIN_QT, you need to # A) set QTDIR either here or in the environment to point to the Qt5 # library installation root. (Qt2 or Qt3 will not work.) ifdef WANT_WIN_QT +# Qt installed via homebrew QTDIR=$(shell brew --prefix)/opt/qt +# Qt installed via macports (qt511 package; 5.13 requires OSX 10.12 or later) +#QTDIR=/opt/local/libexec/qt5 endif # WANT_WIN_QT # 2. Is this a build for a binary that will be shared among different users @@ -64,8 +67,23 @@ CXX=clang++ -std=gnu++11 # You shouldn't need to change anything below here. # +ifdef WANT_WIN_QT +LINK = $(CXX) +else +LINK = $(CC) +endif + #CFLAGS+=-W -Wimplicit -Wreturn-type -Wunused -Wformat -Wswitch -Wshadow -Wcast-qual -Wwrite-strings -DGCC_WARN CFLAGS+=-Wall -Wextra -Wno-missing-field-initializers -Wimplicit -Wreturn-type -Wunused -Wformat -Wswitch -Wshadow -Wwrite-strings -DGCC_WARN +ifndef WANT_WIN_QT +# these are normally used when compiling nethack's core +CFLAGS+=-ansi -pedantic -Wno-long-long +# but -ansi -pendantic forces C90 sematics and win/Qt/qt_*.cpp trigger +#In file included from .../qt5/include/QtCore/qglobal.h:105: +#.../qt5/include/QtCore/qcompilerdetection.h:561:6: +# error Qt requires a C++11 compiler and yours does not seem to be that. +# so we suppress them when the build includes Qt +endif # As of LLVM build 2336.1.00, this gives dozens of spurious messages, so # leave it out by default. #CFLAGS+=-Wunreachable-code @@ -88,7 +106,6 @@ endif WINSRC = WINOBJ0 = WINLIB = -LINK = $(CC) VARDATND = ifdef WANT_WIN_TTY @@ -101,25 +118,34 @@ CFLAGS += -DNOTTYGRAPHICS endif # !WANT_WIN_TTY ifdef WANT_WIN_X11 +WINX11LIB = -lXaw -lXmu -lXext -lXt -lX11 +VARDATND0 = x11tiles NetHack.ad pet_mark.xbm pilemark.xbm +# -x: if built without dlb, some versions of mkfontdir think *.lev are fonts +POSTINSTALL+= bdftopcf win/X11/nh10.bdf > $(HACKDIR)/nh10.pcf; ( cd $(HACKDIR); mkfontdir -x .lev ); +CFLAGS += -DX11_GRAPHICS +# separate from CFLAGS so that we don't pass it to every file +X11CFLAGS = -I/opt/X11/include +# avoid repeated complaints about _X_NONNULL(args...) in +X11CFLAGS += -Wno-variadic-macros +ifdef USE_XPM +CFLAGS += -DUSE_XPM +WINX11LIB += -lXpm +VARDATND0 += rip.xpm +endif WINSRC += $(WINX11SRC) WINOBJ0 += $(WINX11OBJ) WINLIB += $(WINX11LIB) -LFLAGS += -L/opt/X11/lib -VARDATND += x11tiles NetHack.ad pet_mark.xbm pilemark.xbm -POSTINSTALL+= bdftopcf win/X11/nh10.bdf > $(HACKDIR)/nh10.pcf; ( cd $(HACKDIR); mkfontdir -x .lev ); -CFLAGS += -DX11_GRAPHICS -I/opt/X11/include -# avoid repeated complaints about _X_NONNULL(args...) in -CFLAGS += -Wno-variadic-macros +LFLAGS=-L/opt/X11/lib endif # WANT_WIN_X11 ifdef WANT_WIN_QT CFLAGS += -DQT_GRAPHICS -DNOUSER_SOUNDS -CFLAGS += $(shell PKG_CONFIG_PATH=$(QTDIR)/lib/pkgconfig pkg-config Qt5Gui Qt5Widgets Qt5Multimedia --cflags) +QTCXXFLAGS += -Wno-deprecated-declarations +QTCXXFLAGS += $(shell PKG_CONFIG_PATH=$(QTDIR)/lib/pkgconfig pkg-config Qt5Gui Qt5Widgets Qt5Multimedia --cflags) WINLIB += $(shell PKG_CONFIG_PATH=$(QTDIR)/lib/pkgconfig pkg-config Qt5Gui Qt5Widgets Qt5Multimedia --libs) -LINK=$(CXX) -WINSRC += $(WINQT4SRC) -WINOBJ0 += $(WINQT4OBJ) -VARDATND += rip.xpm +WINSRC += $(WINQTSRC) +WINOBJ0 += $(WINQTOBJ) +VARDATND0 = nhtiles.bmp rip.xpm nhsplash.xpm MOC = moc # XXX if /Developer/qt exists and QTDIR not set, use that @@ -131,6 +157,8 @@ endif # WANT_WIN_QT # prevent duplicate tile.o in WINOBJ WINOBJ = $(sort $(WINOBJ0)) +# also prevent duplicate data files if both X11 and Qt are being supported +VARDATND+= $(sort $(VARDATND0)) ifdef WANT_SHARE_INSTALL # if $GAMEUID is root, we install into roughly proper Mac locations, otherwise diff --git a/sys/unix/hints/macosx10.14 b/sys/unix/hints/macosx10.14 index e43b5f19d..79454a7ae 100644 --- a/sys/unix/hints/macosx10.14 +++ b/sys/unix/hints/macosx10.14 @@ -1,5 +1,5 @@ # -# NetHack 3.6 macosx10.14 $NHDT-Date: 1573841535 2019/11/15 18:12:15 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.60 $ +# NetHack 3.7 macosx10.14 $NHDT-Date: 1596498422 2020/08/03 23:47:02 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.64 $ # Copyright (c) Kenneth Lorber, Kensington, Maryland, 2015. # NetHack may be freely redistributed. See license for details. # diff --git a/sys/unix/hints/macosx10.5 b/sys/unix/hints/macosx10.5 index 3cbe335be..b4a5def41 100644 --- a/sys/unix/hints/macosx10.5 +++ b/sys/unix/hints/macosx10.5 @@ -1,5 +1,5 @@ # -# NetHack 3.6 macosx10.5 $NHDT-Date: 1566346606 2019/08/21 00:16:46 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.32 $ +# NetHack 3.7 macosx10.5 $NHDT-Date: 1596498424 2020/08/03 23:47:04 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.34 $ # Copyright (c) Kenneth Lorber, Kensington, Maryland, 2009. # NetHack may be freely redistributed. See license for details. # diff --git a/sys/unix/hints/macosx10.7 b/sys/unix/hints/macosx10.7 index 4937c64dc..e307e0ec8 100644 --- a/sys/unix/hints/macosx10.7 +++ b/sys/unix/hints/macosx10.7 @@ -1,5 +1,5 @@ # -# NetHack 3.6 macosx10.7 $NHDT-Date: 1566346606 2019/08/21 00:16:46 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.36 $ +# NetHack 3.7 macosx10.7 $NHDT-Date: 1596498424 2020/08/03 23:47:04 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.38 $ # Copyright (c) Kenneth Lorber, Kensington, Maryland, 2009. # NetHack may be freely redistributed. See license for details. # diff --git a/sys/unix/hints/macosx10.8 b/sys/unix/hints/macosx10.8 index a6e9c4d3c..0961bb198 100644 --- a/sys/unix/hints/macosx10.8 +++ b/sys/unix/hints/macosx10.8 @@ -1,5 +1,5 @@ # -# NetHack 3.6 macosx10.8 $NHDT-Date: 1566346607 2019/08/21 00:16:47 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.38 $ +# NetHack 3.7 macosx10.8 $NHDT-Date: 1596498425 2020/08/03 23:47:05 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.40 $ # Copyright (c) Kenneth Lorber, Kensington, Maryland, 2009. # NetHack may be freely redistributed. See license for details. # diff --git a/sys/unix/hints/solaris b/sys/unix/hints/solaris index 2140330dd..9d02d4bd3 100644 --- a/sys/unix/hints/solaris +++ b/sys/unix/hints/solaris @@ -1,5 +1,5 @@ # -# NetHack 3.6 unix $NHDT-Date: 1554411633 2019/04/04 21:00:33 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.0 $ +# NetHack 3.7 unix $NHDT-Date: 1596498426 2020/08/03 23:47:06 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.0 $ # Copyright (c) Kevin Smolkowski "Snivik", Elgin Oregon 2019. # NetHack may be freely redistributed. See license for details. # diff --git a/sys/unix/hints/solaris-playground b/sys/unix/hints/solaris-playground index 5e51df6f2..b44bccf27 100644 --- a/sys/unix/hints/solaris-playground +++ b/sys/unix/hints/solaris-playground @@ -1,5 +1,5 @@ # -# NetHack 3.6 unix $NHDT-Date: 1554411633 2019/04/04 21:00:33 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.0 $ +# NetHack 3.7 unix $NHDT-Date: 1596498427 2020/08/03 23:47:07 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.0 $ # Copyright (c) Kevin Smolkowski "Snivik", Elgin Oregon 2019. # NetHack may be freely redistributed. See license for details. # diff --git a/sys/unix/hints/unix b/sys/unix/hints/unix index bd2ef8684..b761757ea 100644 --- a/sys/unix/hints/unix +++ b/sys/unix/hints/unix @@ -1,5 +1,5 @@ # -# NetHack 3.6 unix $NHDT-Date: 1432512813 2015/05/25 00:13:33 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ +# NetHack 3.7 unix $NHDT-Date: 1596498428 2020/08/03 23:47:08 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.14 $ # Copyright (c) Kenneth Lorber, Kensington, Maryland, 2007. # NetHack may be freely redistributed. See license for details. # diff --git a/sys/unix/mkmkfile.sh b/sys/unix/mkmkfile.sh index 4c003d639..90e134657 100755 --- a/sys/unix/mkmkfile.sh +++ b/sys/unix/mkmkfile.sh @@ -1,5 +1,5 @@ #!/bin/sh -# NetHack 3.6 mkmkfile.sh $NHDT-Date: 1432512788 2015/05/25 00:13:08 $ $NHDT-Branch: master $:$NHDT-Revision: 1.13 $ +# NetHack 3.7 mkmkfile.sh $NHDT-Date: 1597332770 2020/08/13 15:32:50 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.15 $ # Copyright (c) Kenneth Lorber, Kensington, Maryland, 2007. # NetHack may be freely redistributed. See license for details. @@ -23,7 +23,8 @@ echo "### Start $5 PRE" >> $3 echo "###" >> $3 awk '/^#-PRE/,/^#-POST/{ \ if(index($0, "#-PRE") == 1) print "# (new segment at source line",NR,")"; \ - if(index($0, "#-P") != 1) print}' $4 >> $3 + if(index($0, "#-INCLUDE") == 1) system("cat hints/include/"$2); \ + else if(index($0, "#-P") != 1) print}' $4 >> $3 echo "### End $5 PRE" >> $3 echo "" >> $3 @@ -39,5 +40,6 @@ echo "### Start $5 POST" >> $3 echo "###" >> $3 awk '/^#-POST/,/^#-PRE/{ \ if(index($0, "#-POST") == 1) print "# (new segment at source line",NR,")"; \ - if(index($0, "#-P") != 1) print}' $4 >> $3 + if(index($0, "#-INCLUDE") == 1) system("cat hints/include/"$2); \ + else if(index($0, "#-P") != 1) print}' $4 >> $3 echo "### End $5 POST" >> $3 diff --git a/sys/unix/nethack.sh b/sys/unix/nethack.sh index 2c2b62cdf..9ce743494 100755 --- a/sys/unix/nethack.sh +++ b/sys/unix/nethack.sh @@ -1,5 +1,5 @@ #!/bin/sh -# NetHack 3.6 nethack.sh $NHDT-Date: 1552425075 2019/03/12 21:11:15 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.20 $ +# NetHack 3.7 nethack.sh $NHDT-Date: 1596498294 2020/08/03 23:44:54 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.21 $ # Copyright (c) 2015 by Kenneth Lorber, Kensington, Maryland # NetHack may be freely redistributed. See license for details. diff --git a/sys/unix/setup.sh b/sys/unix/setup.sh index 043bf90d4..69595fd00 100755 --- a/sys/unix/setup.sh +++ b/sys/unix/setup.sh @@ -1,5 +1,5 @@ #!/bin/sh -# NetHack 3.6 setup.sh $NHDT-Date: 1432512789 2015/05/25 00:13:09 $ $NHDT-Branch: master $:$NHDT-Revision: 1.14 $ +# NetHack 3.7 setup.sh $NHDT-Date: 1596498296 2020/08/03 23:44:56 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.17 $ # Copyright (c) Kenneth Lorber, Kensington, Maryland, 2007. # NetHack may be freely redistributed. See license for details. # diff --git a/sys/unix/sysconf b/sys/unix/sysconf index 71e786f43..c62852522 100644 --- a/sys/unix/sysconf +++ b/sys/unix/sysconf @@ -1,4 +1,4 @@ -# NetHack 3.6 sysconf $NHDT-Date: 1589575728 2020/05/15 20:48:48 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.38 $ +# NetHack 3.7 sysconf $NHDT-Date: 1596498296 2020/08/03 23:44:56 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.39 $ # Copyright (c) 2015 by Kenneth Lorber, Kensington, Maryland # NetHack may be freely redistributed. See license for details. # diff --git a/sys/unix/unixmain.c b/sys/unix/unixmain.c index 59f8d9edf..c6fea0d3b 100644 --- a/sys/unix/unixmain.c +++ b/sys/unix/unixmain.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 unixmain.c $NHDT-Date: 1589326677 2020/05/12 23:37:57 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.86 $ */ +/* NetHack 3.7 unixmain.c $NHDT-Date: 1605493691 2020/11/16 02:28:11 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.90 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2011. */ /* NetHack may be freely redistributed. See license for details. */ @@ -647,11 +647,11 @@ char *name; boolean check_user_string(optstr) -char *optstr; +const char *optstr; { struct passwd *pw; int pwlen; - char *eop, *w; + const char *eop, *w; char *pwname = 0; if (optstr[0] == '*') @@ -663,7 +663,7 @@ char *optstr; if (!pwname || !*pwname) return FALSE; pwlen = (int) strlen(pwname); - eop = eos(optstr); + eop = eos((char *) optstr); /* temporarily cast away 'const' */ w = optstr; while (w + pwlen <= eop) { if (!*w) diff --git a/sys/unix/unixres.c b/sys/unix/unixres.c index cd0954a1f..f44cd2cc5 100644 --- a/sys/unix/unixres.c +++ b/sys/unix/unixres.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 unixres.c $NHDT-Date: 1432512788 2015/05/25 00:13:08 $ $NHDT-Branch: master $:$NHDT-Revision: 1.12 $ */ +/* NetHack 3.7 unixres.c $NHDT-Date: 1596498298 2020/08/03 23:44:58 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.14 $ */ /* Copyright (c) Slash'EM development team, 2001. */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/sys/unix/unixunix.c b/sys/unix/unixunix.c index 546c9a185..77d3527db 100644 --- a/sys/unix/unixunix.c +++ b/sys/unix/unixunix.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 unixunix.c $NHDT-Date: 1432512788 2015/05/25 00:13:08 $ $NHDT-Branch: master $:$NHDT-Revision: 1.22 $ */ +/* NetHack 3.7 unixunix.c $NHDT-Date: 1605493693 2020/11/16 02:28:13 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.32 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Kenneth Lorber, Kensington, Maryland, 2015. */ /* NetHack may be freely redistributed. See license for details. */ @@ -271,9 +271,8 @@ dosh() #ifdef SYSCF if (!sysopt.shellers || !sysopt.shellers[0] || !check_user_string(sysopt.shellers)) { - /* FIXME: should no longer assume a particular command keystroke, - and perhaps ought to say "unavailable" rather than "unknown" */ - Norep("Unknown command '!'."); + /* FIXME: should no longer assume a particular command keystroke */ + Norep("Unavailable command '!'."); return 0; } #endif diff --git a/sys/vms/Makefile.dat b/sys/vms/Makefile.dat index 11e7e41c6..efe363297 100644 --- a/sys/vms/Makefile.dat +++ b/sys/vms/Makefile.dat @@ -1,5 +1,5 @@ # NetHack Makefile (VMS) - data files: special levels and other data. -# NetHack 3.6 Makefile.dat $NHDT-Date: 1542388601 2018/11/16 17:16:41 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.10 $ +# NetHack 3.7 Makefile.dat $NHDT-Date: 1596498300 2020/08/03 23:45:00 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.12 $ # Copyright (c) 2015 by Mike Stephenson # NetHack may be freely redistributed. See license for details. diff --git a/sys/vms/Makefile.doc b/sys/vms/Makefile.doc index 624f5ea0a..d728620d4 100644 --- a/sys/vms/Makefile.doc +++ b/sys/vms/Makefile.doc @@ -1,5 +1,5 @@ # NetHack Makefile (VMS) - for the [Unix] documentation. -# NetHack 3.6 Makefile.doc $NHDT-Date: 1524689428 2018/04/25 20:50:28 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.9 $ +# NetHack 3.7 Makefile.doc $NHDT-Date: 1596498301 2020/08/03 23:45:01 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.10 $ # Copyright (c) 2011 by Robert Patrick Rankin # NetHack may be freely redistributed. See license for details. diff --git a/sys/vms/Makefile.src b/sys/vms/Makefile.src index 7fb33e2b7..fa561d17e 100644 --- a/sys/vms/Makefile.src +++ b/sys/vms/Makefile.src @@ -1,5 +1,5 @@ # NetHack Makefile (VMS) - for building nethack itself. -# NetHack 3.6 Makefile.src $NHDT-Date: 1594155889 2020/07/07 21:04:49 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.50 $ +# NetHack 3.7 Makefile.src $NHDT-Date: 1596498302 2020/08/03 23:45:02 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.52 $ # Copyright (c) 2011 by Robert Patrick Rankin # NetHack may be freely redistributed. See license for details. @@ -180,7 +180,7 @@ HACKINCL = align.h artifact.h artilist.h attrib.h color.h \ monattk.h mondata.h monflag.h monst.h monsym.h obj.h objclass.h \ patchlevel.h pcconf.h permonst.h prop.h rect.h \ region.h rm.h sp_lev.h spell.h sys.h system.h tcap.h timeout.h \ - tradstdc.h trampoli.h trap.h unixconf.h vision.h \ + tradstdc.h trap.h unixconf.h vision.h \ vmsconf.h wintty.h winX.h winprocs.h wintype.h you.h youprop.h #HSOURCES = $(HACKINCL) date.h onames.h pm.h vis_tab.h\ @@ -215,7 +215,7 @@ HOBJ = $(FIRSTOBJ) $(SYSOBJ) $(WINOBJ) $(RANDOBJ) \ LUAOBJ = nhlua.o,nhlsel.o -# 5.4.0 adds header files ljumptab.h and lopnames.h and removes lbitlib.c +# 5.4.0 added header files ljumptab.h and lopnames.h and removes lbitlib.c # so comment top two and uncomment bottom two for the previous version (5.3.5) LUA535SRCFILES = LUA535OBJFILES = @@ -403,7 +403,7 @@ $(HACK_H) : $(INC)hack.h $(CONFIG_H) $(INC)align.h \ $(INC)onames.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)trampoli.h $(INC)sys.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.top b/sys/vms/Makefile.top index 2bdb2c951..c12946959 100644 --- a/sys/vms/Makefile.top +++ b/sys/vms/Makefile.top @@ -1,5 +1,5 @@ # NetHack Makefile (VMS) - top level for making & installing everything. -# NetHack 3.6 Makefile.top $NHDT-Date: 1524689428 2018/04/25 20:50:28 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.10 $ +# NetHack 3.7 Makefile.top $NHDT-Date: 1596498303 2020/08/03 23:45:03 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.11 $ # Copyright (c) 2011 by Robert Patrick Rankin # NetHack may be freely redistributed. See license for details. diff --git a/sys/vms/Makefile.utl b/sys/vms/Makefile.utl index 713a37995..651223aa1 100644 --- a/sys/vms/Makefile.utl +++ b/sys/vms/Makefile.utl @@ -1,5 +1,5 @@ # NetHack Makefile (VMS) - for utility programs. -# NetHack 3.6 Makefile.utl $NHDT-Date: 1542388602 2018/11/16 17:16:42 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.16 $ +# NetHack 3.7 Makefile.utl $NHDT-Date: 1596498303 2020/08/03 23:45:03 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.19 $ # Copyright (c) 2011 by Robert Patrick Rankin # NetHack may be freely redistributed. See license for details. diff --git a/sys/vms/lev_lex.h b/sys/vms/lev_lex.h index 31a923f42..2198df851 100644 --- a/sys/vms/lev_lex.h +++ b/sys/vms/lev_lex.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 lev_lex.h $NHDT-Date: 1432512790 2015/05/25 00:13:10 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ +/* NetHack 3.7 lev_lex.h $NHDT-Date: 1596498300 2020/08/03 23:45:00 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.9 $ */ /* "vms/lev_lex.h" copied into "util/stdio.h" for use in *_lex.c only! * This is an awful kludge to allow util/*_lex.c made by SunOS's `lex' * to be compiled as is. (It isn't needed with `flex' or VMS POSIX diff --git a/sys/vms/oldcrtl.c b/sys/vms/oldcrtl.c index 40a30127b..43bbd815a 100644 --- a/sys/vms/oldcrtl.c +++ b/sys/vms/oldcrtl.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 oldcrtl.c $NHDT-Date: 1432512789 2015/05/25 00:13:09 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ +/* NetHack 3.7 oldcrtl.c $NHDT-Date: 1596498304 2020/08/03 23:45:04 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.9 $ */ /* Pat Rankin May'90 */ /* VMS NetHack support, not needed for vms 4.6,4.7,5.x,or later */ diff --git a/sys/vms/sysconf b/sys/vms/sysconf index b4ffd357b..16ce0c684 100644 --- a/sys/vms/sysconf +++ b/sys/vms/sysconf @@ -1,4 +1,4 @@ -# NetHack 3.6 sysconf $NHDT-Date: 1524689429 2018/04/25 20:50:29 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.2 $ +# NetHack 3.7 sysconf $NHDT-Date: 1596498305 2020/08/03 23:45:05 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.4 $ # Copyright (c) 2015 by Robert Patrick Rankin # NetHack may be freely redistributed. See license for details. # diff --git a/sys/vms/vmsfiles.c b/sys/vms/vmsfiles.c index 89e6aff4a..02602d147 100644 --- a/sys/vms/vmsfiles.c +++ b/sys/vms/vmsfiles.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 vmsfiles.c $NHDT-Date: 1449801740 2015/12/11 02:42:20 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.10 $ */ +/* NetHack 3.7 vmsfiles.c $NHDT-Date: 1596498306 2020/08/03 23:45:06 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.12 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2007. */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/sys/vms/vmsmail.c b/sys/vms/vmsmail.c index 989775687..4e2eaf06f 100644 --- a/sys/vms/vmsmail.c +++ b/sys/vms/vmsmail.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 vmsmail.c $NHDT-Date: 1449801741 2015/12/11 02:42:21 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.10 $ */ +/* NetHack 3.7 vmsmail.c $NHDT-Date: 1596498307 2020/08/03 23:45:07 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.11 $ */ /* Copyright (c) Robert Patrick Rankin, 1991. */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/sys/vms/vmsmain.c b/sys/vms/vmsmain.c index f4631557c..18657be9f 100644 --- a/sys/vms/vmsmain.c +++ b/sys/vms/vmsmain.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 vmsmain.c $NHDT-Date: 1449801742 2015/12/11 02:42:22 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.32 $ */ +/* NetHack 3.7 vmsmain.c $NHDT-Date: 1596498307 2020/08/03 23:45:07 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.45 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2011. */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/sys/vms/vmsmisc.c b/sys/vms/vmsmisc.c index 8cb266cc7..6da4ed3f5 100644 --- a/sys/vms/vmsmisc.c +++ b/sys/vms/vmsmisc.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 vmsmisc.c $NHDT-Date: 1524689429 2018/04/25 20:50:29 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.11 $ */ +/* NetHack 3.7 vmsmisc.c $NHDT-Date: 1596498308 2020/08/03 23:45:08 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.12 $ */ /* Copyright (c) 2011 by Robert Patrick Rankin */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/sys/vms/vmstty.c b/sys/vms/vmstty.c index a04928839..e26e7db8d 100644 --- a/sys/vms/vmstty.c +++ b/sys/vms/vmstty.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 vmstty.c $NHDT-Date: 1449801743 2015/12/11 02:42:23 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.17 $ */ +/* NetHack 3.7 vmstty.c $NHDT-Date: 1596498309 2020/08/03 23:45:09 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.21 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2011. */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/sys/vms/vmsunix.c b/sys/vms/vmsunix.c index 2eec83b01..66afa88a2 100644 --- a/sys/vms/vmsunix.c +++ b/sys/vms/vmsunix.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 vmsunix.c $NHDT-Date: 1449801743 2015/12/11 02:42:23 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.15 $ */ +/* NetHack 3.7 vmsunix.c $NHDT-Date: 1605493693 2020/11/16 02:28:13 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.24 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2011. */ /* NetHack may be freely redistributed. See license for details. */ @@ -54,7 +54,7 @@ int fd; if (fstat(fd, &buf)) return 0; /* cannot get status */ #ifndef INSURANCE - if (buf.st_size != sizeof(int)) + if (buf.st_size != sizeof (int)) return 0; /* not an xlock file */ #endif (void) time(&date); @@ -62,7 +62,7 @@ int fd; int lockedpid; /* should be the same size as hackpid */ unsigned long status, dummy, code = JPI$_PID; - if (read(fd, (genericptr_t) &lockedpid, sizeof(lockedpid)) + if (read(fd, (genericptr_t) &lockedpid, sizeof lockedpid) != sizeof(lockedpid)) /* strange ... */ return 0; status = lib$getjpi(&code, &lockedpid, 0, &dummy); @@ -138,7 +138,7 @@ getlock() error(g.locknum ? "Too many hacks running now." : "There is a game in progress under your name."); -gotlock: + gotlock: fd = creat(g.lock, FCMASK); unlock_file(HLOCK); if (fd == -1) { @@ -373,6 +373,45 @@ privon() } #endif /* CHDIR || SHELL || SECURE */ +#ifdef SYSCF +boolean +check_user_string(userlist) +const char *userlist; +{ + char usrnambuf[BUFSZ]; + const char *sptr, *p, *q; + int ln; + + if (!strcmp(userlist, "*")) + return TRUE; + + /* FIXME: ought to use $getjpi or $getuai to retrieve user name here... */ + Strcpy(usrnambuf, nh_getenv("USER")); + ln = (int) strlen(usrnambuf); + if (!ln) + return FALSE; + + while ((sptr = strstri(userlist, usrnambuf)) != 0) { + /* check for full word: start of list or following a space or comma */ + if ((sptr == userlist || sptr[-1] == ' ' || sptr[-1] == ',') + /* and also preceding a space or comma or at end of list */ + && (sptr[ln] == ' ' || sptr[ln] == ',' || sptr[ln] == '\0')) + return TRUE; + /* doesn't match full word, but maybe we got a false hit when + looking for "jane" in the list "janedoe jane" so keep going */ + p = index(sptr + 1, ' '); + q = index(sptr + 1, ','); + if (!p || (q && q < p)) + p = q; + if (!p) + break; + userlist = p + 1; + } + + return FALSE; +} +#endif /* SYSCF */ + #if defined(SHELL) || defined(SUSPEND) static void hack_escape(screen_manip, msg_str) @@ -406,6 +445,14 @@ unsigned long dosh_pid = 0, /* this should cover any interactive escape */ int dosh() { +#ifdef SYSCF + if (!sysopt.shellers || !sysopt.shellers[0] + || !check_user_string(sysopt.shellers)) { + /* FIXME: should no longer assume a particular command keystroke */ + Norep("Unavailable command '!'."); + return 0; + } +#endif return vms_doshell("", TRUE); /* call for interactive child process */ } @@ -617,7 +664,7 @@ int how; /* 1: exit after traceback; 2: stay in debugger */ in a last-gasp environment so apply the KISS principle...) */ DBGCMD("set Module/Calls ; show Calls 18"), /* epilogue; "exit" ends the sequence it's part of, but it doesn't - seem able to cause program termination end when used separately; + seem able to cause program termination when used separately; instead of relying on it, we'll redirect debugger input to come from the null device so that it'll get an end-of-input condition when it tries to get a command from the user */ @@ -844,7 +891,7 @@ const unsigned long lib$initialize[] = { (unsigned long) (void *) vmsexeini }; #endif /* We also need to link against a linker options file containing: sys$library:starlet.olb/Include=(lib$initialize) -psect_attr=lib$initialize, Con,Usr,noPic,Rel,Gbl,noShr,noExe,Rd,noWrt,Long +psect_attr=lib$initialize, Con,Rel,Gbl,noShr,noExe,Rd,noWrt */ #endif /* C_LIB$INITIALIZE */ /* End of debugger hackery. */ diff --git a/sys/winnt/.nethackrc.template b/sys/winnt/.nethackrc.template index b2bacbd7f..053e48358 100644 --- a/sys/winnt/.nethackrc.template +++ b/sys/winnt/.nethackrc.template @@ -1,4 +1,4 @@ -# NetHack 3.6 defaults.nh $NHDT-Date: 1524689357 2018/04/25 20:49:17 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.32 $ +# NetHack 3.7 defaults.nh $NHDT-Date: 1524689357 2018/04/25 20:49:17 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.32 $ # Copyright (c) 2006 by Michael Allison # NetHack may be freely redistributed. See license for details. diff --git a/sys/winnt/Install.nt b/sys/winnt/Install.nt index 22c9f4484..a5ebaca2b 100644 --- a/sys/winnt/Install.nt +++ b/sys/winnt/Install.nt @@ -7,7 +7,7 @@ ============================================================== Last revision: $NHDT-Date: 1594155895 2020/07/07 21:04:55 $ -Credit for the porting of NetHack to the Win32 Console Subsystem goes to +Credit for the porting of NetHack to the Win32 Console Subsystem goes to the NT Porting Team started by Michael Allison. Credit for the Win32 Graphical version of NetHack (aka "NetHack for @@ -18,7 +18,7 @@ Alex Kompel, Dion Nicolaas, Yitzhak Sapir, Derek S. Ray, Michael Allison, Pasi Kallinen, Bart House, and Janet Walz contributed to the maintainance of the tty and graphical windows versions of NetHack 3.7.0. -You can build a TTY version of NetHack and a Windows Graphical +You can build a TTY version of NetHack and a Windows Graphical version. You can use one of the following build environments: o A copy of Microsoft Visual Studio 2017 Community Edition or @@ -26,9 +26,9 @@ version. You can use one of the following build environments: OR - o (Untested for 3.7) A copy of MinGW. MinGW is a collection of header - files and import libraries with which native Windows32 programs - can be built; the MinGW distribution contains the GNU Compiler + o (Untested for 3.7) A copy of MinGW. MinGW is a collection of header + files and import libraries with which native Windows32 programs + can be built; the MinGW distribution contains the GNU Compiler Collection. You can download MinGW at http://www.mingw.org/ Earlier versions of MinGW will not allow you to build the Windows @@ -38,7 +38,7 @@ version. You can use one of the following build environments: | Directories for a Win32 NetHack build | \---------------------------------------------/ - + (NetHack-top) | +-----+-----+------+------+-----+----------+---------~---------+ @@ -47,32 +47,29 @@ version. You can use one of the following build environments: | | | +----+ +------+ +-----------+ | | | | | | - share winnt tty win32 Lua-5.4.0 pdcurses + share winnt tty win32 Lua-5.4.2 pdcurses | - vs2017 + vs - /--------------------------------------------------------\ -| Building And Running Using Visual Studio 2017 | +| Building And Running Using Visual Studio 2017 or 2019 | \--------------------------------------------------------/ -If you are NOT using Visual Studio 2017 IDE, or you prefer to build +Before proceeding, please obtain the lua-5.4.2 sources and copy them to +the new directory lib\lua-5.4.2\src. This source can be obtain either from +http://www.lua.org/ftp/lua-5.4.2.tar.gz or from the git hub mirror +https://github.com/lua/lua.git using the tag 'v5.4.2'. The build expects +to find lua files such as 'lua.h' at 'lib\lua-5.4.2\src\lua.h'. + +If you are NOT using Visual Studio 2017 or 2019 IDE, or you prefer to build using a Make utility and a Makefile proceed to "Building Using Make". -When using either Visual Studio 2017, you simply need to load the +When using either Visual Studio 2017 or 2019, you simply need to load the solution file within the IDE, build the solution and run the version of NetHack you wish to run. -The Visual Studio 2017 NetHack solution file can be found here: - win\win32\vs2017\NetHack.sln - -You can use that same win\win32\vs2017\NetHack.sln with Visual Studio 2019, -but you may have to retarget the projects: - Windows SDK Version: 10.0.17763.0 [ There have been some reports of - difficulties if you instead choose - "10.0 (latest installed version)" ] - Platform Toolset: Upgrade to v142 - +The Visual Studio NetHack solution file can be found here: + win\win32\vs\NetHack.sln Before executing the steps to build listed in the next paragraph, decide if you want to include optional curses window-port. See @@ -89,23 +86,23 @@ You can also build all the projects for all platforms and configurations using a "build.bat" batch file found in the same directory as the solution. Open a developer command prompt for the version of Visual Studio you are -using. Change to the directory win\win32\vs2017 and run "build.bat". +using. Change to the directory win\win32\vs and run "build.bat". * Optional curses window-port support * Since 3.6.2, the community patch for a window-port that uses curses has been -incorporated into the NetHack source code tree. That window-port, which +incorporated into the NetHack source code tree. That window-port, which evolved from work originally done by Karl Garrison, has been used in several NetHack variants and on nethack.alt.org and on www.hardfought.org/nethack/. If you want to include the curses window-port support in your Visual Studio build, you will have to first obtain the PDCurses sources from https://github.com/wmcbrine/PDCurses -and have them available prior to building NetHack. There are two ways to -enable curses window-port support during the VS build: Either set the -environment variable PDCURSES to a folder containing a PDCurses +and have them available prior to building NetHack. There are two ways to +enable curses window-port support during the VS build: Either set the +environment variable PDCURSES to a folder containing a PDCurses repository/source-tree - OR + OR Place the PDCurses folder alongside the NetHack source repository prior to proceeding with steps 1 through 5 above. @@ -117,8 +114,8 @@ to proceeding with steps 1 through 5 above. -------------------------------------------------------------------------- -- Beginning of prerequisite step -- -The first step in building either version of NetHack via Makefile is to -execute sys\winnt\nhsetup.bat to move some files to their required locations. +The first step in building either version of NetHack via Makefile is to +execute sys\winnt\nhsetup.bat to move some files to their required locations. From the command prompt: cd sys\winnt @@ -141,25 +138,25 @@ command line using the Makefile approach: NetHackW. The executable for Console NetHack will be named NetHack.exe. The -executable for Graphical NetHack will be named NetHackW.exe. The +executable for Graphical NetHack will be named NetHackW.exe. The Makefile configuration will build both; NetHackW.exe and NetHack.exe will be able to use the same datafiles, save files and bones files. -Since the last official release of NetHack, compilers and computer +Since the last official release of NetHack, compilers and computer architectures have evolved and you can now choose whether to build a 32-bit x86 version, or a 64-bit x64 version. The default Makefile -is set up for a 32-bit x86 version, but that's only because it will +is set up for a 32-bit x86 version, but that's only because it will run on the most number of existing Windows environments. NetHack's save files and bones files in the 3.7.0 release have not yet -evolved enough to allow them to interchange between the 32-bit version +evolved enough to allow them to interchange between the 32-bit version and the 64-bit version (or between different platforms). Hopefully that will change in an upcoming release. I. Dispelling the Myths: Compiling NetHack for Windows is not as easy as it sounds, nor as hard - as it looks, however it will behoove you to read this entire section + as it looks, however it will behoove you to read this entire section through before beginning the task. We have provided a Makefile for each of the following compilers: @@ -168,10 +165,10 @@ I. Dispelling the Myths: The Community Editions are fine and available at no cost o MinGW 2.0 (with GCC 3.2) - The Microsoft Visual Studio makefile was created for use - with MS NMAKE which is provided with the Microsoft compiler. + The Microsoft Visual Studio makefile was created for use + with MS NMAKE which is provided with the Microsoft compiler. The supplied Makefile may work with earlier versions of the Microsoft - compiler, but that has not been tested. + compiler, but that has not been tested. The GCC Makefile was created for use with GNU Make version 3.79.1, which comes with the MinGW package. @@ -185,41 +182,41 @@ II. To compile your copy of NetHack on a Windows machine: Setting Up -1. It almost goes without saying that you should make sure that your +1. It almost goes without saying that you should make sure that your tools are set up and running correctly. That includes ensuring that all the necessary environment variables for the compiler environment - are set correctly. + are set correctly. - Change your current directory to the src subfolder of the nethack + Change your current directory to the src subfolder of the nethack source tree. cd src - GCC + GCC - For the GCC Makefile, add \bin to your path, where + For the GCC Makefile, add \bin to your path, where is your MinGW root directory.). - Change your current directory to src subfolder of the nethack + Change your current directory to src subfolder of the nethack source tree. cd src 2. Since 3.6.2, the community patch for an optional curses window-port - has been incorporated into the NetHack source code tree. That + has been incorporated into the NetHack source code tree. That window-port, which evolved from work originally done by Karl Garrison, - has been used in several NetHack variants and on nethack.alt.org and - on www.hardfought.org/nethack/. The optional curses window-port is + has been used in several NetHack variants and on nethack.alt.org and + on www.hardfought.org/nethack/. The optional curses window-port is available for Windows, Mac OS X, and Unix (and also DOS). If you want to include the optional curses window-port support in your - command line Makefile build, you will have to first obtain the + command line Makefile build, you will have to first obtain the PDCurses sources from https://github.com/wmcbrine/PDCurses and have that source code tree available prior to building NetHack. - Edit your Makefile and in Question 4 of the four decisions you can + Edit your Makefile and in Question 4 of the four decisions you can make in there, uncomment these two lines: ADD_CURSES=Y PDCURSES_TOP=..\..\pdcurses - Adjust the PDCURSES_TOP macro so that it points to the correct + Adjust the PDCURSES_TOP macro so that it points to the correct location for the top of the PDCurses source tree if it differs from the path shown. @@ -228,8 +225,8 @@ Setting Up subdirectories dat, doc, include, src, sys\share, sys\winnt, win\tty, util. - If you are including the optional Curses window port into your - build,then you will need the top of the PDCurses sources in a + If you are including the optional Curses window port into your + build,then you will need the top of the PDCurses sources in a folder parallel to the top of the NetHack folder (or you will need to change the value of the PDCURSES_TOP macro in the Makefile to specify the appropriate location. @@ -257,7 +254,7 @@ Compiling 5. Now that everything is set up... For the Visual Studio compiler, as mentioned above, you should now be - at the command prompt to carry out the build and your current + at the command prompt to carry out the build and your current directory should be the src subdirectory in the NetHack source tree. In the src subdirectory, issue this command: @@ -273,7 +270,7 @@ Compiling particular machine of course, but you should be able to go for lunch and return to find everything finished. The less memory, and slower your machine, the longer the lunch you may take. :-) - + In any case, it is likely that the command prompt window where you are doing the compiling will be occupied for a while. If all goes well, you will get an NetHack executable. @@ -284,7 +281,7 @@ Notes: your current directory to src and issue the appropriate command for your compiler: - For Microsoft compiler: + For Microsoft compiler: nmake For GCC: @@ -299,19 +296,19 @@ Notes: have to delete dgn_flex.c, dgn_yacc.c, lev_flex.c, and lev_yacc.c from the util directory to ensure that they are remade. -2. Depending on the build and compiler and tools used above, the +2. Depending on the build and compiler and tools used above, the executable produced by the TTY build is either: - - a 32-bit (x86), flat-address space, non-overlayed .exe file, + - a 32-bit (x86), flat-address space, non-overlayed .exe file, which should run on any recent Win32 environment. or - - a 64-bit (x64) .exe file, + - a 64-bit (x64) .exe file, which should run on any 64-bit Windows O/S. Note that saved games are NOT compatible between the 32-bit and the 64-bit versions at this time. NetHack.exe is the tty version. NetHackW.exe is the graphical version. -Play NetHack. +Play NetHack. PROBLEMS diff --git a/sys/winnt/Makefile.gcc b/sys/winnt/Makefile.gcc index 8806db9f3..45c790a60 100644 --- a/sys/winnt/Makefile.gcc +++ b/sys/winnt/Makefile.gcc @@ -1,4 +1,4 @@ -# NetHack 3.7 Makefile.gcc $NHDT-Date: 1594155895 2020/07/07 21:04:55 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.109 $ +# NetHack 3.7 Makefile.gcc $NHDT-Date: 1597761345 2020/08/18 14:35:45 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.114 $ # Copyright (c) 2010 by Michael Allison # NetHack may be freely redistributed. See license for details. # @@ -34,7 +34,7 @@ # # Build Options Decisions # -# There are currently 4 decisions that you can choose to make. +# There are currently 4 decisions that you can choose to make. # None of the 4 decisions are absolutely required because defaults are in place: # 1. Where do you want your build to end up? # 2. Do you want debug information in the executable? @@ -92,11 +92,11 @@ TARGET_CPU=x86 # # 4. Uncomment these and set them appropriately if you want to # include curses port support alongside TTY support in your -# NetHack.exe binary. +# NetHack.exe binary. # -# You'll have to set PDCURSES_H to the correct location of the +# You'll have to set PDCURSES_H to the correct location of the # PDCurses header (.h) files and PDCURSES_C to the location -# of your PDCurses C files which must already be resident on +# of your PDCurses C files which must already be resident on # your machine. # # ADD_CURSES=Y @@ -104,19 +104,19 @@ TARGET_CPU=x86 #4b Qt # -#WANT_WIN_QT4 = N +#WANT_WIN_QT = N -# WANT_WIN_QT4 requires Qt 4 or Qt 5, see +# WANT_WIN_QT requires Qt 4 or Qt 5, see # https://www.qt.io/download-open-source/ # Earlier versions of Qt are not compatible with Windows # For Qt 5, use: # -#QT4_DIRECTORY = c:/Qt/Qt5.9.2/5.9.2/mingw53_32 +#QT_DIRECTORY = c:/Qt/Qt5.9.2/5.9.2/mingw53_32 #HAVE_QT5 = Y # For Qt 4, comment out the above two lines and use: # -#QT4_DIRECTORY = c:/Qt/4.8.6 +#QT_DIRECTORY = c:/Qt/4.8.6 #HAVE_QT5 = N # @@ -127,23 +127,26 @@ TARGET_CPU=x86 # #--------------------------------------------------------------- ifndef LUA_VERSION -LUAVER=5.4.0 +LUAVER=5.4.2 else LUAVER=$(LUA_VERSION) endif #--------------------------------------------------------------- # Location of LUA # -# Original source needs to be obtained from: -# http://www.lua.org/ftp/lua-5.4.0.tar.gz +# Original source needs to be obtained from: +# http://www.lua.org/ftp/lua-5.4.2.tar.gz # # This build assumes that the LUA sources are located # at the specified location. If they are actually elsewhere # you'll need to specify the correct spot below in order to # successfully build NetHack-3.7. # +ifndef ADD_LUA ADD_LUA=Y LUATOP=../lib/lua-$(LUAVER) +WANT_LUAC=Y +endif # #============================================================================== # This marks the end of the BUILD DECISIONS section. @@ -185,8 +188,9 @@ NHV=$(subst ",,$(NHV1)) # MSWSYS - mswin specific files # TTY - window port files (tty) # MSWIN - window port files (win32) -# WCURSES - window port files (curses) -# WSHR - Tile support files +# WCURSES - window port files (curses) +# WSHR - Tile support files +# QT - QT window support files INCL =../include DAT =../dat @@ -199,6 +203,7 @@ TTY =../win/tty MSWIN =../win/win32 WCURSES =../win/curses WSHR =../win/share +QT =../win/Qt # # Object directory. @@ -216,7 +221,7 @@ RANDOM = $(OBJ)/random.o BCRYPT=-lbcrypt WINPFLAG = -DTILES -DMSWIN_GRAPHICS -DWIN32CON -D_WIN32_IE=0x0400 -D_WIN32_WINNT=0x0601 -DWINVER=0x0601 -ifeq "$(WANT_WIN_QT4)" "Y" +ifeq "$(WANT_WIN_QT)" "Y" WINPFLAG += -DQT_GRAPHICS -DPIXMAPDIR='"."' endif # To store all the level files, @@ -301,13 +306,13 @@ PPMWRITERS = $(O)ppmwrite.o $(O)alloc.o $(O)panic.o # VOBJ01 = $(O)allmain.o $(O)alloc.o $(O)apply.o $(O)artifact.o -VOBJ02 = $(O)attrib.o $(O)ball.o $(O)bones.o $(O)botl.o -VOBJ03 = $(O)cmd.o $(O)dbridge.o $(O)decl.o $(O)detect.o -VOBJ04 = $(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 -VOBJ06 = $(O)dothrow.o $(O)drawing.o $(O)dungeon.o $(O)eat.o -VOBJ07 = $(O)end.o $(O)engrave.o $(O)exper.o $(O)explode.o -VOBJ08 = $(O)extralev.o $(O)files.o $(O)fountain.o $(O)hack.o +VOBJ02 = $(O)attrib.o $(O)ball.o $(O)bones.o $(O)botl.o +VOBJ03 = $(O)cmd.o $(O)dbridge.o $(O)decl.o $(O)detect.o +VOBJ04 = $(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 +VOBJ06 = $(O)dothrow.o $(O)drawing.o $(O)dungeon.o $(O)eat.o +VOBJ07 = $(O)end.o $(O)engrave.o $(O)exper.o $(O)explode.o +VOBJ08 = $(O)extralev.o $(O)files.o $(O)fountain.o $(O)hack.o VOBJ09 = $(O)hacklib.o $(O)insight.o $(O)invent.o $(O)isaac64.o VOBJ10 = $(O)light.o $(O)lock.o $(O)mail.o $(O)makemon.o VOBJ11 = $(O)mapglyph.o $(O)mdlib.o $(O)mcastu.o $(O)mhitm.o @@ -325,9 +330,9 @@ VOBJ22 = $(O)shknam.o $(O)sit.o $(O)sounds.o $(O)sp_lev.o VOBJ23 = $(O)spell.o $(O)steal.o $(O)steed.o $(O)symbols.o VOBJ24 = $(O)sys.o $(O)teleport.o $(O)timeout.o $(O)topten.o VOBJ25 = $(O)track.o $(O)trap.o $(O)u_init.o $(O)uhitm.o -VOBJ26 = $(O)vault.o $(O)vis_tab.o $(O)vision.o $(O)weapon.o -VOBJ27 = $(O)were.o $(O)wield.o $(O)windows.o $(O)wizard.o -VOBJ28 = $(O)worm.o $(O)worn.o $(O)write.o $(O)zap.o +VOBJ26 = $(O)vault.o $(O)vision.o $(O)weapon.o $(O)were.o +VOBJ27 = $(O)wield.o $(O)windows.o $(O)wizard.o $(O)worm.o +VOBJ28 = $(O)worn.o $(O)write.o $(O)zap.o ifeq "$(ADD_LUA)" "Y" LUAOBJ = $(O)nhlua.o $(O)nhlsel.o $(O)nhlobj.o @@ -348,7 +353,7 @@ CURSESOBJ= endif SOBJ = $(O)windmain.o $(O)winnt.o $(O)win10.o \ - $(O)safeproc.o $(O)nhlan.o $(SOUND) + $(O)safeproc.o $(O)nhlan.o $(SOUND) OBJS = $(VOBJ01) $(VOBJ02) $(VOBJ03) $(VOBJ04) $(VOBJ05) \ $(VOBJ06) $(VOBJ07) $(VOBJ08) $(VOBJ09) $(VOBJ10) \ @@ -366,12 +371,12 @@ GUIOBJ = $(O)mhaskyn.o $(O)mhdlg.o \ endif -ifeq "$(WANT_WIN_QT4)" "Y" - GUIOBJ += $(O)qt4bind.o $(O)qt4click.o $(O)qt4clust.o $(O)qt4delay.o \ - $(O)qt4glyph.o $(O)qt4icon.o $(O)qt4inv.o $(O)qt4key.o $(O)qt4line.o \ - $(O)qt4main.o $(O)qt4map.o $(O)qt4menu.o $(O)qt4msg.o $(O)qt4plsel.o \ - $(O)qt4rip.o $(O)qt4set.o $(O)qt4stat.o $(O)qt4str.o $(O)qt4streq.o \ - $(O)qt4svsel.o $(O)qt4win.o $(O)qt4xcmd.o $(O)qt4yndlg.o +ifeq "$(WANT_WIN_QT)" "Y" + GUIOBJ += $(O)qt_bind.o $(O)qt_click.o $(O)qt_clust.o $(O)qt_delay.o \ + $(O)qt_glyph.o $(O)qt_icon.o $(O)qt_inv.o $(O)qt_key.o $(O)qt_line.o \ + $(O)qt_main.o $(O)qt_map.o $(O)qt_menu.o $(O)qt_msg.o $(O)qt_plsel.o \ + $(O)qt_rip.o $(O)qt_set.o $(O)qt_stat.o $(O)qt_str.o $(O)qt_streq.o \ + $(O)qt_svsel.o $(O)qt_win.o $(O)qt_xcmd.o $(O)qt_yndlg.o endif ifneq "$(SKIP_NETHACKW)" "Y" @@ -382,14 +387,14 @@ GUIHDR = $(MSWIN)/mhaskyn.h $(MSWIN)/mhdlg.h $(MSWIN)/mhfont.h \ $(MSWIN)/mhtext.h $(MSWIN)/resource.h $(MSWIN)/winMS.h endif -ifeq "$(WANT_WIN_QT4)" "Y" - GUIHDR += $(QT4)/qt4bind.h $(QT4)/qt4click.h $(QT4)/qt4clust.h \ - $(QT4)/qt4delay.h $(QT4)/qt4glyph.h $(QT4)/qt4icon.h $(QT4)/qt4inv.h \ - $(QT4)/qt4kde0.h $(QT4)/qt4key.h $(QT4)/qt4line.h $(QT4)/qt4main.h \ - $(QT4)/qt4map.h $(QT4)/qt4menu.h $(QT4)/qt4msg.h $(QT4)/qt4plsel.h \ - $(QT4)/qt4rip.h $(QT4)/qt4set.h $(QT4)/qt4stat.h $(QT4)/qt4str.h \ - $(QT4)/qt4streq.h $(QT4)/qt4svsel.h $(QT4)/qt4win.h $(QT4)/qt4xcmd.h \ - $(QT4)/qt4yndlg.h +ifeq "$(WANT_WIN_QT)" "Y" + GUIHDR += $(QT)/qt_bind.h $(QT)/qt_click.h $(QT)/qt_clust.h \ + $(QT)/qt_delay.h $(QT)/qt_glyph.h $(QT)/qt_icon.h $(QT)/qt_inv.h \ + $(QT)/qt_kde0.h $(QT)/qt_key.h $(QT)/qt_line.h $(QT)/qt_main.h \ + $(QT)/qt_map.h $(QT)/qt_menu.h $(QT)/qt_msg.h $(QT)/qt_plsel.h \ + $(QT)/qt_rip.h $(QT)/qt_set.h $(QT)/qt_stat.h $(QT)/qt_str.h \ + $(QT)/qt_streq.h $(QT)/qt_svsel.h $(QT)/qt_win.h $(QT)/qt_xcmd.h \ + $(QT)/qt_yndlg.h endif COMCTRL = comctl32.lib @@ -414,18 +419,24 @@ OPTIONS_FILE = $(DAT)\options #===============-================================================= # LUA library -# Source from http://www.lua.org/ftp/lua-5.4.0.tar.gz +# Source from http://www.lua.org/ftp/lua-5.4.2.tar.gz #================================================================= ifndef LUAVER -LUAVER = 5.4.0 +LUAVER = 5.4.2 endif +ifndef LUASRC LUASRC = $(LUATOP)/src +endif LUALIB = $(O)lua-$(LUAVER).static.a LUADLL = $(O)lua-$(LUAVER).a LUAINCL = -I$(LUASRC) #LUAFLAGS = unix added -lm here? +ifeq "$(WANT_LUAC)" "Y" LUATARGETS = lua.exe luac.exe $(LUADLL) $(LUALIB) +else +LUATARGETS = lua.exe $(LUADLL) $(LUALIB) +endif LUASRCFILES = lapi.c lauxlib.c lbaselib.c lcode.c \ lcorolib.c lctype.c ldblib.c ldebug.c ldo.c \ @@ -444,7 +455,7 @@ LUAOBJFILES = $(O)lapi.o $(O)lauxlib.o $(O)lbaselib.o \ $(O)lstring.o $(O)lstrlib.o $(O)ltable.o $(O)ltablib.o \ $(O)ltm.o $(O)lundump.o $(O)lutf8lib.o $(O)lvm.o $(O)lzio.o ifeq "$(LUAVER)" "5.3.5" -# 5.4.0 adds header files ljumptab.h and lopnames.h and removes lbitlib.c +# 5.4.0 added header files ljumptab.h and lopnames.h and removes lbitlib.c # so we have to tack those on for the previous version (5.3.5) LUASRCFILES = $(LUASRCFILES) lbitlib.c LUAOBJFILES = $(LUAOBJFILES) lbitlib.o @@ -474,7 +485,7 @@ PDCLIB = $(O)pdcurses.a PDCINCL = -I$(PDCURSES_TOP) -I$(PDCSRC) -I$(PDCWINCON) else -PDCLIB = +PDCLIB = endif #========================================== @@ -499,7 +510,7 @@ HACK_H = $(INCL)/hack.h $(CONFIG_H) $(INCL)/align.h $(INCL)/context.h \ $(INCL)/timeout.h $(INCL)/trap.h $(INCL)/flag.h $(INCL)/rm.h \ $(INCL)/vision.h $(INCL)/display.h $(INCL)/engrave.h \ $(INCL)/rect.h $(INCL)/region.h $(INCL)/winprocs.h \ - $(INCL)/wintty.h $(INCL)/sys.h $(INCL)/trampoli.h + $(INCL)/wintty.h $(INCL)/sys.h DGN_FILE_H = $(INCL)/dgn_file.h SP_LEV_H = $(INCL)/sp_lev.h @@ -543,7 +554,7 @@ rc = windres link = gcc endif -ifeq "$(WANT_WIN_QT4)" "Y" +ifeq "$(WANT_WIN_QT)" "Y" link = g++ endif @@ -563,17 +574,17 @@ CFLAGSBASE = -c $(cflags) $(WINPINC) $(cdebug) $(CURSESDEF) baselibs = -lwinmm -lshell32 -lole32 -luuid conlibs = -lgdi32 $(baselibs) $(BCRYPT) guilibs = -lcomctl32 $(baselibs) $(BCRYPT) -ifeq "$(WANT_WIN_QT4)" "Y" +ifeq "$(WANT_WIN_QT)" "Y" # Might be either Qt 4 or Qt 5 ifeq "$(HAVE_QT5)" "Y" - guilibs += $(QT4_DIRECTORY)/lib/libQt5Core.a - guilibs += $(QT4_DIRECTORY)/lib/libQt5Gui.a - guilibs += $(QT4_DIRECTORY)/lib/libQt5Widgets.a - conlibs += $(QT4_DIRECTORY)/lib/libQt5Core.a + guilibs += $(QT_DIRECTORY)/lib/libQt5Core.a + guilibs += $(QT_DIRECTORY)/lib/libQt5Gui.a + guilibs += $(QT_DIRECTORY)/lib/libQt5Widgets.a + conlibs += $(QT_DIRECTORY)/lib/libQt5Core.a else - guilibs += $(QT4_DIRECTORY)/lib/libQtCore4.a - guilibs += $(QT4_DIRECTORY)/lib/libQtGui4.a - conlibs += $(QT4_DIRECTORY)/lib/libQtCore4.a + guilibs += $(QT_DIRECTORY)/lib/libQtCore4.a + guilibs += $(QT_DIRECTORY)/lib/libQtGui4.a + conlibs += $(QT_DIRECTORY)/lib/libQtCore4.a endif endif @@ -581,7 +592,7 @@ endif # Extra files needed for some ports #========================================== EXTRA_FILES = -ifeq "$(WANT_WIN_QT4)" "Y" +ifeq "$(WANT_WIN_QT)" "Y" ifeq "$(HAVE_QT5)" "Y" EXTRA_FILES += $(GAMEDIR)/Qt5Core.dll EXTRA_FILES += $(GAMEDIR)/Qt5Gui.dll @@ -711,19 +722,19 @@ $(OBJ)/%.o : $(LUASRC)/%.c $(cc) $(CFLAGS) -o$@ $< #========================================== -# Rules for files in win/Qt4 +# Rules for files in win/Qt #========================================== ifeq "$(HAVE_QT5)" "Y" -QT4_CXXFLAGS = -std=c++11 +QT_CXXFLAGS = -std=c++11 else -QT4_CXXFLAGS = +QT_CXXFLAGS = endif -$(OBJ)/%.o : $(QT4)/%.cpp - $(cxx) $(CXXFLAGS) $(QT4_CXXFLAGS) -I$(MSWIN) -I$(QT4_DIRECTORY)/include -o$@ $< +$(OBJ)/%.o : $(QT)/%.cpp + $(cxx) $(CXXFLAGS) $(QT_CXXFLAGS) -I$(MSWIN) -I$(QT_DIRECTORY)/include -o$@ $< -$(QT4)/%.moc : $(QT4)/%.h - $(QT4_DIRECTORY)\bin\moc -o $@ $< +$(QT)/%.moc : $(QT)/%.h + $(QT_DIRECTORY)\bin\moc -o $@ $< ifeq "$(SKIP_NETHACKW)" "Y" NETHACKW_EXE = @@ -740,7 +751,7 @@ SHELL=CMD.EXE # Since DOS doesn't allow / as path separator, and GCC doesn't allow \ as # path separator, we must change all pathnames when performing DOS commands. # This is done by blindly applying $(subst /,\, ...) on every command. -# Where any command contain / for another reason (switch char, a little +# Where any command contain / for another reason (switch char, a little # more care is taken. # @@ -792,20 +803,20 @@ recover: $(U)recover.exe $(subst /,\,if exist $(U)recover.exe copy $(U)recover.exe $(GAMEDIR)) $(subst /,\,if exist $(DOC)/recover.txt copy $(DOC)/recover.txt $(GAMEDIR)/recover.txt) -$(O)sp_lev.tag: $(O)utility.tag +$(O)sp_lev.tag: $(O)utility.tag $(subst /,\,echo sp_levs done > $(O)sp_lev.tag) $(O)utility.tag: $(INCL)/date.h $(INCL)/onames.h $(INCL)/pm.h \ - $(SRC)/vis_tab.c $(INCL)/vis_tab.h $(TILEUTIL16) + $(TILEUTIL16) $(subst /,\,@echo utilities made >$@) @echo utilities made. $(INCL)/nhlua.h: echo /* nhlua.h - generated by top Makefile */ > $@ - @echo #include "../lib/lua-$(LUA_VERSION)/src/lua.h" >> $@ + @echo #include "$(LUASRC)/lua.h" >> $@ @echo LUA_API int (lua_error) (lua_State *L) NORETURN; >>$@ - @echo #include "../lib/lua-$(LUA_VERSION)/src/lualib.h" >> $@ - @echo #include "../lib/lua-$(LUA_VERSION)/src/lauxlib.h" >> $@ + @echo #include "$(LUASRC)/lualib.h" >> $@ + @echo #include "$(LUASRC)/lauxlib.h" >> $@ @echo /*nhlua.h*/ >> $@ tileutil: $(U)gif2txt.exe $(U)gif2tx32.exe $(U)txt2ppm.exe @@ -817,7 +828,7 @@ $(O)winres.o: $(TILEBMP16) $(MSWIN)/NetHackW.rc $(MSWIN)/mnsel.bmp \ $(MSWIN)/splash.bmp $(rc) -o$@ --include-dir $(MSWIN) -i $(MSWIN)/NetHackW.rc -$(O)conres.o: $(MSWSYS)/console.rc $(MSWSYS)/NetHack.ico +$(O)conres.o: $(MSWSYS)/console.rc $(MSWSYS)/NetHack.ico $(rc) -o$@ --include-dir $(MSWSYS) -i $(MSWSYS)/console.rc #========================================== @@ -856,7 +867,7 @@ $(GAMEDIR)/NetHackW.exe : gamedir.tag $(PDCLIB) $(O)tile.o $(O)ttystub.o \ endif $(O)nhdefkey.o: - $(cc) $(CFLAGS) -DBUILD_DLL -o$@ $(MSWSYS)/nhdefkey.c + $(cc) $(CFLAGS) -DBUILD_DLL -o$@ $(MSWSYS)/nhdefkey.c $(GAMEDIR)/nhdefkey.dll : $(O)nhdefkey.o gamedir.tag @echo Linking $@ @@ -864,7 +875,7 @@ $(GAMEDIR)/nhdefkey.dll : $(O)nhdefkey.o gamedir.tag -Wl,--add-stdcall-alias -o $@ $< $(O)nh340key.o: - $(cc) $(CFLAGS) -DBUILD_DLL -o$@ $(MSWSYS)/nh340key.c + $(cc) $(CFLAGS) -DBUILD_DLL -o$@ $(MSWSYS)/nh340key.c $(GAMEDIR)/nh340key.dll : $(O)nh340key.o gamedir.tag @echo Linking $@ @@ -872,7 +883,7 @@ $(GAMEDIR)/nh340key.dll : $(O)nh340key.o gamedir.tag -Wl,--add-stdcall-alias -o $@ $< $(O)nhraykey.o: - $(cc) $(CFLAGS) -DBUILD_DLL -o$@ $(MSWSYS)/nhraykey.c + $(cc) $(CFLAGS) -DBUILD_DLL -o$@ $(MSWSYS)/nhraykey.c $(GAMEDIR)/nhraykey.dll : $(O)nhraykey.o gamedir.tag @echo Linking $@ @@ -926,12 +937,6 @@ $(INCL)/onames.h : $(U)makedefs.exe $(INCL)/pm.h : $(U)makedefs.exe $(subst /,\,$(U)makedefs -p) -$(INCL)/vis_tab.h: $(U)makedefs.exe - $(subst /,\,$(U)makedefs -z) - -$(SRC)/vis_tab.c: $(U)makedefs.exe - $(subst /,\,$(U)makedefs -z) - $(DAT)/data: $(O)utility.tag $(DATABASE) $(subst /,\,$(U)makedefs -d) @@ -1161,7 +1166,7 @@ $(O)til2bm32.o: $(WSHR)/til2bm32.c $(HACK_H) $(TILE_H) $(MSWSYS)/win32api.h $(O)pdcurses.a : $(PDCLIBOBJS) $(PDCOBJS) ar rcs $@ $(PDCLIBOBJS) $(PDCOBJS) - + #============================================================= # LUA #============================================================= @@ -1201,9 +1206,7 @@ ifneq "$(W_GAMEDIR)" "" if exist $(W_GAMEDIR)\nhdat$(NHV) del $(W_GAMEDIR)\nhdat$(NHV) endif ifneq "$(W_SRC)" "" - if exist $(W_SRC)\vis_tab.c del $(W_SRC)\vis_tab.c if exist $(W_SRC)\tile.c del $(W_SRC)\tile.c - if exist $(W_SRC)\vis_tab.c del $(W_SRC)\vis_tab.c if exist $(W_SRC)\nhdat$(NHV). del $(W_SRC)\nhdat$(NHV). endif ifneq "$(W_DAT)" "" @@ -1254,7 +1257,6 @@ ifneq "$(W_INCL)" "" if exist $(W_INCL)\date.h del $(W_INCL)\date.h if exist $(W_INCL)\onames.h del $(W_INCL)\onames.h if exist $(W_INCL)\pm.h del $(W_INCL)\pm.h - if exist $(W_INCL)\vis_tab.h del $(W_INCL)\vis_tab.h endif ifeq "$(ADD_CURSES)" "Y" ifneq "$(W_OBJ)" "" @@ -1350,7 +1352,7 @@ $(O)tile.o: $(SRC)/tile.c $(HACK_H) $(O)panic.o: $(U)panic.c $(CONFIG_H) $(cc) $(CFLAGS) -o$@ $(U)panic.c -# +# # sys/share dependencies # @@ -1359,7 +1361,7 @@ $(O)panic.o: $(U)panic.c $(CONFIG_H) # # Other dependencies needed by some ports -# +# ifeq "$(ADD_CURSES)" "Y" # curses window port dependencies @@ -1373,22 +1375,22 @@ $(O)cursstat.o: $(WCURSES)/cursstat.c $(WCURSES)/cursstat.h $(INCL)/wincurs.h $(O)curswins.o: $(WCURSES)/curswins.c $(WCURSES)/curswins.h $(INCL)/wincurs.h endif -ifeq "$(WANT_WIN_QT4)" "Y" +ifeq "$(WANT_WIN_QT)" "Y" # Qt dependencies -$(GAMEDIR))/Qt5Core.dll : $(QT4_DIRECTORY)/bin/Qt5Core.dll +$(GAMEDIR))/Qt5Core.dll : $(QT_DIRECTORY)/bin/Qt5Core.dll $(subst /,\,@copy $< $@ >nul) -$(GAMEDIR))/Qt5Gui.dll : $(QT4_DIRECTORY)/bin/Qt5Gui.dll +$(GAMEDIR))/Qt5Gui.dll : $(QT_DIRECTORY)/bin/Qt5Gui.dll $(subst /,\,@copy $< $@ >nul) -$(GAMEDIR)/Qt5Widgets.dll : $(QT4_DIRECTORY)/bin/Qt5Widgets.dll +$(GAMEDIR)/Qt5Widgets.dll : $(QT_DIRECTORY)/bin/Qt5Widgets.dll $(subst /,\,@copy $< $@ >nul) -$(GAMEDIR)/QtCore4.dll : $(QT4_DIRECTORY)/bin/QtCore4.dll +$(GAMEDIR)/QtCore4.dll : $(QT_DIRECTORY)/bin/QtCore4.dll $(subst /,\,@copy $< $@ >nul) -$(GAMEDIR)/QtGui4.dll : $(QT4_DIRECTORY)/bin/QtGui4.dll +$(GAMEDIR)/QtGui4.dll : $(QT_DIRECTORY)/bin/QtGui4.dll $(subst /,\,@copy $< $@ >nul) $(GAMEDIR)/nhtiles.bmp : $(SRC)/tiles.bmp @@ -1397,15 +1399,15 @@ $(GAMEDIR)/nhtiles.bmp : $(SRC)/tiles.bmp $(GAMEDIR)/rip.xpm : ../win/X11/rip.xpm $(subst /,\,@copy $< $@ >nul) # Dependencies on .moc files (for Qt 4 or 5) -$(OBJ)/qt4main.o : $(QT4)/qt4main.cpp $(QT4)/qt4main.moc $(QT4)/qt4kde0.moc -$(OBJ)/qt4map.o : $(QT4)/qt4map.cpp $(QT4)/qt4map.moc -$(OBJ)/qt4menu.o : $(QT4)/qt4menu.cpp $(QT4)/qt4menu.moc -$(OBJ)/qt4msg.o : $(QT4)/qt4msg.cpp $(QT4)/qt4msg.moc -$(OBJ)/qt4plsel.o : $(QT4)/qt4plsel.cpp $(QT4)/qt4plsel.moc -$(OBJ)/qt4set.o : $(QT4)/qt4set.cpp $(QT4)/qt4set.moc -$(OBJ)/qt4stat.o : $(QT4)/qt4stat.cpp $(QT4)/qt4stat.moc -$(OBJ)/qt4xcmd.o : $(QT4)/qt4xcmd.cpp $(QT4)/qt4xcmd.moc -$(OBJ)/qt4yndlg.o : $(QT4)/qt4yndlg.cpp $(QT4)/qt4yndlg.moc +$(OBJ)/qt_main.o : $(QT)/qt_main.cpp $(QT)/qt_main.moc $(QT)/qt_kde0.moc +$(OBJ)/qt_map.o : $(QT)/qt_map.cpp $(QT)/qt_map.moc +$(OBJ)/qt_menu.o : $(QT)/qt_menu.cpp $(QT)/qt_menu.moc +$(OBJ)/qt_msg.o : $(QT)/qt_msg.cpp $(QT)/qt_msg.moc +$(OBJ)/qt_plsel.o : $(QT)/qt_plsel.cpp $(QT)/qt_plsel.moc +$(OBJ)/qt_set.o : $(QT)/qt_set.cpp $(QT)/qt_set.moc +$(OBJ)/qt_stat.o : $(QT)/qt_stat.cpp $(QT)/qt_stat.moc +$(OBJ)/qt_xcmd.o : $(QT)/qt_xcmd.cpp $(QT)/qt_xcmd.moc +$(OBJ)/qt_yndlg.o : $(QT)/qt_yndlg.cpp $(QT)/qt_yndlg.moc endif # @@ -1416,7 +1418,7 @@ endif # with -o$@ # * targets prefixed with $(O) # * $(CC) changed to $(cc) -# but otherwise untouched. +# but otherwise untouched. # That means that there is some irrelevant stuff # in here, but maintenance should be easier. # @@ -1479,67 +1481,124 @@ $(O)wintext.o: ../win/X11/wintext.c $(HACK_H) $(INCL)/winX.h $(INCL)/xwindow.h $(O)winval.o: ../win/X11/winval.c $(HACK_H) $(INCL)/winX.h $(cc) $(CFLAGS) -o$@ ../win/X11/winval.c $(O)tile.o: $(SRC)/tile.c $(HACK_H) -$(O)gnaskstr.o: ../win/gnome/gnaskstr.c ../win/gnome/gnaskstr.h \ - ../win/gnome/gnmain.h - $(cc) $(CFLAGS) $(GNOMEINC) -o$@ ../win/gnome/gnaskstr.c -$(O)gnbind.o: ../win/gnome/gnbind.c ../win/gnome/gnbind.h ../win/gnome/gnmain.h \ - ../win/gnome/gnaskstr.h ../win/gnome/gnyesno.h - $(cc) $(CFLAGS) $(GNOMEINC) -o$@ ../win/gnome/gnbind.c -$(O)gnglyph.o: ../win/gnome/gnglyph.c ../win/gnome/gnglyph.h $(INCL)/tile2x11.h - $(cc) $(CFLAGS) $(GNOMEINC) -o$@ ../win/gnome/gnglyph.c -$(O)gnmain.o: ../win/gnome/gnmain.c ../win/gnome/gnmain.h ../win/gnome/gnsignal.h \ - ../win/gnome/gnbind.h ../win/gnome/gnopts.h $(HACK_H) \ - $(INCL)/date.h - $(cc) $(CFLAGS) $(GNOMEINC) -o$@ ../win/gnome/gnmain.c -$(O)gnmap.o: ../win/gnome/gnmap.c ../win/gnome/gnmap.h ../win/gnome/gnglyph.h \ - ../win/gnome/gnsignal.h $(HACK_H) - $(cc) $(CFLAGS) $(GNOMEINC) -o$@ ../win/gnome/gnmap.c -$(O)gnmenu.o: ../win/gnome/gnmenu.c ../win/gnome/gnmenu.h ../win/gnome/gnmain.h \ - ../win/gnome/gnbind.h - $(cc) $(CFLAGS) $(GNOMEINC) -o$@ ../win/gnome/gnmenu.c -$(O)gnmesg.o: ../win/gnome/gnmesg.c ../win/gnome/gnmesg.h ../win/gnome/gnsignal.h - $(cc) $(CFLAGS) $(GNOMEINC) -o$@ ../win/gnome/gnmesg.c -$(O)gnopts.o: ../win/gnome/gnopts.c ../win/gnome/gnopts.h ../win/gnome/gnglyph.h \ - ../win/gnome/gnmain.h ../win/gnome/gnmap.h $(HACK_H) - $(cc) $(CFLAGS) $(GNOMEINC) -o$@ ../win/gnome/gnopts.c -$(O)gnplayer.o: ../win/gnome/gnplayer.c ../win/gnome/gnplayer.h \ - ../win/gnome/gnmain.h $(HACK_H) - $(cc) $(CFLAGS) $(GNOMEINC) -o$@ ../win/gnome/gnplayer.c -$(O)gnsignal.o: ../win/gnome/gnsignal.c ../win/gnome/gnsignal.h \ - ../win/gnome/gnmain.h - $(cc) $(CFLAGS) $(GNOMEINC) -o$@ ../win/gnome/gnsignal.c -$(O)gnstatus.o: ../win/gnome/gnstatus.c ../win/gnome/gnstatus.h \ - ../win/gnome/gnsignal.h ../win/gnome/gn_xpms.h \ - ../win/gnome/gnomeprv.h - $(cc) $(CFLAGS) $(GNOMEINC) -o$@ ../win/gnome/gnstatus.c -$(O)gntext.o: ../win/gnome/gntext.c ../win/gnome/gntext.h ../win/gnome/gnmain.h \ - ../win/gnome/gn_rip.h - $(cc) $(CFLAGS) $(GNOMEINC) -o$@ ../win/gnome/gntext.c -$(O)gnworn.o: ../win/gnome/gnworn.c ../win/gnome/gnworn.h ../win/gnome/gnglyph.h \ - ../win/gnome/gnsignal.h ../win/gnome/gnomeprv.h - $(cc) $(CFLAGS) $(GNOMEINC) -o$@ ../win/gnome/gnworn.c -$(O)gnyesno.o: ../win/gnome/gnyesno.c ../win/gnome/gnbind.h ../win/gnome/gnyesno.h - $(cc) $(CFLAGS) $(GNOMEINC) -o$@ ../win/gnome/gnyesno.c -$(O)wingem.o: ../win/gem/wingem.c $(HACK_H) $(INCL)/func_tab.h $(INCL)/dlb.h \ - $(INCL)/wingem.h - $(cc) $(CFLAGS) -o$@ ../win/gem/wingem.c -$(O)wingem1.o: ../win/gem/wingem1.c $(INCL)/gem_rsc.h $(INCL)/load_img.h \ - $(INCL)/gr_rect.h $(INCL)/wintype.h $(INCL)/wingem.h - $(cc) $(CFLAGS) -o$@ ../win/gem/wingem1.c -$(O)load_img.o: ../win/gem/load_img.c $(INCL)/load_img.h - $(cc) $(CFLAGS) -o$@ ../win/gem/load_img.c -$(O)gr_rect.o: ../win/gem/gr_rect.c $(INCL)/gr_rect.h - $(cc) $(CFLAGS) -o$@ ../win/gem/gr_rect.c -$(O)qt_win.o: ../win/Qt/qt_win.cpp $(HACK_H) $(INCL)/func_tab.h \ - $(INCL)/dlb.h $(INCL)/tile2x11.h \ - $(INCL)/qt_win.h $(INCL)/qt_clust.h $(INCL)/qt_kde0.h \ - $(INCL)/qt_xpms.h qt_win.moc qt_kde0.moc qttableview.moc - $(CXX) $(CXXFLAGS) -o$@ ../win/Qt/qt_win.cpp -$(O)qt_clust.o: ../win/Qt/qt_clust.cpp $(INCL)/qt_clust.h - $(CXX) $(CXXFLAGS) -o$@ ../win/Qt/qt_clust.cpp -$(O)qttableview.o: ../win/Qt/qttableview.cpp $(INCL)/qttableview.h - $(CXX) $(CXXFLAGS) -o$@ ../win/Qt/qttableview.cpp -$(O)vis_tab.o: vis_tab.c $(CONFIG_H) $(INCL)/vis_tab.h +#--- +$(O)qt_bind.o: ../win/Qt/qt_bind.cpp $(HACK_H) ../win/Qt/qt_pre.h \ + ../win/Qt/qt_post.h ../win/Qt/qt_bind.h ../win/Qt/qt_main.h \ + ../win/Qt/qt_kde0.h ../win/Qt/qt_click.h ../win/Qt/qt_delay.h \ + ../win/Qt/qt_xcmd.h ../win/Qt/qt_key.h ../win/Qt/qt_map.h \ + ../win/Qt/qt_win.h ../win/Qt/qt_clust.h ../win/Qt/qt_menu.h \ + ../win/Qt/qt_rip.h ../win/Qt/qt_msg.h ../win/Qt/qt_plsel.h \ + ../win/Qt/qt_svsel.h ../win/Qt/qt_set.h ../win/Qt/qt_stat.h \ + ../win/Qt/qt_icon.h ../win/Qt/qt_streq.h ../win/Qt/qt_line.h \ + ../win/Qt/qt_yndlg.h ../win/Qt/qt_str.h ../include/dlb.h +# $(CXX) $(CXXFLAGS) -c -o $@ ../win/Qt/qt_bind.cpp +$(O)qt_click.o: ../win/Qt/qt_click.cpp $(HACK_H) ../win/Qt/qt_pre.h \ + ../win/Qt/qt_post.h ../win/Qt/qt_click.h +# $(CXX) $(CXXFLAGS) -c -o $@ ../win/Qt/qt_click.cpp +$(O)qt_clust.o: ../win/Qt/qt_clust.cpp ../win/Qt/qt_clust.h +# $(CXX) $(CXXFLAGS) -c -o $@ ../win/Qt/qt_clust.cpp +$(O)qt_delay.o: ../win/Qt/qt_delay.cpp $(HACK_H) ../win/Qt/qt_pre.h \ + ../win/Qt/qt_post.h ../win/Qt/qt_delay.h +# $(CXX) $(CXXFLAGS) -c -o $@ ../win/Qt/qt_delay.cpp +$(O)qt_glyph.o: ../win/Qt/qt_glyph.cpp $(HACK_H) ../include/tile2x11.h \ + ../win/Qt/qt_pre.h ../win/Qt/qt_post.h ../win/Qt/qt_glyph.h \ + ../win/Qt/qt_bind.h ../win/Qt/qt_main.h ../win/Qt/qt_kde0.h \ + ../win/Qt/qt_set.h ../win/Qt/qt_inv.h ../win/Qt/qt_map.h \ + ../win/Qt/qt_win.h ../win/Qt/qt_clust.h ../win/Qt/qt_str.h +# $(CXX) $(CXXFLAGS) -c -o $@ ../win/Qt/qt_glyph.cpp +$(O)qt_icon.o: ../win/Qt/qt_icon.cpp $(HACK_H) ../win/Qt/qt_pre.h \ + ../win/Qt/qt_post.h ../win/Qt/qt_icon.h +# $(CXX) $(CXXFLAGS) -c -o $@ ../win/Qt/qt_icon.cpp +$(O)qt_inv.o: ../win/Qt/qt_inv.cpp $(HACK_H) ../win/Qt/qt_pre.h \ + ../win/Qt/qt_post.h ../win/Qt/qt_inv.h ../win/Qt/qt_glyph.h \ + ../win/Qt/qt_set.h ../win/Qt/qt_bind.h ../win/Qt/qt_main.h \ + ../win/Qt/qt_kde0.h +# $(CXX) $(CXXFLAGS) -c -o $@ ../win/Qt/qt_inv.cpp +$(O)qt_key.o: ../win/Qt/qt_key.cpp $(HACK_H) ../win/Qt/qt_pre.h \ + ../win/Qt/qt_post.h ../win/Qt/qt_key.h +# $(CXX) $(CXXFLAGS) -c -o $@ ../win/Qt/qt_key.cpp +$(O)qt_line.o: ../win/Qt/qt_line.cpp $(HACK_H) ../win/Qt/qt_pre.h \ + ../win/Qt/qt_post.h ../win/Qt/qt_line.h +# $(CXX) $(CXXFLAGS) -c -o $@ ../win/Qt/qt_line.cpp +$(O)qt_main.o: ../win/Qt/qt_main.cpp $(HACK_H) ../win/Qt/qt_pre.h \ + ../win/Qt/qt_post.h ../win/Qt/qt_main.h ../win/Qt/qt_kde0.h \ + qt_main.moc ../win/Qt/qt_bind.h ../win/Qt/qt_glyph.h \ + ../win/Qt/qt_inv.h ../win/Qt/qt_key.h ../win/Qt/qt_map.h \ + ../win/Qt/qt_win.h ../win/Qt/qt_clust.h ../win/Qt/qt_msg.h \ + ../win/Qt/qt_set.h ../win/Qt/qt_stat.h ../win/Qt/qt_icon.h \ + ../win/Qt/qt_str.h qt_kde0.moc +# $(CXX) $(CXXFLAGS) -c -o $@ ../win/Qt/qt_main.cpp +$(O)qt_map.o: ../win/Qt/qt_map.cpp $(HACK_H) ../win/Qt/qt_pre.h \ + ../win/Qt/qt_post.h ../win/Qt/qt_map.h ../win/Qt/qt_win.h \ + ../win/Qt/qt_clust.h qt_map.moc ../win/Qt/qt_click.h \ + ../win/Qt/qt_glyph.h ../win/Qt/qt_xpms.h ../win/Qt/qt_set.h \ + ../win/Qt/qt_bind.h ../win/Qt/qt_main.h ../win/Qt/qt_kde0.h \ + ../win/Qt/qt_str.h +# $(CXX) $(CXXFLAGS) -c -o $@ ../win/Qt/qt_map.cpp +$(O)qt_menu.o: ../win/Qt/qt_menu.cpp $(HACK_H) ../win/Qt/qt_pre.h \ + ../win/Qt/qt_post.h ../win/Qt/qt_menu.h ../win/Qt/qt_win.h \ + ../win/Qt/qt_rip.h qt_menu.moc ../win/Qt/qt_glyph.h \ + ../win/Qt/qt_set.h ../win/Qt/qt_bind.h ../win/Qt/qt_main.h \ + ../win/Qt/qt_kde0.h ../win/Qt/qt_streq.h ../win/Qt/qt_line.h \ + ../win/Qt/qt_str.h +# $(CXX) $(CXXFLAGS) -c -o $@ ../win/Qt/qt_menu.cpp +$(O)qt_msg.o: ../win/Qt/qt_msg.cpp $(HACK_H) ../win/Qt/qt_pre.h \ + ../win/Qt/qt_post.h ../win/Qt/qt_msg.h ../win/Qt/qt_win.h \ + qt_msg.moc ../win/Qt/qt_map.h ../win/Qt/qt_clust.h \ + ../win/Qt/qt_set.h ../win/Qt/qt_bind.h ../win/Qt/qt_main.h \ + ../win/Qt/qt_kde0.h ../win/Qt/qt_str.h +# $(CXX) $(CXXFLAGS) -c -o $@ ../win/Qt/qt_msg.cpp +$(O)qt_plsel.o: ../win/Qt/qt_plsel.cpp $(HACK_H) ../win/Qt/qt_pre.h \ + ../win/Qt/qt_post.h ../win/Qt/qt_plsel.h qt_plsel.moc \ + ../win/Qt/qt_bind.h ../win/Qt/qt_main.h ../win/Qt/qt_kde0.h \ + ../win/Qt/qt_glyph.h ../win/Qt/qt_set.h ../win/Qt/qt_str.h +# $(CXX) $(CXXFLAGS) -c -o $@ ../win/Qt/qt_plsel.cpp +$(O)qt_rip.o: ../win/Qt/qt_rip.cpp $(HACK_H) ../win/Qt/qt_pre.h \ + ../win/Qt/qt_post.h ../win/Qt/qt_rip.h ../win/Qt/qt_bind.h \ + ../win/Qt/qt_main.h ../win/Qt/qt_kde0.h ../win/Qt/qt_str.h +# $(CXX) $(CXXFLAGS) -c -o $@ ../win/Qt/qt_rip.cpp +$(O)qt_set.o: ../win/Qt/qt_set.cpp $(HACK_H) ../win/Qt/qt_pre.h \ + ../win/Qt/qt_post.h ../win/Qt/qt_set.h ../win/Qt/qt_bind.h \ + ../win/Qt/qt_main.h ../win/Qt/qt_kde0.h qt_set.moc \ + ../win/Qt/qt_glyph.h ../win/Qt/qt_str.h +# $(CXX) $(CXXFLAGS) -c -o $@ ../win/Qt/qt_set.cpp +$(O)qt_stat.o: ../win/Qt/qt_stat.cpp $(HACK_H) ../win/Qt/qt_pre.h \ + ../win/Qt/qt_post.h ../win/Qt/qt_stat.h ../win/Qt/qt_win.h \ + ../win/Qt/qt_icon.h qt_stat.moc ../win/Qt/qt_set.h \ + ../win/Qt/qt_bind.h ../win/Qt/qt_main.h ../win/Qt/qt_kde0.h \ + ../win/Qt/qt_str.h ../win/Qt/qt_xpms.h +# $(CXX) $(CXXFLAGS) -c -o $@ ../win/Qt/qt_stat.cpp +$(O)qt_str.o: ../win/Qt/qt_str.cpp ../win/Qt/qt_str.h +# $(CXX) $(CXXFLAGS) -c -o $@ ../win/Qt/qt_str.cpp +$(O)qt_streq.o: ../win/Qt/qt_streq.cpp $(HACK_H) ../win/Qt/qt_pre.h \ + ../win/Qt/qt_post.h ../win/Qt/qt_streq.h ../win/Qt/qt_line.h \ + ../win/Qt/qt_str.h +# $(CXX) $(CXXFLAGS) -c -o $@ ../win/Qt/qt_streq.cpp +$(O)qt_svsel.o: ../win/Qt/qt_svsel.cpp $(HACK_H) ../win/Qt/qt_pre.h \ + ../win/Qt/qt_post.h ../win/Qt/qt_svsel.h ../win/Qt/qt_bind.h \ + ../win/Qt/qt_main.h ../win/Qt/qt_kde0.h ../win/Qt/qt_str.h +# $(CXX) $(CXXFLAGS) -c -o $@ ../win/Qt/qt_svsel.cpp +#$(O)qttableview.o: ../win/Qt/qttableview.cpp $(INCL)/qttableview.h +# $(CXX) $(CXXFLAGS) -o$@ $(QT)/qttableview.cpp +$(O)qt_win.o: ../win/Qt/qt_win.cpp $(HACK_H) ../win/Qt/qt_pre.h \ + ../win/Qt/qt_post.h ../win/Qt/qt_win.h ../win/Qt/qt_bind.h \ + ../win/Qt/qt_main.h ../win/Qt/qt_kde0.h ../win/Qt/qt_click.h \ + ../win/Qt/qt_glyph.h ../win/Qt/qt_inv.h ../win/Qt/qt_key.h \ + ../win/Qt/qt_icon.h ../win/Qt/qt_map.h ../win/Qt/qt_clust.h \ + ../win/Qt/qt_menu.h ../win/Qt/qt_rip.h ../win/Qt/qt_msg.h \ + ../win/Qt/qt_set.h +# $(CXX) $(CXXFLAGS) -c -o $@ ../win/Qt/qt_win.cpp +$(O)qt_xcmd.o: ../win/Qt/qt_xcmd.cpp $(HACK_H) ../include/func_tab.h \ + ../win/Qt/qt_pre.h ../win/Qt/qt_post.h ../win/Qt/qt_xcmd.h \ +# qt_xcmd.moc ../win/Qt/qt_bind.h ../win/Qt/qt_main.h \ +# ../win/Qt/qt_kde0.h ../win/Qt/qt_set.h ../win/Qt/qt_str.h +# $(CXX) $(CXXFLAGS) -c -o $@ ../win/Qt/qt_xcmd.cpp +$(O)qt_yndlg.o: ../win/Qt/qt_yndlg.cpp $(HACK_H) ../win/Qt/qt_pre.h \ + ../win/Qt/qt_post.h ../win/Qt/qt_yndlg.h qt_yndlg.moc \ + ../win/Qt/qt_str.h +# $(CXX) $(CXXFLAGS) -c -o $@ ../win/Qt/qt_yndlg.cpp +#--- +$(O)vis_tab.o: vis_tab.c $(CONFIG_H) $(O)allmain.o: allmain.c $(HACK_H) $(O)alloc.o: alloc.c $(CONFIG_H) $(O)apply.o: apply.c $(HACK_H) @@ -1562,7 +1621,8 @@ $(O)dog.o: dog.c $(HACK_H) $(O)dogmove.o: dogmove.c $(HACK_H) $(INCL)/mfndpos.h $(O)dokick.o: dokick.c $(HACK_H) $(O)dothrow.o: dothrow.c $(HACK_H) -$(O)drawing.o: drawing.c $(CONFIG_H) +$(O)drawing.o: drawing.c $(CONFIG_H) $(INCL)/color.h $(INCL)/rm.h \ + $(INCL)/objclass.h $(INCL)/monsym.h $(O)dungeon.o: dungeon.c $(HACK_H) $(INCL)/dgn_file.h $(INCL)/dlb.h $(O)eat.o: eat.c $(HACK_H) $(O)end.o: end.c $(HACK_H) $(INCL)/dlb.h @@ -1646,7 +1706,7 @@ $(O)u_init.o: u_init.c $(HACK_H) $(O)uhitm.o: uhitm.c $(HACK_H) $(O)vault.o: vault.c $(HACK_H) $(O)version.o: version.c $(HACK_H) $(INCL)/date.h -$(O)vision.o: vision.c $(HACK_H) $(INCL)/vis_tab.h +$(O)vision.o: vision.c $(HACK_H) $(O)weapon.o: weapon.c $(HACK_H) $(O)were.o: were.c $(HACK_H) $(O)wield.o: wield.c $(HACK_H) diff --git a/sys/winnt/Makefile.msc b/sys/winnt/Makefile.msc index 046016feb..01cd6f595 100644 --- a/sys/winnt/Makefile.msc +++ b/sys/winnt/Makefile.msc @@ -4,7 +4,7 @@ #============================================================================== # Build Tools Environment # -# NetHack 3.7 Work-in-progress Makefile for +# NetHack 3.7 Work-in-progress Makefile for # MS Visual Studio Visual C++ compiler # # Visual Studio Compilers Tested: @@ -22,11 +22,11 @@ # # BEFORE YOU START, in addition to your C compiler and linker, # -# o You will need a complete Lua source tree parallel to your +# o You will need a complete Lua source tree parallel to your # NetHack source tree. Lua is not an optional requirement, # it is required in order to process the level and dungeon -# description files during the game. You can obtain the -# Lua source from here: +# description files during the game. You can obtain the +# Lua source from here: # https://www.lua.org/download.html # # o If you want to include the curses Window port in the non-GUI @@ -37,7 +37,7 @@ # or via git from here: # git clone https://github.com/wmcbrine/PDCurses.git ../pdcurses # -# o If you want your build of NetHack to include support for +# o If you want your build of NetHack to include support for # compressing your save files, or to be able to exchange and use # compressed save files that originated on another platform such # as Linux or a handheld phone or tablet, then you will need @@ -60,16 +60,16 @@ # # Build Options Decisions # -# There are currently 5 decisions that you can choose to make. -# none of the 5 decisions are absolutely required because defaults +# There are currently 5 decisions that you can choose to make. +# none of the 5 decisions are absolutely required because defaults # are in place: # # 1. Where do you want your build results to end up? # 2. Do you want to include the optional curses port? -# 3. Do you want to include compressed savefile support to +# 3. Do you want to include compressed savefile support to # transfer compressed savefiles between platforms? # 4. Do you want debug information in the executable? -# 5. Do you want to explicitly override auto-detection of +# 5. Do you want to explicitly override auto-detection of # a 32-bit or 64-bit target? # # Mandatory Lua source Location (not optional) @@ -88,13 +88,13 @@ GAMEDIR = ..\binary # Default game build directory # #------------------------------------------------------------------------------ -# OPTIONAL - Curses window port support +# OPTIONAL - Curses window port support # # 2. Uncomment these and set them appropriately if you want to # include curses port support alongside TTY support in your -# NetHack.exe binary. +# NetHack.exe binary. # -# You'll have to set PDCURSES_H to the correct location of the +# You'll have to set PDCURSES_H to the correct location of the # PDCurses header (.h) files and PDCURSES_C to the location # of your PDCurses C files. # @@ -112,13 +112,13 @@ GAMEDIR = ..\binary # Default game build directory # #------------------------------------------------------------------------------ # 4. Do you want debug information available to the executable? -# +# DEBUGINFO = Y # #------------------------------------------------------------------------------ # 5. This Makefile will attempt to auto-detect your selected target architecture # based on Visual Studio command prompt configuration settins etc. -# However, if you want to manually override generation of a +# However, if you want to manually override generation of a # 32-bit or 64-bit build target, you can uncomment the apppropriate # TARGET_CPU line below. # @@ -131,7 +131,7 @@ DEBUGINFO = Y # This marks the end of the BUILD DECISIONS section. #============================================================================== !IFNDEF LUA_VERSION -LUAVER=5.4.0 +LUAVER=5.4.2 !ELSE LUAVER=$(LUA_VERSION) !ENDIF @@ -139,8 +139,8 @@ LUAVER=$(LUA_VERSION) # # Location of LUA # -# Original source needs to be obtained from: -# http://www.lua.org/ftp/lua-5.4.0.tar.gz +# Original source needs to be obtained from: +# http://www.lua.org/ftp/lua-5.4.2.tar.gz # # This build assumes that the LUA sources are located # at the specified location. If they are actually elsewhere @@ -187,8 +187,10 @@ SSYS = ..\sys\share # Shared system files MSWSYS = ..\sys\winnt # mswin 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 +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 # # Object directory. @@ -200,8 +202,7 @@ OBJ = o #========================================== # Exe File Info. #========================================== - -# + # # Optional high-quality BSD random number generation routines # (see pcconf.h). Set to nothing if not used. @@ -251,12 +252,10 @@ U = $(UTIL)^\ !IFDEF TEST_CROSSCOMPILE HOST=_host CROSSCOMPILE_TARGET= -DCROSSCOMPILE_TARGET -CROSSCOMPILE_HOST= -DCROSSCOMPILE_HOST CROSSCOMPILE= -DCROSSCOMPILE !ELSE HOST= CROSSCOMPILE_TARGET= -CROSSCOMPILE_HOST= CROSSCOMPILE= !ENDIF @@ -292,13 +291,13 @@ PPMWRITERS = $(O)ppmwrite.o $(O)alloc$(HOST).o $(O)panic$(HOST).o # VOBJ01 = $(O)allmain.o $(O)alloc.o $(O)apply.o $(O)artifact.o -VOBJ02 = $(O)attrib.o $(O)ball.o $(O)bones.o $(O)botl.o -VOBJ03 = $(O)cmd.o $(O)dbridge.o $(O)decl.o $(O)detect.o -VOBJ04 = $(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 -VOBJ06 = $(O)dothrow.o $(O)drawing.o $(O)dungeon.o $(O)eat.o -VOBJ07 = $(O)end.o $(O)engrave.o $(O)exper.o $(O)explode.o -VOBJ08 = $(O)extralev.o $(O)files.o $(O)fountain.o $(O)hack.o +VOBJ02 = $(O)attrib.o $(O)ball.o $(O)bones.o $(O)botl.o +VOBJ03 = $(O)cmd.o $(O)dbridge.o $(O)decl.o $(O)detect.o +VOBJ04 = $(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 +VOBJ06 = $(O)dothrow.o $(O)drawing.o $(O)dungeon.o $(O)eat.o +VOBJ07 = $(O)end.o $(O)engrave.o $(O)exper.o $(O)explode.o +VOBJ08 = $(O)extralev.o $(O)files.o $(O)fountain.o $(O)hack.o VOBJ09 = $(O)hacklib.o $(O)insight.o $(O)invent.o $(O)isaac64.o VOBJ10 = $(O)light.o $(O)lock.o $(O)mail.o $(O)makemon.o VOBJ11 = $(O)mapglyph.o $(O)mcastu.o $(O)mhitm.o $(O)mhitu.o @@ -316,9 +315,9 @@ VOBJ22 = $(O)sit.o $(O)sounds.o $(O)sp_lev.o $(O)spell.o VOBJ23 = $(O)steal.o $(O)steed.o $(O)symbols.o $(O)sys.o VOBJ24 = $(O)teleport.o $(O)timeout.o $(O)topten.o $(O)track.o VOBJ25 = $(O)trap.o $(O)u_init.o $(O)uhitm.o $(O)vault.o -VOBJ26 = $(O)vis_tab.o $(O)vision.o $(O)weapon.o $(O)were.o -VOBJ27 = $(O)wield.o $(O)windows.o $(O)wizard.o $(O)worm.o -VOBJ28 = $(O)worn.o $(O)write.o $(O)zap.o +VOBJ26 = $(O)vision.o $(O)weapon.o $(O)were.o $(O)wield.o +VOBJ27 = $(O)windows.o $(O)wizard.o $(O)worm.o $(O)worn.o +VOBJ28 = $(O)write.o $(O)zap.o LUAOBJ = $(O)nhlua.o $(O)nhlsel.o $(O)nhlobj.o @@ -341,7 +340,7 @@ CURSESOBJ= $(O)cursdial.o $(O)cursinit.o $(O)cursinvt.o $(O)cursmain.o \ !ENDIF SOBJ = $(O)windmain.o $(O)winnt.o $(O)win10.o \ - $(O)safeproc.o $(O)nhlan.o $(SOUND) + $(O)safeproc.o $(O)nhlan.o $(SOUND) OBJS = $(MDLIB) \ $(VOBJ01) $(VOBJ02) $(VOBJ03) $(VOBJ04) $(VOBJ05) \ @@ -385,7 +384,7 @@ OPTIONS_FILE = $(DAT)\options #===============-================================================= # LUA library -# Source from http://www.lua.org/ftp/lua-5.4.0.tar.gz +# Source from http://www.lua.org/ftp/lua-5.4.2.tar.gz #================================================================= !IFNDEF LUAVER @@ -395,6 +394,12 @@ LUATMP = $(LUATMP:-beta=) #strip suffix if exists "-beta" !IF "$(LUATMP)" == "5.4.0" LUAVER = 5.4.0 !ENDIF +!IF "$(LUATMP)" == "5.4.1" +LUAVER = 5.4.1 +!ENDIF +!IF "$(LUATMP)" == "5.4.2" +LUAVER = 5.4.2 +!ENDIF !ELSE !ERROR NetHack 3.7 requires LUA so LUATOP must be defined !ENDIF @@ -405,7 +410,7 @@ LUATMP = $(LUATMP:-BETA=) #strip suffix if exists "-BETA" !IF "$(LUATMP)" == "5.3.5" LUAVER = 5.3.5 !ELSE -LUAVER = 5.4.0 +LUAVER = 5.4.2 !ENDIF !ENDIF !ENDIF @@ -437,7 +442,7 @@ LUAOBJFILES = $(O)lapi.o $(O)lauxlib.o $(O)lbaselib.o \ LUASRCFILES = $(LUASRCFILES) lbitlib.c LUAOBJFILES = $(LUAOBJFILES) $(O)lbitlib.o !ELSE -# 5.4.0 adds header files ljumptab.h and lopnames.h +# 5.4.0 added header files ljumptab.h and lopnames.h # and removes lbitlib.c !ENDIF @@ -469,7 +474,7 @@ PDCLIB = $(O)pdcurses.lib PDCINCL = /I$(PDCURSES_TOP) /I$(PDCSRC) /I$(PDCWINCON) !ELSE -PDCLIB = +PDCLIB = !ENDIF #========================================== @@ -496,8 +501,7 @@ HACK_H = $(INCL)\hack.h $(CONFIG_H) $(INCL)\lint.h $(INCL)\align.h \ $(INCL)\mextra.h $(INCL)\skills.h $(INCL)\onames.h \ $(INCL)\timeout.h $(INCL)\trap.h $(INCL)\flag.h \ $(INCL)\vision.h $(INCL)\display.h $(INCL)\engrave.h \ - $(INCL)\winprocs.h $(INCL)\sys.h $(INCL)\wintty.h \ - $(INCL)\trampoli.h + $(INCL)\winprocs.h $(INCL)\sys.h $(INCL)\wintty.h TILE_H = ..\win\share\tile.h @@ -529,18 +533,18 @@ CTAGSOPT =--language-force=c --sort=no -D"Bitfield(x,n)=unsigned x : n" --excmd= # TINC = $(INCL:\=/) TSRC = $(SRC:\=/) - + cc=cl cpp=cpp link=link rc=Rc -# Before we get started, this section is used to determine the version of -# Visual Studio we are using. We set VSVER to 0000 to flag any version that +# Before we get started, this section is used to determine the version of +# Visual Studio we are using. We set VSVER to 0000 to flag any version that # is too old or untested. # -#NMAKE version 1426288060 is distributed with latest VS 2019 +#NMAKE version 1428293350 from latest VS 2019 (December 8, 2020 version 16.8.3) #!MESSAGE $(MAKEFLAGS) #!MESSAGE $(MAKEDIR) @@ -564,9 +568,9 @@ VSVER=2013 VSVER=2015 !ELSEIF ($(MAKEVERSION) > 1411000000) && ($(MAKEVERSION) < 1416270312) VSVER=2017 -!ELSEIF ($(MAKEVERSION) > 1416270311) && ($(MAKEVERSION) < 1426288061) +!ELSEIF ($(MAKEVERSION) > 1416270311) && ($(MAKEVERSION) < 1428293351) VSVER=$(VSNEWEST) -!ELSEIF ($(MAKEVERSION) > 1426288060) +!ELSEIF ($(MAKEVERSION) > 1428293350) VSVER=2999 #untested future version !ENDIF @@ -593,7 +597,7 @@ VSVER=2999 #untested future version !include ! ENDIF -#These will be in the environment variables with one of the VS2017 +#These will be in the environment variables with one of the Visual Studio #developer command prompts. #VSCMD_ARG_HOST_ARCH=x64 #VSCMD_ARG_TGT_ARCH=x86 @@ -852,26 +856,26 @@ install: $(INCL)\nhlua.h $(O)envchk.tag $(O)obj.tag $(O)utility.tag $(GAMEDIR)\N # Main game targets. #========================================== -# The section for linking the NetHack image looks a little strange at -# first, especially if you are used to UNIX makes, or NDMAKE. It is -# Microsoft nmake specific, and it gets around the problem of the -# link command line being too long for the linker. An "in-line" linker +# The section for linking the NetHack image looks a little strange at +# first, especially if you are used to UNIX makes, or NDMAKE. It is +# Microsoft nmake specific, and it gets around the problem of the +# link command line being too long for the linker. An "in-line" linker # response file is generated temporarily. # # It takes advantage of the following features of nmake: # -# Inline files : +# Inline files : # Specifying the "<<" means to start an inline file. -# Another "<<" at the start of a line closes the +# Another "<<" at the start of a line closes the # inline file. # # Substitution within Macros: # $(mymacro:string1=string2) replaces every -# occurrence of string1 with string2 in the -# macro mymacro. Special ascii key codes may be -# used in the substitution text by preceding it +# occurrence of string1 with string2 in the +# macro mymacro. Special ascii key codes may be +# used in the substitution text by preceding it # with ^ as we have done below. Every occurence -# of a in $(ALLOBJ) is replaced by +# of a in $(ALLOBJ) is replaced by # <+>. GAMEOBJ=$(ALLOBJ:^ =^ @@ -888,7 +892,7 @@ GAMEOBJ=$(GAMEOBJ:^ =^ # libs: $(LIBS) $(conlibs) $(guilibs) $(COMCTRL) # objs: $(GAMEOBJ) $(TTYOBJ) $(O)nttty.o $(O)tile.o $(GUIOBJ) # otherwise: -# libs: $(LIBS) $(conlibs) +# libs: $(LIBS) $(conlibs) # objs: $(GAMEOBJ) $(TTYOBJ) $(O)tile.o $(O)guistub.o @@ -1026,11 +1030,11 @@ $(O)sp_lev.tag: echo sp_levs done > $(O)sp_lev.tag $(O)utility.tag: $(INCL)\nhlua.h $(INCL)\date.h $(INCL)\onames.h $(INCL)\pm.h \ - $(SRC)\vis_tab.c $(INCL)\vis_tab.h $(TILEUTIL16) + $(TILEUTIL16) @echo utilities made >$@ @echo utilities made. -$(INCL)\nhlua.h: +$(INCL)\nhlua.h: @echo /* nhlua.h - generated by Makefile */ > $@ @echo #include "../lib/lua-$(LUAVER)/src/lua.h" >> $@ @echo LUA_API int (lua_error) (lua_State *L) NORETURN; >> $@ @@ -1053,7 +1057,7 @@ $(O)console.res: $(MSWSYS)\console.rc $(MSWSYS)\NetHack.ico # # Secondary Targets. # - + #========================================== # Makedefs Stuff #========================================== @@ -1062,7 +1066,7 @@ $(U)nhsizes3.exe: $(O)nhsizes3.o $(link) $(lflagsBuild) -out:$@ $(O)nhsizes.o $(O)panic$(HOST).o $(O)alloc$(HOST).o $(O)nhsizes3.o: $(CONFIG_H) nhsizes3.c - @$(cc) $(cflagsBuild) $(CROSSCOMPILE) $(CROSSCOMPILE_HOST) -Fo$@ nhsizes3.c + @$(cc) $(cflagsBuild) $(CROSSCOMPILE) -Fo$@ nhsizes3.c $(U)makedefs.exe: $(MAKEDEFSOBJS) @echo Linking $(@:\=/) @@ -1075,8 +1079,8 @@ $(O)makedefs.o: $(U)makedefs.c $(SRC)\mdlib.c $(CONFIG_H) $(INCL)\permonst.h \ $(INCL)\dlb.h @if not exist $(OBJ)\*.* echo creating directory $(OBJ:\=/) @if not exist $(OBJ)\*.* mkdir $(OBJ) - @$(cc) -DENUM_PM $(cflagsBuild) $(CROSSCOMPILE) $(CROSSCOMPILE_HOST) -Fo$@ $(U)makedefs.c -# @$(cc) -DENUM_PM $(cflagsBuild) $(CROSSCOMPILE) $(CROSSCOMPILE_HOST) /EP -Fo$@ $(U)makedefs.c >makedefs.c.preprocessed + @$(cc) -DENUM_PM $(cflagsBuild) $(CROSSCOMPILE) -Fo$@ $(U)makedefs.c +# @$(cc) -DENUM_PM $(cflagsBuild) $(CROSSCOMPILE) /EP -Fo$@ $(U)makedefs.c >makedefs.c.preprocessed # # date.h should be remade every time any of the source or include @@ -1092,12 +1096,6 @@ $(INCL)\onames.h : $(U)makedefs.exe $(INCL)\pm.h : $(U)makedefs.exe $(U)makedefs -p -$(INCL)\vis_tab.h: $(U)makedefs.exe - $(U)makedefs -z - -$(SRC)\vis_tab.c: $(U)makedefs.exe - $(U)makedefs -z - #========================================== # uudecode utility and uuencoded targets #========================================== @@ -1107,14 +1105,14 @@ $(U)uudecode.exe: $(O)uudecode.o @$(link) $(lflagsBuild) /PDB:"$(O)$(@B).PDB" /MAP:"$(O)$(@B).MAP" -out:$@ $(O)uudecode.o $(O)uudecode.o: $(SSYS)\uudecode.c - @$(cc) $(cflagsBuild) $(CROSSCOMPILE) $(CROSSCOMPILE_HOST) /D_CRT_SECURE_NO_DEPRECATE -Fo$@ $(SSYS)\uudecode.c + @$(cc) $(cflagsBuild) $(CROSSCOMPILE) /D_CRT_SECURE_NO_DEPRECATE -Fo$@ $(SSYS)\uudecode.c -$(MSWSYS)\NetHack.ico : $(U)uudecode.exe $(MSWSYS)\nhico.uu +$(MSWSYS)\NetHack.ico : $(U)uudecode.exe $(MSWSYS)\nhico.uu chdir $(MSWSYS) ..\..\util\uudecode.exe nhico.uu chdir ..\..\src -$(MSWIN)\NetHack.ico : $(U)uudecode.exe $(MSWSYS)\nhico.uu +$(MSWIN)\NetHack.ico : $(U)uudecode.exe $(MSWSYS)\nhico.uu chdir $(MSWIN) ..\..\util\uudecode.exe ../../sys/winnt/nhico.uu chdir ..\..\src @@ -1190,6 +1188,32 @@ $(O)envchk.tag: $(O)obj.tag #========================================== #=========== SECONDARY TARGETS ============ #========================================== +fetch-lua: fetch-actual-Lua + +fetch-Lua: fetch-actual-Lua + +fetch-actual-Lua: + @if not exist ..\lib\*.* mkdir ..\lib + cd ..\lib + 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 ..\lib\lua-$(LUAVER) + +fetch-pdcurses: + @if not exist ..\lib\*.* mkdir ..\lib + cd ..\lib + curl -L -R https://codeload.github.com/wmcbrine/PDCurses/zip/master -o pdcurses.zip + powershell -command "Expand-Archive -Path .\pdcurses.zip -DestinationPath ./pdcurses-temp" + if exist .\pdcurses\* rd .\pdcurses /s /Q + move .\pdcurses-temp\PDCurses-master . + ren PDCurses-master pdcurses + if exist .\pdcurses-temp\* rd .\pdcurses-temp /s /Q + if exist .\pdcurses.zip del .\pdcurses.zip + cd ..\src + @echo pdcurses has been fetched into ..\lib\pdcurses #========================================== # DLB utility and nhdatNNN file creation @@ -1206,7 +1230,7 @@ $(U)dlb.exe: $(DLBOBJ_HOST) $(O)dlb$(HOST).o !IFDEF TEST_CROSSCOMPILE $(O)dlb$(HOST).o: $(O)dlb_main$(HOST).o $(O)alloc$(HOST).o $(O)panic$(HOST).o $(INCL)\dlb.h - @$(cc) $(cflagsBuild) $(CROSSCOMPILE) $(CROSSCOMPILE_HOST) /Fo$@ $(SRC)\dlb.c + @$(cc) $(cflagsBuild) $(CROSSCOMPILE) /Fo$@ $(SRC)\dlb.c !ENDIF $(O)dlb.o: $(O)dlb_main.o $(O)alloc.o $(O)panic.o $(INCL)\dlb.h @@ -1214,7 +1238,7 @@ $(O)dlb.o: $(O)dlb_main.o $(O)alloc.o $(O)panic.o $(INCL)\dlb.h !IFDEF TEST_CROSSCOMPILE $(O)dlb_main$(HOST).o: $(UTIL)\dlb_main.c $(INCL)\config.h $(INCL)\dlb.h - @$(cc) $(cflagsBuild) $(CROSSCOMPILE) $(CROSSCOMPILE_HOST) /Fo$@ $(UTIL)\dlb_main.c + @$(cc) $(cflagsBuild) $(CROSSCOMPILE) /Fo$@ $(UTIL)\dlb_main.c !ENDIF $(O)dlb_main.o: $(UTIL)\dlb_main.c $(INCL)\config.h $(INCL)\dlb.h @@ -1275,28 +1299,28 @@ $(U)tilemap.exe: $(O)tilemap.o @$(link) $(lflagsBuild) /PDB:"$(O)$(@B).PDB" /MAP:"$(O)$(@B).MAP" -out:$@ $(O)tilemap.o $(O)tilemap.o: $(WSHR)\tilemap.c $(HACK_H) - @$(cc) $(cflagsBuild) $(CROSSCOMPILE) $(CROSSCOMPILE_HOST) -Fo$@ $(WSHR)\tilemap.c + @$(cc) $(cflagsBuild) $(CROSSCOMPILE) -Fo$@ $(WSHR)\tilemap.c $(O)tiletx32.o: $(WSHR)\tilemap.c $(HACK_H) - @$(cc) $(cflagsBuild) $(CROSSCOMPILE) $(CROSSCOMPILE_HOST) /DTILETEXT /DTILE_X=32 /DTILE_Y=32 -Fo$@ $(WSHR)\tilemap.c + @$(cc) $(cflagsBuild) $(CROSSCOMPILE) /DTILETEXT /DTILE_X=32 /DTILE_Y=32 -Fo$@ $(WSHR)\tilemap.c $(O)tiletxt.o: $(WSHR)\tilemap.c $(HACK_H) - @$(cc) $(cflagsBuild) $(CROSSCOMPILE) $(CROSSCOMPILE_HOST) /DTILETEXT -Fo$@ $(WSHR)\tilemap.c + @$(cc) $(cflagsBuild) $(CROSSCOMPILE) /DTILETEXT -Fo$@ $(WSHR)\tilemap.c $(O)gifread.o: $(WSHR)\gifread.c $(CONFIG_H) $(TILE_H) - @$(cc) $(cflagsBuild) $(CROSSCOMPILE) $(CROSSCOMPILE_HOST) -I$(WSHR) -Fo$@ $(WSHR)\gifread.c + @$(cc) $(cflagsBuild) $(CROSSCOMPILE) -I$(WSHR) -Fo$@ $(WSHR)\gifread.c $(O)gifrd32.o: $(WSHR)\gifread.c $(CONFIG_H) $(TILE_H) - @$(cc) $(cflagsBuild) $(CROSSCOMPILE) $(CROSSCOMPILE_HOST) -I$(WSHR) /DTILE_X=32 /DTILE_Y=32 -Fo$@ $(WSHR)\gifread.c + @$(cc) $(cflagsBuild) $(CROSSCOMPILE) -I$(WSHR) /DTILE_X=32 /DTILE_Y=32 -Fo$@ $(WSHR)\gifread.c $(O)ppmwrite.o: $(WSHR)\ppmwrite.c $(CONFIG_H) $(TILE_H) - @$(cc) $(cflagsBuild) $(CROSSCOMPILE) $(CROSSCOMPILE_HOST) -I$(WSHR) -Fo$@ $(WSHR)\ppmwrite.c + @$(cc) $(cflagsBuild) $(CROSSCOMPILE) -I$(WSHR) -Fo$@ $(WSHR)\ppmwrite.c $(O)tiletext.o: $(WSHR)\tiletext.c $(CONFIG_H) $(TILE_H) - @$(cc) $(cflagsBuild) $(CROSSCOMPILE) $(CROSSCOMPILE_HOST) -I$(WSHR) -Fo$@ $(WSHR)\tiletext.c + @$(cc) $(cflagsBuild) $(CROSSCOMPILE) -I$(WSHR) -Fo$@ $(WSHR)\tiletext.c $(O)tilete32.o: $(WSHR)\tiletext.c $(CONFIG_H) $(TILE_H) - @$(cc) $(cflagsBuild) $(CROSSCOMPILE) $(CROSSCOMPILE_HOST) -I$(WSHR) /DTILE_X=32 /DTILE_Y=32 -Fo$@ $(WSHR)\tiletext.c + @$(cc) $(cflagsBuild) $(CROSSCOMPILE) -I$(WSHR) /DTILE_X=32 /DTILE_Y=32 -Fo$@ $(WSHR)\tiletext.c #========================================== # Optional Tile Utilities @@ -1355,10 +1379,34 @@ $(U)til2bm32.exe: $(O)til2bm32.o $(TEXT_IO32) << $(O)tile2bmp.o: $(WSHR)\tile2bmp.c $(HACK_H) $(TILE_H) $(MSWSYS)\win32api.h - @$(cc) $(cflagsBuild) $(CROSSCOMPILE) $(CROSSCOMPILE_HOST) -I$(WSHR) /DPACKED_FILE /Fo$@ $(WSHR)\tile2bmp.c + @$(cc) $(cflagsBuild) $(CROSSCOMPILE) -I$(WSHR) /DPACKED_FILE /Fo$@ $(WSHR)\tile2bmp.c $(O)til2bm32.o: $(WSHR)\tile2bmp.c $(HACK_H) $(TILE_H) $(MSWSYS)\win32api.h - @$(cc) $(cflagsBuild) $(CROSSCOMPILE) $(CROSSCOMPILE_HOST) -I$(WSHR) /DPACKED_FILE /DTILE_X=32 /DTILE_Y=32 /Fo$@ $(WSHR)\tile2bmp.c + @$(cc) $(cflagsBuild) $(CROSSCOMPILE) -I$(WSHR) /DPACKED_FILE /DTILE_X=32 /DTILE_Y=32 /Fo$@ $(WSHR)\tile2bmp.c + +$(U)tile2x11.exe: $(O)tile2x11.o $(O)tiletext.o $(O)tiletxt.o $(O)alloc.o \ + $(O)panic.o $(O)monst.o $(O)objects.o + @echo Linking $(@:\=/) + @$(link) $(lflagsBuild) /PDB:"$(O)$(@B).PDB" /MAP:"$(O)$(@B).MAP" -out:$@ @<<$(@B).lnk + $(O)tile2x11.o + $(O)tiletext.o + $(O)tiletxt.o + $(O)drawing.o + $(O)monst.o + $(O)objects.o + $(O)alloc.o + $(O)panic.o +<< + +$(O)tile2x11.o: $(X11)\tile2x11.c $(HACK_H) $(TILE_H) $(INCL)\tile2x11.h + @$(cc) $(cflagsBuild) $(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 #=============================================================================== # PDCurses @@ -1466,7 +1514,7 @@ $(O)curswins.o: $(WCURSES)\curswins.c $(WCURSES)\curswins.h $(INCL)\wincurs.h $(O)sfstruct.o: $(HACK_H) $(SRC)\sfstruct.c # @$(cc) $(cflagsBuild) -Fo$@ $(SRC)\sfstruct.c - + #=============================================================================== # CROSSCOMPILE #=============================================================================== @@ -1483,7 +1531,7 @@ $(O)sfstruct.o: $(HACK_H) $(SRC)\sfstruct.c !IFDEF TEST_CROSSCOMPILE $(O)mdlib$(HOST).o: $(SRC)\mdlib.c - @$(cc) $(cflagsBuild) $(CROSSCOMPILE) $(CROSSCOMPILE_HOST) -Fo$@ $(SRC)\mdlib.c + @$(cc) $(cflagsBuild) $(CROSSCOMPILE) -Fo$@ $(SRC)\mdlib.c !ENDIF $(O)mdlib.o: $(SRC)\mdlib.c @@ -1497,15 +1545,16 @@ $(O)mdlib.o: $(SRC)\mdlib.c # These have dual-roles and need to be build for host and target platforms. # $(O)panic_host.o: $(U)panic.c $(CONFIG_H) - @$(cc) $(cflagsBuild) $(CROSSCOMPILE) $(CROSSCOMPILE_HOST) -Fo$@ $(U)panic.c + @$(cc) $(cflagsBuild) $(CROSSCOMPILE) -Fo$@ $(U)panic.c $(O)panic.o: $(U)panic.c $(CONFIG_H) @$(cc) $(cflagsBuild) -Fo$@ $(U)panic.c $(O)drawing_host.o: drawing.c $(CONFIG_H) - @$(cc) $(cflagsBuild) $(CROSSCOMPILE) $(CROSSCOMPILE_HOST) -Fo$@ drawing.c + @$(cc) $(cflagsBuild) $(CROSSCOMPILE) -Fo$@ drawing.c -$(O)drawing.o: drawing.c $(CONFIG_H) +$(O)drawing.o: drawing.c $(CONFIG_H) $(INCL)\color.h $(INCL)\rm.h \ + $(INCL)\objclass.h $(INCL)\monsym.h @$(cc) $(cflagsBuild) -Fo$@ drawing.c $(O)monst_host.o: monst.c $(CONFIG_H) $(INCL)\permonst.h $(INCL)\align.h \ @@ -1575,8 +1624,6 @@ spotless: clean 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 $(INCL)\vis_tab.h del $(INCL)\vis_tab.h - if exist $(SRC)\vis_tab.c del $(SRC)\vis_tab.c if exist $(SRC)\tile.c del $(SRC)\tile.c if exist $(U)*.lnk del $(U)*.lnk if exist $(U)*.map del $(U)*.map @@ -1588,7 +1635,6 @@ spotless: clean if exist $(DAT)\dlb.lst del $(DAT)\dlb.lst if exist $(DAT)\porthelp del $(DAT)\porthelp if exist $(O)sp_lev.tag del $(O)sp_lev.tag - if exist $(SRC)\vis_tab.c del $(SRC)\vis_tab.c if exist nhdat$(NHV). del nhdat$(NHV). if exist $(O)obj.tag del $(O)obj.tag if exist $(O)gamedir.tag del $(O)gamedir.tag @@ -1660,10 +1706,10 @@ clean: # OTHER DEPENDENCIES #=================================================================== # -# The rest are stolen from sys/unix/Makefile.src, +# The rest are stolen from sys/unix/Makefile.src, # with the following changes: # * ../include changed to $(INCL) -# * slashes changed to back-slashes +# * slashes changed to back-slashes # * -c (which is included in CFLAGS) substituted with -Fo$@ # * $(CFLAGS) replaced with $(cflagsBuild) # * $(CC) replaced with @$(cc) @@ -1675,8 +1721,6 @@ clean: # That means that there is some irrelevant stuff # in here, but maintenance should be easier. # -$(O)tos.o: ..\sys\atari\tos.c $(HACK_H) $(INCL)\tcap.h -# @$(cc) $(cflagsBuild) -Fo$@ ..\sys\atari\tos.c $(O)pcmain.o: ..\sys\share\pcmain.c $(HACK_H) $(INCL)\dlb.h # @$(cc) $(cflagsBuild) -Fo$@ ..\sys\share\pcmain.c $(O)pcsys.o: ..\sys\share\pcsys.c $(HACK_H) @@ -1735,231 +1779,155 @@ $(O)cursmesg.o: ..\win\curses\cursmesg.c $(HACK_H) $(INCL)\wincurs.h \ $(O)cursinvt.o: ..\win\curses\cursinvt.c $(HACK_H) $(INCL)\wincurs.h \ ..\win\curses\cursinvt.h # @$(cc) $(cflagsBuild) -Fo$@ ..\win\curses\cursinvt.c -#$(O)Window.o: ..\win\X11\Window.c $(INCL)\xwindowp.h $(INCL)\xwindow.h \ +#$(O)Window.o: $(X11)\Window.c $(INCL)\xwindowp.h $(INCL)\xwindow.h \ # $(CONFIG_H) $(INCL)\lint.h -# @$(cc) $(cflagsBuild) $(X11CFLAGS) -Fo$@ ..\win\X11\Window.c -$(O)dialogs.o: ..\win\X11\dialogs.c $(CONFIG_H) $(INCL)\lint.h -# @$(cc) $(cflagsBuild) $(X11CFLAGS) -Fo$@ ..\win\X11\dialogs.c -$(O)winX.o: ..\win\X11\winX.c $(HACK_H) $(INCL)\winX.h $(INCL)\dlb.h \ - $(INCL)\xwindow.h ..\win\X11\nh72icon ..\win\X11\nh56icon \ - ..\win\X11\nh32icon -# @$(cc) $(cflagsBuild) $(X11CFLAGS) -Fo$@ ..\win\X11\winX.c -$(O)winmap.o: ..\win\X11\winmap.c $(INCL)\xwindow.h $(HACK_H) $(INCL)\dlb.h \ +# @$(cc) $(cflagsBuild) $(X11CFLAGS) -Fo$@ $(X11)\Window.c +$(O)dialogs.o: $(X11)\dialogs.c $(CONFIG_H) $(INCL)\lint.h +# @$(cc) $(cflagsBuild) $(X11CFLAGS) -Fo$@ $(X11)\dialogs.c +$(O)winX.o: $(X11)\winX.c $(HACK_H) $(INCL)\winX.h $(INCL)\dlb.h \ + $(INCL)\xwindow.h $(X11)\nh72icon $(X11)\nh56icon \ + $(X11)\nh32icon +# @$(cc) $(cflagsBuild) $(X11CFLAGS) -Fo$@ $(X11)\winX.c +$(O)winmap.o: $(X11)\winmap.c $(INCL)\xwindow.h $(HACK_H) $(INCL)\dlb.h \ $(INCL)\winX.h $(INCL)\tile2x11.h -# @$(cc) $(cflagsBuild) $(X11CFLAGS) -Fo$@ ..\win\X11\winmap.c -$(O)winmenu.o: ..\win\X11\winmenu.c $(HACK_H) $(INCL)\winX.h -# @$(cc) $(cflagsBuild) $(X11CFLAGS) -Fo$@ ..\win\X11\winmenu.c -$(O)winmesg.o: ..\win\X11\winmesg.c $(INCL)\xwindow.h $(HACK_H) $(INCL)\winX.h -# @$(cc) $(cflagsBuild) $(X11CFLAGS) -Fo$@ ..\win\X11\winmesg.c -$(O)winmisc.o: ..\win\X11\winmisc.c $(HACK_H) $(INCL)\func_tab.h \ +# @$(cc) $(cflagsBuild) $(X11CFLAGS) -Fo$@ $(X11)\winmap.c +$(O)winmenu.o: $(X11)\winmenu.c $(HACK_H) $(INCL)\winX.h +# @$(cc) $(cflagsBuild) $(X11CFLAGS) -Fo$@ $(X11)\winmenu.c +$(O)winmesg.o: $(X11)\winmesg.c $(INCL)\xwindow.h $(HACK_H) $(INCL)\winX.h +# @$(cc) $(cflagsBuild) $(X11CFLAGS) -Fo$@ $(X11)\winmesg.c +$(O)winmisc.o: $(X11)\winmisc.c $(HACK_H) $(INCL)\func_tab.h \ $(INCL)\winX.h -# @$(cc) $(cflagsBuild) $(X11CFLAGS) -Fo$@ ..\win\X11\winmisc.c -$(O)winstat.o: ..\win\X11\winstat.c $(HACK_H) $(INCL)\winX.h $(INCL)\xwindow.h -# @$(cc) $(cflagsBuild) $(X11CFLAGS) -Fo$@ ..\win\X11\winstat.c -$(O)wintext.o: ..\win\X11\wintext.c $(HACK_H) $(INCL)\winX.h $(INCL)\xwindow.h -# @$(cc) $(cflagsBuild) $(X11CFLAGS) -Fo$@ ..\win\X11\wintext.c -$(O)winval.o: ..\win\X11\winval.c $(HACK_H) $(INCL)\winX.h -# @$(cc) $(cflagsBuild) $(X11CFLAGS) -Fo$@ ..\win\X11\winval.c -$(O)tile.o: $(SRC)\tile.c $(HACK_H) -$(O)gnaskstr.o: ..\win\gnome\gnaskstr.c ..\win\gnome\gnaskstr.h \ - ..\win\gnome\gnmain.h -# @$(cc) $(cflagsBuild) $(GNOMEINC) -Fo$@ ..\win\gnome\gnaskstr.c -$(O)gnbind.o: ..\win\gnome\gnbind.c ..\win\gnome\gnbind.h ..\win\gnome\gnomeprv.h \ - $(HACK_H) $(INCL)\dlb.h \ - $(INCL)\winGnome.h ..\win\gnome\gnmain.h \ - ..\win\gnome\gnmap.h ..\win\gnome\gnmenu.h \ - ..\win\gnome\gnplayer.h ..\win\gnome\gnsignal.h \ - ..\win\gnome\gnglyph.h ..\win\gnome\gnstatus.h \ - ..\win\gnome\gntext.h ..\win\gnome\gnmesg.h \ - ..\win\gnome\gnyesno.h ..\win\gnome\gnworn.h \ - ..\win\gnome\gnaskstr.h -# @$(cc) $(cflagsBuild) $(GNOMEINC) -Fo$@ ..\win\gnome\gnbind.c -$(O)gnglyph.o: ..\win\gnome\gnglyph.c ..\win\gnome\gnglyph.h $(CONFIG_H) \ - $(INCL)\tile2x11.h -# @$(cc) $(cflagsBuild) $(GNOMEINC) -Fo$@ ..\win\gnome\gnglyph.c -$(O)gnmain.o: ..\win\gnome\gnmain.c ..\win\gnome\gnmain.h ..\win\gnome\gnsignal.h \ - ..\win\gnome\gnomeprv.h $(HACK_H) $(INCL)\dlb.h \ - $(INCL)\winGnome.h \ - ..\win\gnome\gnglyph.h ..\win\gnome\gnbind.h \ - ..\win\gnome\gnmap.h ..\win\gnome\gnmenu.h \ - ..\win\gnome\gnplayer.h ..\win\gnome\gnstatus.h \ - ..\win\gnome\gntext.h ..\win\gnome\gnmesg.h \ - ..\win\gnome\gnyesno.h ..\win\gnome\gnworn.h \ - ..\win\gnome\gnopts.h $(INCL)\date.h -# @$(cc) $(cflagsBuild) $(GNOMEINC) -Fo$@ ..\win\gnome\gnmain.c -$(O)gnmap.o: ..\win\gnome\gnmap.c ..\win\gnome\gnmap.h $(CONFIG_H) \ - ..\win\gnome\gnglyph.h ..\win\gnome\gnsignal.h \ - ..\win\gnome\gnomeprv.h $(HACK_H) $(INCL)\dlb.h \ - $(INCL)\winGnome.h -# @$(cc) $(cflagsBuild) $(GNOMEINC) -Fo$@ ..\win\gnome\gnmap.c -$(O)gnmenu.o: ..\win\gnome\gnmenu.c ..\win\gnome\gnmenu.h $(CONFIG_H) \ - ..\win\gnome\gnomeprv.h $(HACK_H) $(INCL)\dlb.h \ - $(INCL)\winGnome.h \ - ..\win\gnome\gnmain.h ..\win\gnome\gnbind.h \ - ..\win\gnome\gnmap.h ..\win\gnome\gnplayer.h \ - ..\win\gnome\gnsignal.h ..\win\gnome\gnglyph.h \ - ..\win\gnome\gnstatus.h ..\win\gnome\gntext.h \ - ..\win\gnome\gnmesg.h ..\win\gnome\gnyesno.h \ - ..\win\gnome\gnworn.h $(INCL)\func_tab.h -# @$(cc) $(cflagsBuild) $(GNOMEINC) -Fo$@ ..\win\gnome\gnmenu.c -$(O)gnmesg.o: ..\win\gnome\gnmesg.c ..\win\gnome\gnmesg.h $(CONFIG_H) \ - ..\win\gnome\gnsignal.h ..\win\gnome\gnomeprv.h $(HACK_H) \ - $(INCL)\dlb.h $(INCL)\winGnome.h \ - ..\win\gnome\gnglyph.h -# @$(cc) $(cflagsBuild) $(GNOMEINC) -Fo$@ ..\win\gnome\gnmesg.c -$(O)gnopts.o: ..\win\gnome\gnopts.c ..\win\gnome\gnopts.h ..\win\gnome\gnglyph.h \ - $(CONFIG_H) ..\win\gnome\gnmain.h ..\win\gnome\gnmap.h $(HACK_H) -# @$(cc) $(cflagsBuild) $(GNOMEINC) -Fo$@ ..\win\gnome\gnopts.c -$(O)gnplayer.o: ..\win\gnome\gnplayer.c ..\win\gnome\gnplayer.h \ - ..\win\gnome\gnmain.h $(HACK_H) -# @$(cc) $(cflagsBuild) $(GNOMEINC) -Fo$@ ..\win\gnome\gnplayer.c -$(O)gnsignal.o: ..\win\gnome\gnsignal.c ..\win\gnome\gnsignal.h \ - ..\win\gnome\gnomeprv.h $(HACK_H) $(INCL)\dlb.h \ - $(INCL)\winGnome.h \ - ..\win\gnome\gnglyph.h ..\win\gnome\gnmain.h -# @$(cc) $(cflagsBuild) $(GNOMEINC) -Fo$@ ..\win\gnome\gnsignal.c -$(O)gnstatus.o: ..\win\gnome\gnstatus.c ..\win\gnome\gnstatus.h $(CONFIG_H) \ - ..\win\gnome\gnsignal.h ..\win\gnome\gnomeprv.h $(HACK_H) \ - $(INCL)\dlb.h $(INCL)\winGnome.h \ - ..\win\gnome\gnglyph.h ..\win\gnome\gn_xpms.h -# @$(cc) $(cflagsBuild) $(GNOMEINC) -Fo$@ ..\win\gnome\gnstatus.c -$(O)gntext.o: ..\win\gnome\gntext.c ..\win\gnome\gntext.h $(CONFIG_H) \ - ..\win\gnome\gnmain.h ..\win\gnome\gn_rip.h -# @$(cc) $(cflagsBuild) $(GNOMEINC) -Fo$@ ..\win\gnome\gntext.c -$(O)gnyesno.o: ..\win\gnome\gnyesno.c ..\win\gnome\gnbind.h \ - ..\win\gnome\gnomeprv.h $(HACK_H) $(INCL)\dlb.h \ - $(INCL)\winGnome.h \ - ..\win\gnome\gnmain.h ..\win\gnome\gnmap.h \ - ..\win\gnome\gnmenu.h ..\win\gnome\gnplayer.h \ - ..\win\gnome\gnsignal.h ..\win\gnome\gnglyph.h \ - ..\win\gnome\gnstatus.h ..\win\gnome\gntext.h \ - ..\win\gnome\gnmesg.h ..\win\gnome\gnyesno.h \ - ..\win\gnome\gnworn.h -# @$(cc) $(cflagsBuild) $(GNOMEINC) -Fo$@ ..\win\gnome\gnyesno.c -$(O)gnworn.o: ..\win\gnome\gnworn.c ..\win\gnome\gnworn.h $(CONFIG_H) \ - ..\win\gnome\gnglyph.h ..\win\gnome\gnsignal.h \ - ..\win\gnome\gnomeprv.h $(HACK_H) $(INCL)\dlb.h \ - $(INCL)\winGnome.h -# @$(cc) $(cflagsBuild) $(GNOMEINC) -Fo$@ ..\win\gnome\gnworn.c -$(O)wingem.o: ..\win\gem\wingem.c $(HACK_H) $(INCL)\func_tab.h $(INCL)\dlb.h \ - $(INCL)\wingem.h -# @$(cc) $(cflagsBuild) -Fo$@ ..\win\gem\wingem.c -$(O)wingem1.o: ..\win\gem\wingem1.c $(INCL)\gem_rsc.h $(INCL)\load_img.h \ - $(INCL)\gr_rect.h $(INCL)\wintype.h $(INCL)\wingem.h -# @$(cc) $(cflagsBuild) -Fo$@ ..\win\gem\wingem1.c -$(O)load_img.o: ..\win\gem\load_img.c $(INCL)\load_img.h -# @$(cc) $(cflagsBuild) -Fo$@ ..\win\gem\load_img.c -$(O)gr_rect.o: ..\win\gem\gr_rect.c $(INCL)\gr_rect.h -# @$(cc) $(cflagsBuild) -Fo$@ ..\win\gem\gr_rect.c +# @$(cc) $(cflagsBuild) $(X11CFLAGS) -Fo$@ $(X11)\winmisc.c +$(O)winstat.o: $(X11)\winstat.c $(HACK_H) $(INCL)\winX.h $(INCL)\xwindow.h +# @$(cc) $(cflagsBuild) $(X11CFLAGS) -Fo$@ $(X11)\winstat.c +$(O)wintext.o: $(X11)\wintext.c $(HACK_H) $(INCL)\winX.h $(INCL)\xwindow.h +# @$(cc) $(cflagsBuild) $(X11CFLAGS) -Fo$@ $(X11)\wintext.c +$(O)winval.o: $(X11)\winval.c $(HACK_H) $(INCL)\winX.h +# @$(cc) $(cflagsBuild) $(X11CFLAGS) -Fo$@ $(X11)\winval.c $(O)tile.o: $(SRC)\tile.c $(HACK_H) #cppregex.o: ..\sys\share\cppregex.cpp # $(CXX) $(CXXFLAGS) -Fo$@ ..\sys\share\cppregex.cpp -$(O)qt_bind.o: ..\win\Qt\qt_bind.cpp $(HACK_H) ..\win\Qt\qt_bind.h \ - ..\win\Qt\qt_main.h ..\win\Qt\qt_kde0.h ..\win\Qt\qt_click.h \ - ..\win\Qt\qt_delay.h ..\win\Qt\qt_xcmd.h ..\win\Qt\qt_key.h \ - ..\win\Qt\qt_map.h ..\win\Qt\qt_win.h ..\win\Qt\qt_clust.h \ - ..\win\Qt\qt_menu.h ..\win\Qt\qt_rip.h ..\win\Qt\qt_msg.h \ - ..\win\Qt\qt_plsel.h ..\win\Qt\qt_svsel.h ..\win\Qt\qt_set.h \ - ..\win\Qt\qt_stat.h ..\win\Qt\qt_icon.h ..\win\Qt\qt_streq.h \ - ..\win\Qt\qt_line.h ..\win\Qt\qt_yndlg.h ..\win\Qt\qt_str.h \ - $(INCL)\dlb.h - $(CXX) $(CXXFLAGS) -Fo$@ ..\win\Qt\qt_bind.cpp -$(O)qt_click.o: ..\win\Qt\qt_click.cpp $(HACK_H) ..\win\Qt\qt_click.h - $(CXX) $(CXXFLAGS) -Fo$@ ..\win\Qt\qt_click.cpp -$(O)qt_clust.o: ..\win\Qt\qt_clust.cpp ..\win\Qt\qt_clust.h - $(CXX) $(CXXFLAGS) -Fo$@ ..\win\Qt\qt_clust.cpp -$(O)qt_delay.o: ..\win\Qt\qt_delay.cpp $(HACK_H) ..\win\Qt\qt_delay.h - $(CXX) $(CXXFLAGS) -Fo$@ ..\win\Qt\qt_delay.cpp -$(O)qt_glyph.o: ..\win\Qt\qt_glyph.cpp $(HACK_H) $(INCL)\tile2x11.h \ - ..\win\Qt\qt_glyph.h ..\win\Qt\qt_set.h ..\win\Qt\qt_str.h - $(CXX) $(CXXFLAGS) -Fo$@ ..\win\Qt\qt_glyph.cpp -$(O)qt_icon.o: ..\win\Qt\qt_icon.cpp $(HACK_H) ..\win\Qt\qt_icon.h - $(CXX) $(CXXFLAGS) -Fo$@ ..\win\Qt\qt_icon.cpp -$(O)qt_inv.o: ..\win\Qt\qt_inv.cpp $(HACK_H) ..\win\Qt\qt_inv.h \ - ..\win\Qt\qt_glyph.h ..\win\Qt\qt_set.h - $(CXX) $(CXXFLAGS) -Fo$@ ..\win\Qt\qt_inv.cpp -$(O)qt_key.o: ..\win\Qt\qt_key.cpp $(HACK_H) ..\win\Qt\qt_key.h - $(CXX) $(CXXFLAGS) -Fo$@ ..\win\Qt\qt_key.cpp -$(O)qt_line.o: ..\win\Qt\qt_line.cpp $(HACK_H) ..\win\Qt\qt_line.h - $(CXX) $(CXXFLAGS) -Fo$@ ..\win\Qt\qt_line.cpp -$(O)qt_main.o: ..\win\Qt\qt_main.cpp $(HACK_H) \ - ..\win\Qt\qt_main.h ..\win\Qt\qt_kde0.h qt_main.moc \ - ..\win\Qt\qt_bind.h ..\win\Qt\qt_glyph.h ..\win\Qt\qt_inv.h \ - ..\win\Qt\qt_key.h ..\win\Qt\qt_map.h ..\win\Qt\qt_win.h \ - ..\win\Qt\qt_clust.h ..\win\Qt\qt_msg.h ..\win\Qt\qt_set.h \ - ..\win\Qt\qt_stat.h ..\win\Qt\qt_icon.h ..\win\Qt\qt_str.h \ - qt_kde0.moc - $(CXX) $(CXXFLAGS) -Fo$@ ..\win\Qt\qt_main.cpp -$(O)qt_map.o: ..\win\Qt\qt_map.cpp $(HACK_H) ..\win\Qt\qt_map.h ..\win\Qt\qt_win.h \ - ..\win\Qt\qt_clust.h qt_map.moc ..\win\Qt\qt_click.h \ - ..\win\Qt\qt_glyph.h ..\win\Qt\qt_xpms.h ..\win\Qt\qt_set.h \ - ..\win\Qt\qt_str.h - $(CXX) $(CXXFLAGS) -Fo$@ ..\win\Qt\qt_map.cpp -$(O)qt_menu.o: ..\win\Qt\qt_menu.cpp $(HACK_H) ..\win\Qt\qt_menu.h \ - ..\win\Qt\qt_win.h ..\win\Qt\qt_rip.h qt_menu.moc \ - ..\win\Qt\qt_glyph.h ..\win\Qt\qt_set.h ..\win\Qt\qt_streq.h \ - ..\win\Qt\qt_line.h ..\win\Qt\qt_str.h - $(CXX) $(CXXFLAGS) -Fo$@ ..\win\Qt\qt_menu.cpp -$(O)qt_msg.o: ..\win\Qt\qt_msg.cpp $(HACK_H) ..\win\Qt\qt_msg.h ..\win\Qt\qt_win.h \ - qt_msg.moc ..\win\Qt\qt_map.h ..\win\Qt\qt_clust.h \ - ..\win\Qt\qt_set.h ..\win\Qt\qt_str.h - $(CXX) $(CXXFLAGS) -Fo$@ ..\win\Qt\qt_msg.cpp -$(O)qt_plsel.o: ..\win\Qt\qt_plsel.cpp $(HACK_H) ..\win\Qt\qt_plsel.h qt_plsel.moc \ - ..\win\Qt\qt_bind.h ..\win\Qt\qt_main.h ..\win\Qt\qt_kde0.h \ - ..\win\Qt\qt_glyph.h ..\win\Qt\qt_set.h ..\win\Qt\qt_str.h - $(CXX) $(CXXFLAGS) -Fo$@ ..\win\Qt\qt_plsel.cpp -$(O)qt_rip.o: ..\win\Qt\qt_rip.cpp $(HACK_H) ..\win\Qt\qt_rip.h \ - ..\win\Qt\qt_bind.h ..\win\Qt\qt_main.h ..\win\Qt\qt_kde0.h \ - ..\win\Qt\qt_str.h - $(CXX) $(CXXFLAGS) -Fo$@ ..\win\Qt\qt_rip.cpp -$(O)qt_set.o: ..\win\Qt\qt_set.cpp $(HACK_H) ..\win\Qt\qt_set.h qt_set.moc \ - ..\win\Qt\qt_glyph.h ..\win\Qt\qt_str.h - $(CXX) $(CXXFLAGS) -Fo$@ ..\win\Qt\qt_set.cpp -$(O)qt_stat.o: ..\win\Qt\qt_stat.cpp $(HACK_H) ..\win\Qt\qt_stat.h \ - ..\win\Qt\qt_win.h ..\win\Qt\qt_icon.h qt_stat.moc \ - ..\win\Qt\qt_set.h ..\win\Qt\qt_str.h ..\win\Qt\qt_xpms.h - $(CXX) $(CXXFLAGS) -Fo$@ ..\win\Qt\qt_stat.cpp -$(O)qt_str.o: ..\win\Qt\qt_str.cpp ..\win\Qt\qt_str.h - $(CXX) $(CXXFLAGS) -Fo$@ ..\win\Qt\qt_str.cpp -$(O)qt_streq.o: ..\win\Qt\qt_streq.cpp $(HACK_H) ..\win\Qt\qt_streq.h \ - ..\win\Qt\qt_line.h ..\win\Qt\qt_str.h - $(CXX) $(CXXFLAGS) -Fo$@ ..\win\Qt\qt_streq.cpp -$(O)qt_svsel.o: ..\win\Qt\qt_svsel.cpp $(HACK_H) ..\win\Qt\qt_svsel.h \ - ..\win\Qt\qt_bind.h ..\win\Qt\qt_main.h ..\win\Qt\qt_kde0.h \ - ..\win\Qt\qt_str.h - $(CXX) $(CXXFLAGS) -Fo$@ ..\win\Qt\qt_svsel.cpp -$(O)qt_win.o: ..\win\Qt\qt_win.cpp $(HACK_H) ..\win\Qt\qt_win.h \ - ..\win\Qt\qt_bind.h ..\win\Qt\qt_main.h ..\win\Qt\qt_kde0.h \ - ..\win\Qt\qt_click.h ..\win\Qt\qt_glyph.h ..\win\Qt\qt_inv.h \ - ..\win\Qt\qt_key.h ..\win\Qt\qt_icon.h ..\win\Qt\qt_map.h \ - ..\win\Qt\qt_clust.h ..\win\Qt\qt_menu.h ..\win\Qt\qt_rip.h \ - ..\win\Qt\qt_msg.h ..\win\Qt\qt_set.h - $(CXX) $(CXXFLAGS) -Fo$@ ..\win\Qt\qt_win.cpp -$(O)qt_xcmd.o: ..\win\Qt\qt_xcmd.cpp $(HACK_H) $(INCL)\func_tab.h \ - ..\win\Qt\qt_xcmd.h qt_xcmd.moc ..\win\Qt\qt_bind.h \ - ..\win\Qt\qt_main.h ..\win\Qt\qt_kde0.h ..\win\Qt\qt_set.h \ - ..\win\Qt\qt_str.h - $(CXX) $(CXXFLAGS) -Fo$@ ..\win\Qt\qt_xcmd.cpp -$(O)qt_yndlg.o: ..\win\Qt\qt_yndlg.cpp $(HACK_H) ..\win\Qt\qt_yndlg.h qt_yndlg.moc \ - ..\win\Qt\qt_str.h - $(CXX) $(CXXFLAGS) -Fo$@ ..\win\Qt\qt_yndlg.cpp -$(O)qt3_win.o: ..\win\Qt3\qt3_win.cpp $(HACK_H) $(INCL)\func_tab.h \ - $(INCL)\dlb.h $(INCL)\tile2x11.h \ - ..\win\Qt3\qt3_win.h ..\win\Qt3\qt3_clust.h \ - ..\win\Qt3\qt3_kde0.h ..\win\Qt3\qt3_xpms.h qt3_win.moc \ - qt3_kde0.moc qt3tableview.moc - $(CXX) $(CXXFLAGS) -Fo$@ ..\win\Qt3\qt3_win.cpp -$(O)qt3_clust.o: ..\win\Qt3\qt3_clust.cpp ..\win\Qt3\qt3_clust.h - $(CXX) $(CXXFLAGS) -Fo$@ ..\win\Qt3\qt3_clust.cpp -$(O)qt3tableview.o: ..\win\Qt3\qt3tableview.cpp ..\win\Qt3\qt3tableview.h - $(CXX) $(CXXFLAGS) -Fo$@ ..\win\Qt3\qt3tableview.cpp +#--- +qt_bind.o: $(QT)\qt_bind.cpp $(HACK_H) $(QT)\qt_pre.h \ + $(QT)\qt_post.h $(QT)\qt_bind.h $(QT)\qt_main.h \ + $(QT)\qt_kde0.h $(QT)\qt_click.h $(QT)\qt_delay.h \ + $(QT)\qt_xcmd.h $(QT)\qt_key.h $(QT)\qt_map.h \ + $(QT)\qt_win.h $(QT)\qt_clust.h $(QT)\qt_menu.h \ + $(QT)\qt_rip.h $(QT)\qt_msg.h $(QT)\qt_plsel.h \ + $(QT)\qt_svsel.h $(QT)\qt_set.h $(QT)\qt_stat.h \ + $(QT)\qt_icon.h $(QT)\qt_streq.h $(QT)\qt_line.h \ + $(QT)\qt_yndlg.h $(QT)\qt_str.h $(INCL)\dlb.h + $(CXX) $(CXXFLAGS) -Fo$@ $(QT)\qt_bind.cpp +qt_click.o: $(QT)\qt_click.cpp $(HACK_H) $(QT)\qt_pre.h \ + $(QT)\qt_post.h $(QT)\qt_click.h + $(CXX) $(CXXFLAGS) -Fo$@ $(QT)\qt_click.cpp +qt_clust.o: $(QT)\qt_clust.cpp $(QT)\qt_clust.h + $(CXX) $(CXXFLAGS) -Fo$@ $(QT)\qt_clust.cpp +qt_delay.o: $(QT)\qt_delay.cpp $(HACK_H) $(QT)\qt_pre.h \ + $(QT)\qt_post.h $(QT)\qt_delay.h + $(CXX) $(CXXFLAGS) -Fo$@ $(QT)\qt_delay.cpp +qt_glyph.o: $(QT)\qt_glyph.cpp $(HACK_H) $(INCL)\tile2x11.h \ + $(QT)\qt_pre.h $(QT)\qt_post.h $(QT)\qt_glyph.h \ + $(QT)\qt_bind.h $(QT)\qt_main.h $(QT)\qt_kde0.h \ + $(QT)\qt_set.h $(QT)\qt_inv.h $(QT)\qt_map.h \ + $(QT)\qt_win.h $(QT)\qt_clust.h $(QT)\qt_str.h + $(CXX) $(CXXFLAGS) -Fo$@ $(QT)\qt_glyph.cpp +qt_icon.o: $(QT)\qt_icon.cpp $(HACK_H) $(QT)\qt_pre.h \ + $(QT)\qt_post.h $(QT)\qt_icon.h + $(CXX) $(CXXFLAGS) -Fo$@ $(QT)\qt_icon.cpp +qt_inv.o: $(QT)\qt_inv.cpp $(HACK_H) $(QT)\qt_pre.h \ + $(QT)\qt_post.h $(QT)\qt_inv.h $(QT)\qt_glyph.h \ + $(QT)\qt_set.h $(QT)\qt_bind.h $(QT)\qt_main.h \ + $(QT)\qt_kde0.h + $(CXX) $(CXXFLAGS) -Fo$@ $(QT)\qt_inv.cpp +qt_key.o: $(QT)\qt_key.cpp $(HACK_H) $(QT)\qt_pre.h \ + $(QT)\qt_post.h $(QT)\qt_key.h + $(CXX) $(CXXFLAGS) -Fo$@ $(QT)\qt_key.cpp +qt_line.o: $(QT)\qt_line.cpp $(HACK_H) $(QT)\qt_pre.h \ + $(QT)\qt_post.h $(QT)\qt_line.h + $(CXX) $(CXXFLAGS) -Fo$@ $(QT)\qt_line.cpp +qt_main.o: $(QT)\qt_main.cpp $(HACK_H) $(QT)\qt_pre.h \ + $(QT)\qt_post.h $(QT)\qt_main.h $(QT)\qt_kde0.h \ + qt_main.moc $(QT)\qt_bind.h $(QT)\qt_glyph.h \ + $(QT)\qt_inv.h $(QT)\qt_key.h $(QT)\qt_map.h \ + $(QT)\qt_win.h $(QT)\qt_clust.h $(QT)\qt_msg.h \ + $(QT)\qt_set.h $(QT)\qt_stat.h $(QT)\qt_icon.h \ + $(QT)\qt_str.h qt_kde0.moc + $(CXX) $(CXXFLAGS) -Fo$@ $(QT)\qt_main.cpp +qt_map.o: $(QT)\qt_map.cpp $(HACK_H) $(QT)\qt_pre.h \ + $(QT)\qt_post.h $(QT)\qt_map.h $(QT)\qt_win.h \ + $(QT)\qt_clust.h qt_map.moc $(QT)\qt_click.h \ + $(QT)\qt_glyph.h $(QT)\qt_xpms.h $(QT)\qt_set.h \ + $(QT)\qt_bind.h $(QT)\qt_main.h $(QT)\qt_kde0.h \ + $(QT)\qt_str.h + $(CXX) $(CXXFLAGS) -Fo$@ $(QT)\qt_map.cpp +qt_menu.o: $(QT)\qt_menu.cpp $(HACK_H) $(QT)\qt_pre.h \ + $(QT)\qt_post.h $(QT)\qt_menu.h $(QT)\qt_win.h \ + $(QT)\qt_rip.h qt_menu.moc $(QT)\qt_glyph.h \ + $(QT)\qt_set.h $(QT)\qt_bind.h $(QT)\qt_main.h \ + $(QT)\qt_kde0.h $(QT)\qt_streq.h $(QT)\qt_line.h \ + $(QT)\qt_str.h + $(CXX) $(CXXFLAGS) -Fo$@ $(QT)\qt_menu.cpp +qt_msg.o: $(QT)\qt_msg.cpp $(HACK_H) $(QT)\qt_pre.h \ + $(QT)\qt_post.h $(QT)\qt_msg.h $(QT)\qt_win.h \ + qt_msg.moc $(QT)\qt_map.h $(QT)\qt_clust.h \ + $(QT)\qt_set.h $(QT)\qt_bind.h $(QT)\qt_main.h \ + $(QT)\qt_kde0.h $(QT)\qt_str.h + $(CXX) $(CXXFLAGS) -Fo$@ $(QT)\qt_msg.cpp +qt_plsel.o: $(QT)\qt_plsel.cpp $(HACK_H) $(QT)\qt_pre.h \ + $(QT)\qt_post.h $(QT)\qt_plsel.h qt_plsel.moc \ + $(QT)\qt_bind.h $(QT)\qt_main.h $(QT)\qt_kde0.h \ + $(QT)\qt_glyph.h $(QT)\qt_set.h $(QT)\qt_str.h + $(CXX) $(CXXFLAGS) -Fo$@ $(QT)\qt_plsel.cpp +qt_rip.o: $(QT)\qt_rip.cpp $(HACK_H) $(QT)\qt_pre.h \ + $(QT)\qt_post.h $(QT)\qt_rip.h $(QT)\qt_bind.h \ + $(QT)\qt_main.h $(QT)\qt_kde0.h $(QT)\qt_str.h + $(CXX) $(CXXFLAGS) -Fo$@ $(QT)\qt_rip.cpp +qt_set.o: $(QT)\qt_set.cpp $(HACK_H) $(QT)\qt_pre.h \ + $(QT)\qt_post.h $(QT)\qt_set.h $(QT)\qt_bind.h \ + $(QT)\qt_main.h $(QT)\qt_kde0.h qt_set.moc \ + $(QT)\qt_glyph.h $(QT)\qt_str.h + $(CXX) $(CXXFLAGS) -Fo$@ $(QT)\qt_set.cpp +qt_stat.o: $(QT)\qt_stat.cpp $(HACK_H) $(QT)\qt_pre.h \ + $(QT)\qt_post.h $(QT)\qt_stat.h $(QT)\qt_win.h \ + $(QT)\qt_icon.h qt_stat.moc $(QT)\qt_set.h \ + $(QT)\qt_bind.h $(QT)\qt_main.h $(QT)\qt_kde0.h \ + $(QT)\qt_str.h $(QT)\qt_xpms.h + $(CXX) $(CXXFLAGS) -Fo$@ $(QT)\qt_stat.cpp +qt_str.o: $(QT)\qt_str.cpp $(QT)\qt_str.h + $(CXX) $(CXXFLAGS) -Fo$@ $(QT)\qt_str.cpp +qt_streq.o: $(QT)\qt_streq.cpp $(HACK_H) $(QT)\qt_pre.h \ + $(QT)\qt_post.h $(QT)\qt_streq.h $(QT)\qt_line.h \ + $(QT)\qt_str.h + $(CXX) $(CXXFLAGS) -Fo$@ $(QT)\qt_streq.cpp +qt_svsel.o: $(QT)\qt_svsel.cpp $(HACK_H) $(QT)\qt_pre.h \ + $(QT)\qt_post.h $(QT)\qt_svsel.h $(QT)\qt_bind.h \ + $(QT)\qt_main.h $(QT)\qt_kde0.h $(QT)\qt_str.h + $(CXX) $(CXXFLAGS) -Fo$@ $(QT)\qt_svsel.cpp +qt_win.o: $(QT)\qt_win.cpp $(HACK_H) $(QT)\qt_pre.h \ + $(QT)\qt_post.h $(QT)\qt_win.h $(QT)\qt_bind.h \ + $(QT)\qt_main.h $(QT)\qt_kde0.h $(QT)\qt_click.h \ + $(QT)\qt_glyph.h $(QT)\qt_inv.h $(QT)\qt_key.h \ + $(QT)\qt_icon.h $(QT)\qt_map.h $(QT)\qt_clust.h \ + $(QT)\qt_menu.h $(QT)\qt_rip.h $(QT)\qt_msg.h \ + $(QT)\qt_set.h + $(CXX) $(CXXFLAGS) -Fo$@ $(QT)\qt_win.cpp +qt_xcmd.o: $(QT)\qt_xcmd.cpp $(HACK_H) $(INCL)\func_tab.h \ + $(QT)\qt_pre.h $(QT)\qt_post.h $(QT)\qt_xcmd.h \ + qt_xcmd.moc $(QT)\qt_bind.h $(QT)\qt_main.h \ + $(QT)\qt_kde0.h $(QT)\qt_set.h $(QT)\qt_str.h + $(CXX) $(CXXFLAGS) -Fo$@ $(QT)\qt_xcmd.cpp +qt_yndlg.o: $(QT)\qt_yndlg.cpp $(HACK_H) $(QT)\qt_pre.h \ + $(QT)\qt_post.h $(QT)\qt_yndlg.h qt_yndlg.moc \ + $(QT)\qt_str.h + $(CXX) $(CXXFLAGS) -Fo$@ $(QT)\qt_yndlg.cpp +#---- $(O)wc_chainin.o: ..\win\chain\wc_chainin.c $(HACK_H) # @$(cc) $(cflagsBuild) -Fo$@ ..\win\chain\wc_chainin.c $(O)wc_chainout.o: ..\win\chain\wc_chainout.c $(HACK_H) # @$(cc) $(cflagsBuild) -Fo$@ ..\win\chain\wc_chainout.c $(O)wc_trace.o: ..\win\chain\wc_trace.c $(HACK_H) $(INCL)\func_tab.h # @$(cc) $(cflagsBuild) -Fo$@ ..\win\chain\wc_trace.c -$(O)vis_tab.o: vis_tab.c $(CONFIG_H) $(INCL)\vis_tab.h $(O)allmain.o: allmain.c $(HACK_H) $(O)alloc.o: alloc.c $(CONFIG_H) $(O)apply.o: apply.c $(HACK_H) @@ -1982,7 +1950,6 @@ $(O)dog.o: dog.c $(HACK_H) $(O)dogmove.o: dogmove.c $(HACK_H) $(INCL)\mfndpos.h $(O)dokick.o: dokick.c $(HACK_H) $(O)dothrow.o: dothrow.c $(HACK_H) -$(O)drawing.o: drawing.c $(CONFIG_H) $(O)dungeon.o: dungeon.c $(HACK_H) $(INCL)\dgn_file.h $(INCL)\dlb.h $(O)eat.o: eat.c $(HACK_H) $(O)end.o: end.c $(HACK_H) $(INCL)\dlb.h @@ -2078,7 +2045,7 @@ $(O)uhitm.o: uhitm.c $(HACK_H) $(O)vault.o: vault.c $(HACK_H) $(O)version.o: version.c $(HACK_H) $(INCL)\dlb.h $(INCL)\date.h @$(cc) $(cflagsBuild) $(CROSSCOMPILE) $(CROSSCOMPILE_TARGET) -Fo$@ version.c -$(O)vision.o: vision.c $(HACK_H) $(INCL)\vis_tab.h +$(O)vision.o: vision.c $(HACK_H) $(O)weapon.o: weapon.c $(HACK_H) $(O)were.o: were.c $(HACK_H) $(O)wield.o: wield.c $(HACK_H) diff --git a/sys/winnt/console.rc b/sys/winnt/console.rc index 427079ede..110e94553 100644 --- a/sys/winnt/console.rc +++ b/sys/winnt/console.rc @@ -1,4 +1,4 @@ -/* NetHack 3.6 console.rc $NHDT-Date: 1575245149 2019/12/02 00:05:49 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.13 $ */ +/* NetHack 3.7 console.rc $NHDT-Date: 1596498311 2020/08/03 23:45:11 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.14 $ */ /* Copyright (c) Yitzhak Sapir, 2002. */ /* NetHack may be freely redistributed. See license for details. */ @@ -12,8 +12,8 @@ // VS_VERSION_INFO VERSIONINFO - FILEVERSION 3,6,3,0 - PRODUCTVERSION 3,6,3,0 + FILEVERSION 3,7,0,0 + PRODUCTVERSION 3,7,0,0 FILEFLAGSMASK 0x1fL #ifdef _DEBUG FILEFLAGS 0x9L @@ -29,13 +29,13 @@ BEGIN BLOCK "040904b0" BEGIN VALUE "FileDescription", "NetHack for Windows - TTY Interface\0" - VALUE "FileVersion", "3.6.3\0" + VALUE "FileVersion", "3.7.0\0" VALUE "InternalName", "NetHack\0" - VALUE "LegalCopyright", "Copyright (C) 1985 - 2019. By Stichting Mathematisch Centrum and M. Stephenson. See license for details.\0" + VALUE "LegalCopyright", "Copyright (C) 1985 - 2020. By Stichting Mathematisch Centrum and M. Stephenson. See license for details.\0" VALUE "OriginalFilename", "NetHack.exe\0" VALUE "PrivateBuild", "050102\0" VALUE "ProductName", "NetHack\0" - VALUE "ProductVersion", "3.6.3\0" + VALUE "ProductVersion", "3.7.0\0" END END BLOCK "VarFileInfo" diff --git a/sys/winnt/nh340key.c b/sys/winnt/nh340key.c index a4faa80c1..348bd89e8 100644 --- a/sys/winnt/nh340key.c +++ b/sys/winnt/nh340key.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 nh340key.c $NHDT-Date: 1432512793 2015/05/25 00:13:13 $ $NHDT-Branch: master $:$NHDT-Revision: 1.12 $ */ +/* NetHack 3.7 nh340key.c $NHDT-Date: 1596498312 2020/08/03 23:45:12 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.16 $ */ /* Copyright (c) NetHack PC Development Team 2003 */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/sys/winnt/nhdefkey.c b/sys/winnt/nhdefkey.c index acbb75990..32b7c95dd 100644 --- a/sys/winnt/nhdefkey.c +++ b/sys/winnt/nhdefkey.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 nhdefkey.c $NHDT-Date: 1432512793 2015/05/25 00:13:13 $ $NHDT-Branch: master $:$NHDT-Revision: 1.14 $ */ +/* NetHack 3.7 nhdefkey.c $NHDT-Date: 1596498313 2020/08/03 23:45:13 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.19 $ */ /* Copyright (c) NetHack PC Development Team 2003 */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/sys/winnt/nhraykey.c b/sys/winnt/nhraykey.c index 7ce4e0e50..5bd9e3ead 100644 --- a/sys/winnt/nhraykey.c +++ b/sys/winnt/nhraykey.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 nhraykey.c $NHDT-Date: 1457207047 2016/03/05 19:44:07 $ $NHDT-Branch: chasonr $:$NHDT-Revision: 1.16 $ */ +/* NetHack 3.7 nhraykey.c $NHDT-Date: 1596498314 2020/08/03 23:45:14 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.21 $ */ /* Copyright (c) NetHack PC Development Team 2003 */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/sys/winnt/nhsetup.bat b/sys/winnt/nhsetup.bat index 25ac9fee7..7f65ac88f 100755 --- a/sys/winnt/nhsetup.bat +++ b/sys/winnt/nhsetup.bat @@ -1,4 +1,4 @@ -@REM NetHack 3.6 nhsetup.bat $NHDT-Date: 1554784485 2019/04/09 04:34:45 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.37 $ */ +@REM NetHack 3.7 nhsetup.bat $NHDT-Date: 1596498315 2020/08/03 23:45:15 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.40 $ */ @REM Copyright (c) NetHack PC Development Team 1993-2019 @REM NetHack may be freely redistributed. See license for details. @REM Win32 setup batch file, see Install.nt for details diff --git a/sys/winnt/ntsound.c b/sys/winnt/ntsound.c index c8ec07450..69450b748 100644 --- a/sys/winnt/ntsound.c +++ b/sys/winnt/ntsound.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 ntsound.c $NHDT-Date: 1432512794 2015/05/25 00:13:14 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ */ +/* NetHack 3.7 ntsound.c $NHDT-Date: 1596498316 2020/08/03 23:45:16 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.13 $ */ /* Copyright (c) NetHack PC Development Team 1993 */ /* NetHack may be freely redistributed. See license for details. */ /* */ diff --git a/sys/winnt/nttty.c b/sys/winnt/nttty.c index 6b1a7ea64..c1f1a0f70 100644 --- a/sys/winnt/nttty.c +++ b/sys/winnt/nttty.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 nttty.c $NHDT-Date: 1554215932 2019/04/02 14:38:52 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.99 $ */ +/* NetHack 3.7 nttty.c $NHDT-Date: 1596498316 2020/08/03 23:45:16 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.117 $ */ /* Copyright (c) NetHack PC Development Team 1993 */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/sys/winnt/porthelp b/sys/winnt/porthelp index 3f553739e..a251e14b5 100644 --- a/sys/winnt/porthelp +++ b/sys/winnt/porthelp @@ -1,7 +1,7 @@ - Microsoft Windows specific help file for NetHack 3.6 - Copyright (c) NetHack PC Development Team 1993-2002. + Microsoft Windows specific help file for NetHack 3.7 + Copyright (c) NetHack PC Development Team 1993-2020. NetHack may be freely distributed. See license for details. - (Last Revision: March 16, 2003) + (Last Revision: August 8, 2020) 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 diff --git a/sys/winnt/stubs.c b/sys/winnt/stubs.c index 805298305..7e7fe01f6 100644 --- a/sys/winnt/stubs.c +++ b/sys/winnt/stubs.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 stubs.c $NHDT-Date: 1524689357 2018/04/25 20:49:17 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.3 $ */ +/* NetHack 3.7 stubs.c $NHDT-Date: 1596498317 2020/08/03 23:45:17 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.31 $ */ /* Copyright (c) 2015 by Michael Allison */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/sys/winnt/travis-gcc.sh b/sys/winnt/travis-gcc.sh index bcf44b5b8..e1d5bf6b7 100644 --- a/sys/winnt/travis-gcc.sh +++ b/sys/winnt/travis-gcc.sh @@ -3,6 +3,6 @@ mkdir -p lib cd lib git clone --depth 1 https://github.com/wmcbrine/PDCurses.git pdcurses #git clone --depth 1 https://github.com/universal-ctags/ctags.git ctags -curl -R -O http://www.lua.org/ftp/lua-5.4.0.tar.gz -tar zxf lua-5.4.0.tar.gz +curl -R -O http://www.lua.org/ftp/lua-5.4.2.tar.gz +tar zxf lua-5.4.2.tar.gz cd ../ diff --git a/sys/winnt/win10.c b/sys/winnt/win10.c index 9791bbec6..80542574e 100644 --- a/sys/winnt/win10.c +++ b/sys/winnt/win10.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 win10.c $NHDT-Date: 1432512810 2015/05/25 00:13:30 $ $NHDT-Branch: master $:$NHDT-Revision: 1.15 $ */ +/* NetHack 3.7 win10.c $NHDT-Date: 1596498318 2020/08/03 23:45:18 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.10 $ */ /* Copyright (C) 2018 by Bart House */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/sys/winnt/win10.h b/sys/winnt/win10.h index 517843b87..fd9c9a895 100644 --- a/sys/winnt/win10.h +++ b/sys/winnt/win10.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 win10.h $NHDT-Date: 1432512810 2015/05/25 00:13:30 $ $NHDT-Branch: master $:$NHDT-Revision: 1.15 $ */ +/* 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 */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/sys/winnt/win32api.h b/sys/winnt/win32api.h index 469b8dc96..3d59fa30c 100644 --- a/sys/winnt/win32api.h +++ b/sys/winnt/win32api.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 win32api.h $NHDT-Date: 1432516197 2015/05/25 01:09:57 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ */ +/* NetHack 3.7 win32api.h $NHDT-Date: 1596498320 2020/08/03 23:45:20 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.15 $ */ /* Copyright (c) NetHack PC Development Team 1996 */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/sys/winnt/windmain.c b/sys/winnt/windmain.c index 357c8e38b..a18999a78 100644 --- a/sys/winnt/windmain.c +++ b/sys/winnt/windmain.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 windmain.c $NHDT-Date: 1543465755 2018/11/29 04:29:15 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.101 $ */ +/* NetHack 3.7 windmain.c $NHDT-Date: 1596498320 2020/08/03 23:45:20 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.157 $ */ /* Copyright (c) Derek S. Ray, 2015. */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/sys/winnt/winnt.c b/sys/winnt/winnt.c index bd0d2cf48..f34a68397 100644 --- a/sys/winnt/winnt.c +++ b/sys/winnt/winnt.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 winnt.c $NHDT-Date: 1524321419 2018/04/21 14:36:59 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.30 $ */ +/* NetHack 3.7 winnt.c $NHDT-Date: 1596498321 2020/08/03 23:45:21 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.64 $ */ /* Copyright (c) NetHack PC Development Team 1993, 1994 */ /* NetHack may be freely redistributed. See license for details. */ @@ -483,23 +483,6 @@ char *buf; } #endif /* RUNTIME_PORT_ID */ -/* nhassert_failed is called when an nhassert's condition is false */ -void nhassert_failed(const char * exp, const char * file, int line) -{ - char message[128]; - _snprintf(message, sizeof(message), - "NHASSERT(%s) in '%s' at line %d\n", exp, file, line); - - if (IsDebuggerPresent()) { - OutputDebugStringA(message); - DebugBreak(); - } - - // strip off the newline - message[strlen(message) - 1] = '\0'; - error(message); -} - void nethack_exit(code) int code; @@ -734,6 +717,32 @@ sys_random_seed(VOID_ARGS) return ourseed; } +/* nt_assert_failed is called when an nhassert's condition is false */ +void +nt_assert_failed(expression, filepath, line) + const char * expression; + const char * filepath; + int line; +{ + const char * filename; + + filename = strrchr(filepath, '\\'); + filename = (filename == NULL ? filepath : filename + 1); + + if (IsDebuggerPresent()) { + char message[BUFSIZ]; + snprintf(message, sizeof(message), + "nhassert(%s) failed in file '%s' at line %d", + expression, filename, line); + OutputDebugStringA(message); + DebugBreak(); + } + + /* get file name from path */ + impossible("nhassert(%s) failed in file '%s' at line %d", + expression, filename, line); +} + #endif /* WIN32 */ /*winnt.c*/ diff --git a/sys/winnt/winos.h b/sys/winnt/winos.h index 39a4b408e..55300bda0 100644 --- a/sys/winnt/winos.h +++ b/sys/winnt/winos.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 winos.h $NHDT-Date: 1524321419 2018/04/21 14:36:59 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.30 $ */ +/* NetHack 3.7 winos.h $NHDT-Date: 1596498322 2020/08/03 23:45:22 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.0 $ */ /* Copyright (c) NetHack PC Development Team 2018 */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/test/test_des.lua b/test/test_des.lua index 8cb281bce..9275d801a 100644 --- a/test/test_des.lua +++ b/test/test_des.lua @@ -324,8 +324,8 @@ end function test_region() des.region(selection.area(08,03,54,03),"unlit") des.region(selection.area(56,02,60,03),"lit") - des.region({ region={16,05, 25,06}, lit=1, type="barracks", prefilled=0 }) - des.region({ region={1,5, 3,7}, lit=1, irregular=true, prefilled=true, joined=false }) + des.region({ region={16,05, 25,06}, lit=1, type="barracks", filled=0 }) + des.region({ region={1,5, 3,7}, lit=1, irregular=true, filled=1, joined=false }) end function test_door() diff --git a/test/testwish.lua b/test/testwish.lua index 7aada046b..d28c82e3b 100644 --- a/test/testwish.lua +++ b/test/testwish.lua @@ -1,6 +1,12 @@ local wishtest_objects = { ["a rock"] = { otyp_name = "rock", quan = 1, oclass = "*" }, + ["a gold piece"] = { otyp_name = "gold piece", quan = 1, oclass = "$" }, + ["2 zorkmids"] = { otyp_name = "gold piece", quan = 2, oclass = "$" }, + ["2 worthless pieces of red glass"] = { otyp_name = "worthless piece of red glass", quan = 2, oclass = "*" }, + ["red glass"] = { otyp_name = "worthless piece of red glass", quan = 1, oclass = "*" }, + ["red gem"] = { otyp_descr = "red", oclass = "*" }, + ["orange gem"] = { otyp_descr = "orange", oclass = "*" }, ["5 +3 blessed silver daggers"] = { otyp_name = "silver dagger", blessed = 1, cursed = 0, spe = 3, quan = 5 }, ["an empty locked large box"] = { otyp_name = "large box", is_container = 1, has_contents = 0, olocked = 1 }, ["an empty trapped unlocked chest"] = { otyp_name = "chest", is_container = 1, has_contents = 0, olocked = 0, otrapped = 1 }, @@ -10,36 +16,54 @@ local wishtest_objects = { ["potion of holy water"] = { otyp_name = "water", oclass = "!", blessed = 1, cursed = 0 }, ["potion of unholy water"] = { otyp_name = "water", oclass = "!", blessed = 0, cursed = 1 }, ["cursed greased +2 grey dragon scale mail"] = { otyp_name = "gray dragon scale mail", oclass = "[", blessed = 0, cursed = 1, spe = 2, greased = 1 }, + ["+1 yellow dragon scales"] = { otyp_name = "yellow dragon scales", oclass = "[", spe = 1 }, ["uncursed magic marker (11)"] = { otyp_name = "magic marker", blessed = 0, cursed = 0, spe = 11 }, + ["wand of locking (1:5)"] = { otyp_name = "locking", oclass = "/", recharged = 1, spe = 5 }, + ["wand of opening (0:4)"] = { otyp_name = "opening", oclass = "/", recharged = 0, spe = 4 }, ["lit oil lamp"] = { otyp_name = "oil lamp", lamplit = 1 }, + ["oil lamp (lit)"] = { otyp_name = "oil lamp", lamplit = 1 }, ["6 burning tallow candles"] = { otyp_name = "tallow candle", lamplit = 1, quan = 6 }, ["unlit oil lamp"] = { otyp_name = "oil lamp", lamplit = 0 }, ["7 extinguished wax candles"] = { otyp_name = "wax candle", lamplit = 0, quan = 7 }, ["2 blank scrolls"] = { otyp_name = "blank paper", quan = 2 }, ["3 unlabeled scrolls"] = { otyp_name = "blank paper", quan = 3 }, ["1 unlabelled scroll"] = { otyp_name = "blank paper", quan = 1 }, + ["blank spellbook"] = { otyp_name = "blank paper", oclass = "+" }, + ["unlabeled spellbook"] = { otyp_name = "blank paper", oclass = "+" }, + ["unlabelled spellbook"] = { otyp_name = "blank paper", oclass = "+" }, ["3 rusty poisoned darts"] = { otyp_name = "dart", quan = 3, opoisoned = 1, oeroded = 1 }, ["4 diluted dark green potions named whisky"] = { otyp_descr = "dark green", oclass = "!", quan = 4, odiluted = 1, has_oname = 1, oname = "whisky" }, ["poisoned food ration"] = { otyp_name = "food ration", oclass = "%", age = 1 }, ["empty tin"] = { otyp_name = "tin", oclass = "%", corpsenm = -1, spe = 0 }, ["blessed tin of spinach"] = { otyp_name = "tin", oclass = "%", corpsenm = -1, spe = 1, blessed = 1 }, + ["spinach"] = { otyp_name = "tin", oclass = "%", corpsenm = -1, spe = 1 }, ["trapped tin of floating eye meat"] = { otyp_name = "tin", oclass = "%", otrapped = 1, corpsenm_name = "floating eye" }, ["hill orc corpse"] = { otyp_name = "corpse", oclass = "%", corpsenm_name = "hill orc" }, ["destroy armor"] = { otyp_name = "destroy armor", oclass = "?" }, ["enchant weapon"] = { otyp_name = "enchant weapon", oclass = "?" }, ["scroll of food detection"] = { otyp_name = "food detection", oclass = "?" }, ["scroll of detect food"] = { otyp_name = "food detection", oclass = "?" }, + ["2 scrolls of charging"] = { otyp_name = "charging", oclass = "?", quan = 2 }, ["spellbook of food detection"] = { otyp_name = "detect food", oclass = "+" }, ["spell"] = { NO_OBJ = 1 }, ["-1 ring mail"] = { otyp_name = "ring mail", oclass = "[", spe = -1 }, ["studded leather armor"] = { otyp_name = "studded leather armor", oclass = "[" }, ["leather armor"] = { otyp_name = "leather armor", oclass = "[" }, + ["plate armor"] = { otyp_name = "plate mail", oclass = "[" }, + ["yellow dragon scale armor"] = { otyp_name = "yellow dragon scale mail", oclass = "[" }, + ["speed boots"] = { otyp_name = "speed boots", oclass = "[" }, + ["speedboots"] = { otyp_name = "speed boots", oclass = "[" }, + ["erodeproof speedboots"] = { otyp_name = "speed boots", oclass = "[", oerodeproof = 1 }, + ["fixed boots of speed"] = { otyp_name = "speed boots", oclass = "[", oerodeproof = 1 }, + ["blessed fireproof +2 pair of speed boots"] = { otyp_name = "speed boots", oclass = "[", oerodeproof = 1, blessed = 1, spe = 2 }, ["tooled horn"] = { otyp_name = "tooled horn", oclass = "(" }, ["meat ring"] = { otyp_name = "meat ring", oclass = "%" }, ["beartrap"] = { otyp_name = "beartrap", oclass = "(" }, ["bear trap"] = { otyp_name = "beartrap", oclass = "(" }, ["landmine"] = { otyp_name = "land mine", oclass = "(" }, ["land mine"] = { otyp_name = "land mine", oclass = "(" }, + ["bag of tricks"] = { otyp_name = "bag of tricks", oclass = "(" }, + ["bags of tricks"] = { otyp_name = "bag of tricks", oclass = "(" }, ["sprig of wolfsbane"] = { otyp_name = "sprig of wolfsbane", oclass = "%" }, ["wolfsbane"] = { otyp_name = "sprig of wolfsbane", oclass = "%" }, ["clove of garlic"] = { otyp_name = "clove of garlic", oclass = "%" }, diff --git a/util/dlb_main.c b/util/dlb_main.c index 120de616c..2a32124dc 100644 --- a/util/dlb_main.c +++ b/util/dlb_main.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 dlb_main.c $NHDT-Date: 1570258542 2019/10/05 06:55:42 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.13 $ */ +/* NetHack 3.7 dlb_main.c $NHDT-Date: 1596498258 2020/08/03 23:44:18 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.14 $ */ /* Copyright (c) Kenneth Lorber, Bethesda, Maryland, 1993. */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/util/makedefs.c b/util/makedefs.c index 12bf8009c..65d7f4878 100644 --- a/util/makedefs.c +++ b/util/makedefs.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 makedefs.c $NHDT-Date: 1594347789 2020/07/10 02:23:09 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.182 $ */ +/* NetHack 3.7 makedefs.c $NHDT-Date: 1600855420 2020/09/23 10:03:40 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.188 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Kenneth Lorber, Kensington, Maryland, 2015. */ /* Copyright (c) M. Stephenson, 1990, 1991. */ @@ -124,6 +124,7 @@ static struct version_info version; /* Use this as an out-of-bound value in the close table. */ #define CLOSE_OFF_TABLE_STRING "99" /* for the close table */ #define FAR_OFF_TABLE_STRING "0xff" /* for the far table */ +#define FLG_TEMPFILE 0x01 /* flag for temp file */ #define sign(z) ((z) < 0 ? -1 : ((z) ? 1 : 0)) #ifdef VISION_TABLES @@ -164,8 +165,7 @@ extern void NDECL(monst_globals_init); /* monst.c */ extern void NDECL(objects_globals_init); /* objects.c */ static char *FDECL(name_file, (const char *, const char *)); -static void FDECL(delete_file, (const char *template, const char *)); -static FILE *FDECL(getfp, (const char *, const char *, const char *)); +static FILE *FDECL(getfp, (const char *, const char *, const char *, int)); static void FDECL(do_ext_makedefs, (int, char **)); static char *FDECL(xcrypt, (const char *)); static unsigned long FDECL(read_rumors_file, @@ -382,6 +382,9 @@ const char *tag; return namebuf; } +#ifdef HAS_NO_MKSTEMP +static void FDECL(delete_file, (const char *template, const char *)); + static void delete_file(template, tag) const char *template; @@ -391,19 +394,43 @@ const char *tag; Unlink(name); } +#endif static FILE * -getfp(template, tag, mode) +getfp(template, tag, mode, flg) const char *template; const char *tag; const char *mode; +#ifndef HAS_NO_MKSTEMP +int flg; +#else +int flg UNUSED; +#endif { char *name = name_file(template, tag); - FILE *rv = fopen(name, mode); + FILE *rv = (FILE *) 0; +#ifndef HAS_NO_MKSTEMP + boolean istemp = (flg & FLG_TEMPFILE) != 0; + char tmpfbuf[MAXFNAMELEN]; + int tmpfd; + if (istemp) { + (void) snprintf(tmpfbuf, sizeof tmpfbuf, DATA_TEMPLATE, "mdXXXXXX"); + tmpfd = mkstemp(tmpfbuf); + if (tmpfd >= 0) { + rv = fdopen(tmpfd, WRTMODE); /* temp file is always read+write */ + Unlink(tmpfbuf); + } + } else +#endif + rv = fopen(name, mode); if (!rv) { - Fprintf(stderr, "Can't open '%s'.\n", name); - exit(EXIT_FAILURE); + Fprintf(stderr, "Can't open '%s'.\n", +#ifndef HAS_NO_MKSTEMP + istemp ? tmpfbuf : +#endif + name); + exit(EXIT_FAILURE); } return rv; } @@ -426,7 +453,7 @@ static int FDECL(grep_check_id, (const char *)); static void FDECL(grep_show_wstack, (const char *)); static char *FDECL(do_grep_control, (char *)); static void NDECL(do_grep); -static void FDECL(grep0, (FILE *, FILE *)); +static void FDECL(grep0, (FILE *, FILE *, int)); static int grep_trace = 0; @@ -775,7 +802,7 @@ char *buf; } #endif -static void grep0(FILE *, FILE *); +static void grep0(FILE *, FILE *, int); static void do_grep() @@ -790,14 +817,26 @@ do_grep() exit(EXIT_FAILURE); } - grep0(inputfp, outputfp); + grep0(inputfp, outputfp, 0); } static void -grep0(inputfp0, outputfp0) +grep0(inputfp0, outputfp0, flg) FILE *inputfp0; FILE *outputfp0; +#ifndef HAS_NO_MKSTEMP +int flg; +#else +int flg UNUSED; +#endif { +#ifndef HAS_NO_MKSTEMP + /* if grep0 is passed FLG_TEMPFILE flag, it will + leave the output file open when it returns. + The caller will have to take care of calling + fclose() when it is done with the file */ + boolean istemp = (flg & FLG_TEMPFILE) != 0; +#endif char buf[16384]; /* looong, just in case */ while (!feof(inputfp0) && !ferror(inputfp0)) { @@ -837,7 +876,12 @@ FILE *outputfp0; exit(EXIT_FAILURE); } fclose(inputfp0); - fclose(outputfp0); +#ifndef HAS_NO_MKSTEMP + if (istemp) + rewind(outputfp0); + else +#endif + fclose(outputfp0); if (grep_sp) { Fprintf(stderr, "%d unterminated conditional level%s\n", grep_sp, grep_sp == 1 ? "" : "s"); @@ -967,10 +1011,13 @@ const char *deflt_content; more likely to be picked than normal but it's nothing to worry about */ (void) fputs(xcrypt(deflt_content), ofp); - tfp = getfp(DATA_TEMPLATE, "grep.tmp", WRTMODE); - grep0(ifp, tfp); - ifp = getfp(DATA_TEMPLATE, "grep.tmp", RDTMODE); - + tfp = getfp(DATA_TEMPLATE, "grep.tmp", WRTMODE, FLG_TEMPFILE); + grep0(ifp, tfp, FLG_TEMPFILE); +#ifndef HAS_NO_MKSTEMP + ifp = tfp; +#else + ifp = getfp(DATA_TEMPLATE, "grep.tmp", RDTMODE, 0); +#endif while ((line = fgetline(ifp)) != 0) { if (line[0] != '#' && line[0] != '\n') (void) fputs(xcrypt(line), ofp); @@ -979,7 +1026,9 @@ const char *deflt_content; Fclose(ifp); Fclose(ofp); +#ifdef HAS_NO_MKSTEMP delete_file(DATA_TEMPLATE, "grep.tmp"); +#endif return; } @@ -1086,13 +1135,11 @@ do_date() char githash[BUFSZ], gitbranch[BUFSZ]; char *c, cbuf[60], buf[BUFSZ]; const char *ul_sfx; -#if defined(CROSSCOMPILE) && defined(CROSSCOMPILE_HOST) - int steps = 0; - const char ind[] = " "; +#if defined(CROSSCOMPILE) && !defined(CROSSCOMPILE_TARGET) const char *xpref = "HOST_"; #else const char *xpref = (const char *) 0; -#endif /* CROSSCOMPILE && CROSSCOMPILE_HOST */ +#endif /* CROSSCOMPILE && !CROSSCOMPILE_TARGET */ /* before creating date.h, make sure that xxx_GRAPHICS and DEFAULT_WINDOW_SYS have been set up in a viable fashion */ @@ -1194,10 +1241,10 @@ do_date() ul_sfx = "L"; #endif -#if !defined(CROSSCOMPILE) || defined(CROSSCOMPILE_HOST) +#if !defined(CROSSCOMPILE) || !defined(CROSSCOMPILE_TARGET) Fprintf(ofp, - "\n#if !defined(CROSSCOMPILE) || defined(CROSSCOMPILE_HOST)\n"); -#endif /* CROSSCOMPILE || CROSSCOMPILE_HOST */ + "\n#if !defined(CROSSCOMPILE) || !defined(CROSSCOMPILE_TARGET)\n"); +#endif /* CROSSCOMPILE || !CROSSCOMPILE_TARGET */ if (date_via_env) Fprintf(ofp, "#define SOURCE_DATE_EPOCH (%lu%s) /* via getenv() */\n", (unsigned long) clocktim, ul_sfx); @@ -1218,10 +1265,18 @@ do_date() #endif 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", version_string(buf, ".")); Fprintf(ofp, "#define VERSION_ID \\\n \"%s\"\n", @@ -1233,13 +1288,15 @@ do_date() Fprintf(ofp, "#define NETHACK_GIT_BRANCH \"%s\"\n", gitbranch); } if (xpref && get_gitinfo(githash, gitbranch)) { - Fprintf(ofp, "#else /* !CROSSCOMPILE || CROSSCOMPILE_HOST */\n"); + Fprintf(ofp, "#else /* !CROSSCOMPILE || !CROSSCOMPILE_TARGET */\n"); Fprintf(ofp, "#define NETHACK_%sGIT_SHA \"%s\"\n", xpref, githash); Fprintf(ofp, "#define NETHACK_%sGIT_BRANCH \"%s\"\n", xpref, gitbranch); } - Fprintf(ofp, "#endif /* !CROSSCOMPILE || CROSSCOMPILE_HOST */\n"); +#if !defined(CROSSCOMPILE) || !defined(CROSSCOMPILE_TARGET) + Fprintf(ofp, "#endif /* !CROSSCOMPILE || !CROSSCOMPILE_TARGET */\n"); +#endif Fprintf(ofp, "\n"); #ifdef AMIGA { @@ -1747,10 +1804,13 @@ do_dungeon() } Fprintf(ofp, "%s", Dont_Edit_Data); - tfp = getfp(DATA_TEMPLATE, "grep.tmp", WRTMODE); - grep0(ifp, tfp); - ifp = getfp(DATA_TEMPLATE, "grep.tmp", RDTMODE); - + tfp = getfp(DATA_TEMPLATE, "grep.tmp", WRTMODE, FLG_TEMPFILE); + grep0(ifp, tfp, FLG_TEMPFILE); +#ifndef HAS_NO_MKSTEMP + ifp = tfp; +#else + ifp = getfp(DATA_TEMPLATE, "grep.tmp", RDTMODE, 0); +#endif while ((line = fgetline(ifp)) != 0) { SpinCursor(3); @@ -1764,7 +1824,9 @@ do_dungeon() Fclose(ifp); Fclose(ofp); +#ifdef HAS_NO_MKSTEMP delete_file(DATA_TEMPLATE, "grep.tmp"); +#endif return; } @@ -1826,14 +1888,14 @@ struct permonst *ptr; if ((tmp2 == AD_DRLI) || (tmp2 == AD_STON) || (tmp2 == AD_DRST) || (tmp2 == AD_DRDX) || (tmp2 == AD_DRCO) || (tmp2 == AD_WERE)) n += 2; - else if (strcmp(ptr->mname, "grid bug")) + else if (strcmp(ptr->pmnames[NEUTRAL], "grid bug")) n += (tmp2 != AD_PHYS); 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. */ - if (!strcmp(ptr->mname, "leprechaun")) + if (!strcmp(ptr->pmnames[NEUTRAL], "leprechaun")) n -= 2; /* Finally, adjust the monster level 0 <= n <= 24 (approx.) */ @@ -1867,7 +1929,7 @@ void do_monstr() { struct permonst *ptr; - int i, j; + int i; /* Don't break anything for ports that haven't been updated. */ printf("DEPRECATION WARNINGS:\n"); @@ -1909,9 +1971,9 @@ do_monstr() /* output derived monstr values as a comment */ Fprintf(ofp, "\n\n/*\n * default mons[].difficulty values\n *\n"); - for (ptr = &mons[0], j = 0; ptr->mlet; ptr++) { + for (ptr = &mons[0]; ptr->mlet; ptr++) { i = mstrength(ptr); - Fprintf(ofp, "%-24s %2u\n", ptr->mname, (unsigned int) (uchar) i); + Fprintf(ofp, "%-24s %2u\n", ptr->pmnames[NEUTRAL], (unsigned int) (uchar) i); } Fprintf(ofp, " *\n */\n\n"); @@ -1959,9 +2021,9 @@ do_permonst() Fprintf(ofp, "\n PM_"); else Fprintf(ofp, "\n#define\tPM_"); - if (mons[i].mlet == S_HUMAN && !strncmp(mons[i].mname, "were", 4)) + if (mons[i].mlet == S_HUMAN && !strncmp(mons[i].pmnames[NEUTRAL], "were", 4)) Fprintf(ofp, "HUMAN_"); - for (nam = c = tmpdup(mons[i].mname); *c; c++) + for (nam = c = tmpdup(mons[i].pmnames[NEUTRAL]); *c; c++) if (*c >= 'a' && *c <= 'z') *c -= (char) ('a' - 'A'); else if (*c < 'A' || *c > 'Z') @@ -2091,8 +2153,18 @@ do_objs() break; } /*FALLTHRU*/ + case VENOM_CLASS: + /* fall-through from gem class is ok; objects[] used to have + { "{acid,blinding} venom", "splash of venom" } + but those have been changed to + { "splash of {acid,blinding} venom", "splash of venom" } + so strip the extra "splash of " off to keep same macros */ + if (!strncmp(objnam, "SPLASH_OF_", 10)) + objnam += 10; + /*FALLTHRU*/ default: Fprintf(ofp, "#define\t"); + break; } if (prefix >= 0) Fprintf(ofp, "%s\t%d\n", limit(objnam, prefix), i); diff --git a/util/mdgrep.h b/util/mdgrep.h index 382da338c..dfdd9790f 100644 --- a/util/mdgrep.h +++ b/util/mdgrep.h @@ -1,5 +1,5 @@ /* - * NetHack 3.6 mdgrep.h $NHDT-Date: 1432512785 2015/05/25 00:13:05 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ + * NetHack 3.7 mdgrep.h $NHDT-Date: 1596498259 2020/08/03 23:44:19 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.14 $ * Copyright (c) Kenneth Lorber, Kensington, Maryland, 2008 * NetHack may be freely redistributed. See license for details. * diff --git a/util/mdgrep.pl b/util/mdgrep.pl index 8a4cd8d36..72c06efb7 100644 --- a/util/mdgrep.pl +++ b/util/mdgrep.pl @@ -1,5 +1,5 @@ #!perl -# NetHack 3.6 mdgrep.pl $NHDT-Date: 1593953364 2020/07/05 12:49:24 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.19 $ +# NetHack 3.7 mdgrep.pl $NHDT-Date: 1596498260 2020/08/03 23:44:20 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.20 $ # Copyright (c) Kenneth Lorber, Kensington, Maryland # NetHack may be freely redistributed. See license for details. @@ -44,7 +44,6 @@ # NeXT __osf__ SVR4 _AIX32 _BULL_SOURCE AUX __sgi GNUDOS # TIMED_DELAY DEF_MAILREADER DEF_PAGER NO_SIGNAL PC_LOCKING LATTICE __GO32__ # msleep NO_FILE_LINKS bsdi HPUX AMIFLUSH -# OVERLAY USE_TRAMPOLI USE_OVLx SPEC_LEV DGN_COMP # SCREEN_BIOS SCREEN_DJGPPFAST SCREEN_VGA SCREEN_8514 # EXEPATH NOTSTDC SELECTSAVED NOTPARMDECL @@ -54,17 +53,17 @@ $outfile = "mdgrep.h"; sub start_file { - ($rev) = ('$NHDT-Revision: 1.19 $') =~ m/: (.*) .$/; - my $date = '$NHDT-Date: 1593953366 2020/07/05 12:49:26 $'; + ($rev) = ('$NHDT-Revision: 1.20 $') =~ m/: (.*) .$/; + my $date = '$NHDT-Date: 1596498261 2020/08/03 23:44:21 $'; my $branch = '$NHDT-Branch: NetHack-3.7 $'; - my $revision = '$NHDT-Revision: 1.19 $'; + my $revision = '$NHDT-Revision: 1.20 $'; open(OUT, ">$outfile") || die "open $outfile: $!"; # NB: Date and Revision below will be modified when mdgrep.h is written to # git - this is correct (but it means you must commit changes to mdgrep.pl # before generating mdgrep.h and committing that file). print OUT < or picks Quit, but +typing 'Q' or 'q' picks Save-and-exit because Alt+Q is expected for +the keyboard shortcut. + +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. + +----- diff --git a/win/Qt/qt_bind.cpp b/win/Qt/qt_bind.cpp index cb875f115..ba4c21567 100644 --- a/win/Qt/qt_bind.cpp +++ b/win/Qt/qt_bind.cpp @@ -7,16 +7,8 @@ extern "C" { #include "hack.h" } -#undef Invisible -#undef Warning -#undef index -#undef msleep -#undef rindex -#undef wizard -#undef yn -#undef min -#undef max +#include "qt_pre.h" #include #include #if QT_VERSION >= 0x050000 @@ -25,6 +17,7 @@ extern "C" { #else #include #endif +#include "qt_post.h" #include "qt_bind.h" #include "qt_click.h" #ifdef TIMED_DELAY @@ -53,7 +46,7 @@ extern int qt_compact_mode; namespace nethack_qt_ { -// XXX Should be from Options +// XXX Should be from Options [or from Qt Settings (aka Preferences)]. // // XXX Hmm. Tricky part is that perhaps some macros should only be active // XXX when a key is about to be gotten. For example, the user could @@ -62,13 +55,13 @@ namespace nethack_qt_ { // static struct key_macro_rec { int key; - int state; - const char* macro; + uint state; + const char *macro, *numpad_macro; } key_macro[]={ - { Qt::Key_F1, 0, "n100." }, // Rest (x100) - { Qt::Key_F2, 0, "n20s" }, // Search (x20) - { Qt::Key_Tab, 0, "\001" }, - { 0, 0, 0 } + { Qt::Key_F1, 0U, "100.", "n100." }, // Rest (x100) + { Qt::Key_F2, 0U, "20s", "n20s" }, // Search (x20) + { Qt::Key_Tab, 0U, "\001", "\001" }, // ^A (Do-again) + { 0, 0U, (const char *) 0, (const char *) 0 } }; NetHackQtBind::NetHackQtBind(int& argc, char** argv) : @@ -82,8 +75,9 @@ NetHackQtBind::NetHackQtBind(int& argc, char** argv) : { QPixmap pm("nhsplash.xpm"); if ( iflags.wc_splash_screen && !pm.isNull() ) { - splash = new QFrame(NULL, - Qt::FramelessWindowHint | Qt::X11BypassWindowManagerHint | Qt::WindowStaysOnTopHint ); + splash = new QFrame(NULL, (Qt::FramelessWindowHint + | Qt::X11BypassWindowManagerHint + | Qt::WindowStaysOnTopHint)); QVBoxLayout *vb = new QVBoxLayout(splash); QLabel *lsplash = new QLabel(splash); vb->addWidget(lsplash); @@ -117,9 +111,27 @@ NetHackQtBind::NetHackQtBind(int& argc, char** argv) : } else { splash = 0; } + + // these used to be in MainWindow but we want them before QtSettings + // which we want before MainWindow... + QCoreApplication::setOrganizationName("The NetHack DevTeam"); + QCoreApplication::setOrganizationDomain("nethack.org"); + QCoreApplication::setApplicationName("NetHack-Qt"); // Qt NetHack + { + char cvers[BUFSZ]; + QString qvers = version_string(cvers); + QCoreApplication::setApplicationVersion(qvers); + } +#ifdef MACOSX + /* without this, neither control+x nor option+x do anything; + with it, control+x is ^X and option+x still does nothing */ + QCoreApplication::setAttribute(Qt::AA_MacDontSwapCtrlAndMeta); +#endif + + qt_settings = new NetHackQtSettings(); /*(main->width(),main->height());*/ + main = new NetHackQtMainWindow(keybuffer); connect(qApp, SIGNAL(lastWindowClosed()), qApp, SLOT(quit())); - qt_settings=new NetHackQtSettings(main->width(),main->height()); msgs_strings = new QStringList(); msgs_initd = false; msgs_saved = false; @@ -155,6 +167,11 @@ void NetHackQtBind::qt_init_nhwindows(int* argc, char** argv) // This nethack engine feature should be moved into windowport API nt_kbhit = NetHackQtBind::qt_kbhit; #endif + +#ifndef DYNAMIC_STATUSLINES + // 'statuslines' option can be set in config file but not via 'O' + set_wc2_option_mod_status(WC2_STATUSLINES, set_gameview); +#endif } int NetHackQtBind::qt_kbhit() @@ -173,36 +190,57 @@ void NetHackQtBind::qt_player_selection() void NetHackQtBind::qt_askname() { - have_asked = true; + char default_plname[PL_NSIZ]; - // We do it all here, and nothing in askname + have_asked = true; + str_copy(default_plname, g.plname, PL_NSIZ); + + // We do it all here (plus qt_plsel.cpp and qt_svsel.cpp), + // nothing in player_selection(). char** saved = get_saved_games(); - int ch = -1; + int ch = -1; // -1 => new game if ( saved && *saved ) { if ( splash ) splash->hide(); NetHackQtSavedGameSelector sgsel((const char**)saved); ch = sgsel.choose(); if ( ch >= 0 ) str_copy(g.plname, saved[ch], SIZE(g.plname)); + // caller needs new lock name even if plname[] hasn't changed + // because successful get_saved_games() clobbers g.SAVEF[] + ::iflags.renameinprogress = TRUE; } free_saved_games(saved); switch (ch) { - case -1: - if ( splash ) splash->hide(); - if (NetHackQtPlayerSelector(keybuffer).Choose()) - return; - case -2: - break; - default: - return; + case -1: + // New Game + if (splash) + splash->hide(); + if (NetHackQtPlayerSelector(keybuffer).Choose()) { + // success; handle plname[] verification below prior to returning + break; + } + /*FALLTHRU*/ + case -2: + // Quit + clearlocks(); + qt_exit_nhwindows(0); + nh_terminate(0); + /*NOTREACHED*/ + break; + default: + // picked a character from the saved games list + break; } - // Quit - clearlocks(); - qt_exit_nhwindows(0); - nh_terminate(0); + if (!*g.plname) + // in case Choose() returns with plname[] empty + Strcpy(g.plname, default_plname); + else if (strcmp(g.plname, default_plname) != 0) + // caller needs to set new lock file name + ::iflags.renameinprogress = TRUE; + return; } void NetHackQtBind::qt_get_nh_event() @@ -252,22 +290,30 @@ winid NetHackQtBind::qt_create_nhwindow(int type) NetHackQtWindow* window=0; switch (type) { - case NHW_MAP: { + case NHW_MAP: { NetHackQtMapWindow2* w=new NetHackQtMapWindow2(clickbuffer); main->AddMapWindow(w); window=w; - } break; case NHW_MESSAGE: { + break; + } + case NHW_MESSAGE: { NetHackQtMessageWindow* w=new NetHackQtMessageWindow; main->AddMessageWindow(w); window=w; - } break; case NHW_STATUS: { + break; + } + case NHW_STATUS: { NetHackQtStatusWindow* w=new NetHackQtStatusWindow; main->AddStatusWindow(w); window=w; - } break; case NHW_MENU: + break; + } + case NHW_MENU: window=new NetHackQtMenuOrTextWindow(mainWidget()); - break; case NHW_TEXT: + break; + case NHW_TEXT: window=new NetHackQtTextWindow(mainWidget()); + break; } window->nhid = id; @@ -279,8 +325,7 @@ winid NetHackQtBind::qt_create_nhwindow(int type) #else && main->isVisible() #endif - ) - { + ) { delete splash; splash = 0; } @@ -292,22 +337,26 @@ winid NetHackQtBind::qt_create_nhwindow(int type) void NetHackQtBind::qt_clear_nhwindow(winid wid) { NetHackQtWindow* window=id_to_window[(int)wid]; - window->Clear(); + if (window) + window->Clear(); } void NetHackQtBind::qt_display_nhwindow(winid wid, BOOLEAN_P block) { NetHackQtWindow* window=id_to_window[(int)wid]; - window->Display(block); + if (window) + window->Display(block); } void NetHackQtBind::qt_destroy_nhwindow(winid wid) { NetHackQtWindow* window=id_to_window[(int)wid]; - main->RemoveWindow(window); - if (window->Destroy()) - delete window; - id_to_window[(int)wid] = 0; + if (window) { + main->RemoveWindow(window); + if (window->Destroy()) + delete window; + id_to_window[(int) wid] = 0; + } } void NetHackQtBind::qt_curs(winid wid, int x, int y) @@ -368,10 +417,10 @@ void NetHackQtBind::qt_display_file(const char *filename, BOOLEAN_P must_exist) } } -void NetHackQtBind::qt_start_menu(winid wid, unsigned long mbehavior) +void NetHackQtBind::qt_start_menu(winid wid, unsigned long mbehavior UNUSED) { NetHackQtWindow* window=id_to_window[(int)wid]; - window->StartMenu(); + window->StartMenu(wid == WIN_INVEN); } void NetHackQtBind::qt_add_menu(winid wid, int glyph, @@ -399,7 +448,7 @@ int NetHackQtBind::qt_select_menu(winid wid, int how, MENU_ITEM_P **menu_list) void NetHackQtBind::qt_update_inventory() { if (main) - main->updateInventory(); + main->updateInventory(); // update the paper doll inventory subset /* doesn't work yet if (g.program_state.something_worth_saving && iflags.perm_invent) display_inventory(NULL, false); @@ -425,11 +474,12 @@ void NetHackQtBind::qt_cliparound_window(winid wid, int x, int y) NetHackQtWindow* window=id_to_window[(int)wid]; window->ClipAround(x,y); } -void NetHackQtBind::qt_print_glyph(winid wid,XCHAR_P x,XCHAR_P y,int glyph,int bkglyph) +void NetHackQtBind::qt_print_glyph(winid wid,XCHAR_P x,XCHAR_P y,int glyph, + int bkglyph UNUSED, unsigned *glyphmod) { /* TODO: bkglyph */ NetHackQtWindow* window=id_to_window[(int)wid]; - window->PrintGlyph(x,y,glyph); + window->PrintGlyph(x,y,glyph,glyphmod); } //void NetHackQtBind::qt_print_glyph_compose(winid wid,xchar x,xchar y,int glyph1, int glyph2) //{ @@ -450,27 +500,54 @@ void NetHackQtBind::qt_raw_print_bold(const char *str) int NetHackQtBind::qt_nhgetch() { if (main) - main->fadeHighlighting(); + main->fadeHighlighting(true); // Process events until a key arrives. // while (keybuffer.Empty()) { - qApp->exec(); + int exc = qApp->exec(); + /* + * On OSX (possibly elsewhere), this prevents an infinite + * loop repeatedly issuing the complaint: +QCoreApplication::exec: The event loop is already running + * to stderr if you syncronously start nethack from a terminal + * then switch focus back to that terminal and type ^C. + * SIGINT -> done1() -> done2() -> yn_function("Really quit?") + * in the core asks for another keystroke. + * + * However, it still issues one such complaint, and whatever + * prompt wanted a response ("Really quit?") is shown in the + * message window but is auto-answered with ESC. + */ + if (exc == -1) + keybuffer.Put('\033'); } + // after getting a key rather than before + if (main) + main->fadeHighlighting(false); + return keybuffer.GetAscii(); } int NetHackQtBind::qt_nh_poskey(int *x, int *y, int *mod) { if (main) - main->fadeHighlighting(); + main->fadeHighlighting(true); // Process events until a key or map-click arrives. // while (keybuffer.Empty() && clickbuffer.Empty()) { - qApp->exec(); + int exc = qApp->exec(); + // [see comment above in qt_nhgetch()] + if (exc == -1) + keybuffer.Put('\033'); } + + // after getting a key or click rather than before + if (main) + main->fadeHighlighting(false); + if (!keybuffer.Empty()) { return keybuffer.GetAscii(); } else { @@ -494,94 +571,237 @@ int NetHackQtBind::qt_doprev_message() return 0; } -char NetHackQtBind::qt_yn_function(const char *question_, const char *choices, CHAR_P def) +// display "--More--" as a prompt and wait for a response from the user +// +// Used by qt_display_nhwindow(WIN_MESSAGE, TRUE) where second argument +// True requests blocking. We need it to support MSGTYPE=stop but the +// core also uses that in various other situations. +char NetHackQtBind::qt_more() +{ + char ch = '\033'; + + // without this gameover hack, quitting via menu or window close + // button ends up provoking a complaint from qt_nhgetch() [see the + // ^C comment in that routine] when the core triggers --More-- via + // done2() -> really_done() -> display_nhwindow(WIN_MESSAGE, TRUE) + // (get rid of this if the exec() loop issue gets properly fixed) + if (::g.program_state.gameover) + return ch; // bypass --More-- and just continue with program exit + + NetHackQtMessageWindow *mesgwin = main ? main->GetMessageWindow() : NULL; + + // kill any typeahead; for '!popup_dialog' this forces qt_nhgetch() + keybuffer.Drain(); + + if (mesgwin && !::iflags.wc_popup_dialog && WIN_MESSAGE != WIN_ERR) { + + mesgwin->AddToStr("--More--"); + bool retry = false; + int complain = 0; + do { + ch = NetHackQtBind::qt_nhgetch(); + switch (ch) { + case '\0': // hypothetical + ch = '\033'; + /*FALLTHRU*/ + case ' ': + case '\n': + case '\r': + case '\033': + retry = false; + break; + default: + if (++complain > 1) + NetHackQtBind::qt_nhbell(); + // typing anything caused the most recent message line + // (which happens to our prompt) from having highlighting + // be removed; put that back + if (mesgwin) + mesgwin->RehighlightPrompt(); + retry = true; + break; + } + } while (retry); + // unhighlight the line with the prompt; does not erase the window + NetHackQtBind::qt_clear_nhwindow(WIN_MESSAGE); + + } else { + // use a popup dialog box; unlike yn_function(), we don't show + // the prompt+response in the message window + NetHackQtYnDialog dialog(main, "--More--", " \033\n\r", ' '); + ch = dialog.Exec(); + if (ch == '\0') { + ch = '\033'; + } + // discard any input that YnDialog() might have left pending + keybuffer.Drain(); + } + + return ch; +} + +char NetHackQtBind::qt_yn_function(const char *question_, + const char *choices, CHAR_P def) { QString question(QString::fromLatin1(question_)); QString message; char yn_esc_map='\033'; + int result = -1; if (choices) { - // anything beyond is hidden> - QString choicebuf = choices; - size_t cb = choicebuf.indexOf('\033'); - choicebuf = choicebuf.mid(0U, cb); + QString choicebuf((int) strlen(choices) + 1, QChar('\0')); + for (const char *p = choices; *p; ++p) { + if (*p == '\033') // and anything beyond is hidden + break; + choicebuf += visctrl(*p); + } + choicebuf.truncate(QBUFSZ - 1); // no effect if already shorter message = QString("%1 [%2] ").arg(question, choicebuf); - if (def) message += QString("(%1) ").arg(QChar(def)); + if (def) + message += QString("(%1) ").arg(QChar(def)); // escape maps to 'q' or 'n' or default, in that order - yn_esc_map = (strchr(choices, 'q') ? 'q' : - (strchr(choices, 'n') ? 'n' : def)); + yn_esc_map = strchr(choices, 'q') ? 'q' + : strchr(choices, 'n') ? 'n' + : def; } else { message = question; } - if (qt_settings->ynInMessages() && WIN_MESSAGE!=WIN_ERR) { + if ( + /* + * The 'Settings' dialog doesn't present prompting-in-message-window + * as a candidate for customization but core supports 'popup_dialog' + * option so let player use that instead. + */ +#if 0 + qt_settings->ynInMessages() +#else + !::iflags.wc_popup_dialog +#endif + && WIN_MESSAGE != WIN_ERR) { // Similar to X11 windowport `slow' feature. - int result = -1; - -#ifdef USE_POPUPS - if (choices) { - if (!strcmp(choices,"ynq")) - result = QMessageBox::information (NetHackQtBind::mainWidget(),"NetHack",question,"&Yes","&No","&Quit",0,2); - else if (!strcmp(choices,"yn")) - result = QMessageBox::information(NetHackQtBind::mainWidget(),"NetHack",question,"&Yes", "&No",0,1); - else if (!strcmp(choices, "rl")) - result = QMessageBox::information(NetHackQtBind::mainWidget(),"NetHack",question,"&Right", "&Left",0,1); - - if (result >= 0 && result < strlen(choices)) { - char yn_resp = choices[result]; - message += QString(" %1").arg(yn_resp); - result = yn_resp; - } - } -#endif + char cbuf[20]; + cbuf[0] = '\0'; + // add the prompt to the messsage window NetHackQtBind::qt_putstr(WIN_MESSAGE, ATR_BOLD, message); while (result < 0) { + cbuf[0] = '\0'; char ch=NetHackQtBind::qt_nhgetch(); if (ch=='\033') { result=yn_esc_map; + Strcpy(cbuf, "ESC"); } else if (choices && !strchr(choices,ch)) { if (def && (ch==' ' || ch=='\r' || ch=='\n')) { result=def; + Strcpy(cbuf, visctrl(def)); } else { NetHackQtBind::qt_nhbell(); + // typing anything caused the most recent message line + // (which happens to our prompt) from having highlighting + // be removed; put that back + NetHackQtMessageWindow + *mesgwin = main ? main->GetMessageWindow() : NULL; + if (mesgwin) + mesgwin->RehighlightPrompt(); // and try again... } } else { result=ch; + Strcpy(cbuf, visctrl(ch)); } } - NetHackQtBind::qt_clear_nhwindow(WIN_MESSAGE); + // update the prompt message line to include the response + if (cbuf[0]) { + if (!strcmp(cbuf, " ")) + Strcpy(cbuf, "SPC"); + + NetHackQtMessageWindow *mesgwin = main->GetMessageWindow(); + if (mesgwin) + mesgwin->AddToStr(cbuf); + } - return result; } else { - NetHackQtYnDialog dialog(mainWidget(),question,choices,def); - char ret = dialog.Exec(); - if (!(ret == '\0' || ret == '\033') && choices) - message += QString(" %1").arg(ret); - else if (def) - message += QString(" %1").arg(def); - NetHackQtBind::qt_putstr(WIN_MESSAGE, ATR_BOLD, message); + // use a popup dialog box + NetHackQtYnDialog dialog(main, question, choices, def); + char ret = dialog.Exec(); + if (ret == 0) { + ret = '\033'; + } + // discard any input that YnDialog() might have left pending + keybuffer.Drain(); - return ret; + // combine the prompt and result + char cbuf[40]; + Strcpy(cbuf, (ret == '\033') ? "ESC" + : (ret == ' ') ? "SPC" + : visctrl(ret)); + if (ret == '#' && choices && !strncmp(choices, "yn#", (size_t) 3)) + Sprintf(eos(cbuf), " %ld", ::yn_number); + message += QString(" %1").arg(cbuf); + + // add the prompt with appended response to the message window + if (WIN_MESSAGE != WIN_ERR) + NetHackQtBind::qt_putstr(WIN_MESSAGE, ATR_BOLD, message); + + result = ret; } + + // unhighlight the prompt; does not erase the multi-line message window + if (WIN_MESSAGE != WIN_ERR) + NetHackQtBind::qt_clear_nhwindow(WIN_MESSAGE); + + return (char) result; } void NetHackQtBind::qt_getlin(const char *prompt, char *line) { NetHackQtStringRequestor requestor(mainWidget(),prompt); - if (!requestor.Get(line)) { - line[0]=0; + if (!requestor.Get(line, BUFSZ, 40)) { + Strcpy(line, "\033"); + // discard any input that Get() might have left pending + keybuffer.Drain(); } + + // add the prompt with appended response to the messsage window + char buf[BUFSZ + 20], *q; /* +20: plenty of extra room for visctrl() */ + copynchars(buf, prompt, BUFSZ - 1); + q = eos(buf); + *q++ = ' '; /* guaranteed to fit; temporary lack of terminator is ok */ + + if (line[0] == '\033') { + Strcpy(q, "ESC"); + } else if (line[0] == ' ' && !line[1]) { + Strcpy(q, "SPC"); + } else { + /* buf[] has more than enough room to hold one extra visctrl() + in case q is at the last viable slot and *p yields "M-^c" */ + for (char *p = line; *p && q < &buf[BUFSZ - 1]; ++p, q = eos(q)) + Strcpy(q, visctrl(*p)); + } + if (q > &buf[BUFSZ - 1]) + q = &buf[BUFSZ - 1]; + *q = '\0'; + + NetHackQtBind::qt_putstr(WIN_MESSAGE, ATR_BOLD, buf); + // unhighlight the prompt; does not erase the multi-line message window + NetHackQtBind::qt_clear_nhwindow(WIN_MESSAGE); } +// User has typed '#' to begin entering an extended command; core calls us. int NetHackQtBind::qt_get_ext_cmd() { - NetHackQtExtCmdRequestor requestor(mainWidget()); - return requestor.get(); + NetHackQtExtCmdRequestor *xcmd; + int result; + do { + xcmd = new NetHackQtExtCmdRequestor(mainWidget()); + result = xcmd->get(); + delete xcmd; + } while (result == xcmdNoMatch); + return result; } void NetHackQtBind::qt_number_pad(int) @@ -613,17 +833,30 @@ void NetHackQtBind::qt_outrip(winid wid, int how, time_t when) window->UseRIP(how, when); } -char * NetHackQtBind::qt_getmsghistory(BOOLEAN_P init) +void NetHackQtBind::qt_preference_update(const char *optname) { - NetHackQtMessageWindow* window = main->GetMessageWindow(); +#ifdef DYNAMIC_STATUSLINES // defined in qt_main.h + if (!strcmp(optname, "statuslines")) { + // delete and recreate status window + // to toggle statuslines from 2 to 3 or vice versa + id_to_window[WIN_STATUS] = main->redoStatus(); + } +#else + nhUse(optname); +#endif +} + +char *NetHackQtBind::qt_getmsghistory(BOOLEAN_P init) +{ + NetHackQtMessageWindow *window = main->GetMessageWindow(); if (window) - return (char *)window->GetStr(init); + return (char *) window->GetStr((bool) init); return NULL; } void NetHackQtBind::qt_putmsghistory(const char *msg, BOOLEAN_P is_restoring) { - NetHackQtMessageWindow* window = main->GetMessageWindow(); + NetHackQtMessageWindow *window = main->GetMessageWindow(); if (!window) return; @@ -633,7 +866,7 @@ void NetHackQtBind::qt_putmsghistory(const char *msg, BOOLEAN_P is_restoring) int i = 0; const char *str; - while ((str = window->GetStr((i == 0)))) { + while ((str = window->GetStr((bool) (i == 0))) != 0) { msgs_strings->append(str); i++; } @@ -650,11 +883,11 @@ void NetHackQtBind::qt_putmsghistory(const char *msg, BOOLEAN_P is_restoring) #endif } else if (msgs_saved) { /* restore strings */ - int i; - for (i = 0; i < msgs_strings->size(); i++) { - window->PutStr(ATR_NONE, msgs_strings->at((i))); + for (int i = 0; i < msgs_strings->size(); ++i) { + const QString &nxtmsg = msgs_strings->at(i); + window->PutStr(ATR_NONE, nxtmsg); #ifdef DUMPLOG - dumplogmsg(msgs_strings->at(i).toLatin1().constData()); + dumplogmsg(nxtmsg.toLatin1().constData()); #endif } delete msgs_strings; @@ -662,50 +895,68 @@ void NetHackQtBind::qt_putmsghistory(const char *msg, BOOLEAN_P is_restoring) } } +// event loop callback bool NetHackQtBind::notify(QObject *receiver, QEvent *event) { // Ignore Alt-key navigation to menubar, it's annoying when you // use Alt-Direction to move around. - if ( main && event->type()==QEvent::KeyRelease && main==receiver - && ((QKeyEvent*)event)->key() == Qt::Key_Alt ) - return true; + if (main && receiver == main && event->type() == QEvent::KeyRelease + && ((QKeyEvent *) event)->key() == Qt::Key_Alt) + return true; - bool result=QApplication::notify(receiver,event); - if (event->type()==QEvent::KeyPress) { - QKeyEvent* key_event=(QKeyEvent*)event; + bool result = QApplication::notify(receiver, event); + int evtyp = event->type(); - if (!key_event->isAccepted()) { - const int k=key_event->key(); - bool macro=false; - for (int i=0; !macro && key_macro[i].key; i++) { - if (key_macro[i].key==k - && ((key_macro[i].state&key_event->modifiers())==key_macro[i].state)) - { - keybuffer.Put(key_macro[i].macro); - macro=true; - } - } - QString key=key_event->text(); - QChar ch = !key.isEmpty() ? key.at(0) : 0; - if (ch > 128) ch = 0; - if ( ch == 0 && (key_event->modifiers() & Qt::ControlModifier) ) { - // On Mac, ascii control codes are not sent, force them. - if ( k>=Qt::Key_A && k<=Qt::Key_Z ) - ch = k - Qt::Key_A + 1; - } - if (!macro && ch != 0) { - bool alt = (key_event->modifiers()&Qt::AltModifier) || - (k >= Qt::Key_0 && k <= Qt::Key_9 && (key_event->modifiers()&Qt::ControlModifier)); - keybuffer.Put(key_event->key(),ch.cell() + (alt ? 128 : 0), - key_event->modifiers()); - key_event->accept(); - result=true; - } + if (evtyp == QEvent::KeyPress) { + QKeyEvent *key_event = (QKeyEvent *) event; - if (ch != 0 || macro) { - qApp->exit(); - } - } + if (!key_event->isAccepted()) { + Qt::KeyboardModifiers mod = key_event->modifiers(); + const int k = key_event->key(); + for (int i = 0; key_macro[i].key; i++) { + if (key_macro[i].key == k + && ((key_macro[i].state & mod) == key_macro[i].state)) { + // matched macro; put its expansion into the input buffer + keybuffer.Put(!::iflags.num_pad ? key_macro[i].macro + : key_macro[i].numpad_macro); + key_event->accept(); + qApp->exit(); + return true; + } + } + QString key = key_event->text(); + QChar ch = !key.isEmpty() ? key.at(0) : 0; + if (ch > 128) + ch = 0; + // on OSX, ascii control codes are not sent, force them + if (ch == 0 && (mod & Qt::ControlModifier) != 0) { + if (k >= Qt::Key_A && k <= Qt::Key_Underscore) + ch = (QChar) (k - (Qt::Key_A - 1)); + } + //raw_printf("notify()=%d \"%s\"", k, visctrl(ch.cell())); + // if we have a valid character, queue it up + if (ch != 0) { + bool alt = ((mod & Qt::AltModifier) != 0 + || (k >= Qt::Key_0 && k <= Qt::Key_9 + && (mod & Qt::ControlModifier) != 0)); + keybuffer.Put(k, ch.cell() + (alt ? 128 : 0), (uint) mod); + key_event->accept(); + qApp->exit(); + result = true; + } + +#if 0 /* this was a failed attempt to prevent qt_more() from looping + * after command+q (on OSX) is used to bring up the quit dialog; + * now qt_more() uses an early return if program_state.gameover + * is set */ + } else if (evtyp == QEvent::FocusOut + || evtyp == QEvent::ShortcutOverride + || evtyp == QEvent::PlatformSurface) { + // leave qt_nhgetch()'s event loop if focus switches somewhere else + qApp->exit(); + result = false; +#endif + } } return result; } @@ -718,19 +969,19 @@ QFrame* NetHackQtBind::splash=0; QStringList *NetHackQtBind::msgs_strings; boolean NetHackQtBind::msgs_saved = false; boolean NetHackQtBind::msgs_initd = false; - +#if 0 static void Qt_positionbar(char *) {} - +#endif } // namespace nethack_qt_ struct window_procs Qt_procs = { "Qt", - WC_COLOR | WC_HILITE_PET - | WC_ASCII_MAP | WC_TILED_MAP - | WC_FONT_MAP | WC_TILE_FILE | WC_TILE_WIDTH | WC_TILE_HEIGHT - | WC_PLAYER_SELECTION | WC_SPLASH_SCREEN, - 0L, - {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, /* color availability */ + (WC_COLOR | WC_HILITE_PET + | WC_ASCII_MAP | WC_TILED_MAP + | WC_FONT_MAP | WC_TILE_FILE | WC_TILE_WIDTH | WC_TILE_HEIGHT + | WC_POPUP_DIALOG | WC_PLAYER_SELECTION | WC_SPLASH_SCREEN), + (WC2_HITPOINTBAR | WC2_STATUSLINES), + {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, /* color availability */ nethack_qt_::NetHackQtBind::qt_init_nhwindows, nethack_qt_::NetHackQtBind::qt_player_selection, nethack_qt_::NetHackQtBind::qt_askname, @@ -787,8 +1038,7 @@ struct window_procs Qt_procs = { #else genl_outrip, #endif - genl_preference_update, - + nethack_qt_::NetHackQtBind::qt_preference_update, nethack_qt_::NetHackQtBind::qt_getmsghistory, nethack_qt_::NetHackQtBind::qt_putmsghistory, genl_status_init, @@ -802,7 +1052,11 @@ struct window_procs Qt_procs = { }; #ifndef WIN32 -extern "C" void play_usersound(const char* filename, int volume) +#if defined(USER_SOUNDS) && !defined(QT_NO_SOUND) +extern "C" void play_usersound(const char* filename, int volume UNUSED) +#else +extern "C" void play_usersound(const char* filename UNUSED, int volume UNUSED) +#endif { #ifdef USER_SOUNDS #ifndef QT_NO_SOUND diff --git a/win/Qt/qt_bind.h b/win/Qt/qt_bind.h index e7dacf1c3..73f4d4fa8 100644 --- a/win/Qt/qt_bind.h +++ b/win/Qt/qt_bind.h @@ -63,14 +63,17 @@ public: static void qt_cliparound(int x, int y); static void qt_cliparound_window(winid wid, int x, int y); - static void qt_print_glyph(winid wid,XCHAR_P x,XCHAR_P y,int glyph,int bkglyph); + static void qt_print_glyph(winid wid, XCHAR_P x, XCHAR_P y, + int glyph, int bkglyph, unsigned int *); static void qt_raw_print(const char *str); static void qt_raw_print_bold(const char *str); static int qt_nhgetch(); static int qt_nh_poskey(int *x, int *y, int *mod); static void qt_nhbell(); static int qt_doprev_message(); - static char qt_yn_function(const char *question, const char *choices, CHAR_P def); + static char qt_more(); + static char qt_yn_function(const char *question, + const char *choices, CHAR_P def); static void qt_getlin(const char *prompt, char *line); static int qt_get_ext_cmd(); static void qt_number_pad(int); @@ -78,6 +81,7 @@ public: static void qt_start_screen(); static void qt_end_screen(); + static void qt_preference_update(const char *optname); static char *qt_getmsghistory(BOOLEAN_P init); static void qt_putmsghistory(const char *msg, BOOLEAN_P is_restoring); diff --git a/win/Qt/qt_click.cpp b/win/Qt/qt_click.cpp index 6cee16258..d8f5030b7 100644 --- a/win/Qt/qt_click.cpp +++ b/win/Qt/qt_click.cpp @@ -4,18 +4,13 @@ // qt_click.cpp -- a mouse click buffer +extern "C" { #include "hack.h" -#undef Invisible -#undef Warning -#undef index -#undef msleep -#undef rindex -#undef wizard -#undef yn -#undef min -#undef max +} +#include "qt_pre.h" #include +#include "qt_post.h" #include "qt_click.h" namespace nethack_qt_ { diff --git a/win/Qt/qt_clust.cpp b/win/Qt/qt_clust.cpp index b21a53a74..d63d2d7de 100644 --- a/win/Qt/qt_clust.cpp +++ b/win/Qt/qt_clust.cpp @@ -5,163 +5,165 @@ static void include(QRect& r, const QRect& rect) { - if (rect.left()r.right()) { - r.setRight(rect.right()); - } - if (rect.top()r.bottom()) { - r.setBottom(rect.bottom()); - } + if (rect.left() < r.left()) { + r.setLeft(rect.left()); + } + if (rect.right() > r.right()) { + r.setRight(rect.right()); + } + if (rect.top() < r.top()) { + r.setTop(rect.top()); + } + if (rect.bottom() > r.bottom()) { + r.setBottom(rect.bottom()); + } } /* -A Clusterizer groups rectangles (QRects) into non-overlapping rectangles -by a merging heuristic. -*/ + * A Clusterizer groups rectangles (QRects) into non-overlapping + * rectangles by a merging heuristic. + */ Clusterizer::Clusterizer(int maxclusters) : - cluster(new QRect[maxclusters]), - count(0), - max(maxclusters) -{ } + cluster(new QRect[maxclusters]), + count(0), + max(maxclusters) +{ +} Clusterizer::~Clusterizer() { - delete [] cluster; + delete [] cluster; } void Clusterizer::clear() { - count=0; + count = 0; } void Clusterizer::add(int x, int y) { - add(QRect(x,y,1,1)); + add(QRect(x, y, 1, 1)); } void Clusterizer::add(int x, int y, int w, int h) { - add(QRect(x,y,w,h)); + add(QRect(x, y, w, h)); } void Clusterizer::add(const QRect& rect) { - QRect biggerrect(rect.x()-1,rect.y()-1,rect.width()+2,rect.height()+2); + QRect biggerrect(rect.x() - 1, rect.y() - 1, + rect.width() + 2, rect.height() + 2); - //assert(rect.width()>0 && rect.height()>0); + //assert(rect.width() > 0 && rect.height() > 0); - int cursor; + int cursor; - for (cursor=0; cursor=0) { - include(cluster[cheapest],rect); - return; - } + if (cost < lowestcost) { + bool bad = false; + for (int c = 0; c < count && !bad; c++) { + bad = cluster[c].intersects(larger) && c != cursor; + } + if (!bad) { + cheapest = cursor; + lowestcost = cost; + } + } + } + } + if (cheapest >= 0) { + include(cluster[cheapest], rect); + return; + } - if (count < max) { - cluster[count++]=rect; - return; - } + if (count < max) { + cluster[count++] = rect; + return; + } - // Do cheapest of: - // add to closest cluster - // do cheapest cluster merge, add to new cluster + // Do cheapest of: + // add to closest cluster + // do cheapest cluster merge, add to new cluster - lowestcost=9999999; - cheapest=-1; - for (cursor=0; cursor=0) { - include(cluster[cheapestmerge1],cluster[cheapestmerge2]); - cluster[cheapestmerge2]=cluster[count--]; - } else { - // if (!cheapest) debugRectangles(rect); - include(cluster[cheapest],rect); - } + if (cheapestmerge1 >= 0) { + include(cluster[cheapestmerge1], cluster[cheapestmerge2]); + cluster[cheapestmerge2] = cluster[count--]; + } else { + // if (!cheapest) debugRectangles(rect); + include(cluster[cheapest],rect); + } - // NB: clusters do not intersect (or intersection will - // overwrite). This is a result of the above algorithm, - // given the assumption that (x,y) are ordered topleft - // to bottomright. + // NB: clusters do not intersect (or intersection will + // overwrite). This is a result of the above algorithm, + // given the assumption that (x,y) are ordered topleft + // to bottomright. } const QRect& Clusterizer::operator[](int i) { - return cluster[i]; + return cluster[i]; } diff --git a/win/Qt/qt_delay.cpp b/win/Qt/qt_delay.cpp index 1728b3702..0fa3003ce 100644 --- a/win/Qt/qt_delay.cpp +++ b/win/Qt/qt_delay.cpp @@ -4,18 +4,13 @@ // qt_delay.cpp -- implement a delay +extern "C" { #include "hack.h" -#undef Invisible -#undef Warning -#undef index -#undef msleep -#undef rindex -#undef wizard -#undef yn -#undef min -#undef max +} +#include "qt_pre.h" #include +#include "qt_post.h" #include "qt_delay.h" namespace nethack_qt_ { @@ -32,7 +27,7 @@ void NetHackQtDelay::wait() m_loop.exec(); } -void NetHackQtDelay::timerEvent(QTimerEvent* timer) +void NetHackQtDelay::timerEvent(QTimerEvent* timer UNUSED) { m_loop.exit(); killTimer(m_timer); diff --git a/win/Qt/qt_glyph.cpp b/win/Qt/qt_glyph.cpp index a3e4f24ef..f807282f3 100644 --- a/win/Qt/qt_glyph.cpp +++ b/win/Qt/qt_glyph.cpp @@ -6,24 +6,20 @@ extern "C" { #include "hack.h" +#include "tile2x11.h" /* x11tiles is potential fallback for nhtiles.bmp */ } -#include "tile2x11.h" -#undef Invisible -#undef Warning -#undef index -#undef msleep -#undef rindex -#undef wizard -#undef yn -#undef min -#undef max +#include "qt_pre.h" #include #if QT_VERSION >= 0x050000 #include #endif +#include "qt_post.h" #include "qt_glyph.h" +#include "qt_bind.h" #include "qt_set.h" +#include "qt_inv.h" +#include "qt_map.h" #include "qt_str.h" extern short glyph2tile[]; // from tile.c @@ -45,31 +41,39 @@ static int tilefile_tile_H=16; NetHackQtGlyphs::NetHackQtGlyphs() { const char* tile_file = PIXMAPDIR "/nhtiles.bmp"; - if ( iflags.wc_tile_file ) + + if (iflags.wc_tile_file) tile_file = iflags.wc_tile_file; if (!img.load(tile_file)) { + tiles_per_row = TILES_PER_ROW; + tile_file = PIXMAPDIR "/x11tiles"; if (!img.load(tile_file)) { QString msg; - msg.sprintf("Cannot load x11tiles or nhtiles.bmp"); - QMessageBox::warning(0, "IO Error", msg); + msg.sprintf("Cannot load 'nhtiles.bmp' or 'x11tiles'."); + QMessageBox::warning(0, "IO Error", msg); + iflags.wc_ascii_map = 1; + iflags.wc_tiled_map = 0; } else { - tiles_per_row = TILES_PER_ROW; - if (img.width()%tiles_per_row) { - impossible("Tile file \"%s\" has %d columns, not multiple of row count (%d)", - tile_file, img.width(), tiles_per_row); + if (img.width() % tiles_per_row) { + impossible( + "Tile file \"%s\" has %d columns, not multiple of row count (%d)", + tile_file, img.width(), tiles_per_row); } } } else { tiles_per_row = 40; } - if ( iflags.wc_tile_width ) + if (iflags.wc_tile_width) tilefile_tile_W = iflags.wc_tile_width; + else if (iflags.wc_ascii_map) + tilefile_tile_W = 16; else tilefile_tile_W = img.width() / tiles_per_row; - if ( iflags.wc_tile_height ) + + if (iflags.wc_tile_height) tilefile_tile_H = iflags.wc_tile_height; else tilefile_tile_H = tilefile_tile_W; @@ -77,62 +81,153 @@ NetHackQtGlyphs::NetHackQtGlyphs() setSize(tilefile_tile_W, tilefile_tile_H); } -void NetHackQtGlyphs::drawGlyph(QPainter& painter, int glyph, int x, int y) +void NetHackQtGlyphs::drawGlyph(QPainter& painter, int glyph, int x, int y, + bool fem, bool reversed) { - int tile = glyph2tile[glyph]; - int px = (tile%tiles_per_row)*width(); - int py = tile/tiles_per_row*height(); + if (!reversed) { + int tile = glyph2tile[glyph]; + if (fem) + ++tile; + int px = (tile % tiles_per_row) * width(); + int py = tile / tiles_per_row * height(); - painter.drawPixmap( - x, - y, - pm, - px,py, - width(),height() + painter.drawPixmap(x, y, pm, px, py, width(), height()); + } else { + // for paper doll; mirrored image for left side of two-handed weapon + painter.drawPixmap(x, y, reversed_pixmap(glyph, fem), + 0, 0, width(), height()); + } +} + +void NetHackQtGlyphs::drawCell(QPainter& painter, int glyph, + int cellx, int celly, bool fem) +{ + drawGlyph(painter, glyph, cellx * width(), celly * height(), fem, false); +} + +void NetHackQtGlyphs::drawBorderedCell(QPainter& painter, int glyph, + int cellx, int celly, int border, + bool reversed, bool fem) +{ + int wd = width(), + ht = height(), + yoffset = 1, // tiny extra margin at top + lox = cellx * (wd + 2), + loy = celly * (ht + 2) + yoffset; + + drawGlyph(painter, glyph, lox + 1, loy + 1, fem, reversed); + +#ifdef TEXTCOLOR + if (border != NO_BORDER) { + // gray would be a better mid-point between red and cyan but it + // doesn't show up well enough against the wall tile background + painter.setPen((border == BORDER_CURSED) ? Qt::red + : (border == BORDER_UNCURSED) ? Qt::yellow + : (border == BORDER_BLESSED) ? Qt::cyan + : Qt::white); // BORDER_DEFAULT + // assuming 32x32, draw 34x34 rectangle from 0..33x0..33, outside glyph +#if 0 /* Qt 5.11 drawRect(x,y,width,height) seems to have an off by 1 bug; + * drawRect(0,0,34,34) is drawing at 0..34x0..34 which is 35x35; + * should subtract 1 when adding width and/or height to base coord; + * the relevant code in QtCore/QRect.h is correct so this observable + * misbehavior is a mystery... */ + painter.drawRect(lox, loy, wd + 2, ht + 2); +#else + painter.drawLine(lox, loy, lox + wd + 1, loy); // 0,0->33,0 + painter.drawLine(lox, loy + ht + 1, lox + wd + 1, loy + ht + 1); + painter.drawLine(lox, loy, lox, loy + ht + 1); // 0,0->0,33 + painter.drawLine(lox + wd + 1, loy, lox + wd + 1, loy + ht + 1); +#endif + if (border != BORDER_DEFAULT) { + // assuming 32x32, draw rectangle from 1..32x1..32, inside glyph +#if 0 /* (see above) */ + painter.drawRect(lox + 1, loy + 1, wd, ht); +#else + painter.drawLine(lox + 1, loy + 1, lox + wd, loy + 1); // 1,1->32,1 + painter.drawLine(lox + 1, loy + ht, lox + wd, loy + ht); + painter.drawLine(lox + 1, loy + 1, lox + 1, loy + ht); // 1,1->1,32 + painter.drawLine(lox + wd, loy + 1, lox + wd, loy + ht); +#endif + for (int i = lox + 2; i < lox + wd - 1; i += 2) { + // assuming 32x32, draw points along <2..31,2> and <2..31,31> + painter.drawPoint(i, loy + 2); + painter.drawPoint(i + 1, loy + ht - 1); + } + for (int j = loy + 2; j < loy + ht - 1; j += 2) { + // assuming 32x32, draw points along <2,2..31> and <31,2..31> + painter.drawPoint(lox + 2, j); + painter.drawPoint(lox + wd - 1, j + 1); + } + } + } +#else + nhUse(border); +#endif +} + +// mis-named routine to get the pixmap for a particular glyph +QPixmap NetHackQtGlyphs::glyph(int glyphindx, bool fem) +{ + int tile = glyph2tile[glyphindx]; + if (fem) + ++tile; + int px = (tile % tiles_per_row) * tilefile_tile_W; + int py = tile / tiles_per_row * tilefile_tile_H; + + return QPixmap::fromImage(img.copy(px, py, + tilefile_tile_W, tilefile_tile_H)); +} + +// transpose a glyph's tile horizontally, scaled for use in paper doll +QPixmap NetHackQtGlyphs::reversed_pixmap(int glyphindx, bool fem) +{ + QPixmap pxmp = glyph(glyphindx, fem); +#ifdef ENHANCED_PAPERDOLL + qreal wid = (qreal) pxmp.width(), + //hgt = (qreal) pxmp.height(), + xscale = (qreal) qt_settings->dollWidth / (qreal) tilefile_tile_W, + yscale = (qreal) qt_settings->dollHeight / (qreal) tilefile_tile_H; + QTransform *mirrormatrix = new QTransform( + // negate x coordinates to flip the image across the y-axis + -1.0 * xscale, 0.0, 0.0, yscale, + // slide flipped image to the right to make things positive again + wid * xscale, 0.0 ); + return pxmp.transformed(*mirrormatrix); +#else + return pxmp; +#endif } -void NetHackQtGlyphs::drawCell(QPainter& painter, int glyph, int cellx, int celly) -{ - drawGlyph(painter,glyph,cellx*width(),celly*height()); -} -QPixmap NetHackQtGlyphs::glyph(int glyph) -{ - int tile = glyph2tile[glyph]; - int px = (tile%tiles_per_row)*tilefile_tile_W; - int py = tile/tiles_per_row*tilefile_tile_H; - return QPixmap::fromImage(img.copy(px, py, tilefile_tile_W, tilefile_tile_H)); -} void NetHackQtGlyphs::setSize(int w, int h) { - if ( size == QSize(w,h) ) + if (size == QSize(w, h)) return; - - bool was1 = size == pm1.size(); - size = QSize(w,h); + size = QSize(w, h); if (!w || !h) return; // Still not decided - if ( size == pm1.size() ) { + if (size == pm1.size()) { // not zoomed pm = pm1; return; } - if ( size == pm2.size() ) { + if (size == pm2.size()) { // zoomed pm = pm2; return; } - if (w==tilefile_tile_W && h==tilefile_tile_H) { + bool was1 = (size == pm1.size()); + if (w == tilefile_tile_W && h == tilefile_tile_H) { pm.convertFromImage(img); } else { - QApplication::setOverrideCursor( Qt::WaitCursor ); + QApplication::setOverrideCursor(Qt::WaitCursor); QImage scaled = img.scaled( - w*img.width()/tilefile_tile_W, - h*img.height()/tilefile_tile_H, + w * img.width() / tilefile_tile_W, + h * img.height() / tilefile_tile_H, Qt::IgnoreAspectRatio, Qt::FastTransformation ); - pm.convertFromImage(scaled,Qt::ThresholdDither|Qt::PreferDither); + pm.convertFromImage(scaled, Qt::ThresholdDither | Qt::PreferDither); QApplication::restoreOverrideCursor(); } (was1 ? pm2 : pm1) = pm; diff --git a/win/Qt/qt_glyph.h b/win/Qt/qt_glyph.h index b85c4f4d3..afc2b92ca 100644 --- a/win/Qt/qt_glyph.h +++ b/win/Qt/qt_glyph.h @@ -9,6 +9,11 @@ namespace nethack_qt_ { +enum border_code { + NO_BORDER, BORDER_DEFAULT, + BORDER_CURSED, BORDER_UNCURSED, BORDER_BLESSED +}; + class NetHackQtGlyphs { public: NetHackQtGlyphs(); @@ -18,15 +23,21 @@ public: void toggleSize(); void setSize(int w, int h); - void drawGlyph(QPainter&, int glyph, int pixelx, int pixely); - void drawCell(QPainter&, int glyph, int cellx, int celly); - QPixmap glyph(int glyph); + void drawGlyph(QPainter &, int glyph, int pixelx, int pixely, + bool fem, bool reversed = false); + void drawCell(QPainter &, int glyph, int cellx, int celly, bool fem); + void drawBorderedCell(QPainter &, int glyph, + int cellx, int celly, int bordercode, + bool reversed, bool fem = false); + QPixmap glyph(int glyphindx, bool fem = false); + QPixmap reversed_pixmap(int glyphindx, bool fem = false); private: QImage img; QPixmap pm,pm1, pm2; QSize size; int tiles_per_row; + //QTransform *mirrormatrix; }; } // namespace nethack_qt_ diff --git a/win/Qt/qt_icon.cpp b/win/Qt/qt_icon.cpp index 160fc7e10..b8f0e694d 100644 --- a/win/Qt/qt_icon.cpp +++ b/win/Qt/qt_icon.cpp @@ -2,70 +2,105 @@ // Qt4 conversion copyright (c) Ray Chason, 2012-2014. // NetHack may be freely redistributed. See license for details. -// qt_icon.cpp -- a labelled icon +// qt_icon.cpp -- a labelled icon for display in the status window +// +// TODO? +// When the label specifies two values separated by a slash (curHP/maxHP, +// curEn/maxEn, XpLevel/ExpPoints when 'showexp' is On), highlighting +// for changes is all or nothing based on which field caller passes +// as the value to use for comparison. curHP and curEn go up and down +// without any change to the corresponding maximum all the time. Much +// rarer, but when maxHP and maxEn go up with level gain, the hero +// could be injured by a passive counterattack or collateral damage +// from an area effect--or much simpler, the casting cost of a spell +// that killed a monster and produced the level gain--so the current +// value could stay the same or even go down at same time max goes up. +// Likewise, Exp goes up a lot but Xp relatively rarely. (On the very +// rare occasions where either goes down, they'll both do so.) +// Highlighting two slash-separated values independently would be +// worthwhile but with the 'single label using a style sheet for color' +// approach it isn't going to happen. +// FIXME: +// Every LabelledIcon duplicates hl_better, hl_worse, hl_changd. +// +extern "C" { #include "hack.h" -#undef Invisible -#undef Warning -#undef index -#undef msleep -#undef rindex -#undef wizard -#undef yn -#undef min -#undef max +} +#include "qt_pre.h" #include #if QT_VERSION >= 0x050000 #include #endif +#include "qt_post.h" #include "qt_icon.h" namespace nethack_qt_ { -NetHackQtLabelledIcon::NetHackQtLabelledIcon(QWidget* parent, const char* l) : +NetHackQtLabelledIcon::NetHackQtLabelledIcon(QWidget *parent, const char *l) : QWidget(parent), - low_is_good(false), - prev_value(-123), - turn_count(-1), label(new QLabel(l,this)), - icon(0) + icon(NULL), + comp_mode(BiggerIsBetter), + prev_value(NoNum), + turn_count(-1L) { initHighlight(); } -NetHackQtLabelledIcon::NetHackQtLabelledIcon(QWidget* parent, const char* l, const QPixmap& i) : +NetHackQtLabelledIcon::NetHackQtLabelledIcon(QWidget *parent, const char *l, + const QPixmap &i) : QWidget(parent), - low_is_good(false), - prev_value(-123), - turn_count(-1), label(new QLabel(l,this)), - icon(new QLabel(this)) + icon(new QLabel(this)), + comp_mode(BiggerIsBetter), + prev_value(NoNum), + turn_count(-1L) { setIcon(i); initHighlight(); } +// set up the style sheet strings used to specify color for status field +// labels [done "once", but once for each LabelledIcon that's constructed, +// so about 30 copies overall with 3.6's status conditions] void NetHackQtLabelledIcon::initHighlight() { - hl_good = "QLabel { background-color : green; color : white }"; - hl_bad = "QLabel { background-color : red ; color : white }"; + // note: string "green" is much darker than enum Qt::green + // QColor("green") => #00ff00 + // QColor(Qt::green) => #008000 + // QColor("green").lighter(150) => #00c000 /* hitpoint bar's green */ + hl_better = "QLabel { background-color : #00c000 ; color : white }"; + hl_worse = "QLabel { background-color : red ; color : white }"; + hl_changd = "QLabel { background-color : blue ; color : white }"; } -void NetHackQtLabelledIcon::setLabel(const QString& t, bool lower) +void NetHackQtLabelledIcon::setLabel(const QString &t, bool lower) { if (!label) { label=new QLabel(this); label->setFont(font()); - resizeEvent(0); } if (label->text() != t) { label->setText(t); - highlight(lower==low_is_good ? hl_good : hl_bad); + ForceResize(); + if (comp_mode != NoCompare) { + highlight((comp_mode == NeitherIsBetter) ? hl_changd + : (comp_mode == (lower ? SmallerIsBetter + : BiggerIsBetter)) ? hl_better + : hl_worse); + } else if (turn_count) { + // if we don't want to highlight this status field but it is + // currently highlighted (perhaps optional Score recently went + // up and has just been toggled off), remove the highlight + unhighlight(); + } } } -void NetHackQtLabelledIcon::setLabel(const QString& t, long v, long cv, const QString& tail) +void NetHackQtLabelledIcon::setLabel(const QString& t, long v, long cv, + const QString& tail) { QString buf; if (v==NoNum) { @@ -77,16 +112,19 @@ void NetHackQtLabelledIcon::setLabel(const QString& t, long v, long cv, const QS prev_value=cv; } -void NetHackQtLabelledIcon::setLabel(const QString& t, long v, const QString& tail) +void NetHackQtLabelledIcon::setLabel(const QString& t, long v, + const QString& tail) { setLabel(t,v,v,tail); } void NetHackQtLabelledIcon::setIcon(const QPixmap& i) { - if (icon) icon->setPixmap(i); - else { icon=new QLabel(this); icon->setPixmap(i); resizeEvent(0); } - icon->resize(i.width(),i.height()); + if (!icon) + icon = new QLabel(this); + icon->setPixmap(i); + ForceResize(); + icon->resize(i.width(), i.height()); } void NetHackQtLabelledIcon::setFont(const QFont& f) @@ -95,14 +133,16 @@ void NetHackQtLabelledIcon::setFont(const QFont& f) if (label) label->setFont(f); } +// used to highlight status conditions going from Off (blank) to On as "Worse" void NetHackQtLabelledIcon::show() { -#if QT_VERSION >= 300 - if (isHidden()) -#else - if (!isVisible()) -#endif - highlight(hl_bad); + // Hunger and Encumbrance are worse when going from not shown + // to anything and they're set to SmallerIsBetter, so both + // BiggerIsBetter and SmallerIsBetter warrant hl_worse here. + // Fly, Lev, and Ride are set NeitherIsBetter so that when + // they appear they won't be classified as worse. + if (isHidden() && comp_mode != NoCompare) + highlight((comp_mode != NeitherIsBetter) ? hl_worse : hl_changd); QWidget::show(); } @@ -138,42 +178,50 @@ QSize NetHackQtLabelledIcon::minimumSizeHint() const void NetHackQtLabelledIcon::highlightWhenChanging() { - turn_count=0; + turn_count = 0; // turn_count starts negative (as flag to not highlight) } -void NetHackQtLabelledIcon::lowIsGood() +// set comp_mode to one of NoCompare or {Bigger,Smaller,Neither}IsBetter +void NetHackQtLabelledIcon::setCompareMode(int newmode) { - low_is_good=true; -} - -void NetHackQtLabelledIcon::dissipateHighlight() -{ - if (turn_count>0) { - turn_count--; - if (!turn_count) - unhighlight(); - } -} - -void NetHackQtLabelledIcon::highlight(const QString& hl) -{ - if (label) { // Surely it is?! - if (turn_count>=0) { - label->setStyleSheet(hl); - turn_count=4; - // `4' includes this turn, so dissipates after - // 3 more keypresses. - } else { - label->setStyleSheet(""); - } - } + comp_mode = newmode; } void NetHackQtLabelledIcon::unhighlight() { if (label) { // Surely it is?! - label->setStyleSheet(""); + label->setStyleSheet(""); } + if (turn_count > 0) + turn_count = 0; +} + +void NetHackQtLabelledIcon::highlight(const QString& hl) +{ + if (label) { // Surely it is?! + if (turn_count >= 0) { + label->setStyleSheet(hl); + turn_count = 4; + // 4 includes this turn, so dissipates after 3 more keypresses. + } else { + unhighlight(); + } + } +} + +void NetHackQtLabelledIcon::dissipateHighlight() +{ + if (turn_count > 0) { + if (!--turn_count) + unhighlight(); + } +} + +// used when label (most status fields) or pixmap (alignment, hunger, +// encumbrance) changes value +void NetHackQtLabelledIcon::ForceResize() +{ + this->resizeEvent((QResizeEvent *) NULL); } void NetHackQtLabelledIcon::resizeEvent(QResizeEvent*) diff --git a/win/Qt/qt_icon.h b/win/Qt/qt_icon.h index f1974ba44..454236896 100644 --- a/win/Qt/qt_icon.h +++ b/win/Qt/qt_icon.h @@ -9,26 +9,38 @@ namespace nethack_qt_ { +enum CompareMode { + NoCompare = -1, BiggerIsBetter = 0, + SmallerIsBetter = 1, NeitherIsBetter = 2 +}; + class NetHackQtLabelledIcon : public QWidget { public: - NetHackQtLabelledIcon(QWidget* parent, const char* label); - NetHackQtLabelledIcon(QWidget* parent, const char* label, const QPixmap& icon); + NetHackQtLabelledIcon(QWidget *parent, const char *label); + NetHackQtLabelledIcon(QWidget *parent, const char *label, + const QPixmap &icon); - enum { NoNum=-99999 }; - void setLabel(const QString&, bool lower=true); // a string - void setLabel(const QString&, long, const QString& tail=""); // a number - void setLabel(const QString&, long show_value, long comparative_value, const QString& tail=""); - void setIcon(const QPixmap&); - virtual void setFont(const QFont&); + enum { NoNum = -99999L }; + void setLabel(const QString &, bool lower=true); // string + void setLabel(const QString &, long, const QString &tail=""); // number + void setLabel(const QString &, long show_value, + long comparative_value, const QString &tail=""); + void setIcon(const QPixmap &); + virtual void setFont(const QFont &); + //QString labelText() { return QString(this->label->text()); } void highlightWhenChanging(); - void lowIsGood(); + void setCompareMode(int newmode); void dissipateHighlight(); + void ForceResize(); virtual void show(); virtual QSize sizeHint() const; virtual QSize minimumSizeHint() const; + QLabel *label; + QLabel *icon; + protected: void resizeEvent(QResizeEvent*); @@ -38,14 +50,13 @@ private: void highlight(const QString& highlight); void unhighlight(); - bool low_is_good; - int prev_value; - int turn_count; /* last time the value changed */ - QString hl_good; - QString hl_bad; + int comp_mode; /* compareMode; default is BiggerIsBetter */ + long prev_value; + long turn_count; /* last time the value changed */ - QLabel* label; - QLabel* icon; + QString hl_better; + QString hl_worse; + QString hl_changd; }; } // namespace nethack_qt_ diff --git a/win/Qt/qt_inv.cpp b/win/Qt/qt_inv.cpp index be31d536e..d309b6e52 100644 --- a/win/Qt/qt_inv.cpp +++ b/win/Qt/qt_inv.cpp @@ -2,98 +2,322 @@ // Qt4 conversion copyright (c) Ray Chason, 2012-2014. // NetHack may be freely redistributed. See license for details. -// qt_inv.cpp -- inventory usage window -// This is at the top center of the main window +// qt_inv.cpp -- inventory subset of equipment in use, +// displayed in a rectangular grid of object tiles +// +// Essentially a "paper doll" style display. [grep fodder] +// +// This is at the top center of the main window, between messages and +// status. Qt settings (non-OSX) or Preferences (OSX) has a checkbox to +// show it or hide it, plus the tile size to use (independent of map's +// tile size). Supported tile size is 6..48x6..48 with default of 32x32. +// +// TODO? +// When yn_function() is asking for an inventory letter (not sure whether +// that is currently discernable...), allow clicking on a cell in the +// paper doll grid to return the invlet of the item clicked upon. +// extern "C" { #include "hack.h" } -#undef Invisible -#undef Warning -#undef index -#undef msleep -#undef rindex -#undef wizard -#undef yn -#undef min -#undef max +#include "qt_pre.h" #include #if QT_VERSION >= 0x050000 #include #endif +#include "qt_post.h" #include "qt_inv.h" #include "qt_glyph.h" +#include "qt_main.h" #include "qt_set.h" namespace nethack_qt_ { +static struct obj * +find_tool(int tooltyp) +{ + struct obj *o; + + for (o = g.invent; o; o = o->nobj) { + if ((tooltyp == LEASH && o->otyp == LEASH && o->leashmon) + // OIL_LAMP is used for candles, lamps, lantern, candelabrum too + || (tooltyp == OIL_LAMP && o->lamplit)) + break; + } + return o; +} + NetHackQtInvUsageWindow::NetHackQtInvUsageWindow(QWidget* parent) : QWidget(parent) { setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + // needed to enable tool tips + setMouseTracking(true); + + // paperdoll is 6x3 but the indices are column oriented: 0..2x0..5 + for (int x = 0; x <= 2; ++x) + for (int y = 0; y <= 5; ++y) + tips[x][y] = NULL; } -void NetHackQtInvUsageWindow::drawWorn(QPainter& painter, obj* nhobj, int x, int y, bool canbe) +NetHackQtInvUsageWindow::~NetHackQtInvUsageWindow() +{ + for (int x = 0; x <= 2; ++x) + for (int y = 0; y <= 5; ++y) + if (tips[x][y]) + free((void *) tips[x][y]), tips[x][y] = NULL; +} + +void NetHackQtInvUsageWindow::drawWorn(QPainter &painter, obj *nhobj, + int x, int y, // cell index, not pixels + const char *alttip, int flags) { short int glyph; - if (nhobj) - glyph=obj_to_glyph(nhobj, rn2_on_display_rng); - else if (canbe) - glyph=cmap_to_glyph(S_room); - else - glyph=cmap_to_glyph(S_stone); + int border; + char tipstr[1 + BUFSZ + 1]; // extra room for leading and trailing space + bool rev = (flags == dollReverse), + canbe = (flags != dollUnused); - qt_settings->glyphs().drawCell(painter,glyph,x,y); + if (nhobj) { + border = BORDER_DEFAULT; +#ifdef ENHANCED_PAPERDOLL + // color margin around cell containing item whose BUC state is known + if (Role_if('P') && !Blind) + nhobj->bknown = 1; + if (nhobj->bknown) + border = nhobj->cursed ? BORDER_CURSED + : !nhobj->blessed ? BORDER_UNCURSED + : BORDER_BLESSED; + + // border color is used to indicate BUC state; make tip text match + boolean save_implicit_uncursed = ::flags.implicit_uncursed; + ::flags.implicit_uncursed = FALSE; + // set up a tool tip describing the item that will be displayed here + Sprintf(tipstr, " %s ", // extra spaces for enhanced readability + // xprname: invlet, space, dash, space, object description + xprname(nhobj, (char *) NULL, nhobj->invlet, FALSE, 0L, 0L)); + ::flags.implicit_uncursed = save_implicit_uncursed; + + // tips are managed with nethack's alloc(); we don't track allocation + // amount; allocated buffers get reused when big enough (usual case + // since paperdoll updates occur more often than equipment changes) + if (tips[x][y] && strlen(tipstr) > strlen(tips[x][y])) + free((void *) tips[x][y]), tips[x][y] = NULL; + + if (tips[x][y]) + Strcpy(tips[x][y], tipstr); // guaranteed to fit + else + tips[x][y] = dupstr(tipstr); +#endif + glyph = obj_to_glyph(nhobj, rn2_on_display_rng); + } else { + border = NO_BORDER; +#ifdef ENHANCED_PAPERDOLL + // caller usually passes an alternate tool tip for empty cells + size_t altlen = alttip ? 1U + strlen(alttip) + 1U : 0U; + if (tips[x][y] && (!alttip || altlen > strlen(tips[x][y]))) + free((void *) tips[x][y]), tips[x][y] = NULL; + + if (alttip) { + Sprintf(tipstr, " %s ", alttip); + if (tips[x][y]) + Strcpy(tips[x][y], tipstr); // guaranteed to fit + else + tips[x][y] = dupstr(tipstr); + } +#else + nhUse(alttip); +#endif + // an empty slot is shown as floor tile unless it's always empty + glyph = canbe ? cmap_to_glyph(S_room) : GLYPH_UNEXPLORED; + } + qt_settings->glyphs().drawBorderedCell(painter, glyph, x, y, border, rev); } +// called to update the paper doll inventory subset void NetHackQtInvUsageWindow::paintEvent(QPaintEvent*) { - // 012 + // Paper doll is a 6 row by 3 column grid of worn and wielded + // equipment showing the map tiles that the inventory objects + // would be displayed as if they were on the floor. // - //0 WhB - //1 s"w - //2 gCg - //3 =A= - //4 T - //5 S + // 0 1 2 two- dual + // [ old ] normal hander wielding legend + // 0 [x H b] b H q b H q b H q b eyewear H helmet q quiver + // 1 [S " w] S " w W " W X " w S shield " amulet w weapon + // 2 [G C G] G C x G C x G C . G gloves C cloak x alt-weap + // 3 [= A =] = A = = A = = A = = left rg A suit = right ring + // 4 [. U .] l U L l U L l U L l leash U shirt L light + // 5 [. F .] . F . . F . . F . . blank F boots . blank + // W wielded two-handed weapon + // X wielded secondary weapon + // + // 3.7: use a different layout (also different legend for it, above): + // show gloves in only one slot; + // move alternate weapon to former right hand glove slot; + // move blindfold to former alternate weapon slot; + // add quiver to former blindfold slot; + // show secondary weapon in shield slot when two-weapon is active; + // show two-handed primary weapon in both shield and uwep slots; + // add lit lamp/lantern/candle/candelabrum on lower right side; + // add leash-in-use on lower left side + // + // Actually indexed by grid[column][row]. + +#ifdef ENHANCED_PAPERDOLL + if (iflags.wc_ascii_map) + qt_settings->doll_is_shown = false; + if (!qt_settings->doll_is_shown) + return; + // set glyphs() for the paper doll; might be different size than map's + qt_settings->glyphs().setSize(qt_settings->dollWidth, + qt_settings->dollHeight); + + /* for drawWorn()'s use of obj->invlet */ + if (!flags.invlet_constant) + reassign(); +#endif QPainter painter; painter.begin(this); - // Blanks - drawWorn(painter,0,0,4,false); - drawWorn(painter,0,0,5,false); - drawWorn(painter,0,2,4,false); - drawWorn(painter,0,2,5,false); + // String argument is for a tool tip when the object in question is Null. + // + // left column + drawWorn(painter, ublindf, 0, 0, "no eyewear"); // bf|towel|lenses + /* shield slot varies depending upon weapon usage; + no alt tool tip is needed for first two cases because object will + never be Null when the corresponding tests pass */ + if (u.twoweap) + drawWorn(painter, uswapwep, 0, 1, NULL); // secondary weapon, in use + else if (uwep && bimanual(uwep)) // show two-handed uwep twice + drawWorn(painter, uwep, 0, 1, NULL, dollReverse); // uwep on left + else + drawWorn(painter, uarms, 0, 1, "no shield"); + drawWorn(painter, uarmg, 0, 2, "no gloves"); + drawWorn(painter, uleft, 0, 3, "no left ring"); + /* light source and leash aren't unique and don't have pointers defined */ + drawWorn(painter, find_tool(LEASH), 0, 4, "no leashes in use"); + drawWorn(painter, NULL, 0, 5, NULL, dollUnused); // always blank - drawWorn(painter,uarm,1,3); // Armour - drawWorn(painter,uarmc,1,2); // Cloak - drawWorn(painter,uarmh,1,0); // Helmet - drawWorn(painter,uarms,0,1); // Shield - drawWorn(painter,uarmg,0,2); // Gloves - repeated - drawWorn(painter,uarmg,2,2); // Gloves - repeated - drawWorn(painter,uarmf,1,5); // Shoes (feet) - drawWorn(painter,uarmu,1,4); // Undershirt - drawWorn(painter,uleft,0,3); // RingL - drawWorn(painter,uright,2,3); // RingR + // middle column; no unused slots + drawWorn(painter, uarmh, 1, 0, "no helmet"); + drawWorn(painter, uamul, 1, 1, "no amulet"); + drawWorn(painter, uarmc, 1, 2, "no cloak"); + drawWorn(painter, uarm, 1, 3, "no suit"); + drawWorn(painter, uarmu, 1, 4, "no shirt"); + drawWorn(painter, uarmf, 1, 5, "no boots"); - drawWorn(painter,uwep,2,1); // Weapon - drawWorn(painter,uswapwep,0,0); // Secondary weapon - drawWorn(painter,uamul,1,1); // Amulet - drawWorn(painter,ublindf,2,0); // Blindfold + // right column + drawWorn(painter, uquiver, 2, 0, "nothing readied for firing"); // quiver + drawWorn(painter, uwep, 2, 1, "no weapon"); + /* uswapwep slot varies depending upon dual-wielding state; + shown in shield slot when actively wielded, so uswapwep slot is empty + then and an alternate tool tip is used to explain that emptiness */ + if (!u.twoweap) + drawWorn(painter, uswapwep, 2, 2, "no alternate weapon"); + else + drawWorn(painter, NULL, 2, 2, "secondary weapon is wielded"); + drawWorn(painter, uright, 2, 3, "no right ring"); + /* OIL_LAMP matches lit candles, lamps, lantern, and candelabrum + (and might also duplicate Sunsword when it is wielded--hence lit-- + depending upon whether another light source precedes it in invent) */ + drawWorn(painter, find_tool(OIL_LAMP), 2, 4, "no active light sources"); + drawWorn(painter, NULL, 2, 5, NULL, dollUnused); // always blank painter.end(); + +#ifdef ENHANCED_PAPERDOLL + // reset glyphs() to the ones being used for the map + qt_settings->glyphs().setSize(qt_settings->tileWidth, + qt_settings->tileHeight); +#endif } QSize NetHackQtInvUsageWindow::sizeHint(void) const { if (qt_settings) { - return QSize(qt_settings->glyphs().width()*3, - qt_settings->glyphs().height()*6); + int w = 0, h = 1; // one pixel margin at top + // 1+X+1: one pixel border surrounding each tile in the paper doll, + // so +1 left and +1 right, also +1 above and +1 below +#ifdef ENHANCED_PAPERDOLL + if (iflags.wc_ascii_map) + qt_settings->doll_is_shown = false; + if (qt_settings->doll_is_shown) { + w += (1 + qt_settings->dollWidth + 1) * 3; + h += (1 + qt_settings->dollHeight + 1) * 6; + } +#else + if (iflags.wc_tiled_map) { + w += (1 + qt_settings->glyphs().width() + 1) * 3; + h += (1 + qt_settings->glyphs().height() + 1) * 6; + } +#endif + return QSize(w, h); } else { return QWidget::sizeHint(); } } +// ENHANCED_PAPERDOLL - called when a tool tip is triggered by hovering mouse +bool NetHackQtInvUsageWindow::tooltip_event(QHelpEvent *tipevent) +{ +#ifdef ENHANCED_PAPERDOLL + if (iflags.wc_ascii_map) + qt_settings->doll_is_shown = false; + if (!qt_settings->doll_is_shown) { + tipevent->ignore(); + return false; + } + int wd = qt_settings->dollWidth, + ht = qt_settings->dollHeight; + + // inverse of drawBorderedCell(); + int yoffset = 1, // tiny extra margin at top + ex = tipevent->pos().x(), + ey = tipevent->pos().y() - yoffset, + // KISS: treat 1-pixel margin around cells as part of enclosed cell + cellx = ex / (wd + 2), + celly = ey / (ht + 2); + + const char *tip = (cellx >= 0 && cellx <= 2 && celly >= 0 && celly <= 5) + ? tips[cellx][celly] : NULL; + if (tip && *tip) { + QToolTip::showText(tipevent->globalPos(), QString(tip)); + } else { + QToolTip::hideText(); + tipevent->ignore(); + } +#else + nhUse(tipevent); +#endif /* ENHANCED_PAPERDOLL */ + return true; +} + +// ENHANCED_PAPERDOLL - event handler is necessary to support tool tips +bool NetHackQtInvUsageWindow::event(QEvent *event) +{ +#ifdef ENHANCED_PAPERDOLL + if (event->type() == QEvent::ToolTip) { + QHelpEvent *tipevent = static_cast (event); + return tooltip_event(tipevent); + } +#endif + // with this routine intercepting events, we need to pass along + // paint and mouse-press events to have them handled + return QWidget::event(event); + +} + +// ENHANCED_PAPERDOLL - clicking on the PaperDoll runs #seeall ('*') +void NetHackQtInvUsageWindow::mousePressEvent(QMouseEvent *event UNUSED) +{ +#ifdef ENHANCED_PAPERDOLL + QWidget *main = NetHackQtBind::mainWidget(); + (static_cast (main))->FuncAsCommand(doprinuse); +#endif +} + } // namespace nethack_qt_ diff --git a/win/Qt/qt_inv.h b/win/Qt/qt_inv.h index 4c74b8a6a..2c1c694e0 100644 --- a/win/Qt/qt_inv.h +++ b/win/Qt/qt_inv.h @@ -10,14 +10,26 @@ namespace nethack_qt_ { +// for calls to drawWorn +enum drawWornFlag { dollNoFlag = 0, dollUnused = 1, dollReverse = 2 }; + class NetHackQtInvUsageWindow : public QWidget { public: NetHackQtInvUsageWindow(QWidget* parent); + virtual ~NetHackQtInvUsageWindow(); virtual void paintEvent(QPaintEvent*); virtual QSize sizeHint(void) const; +protected: + virtual bool event(QEvent *event); + virtual void mousePressEvent(QMouseEvent *event); + private: - void drawWorn(QPainter& painter, obj*, int x, int y, bool canbe=true); + void drawWorn(QPainter &painter, obj *nhobj, int x, int y, + const char *alttip, int flags = dollNoFlag); + bool tooltip_event(QHelpEvent *tipevent); + + char *tips[3][6]; // PAPERDOLL is a grid of 3x6 cells for tiles }; } // namespace nethack_qt_ diff --git a/win/Qt/qt_key.cpp b/win/Qt/qt_key.cpp index 2a43f7c85..060fc1eed 100644 --- a/win/Qt/qt_key.cpp +++ b/win/Qt/qt_key.cpp @@ -4,18 +4,13 @@ // qt_key.cpp -- a key buffer +extern "C" { #include "hack.h" -#undef Invisible -#undef Warning -#undef index -#undef msleep -#undef rindex -#undef wizard -#undef yn -#undef min -#undef max +} +#include "qt_pre.h" #include +#include "qt_post.h" #include "qt_key.h" namespace nethack_qt_ { @@ -28,17 +23,19 @@ NetHackQtKeyBuffer::NetHackQtKeyBuffer() : bool NetHackQtKeyBuffer::Empty() const { return in==out; } bool NetHackQtKeyBuffer::Full() const { return (in+1)%maxkey==out; } -void NetHackQtKeyBuffer::Put(int k, int a, int state) +void NetHackQtKeyBuffer::Put(int k, int a, uint kbstate) { + //raw_printf("k:%3d a:'%s' s:0x%08x", k, visctrl((char) a), kbstate); if ( Full() ) return; // Safety - key[in]=k; - ascii[in]=a; - in=(in+1)%maxkey; + key[in] = k; + ascii[in] = a; + state[in] = (Qt::KeyboardModifiers) kbstate; + in = (in + 1) % maxkey; } void NetHackQtKeyBuffer::Put(char a) { - Put(0,a,0); + Put(0, a, 0U); } void NetHackQtKeyBuffer::Put(const char* str) @@ -88,4 +85,9 @@ Qt::KeyboardModifiers NetHackQtKeyBuffer::TopState() const return state[out]; } +void NetHackQtKeyBuffer::Drain() +{ + in = out = 0; +} + } // namespace nethack_qt_ diff --git a/win/Qt/qt_key.h b/win/Qt/qt_key.h index c2ef3a89b..a96c0a07f 100644 --- a/win/Qt/qt_key.h +++ b/win/Qt/qt_key.h @@ -16,7 +16,7 @@ public: bool Empty() const; bool Full() const; - void Put(int k, int ascii, int state); + void Put(int k, int ascii, uint state); void Put(char a); void Put(const char* str); int GetKey(); @@ -27,6 +27,8 @@ public: int TopAscii() const; Qt::KeyboardModifiers TopState() const; + void Drain(); + private: enum { maxkey=64 }; int key[maxkey]; diff --git a/win/Qt/qt_line.cpp b/win/Qt/qt_line.cpp index 6374bea3f..482122589 100644 --- a/win/Qt/qt_line.cpp +++ b/win/Qt/qt_line.cpp @@ -4,21 +4,16 @@ // qt_line.cpp -- a one line input window +extern "C" { #include "hack.h" -#undef Invisible -#undef Warning -#undef index -#undef msleep -#undef rindex -#undef wizard -#undef yn -#undef min -#undef max +} +#include "qt_pre.h" #include #if QT_VERSION >= 0x050000 #include #endif +#include "qt_post.h" #include "qt_line.h" namespace nethack_qt_ { @@ -28,7 +23,7 @@ NetHackQtLineEdit::NetHackQtLineEdit() : { } -NetHackQtLineEdit::NetHackQtLineEdit(QWidget* parent, const char* name) : +NetHackQtLineEdit::NetHackQtLineEdit(QWidget* parent, const char* name UNUSED) : QLineEdit(parent) { } diff --git a/win/Qt/qt_main.cpp b/win/Qt/qt_main.cpp index b27b1067c..cb2eade3d 100644 --- a/win/Qt/qt_main.cpp +++ b/win/Qt/qt_main.cpp @@ -7,20 +7,13 @@ extern "C" { #include "hack.h" } -#undef Invisible -#undef Warning -#undef index -#undef msleep -#undef rindex -#undef wizard -#undef yn -#undef min -#undef max +#include "qt_pre.h" #include #if QT_VERSION >= 0x050000 #include #endif +#include "qt_post.h" #include "qt_main.h" #include "qt_main.moc" #include "qt_bind.h" @@ -301,7 +294,7 @@ static const char * fire_xpm[] = { " . o ", " o "}; /* XPM */ -static const char * get_xpm[] = { +static const char * pickup_xpm[] = { "12 13 3 1", " c None", ". c #000000000000", @@ -359,6 +352,25 @@ static const char * eat_xpm[] = { " oo oo ", " oo oo "}; /* XPM */ +static const char * search_xpm[] = { +"12 13 3 1", +" c None", +". c #FFFFFFFF0000", +"X c #7F0000000000", +" ", +" XXXXX ", +" X ... X ", +" X.....X ", +" X.....X ", +" X ... X ", +" XXXXX ", +" X ", +" X ", +" X ", +" X ", +" X ", +" "}; +/* XPM */ static const char * rest_xpm[] = { "12 13 2 1", " c None", @@ -377,7 +389,7 @@ static const char * rest_xpm[] = { " .... ", " "}; /* XPM */ -static const char * cast_a_xpm[] = { +static const char * cast_a_xpm[] UNUSED = { "12 13 3 1", " c None", ". c #FFFF6DB60000", @@ -396,7 +408,7 @@ static const char * cast_a_xpm[] = { " . X X ", " . X X "}; /* XPM */ -static const char * cast_b_xpm[] = { +static const char * cast_b_xpm[] UNUSED = { "12 13 3 1", " c None", ". c #FFFF6DB60000", @@ -415,7 +427,7 @@ static const char * cast_b_xpm[] = { " . X X ", " . XXX "}; /* XPM */ -static const char * cast_c_xpm[] = { +static const char * cast_c_xpm[] UNUSED = { "12 13 3 1", " c None", ". c #FFFF6DB60000", @@ -437,32 +449,60 @@ static const char * cast_c_xpm[] = { static QString aboutMsg() { + char *p, vbuf[BUFSZ]; + /* nethack's getversionstring() includes a final period + but we're using it mid-sentence so strip period off */ + if ((p = strrchr(getversionstring(vbuf), '.')) != 0 && *(p + 1) == '\0') + *p = '\0'; + /* it's also long; break it into two pieces */ + (void) strsubst(vbuf, " - ", "\n- "); QString msg; msg.sprintf( - "Qt NetHack is a version of NetHack built\n" + // format + "NetHack-Qt is a version of NetHack built using" // no newline #ifdef KDE - "using KDE and the Qt GUI toolkit.\n" + " KDE and" // ditto +#endif + " the Qt %d GUI toolkit.\n" // short Qt version + "\n" + "This is %s%s.\n" // long nethack version and full Qt version + "\n" + "NetHack's Qt interface originally developed by Warwick Allison.\n" + "\n" +#if 0 + "Homepage:\n http://trolls.troll.no/warwick/nethack/\n" //obsolete +#endif +#ifdef KDE + "KDE:\n https://kde.org/\n" +#endif +#if 1 + "Qt:\n https://qt.io/\n" #else - "using the Qt GUI toolkit.\n" + "Qt:\n http://www.troll.no/\n" // obsolete #endif - "This is version %d.%d.%d\n\n" - "Homepage:\n http://trolls.troll.no/warwick/nethack/\n\n" -#ifdef KDE - "KDE:\n http://www.kde.org\n" + "NetHack:\n %s\n", // DEVTEAM_URL + // arguments +#ifdef QT_VERSION_MAJOR + QT_VERSION_MAJOR, +#else + 5, // Qt version macro should exist; if not, assume Qt5 #endif - "Qt:\n http://www.troll.no", - VERSION_MAJOR, - VERSION_MINOR, - PATCHLEVEL); + vbuf, // nethack version +#ifdef QT_VERSION_STR + " with Qt " QT_VERSION_STR, +#else + "", +#endif + DEVTEAM_URL); return msg; } class SmallToolButton : public QToolButton { public: - SmallToolButton(const QPixmap & pm, const QString &textLabel, - const QString& grouptext, - QObject * receiver, const char* slot, - QWidget * parent) : + SmallToolButton(const QPixmap &pm, const QString &textLabel, + const QString &grouptext, + QObject *receiver, const char *slot, + QWidget *parent) : QToolButton(parent) { setIcon(QIcon(pm)); @@ -489,16 +529,25 @@ NetHackQtMainWindow::NetHackQtMainWindow(NetHackQtKeyBuffer& ks) : addToolBar(toolbar); menubar = menuBar(); - QCoreApplication::setOrganizationName("The NetHack DevTeam"); - QCoreApplication::setOrganizationDomain("nethack.org"); - QCoreApplication::setApplicationName("NetHack"); - - setWindowTitle("Qt NetHack"); - if ( qt_compact_mode ) - setWindowIcon(QIcon(QPixmap(nh_icon_small))); - else - setWindowIcon(QIcon(QPixmap(nh_icon))); + setWindowTitle("NetHack-Qt"); + setWindowIcon(QIcon(QPixmap(qt_compact_mode ? nh_icon_small : nh_icon))); +#ifdef MACOSX + /* + * OSX Note: + * The toolbar on OSX starts with a system menu labeled with the + * Apple logo and an application menu labeled with the application's + * name (taken from Info.plist if present, otherwise the base name + * of the running program). After that, application-specific menus + * (in our case "game",...,"help") follow. Several menu entry + * names ("About", "Quit"/"Exit", "Preferences"/"Options"/ + * "Settings"/"Setup"/"Config") get hijacked and placed in the + * application menu (and renamed in the process) even if the code + * here tries to put them in another menu. + * See QtWidgets/doc/qmenubar.html for slightly more information. + * setMenuRole() can be used to override this behavior. + */ +#endif QMenu* game=new QMenu; QMenu* apparel=new QMenu; QMenu* act1=new QMenu; @@ -507,7 +556,6 @@ NetHackQtMainWindow::NetHackQtMainWindow(NetHackQtKeyBuffer& ks) : QMenu* info=new QMenu; QMenu *help; - #ifdef KDE help = kapp->getHelpMenu( true, "" ); help->addSeparator(); @@ -527,11 +575,26 @@ NetHackQtMainWindow::NetHackQtMainWindow(NetHackQtKeyBuffer& ks) : { game, "Compilation", 3, doextversion}, { game, "History", 3, dohistory}, { game, "Redraw", 0, doredraw}, // useless - { game, "Options", 3, doset}, + { game, +#ifdef MACOSX + /* Qt on OSX would rename "Options" to "Preferences..." and + move it from intended destination to the application menu; + the ampersand produces &O which makes Alt+O into a keyboard + shortcut--except those are disabled by default by Qt on OSX */ + "Run-time &" // rely on adjacent string concatenation +#endif + "Options", 3, doset}, { game, "Explore mode", 3, enter_explore_mode}, { game, 0, 3}, - { game, "Save", 3, dosave}, - { game, "Quit", 3, done2}, + { game, "Save-and-exit", 3, dosave}, + { game, +#ifdef MACOSX + /* need something to prevent matching leading "quit" so that it + isn't hijacked for the application menu; the ampersand is to + make &Q be a keyboard shortcut (but see Options above) */ + "\177&" +#endif + "Quit-without-saving", 3, done2}, { apparel, "Apparel off", 2, doddoremarm}, { apparel, "Remove many", 1, doddoremarm}, @@ -541,11 +604,11 @@ NetHackQtMainWindow::NetHackQtMainWindow(NetHackQtKeyBuffer& ks) : { apparel, "Two weapon combat", 3, dotwoweapon}, { apparel, "Load quiver", 3, dowieldquiver}, { apparel, 0, 3}, - { apparel, "Wear armour", 3, dowear}, - { apparel, "Take off armour", 3, dotakeoff}, + { apparel, "Wear armor", 3, dowear}, + { apparel, "Take off armor", 3, dotakeoff}, { apparel, 0, 3}, - { apparel, "Put on non-armour", 3, doputon}, - { apparel, "Remove non-armour", 3, doremring}, + { apparel, "Put on accessories", 3, doputon}, + { apparel, "Remove accessories", 3, doremring}, /* { act1, "Again\tCtrl+A", "\001", 2}, { act1, 0, 0, 3}, */ @@ -560,12 +623,13 @@ NetHackQtMainWindow::NetHackQtMainWindow(NetHackQtKeyBuffer& ks) : /* { act1, "Fight\tShift+F", "F", 3}, */ { act1, "Fire from quiver", 2, dofire}, { act1, "Force", 3, doforce}, - { act1, "Get", 2, dopickup}, { act1, "Jump", 3, dojump}, { act2, "Kick", 2, dokick}, { act2, "Loot", 3, doloot}, { act2, "Open door", 3, doopen}, { act2, "Pay", 3, dopay}, + // calling this "Get" was confusing to experienced players + { act1, "Pick up (was Get)", 3, dopickup}, { act2, "Rest", 2, donull}, { act2, "Ride", 3, doride}, { act2, "Search", 3, dosearch}, @@ -598,40 +662,87 @@ NetHackQtMainWindow::NetHackQtMainWindow(NetHackQtKeyBuffer& ks) : { help, 0, 1}, { info, "Inventory", 3, ddoinv}, + { info, "Attributes (extended status)", 3, doattributes }, + { info, "Overview", 3, dooverview }, { info, "Conduct", 3, doconduct}, { info, "Discoveries", 3, dodiscovered}, { info, "List/reorder spells", 3, dovspell}, - { info, "Adjust letters", 2, doorganize}, + { info, "Adjust inventory letters", 3, doorganize }, { info, 0, 3}, { info, "Name object or creature", 3, docallcmd}, + { info, "Annotate level", 3, donamelevel }, { info, 0, 3}, { info, "Skills", 3, enhance_weapon_skill}, { 0, 0, 0 } }; - int i; + QAction *actn; +#ifndef MACOSX + (void) game->addAction("Qt settings...", this, SLOT(doQtSettings(bool))); +#else + /* on OSX, put this in the application menu instead of the game menu; + Qt would change the action name behind our backs; do it explicitly */ + actn = game->addAction("Preferences...", this, SLOT(doQtSettings(bool))); + actn->setMenuRole(QWidgetAction::PreferencesRole); + /* we also want a "Quit NetHack" entry in the application menu; + when "_Quit-without-saving" was called "Quit" it got intercepted + for that, but now this needs to be added separately; we'll use a + handy menu and let the interception put it in the intended place; + unlike About, it is not a duplicate; _Quit-without-saving runs + nethack's #quit command with "really quit?" prompt, this quit--with + Command+q as shortcut--pops up a dialog to choose between quit or + cancel-and-resume-playing */ + actn = game->addAction("Quit NetHack-Qt", this, SLOT(doQuit(bool))); + actn->setMenuRole(QWidgetAction::QuitRole); +#endif - game->addAction("Qt settings...",this,SLOT(doQtSettings(bool))); - help->addAction("About Qt NetHack...",this,SLOT(doAbout(bool))); - //help->addAction("NetHack Guidebook...",this,SLOT(doGuidebook(bool))); + actn = help->addAction("About NetHack-Qt", this, SLOT(doAbout(bool))); +#ifdef MACOSX + actn->setMenuRole(QWidgetAction::AboutRole); + /* for OSX, the preceding "About" went into the application menu; + now add another duplicate one to the Help dropdown menu */ + actn = help->addAction("About NetHack-Qt", this, SLOT(doAbout(bool))); + actn->setMenuRole(QWidgetAction::NoRole); +#else + nhUse(actn); +#endif help->addSeparator(); - for (i=0; item[i].menu; i++) { + //help->addAction("NetHack Guidebook", this, SLOT(doGuidebook(bool))); + //help->addSeparator(); + + for (int i = 0; item[i].menu; ++i) { if ( item[i].flags & (qt_compact_mode ? 1 : 2) ) { if (item[i].name) { char actchar[32]; char menuitem[BUFSZ]; - actchar[0] = '\0'; + actchar[0] = actchar[1] = '\0'; if (item[i].funct) { actchar[0] = cmd_from_func(item[i].funct); - actchar[1] = '\0'; + if (actchar[0] + /* M-c won't work; translation between character + sets by the QString class can classify such + characters as erroneous and change them to '?' */ + && ((actchar[0] & 0x7f) != actchar[0] + /* the vi movement keys won't work reliably + because toggling number_pad affects them but + doesn't redo these menus */ + || strchr("hjklyubnHJKLYUBN", actchar[0]) + || strchr("hjklyubn", (actchar[0] | 0x60)))) + actchar[0] = '\0'; } if (actchar[0] && !qt_compact_mode) - Sprintf(menuitem, "%s\t%s", item[i].name, + Sprintf(menuitem, "%.50s\t%.9s", item[i].name, visctrl(actchar[0])); else Sprintf(menuitem, "%s", item[i].name); + + if (item[i].funct && !actchar[0]) { + actchar[0] = '#'; + (void) cmdname_from_func(item[i].funct, + &actchar[1], FALSE); + } if (actchar[0]) { QString name = menuitem; QAction *action = item[i].menu->addAction(name); @@ -673,55 +784,64 @@ NetHackQtMainWindow::NetHackQtMainWindow(NetHackQtKeyBuffer& ks) : info->setTitle("Info"); menubar->addMenu(info); menubar->addSeparator(); +#ifndef MACOSX help->setTitle("Help"); +#else + // On OSX, an entry in the menubar called "Help" will get an + // extra action, "Search [______]", inserted as the first entry. + // We have no control over what it does and don't want it. + // + // Using actions() to fetch a list of all entries doesn't find it, + // so we don't have its widget pointer to pass to removeAction(). + // + // Altering the name with an invisible character to inhibit + // string matching is ludicrous but keeps the unwanted action + // from getting inserted into the "Help" menu behind our back. + // Underscore works too and is more robust but unless we prepend + // it to every entry, "_Help" would stand out as strange. + help->setTitle("\177Help"); + // (Renaming back to "Help" after the fact does reset the menu's + // name but it also results in the Search action being added. + // Perhaps a custom context menu that changes its name to "Help" + // as it is being shown--and possibly changes back afterward-- + // would work but the name mangling hack is much simpler.) +#endif menubar->addMenu(help); } + // order changed: was Again, Get, Kick, Throw, Fire, Drop, Eat, Rest + // now Again, PickUp, Drop, Kick, Throw, Fire, Eat, Rest QSignalMapper* sm = new QSignalMapper(this); - connect(sm, SIGNAL(mapped(const QString&)), this, SLOT(doKeys(const QString&))); - QToolButton* tb; - char actchar[32]; - tb = new SmallToolButton( QPixmap(again_xpm),"Again","Action", sm, SLOT(map()), toolbar ); - Sprintf(actchar, "%c", g.Cmd.spkeys[NHKF_DOAGAIN]); - sm->setMapping(tb, actchar ); - toolbar->addWidget(tb); - tb = new SmallToolButton( QPixmap(get_xpm),"Get","Action", sm, SLOT(map()), toolbar ); - Sprintf(actchar, "%c", cmd_from_func(dopickup)); - sm->setMapping(tb, actchar ); - toolbar->addWidget(tb); - tb = new SmallToolButton( QPixmap(kick_xpm),"Kick","Action", sm, SLOT(map()), toolbar ); - Sprintf(actchar, "%c", cmd_from_func(dokick)); - sm->setMapping(tb, actchar ); - toolbar->addWidget(tb); - tb = new SmallToolButton( QPixmap(throw_xpm),"Throw","Action", sm, SLOT(map()), toolbar ); - Sprintf(actchar, "%c", cmd_from_func(dothrow)); - sm->setMapping(tb, actchar ); - toolbar->addWidget(tb); - tb = new SmallToolButton( QPixmap(fire_xpm),"Fire","Action", sm, SLOT(map()), toolbar ); - Sprintf(actchar, "%c", cmd_from_func(dofire)); - sm->setMapping(tb, actchar ); - toolbar->addWidget(tb); - tb = new SmallToolButton( QPixmap(drop_xpm),"Drop","Action", sm, SLOT(map()), toolbar ); - Sprintf(actchar, "%c", cmd_from_func(doddrop)); - sm->setMapping(tb, actchar ); - toolbar->addWidget(tb); - tb = new SmallToolButton( QPixmap(eat_xpm),"Eat","Action", sm, SLOT(map()), toolbar ); - Sprintf(actchar, "%c", cmd_from_func(doeat)); - sm->setMapping(tb, actchar ); - toolbar->addWidget(tb); - tb = new SmallToolButton( QPixmap(rest_xpm),"Rest","Action", sm, SLOT(map()), toolbar ); - Sprintf(actchar, "%c", cmd_from_func(donull)); - sm->setMapping(tb, actchar ); - toolbar->addWidget(tb); + connect(sm, SIGNAL(mapped(const QString&)), + this, SLOT(doKeys(const QString&))); + // 'donull' is a placeholder here; AddToolButton() will fix it up; + // button will be omitted if DOAGAIN is bound to '\0' + AddToolButton(toolbar, sm, "Again", donull, QPixmap(again_xpm)); + // this used to be called "Get" which is confusing to experienced players + AddToolButton(toolbar, sm, "Pick up", dopickup, QPixmap(pickup_xpm)); + AddToolButton(toolbar, sm, "Drop", doddrop, QPixmap(drop_xpm)); + AddToolButton(toolbar, sm, "Kick", dokick, QPixmap(kick_xpm)); + AddToolButton(toolbar, sm, "Throw", dothrow, QPixmap(throw_xpm)); + AddToolButton(toolbar, sm, "Fire", dofire, QPixmap(fire_xpm)); + AddToolButton(toolbar, sm, "Eat", doeat, QPixmap(eat_xpm)); + AddToolButton(toolbar, sm, "Search", dosearch, QPixmap(search_xpm)); + AddToolButton(toolbar, sm, "Rest", donull, QPixmap(rest_xpm)); - connect(game,SIGNAL(triggered(QAction *)),this,SLOT(doMenuItem(QAction *))); - connect(apparel,SIGNAL(triggered(QAction *)),this,SLOT(doMenuItem(QAction *))); - connect(act1,SIGNAL(triggered(QAction *)),this,SLOT(doMenuItem(QAction *))); + connect(game, SIGNAL(triggered(QAction *)), + this, SLOT(doMenuItem(QAction *))); + connect(apparel, SIGNAL(triggered(QAction *)), + this, SLOT(doMenuItem(QAction *))); + connect(act1, SIGNAL(triggered(QAction *)), + this, SLOT(doMenuItem(QAction *))); if (act2 != act1) - connect(act2,SIGNAL(triggered(QAction *)),this,SLOT(doMenuItem(QAction *))); - connect(magic,SIGNAL(triggered(QAction *)),this,SLOT(doMenuItem(QAction *))); - connect(info,SIGNAL(triggered(QAction *)),this,SLOT(doMenuItem(QAction *))); - connect(help,SIGNAL(triggered(QAction *)),this,SLOT(doMenuItem(QAction *))); + connect(act2, SIGNAL(triggered(QAction *)), + this, SLOT(doMenuItem(QAction *))); + connect(magic, SIGNAL(triggered(QAction *)), + this, SLOT(doMenuItem(QAction *))); + connect(info, SIGNAL(triggered(QAction *)), + this, SLOT(doMenuItem(QAction *))); + connect(help, SIGNAL(triggered(QAction *)), + this, SLOT(doMenuItem(QAction *))); #ifdef KDE setMenu (menubar); @@ -769,6 +889,31 @@ NetHackQtMainWindow::NetHackQtMainWindow(NetHackQtKeyBuffer& ks) : } } +// add a toolbar button to invoke command 'name' via function '(*func)()' +void NetHackQtMainWindow::AddToolButton(QToolBar *toolbar, QSignalMapper *sm, + const char *name, int NDECL((*func)), + QPixmap xpm) +{ + char actchar[2]; + uchar key; + + // the ^A command is just a keystroke, not a full blown command function + if (!strcmp(name, "Again")) { + key = ::g.Cmd.spkeys[NHKF_DOAGAIN]; + } else + key = (uchar) cmd_from_func(func); + + // if key is valid, add a button for it; otherwise omit the command + // (won't work as intended if a different command is bound to same key) + if (key) { + QToolButton *tb = new SmallToolButton(xpm, QString(name), "Action", + sm, SLOT(map()), toolbar); + actchar[0] = '\0'; + sm->setMapping(tb, strkitten(actchar, (char) key)); + toolbar->addWidget(tb); + } +} + void NetHackQtMainWindow::zoomMap() { qt_settings->toggleGlyphSize(); @@ -799,7 +944,8 @@ public: const QMimeSource* data(const QString& abs_name) const { const QMimeSource* r = 0; - if ( (NetHackMimeSourceFactory*)this == Q3MimeSourceFactory::defaultFactory() ) + if ( (NetHackMimeSourceFactory *) this + == Q3MimeSourceFactory::defaultFactory() ) r = Q3MimeSourceFactory::data(abs_name); else r = Q3MimeSourceFactory::defaultFactory()->data(abs_name); @@ -826,6 +972,12 @@ public: void NetHackQtMainWindow::doMenuItem(QAction *action) { + /* this converts meta characters to '?'; menu processing has been + changed to send multi-character "#abc" instead (already needed + for commands that didn't have either a regular keystroke or a + meta shortcut); it must send just enough to disambiguate from + other extended command names, otherwise the remainder would be + left in the queue for subsequent handling as additional commands */ doKeys(action->data().toString()); } @@ -837,7 +989,47 @@ void NetHackQtMainWindow::doQtSettings(bool) void NetHackQtMainWindow::doAbout(bool) { - QMessageBox::about(this, "About Qt NetHack", aboutMsg()); + QMessageBox::about(this, "About NetHack-Qt", aboutMsg()); +} + +// on OSX, "quit nethack" has been selected in the application menu or +// "Command+Q" has been typed -- user is asking to quit the application; +// unlike with the window's Close button, user has a chance to back out +void NetHackQtMainWindow::doQuit(bool) +{ + // there is a separate Quit-without-saving menu entry in the game menu + // that leads to nethack's "Really quit?" prompt; OSX players can use + // either one, other implementations only have that other one (plus + // nethack's #quit command itself) but this routine is unconditional + // in case someone wants to change that +#ifdef MACOSX + QString info; + info.sprintf("This will end your NetHack session.%s", + !g.program_state.something_worth_saving ? "" + : "\n(Cancel quitting and use the Save command" + "\nto save your current game.)"); + /* this is similar to closeEvent but the details are different; + first choice (Cancel) is the default action for most arbitrary keys; + the second choice (Quit) is the action for or ; + leaves the popup waiting for some other response; + the & settings for Alt+ shortcuts don't work on OSX */ + int act = QMessageBox::information(this, "NetHack", info, + "&Cancel and return to game", + "&Quit without saving", + 0, 1); + switch (act) { + case 0: + // cancel + break; // return to game + case 1: + // quit -- bypass the prompting preformed by done2() + g.program_state.stopprint++; + ::done(QUIT); + /*NOTREACHED*/ + break; + } +#endif + return; } #if 0 // RLC this isn't used @@ -855,10 +1047,26 @@ void NetHackQtMainWindow::doGuidebook(bool) } #endif +void NetHackQtMainWindow::doKeys(const char *cmds) +{ + keysink.Put(cmds); + qApp->exit(); +} + void NetHackQtMainWindow::doKeys(const QString& k) { - keysink.Put(k.toLatin1().constData()); - qApp->exit(); + /* [this should probably be using toLocal8Bit(); + toAscii() is not offered as an alternative...] */ + doKeys(k.toLatin1().constData()); +} + +// queue up the command name for a function, as if user had typed it +void NetHackQtMainWindow::FuncAsCommand(int NDECL((*func))) +{ + char cmdbuf[32]; + Strcpy(cmdbuf, "#"); + (void) cmdname_from_func(func, &cmdbuf[1], FALSE); + doKeys(cmdbuf); } void NetHackQtMainWindow::AddMessageWindow(NetHackQtMessageWindow* window) @@ -908,14 +1116,21 @@ void NetHackQtMainWindow::RemoveWindow(NetHackQtWindow* window) void NetHackQtMainWindow::updateInventory() { - if ( invusage ) + if (invusage) { invusage->repaint(); + } } -void NetHackQtMainWindow::fadeHighlighting() +void NetHackQtMainWindow::fadeHighlighting(bool before_key) { - if (status) { - status->fadeHighlighting(); + if (before_key) { + // status highlighting fades at start of turn + if (status) + status->fadeHighlighting(); + } else { + // message highlighting fades after user has given input + if (message && message->hilit_mesgs()) + message->unhighlight_mesgs(); } } @@ -941,6 +1156,105 @@ void NetHackQtMainWindow::layout() toph,c->width(),maph); } #endif + + if (qt_settings && !qt_compact_mode + && map && message && status && invusage) { + // For the initial PaperDoll sizing, message window + // and/or status window might still be empty; + // widen them before changing PaperDoll to use saved settings. + QList splittersizes = hsplitter->sizes(); +#define MIN_WIN_WIDTH 400 + if (splittersizes[0] < MIN_WIN_WIDTH + || splittersizes[2] < MIN_WIN_WIDTH) { + if (splittersizes[0] < MIN_WIN_WIDTH) + splittersizes[0] = MIN_WIN_WIDTH; +#ifndef ENHANCED_PAPERDOLL + if (splittersizes[1] < 6) // TILEWMIN + splittersizes[1] = 16; // 16x16 +#endif + if (splittersizes[2] < MIN_WIN_WIDTH) + splittersizes[2] = MIN_WIN_WIDTH; + hsplitter->setSizes(splittersizes); + } +#ifdef ENHANCED_PAPERDOLL + // call resizePaperDoll() indirectly... + qt_settings->resizeDoll(); +#endif + // reset widths + int w = width(); /* of main window */ + int d = invusage->width(); + splittersizes[2] = w / 2 - (d * 1 / 4); // status + splittersizes[1] = d; // invusage + splittersizes[0] = w / 2 - (d * 3 / 4); // messages + hsplitter->setSizes(splittersizes); + } +} + +#ifdef DYNAMIC_STATUSLINES +// called when 'statuslines' changes from 2 to 3 or vice versa; simpler to +// destroy and recreate the status window than to adjust existing fields +NetHackQtWindow *NetHackQtMainWindow::redoStatus() +{ + NetHackQtStatusWindow *oldstatus = this->status; + if (!oldstatus) + return NULL; // not ready yet? + this->status = new NetHackQtStatusWindow; + + if (!qt_compact_mode) + hsplitter->replaceWidget(2, this->status->Widget()); + + delete oldstatus; + ShowIfReady(); + + return (NetHackQtWindow *) this->status; +} +#endif + +void NetHackQtMainWindow::resizePaperDoll(bool showdoll) +{ +#ifdef ENHANCED_PAPERDOLL + // this is absurd... + NetHackQtInvUsageWindow *w = static_cast + (NetHackQtBind::mainWidget())->invusage; + QList hsplittersizes = hsplitter->sizes(), + vsplittersizes = vsplitter->sizes(); + w->resize(w->sizeHint()); + + int oldwidth = hsplittersizes[1], + newwidth = w->width(); + if (newwidth != oldwidth) { + if (oldwidth > newwidth) + hsplittersizes[0] += (oldwidth - newwidth); + else + hsplittersizes[2] += (newwidth - oldwidth); + hsplittersizes[1] = newwidth; + hsplitter->setSizes(hsplittersizes); + } + + // Height limit is 48+2 pixels per doll cell plus 1 pixel margin at top; + // values greater than 44+2 need taller window which pushes the map down + // (when font size 'Large' is used for messages and status; threshold + // may vary by 1 or 2 for other sizes). + // FIXME: this doesn't shrink the window back if size is reduced from 45+ + int oldheight = vsplittersizes[0], + newheight = w->height(); + if (newheight > oldheight && oldheight > 0 && vsplittersizes[1] > 0) { + vsplittersizes[0] = newheight; + vsplitter->setSizes(vsplittersizes); + } + + if (showdoll) { + if (w->isHidden()) + w->show(); + else + w->repaint(); + } else { + if (w->isVisible()) + w->hide(); + } +#else + nhUse(showdoll); +#endif /* ENHANCED_PAPERDOLL */ } void NetHackQtMainWindow::resizeEvent(QResizeEvent*) @@ -978,82 +1292,103 @@ void NetHackQtMainWindow::keyPressEvent(QKeyEvent* event) const char* d = g.Cmd.dirchars; switch (event->key()) { - case Qt::Key_Up: + case Qt::Key_Up: if ( dirkey == d[0] ) dirkey = d[1]; else if ( dirkey == d[4] ) dirkey = d[3]; else dirkey = d[2]; - break; case Qt::Key_Down: + break; + case Qt::Key_Down: if ( dirkey == d[0] ) dirkey = d[7]; else if ( dirkey == d[4] ) dirkey = d[5]; else dirkey = d[6]; - break; case Qt::Key_Left: + break; + case Qt::Key_Left: if ( dirkey == d[2] ) dirkey = d[1]; else if ( dirkey == d[6] ) dirkey = d[7]; else dirkey = d[0]; - break; case Qt::Key_Right: + break; + case Qt::Key_Right: if ( dirkey == d[2] ) dirkey = d[3]; else if ( dirkey == d[6] ) dirkey = d[5]; else dirkey = d[4]; - break; case Qt::Key_PageUp: + break; + case Qt::Key_PageUp: dirkey = 0; if (message) message->Scroll(0,-1); - break; case Qt::Key_PageDown: + break; + case Qt::Key_PageDown: dirkey = 0; if (message) message->Scroll(0,+1); - break; case Qt::Key_Space: - if ( flags.rest_on_space ) { - event->ignore(); - return; - } - case Qt::Key_Enter: + break; + case Qt::Key_Space: + //if (flags.rest_on_space) { + event->ignore(); // punt to NetHackQtBind::notify() + return; + //} + case Qt::Key_Enter: if ( map ) map->clickCursor(); - break; default: + break; + default: dirkey = 0; event->ignore(); + break; } } -void NetHackQtMainWindow::closeEvent(QCloseEvent* e) +// game window's Close button has been activated +void NetHackQtMainWindow::closeEvent(QCloseEvent *e UNUSED) { + int ok = 0; if ( g.program_state.something_worth_saving ) { - switch ( QMessageBox::information( this, "NetHack", - "This will end your NetHack session", - "&Save", "&Cancel", 0, 1 ) ) - { - case 0: - // See dosave() function - if (dosave0()) { - u.uhp = -1; - NetHackQtBind::qt_exit_nhwindows(0); - nh_terminate(EXIT_SUCCESS); - } - break; - case 1: - break; // ignore the event + /* this used to offer "Save" and "Cancel" + but cancel (ignoring the close attempt) won't work + if user has clicked on the window's Close button */ + int act = QMessageBox::information(this, "NetHack", + "This will end your NetHack session.", + "&Save and exit", "&Quit without saving", 0, 1); + switch (act) { + case 0: + // See dosave() function + ok = dosave0(); + break; + case 1: + // quit -- bypass the prompting preformed by done2() + ok = 1; + g.program_state.stopprint++; + ::done(QUIT); + /*NOTREACHED*/ + break; } } else { - e->accept(); + /* nothing worth saving; just close/quit */ + ok = 1; } + /* if !ok, we should try to continue, but we don't... */ + u.uhp = -1; + NetHackQtBind::qt_exit_nhwindows(0); + nh_terminate(EXIT_SUCCESS); } void NetHackQtMainWindow::ShowIfReady() { if (message && map && status) { - QWidget* hp = qt_compact_mode ? static_cast(stack) : static_cast(hsplitter); - QWidget* vp = qt_compact_mode ? static_cast(stack) : static_cast(vsplitter); + QWidget* hp = qt_compact_mode ? static_cast(stack) + : static_cast(hsplitter); + QWidget* vp = qt_compact_mode ? static_cast(stack) + : static_cast(vsplitter); message->Widget()->setParent(hp); map->Widget()->setParent(vp); status->Widget()->setParent(hp); diff --git a/win/Qt/qt_main.h b/win/Qt/qt_main.h index 2e4a2a5d0..1b4441ec9 100644 --- a/win/Qt/qt_main.h +++ b/win/Qt/qt_main.h @@ -14,6 +14,11 @@ #include "qt_kde0.h" #endif +// Allow changing 'statuslines:2' to 'statuslines:3' or vice versa +// while the game is running; deletes and re-creates the status window. +// [Used in qt_bind.cpp and qt_main.cpp, but not referenced in qt_stat.cpp.] +#define DYNAMIC_STATUSLINES + namespace nethack_qt_ { class NetHackQtInvUsageWindow; @@ -47,13 +52,23 @@ public: void RemoveWindow(NetHackQtWindow* window); void updateInventory(); - void fadeHighlighting(); + void fadeHighlighting(bool before_key); + + void FuncAsCommand(int NDECL((*func))); + // this is unconditional in case qt_main.h comes before qt_set.h + void resizePaperDoll(bool); // ENHANCED_PAPERDOLL +#ifdef DYNAMIC_STATUSLINES + // called when 'statuslines' option has been changed + NetHackQtWindow *redoStatus(); +#endif public slots: void doMenuItem(QAction *); void doQtSettings(bool); void doAbout(bool); + void doQuit(bool); //RLC void doGuidebook(bool); + void doKeys(const char *); void doKeys(const QString&); protected: @@ -71,6 +86,8 @@ private slots: private: void ShowIfReady(); + void AddToolButton(QToolBar *toolbar, QSignalMapper *sm, + const char *name, int NDECL((*func)), QPixmap xpm); #ifdef KDE KMenuBar* menubar; diff --git a/win/Qt/qt_map.cpp b/win/Qt/qt_map.cpp index 74d30b3c8..01047e83a 100644 --- a/win/Qt/qt_map.cpp +++ b/win/Qt/qt_map.cpp @@ -7,28 +7,68 @@ extern "C" { #include "hack.h" } -#undef Invisible -#undef Warning -#undef index -#undef msleep -#undef rindex -#undef wizard -#undef yn -#undef min -#undef max +#include "qt_pre.h" #include #if QT_VERSION >= 0x050000 #include #endif +#include "qt_post.h" #include "qt_map.h" #include "qt_map.moc" #include "qt_click.h" #include "qt_glyph.h" -#include "qt_xpms.h" #include "qt_set.h" #include "qt_str.h" +// pet- and pile-mark xpm arrays moved out of qt_xpms.h so that we don't +// include it here anymore; including that header in two files resulted in +// two copies of all the static xpm data and all the rest is for qt_stat.cpp +// +/* XPM */ +static const char *pet_mark_xpm[] = { +/* width height ncolors chars_per_pixel */ +"8 7 2 1", +/* colors */ +". c None", +" c #FF0000", +/* pixels */ +"........", +".. . .", +". ", +". ", +".. .", +"... ..", +".... ..." +}; +/* XPM */ +static const char *pet_mark_small_xpm[] = { +/* width height ncolors chars_per_pixel */ +"5 5 2 1", +/* colors */ +". c None", +"X c #FF0000", +/* pixels */ +".X.X.", +"XXXXX", +".XXX.", +"..X.." +}; +/* XPM */ +static const char *pile_mark_xpm[] = { +/* width height ncolors chars_per_pixel */ +"5 5 2 1", +/* colors */ +". c None", +"X c #00FF00", +/* pixels */ +"..X..", +"..X..", +"XXXXX", +"..X..", +"..X.." +}; + // temporary extern int qt_compact_mode; // end temporary @@ -38,26 +78,31 @@ namespace nethack_qt_ { #ifdef TEXTCOLOR static const QPen& nhcolor_to_pen(int c) { - static QPen* pen=0; - if ( !pen ) { - pen = new QPen[17]; - pen[0] = QColor(64,64,64); - pen[1] = QColor(Qt::red); - pen[2] = QColor(0,191,0); - pen[3] = QColor(127,127,0); - pen[4] = QColor(Qt::blue); - pen[5] = QColor(Qt::magenta); - pen[6] = QColor(Qt::cyan); - pen[7] = QColor(Qt::gray); - pen[8] = QColor(Qt::white); // no color - pen[9] = QColor(255,127,0); - pen[10] = QColor(127,255,127); - pen[11] = QColor(Qt::yellow); - pen[12] = QColor(127,127,255); - pen[13] = QColor(255,127,255); - pen[14] = QColor(127,255,255); - pen[15] = QColor(Qt::white); - pen[16] = QColor(Qt::black); + 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); } return pen[c]; @@ -65,37 +110,63 @@ static const QPen& nhcolor_to_pen(int c) #endif NetHackQtMapViewport::NetHackQtMapViewport(NetHackQtClickBuffer& click_sink) : - QWidget(NULL), - rogue_font(NULL), - clicksink(click_sink), - change(10) + QWidget(NULL), + rogue_font(NULL), + clicksink(click_sink), + change(10) { - pet_annotation = QPixmap(qt_compact_mode ? pet_mark_small_xpm : pet_mark_xpm); + pet_annotation = QPixmap(qt_compact_mode ? pet_mark_small_xpm + : pet_mark_xpm); pile_annotation = QPixmap(pile_mark_xpm); - Clear(); + Clear(); // initializes glyph[][], glyphttychar, glyphcolor, glyphflags cursor.setX(0); cursor.setY(0); } NetHackQtMapViewport::~NetHackQtMapViewport(void) { - delete rogue_font; + delete rogue_font; //rogue_font = NULL; +} + +// pick a font to use for text map; rogue level is always displayed as text +void NetHackQtMapViewport::SetupTextmapFont(QPainter &painter) +{ + QString fontfamily = iflags.wc_font_map ? iflags.wc_font_map + : "Monospace"; + int maybebold = QFont::Normal; + if (fontfamily.right(5).toLower() == "-bold") { + fontfamily.truncate(fontfamily.length() - 5); + maybebold = QFont::Bold; + } + // Find font... + int pts = 5; + while (pts < 32) { + QFont f(fontfamily, pts, maybebold); + painter.setFont(QFont(fontfamily, pts)); + QFontMetrics fm = painter.fontMetrics(); + if (fm.width("M") > qt_settings->glyphs().width()) + break; + if (fm.height() > qt_settings->glyphs().height()) + break; + pts++; + } + rogue_font = new QFont(fontfamily, pts - 1); } void NetHackQtMapViewport::paintEvent(QPaintEvent* event) { - QRect area=event->rect(); + NetHackQtGlyphs &glyphs = qt_settings->glyphs(); + int gW = glyphs.width(), + gH = glyphs.height(); + QRect area = event->rect(); QRect garea; - garea.setCoords( - std::max(0,area.left()/qt_settings->glyphs().width()), - std::max(0,area.top()/qt_settings->glyphs().height()), - std::min(COLNO-1,area.right()/qt_settings->glyphs().width()), - std::min(ROWNO-1,area.bottom()/qt_settings->glyphs().height()) - ); + garea.setCoords(std::max(0, area.left() / gW), + std::max(0, area.top() / gH), + std::min(COLNO - 1, area.right() / gW), + std::min(ROWNO - 1, area.bottom() / gH)); QPainter painter; - painter.begin(this); if (Is_rogue_level(&u.uz) || iflags.wc_ascii_map) { @@ -104,87 +175,73 @@ void NetHackQtMapViewport::paintEvent(QPaintEvent* event) painter.setClipRect( event->rect() ); // (normally we don't clip) painter.fillRect( event->rect(), Qt::black ); - if ( !rogue_font ) { - // Find font... - int pts = 5; - QString fontfamily = iflags.wc_font_map - ? iflags.wc_font_map : "Monospace"; - bool bold = false; - if ( fontfamily.right(5).toLower() == "-bold" ) { - fontfamily.truncate(fontfamily.length()-5); - bold = true; - } - while ( pts < 32 ) { - QFont f(fontfamily, pts, bold ? QFont::Bold : QFont::Normal); - painter.setFont(QFont(fontfamily, pts)); - QFontMetrics fm = painter.fontMetrics(); - if ( fm.width("M") > qt_settings->glyphs().width() ) - break; - if ( fm.height() > qt_settings->glyphs().height() ) - break; - pts++; - } - rogue_font = new QFont(fontfamily,pts-1); - } + if (!rogue_font) + SetupTextmapFont(painter); painter.setFont(*rogue_font); - for (int j=garea.top(); j<=garea.bottom(); j++) { - for (int i=garea.left(); i<=garea.right(); i++) { - unsigned short g=Glyph(i,j); - int color; - int ch; + for (int j = garea.top(); j <= garea.bottom(); j++) { + for (int i = garea.left(); i <= garea.right(); i++) { +#if 0 + unsigned short g = Glyph(i, j); + int colortmp; + int chtmp; unsigned special; - - painter.setPen( Qt::green ); /* map glyph to character and color */ - mapglyph(g, &ch, &color, &special, i, j, 0); + mapglyph(g, &chtmp, &colortmp, &special, i, j, 0); + unsigned short ch = (unsigned short) chtmp, + color = (unsigned short) colortmp; +#else + unsigned short color = Glyphcolor(i, j); + unsigned short ch = Glyphttychar(i, j); + unsigned special = Glyphflags(i, j); +#endif ch = cp437(ch); #ifdef TEXTCOLOR painter.setPen( nhcolor_to_pen(color) ); +#else + painter.setPen( Qt::green ); #endif - if (!DrawWalls( - painter, - i*qt_settings->glyphs().width(), - j*qt_settings->glyphs().height(), - qt_settings->glyphs().width(), - qt_settings->glyphs().height(), - ch)) { - painter.drawText( - i*qt_settings->glyphs().width(), - j*qt_settings->glyphs().height(), - qt_settings->glyphs().width(), - qt_settings->glyphs().height(), - Qt::AlignCenter, - QString(QChar(ch)).left(1) - ); + if (!DrawWalls(painter, i * gW, j * gH, gW, gH, ch)) { + painter.drawText(i * gW, j * gH, gW, gH, Qt::AlignCenter, + QString(QChar(ch)).left(1)); } #ifdef TEXTCOLOR - if (((special & MG_PET) != 0) && ::iflags.hilite_pet) { - painter.drawPixmap(QPoint(i*qt_settings->glyphs().width(), j*qt_settings->glyphs().height()), pet_annotation); - } else if (((special & MG_OBJPILE) != 0) && ::iflags.hilite_pile) { - painter.drawPixmap(QPoint(i*qt_settings->glyphs().width(), j*qt_settings->glyphs().height()), pile_annotation); + if ((special & MG_PET) != 0 && ::iflags.hilite_pet) { + painter.drawPixmap(QPoint(i * gW, j * gH), + pet_annotation); + } else if ((special & MG_OBJPILE) != 0 + && ::iflags.hilite_pile) { + painter.drawPixmap(QPoint(i * gW, j * gH), + pile_annotation); } #endif } } painter.setFont(font()); - } else { - for (int j=garea.top(); j<=garea.bottom(); j++) { - for (int i=garea.left(); i<=garea.right(); i++) { - unsigned short g=Glyph(i,j); + } else { // tiles + for (int j = garea.top(); j <= garea.bottom(); j++) { + for (int i = garea.left(); i <= garea.right(); i++) { + unsigned short g = Glyph(i,j); +#if 0 int color; int ch; unsigned special; mapglyph(g, &ch, &color, &special, i, j, 0); - qt_settings->glyphs().drawCell(painter, g, i, j); -#ifdef TEXTCOLOR - if (((special & MG_PET) != 0) && ::iflags.hilite_pet) { - painter.drawPixmap(QPoint(i*qt_settings->glyphs().width(), j*qt_settings->glyphs().height()), pet_annotation); - } else if (((special & MG_OBJPILE) != 0) && ::iflags.hilite_pile) { - painter.drawPixmap(QPoint(i*qt_settings->glyphs().width(), j*qt_settings->glyphs().height()), pile_annotation); - } +#else + unsigned special = Glyphflags(i, j); #endif + bool femflag = (special & MG_FEMALE) ? true : false; + glyphs.drawCell(painter, g, i, j, femflag); + + if ((special & MG_PET) != 0 && ::iflags.hilite_pet) { + painter.drawPixmap(QPoint(i * gW, j * gH), + pet_annotation); + } else if ((special & MG_OBJPILE) != 0 + && ::iflags.hilite_pile) { + painter.drawPixmap(QPoint(i * gW, j * gH), + pile_annotation); + } } } } @@ -196,48 +253,50 @@ void NetHackQtMapViewport::paintEvent(QPaintEvent* event) #else painter.setPen( Qt::green ); // REALLY primitive #endif - } else - { - int hp100; - if (u.mtimedone) { - hp100=u.mhmax ? u.mh*100/u.mhmax : 100; - } else { - hp100=u.uhpmax ? u.uhp*100/u.uhpmax : 100; - } + } else { + int hp = !Upolyd ? u.uhp : u.mh, + hpmax = !Upolyd ? u.uhpmax : u.mhmax, + hp100 = hpmax ? (hp * 100 / hpmax) : 100; - if (hp100 > 75) painter.setPen(Qt::white); - else if (hp100 > 50) painter.setPen(Qt::yellow); - else if (hp100 > 25) painter.setPen(QColor(0xff,0xbf,0x00)); // orange - else if (hp100 > 10) painter.setPen(Qt::red); - else painter.setPen(Qt::magenta); + // this uses a different color scheme from hitpoint bar but has + // the same cutoff thresholds (except for lack of separate 100%) + if (hp100 < 10 || hp < 5) + painter.setPen(Qt::magenta); + else if (hp100 < 25 || hp < 10 ) + painter.setPen(Qt::red); + else if (hp100 < 50) + painter.setPen(QColor(0xff, 0xbf, 0x00)); // orange + else if (hp100 < 75) + painter.setPen(Qt::yellow); + else + painter.setPen(Qt::white); } - painter.drawRect( - cursor.x()*qt_settings->glyphs().width(),cursor.y()*qt_settings->glyphs().height(), - qt_settings->glyphs().width()-1,qt_settings->glyphs().height()-1); + painter.drawRect(cursor.x() * gW, cursor.y() * gH, gW - 1, gH - 1); } #if 0 if (area.intersects(messages_rect)) { painter.setPen(Qt::black); - painter.drawText(viewport.contentsX()+1,viewport.contentsY()+1, - viewport.width(),0, Qt::TextWordWrap|Qt::AlignTop|Qt::AlignLeft|Qt::TextDontClip, messages); + painter.drawText(viewport.contentsX() + 1, viewport.contentsY() + 1, + viewport.width(), 0, + (Qt::TextWordWrap | Qt::AlignTop + | Qt::AlignLeft | Qt::TextDontClip), messages); painter.setPen(Qt::white); - painter.drawText(viewport.contentsX(),viewport.contentsY(), - viewport.width(),0, Qt::TextWordWrap|Qt::AlignTop|Qt::AlignLeft|Qt::TextDontClip, messages); + painter.drawText(viewport.contentsX(), viewport.contentsY(), + viewport.width(), 0, + (Qt::TextWordWrap | Qt::AlignTop + | Qt::AlignLeft | Qt::TextDontClip), messages); } #endif painter.end(); } -bool NetHackQtMapViewport::DrawWalls( - QPainter& painter, - int x, int y, int w, int h, - unsigned ch) +bool NetHackQtMapViewport::DrawWalls(QPainter& painter, int x, int y, + int w, int h, unsigned short ch) { - enum - { + enum wallbits { w_left = 0x01, w_right = 0x02, w_up = 0x04, @@ -251,89 +310,72 @@ bool NetHackQtMapViewport::DrawWalls( unsigned walls; int x1, y1, x2, y2, x3, y3; - linewidth = ((w < h) ? w : h)/8; - if (linewidth == 0) linewidth = 1; + linewidth = ((w < h) ? w : h) / 8; + if (linewidth == 0) + linewidth = 1; // Single walls walls = 0; - switch (ch) - { - case 0x2500: // BOX DRAWINGS LIGHT HORIZONTAL + switch (ch) { + case 0x2500: // box drawings light horizontal walls = w_left | w_right; break; - - case 0x2502: // BOX DRAWINGS LIGHT VERTICAL + case 0x2502: // box drawings light vertical walls = w_up | w_down; break; - - case 0x250C: // BOX DRAWINGS LIGHT DOWN AND RIGHT + case 0x250C: // box drawings light down and right walls = w_down | w_right; break; - - case 0x2510: // BOX DRAWINGS LIGHT DOWN AND LEFT + case 0x2510: // box drawings light down and left walls = w_down | w_left; break; - - case 0x2514: // BOX DRAWINGS LIGHT UP AND RIGHT + case 0x2514: // box drawings light up and right walls = w_up | w_right; break; - - case 0x2518: // BOX DRAWINGS LIGHT UP AND LEFT + case 0x2518: // box drawings light up and left walls = w_up | w_left; break; - - case 0x251C: // BOX DRAWINGS LIGHT VERTICAL AND RIGHT + case 0x251C: // box drawings light vertical and right walls = w_up | w_down | w_right; break; - - case 0x2524: // BOX DRAWINGS LIGHT VERTICAL AND LEFT + case 0x2524: // box drawings light vertical and left walls = w_up | w_down | w_left; break; - - case 0x252C: // BOX DRAWINGS LIGHT DOWN AND HORIZONTAL + case 0x252C: // box drawings light down and horizontal walls = w_down | w_left | w_right; break; - - case 0x2534: // BOX DRAWINGS LIGHT UP AND HORIZONTAL + case 0x2534: // box drawings light up and horizontal walls = w_up | w_left | w_right; break; - - case 0x253C: // BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL + case 0x253C: // box drawings light vertical and horizontal walls = w_up | w_down | w_left | w_right; break; } - if (walls != 0) - { - x1 = x + w/2; - switch (walls & (w_up | w_down)) - { + if (walls != 0) { + x1 = x + w / 2; + switch (walls & (w_up | w_down)) { case w_up: - painter.drawLine(x1, y, x1, y+h/2); + painter.drawLine(x1, y, x1, y + h / 2); break; - case w_down: - painter.drawLine(x1, y+h/2, x1, y+h-1); + painter.drawLine(x1, y + h / 2, x1, y + h - 1); break; - case w_up | w_down: - painter.drawLine(x1, y, x1, y+h-1); + painter.drawLine(x1, y, x1, y + h - 1); break; } - y1 = y + h/2; - switch (walls & (w_left | w_right)) - { + y1 = y + h / 2; + switch (walls & (w_left | w_right)) { case w_left: - painter.drawLine(x, y1, x+w/2, y1); + painter.drawLine(x, y1, x + w / 2, y1); break; - case w_right: - painter.drawLine(x+w/2, y1, x+w-1, y1); + painter.drawLine(x + w / 2, y1, x + w - 1, y1); break; - case w_left | w_right: - painter.drawLine(x, y1, x+w-1, y1); + painter.drawLine(x, y1, x + w - 1, y1); break; } @@ -342,108 +384,88 @@ bool NetHackQtMapViewport::DrawWalls( // Double walls walls = 0; - switch (ch) - { - case 0x2550: // BOX DRAWINGS DOUBLE HORIZONTAL + switch (ch) { + case 0x2550: // box drawings double horizontal walls = w_left | w_right | w_sq_top | w_sq_bottom; break; - - case 0x2551: // BOX DRAWINGS DOUBLE VERTICAL + case 0x2551: // box drawings double vertical walls = w_up | w_down | w_sq_left | w_sq_right; break; - - case 0x2554: // BOX DRAWINGS DOUBLE DOWN AND RIGHT + case 0x2554: // box drawings double down and right walls = w_down | w_right | w_sq_top | w_sq_left; break; - - case 0x2557: // BOX DRAWINGS DOUBLE DOWN AND LEFT + case 0x2557: // box drawings double down and left walls = w_down | w_left | w_sq_top | w_sq_right; break; - - case 0x255A: // BOX DRAWINGS DOUBLE UP AND RIGHT + case 0x255A: // box drawings double up and right walls = w_up | w_right | w_sq_bottom | w_sq_left; break; - - case 0x255D: // BOX DRAWINGS DOUBLE UP AND LEFT + case 0x255D: // box drawings double up and left walls = w_up | w_left | w_sq_bottom | w_sq_right; break; - - case 0x2560: // BOX DRAWINGS DOUBLE VERTICAL AND RIGHT + case 0x2560: // box drawings double vertical and right walls = w_up | w_down | w_right | w_sq_left; break; - - case 0x2563: // BOX DRAWINGS DOUBLE VERTICAL AND LEFT + case 0x2563: // box drawings double vertical and left walls = w_up | w_down | w_left | w_sq_right; break; - - case 0x2566: // BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL + case 0x2566: // box drawings double down and horizontal walls = w_down | w_left | w_right | w_sq_top; break; - - case 0x2569: // BOX DRAWINGS DOUBLE UP AND HORIZONTAL + case 0x2569: // box drawings double up and horizontal walls = w_up | w_left | w_right | w_sq_bottom; break; - - case 0x256C: // BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL + case 0x256C: // box drawings double vertical and horizontal walls = w_up | w_down | w_left | w_right; break; } - if (walls != 0) - { - x1 = x + w/2 - linewidth; - x2 = x + w/2 + linewidth; + + if (walls != 0) { + x1 = x + w / 2 - linewidth; + x2 = x + w / 2 + linewidth; x3 = x + w - 1; - y1 = y + h/2 - linewidth; - y2 = y + h/2 + linewidth; + y1 = y + h / 2 - linewidth; + y2 = y + h / 2 + linewidth; y3 = y + h - 1; - if (walls & w_up) - { + if (walls & w_up) { painter.drawLine(x1, y, x1, y1); painter.drawLine(x2, y, x2, y1); } - if (walls & w_down) - { + if (walls & w_down) { painter.drawLine(x1, y2, x1, y3); painter.drawLine(x2, y2, x2, y3); } - if (walls & w_left) - { + if (walls & w_left) { painter.drawLine(x, y1, x1, y1); painter.drawLine(x, y2, x1, y2); } - if (walls & w_right) - { + if (walls & w_right) { painter.drawLine(x2, y1, x3, y1); painter.drawLine(x2, y2, x3, y2); } - if (walls & w_sq_top) - { + if (walls & w_sq_top) { painter.drawLine(x1, y1, x2, y1); } - if (walls & w_sq_bottom) - { + if (walls & w_sq_bottom) { painter.drawLine(x1, y2, x2, y2); } - if (walls & w_sq_left) - { + if (walls & w_sq_left) { painter.drawLine(x1, y1, x1, y2); } - if (walls & w_sq_right) - { + if (walls & w_sq_right) { painter.drawLine(x2, y1, x2, y2); } + return true; } // Solid blocks - if (0x2591 <= ch && ch <= 0x2593) - { + if (0x2591 <= ch && ch <= 0x2593) { unsigned shade = ch - 0x2590; QColor rgb(painter.pen().color()); - QColor rgb2( - rgb.red()*shade/4, - rgb.green()*shade/4, - rgb.blue()*shade/4); + QColor rgb2(rgb.red() * shade / 4, + rgb.green() * shade / 4, + rgb.blue() * shade / 4); painter.fillRect(x, y, w, h, rgb2); return true; } @@ -453,26 +475,23 @@ bool NetHackQtMapViewport::DrawWalls( void NetHackQtMapViewport::mousePressEvent(QMouseEvent* event) { - clicksink.Put( - event->pos().x()/qt_settings->glyphs().width(), - event->pos().y()/qt_settings->glyphs().height(), - event->button()==Qt::LeftButton ? CLICK_1 : CLICK_2 - ); + clicksink.Put(event->pos().x() / qt_settings->glyphs().width(), + event->pos().y() / qt_settings->glyphs().height(), + (event->button() == Qt::LeftButton) ? CLICK_1 : CLICK_2); qApp->exit(); } void NetHackQtMapViewport::updateTiles() { change.clear(); - change.add(0,0,COLNO,ROWNO); + change.add(0, 0, COLNO, ROWNO); delete rogue_font; rogue_font = NULL; } QSize NetHackQtMapViewport::sizeHint() const { - return QSize( - qt_settings->glyphs().width() * COLNO, - qt_settings->glyphs().height() * ROWNO); + return QSize(qt_settings->glyphs().width() * COLNO, + qt_settings->glyphs().height() * ROWNO); } QSize NetHackQtMapViewport::minimumSizeHint() const @@ -482,65 +501,77 @@ QSize NetHackQtMapViewport::minimumSizeHint() const void NetHackQtMapViewport::clickCursor() { - clicksink.Put(cursor.x(),cursor.y(),CLICK_1); + clicksink.Put(cursor.x(), cursor.y(), CLICK_1); qApp->exit(); } +// [re-]init map display to unexplored with no changed cells void NetHackQtMapViewport::Clear() { - unsigned short stone=cmap_to_glyph(S_stone); + for (int j = 0; j < ROWNO; ++j) { + // + // FIXME: map column 0 should be surpressed from being displayed + // + Glyph(0, j) = GLYPH_NOTHING; + Glyphttychar(0, j) = ' '; + Glyphcolor(0, j) = NO_COLOR; + Glyphflags(0, j) = 0U; - for (int j=0; jglyphs().width(), - ch.y()*qt_settings->glyphs().height(), - ch.width()*qt_settings->glyphs().width(), - ch.height()*qt_settings->glyphs().height() - ); - } + int gW = qt_settings->glyphs().width(), + gH = qt_settings->glyphs().height(); + for (int i = 0; i < change.clusters(); i++) { + const QRect& chg = change[i]; + repaint(chg.x() * gW, chg.y() * gH, + chg.width() * gW, chg.height() * gH); + } change.clear(); if (block) { - yn_function("Press a key when done viewing",0,'\0'); + yn_function("Press a key when done viewing", NULL, '\0'); } } void NetHackQtMapViewport::CursorTo(int x,int y) { - Changed(cursor.x(),cursor.y()); + Changed(cursor.x(), cursor.y()); cursor.setX(x); cursor.setY(y); - Changed(cursor.x(),cursor.y()); + Changed(cursor.x(), cursor.y()); } -void NetHackQtMapViewport::PrintGlyph(int x,int y,int glyph) +void NetHackQtMapViewport::PrintGlyph(int x, int y, int theglyph, + unsigned *glyphmod) { - Glyph(x,y)=glyph; - Changed(x,y); + Glyph(x, y) = (unsigned short) theglyph; + Glyphttychar(x, y) = (unsigned short) glyphmod[GM_TTYCHAR]; + Glyphcolor(x, y) = (unsigned short) glyphmod[GM_COLOR]; + Glyphflags(x, y) = glyphmod[GM_FLAGS]; + Changed(x, y); } void NetHackQtMapViewport::Changed(int x, int y) { - change.add(x,y); + change.add(x, y); } NetHackQtMapWindow2::NetHackQtMapWindow2(NetHackQtClickBuffer& click_sink) : - QScrollArea(NULL), - m_viewport(new NetHackQtMapViewport(click_sink)) + QScrollArea(NULL), + m_viewport(new NetHackQtMapViewport(click_sink)) { QPalette palette; palette.setColor(backgroundRole(), Qt::black); @@ -548,22 +579,22 @@ NetHackQtMapWindow2::NetHackQtMapWindow2(NetHackQtClickBuffer& click_sink) : setWidget(m_viewport); - connect(qt_settings,SIGNAL(tilesChanged()),this,SLOT(updateTiles())); + connect(qt_settings, SIGNAL(tilesChanged()), this, SLOT(updateTiles())); updateTiles(); } void NetHackQtMapWindow2::updateTiles() { NetHackQtGlyphs& glyphs = qt_settings->glyphs(); - int gw = glyphs.width(); - int gh = glyphs.height(); + int gW = glyphs.width(); + int gH = glyphs.height(); // Be exactly the size we want to be - full map... - m_viewport->resize(COLNO*gw,ROWNO*gh); + m_viewport->resize(COLNO * gW, ROWNO * gH); - verticalScrollBar()->setSingleStep(gh); - verticalScrollBar()->setPageStep(gh); - horizontalScrollBar()->setSingleStep(gw); - horizontalScrollBar()->setPageStep(gw); + verticalScrollBar()->setSingleStep(gH); + verticalScrollBar()->setPageStep(gH); + horizontalScrollBar()->setSingleStep(gW); + horizontalScrollBar()->setPageStep(gW); m_viewport->updateTiles(); Display(false); @@ -578,14 +609,18 @@ void NetHackQtMapWindow2::clearMessages() messages_rect = QRect(); } -void NetHackQtMapWindow2::putMessage(int attr, const QString& text) +void NetHackQtMapWindow2::putMessage(int attr UNUSED, const QString& text) { - if ( !messages.isEmpty() ) + if (!messages.isEmpty()) messages += "\n"; messages += QString(text).replace(QChar(0x200B), ""); - QFontMetrics fm = fontMetrics(); #if 0 - messages_rect = fm.boundingRect(viewport.contentsX(),viewport.contentsY(),viewport.width(),0, Qt::TextWordWrap|Qt::AlignTop|Qt::AlignLeft|Qt::TextDontClip, messages); + QFontMetrics fm = fontMetrics(); + messages_rect = fm.boundingRect(viewport.contentsX(), viewport.contentsY(), + viewport.width(), 0, + (Qt::TextWordWrap | Qt::AlignTop + | Qt::AlignLeft | Qt::TextDontClip), + messages); update(messages_rect); #endif } @@ -615,7 +650,7 @@ void NetHackQtMapWindow2::CursorTo(int x,int y) m_viewport->CursorTo(x, y); } -void NetHackQtMapWindow2::PutStr(int attr, const QString& text) +void NetHackQtMapWindow2::PutStr(int attr UNUSED, const QString& text UNUSED) { puts("unexpected PutStr in MapWindow"); } @@ -630,9 +665,9 @@ void NetHackQtMapWindow2::ClipAround(int x,int y) ensureVisible(x,y,width()*0.45,height()*0.45); } -void NetHackQtMapWindow2::PrintGlyph(int x,int y,int glyph) +void NetHackQtMapWindow2::PrintGlyph(int x,int y,int glyph, unsigned *glyphmod) { - m_viewport->PrintGlyph(x, y, glyph); + m_viewport->PrintGlyph(x, y, glyph, glyphmod); } #if 0 //RLC @@ -653,7 +688,8 @@ NetHackQtMapWindow::NetHackQtMapWindow(NetHackQtClickBuffer& click_sink) : palette.setColor(viewport.backgroundRole(), Qt::black); viewport.setPalette(palette); - pet_annotation = QPixmap(qt_compact_mode ? pet_mark_small_xpm : pet_mark_xpm); + pet_annotation = QPixmap(qt_compact_mode ? pet_mark_small_xpm + : pet_mark_xpm); pile_annotation = QPixmap(pile_mark_xpm); cursor.setX(0); @@ -689,7 +725,11 @@ void NetHackQtMapWindow::putMessage(int attr, const QString& text) messages += "\n"; messages += QString(text).replace(QChar(0x200B), ""); QFontMetrics fm = fontMetrics(); - messages_rect = fm.boundingRect(viewport.contentsX(),viewport.contentsY(),viewport.width(),0, Qt::TextWordWrap|Qt::AlignTop|Qt::AlignLeft|Qt::TextDontClip, messages); + messages_rect = fm.boundingRect(viewport.contentsX(), viewport.contentsY(), + viewport.width(), 0, + (Qt::TextWordWrap | Qt::AlignTop + | Qt::AlignLeft | Qt::TextDontClip), + messages); update(messages_rect); } @@ -747,12 +787,17 @@ void NetHackQtMapWindow::Scroll(int dx, int dy) void NetHackQtMapWindow::Clear() { - unsigned short stone=cmap_to_glyph(S_stone); - - for (int j=0; jglyphs().width(), j*qt_settings->glyphs().height()), pet_annotation); - } else if (((special & MG_OBJPILE) != 0) && ::iflags.hilite_pile) { - painter.drawPixmap(QPoint(i*qt_settings->glyphs().width(), j*qt_settings->glyphs().height()), pile_annotation); + if ((special & MG_PET) != 0 && ::iflags.hilite_pet) { + painter.drawPixmap(QPoint(i*qt_settings->glyphs().width(), + j*qt_settings->glyphs().height()), + pet_annotation); + } else if ((special & MG_OBJPILE) != 0 + && ::iflags.hilite_pile) { + painter.drawPixmap(QPoint(i*qt_settings->glyphs().width(), + j*qt_settings->glyphs().height()), + pile_annotation); } #endif } @@ -856,16 +911,28 @@ void NetHackQtMapWindow::paintEvent(QPaintEvent* event) for (int j=garea.top(); j<=garea.bottom(); j++) { for (int i=garea.left(); i<=garea.right(); i++) { unsigned short g=Glyph(i,j); +#if 0 int color; int ch; unsigned special; mapglyph(g, &ch, &color, &special, i, j, 0); - qt_settings->glyphs().drawCell(painter, g, i, j); +#else + int color = Glyphcolor(i,j); + int ch = Glyphttychar(i,j); + unsigned special = Glyphflags(i,j); +#endif + bool femflag = (special & MG_FEMALE) ? true : false; + qt_settings->glyphs().drawCell(painter, g, i, j, femflag); #ifdef TEXTCOLOR - if (((special & MG_PET) != 0) && ::iflags.hilite_pet) { - painter.drawPixmap(QPoint(i*qt_settings->glyphs().width(), j*qt_settings->glyphs().height()), pet_annotation); - } else if (((special & MG_OBJPILE) != 0) && ::iflags.hilite_pile) { - painter.drawPixmap(QPoint(i*qt_settings->glyphs().width(), j*qt_settings->glyphs().height()), pile_annotation); + if ((special & MG_PET) != 0 && ::iflags.hilite_pet) { + painter.drawPixmap(QPoint(i*qt_settings->glyphs().width(), + j*qt_settings->glyphs().height()), + pet_annotation); + } else if ((special & MG_OBJPILE) != 0 + && ::iflags.hilite_pile) { + painter.drawPixmap(QPoint(i*qt_settings->glyphs().width(), + j*qt_settings->glyphs().height()), + pile_annotation); } #endif } @@ -882,31 +949,41 @@ void NetHackQtMapWindow::paintEvent(QPaintEvent* event) } else { int hp100; - if (u.mtimedone) { + if (Upolyd) { hp100=u.mhmax ? u.mh*100/u.mhmax : 100; } else { hp100=u.uhpmax ? u.uhp*100/u.uhpmax : 100; } - if (hp100 > 75) painter.setPen(Qt::white); - else if (hp100 > 50) painter.setPen(Qt::yellow); - else if (hp100 > 25) painter.setPen(QColor(0xff,0xbf,0x00)); // orange - else if (hp100 > 10) painter.setPen(Qt::red); - else painter.setPen(Qt::magenta); + if (hp100 > 75) + painter.setPen(Qt::white); + else if (hp100 > 50) + painter.setPen(Qt::yellow); + else if (hp100 > 25) + painter.setPen(QColor(0xff, 0xbf, 0x00)); // orange + else if (hp100 > 10) + painter.setPen(Qt::red); + else + painter.setPen(Qt::magenta); } - painter.drawRect( - cursor.x()*qt_settings->glyphs().width(),cursor.y()*qt_settings->glyphs().height(), - qt_settings->glyphs().width()-1,qt_settings->glyphs().height()-1); + painter.drawRect(cursor.x() * qt_settings->glyphs().width(), + cursor.y() * qt_settings->glyphs().height(), + qt_settings->glyphs().width() - 1, + qt_settings->glyphs().height() - 1); } if (area.intersects(messages_rect)) { painter.setPen(Qt::black); - painter.drawText(viewport.contentsX()+1,viewport.contentsY()+1, - viewport.width(),0, Qt::TextWordWrap|Qt::AlignTop|Qt::AlignLeft|Qt::TextDontClip, messages); + painter.drawText(viewport.contentsX() + 1, viewport.contentsY() + 1, + viewport.width(), 0, + (Qt::TextWordWrap | Qt::AlignTop + | Qt::AlignLeft | Qt::TextDontClip), messages); painter.setPen(Qt::white); - painter.drawText(viewport.contentsX(),viewport.contentsY(), - viewport.width(),0, Qt::TextWordWrap|Qt::AlignTop|Qt::AlignLeft|Qt::TextDontClip, messages); + painter.drawText(viewport.contentsX(), viewport.contentsY(), + viewport.width(), 0, + (Qt::TextWordWrap | Qt::AlignTop + | Qt::AlignLeft | Qt::TextDontClip), messages); } painter.end(); @@ -954,9 +1031,12 @@ void NetHackQtMapWindow::ClipAround(int x,int y) viewport.center(x,y,0.45,0.45); } -void NetHackQtMapWindow::PrintGlyph(int x,int y,int glyph) +void NetHackQtMapWindow::PrintGlyph(int x,int y,int glyph, unsigned *glyphmod) { Glyph(x,y)=glyph; + Glyphttychar(x,y)=glyphmod[GM_TTYCHAR]; + Glyphcolor(x,y)=glyphmod[GM_COLOR]; + Glyphflags(x,y)=glyphmod[GM_FLAGS]; Changed(x,y); } diff --git a/win/Qt/qt_map.h b/win/Qt/qt_map.h index 8849a18da..82050dc98 100644 --- a/win/Qt/qt_map.h +++ b/win/Qt/qt_map.h @@ -22,28 +22,44 @@ public: protected: virtual void paintEvent(QPaintEvent* event); - bool DrawWalls(QPainter& painter, int x, int y, int w, int h, unsigned ch); + bool DrawWalls(QPainter& painter, int x, int y, + int w, int h, unsigned short ch); virtual QSize sizeHint() const; virtual QSize minimumSizeHint() const; virtual void mousePressEvent(QMouseEvent* event); private: - QFont *rogue_font; - unsigned short glyph[ROWNO][COLNO]; - unsigned short& Glyph(int x, int y) { return glyph[y][x]; } - QPoint cursor; - QPixmap pet_annotation; + QFont *rogue_font; + unsigned short glyph[ROWNO][COLNO]; + unsigned short &Glyph(int x, int y) { + return glyph[y][x]; + } + unsigned short glyphttychar[ROWNO][COLNO]; + unsigned short &Glyphttychar(int x, int y) { + return glyphttychar[y][x]; + } + unsigned short glyphcolor[ROWNO][COLNO]; + unsigned short &Glyphcolor(int x, int y) { + return glyphcolor[y][x]; + } + unsigned int glyphflags[ROWNO][COLNO]; + unsigned int &Glyphflags(int x, int y) { + return glyphflags[y][x]; + } + QPoint cursor; + QPixmap pet_annotation; QPixmap pile_annotation; - NetHackQtClickBuffer& clicksink; - Clusterizer change; + NetHackQtClickBuffer &clicksink; + Clusterizer change; void clickCursor(); void Clear(); void Display(bool block); void CursorTo(int x,int y); - void PrintGlyph(int x,int y,int glyph); + void PrintGlyph(int x,int y,int glyph,unsigned *glyphmod); void Changed(int x, int y); void updateTiles(); + void SetupTextmapFont(QPainter &painter); // NetHackQtMapWindow2 passes through many calls to the viewport friend class NetHackQtMapWindow2; @@ -63,7 +79,7 @@ public: virtual void CursorTo(int x,int y); virtual void PutStr(int attr, const QString& text); virtual void ClipAround(int x,int y); - virtual void PrintGlyph(int x,int y,int glyph); + virtual void PrintGlyph(int x,int y,int glyph,unsigned *glyphmod); signals: void resized(); diff --git a/win/Qt/qt_menu.cpp b/win/Qt/qt_menu.cpp index b959ad5d0..e02cd3d40 100644 --- a/win/Qt/qt_menu.cpp +++ b/win/Qt/qt_menu.cpp @@ -4,23 +4,37 @@ // qt_menu.cpp -- a menu or text-list widget +// +// TODO: +// inventory menus reuse the same menu window over and over (in the core); +// it isn't resizing properly to reflect each new instance's content; +// [temporary 'fix' allocates at least 15 lines in case a really short +// subset is displayed before a full inventory; but all inventory menus +// will be padded to that length when they might otherwise show all the +// entries with less, and inventories which have more will need to be +// scrolled to see the excess even if a taller menu would fit on the +// screen; code now has to distinguish between inventory menu and +// 'other' menu so that the latter isn't padded too] +// implement next_page, prev_page, first_page, and last_page to work +// like they do for X11: scroll menu window as if it were paginated; +// entering a count that uses more digits than the previous biggest count +// widens count field but fails to widen the whole menu so a horizontal +// scrollbar might appear; +// create and use custom check-box icons to visually distinguish +// pre-selected entries and numeric subset entries from ordinary select +// and unselected. +// + extern "C" { #include "hack.h" } -#undef Invisible -#undef Warning -#undef index -#undef msleep -#undef rindex -#undef wizard -#undef yn -#undef min -#undef max +#include "qt_pre.h" #include #if QT_VERSION >= 0x050000 #include #endif +#include "qt_post.h" #include "qt_menu.h" #include "qt_menu.moc" #include "qt_glyph.h" @@ -32,6 +46,7 @@ extern "C" { extern "C" int qt_compact_mode; // end temporary +/* for documentation rather than necessity; hack.h -> decl.h declares this */ extern "C" struct menucoloring *menu_colorings; namespace nethack_qt_ { @@ -40,6 +55,24 @@ namespace nethack_qt_ { void centerOnMain( QWidget* w ); // end temporary +uchar keyValue(QKeyEvent *key_event) +{ + // key_event manipulation derived from NetHackQtBind::notify() + const int k = key_event->key(); + Qt::KeyboardModifiers mod = key_event->modifiers(); + QChar ch = !key_event->text().isEmpty() ? key_event->text().at(0) : 0; + if (ch >= 128) + ch = 0; + // on OSX, ascii control codes are not sent, force them + if (ch == 0 && (mod & Qt::ControlModifier) != 0) { + if (k >= Qt::Key_A && k <= Qt::Key_Underscore) + ch = QChar((k - (Qt::Key_A - 1))); + } + uchar result = (uchar) ch.cell(); + //raw_printf("kV: k=%d, ch=%d", k, result); + return result; +} + QSize NetHackQtTextListBox::sizeHint() const { QScrollBar *hscroll = horizontalScrollBar(); @@ -59,40 +92,103 @@ int NetHackQtMenuListBox::TotalWidth() const int NetHackQtMenuListBox::TotalHeight() const { - int height = 0; + int row, rowheight, height = 0; - for (int row = 0; row < rowCount(); ++row) { + for (row = 0; row < rowCount(); ++row) { height += rowHeight(row); } + // 20: arbitrary; should always have at least 1 row so it shouldn't matter + rowheight = (row > 0) ? rowHeight(row - 1) : 20; + + // + // FIXME: + // The core reuses one window for inventory displays and this + // part of sizeHint() is working for the initial size but is + // ineffective for later resizes. + // + + // TEMPORARY: + // in case first inventory menu displayed is a short one pad it + // with blank lines so later long ones won't be far too short + if ((dynamic_cast (parent()))->is_invent) { + if (row < 15) + height += (15 - row) * rowheight; + } + + // include extra height so that there will be a blank gap after the + // last entry to show that there is nothing to scroll forward too + height += rowheight / 2; return height; } QSize NetHackQtMenuListBox::sizeHint() const { - QScrollBar *hscroll = horizontalScrollBar(); - int hsize = hscroll ? hscroll->height() : 0; - return QSize(TotalWidth()+hsize, TotalHeight()+hsize); + QScrollBar *hscroll = horizontalScrollBar(), + *vscroll = verticalScrollBar(); + int hsize = (hscroll && hscroll->isVisible()) ? hscroll->height() : 0, + vsize = (vscroll && vscroll->isVisible()) ? vscroll->width() : 0; + hsize += MENU_WIDTH_SLOP, vsize += MENU_WIDTH_SLOP; + // note: a vertical scrollbar affects widget width, a horizontal one height + return QSize(TotalWidth() + vsize, TotalHeight() + hsize); } -// Table view columns: +// +// FIXME: +// Inventory displays reuse the same menu window and so far this +// is not updating the size as intended. The size of the first +// instance persists. +// + +// resize current menu window and the table (rows of entries) inside it +void NetHackQtMenuWindow::MenuResize() +{ + // when this was just 'adjustSize()', our sizeHints() was not + // being called so explicitly indicate the table widget + table->adjustSize(); + this->adjustSize(); + + // Temporary? workaround for scrolling becoming wedged if using + // all/none/invert removes all counts so we narrow a non-empty + // count column to empty. [That can take away the horizontal + // scroll bar but should not be affecting the vertical one, yet + // is (Qt 5.11.3).] Typing any digit restored normal scrolling + // and the only significant thing about that is that it updates + // the prompt line which is outside the table of menu items where + // scrolling takes place. Oddly, both prompt changes are needed + // (possibly the unnecessary space in the first is being optimized + // away but the second call to remove it isn't aware of that, or + // perhaps the 'fix' only happens when the line gets shorter). + prompt.setText(promptstr + " "); + prompt.setText(promptstr); + // [Later: becoming wedged doesn't just occur after shrinking the + // count column and seems to be triggered by table->adjustSize().] +} + +// Table view columns (0..4): // -// [pick-count] [accel] [glyph] [string] +// [pick-count] [check-box] [object-glyph] [selector-letter] [description] // -// Maybe accel should be near string. We'll see. -// pick-count normally blank. -// double-clicking or click-on-count gives pop-up entry -// string is green when selected +// pick-count is normally empty and gets wider as needed. // NetHackQtMenuWindow::NetHackQtMenuWindow(QWidget *parent) : QDialog(parent), + is_invent(false), // reset to True when window is core's WIN_INVEN table(new NetHackQtMenuListBox()), prompt(0), - counting(false) + biggestcount(0L), // largest subset amount that user has entered + countdigits(0), // number of digits needed by biggestcount + counting(false), // user has typed a digit and more might follow + searching(false) // user has begun entering a search target string { + // setFont() was in SelectMenu(), in time to be rendered but too late + // when measuring the width and height that will be needed + QFont tablefont(qt_settings->normalFixedFont()); + table->setFont(tablefont); + QGridLayout *grid = new QGridLayout(); table->setColumnCount(5); table->setFrameStyle(QFrame::Panel|QFrame::Sunken); - table->setLineWidth(2); + table->setLineWidth(2); // note: this is not row spacing table->setShowGrid(false); table->horizontalHeader()->hide(); table->verticalHeader()->hide(); @@ -132,7 +228,8 @@ NetHackQtMenuWindow::NetHackQtMenuWindow(QWidget *parent) : grid->setRowStretch(2, 1); setFocusPolicy(Qt::StrongFocus); table->setFocusPolicy(Qt::NoFocus); - connect(table, SIGNAL(cellClicked(int,int)), this, SLOT(cellToggleSelect(int,int))); + connect(table, SIGNAL(cellClicked(int,int)), + this, SLOT(TableCellClicked(int,int))); setLayout(grid); } @@ -143,11 +240,24 @@ NetHackQtMenuWindow::~NetHackQtMenuWindow() QWidget* NetHackQtMenuWindow::Widget() { return this; } -void NetHackQtMenuWindow::StartMenu() +// +// Note: inventory menus reuse the same menu window over and over +// so StartMenu(), AddMenu(), EndMenu(), and SelectMenu() +// can't rely on the MenuWindow constructor for initialization. +// + +void NetHackQtMenuWindow::StartMenu(bool using_WIN_INVEN) { - table->setRowCount((itemcount=0)); - next_accel=0; - has_glyphs=false; + itemcount = 0; + table->setRowCount(itemcount); + next_accel = 0; + has_glyphs = false; + biggestcount = 0L; + countdigits = 0; + ClearCount(); // reset 'counting' flag and digit string 'countstr' + ClearSearch(); // reset 'searching' flag + + is_invent = using_WIN_INVEN; } NetHackQtMenuWindow::MenuItem::MenuItem() : @@ -159,13 +269,15 @@ NetHackQtMenuWindow::MenuItem::~MenuItem() { } -void NetHackQtMenuWindow::AddMenu(int glyph, const ANY_P* identifier, - char ch, char gch, int attr, const QString& str, unsigned itemflags) +void NetHackQtMenuWindow::AddMenu(int glyph, const ANY_P *identifier, + char ch, char gch, int attr, + const QString& str, unsigned itemflags) { bool presel = (itemflags & MENU_ITEMFLAGS_SELECTED) != 0; if (!ch && identifier->a_void!=0) { // Supply a keyboard accelerator. Limited supply. - static char accel[]="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + static char accel[] + = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; if (accel[next_accel]) { ch=accel[next_accel++]; } @@ -174,15 +286,15 @@ void NetHackQtMenuWindow::AddMenu(int glyph, const ANY_P* identifier, if ((int)itemlist.size() < itemcount+1) { itemlist.resize(itemcount*4+10); } - itemlist[itemcount].glyph=glyph; - itemlist[itemcount].identifier=*identifier; - itemlist[itemcount].ch=ch; - itemlist[itemcount].gch=gch; - itemlist[itemcount].attr=attr; - itemlist[itemcount].str=str; - itemlist[itemcount].selected=presel; - itemlist[itemcount].itemflags=itemflags; - itemlist[itemcount].count=-1; + itemlist[itemcount].glyph = glyph; + itemlist[itemcount].identifier = *identifier; + itemlist[itemcount].ch = ch; + itemlist[itemcount].gch = gch; + itemlist[itemcount].attr = attr; + itemlist[itemcount].str = str; + itemlist[itemcount].selected = itemlist[itemcount].preselected = presel; + itemlist[itemcount].itemflags = itemflags; + itemlist[itemcount].count = -1L; itemlist[itemcount].color = -1; // Display the boulder symbol correctly if (str.left(8) == "boulder\t") { @@ -194,14 +306,15 @@ void NetHackQtMenuWindow::AddMenu(int glyph, const ANY_P* identifier, } } int mcolor, mattr; - if (attr == 0 + if (attr == 0 && ::iflags.use_menu_color && get_menu_coloring(str.toLatin1().constData(), &mcolor, &mattr)) { itemlist[itemcount].attr = mattr; itemlist[itemcount].color = mcolor; } ++itemcount; - if (glyph!=NO_GLYPH) has_glyphs=true; + if (glyph != NO_GLYPH) + has_glyphs = true; } void NetHackQtMenuWindow::EndMenu(const QString& p) @@ -212,135 +325,241 @@ void NetHackQtMenuWindow::EndMenu(const QString& p) int NetHackQtMenuWindow::SelectMenu(int h, MENU_ITEM_P **menu_list) { - QFont tablefont(qt_settings->normalFont()); - table->setFont(tablefont); - table->setRowCount(itemcount); how=h; - ok->setEnabled(how!=PICK_ONE);ok->setDefault(how!=PICK_ONE); - cancel->setEnabled(how!=PICK_NONE); - all->setEnabled(how==PICK_ANY); - none->setEnabled(how==PICK_ANY); - invert->setEnabled(how==PICK_ANY); - search->setEnabled(how!=PICK_NONE); + int presel_ct = 0; + for (int i = 0; i < itemcount; ++i) + if (itemlist[i].preselected) + ++presel_ct; + bool ok_ok = (how != PICK_ONE || presel_ct == 1); + ok->setEnabled(ok_ok); ok->setDefault(ok_ok); + cancel->setEnabled(true); + all->setEnabled(how == PICK_ANY || (how == PICK_ONE && itemcount == 1)); + none->setEnabled(how == PICK_ANY || (how == PICK_ONE && presel_ct == 1)); + invert->setEnabled(how == PICK_ANY || (how == PICK_ONE && itemcount == 1)); + search->setEnabled(how != PICK_NONE); setResult(-1); // Set contents of table QFontMetrics fm(table->font()); - for (int i = 0; i < 5; i++) { - table->setColumnWidth(i, 0); + for (int col = 0; col < 5; ++col) { + table->setColumnWidth(col, 0); } - for (int i = 0; i < itemcount; i++) { - AddRow(i, itemlist[i]); + // default height is way too big; rows end up being double-spaced with it + int rowheight = fm.height() * 3 / 5; + for (int row = 0; row < itemcount; ++row) { + AddRow(row, itemlist[row]); + table->setRowHeight(row, rowheight); } + PadMenuColumns(::iflags.menu_tab_sep ? true : false); - // Determine column widths - std::vector col_widths; - for (std::size_t i = 0; i < itemlist.size(); ++i) { - QStringList columns = itemlist[i].str.split("\t"); - if (!itemlist[i].Selectable() && columns.size() == 1) - { - // Nonselectable line with no column dividers - // Assume this is a section header - continue; - } - for (std::size_t j = 0U; j < columns.size(); ++j) { - int w = fm.width(columns[j] + " \t"); - if (j >= col_widths.size()) { - col_widths.push_back(w); - } else if (col_widths[j] < w) { - col_widths[j] = w; - } - } - } + MenuResize(); - // Pad each column to its column width - for (std::size_t i = 0U; i < itemlist.size(); ++i) { - QTableWidgetItem *twi = table->item(i, 4); - if (twi == NULL) { continue; } - QString text = twi->text(); - QStringList columns = text.split("\t"); - for (std::size_t j = 0U; j+1U < columns.size(); ++j) { - columns[j] += "\t"; - int width = col_widths[j]; - while (fm.width(columns[j]) < width) { - columns[j] += "\t"; - } - } - text = columns.join(""); - twi->setText(text); - WidenColumn(4, fm.width(text)); - } - - // FIXME: size for compact mode + //old FIXME: size for compact mode //resize(this->width(), parent()->height()*7/8); move(0, 0); - adjustSize(); centerOnMain(this); - exec(); - int result=this->result(); - *menu_list=0; - if (result>0 && how!=PICK_NONE) { - if (how==PICK_ONE) { - int i; - for (i=0; iresult(); + + *menu_list = (MENU_ITEM_P *) 0; + if (result > 0 && how != PICK_NONE) { + int n = 0; + for (int i = 0; i < itemcount; ++i) + if (itemlist[i].selected) + ++n; + if (n) { + *menu_list = (MENU_ITEM_P *) alloc(n * sizeof(MENU_ITEM_P)); + n = 0; + for (int i = 0; i < itemcount; ++i) { + if (itemlist[i].selected) { + (*menu_list)[n].item = itemlist[i].identifier; + (*menu_list)[n].count = count(i); + ++n; + } + } + } + return n; } else { return -1; } } +// pad the menu columns so that they all line up +void NetHackQtMenuWindow::PadMenuColumns(bool split_descr) +{ + QFontMetrics fm(table->font()); + QString col0width_str = ""; + if (biggestcount > 0L) + col0width_str.sprintf("%*ld", std::max(countdigits, 1), biggestcount); + int col0width_int = (int) fm.width(col0width_str) + MENU_WIDTH_SLOP; + if (col0width_int > table->columnWidth(0)) + WidenColumn(0, col0width_int); + + // If the description (column 4) is a tab separated list, split + // it into fields and figure out how wide each field should be. + // Needs to be done at most once for any given menu instantiation. + std::vector col_widths(1, 0); // start with 1 element init'd to 0 + if (split_descr) { + for (int row = 0; row < itemcount; ++row) { + QTableWidgetItem *twi = table->item(row, 4); // description + if (twi == NULL) + continue; + // if a header/footnote/&c with no sub-fields, don't inflate + // the size of col_widths[0] + if (!itemlist[row].Selectable() + && !itemlist[row].str.contains(QChar('\t'))) + continue; + // determine column widths of sub-fields within description + QStringList columns = itemlist[row].str.split("\t"); + for (int fld = 0; fld < (int) columns.size(); ++fld) { + bool lastcol = (fld == (int) columns.size() - 1); + int w = fm.width(columns[fld] + (lastcol ? "" : " ")); + if (fld >= (int) col_widths.size()) { + col_widths.push_back(w); // add another element + } else if (col_widths[fld] < w) { + col_widths[fld] = w; + } + } + } + } // split_descr + + // Reformat all counts so that they line up right justified and + // pad each field within description to fill that field's width. + int widest4 = 0; + for (int row = 0; row < (int) itemlist.size(); ++row) { + // column 0 (subset count); format as right-justified number + QTableWidgetItem *cnt = table->item(row, 0); + if (cnt != NULL) { + QString Amt = ""; + long amt = count(row); // fetch item(row,0) as a number + if (amt > 0L) + Amt.sprintf("%*ld", countdigits, amt); + cnt->setText(Amt); + } + + // column 4 (item description) + QTableWidgetItem *twi = table->item(row, 4); + if (twi == NULL) + continue; + QString text = twi->text(); + if (split_descr) { + QStringList columns = text.split("\t"); + for (int fld = 0; fld < (int) columns.size() - 1; ++fld) { + //columns[fld] += "\t"; /* (used to pad with tabs) */ + int width = col_widths[fld]; + while (fm.width(columns[fld]) < width) + columns[fld] += " "; //"\t"; + } + text = columns.join(""); + twi->setText(text); + } + // TODO? if description needs to wrap, increase the height of this row + int wid = fm.width(text) + MENU_WIDTH_SLOP; + if (wid > widest4) + widest4 = wid; + } + if (widest4 > table->columnWidth(4)) + WidenColumn(4, widest4); +} + +// got a bigger count than previously; might need to widen column 0 +// (or possibly had all counts removed and need to shrink column 0) +void NetHackQtMenuWindow::UpdateCountColumn(long newcount) +{ + if (newcount < 0L) { + // this will happen if user clicks on [all],[none],[invert] buttons; + // they clear all pending counts while selecting or unselecting + biggestcount = 0L; + countdigits = 0; + table->setColumnWidth(0, 0); + WidenColumn(0, MENU_WIDTH_SLOP); + } else { + biggestcount = std::max(biggestcount, newcount); + QString num; + num.sprintf("%*ld", std::max(countdigits, 1), biggestcount); + int numlen = (int) num.length(); + if (numlen % 2) + ++numlen; + if (numlen <= countdigits) + return; + countdigits = numlen; + // FIXME: neither adjusting the table size (below) nor the + // menu widget size (also below) is making the menu widget + // bigger after the count column has been expanded + } + + PadMenuColumns(false); + + MenuResize(); + 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::AddRow(int row, const MenuItem& mi) { - static const QColor colors[] = { - QColor(64, 64, 64), - QColor(Qt::red), - QColor(0, 191, 0), - QColor(127, 127, 0), - QColor(Qt::blue), - QColor(Qt::magenta), - QColor(Qt::cyan), - QColor(Qt::gray), - QColor(Qt::white), - QColor(255, 127, 0), - QColor(127, 255, 127), - QColor(Qt::yellow), - QColor(127, 127, 255), - QColor(255, 127, 255), - QColor(127, 255, 255), - QColor(Qt::white) - }; QFontMetrics fm(table->font()); QTableWidgetItem *twi; @@ -349,13 +568,19 @@ void NetHackQtMenuWindow::AddRow(int row, const MenuItem& mi) twi = new QTableWidgetItem(""); table->setItem(row, 0, twi); twi->setFlags(Qt::ItemIsEnabled); - WidenColumn(0, fm.width("999999")); - // Check box, set if selected +#if 0 // active count field now widened as needed rather than preset + WidenColumn(0, fm.width("999999") + MENU_WIDTH_SLOP); +#else + WidenColumn(0, MENU_WIDTH_SLOP); +#endif + + // Check box, set if pre-selected QCheckBox *cb = new QCheckBox(); - cb->setChecked(mi.selected); + cb->setChecked(mi.preselected ? Qt::Checked : Qt::Unchecked); cb->setFocusPolicy(Qt::NoFocus); - if (how == PICK_ONE) - connect(cb, SIGNAL(clicked(bool)), this, SLOT(DoSelection(bool))); + // CheckboxClicked() will call ToggleSelect() for item whose checkbox + // gets clicked upon + connect(cb, SIGNAL(clicked(bool)), this, SLOT(CheckboxClicked(bool))); table->setCellWidget(row, 1, cb); WidenColumn(1, cb->width()); } @@ -367,14 +592,14 @@ void NetHackQtMenuWindow::AddRow(int row, const MenuItem& mi) twi->setFlags(Qt::ItemIsEnabled); WidenColumn(2, pm.width()); } + QString letter, text(mi.str); if (mi.ch != 0) { // Letter specified letter = QString(mi.ch) + " - "; - } - else { + } else { // Letter is left blank, except for skills display when # and * are - // presented + // presented (note: they're just displayed, not become selectors) if (text.startsWith(" ")) { // If mi.str starts with " ", it's meant to line up with lines // that have a letter; we don't want that here @@ -388,48 +613,62 @@ void NetHackQtMenuWindow::AddRow(int row, const MenuItem& mi) twi = new QTableWidgetItem(letter); table->setItem(row, 3, twi); table->item(row, 3)->setFlags(Qt::ItemIsEnabled); - WidenColumn(3, fm.width(letter)); + // add extra padding because the measured width comes out too narrow; + // for the normal case of "a - ", the trailing space hid the fact that + // the column wasn't wide enough for four characters; for the " #" + // and " *" cases, the last character was replaced by very tiny "..." + int w = (int) fm.width(letter); + if (w) + w += MENU_WIDTH_SLOP / 2; + WidenColumn(3, w); + twi = new QTableWidgetItem(text); table->setItem(row, 4, twi); table->item(row, 4)->setFlags(Qt::ItemIsEnabled); WidenColumn(4, fm.width(text)); - if (mi.color != -1) { - twi->setForeground(colors[mi.color]); + if ((int) mi.color != -1) { + twi->setForeground(colors[mi.color].q); } - QFont itemfont(table->font()); - switch (mi.attr) { - case ATR_BOLD: - itemfont.setWeight(QFont::Bold); - twi->setFont(itemfont); - break; - - case ATR_DIM: - twi->setFlags(Qt::NoItemFlags); - break; - - case ATR_ULINE: - itemfont.setUnderline(true); - twi->setFont(itemfont); - break; - - case ATR_INVERSE: - { - QBrush fg = twi->foreground(); - QBrush bg = twi->background(); - if (fg == bg) { - // default foreground and background come up the same for - // some unknown reason - twi->setForeground(Qt::white); - twi->setBackground(Qt::black); - } else { - twi->setForeground(bg); - twi->setBackground(fg); - } - } - break; - } + if (mi.attr != ATR_NONE) { + QFont itemfont(table->font()); + switch (mi.attr) { + case ATR_BOLD: + itemfont.setWeight(QFont::Bold); + twi->setFont(itemfont); + break; + case ATR_DIM: + twi->setFlags(Qt::NoItemFlags); + break; + case ATR_ULINE: + itemfont.setUnderline(true); + twi->setFont(itemfont); + break; + case ATR_INVERSE: { + QBrush fg = twi->foreground(); + QBrush bg = twi->background(); + if (fg.color() == bg.color()) { + // default foreground and background come up the same for + // some unknown reason + //[pr: both are set to 'Qt::color1' which has same RGB + // value as 'Qt::black'; X11 on OSX behaves similarly] + if (fg.color() == Qt::color1) { + fg = Qt::black; + bg = Qt::white; + } else { + fg = (bg.color() == Qt::white) ? Qt::black : Qt::white; + } + } + twi->setForeground(bg); + twi->setBackground(fg); + break; + } + case ATR_BLINK: + // not supported + break; + } /* switch */ + } /* if mi.attr != ATR_NONE */ } void NetHackQtMenuWindow::WidenColumn(int column, int width) @@ -443,19 +682,24 @@ void NetHackQtMenuWindow::WidenColumn(int column, int width) void NetHackQtMenuWindow::InputCount(char key) { - if (key == '\b') - { - if (counting) - { + if (key == '\b' || key == '\177' || how == PICK_NONE) { + if (counting) { if (countstr.isEmpty()) ClearCount(); else countstr = countstr.mid(0, countstr.size() - 1); } - } - else - { + } else { counting = true; + // starting a count (enforced by caller) with '#' is optional; + // if used, show visible '0' + if (key == '#') + key = '0'; + // if we have non-zero digit and are currently showing visible '0', + // replace instead of append; doesn't attempt to handle multiple + // leading zeroes--they won't affect the outcome, just look odd + else if (key > '0' && countstr == "0") + countstr = ""; countstr += QChar(key); } if (counting) @@ -469,155 +713,280 @@ void NetHackQtMenuWindow::ClearCount(void) countstr = ""; } -void NetHackQtMenuWindow::keyPressEvent(QKeyEvent* event) +void NetHackQtMenuWindow::keyPressEvent(QKeyEvent *key_event) { - QString text = event->text(); + uchar key = keyValue(key_event); + if (!key) + return; - const QChar *uni = text.unicode(); - for (unsigned k = 0; uni[k] != 0; k++) { - unsigned key = uni[k].unicode(); - if (key=='\033') { - if (counting) - ClearCount(); - else - reject(); - } else if (key=='\r' || key=='\n' || key==' ') - accept(); - else if (key==MENU_SEARCH) - Search(); - else if (key==MENU_SELECT_ALL || key==MENU_SELECT_PAGE) - All(); - else if (key==MENU_INVERT_ALL || key==MENU_INVERT_PAGE) - Invert(); - else if (key==MENU_UNSELECT_ALL || key==MENU_UNSELECT_PAGE) - ChooseNone(); - else if (('0' <= key && key <= '9') || key == '\b') - InputCount(key); - else { - for (int i=0; iitem(i, 0); - if (count != NULL) count->setText(""); + if (counting) + ClearCount(); // discard any pending count + for (int row = 0; row < itemcount; ++row) { + itemlist[row].selected = itemlist[row].preselected = false; + if (!itemlist[row].Selectable()) + continue; + itemlist[row].selected = true; - QCheckBox *cb = dynamic_cast(table->cellWidget(i, 1)); - if (cb != NULL) cb->setChecked(true); + QTableWidgetItem *count = table->item(row, 0); + if (count != NULL) { + count->setText(""); + } + QCheckBox *cb = dynamic_cast (table->cellWidget(row, 1)); + if (cb != NULL) { + cb->setChecked(Qt::Checked); + } + } + if (biggestcount > 0L) { // had one or more counts + UpdateCountColumn(-1L); // all counts are now gone + } else { + table->repaint(); } } + void NetHackQtMenuWindow::ChooseNone() { - if (how != PICK_ANY) + if (how == PICK_NONE) return; - for (int i=0; iitem(i, 0); - if (count != NULL) count->setText(""); - - QCheckBox *cb = dynamic_cast(table->cellWidget(i, 1)); - if (cb != NULL) cb->setChecked(false); - } -} -void NetHackQtMenuWindow::Invert() -{ - if (how != PICK_ANY) - return; - - for (int i=0; iitem(i, 0); - if (count != NULL) count->setText(""); - - QCheckBox *cb = dynamic_cast(table->cellWidget(i, 1)); - if (cb != NULL) cb->setChecked(cb->checkState() == Qt::Unchecked); + QTableWidgetItem *count = table->item(row, 0); + if (count != NULL) { + count->setText(""); + } + QCheckBox *cb = dynamic_cast (table->cellWidget(row, 1)); + if (cb != NULL) { + cb->setChecked(Qt::Unchecked); + } + } + if (biggestcount > 0L) { // had one or more counts + UpdateCountColumn(-1L); // all counts are now gone + } else { + table->repaint(); } } + +void NetHackQtMenuWindow::Invert() +{ + if (how == PICK_NONE) + return; + + if (counting) + ClearCount(); // discard any pending count + for (int row = 0; row < itemcount; ++row) { + if (!menuitem_invert_test(0, itemlist[row].itemflags, + itemlist[row].preselected)) + continue; + ToggleSelect(row, false); + } + if (biggestcount > 0L) { // had one or more counts + UpdateCountColumn(-1L); // all counts are now gone + } else { + table->repaint(); + } +} + void NetHackQtMenuWindow::Search() { if (how == PICK_NONE) return; + searching = true; NetHackQtStringRequestor requestor(this, "Search for:"); - char line[256]; + char line[BUFSZ]; + line[0] = '\0'; /* for EDIT_GETLIN */ if (requestor.Get(line)) { for (int i=0; i(table->cellWidget(i, 1)); - if (cb == NULL) return; + searching = false; +} - cb->setChecked((counting && !countstr.isEmpty()) - || cb->checkState() == Qt::Unchecked); +void NetHackQtMenuWindow::ToggleSelect(int row, bool already_toggled) +{ + if (itemlist[row].Selectable()) { + QCheckBox *cb = dynamic_cast (table->cellWidget(row, 1)); + if (cb == NULL) + return; - QTableWidgetItem *count = table->item(i, 0); - if (count != NULL) count->setText(countstr); + if (how == PICK_ONE) { + // explicitly picking a preselected item in a pick-one menu + // chooses that item rather than toggling preselection off; + // by clearing whole menu, the code below will select item #row + ChooseNone(); + already_toggled = false; + // FIXME? this won't handle a pending count properly; + // are there any pick-one menus with preselected choice + // where a count is useful? + } else { + itemlist[row].preselected = false; // flag is now out-of-date + } - ClearCount(); + QTableWidgetItem *countfield = table->item(row, 0); + if (!counting) { + if (!already_toggled) + cb->setChecked((cb->checkState() == Qt::Unchecked) // toggle + ? Qt::Checked : Qt::Unchecked); + itemlist[row].selected = (cb->checkState() != Qt::Unchecked); + if (countfield != NULL) + countfield->setText(""); + } else { + long amt = 1L; + if (countfield != NULL) { + countfield->setText(countstr); // store in item(row,0) + amt = count(row); // fetch item(row,0) as a number + QString Amt = ""; + if (amt > 0L) + Amt.sprintf("%*ld", countdigits, amt); + countfield->setText(Amt); // store right-justified value + } + ClearCount(); // blank out 'countstr' and reset 'counting' - if (how==PICK_ONE) { - accept(); - } + // TODO: use a custom icon for check mark, like tty's '#' vs '+' + // [maybe not necessary since unlike tty menus, count is visible] + + // uncheck if count is explicitly 0, otherwise check + cb->setChecked((amt > 0L) ? Qt::Checked : Qt::Unchecked); + itemlist[row].selected = (cb->checkState() != Qt::Unchecked); + + // if this count is larger than the biggest we've seen + // so far, it might need more digits to render; if so, + // all pending counts should be reformatted with new width + if (amt > biggestcount) + UpdateCountColumn(amt); + } + + if (how == PICK_ONE && isSelected(row)) + accept(); + else + table->repaint(); } } -void NetHackQtMenuWindow::cellToggleSelect(int i, int j) +// table cell click handler for cells (*,col) where col != 1 +void NetHackQtMenuWindow::TableCellClicked(int row, int col UNUSED) { - ToggleSelect(i); + ToggleSelect(row, false); } -void NetHackQtMenuWindow::DoSelection(bool) +// checkbox click handler for table cells (*,1); +// presence of a checkbox in the clicked cell prevents the table cell click +// handler above from being called even if this handler doesn't get set up +void NetHackQtMenuWindow::CheckboxClicked(bool on_off UNUSED) { - if (how == PICK_ONE) { - accept(); + // find which checkbox just got toggled by looking for one whose + // check state doesn't match corresponding itemlist[].selected flag + // [there's got to be a more direct way of achieving this...] + for (int row = 0; row < itemcount; ++row) { + // for pick-one menu, ToggleSelect() will return to menu's caller + if (itemlist[row].Selectable()) { + if (!isSelected(row) ^ !itemlist[row].selected) { + // signal dispatcher has already checked or unchecked this box + ToggleSelect(row, true); + return; + } + } } + // didn't find any changed checkbox; should never happen; what to do? } bool NetHackQtMenuWindow::isSelected(int row) { - QCheckBox *cb = dynamic_cast(table->cellWidget(row, 1)); - return cb != NULL && cb->checkState() != Qt::Unchecked; + QCheckBox *cb = dynamic_cast (table->cellWidget(row, 1)); + return cb ? (cb->checkState() != Qt::Unchecked) : false; } -int NetHackQtMenuWindow::count(int row) +// convert text count to numeric for final result +long NetHackQtMenuWindow::count(int row) { QTableWidgetItem *count = table->item(row, 0); - if (count == NULL) return -1; + if (count == NULL) + return -1L; QString cstr = count->text(); - return cstr.isEmpty() ? -1 : cstr.toInt(); + return cstr.isEmpty() ? -1L : cstr.toLong(); } +// initialize a text window NetHackQtTextWindow::NetHackQtTextWindow(QWidget *parent) : QDialog(parent), use_rip(false), str_fixed(false), - ok("Dismiss",this), - search("Search",this), + textsearching(false), + ok("&Dismiss", this), + search("&Search", this), lines(new NetHackQtTextListBox(this)), + target(""), rip(this) { + // + // TODO? + // Searching would be far more convenient if the window contained + // the search string requestor widget instead of just a [Search] + // button to request a popup for that. + // Also, searching should probably be disabled if the entire text + // fits within the window so there's nothing to scroll through. + // + ok.setDefault(true); - connect(&ok,SIGNAL(clicked()),this,SLOT(accept())); - connect(&search,SIGNAL(clicked()),this,SLOT(Search())); - connect(qt_settings,SIGNAL(fontChanged()),this,SLOT(doUpdate())); + connect(&ok,SIGNAL(clicked()), this, SLOT(doDismiss())); + connect(&search, SIGNAL(clicked()), this, SLOT(Search())); + connect(qt_settings, SIGNAL(fontChanged()), this, SLOT(doUpdate())); QVBoxLayout* vb = new QVBoxLayout(this); vb->addWidget(&rip); @@ -626,6 +995,12 @@ NetHackQtTextWindow::NetHackQtTextWindow(QWidget *parent) : hb->addWidget(&ok); hb->addWidget(&search); vb->addWidget(lines); + + // we don't want keystrokes being sent to the main window for use as + // commands while this text window is popped up + setFocusPolicy(Qt::StrongFocus); + // needed so that keystrokes get sent to our keyPressEvent() + lines->setFocusPolicy(Qt::NoFocus); } void NetHackQtTextWindow::doUpdate() @@ -636,7 +1011,6 @@ void NetHackQtTextWindow::doUpdate() NetHackQtTextWindow::~NetHackQtTextWindow() { - } QWidget* NetHackQtTextWindow::Widget() @@ -646,19 +1020,28 @@ QWidget* NetHackQtTextWindow::Widget() bool NetHackQtTextWindow::Destroy() { - return !isVisible(); + return true; /*!isVisible();*/ +} + +void NetHackQtTextWindow::doDismiss() +{ + // [Clear() was needed when the search target string was kept in + // a static buffer but is superfluous now that that's part of + // the TextWindow class and initialized in the constructor.] + Clear(); + accept(); } void NetHackQtTextWindow::UseRIP(int how, time_t when) { // Code from X11 windowport #define STONE_LINE_LEN 16 /* # chars that fit on one line */ -#define NAME_LINE 0 /* line # for player name */ -#define GOLD_LINE 1 /* line # for amount of gold */ +#define NAME_LINE 0 /* line # for player name */ +#define GOLD_LINE 1 /* line # for amount of gold */ #define DEATH_LINE 2 /* line # for death description */ -#define YEAR_LINE 6 /* line # for year */ +#define YEAR_LINE 6 /* line # for year */ -static char** rip_line=0; + static char **rip_line = 0; if (!rip_line) { rip_line=new char*[YEAR_LINE+1]; for (int i=0; i 999999999L) + cash = 999999999L; + (void) snprintf(rip_line[GOLD_LINE], STONE_LINE_LEN + 1, "%ld Au", cash); /* Put together death description */ formatkiller(buf, sizeof buf, how, FALSE); //str_copy(buf, killer, SIZE(buf)); /* Put death type on stone */ - for (line=DEATH_LINE, dpx = buf; line STONE_LINE_LEN) { - for(i = STONE_LINE_LEN; - ((i0 > STONE_LINE_LEN) && i); i--) - if(dpx[i] == ' ') i0 = i; - if(!i) i0 = STONE_LINE_LEN; + if (i0 > STONE_LINE_LEN) { + for (i = STONE_LINE_LEN; (i > 0) && (i0 > STONE_LINE_LEN); --i) + if (dpx[i] == ' ') + i0 = i; + if (!i) + i0 = STONE_LINE_LEN; } tmpchar = dpx[i0]; dpx[i0] = 0; - str_copy(rip_line[line], dpx, STONE_LINE_LEN+1); + (void) str_copy(rip_line[line], dpx, STONE_LINE_LEN + 1); if (tmpchar != ' ') { dpx[i0] = tmpchar; dpx= &dpx[i0]; - } else dpx= &dpx[i0+1]; + } else { + dpx= &dpx[i0 + 1]; + } } - /* Put year on stone */ - snprintf(rip_line[YEAR_LINE], STONE_LINE_LEN+1, "%4d", getyear()); + /* Put year on stone; + 64 bit configuration with 64 bit int is capable of overflowing + STONE_LINE_LEN characters; a compiler might warn about that, + so force a value that it can recognize as fitting within buffer's + range ("%4d" imposes a minimum number of digits, not a maximum) */ + int year = (int) ((yyyymmdd(when) / 10000L) % 10000L); /* Y10K bug! */ + (void) snprintf(rip_line[YEAR_LINE], STONE_LINE_LEN + 1, "%4d", year); - rip.setLines(rip_line,YEAR_LINE+1); - - use_rip=true; + rip.setLines(rip_line, YEAR_LINE + 1); + use_rip = true; } void NetHackQtTextWindow::Clear() { lines->clear(); - use_rip=false; - str_fixed=false; + target[0] = '\0'; // discard search target string + use_rip = false; + str_fixed = false; + textsearching = false; } -void NetHackQtTextWindow::Display(bool block) +void NetHackQtTextWindow::Display(bool block UNUSED) { + // make sure window isn't completely empty + if (!lines->count()) + PutStr(ATR_NONE, ""); + if (str_fixed) { lines->setFont(qt_settings->normalFixedFont()); } else { @@ -747,31 +1158,87 @@ void NetHackQtTextWindow::Display(bool block) centerOnMain(this); show(); } + + lines->clearSelection(); // affects [Search] + exec(); + textsearching = false; } -void NetHackQtTextWindow::PutStr(int attr, const QString& text) +void NetHackQtTextWindow::PutStr(int attr UNUSED, const QString& text) { str_fixed=str_fixed || text.contains(" "); lines->addItem(text); } +// prompt for a target string and search current text window for it; +// if found, highlight the next line target occurs on; +// multiple searches with same or different search string are supported void NetHackQtTextWindow::Search() { - NetHackQtStringRequestor requestor(this, "Search for:"); - static char line[256]=""; - requestor.SetDefault(line); - if (requestor.Get(line)) { - int current=lines->currentRow(); - for (int i=1; icount(); i++) { - int lnum=(i+current)%lines->count(); - QString str=lines->item(lnum)->text(); - if (str.contains(line)) { - lines->setCurrentRow(lnum); - return; - } - } - lines->setCurrentItem(NULL); + textsearching = true; + NetHackQtStringRequestor requestor(this, "Search for:", "Done", "Find"); + requestor.SetDefault(target); + boolean get_a_line = requestor.Get(target, (int) sizeof target); + + // FIXME: + // Force text window to be on top. Without this, it moves behind + // the map after the string requestor completes. Then it can't + // be seen or accessed (unless the game window is minimized or + // dragged out of the way). Unfortunately the window noticeably + // vanishes and then immediately gets redrawn. + if (!this->isActiveWindow()) { + this->activateWindow(); + this->raise(); + } + + if (get_a_line) { + int linecount = lines->count(); + int current = lines->currentRow(); + if (current == -1) + current = 0; + // when no row is highlighted (selected), start the search + // on the current row, otherwise start on the row after it + // [normally means that the very first row is a candidate + // for containing the target during the very first search] + int startln = lines->selectedItems().count(); + for (int i = startln; i < linecount; ++i) { + int lnum = (i + current) % linecount; + const QString &str = lines->item(lnum)->text(); + // Check whether target occurs on this line. If it does, + // the line is highlighted and this search finishes. + // When not currently within view, highlighting also + // scrolls the view to make it become the bottom line. + // A subsequent search will remember the target string + // and start searching on the line past the highlighted + // one (even if a new target is specified). + if (str.contains(target, Qt::CaseInsensitive)) { + lines->setCurrentRow(lnum); + return; + } + } + lines->setCurrentItem(NULL); + } else { + target[0] = '\0'; + } + textsearching = false; + return; +} + +void NetHackQtTextWindow::keyPressEvent(QKeyEvent *key_event) +{ + uchar key = keyValue(key_event); + + if (key == MENU_SEARCH) { + if (!use_rip) + Search(); + } else if (key == '\n' || key == '\r') { + if (!textsearching) + accept(); + } else if (key == '\033') { + reject(); + } else { + QDialog::keyPressEvent(key_event); } } @@ -811,13 +1278,14 @@ void NetHackQtMenuOrTextWindow::PutStr(int attr, const QString& text) } // Menu -void NetHackQtMenuOrTextWindow::StartMenu() +void NetHackQtMenuOrTextWindow::StartMenu(bool using_WIN_INVEN) { if (!actual) actual=new NetHackQtMenuWindow(parent); - actual->StartMenu(); + actual->StartMenu(using_WIN_INVEN); } -void NetHackQtMenuOrTextWindow::AddMenu(int glyph, const ANY_P* identifier, char ch, char gch, int attr, - const QString& str, unsigned itemflags) +void NetHackQtMenuOrTextWindow::AddMenu(int glyph, const ANY_P* identifier, + char ch, char gch, int attr, + const QString& str, unsigned itemflags) { if (!actual) impossible("AddMenu called before we know if Menu or Text"); actual->AddMenu(glyph,identifier,ch,gch,attr,str,itemflags); diff --git a/win/Qt/qt_menu.h b/win/Qt/qt_menu.h index 7aa5c2b8d..18be9e732 100644 --- a/win/Qt/qt_menu.h +++ b/win/Qt/qt_menu.h @@ -10,8 +10,13 @@ #include "qt_win.h" #include "qt_rip.h" +// some menu fields aren't wide enough even though sized for measured text +#define MENU_WIDTH_SLOP 10 /* this should not be necessary */ + namespace nethack_qt_ { +extern uchar keyValue(QKeyEvent *key_event); // also used in qt_xcmd.cpp + class NetHackQtTextListBox : public QListWidget { public: NetHackQtTextListBox(QWidget* parent = NULL) : QListWidget(parent) { } @@ -53,21 +58,24 @@ public: virtual QWidget* Widget(); - virtual void StartMenu(); - virtual void AddMenu(int glyph, const ANY_P* identifier, char ch, char gch, int attr, - const QString& str, unsigned itemflags); + virtual void StartMenu(bool using_WIN_INVEN = false); + virtual void AddMenu(int glyph, const ANY_P *identifier, + char ch, char gch, int attr, + const QString& str, unsigned itemflags); virtual void EndMenu(const QString& prompt); virtual int SelectMenu(int how, MENU_ITEM_P **menu_list); + bool is_invent; // using core's WIN_INVEN + public slots: void All(); void ChooseNone(); void Invert(); void Search(); - void ToggleSelect(int); - void cellToggleSelect(int, int); - void DoSelection(bool); + void ToggleSelect(int row, bool alyready_checked); + void TableCellClicked(int row, int col); + void CheckboxClicked(bool on_off); protected: virtual void keyPressEvent(QKeyEvent*); @@ -81,10 +89,11 @@ private: ANY_P identifier; int attr; QString str; - int count; + long count; char ch; char gch; - bool selected; + bool selected; // True if checkbox is set + bool preselected; // True if caller told us to set checkbox unsigned itemflags; unsigned color; @@ -108,19 +117,26 @@ private: // Count replaces prompt while it is being input QString promptstr; QString countstr; - bool counting; + long biggestcount; // determines width of field #0 + int countdigits; // number of digits to format biggestcount + bool counting; // in midst of entering a count + bool searching; // in midst of entering a search string void InputCount(char key); void ClearCount(void); - int how; - - bool has_glyphs; + int how; // pick-none, pick-one, pick-any + bool has_glyphs; // at least one item specified a glyph bool isSelected(int row); - int count(int row); + long count(int row); void AddRow(int row, const MenuItem& mi); void WidenColumn(int column, int width); + void PadMenuColumns(bool split_descr); + void MenuResize(); + void UpdateCountColumn(long newcount); + + void ClearSearch(); }; class NetHackQtTextWindow : public QDialog, public NetHackQtWindow { @@ -141,15 +157,21 @@ public slots: void Search(); private slots: + void doDismiss(); void doUpdate(); +protected: + virtual void keyPressEvent(QKeyEvent *); + private: bool use_rip; bool str_fixed; + bool textsearching; QPushButton ok; QPushButton search; NetHackQtTextListBox* lines; + char target[BUFSZ]; NetHackQtRIP rip; }; @@ -157,7 +179,7 @@ private: class NetHackQtMenuOrTextWindow : public NetHackQtWindow { private: NetHackQtWindow* actual; - QWidget *parent; + QWidget *parent; public: NetHackQtMenuOrTextWindow(QWidget *parent = NULL); @@ -171,9 +193,10 @@ public: virtual void PutStr(int attr, const QString& text); // Menu - virtual void StartMenu(); - virtual void AddMenu(int glyph, const ANY_P* identifier, char ch, char gch, int attr, - const QString& str, unsigned itemflags); + virtual void StartMenu(bool using_WIN_INVENT = false); + virtual void AddMenu(int glyph, const ANY_P *identifier, + char ch, char gch, int attr, + const QString& str, unsigned itemflags); virtual void EndMenu(const QString& prompt); virtual int SelectMenu(int how, MENU_ITEM_P **menu_list); diff --git a/win/Qt/qt_msg.cpp b/win/Qt/qt_msg.cpp index 516e992df..66fd93dae 100644 --- a/win/Qt/qt_msg.cpp +++ b/win/Qt/qt_msg.cpp @@ -7,20 +7,13 @@ extern "C" { #include "hack.h" } -#undef Invisible -#undef Warning -#undef index -#undef msleep -#undef rindex -#undef wizard -#undef yn -#undef min -#undef max +#include "qt_pre.h" #include #if QT_VERSION >= 0x050000 #include #endif +#include "qt_post.h" #include "qt_msg.h" #include "qt_msg.moc" #include "qt_map.h" @@ -30,9 +23,12 @@ extern "C" { namespace nethack_qt_ { NetHackQtMessageWindow::NetHackQtMessageWindow() : - list(new QListWidget()) + list(new QListWidget()), + scrollarea(new QScrollArea()) { list->setFocusPolicy(Qt::NoFocus); + scrollarea->setFocusPolicy(Qt::NoFocus); + scrollarea->takeWidget(); ::iflags.window_inited = 1; map = 0; currgetmsg = 0; @@ -46,7 +42,9 @@ NetHackQtMessageWindow::~NetHackQtMessageWindow() delete list; } -QWidget* NetHackQtMessageWindow::Widget() { return list; } +QWidget* NetHackQtMessageWindow::Widget() { + return list; +} void NetHackQtMessageWindow::setMap(NetHackQtMapWindow2* m) { @@ -61,7 +59,7 @@ void NetHackQtMessageWindow::updateFont() map->setFont(qt_settings->normalFont()); } -void NetHackQtMessageWindow::Scroll(int dx, int dy) +void NetHackQtMessageWindow::Scroll(int dx UNUSED, int dy UNUSED) { //RLC Is this necessary? //RLC list->Scroll(dx,dy); @@ -69,7 +67,10 @@ void NetHackQtMessageWindow::Scroll(int dx, int dy) void NetHackQtMessageWindow::Clear() { - if ( map ) + if (list) + NetHackQtMessageWindow::unhighlight_mesgs(); + + if (map) map->clearMessages(); } @@ -85,6 +86,10 @@ void NetHackQtMessageWindow::Display(bool block) list->repaint(); changed=false; } + if (block) { + // we don't care what the response is here + (void) NetHackQtBind::qt_more(); + } } const char * NetHackQtMessageWindow::GetStr(bool init) @@ -95,8 +100,9 @@ const char * NetHackQtMessageWindow::GetStr(bool init) QListWidgetItem *item = list->item(currgetmsg++); if (item) { QString str = item->text(); - //raw_printf("getstr[%i]='%s'", currgetmsg, str.toLatin1().constData()); - return str.toLatin1().constData(); + const char *result = str.toLatin1().constData(); + //raw_printf("getstr[%d]='%s'", currgetmsg, result); + return result; } return NULL; } @@ -113,39 +119,111 @@ void NetHackQtMessageWindow::PutStr(int attr, const QString& text) } else { text2 = text; } + #if 0 - QListWidgetItem *item = new QListWidgetItem(text2); - - QFont font = item->font(); - font.setUnderline(attr == ATR_ULINE); - font.setWeight((attr == ATR_BOLD) ? QFont::Bold : QFont::Normal); - item->setFont(font); - - QColor fg = item->foreground().color(); - QColor bg = item->background().color(); - if (attr == ATR_DIM) - { - fg.setAlpha(fg.alpha() / 2); + if (attr != ATR_NONE) { + QListWidgetItem *item = new QListWidgetItem(text2); + if (attr != ATR_DIM && attr != ATR_INVERSE) { + QFont font = item->font(); + font.setUnderline(attr == ATR_ULINE); + font.setWeight((attr == ATR_BOLD) ? QFont::Bold : QFont::Normal); + item->setFont(font); + // ATR_BLINK not supported + } else { + // ATR_DIM or ATR_INVERSE + QBrush fg = item->foreground(); + QBrush bg = item->background(); + if (fg.color() == bg.color()) { // from menu coloring [AddRow()] + // default foreground and background come up the same for + // some unknown reason + //[pr: both are set to 'Qt::color1' which has same RGB + // value as 'Qt::black'; X11 on OSX behaves similarly] + if (fg.color() == Qt::color1) { + fg = Qt::black; + bg = Qt::white; + } else { + fg = (bg.color() == Qt::white) ? Qt::black : Qt::white; + } + } + if (attr == ATR_DIM) { + QColor fg_clr = fg.color(); + fg_clr.setAlpha(fg_clr.alpha() / 2); + item->setFlags(Qt::NoItemFlags); + } else if (attr == ATR_INVERSE) { + QBrush swapfb; + swapfb = fg; fg = bg; bg = swapfb; + } + item->setForeground(fg); + item->setBackground(bg); + } } - if (attr == ATR_INVERSE) - { - QColor swap; - swap = fg; fg = bg; bg = swap; - } - item->setForeground(fg); - item->setBackground(bg); +#else + nhUse(attr); #endif - // ATR_BLINK not supported - if (list->count() >= ::iflags.msg_history) + if (list->count() >= (int) ::iflags.msg_history) delete list->item(0); list->addItem(text2); + /* assert( list->count() > 0 ); */ - // Force scrollbar to bottom - list->setCurrentRow(list->count()-1); + // force scrollbar to bottom; + // selects most recent message, which causes it to be highlighted + list->setCurrentRow(list->count() - 1); - if ( map ) + // if message window has been scrolled right, force back to left edge + QScrollBar *sb = list->horizontalScrollBar(); + if (sb && sb->value() > 0) { + sb->setValue(0); + this->viewport()->update(); + } + + if (map) map->putMessage(attr, text2); } +// append to the last message; usually the user's answer to a prompt +void NetHackQtMessageWindow::AddToStr(const char *answer) +{ + if (list) { + QListWidgetItem *item = list->currentItem(); + int ct = 0; + if (!item && (ct = list->count()) > 0) { + list->setCurrentRow(ct - 1); + item = list->currentItem(); + } + if (item) + item->setText(item->text() + QString(" %1").arg(answer)); + else // just in case... + NetHackQtMessageWindow::PutStr(ATR_NONE, answer); + } +} + +// used when yn_function() or more() rejects player's input and tries again +void NetHackQtMessageWindow::RehighlightPrompt() +{ + // selects most recent message, which causes it to be highlighted + if (list && list->count()) + list->setCurrentRow(list->count() - 1); +} + +// are there any highlighted messages? +bool NetHackQtMessageWindow::hilit_mesgs() +{ + // PutStr() uses setCurrentRow() to select the last message line; + // being selected causes that line to be highlighted. + // + // We could/should keep track of whether anything is currently + // highlighted instead of just assuming that last message still is. + if (list && list->count()) + return true; + return false; +} + +// unhighlight any highlighted messages +void NetHackQtMessageWindow::unhighlight_mesgs() +{ + if (list) + list->clearSelection(); +} + } // namespace nethack_qt_ diff --git a/win/Qt/qt_msg.h b/win/Qt/qt_msg.h index 08c029b9b..b3274bc13 100644 --- a/win/Qt/qt_msg.h +++ b/win/Qt/qt_msg.h @@ -13,7 +13,7 @@ namespace nethack_qt_ { class NetHackQtMapWindow2; -class NetHackQtMessageWindow : QObject, public NetHackQtWindow { +class NetHackQtMessageWindow : QScrollArea, public NetHackQtWindow { Q_OBJECT public: NetHackQtMessageWindow(); @@ -30,9 +30,16 @@ public: void setMap(NetHackQtMapWindow2*); + void RehighlightPrompt(); + bool hilit_mesgs(); + void unhighlight_mesgs(); + // for adding the answer for yn() to its prompt string + void AddToStr(const char *answerbuf); + private: - QListWidget* list; - bool changed; + QListWidget *list; + QScrollArea *scrollarea; + bool changed; int currgetmsg; NetHackQtMapWindow2* map; diff --git a/win/Qt/qt_plsel.cpp b/win/Qt/qt_plsel.cpp index c77203bec..e20735b56 100644 --- a/win/Qt/qt_plsel.cpp +++ b/win/Qt/qt_plsel.cpp @@ -4,23 +4,27 @@ // qt_plsel.cpp -- player selector dialog +// +// TODO: +// increase height so that no scrolling is needed for role list [needs +// to be done properly instead of forcing logo string to be taller] +// the [Random] button doesn't do anything; +// make race first vs role first dynamically selectable (tty allows +// gender first and alignment first too); +// maybe add a set of radio buttons for normal mode vs explore mode +// [vs wizard mode if eligible] +// + extern "C" { #include "hack.h" } -#undef Invisible -#undef Warning -#undef index -#undef msleep -#undef rindex -#undef wizard -#undef yn -#undef min -#undef max +#include "qt_pre.h" #include #if QT_VERSION >= 0x050000 #include #endif +#include "qt_post.h" #include "qt_plsel.h" #include "qt_plsel.moc" #include "qt_bind.h" @@ -31,30 +35,61 @@ extern "C" { // Warwick prefers it this way... #define QT_CHOOSE_RACE_FIRST +/* check whether plname[] is among the list of generic user names */ +static bool generic_plname() +{ + if (*g.plname) { + const char *sptr, *p; + const char *genericusers = sysopt.genericusers; + int ln = (int) strlen(g.plname); + + if (!genericusers || !*genericusers) + genericusers = "player games"; + else if (!strcmp(genericusers, "*")) /* "*" => always ask for name */ + return true; + + while ((sptr = strstri(genericusers, g.plname)) != NULL) { + /* check for full word: start of list or following a space */ + if ((sptr == genericusers || sptr[-1] == ' ') + /* and also preceding a space or at end of list */ + && (sptr[ln] == ' ' || sptr[ln] == '\0')) + return true; + /* doesn't match full word, but maybe we got a false hit when + looking for "play" in list "player play" so keep going */ + if ((p = strchr(sptr + 1, ' ')) == NULL) + break; + genericusers = p + 1; + } + } + return false; +} + namespace nethack_qt_ { // temporary void centerOnMain( QWidget* w ); // end temporary -static const char nh_attribution[] = "
NetHack %1" - "
by the NetHack DevTeam
"; +// hack: padded with blank lines by inserting breaks above and below in +// order to force window to be tall enough to show all the roles at once +static const char nh_attribution[] = "
NetHack %1" + "
by the NetHack DevTeam

"; class NhPSListViewItem : public QTableWidgetItem { public: - NhPSListViewItem( QTableWidget* parent, const QString& name ) : + NhPSListViewItem( QTableWidget* parent UNUSED, const QString& name ) : QTableWidgetItem(name) { } - void setGlyph(int g) + void setGlyph(int g, bool fem) { NetHackQtGlyphs& glyphs = qt_settings->glyphs(); int gw = glyphs.width(); int gh = glyphs.height(); QPixmap pm(gw,gh); QPainter p(&pm); - glyphs.drawGlyph(p, g, 0, 0); + glyphs.drawGlyph(p, g, 0, 0, fem); p.end(); setIcon(QIcon(pm)); //RLC setHeight(std::max(pm.height()+1,height())); @@ -89,7 +124,7 @@ public: #endif ) { - setGlyph(monnum_to_glyph(roles[id].malenum)); + setGlyph(monnum_to_glyph(roles[id].malenum), false); } }; @@ -104,7 +139,7 @@ public: #endif ) { - setGlyph(monnum_to_glyph(races[id].malenum)); + setGlyph(monnum_to_glyph(races[id].malenum), false); } }; @@ -138,16 +173,21 @@ public: } }; -NetHackQtPlayerSelector::NetHackQtPlayerSelector(NetHackQtKeyBuffer& ks) : +NetHackQtPlayerSelector::NetHackQtPlayerSelector(NetHackQtKeyBuffer& ks UNUSED) : QDialog(NetHackQtBind::mainWidget()), - fully_specified_role(true) + fully_specified_role(true), + chosen_gend(ROLE_NONE), + chosen_align(ROLE_NONE), + rand_btn(new QPushButton("Random")), + play_btn(new QPushButton("Play")), + quit_btn(new QPushButton("Quit")) { /* 0 1 2 + Name ------------------------------------+ 0 | | + ---- ------------------------------------+ - + Role ---+ + Race ---+ + Gender ------+ + + Race ---+ + Role ---+ + Gender ------+ | | | | | * Male | 1 | | | | | * Female | | | | | +--------------+ @@ -172,30 +212,37 @@ NetHackQtPlayerSelector::NetHackQtPlayerSelector(NetHackQtKeyBuffer& ks) : QVBoxLayout *namelayout = new QVBoxLayout(namebox); QLineEdit* name = new QLineEdit(namebox); namelayout->addWidget(name); - name->setMaxLength(sizeof(g.plname)-1); - if ( strncmp(g.plname,"player",6) && strncmp(g.plname,"games",5) ) - name->setText(g.plname); + name->setMaxLength(PL_NSIZ - 1); + name->setPlaceholderText(QString(" (required)")); // grayed out + + // if plname[] contains a generic user name, clear it + if (generic_plname()) + *g.plname = '\0'; + name->setText(g.plname); connect(name, SIGNAL(textChanged(const QString&)), - this, SLOT(selectName(const QString&)) ); + this, SLOT(selectName(const QString&))); name->setFocus(); - QGroupBox* genderbox = new QGroupBox("Gender",this); + + // changed to move gender and alignment labels inside their boxes (below) + QGroupBox *genderbox = new QGroupBox(); QButtonGroup *gendergroup = new QButtonGroup(this); - QGroupBox* alignbox = new QGroupBox("Alignment",this); + QGroupBox *alignbox = new QGroupBox(); QButtonGroup *aligngroup = new QButtonGroup(this); - QVBoxLayout* vbgb = new QVBoxLayout(genderbox); - QVBoxLayout* vbab = new QVBoxLayout(alignbox); + // these two QVBoxLayout pointers aren't used, the vertical box layouts + // being assigned to them are... + QVBoxLayout* vbgb UNUSED = new QVBoxLayout(genderbox); + QVBoxLayout* vbab UNUSED = new QVBoxLayout(alignbox); char versionbuf[QBUFSZ]; - QLabel* logo = new QLabel(QString(nh_attribution).arg(version_string(versionbuf)), this); + QLabel *logo = new QLabel(QString(nh_attribution).arg( + version_string(versionbuf)), this); l->addWidget( namebox, 0,0,1,3 ); -#ifdef QT_CHOOSE_RACE_FIRST - race = new NhPSListView(this); role = new NhPSListView(this); + race = new NhPSListView(this); +#ifdef QT_CHOOSE_RACE_FIRST l->addWidget( race, 1,0,6,1 ); l->addWidget( role, 1,1,6,1 ); #else - role = new NhPSListView(this); - race = new NhPSListView(this); l->addWidget( role, 1,0,6,1 ); l->addWidget( race, 1,1,6,1 ); #endif @@ -210,6 +257,7 @@ NetHackQtPlayerSelector::NetHackQtPlayerSelector(NetHackQtKeyBuffer& ks) : chosen_gend = flags.initgend; chosen_align = flags.initalign; + bool fem = (chosen_gend > ROLE_NONE); // XXX QListView unsorted goes in rev. for (nrole=0; roles[nrole].name.m; nrole++) @@ -217,12 +265,13 @@ NetHackQtPlayerSelector::NetHackQtPlayerSelector(NetHackQtKeyBuffer& ks) : role->setRowCount(nrole); for (i=0; roles[i].name.m; i++) { QTableWidgetItem *item = new QTableWidgetItem( - QIcon(qt_settings->glyphs().glyph(roles[i].malenum)), - roles[i].name.m); + QIcon(qt_settings->glyphs().glyph(roles[i].malenum, fem)), + roles[i].name.m); item->setFlags(Qt::ItemIsEnabled|Qt::ItemIsSelectable); role->setItem(i, 0, item); } - connect( role, SIGNAL(currentCellChanged(int, int, int, int)), this, SLOT(selectRole(int, int, int, int)) ); + connect(role, SIGNAL(currentCellChanged(int, int, int, int)), + this, SLOT(selectRole(int, int, int, int))); role->setHorizontalHeaderLabels(QStringList("Role")); role->resizeColumnToContents(0); @@ -232,44 +281,55 @@ NetHackQtPlayerSelector::NetHackQtPlayerSelector(NetHackQtKeyBuffer& ks) : race->setRowCount(nrace); for (i=0; races[i].noun; i++) { QTableWidgetItem *item = new QTableWidgetItem( - QIcon(qt_settings->glyphs().glyph(races[i].malenum)), + QIcon(qt_settings->glyphs().glyph(races[i].malenum, fem)), races[i].noun); item->setFlags(Qt::ItemIsEnabled|Qt::ItemIsSelectable); race->setItem(i, 0, item); } - connect( race, SIGNAL(currentCellChanged(int, int, int, int)), this, SLOT(selectRace(int, int, int, int)) ); + connect(race, SIGNAL(currentCellChanged(int, int, int, int)), + this, SLOT(selectRace(int, int, int, int))); race->setHorizontalHeaderLabels(QStringList("Race")); race->resizeColumnToContents(0); + // TODO: + // Render the alignment and gender labels smaller to match the + // horizontal header labels for role and race; getting the font from + // race table above and setting it for labels below made no difference. + // + // Maybe, if the order of choosing becomes more dynamic: + // Replace the role and race glyphs when gender gets set. + + QLabel *gendlabel = new QLabel("Gender"); + genderbox->layout()->addWidget(gendlabel); gender = new QRadioButton*[ROLE_GENDERS]; for (i=0; ilayout()->addWidget(gender[i]); gendergroup->addButton(gender[i], i); } - connect( gendergroup, SIGNAL(buttonPressed(int)), this, SLOT(selectGender(int)) ); + connect(gendergroup, SIGNAL(buttonPressed(int)), + this, SLOT(selectGender(int))); + QLabel *alignlabel = new QLabel("Alignment"); + alignbox->layout()->addWidget(alignlabel); alignment = new QRadioButton*[ROLE_ALIGNS]; for (i=0; ilayout()->addWidget(alignment[i]); aligngroup->addButton(alignment[i], i); } - connect( aligngroup, SIGNAL(buttonPressed(int)), this, SLOT(selectAlignment(int)) ); + connect(aligngroup, SIGNAL(buttonPressed(int)), + this, SLOT(selectAlignment(int))); - QPushButton* rnd = new QPushButton("Random",this); - l->addWidget( rnd, 4, 2 ); - rnd->setDefault(false); - connect( rnd, SIGNAL(clicked()), this, SLOT(Randomize()) ); - - QPushButton* ok = new QPushButton("Play",this); - l->addWidget( ok, 5, 2 ); - ok->setDefault(true); - connect( ok, SIGNAL(clicked()), this, SLOT(accept()) ); - - QPushButton* cancel = new QPushButton("Quit",this); - l->addWidget( cancel, 6, 2 ); - connect( cancel, SIGNAL(clicked()), this, SLOT(reject()) ); + l->addWidget(rand_btn, 4, 2); + connect(rand_btn, SIGNAL(clicked()), this, SLOT(Randomize())); + l->addWidget(play_btn, 5, 2); + connect(play_btn, SIGNAL(clicked()), this, SLOT(accept())); + l->addWidget(quit_btn, 6, 2); + connect(quit_btn, SIGNAL(clicked()), this, SLOT(reject())); + // if plname[] is non-empty, the Play button is enabled and the default; + // otherwise, Play is disabled and Quit is the default + plnamePlayVsQuit(); Randomize(); } @@ -314,7 +374,7 @@ void NetHackQtPlayerSelector::Randomize() } // make sure we have a valid combination, honoring - // the users request if possible. + // the user's request if possible. bool choose_race_first; #ifdef QT_CHOOSE_RACE_FIRST choose_race_first = true; @@ -368,12 +428,35 @@ void NetHackQtPlayerSelector::Randomize() race->setCurrentCell(ra, 0); } -void NetHackQtPlayerSelector::selectName(const QString& n) +// if plname[] is empty, disable [Play], otherwise [Play] is the default +void NetHackQtPlayerSelector::plnamePlayVsQuit() { - str_copy(g.plname,n.toLatin1().constData(),SIZE(g.plname)); + if (*g.plname) { + play_btn->setEnabled(true); + play_btn->setDefault(true); + //quit_btn->setDefault(false); + } else { + play_btn->setEnabled(false); // [Play] still visible but grayed out + //play_btn->setDefault(false); + quit_btn->setDefault(true); + } } -void NetHackQtPlayerSelector::selectRole(int crow, int ccol, int prow, int pcol) +// the line edit widget for the name field has received input +void NetHackQtPlayerSelector::selectName(const QString& n) +{ + const char *name_str = n.toLatin1().constData(); + // skip any leading spaces + // (it would be better to set up a validator that rejects leading spaces) + while (*name_str == ' ') + ++name_str; + str_copy(g.plname, name_str, PL_NSIZ); + // possibly enable or disable the [Play] button + plnamePlayVsQuit(); +} + +void NetHackQtPlayerSelector::selectRole(int crow, int ccol, + int prow, int pcol) { int ra = race->currentRow(); int ro = role->currentRow(); @@ -402,17 +485,20 @@ void NetHackQtPlayerSelector::selectRole(int crow, int ccol, int prow, int pcol) item = role->item(j, 0); item->setSelected(item == i); bool v = validrace(j,ra); - item->setFlags( - v ? Qt::ItemIsEnabled|Qt::ItemIsSelectable - : Qt::NoItemFlags); + item->setFlags(v ? Qt::ItemIsEnabled|Qt::ItemIsSelectable + : Qt::NoItemFlags); } + nhUse(crow); + nhUse(ccol); + nhUse(pcol); #endif //flags.initrole = role->currentRow(); setupOthers(); } -void NetHackQtPlayerSelector::selectRace(int crow, int ccol, int prow, int pcol) +void NetHackQtPlayerSelector::selectRace(int crow, int ccol, + int prow, int pcol) { int ra = race->currentRow(); int ro = role->currentRow(); @@ -440,10 +526,12 @@ void NetHackQtPlayerSelector::selectRace(int crow, int ccol, int prow, int pcol) item = race->item(j, 0); item->setSelected(item == i); bool v = validrace(ro,j); - item->setFlags( - v ? Qt::ItemIsEnabled|Qt::ItemIsSelectable - : Qt::NoItemFlags); + item->setFlags(v ? Qt::ItemIsEnabled|Qt::ItemIsSelectable + : Qt::NoItemFlags); } + nhUse(crow); + nhUse(ccol); + nhUse(pcol); #endif //flags.initrace = race->currentRow(); diff --git a/win/Qt/qt_plsel.h b/win/Qt/qt_plsel.h index 5e2f7923e..985b544dc 100644 --- a/win/Qt/qt_plsel.h +++ b/win/Qt/qt_plsel.h @@ -22,6 +22,7 @@ public slots: void Quit(); void Random(); void Randomize(); + void plnamePlayVsQuit(); void selectName(const QString& n); void selectRole(int current, int, int previous, int); @@ -38,9 +39,14 @@ private: QTableWidget* race; QRadioButton **gender; QRadioButton **alignment; + bool fully_specified_role; int chosen_gend; int chosen_align; + + QPushButton *rand_btn; + QPushButton *play_btn; + QPushButton *quit_btn; }; } // namespace nethack_qt_ diff --git a/win/Qt/qt_post.h b/win/Qt/qt_post.h new file mode 100644 index 000000000..a63122f43 --- /dev/null +++ b/win/Qt/qt_post.h @@ -0,0 +1,13 @@ +/* NetHack 3.7 qt_post.h $NHDT-Date: 1597276832 2020/08/13 00:00:32 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.0 $ */ + +/* + * qt_post.h -- reverse part of qt_pre.h. + * + * #include after . + */ + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif /* __clang__ */ + +/*qt_post.h*/ diff --git a/win/Qt/qt_pre.h b/win/Qt/qt_pre.h new file mode 100644 index 000000000..e3dcdde0d --- /dev/null +++ b/win/Qt/qt_pre.h @@ -0,0 +1,28 @@ +/* NetHack 3.7 qt_pre.h $NHDT-Date: 1597276835 2020/08/13 00:00:35 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.0 $ */ + +/* + * qt_pre.h -- undefine some nethack macros which conflict with Qt headers. + * + * #include after "hack.h", before . + */ + +#undef Invisible +#undef Warning +#undef index +#undef msleep +#undef rindex +#undef wizard +#undef yn +#undef min +#undef max + +/* disable warnings for shadowed names; some of the Qt prototypes use + placeholder argument names which conflict with nethack variables + ('g', 'u', a couple of others) */ +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wshadow" +#endif + +/*qt_pre.h*/ + diff --git a/win/Qt/qt_rip.cpp b/win/Qt/qt_rip.cpp index cbe795f85..aa7a8ebc4 100644 --- a/win/Qt/qt_rip.cpp +++ b/win/Qt/qt_rip.cpp @@ -4,21 +4,16 @@ // qt_rip.cpp -- tombstone window +extern "C" { #include "hack.h" -#undef Invisible -#undef Warning -#undef index -#undef msleep -#undef rindex -#undef wizard -#undef yn -#undef min -#undef max +} +#include "qt_pre.h" #include #if QT_VERSION >= 0x050000 #include #endif +#include "qt_post.h" #include "qt_rip.h" #include "qt_bind.h" #include "qt_str.h" @@ -69,7 +64,7 @@ QSize NetHackQtRIP::sizeHint() const return pixmap->size(); } -void NetHackQtRIP::paintEvent(QPaintEvent* event) +void NetHackQtRIP::paintEvent(QPaintEvent* event UNUSED) { if ( riplines ) { int pix_x=(width()-pixmap->width())/2; diff --git a/win/Qt/qt_set.cpp b/win/Qt/qt_set.cpp index 2ac70fd9d..2f6655417 100644 --- a/win/Qt/qt_set.cpp +++ b/win/Qt/qt_set.cpp @@ -2,28 +2,53 @@ // Qt4 conversion copyright (c) Ray Chason, 2012-2014. // NetHack may be freely redistributed. See license for details. -// qt_set.cpp -- the Qt settings +// qt_set.cpp -- Qt-specific settings, saved and restored by Qt so +// persist not just across save/restore but into new games. +extern "C" { #include "hack.h" -#undef Invisible -#undef Warning -#undef index -#undef msleep -#undef rindex -#undef wizard -#undef yn -#undef min -#undef max +} +#include "qt_pre.h" #include #if QT_VERSION >= 0x050000 #include #endif +#include "qt_post.h" #include "qt_set.h" #include "qt_set.moc" #include "qt_glyph.h" +#include "qt_main.h" +#include "qt_bind.h" +#include "qt_xcmd.h" #include "qt_str.h" +// Dialog box accessed via "Qt Settings..." in the games menu (non-OSX) +// or via "Preferences..." in the application menu (OSX): +//-- +// "Qt NetHack Settings" +// "Map:" [ ] Zoomed -- check box +// tilewidth -- number entry spinner +// tileheight -- ditto +// "Invent:" [ ] Shown -- check box +// dollwidth -- number entry spinner +// dollheight -- ditto +// "Font:" fontsize -- Huge:18pt, Large:14, Medium:12, Small:10, Tiny:8 +// [dismiss] -- button +//-- +// Map remembers 2 size pairs, one for Zoomed unchecked, another for checked. +// (Player controls whether the box is checked, using the dialog to manually +// switch back and forth if desired; nothing forces the Zoomed setting to +// specify larger tile size than not-Zoomed.) +// Paper doll inventory subset is shown or suppressed depending on check box. +// (It only remembers one tile size pair and that only matters when shown. +// The size could be different from both map settings but it is highly +// recommended that it match one of those unless Zoomed is never toggled.) +// Font size is used for message window and for text in the status window. +// (TODO: support separate font sizes for the two windows.) +// There's no way to undo or avoid saving any changes which player makes but +// all of the fields can be manually reversed. + /* Used by tile/font-size patch below and in ../../src/files.c */ char *qt_tilewidth=NULL; char *qt_tileheight=NULL; @@ -39,13 +64,20 @@ namespace nethack_qt_ { #define TILEWMIN 6 #define TILEHMIN 6 -NetHackQtSettings::NetHackQtSettings(int w, int h) : +NetHackQtSettings::NetHackQtSettings() : settings(), + whichsize("&Zoomed", this), tilewidth(this), tileheight(this), - widthlbl("&Width:",this), - heightlbl("&Height:",this), - whichsize("&Zoomed",this), + widthlbl("Tile &width:", this), + heightlbl("Tile &height:", this), +#ifdef ENHANCED_PAPERDOLL + dollshown("&Shown", this), + dollwidth(this), + dollheight(this), + dollwidthlbl("&Doll width:", this), // should "Doll tile width"... + dollheightlbl("Doll height:", this), // ...but that's too verbose +#endif fontsize(this), normal("times"), #ifdef WS_WIN @@ -55,7 +87,6 @@ NetHackQtSettings::NetHackQtSettings(int w, int h) : #endif large("times"), theglyphs(0) - { int default_fontsize; @@ -63,11 +94,27 @@ NetHackQtSettings::NetHackQtSettings(int w, int h) : tilewidth.setRange(TILEWMIN, 128); heightlbl.setBuddy(&tileheight); tileheight.setRange(TILEHMIN, 128); - tilewidth.setValue(settings.value("tilewidth", 16).toInt()); tileheight.setValue(settings.value("tileheight", 16).toInt()); +#ifdef ENHANCED_PAPERDOLL + dollwidthlbl.setBuddy(&dollwidth); + dollwidth.setRange(TILEWMIN, 48); + dollheightlbl.setBuddy(&dollheight); + dollheight.setRange(TILEHMIN, 48); + dollwidth.setValue(settings.value("dollwidth", 32).toInt()); + dollheight.setValue(settings.value("dollheight", 32).toInt()); + doll_is_shown = settings.value("dollShown", true).toBool(); + // needed the very first time + settings.setValue("dollShown", QVariant(doll_is_shown)); +#endif default_fontsize = settings.value("fontsize", 2).toInt(); + // these aren't currently part of the settings dialog; they're managed + // by the extended commands menu ('#' command) and updateXcmd() below + // but are included in qt_settings to be remembered across play sessions + xcmd_by_row = settings.value("xcmdByRow", false).toBool(); + xcmd_set = settings.value("xcmdSet", all_cmds).toInt(); + // Tile/font sizes read from .nethackrc if (qt_tilewidth != NULL) { tilewidth.setValue(atoi(qt_tilewidth)); @@ -91,39 +138,75 @@ NetHackQtSettings::NetHackQtSettings(int w, int h) : theglyphs=new NetHackQtGlyphs(); resizeTiles(); - connect(&tilewidth,SIGNAL(valueChanged(int)),this,SLOT(resizeTiles())); - connect(&tileheight,SIGNAL(valueChanged(int)),this,SLOT(resizeTiles())); - connect(&whichsize,SIGNAL(toggled(bool)),this,SLOT(setGlyphSize(bool))); + connect(&whichsize, SIGNAL(toggled(bool)), this, SLOT(setGlyphSize(bool))); + connect(&tilewidth, SIGNAL(valueChanged(int)), this, SLOT(resizeTiles())); + connect(&tileheight, SIGNAL(valueChanged(int)), this, SLOT(resizeTiles())); +#ifdef ENHANCED_PAPERDOLL + connect(&dollshown, SIGNAL(toggled(bool)), this, SLOT(setDollShown(bool))); + connect(&dollwidth, SIGNAL(valueChanged(int)), this, SLOT(resizeDoll())); + connect(&dollheight, SIGNAL(valueChanged(int)), this, SLOT(resizeDoll())); +#endif + + fontsize.setMinimumContentsLength((int) strlen("Medium")); fontsize.addItem("Huge"); fontsize.addItem("Large"); fontsize.addItem("Medium"); fontsize.addItem("Small"); fontsize.addItem("Tiny"); fontsize.setCurrentIndex(default_fontsize); - connect(&fontsize,SIGNAL(activated(int)),this,SLOT(changedFont())); + connect(&fontsize, SIGNAL(activated(int)), this, SLOT(changedFont())); - QGridLayout* grid = new QGridLayout(this); - grid->addWidget(&whichsize, 0, 0, 1, 2); - grid->addWidget(&tilewidth, 1, 1); grid->addWidget(&widthlbl, 1, 0); - grid->addWidget(&tileheight, 2, 1); grid->addWidget(&heightlbl, 2, 0); - QLabel* flabel=new QLabel("&Font:",this); + int row = 0; // used like X11-style XtSetArg(), ++argc + QGridLayout *grid = new QGridLayout(this); + // dialog box label, spans first two rows and all three columns + QLabel *settings_label = new QLabel("Qt NetHack Settings\n", this); + grid->addWidget(settings_label, row, 0, 2, 3), row += 2; // uses extra row + settings_label->setAlignment(Qt::AlignHCenter | Qt::AlignTop); + + QLabel *map_label = new QLabel("&Map:", this); + map_label->setBuddy(&whichsize); + grid->addWidget(map_label, row, 0), // "Map: [ ]Zoomed" + grid->addWidget(&whichsize, row, 1), ++row; + grid->addWidget(&widthlbl, row, 1), + grid->addWidget(&tilewidth, row, 2), ++row; + grid->addWidget(&heightlbl, row, 1), + grid->addWidget(&tileheight, row, 2), ++row; + +#ifdef ENHANCED_PAPERDOLL + dollshown.QAbstractButton::setChecked(doll_is_shown); + QLabel *doll_label = new QLabel("&Invent:", this); + doll_label->setBuddy(&dollshown); + grid->addWidget(doll_label, row, 0), // "Invent: [ ]Shown" + grid->addWidget(&dollshown, row, 1), ++row; + grid->addWidget(&dollwidthlbl, row, 1), + grid->addWidget(&dollwidth, row, 2), ++row; + grid->addWidget(&dollheightlbl, row, 1), + grid->addWidget(&dollheight, row, 2), ++row; +#endif + + QLabel *flabel = new QLabel("&Font:", this); flabel->setBuddy(&fontsize); - grid->addWidget(flabel, 3, 0); grid->addWidget(&fontsize, 3, 1); - QPushButton* dismiss=new QPushButton("Dismiss",this); + grid->addWidget(flabel, row, 0), + grid->addWidget(&fontsize, row, 1), ++row; + + QPushButton *dismiss = new QPushButton("Dismiss", this); dismiss->setDefault(true); - grid->addWidget(dismiss, 4, 0, 1, 2); - grid->setRowStretch(4,0); - grid->setColumnStretch(1,1); - grid->setColumnStretch(2,2); + grid->addWidget(dismiss, row, 0, 1, 3), ++row; + grid->setRowStretch(row - 1, 0); + grid->setColumnStretch(1, 1); + grid->setColumnStretch(2, 2); grid->activate(); - connect(dismiss,SIGNAL(clicked()),this,SLOT(accept())); - resize(150,140); + connect(dismiss, SIGNAL(clicked()), this, SLOT(accept())); + resize(150, 140); } NetHackQtGlyphs& NetHackQtSettings::glyphs() { + // Caveat: + // 'theglyphs' will be Null if the tiles file couldn't be loaded; + // the game can still procede with an ascii map in that situation. return *theglyphs; } @@ -135,13 +218,16 @@ void NetHackQtSettings::changedFont() void NetHackQtSettings::resizeTiles() { - int w = tilewidth.value(); - int h = tileheight.value(); + tileWidth = tilewidth.value(); + tileHeight = tileheight.value(); - settings.setValue("tilewidth", tilewidth.value()); - settings.setValue("tileheight", tileheight.value()); - theglyphs->setSize(w,h); - emit tilesChanged(); + settings.setValue("tilewidth", tileWidth); + settings.setValue("tileheight", tileHeight); + + if (theglyphs) { + theglyphs->setSize(tileWidth, tileHeight); + emit tilesChanged(); + } } void NetHackQtSettings::toggleGlyphSize() @@ -149,7 +235,7 @@ void NetHackQtSettings::toggleGlyphSize() whichsize.toggle(); } -void NetHackQtSettings::setGlyphSize(bool which) +void NetHackQtSettings::setGlyphSize(bool which UNUSED) { QSize n = QSize(tilewidth.value(),tileheight.value()); if ( othersize.isValid() ) { @@ -164,6 +250,47 @@ void NetHackQtSettings::setGlyphSize(bool which) othersize = n; } +#ifdef ENHANCED_PAPERDOLL +void NetHackQtSettings::resizeDoll() +{ + dollWidth = dollwidth.value(); + dollHeight = dollheight.value(); + + settings.setValue("dollwidth", dollWidth); + settings.setValue("dollheight", dollHeight); + settings.setValue("dollShown", doll_is_shown); + + //NetHackQtMainWindow::resizePaperDoll(doll_is_shown); + NetHackQtMainWindow *w = static_cast + (NetHackQtBind::mainWidget()); + w->resizePaperDoll(doll_is_shown); +} + +void NetHackQtSettings::toggleDollShown() +{ + dollshown.toggle(); +} + +void NetHackQtSettings::setDollShown(bool on_off) +{ + if (on_off != doll_is_shown) { + dollshown.QAbstractButton::setChecked(on_off); + doll_is_shown = on_off; + resizeDoll(); + } +} +#endif + +// called from NetHackQtExtCmdRequestor::Retry() +void NetHackQtSettings::updateXcmd(bool by_row, int which_set) +{ + // update 'settings' to have Qt store the revised values for next session + xcmd_by_row = by_row; + settings.setValue("xcmdByRow", QVariant(xcmd_by_row)); + xcmd_set = which_set; + settings.setValue("xcmdSet", xcmd_set); +} + const QFont& NetHackQtSettings::normalFont() { static int size[]={ 18, 14, 12, 10, 8 }; diff --git a/win/Qt/qt_set.h b/win/Qt/qt_set.h index 6b2aa6a4a..14ec92c02 100644 --- a/win/Qt/qt_set.h +++ b/win/Qt/qt_set.h @@ -7,15 +7,30 @@ #ifndef QT4SET_H #define QT4SET_H +#define ENHANCED_PAPERDOLL /* separate size from map tiles, can be hidden */ + +#include "qt_bind.h" // needed for mainWidget() for updateInventory() + namespace nethack_qt_ { class NetHackQtGlyphs; +class NetHackQtMainWindow; class NetHackQtSettings : public QDialog { Q_OBJECT public: - // Size of window - used to decide default sizes - NetHackQtSettings(int width, int height); + int tileWidth = 16, tileHeight = 16; +#ifdef ENHANCED_PAPERDOLL + int dollWidth = 32, dollHeight = 32; + bool doll_is_shown = true; +#endif + bool xcmd_by_row = false; + int xcmd_set = 0; // all_cmds + + // dialog box for Qt-specific settings + NetHackQtSettings(); + + void updateXcmd(bool by_row, int which_set); NetHackQtGlyphs& glyphs(); const QFont& normalFont(); @@ -31,21 +46,41 @@ signals: public slots: void toggleGlyphSize(); void setGlyphSize(bool); +#ifdef ENHANCED_PAPERDOLL + void toggleDollShown(); + void setDollShown(bool); + void resizeDoll(); +#endif private: QSettings settings; + + QCheckBox whichsize; QSpinBox tilewidth; QSpinBox tileheight; QLabel widthlbl; QLabel heightlbl; - QCheckBox whichsize; QSize othersize; +#ifdef ENHANCED_PAPERDOLL + QCheckBox dollshown; + QSpinBox dollwidth; + QSpinBox dollheight; + QLabel dollwidthlbl; + QLabel dollheightlbl; +#endif QComboBox fontsize; QFont normal, normalfixed, large; NetHackQtGlyphs* theglyphs; +#if 0 + void updateInventory() + { + static_cast (NetHackQtBind::mainWidget()) + ->updateInventory(); + } +#endif private slots: void resizeTiles(); diff --git a/win/Qt/qt_stat.cpp b/win/Qt/qt_stat.cpp index 5e6918f00..3fca92c89 100644 --- a/win/Qt/qt_stat.cpp +++ b/win/Qt/qt_stat.cpp @@ -2,25 +2,88 @@ // Qt4 conversion copyright (c) Ray Chason, 2012-2014. // NetHack may be freely redistributed. See license for details. -// qt_stat.cpp -- bindings between the Qt 4 interface and the main code +// qt_stat.cpp -- status window, upper right portion of the overall window +// +// The Qt status window consists of many lines: +// +// hitpoint bar (when enabled) +// Title (plname the Rank or plname the MonsterSpecies) +// Dungeon location (branch and level) +// separator line +// six icons (special 40x40 tiles, paired with...) +// six characteristic texts ("Str:18/03", "Dex:15", &c) +// separator line +// five status fields without icons (some containing two values: +// HP/HPmax, Energy/Enmax, AC, XpLevel/ExpPoints or HD, [blank], Gold) +// separator line +// line with two optional text fields (Time:1234, Score:89), maybe blank +// varying number of icons (one or more, each paired with...) +// corresponding text (Alignment plus zero or more status conditions +// including Hunger if not "normal" and encumbrance if not "normal") +// +// The hitpoint bar spans the width of the status window when enabled. +// Title and location are centered. +// The icons and text for the six characteristics are evenly spaced; +// this pair of lines is sometimes referred to as "row 1" below. +// The five main stats or slash-separated stat pairs are padded with an +// empty slot between Xp and Gold; adding the sixth makes that row +// line up with the characteristics; this line is sometimes referred +// to as "row 2". +// Time and Score are spaced as if each were three fields wide; their +// line is "row 3" relative to statuslines:2 vs statuslines:3. +// Icons and texts for alignment and conditions are left justified. +// The separator lines are thin and don't take up much vertical space. +// When enabled, the hitpoint bar bisects the margin above Title, +// increasing the overall status height by 9 pixels; when disabled, +// the status shifts up by those 9 pixels. +// When row 3 (Time, Score) is blank, it still takes up the vertical +// space that would be used to show those values. +// +// The above is for statuslines:3, which used to be the default. For +// statuslines:2, rows 1 and 2 are extended from six to seven fields +// and row 3 (optional Time, Score) is eliminated. Alignment is +// moved from the beginning of the Conditions pair (icon over text) +// of lines up to the end of row 1, the Characteristics pair of lines, +// with a separator between Cha:NN and it. Time, when active, is +// placed after Gold. Score, if enabled and active, is shown in the +// filler slot before Gold. When there are no Conditions to display, +// there is an an invisible fake one (blank icon over blank text) +// rendered in order to preserve the vertical space they need. +// +// FIXME: +// When hitpoint bar is shown, attempting to resize horizontally won't +// do anything. Toggling it off, then resizing, and back On works. +// (Caused by specifying min-width and max-width constraints in the +// style sheets used to control color, but removing those constraints +// causes the bar display to get screwed up.) +// There are separate icons for Satiated and Hungry, but Weak, Fainting, +// and Fainted all share the Hungry one. Weak should have its own, +// Fainting+Fainted should have another. The current two depict +// plates with cutlery which is a bit of an anachronism. Statiated +// could be replaced by a figure in profile with a bulging belly, +// Hungry similar but with a slightly concave belly, Weak either a +// collapsing figure or a much larger concavity or both, Fainting/ +// Fainted a fully collapsed figure. +// +// TODO: +// If/when status conditions become too wide for the status window, scale +// down their icons and switch their text to a smaller font to match. +// Title and Location are explicitly rendered with a bigger font than +// the rest of status. That takes up more space, which is ok, but it +// also increases the vertical margin in between them by more than is +// necessary. Should squeeze some of that excess blank space out. +// extern "C" { #include "hack.h" } -#undef Invisible -#undef Warning -#undef index -#undef msleep -#undef rindex -#undef wizard -#undef yn -#undef min -#undef max +#include "qt_pre.h" #include #if QT_VERSION >= 0x050000 #include #endif +#include "qt_post.h" #include "qt_stat.h" #include "qt_stat.moc" #include "qt_set.h" @@ -30,43 +93,69 @@ extern "C" { extern const char *enc_stat[]; /* from botl.c */ extern const char *hu_stat[]; /* from eat.c */ +extern int qt_compact_mode; + namespace nethack_qt_ { NetHackQtStatusWindow::NetHackQtStatusWindow() : - // Notes: - // Alignment needs -2 init value, because -1 is an alignment. - // Armor Class is an schar, so 256 is out of range. - // Blank value is 0 and should never change. + /* first three rows: hitpoint bar, title (plname the Rank), location */ + hpbar_health(this), + hpbar_injury(this), name(this,"(name)"), dlevel(this,"(dlevel)"), - str(this,"STR"), - dex(this,"DEX"), - con(this,"CON"), - intel(this,"INT"), - wis(this,"WIS"), - cha(this,"CHA"), - gold(this,"Gold"), + /* next two rows: icon over text label for the six characteristics */ + str(this, "Str"), + dex(this, "Dex"), + con(this, "Con"), + intel(this, "Int"), + wis(this, "Wis"), + cha(this, "Cha"), + /* sixth row, text only: some contain two slash-separated values */ hp(this,"Hit Points"), power(this,"Power"), - ac(this,"Armour Class"), - level(this,"Level"), - exp(this,"Experience"), + ac(this,"Armor Class"), + level(this,"Level"), // Xp level, with "/"+Exp points optionally appended + blank1(this, ""), // used for padding to align columns (was once 'exp') + gold(this,"Gold"), // gold used to be this row's first column, now last + /* seventh row: two optionally displayed values (just text, no icons) */ + time(this,"Time"), // if 'time' option On + score(this,"Score"), // if SCORE_ON_BOTL defined and 'showscore' option On + /* last two rows: alignment followed by conditions (icons over text) */ align(this,"Alignment"), - time(this,"Time"), - score(this,"Score"), + blank2(this, " "), // used to prevent Conditions row from being empty hunger(this,""), - confused(this,"Confused"), - sick_fp(this,"Sick"), - sick_il(this,"Ill"), - blind(this,""), - stunned(this,"Stunned"), - hallu(this,"Hallu"), encumber(this,""), - hline1(this), + stoned(this,"Stone"), // major conditions + slimed(this,"Slime"), + strngld(this,"Strngl"), + sick_fp(this,"FoodPois"), + sick_il(this,"TermIll"), + stunned(this,"Stun"), // minor conditions + confused(this,"Conf"), + hallu(this,"Hallu"), + blind(this,"Blind"), + deaf(this,"Deaf"), + lev(this,"Lev"), // 'other' conditions + fly(this,"Fly"), + ride(this,"Ride"), + hline1(this), // separators hline2(this), hline3(this), - first_set(true) + vline1(this), // vertical separator between Characteristics and Alignment + vline2(this), // padding for row 2 to match row 1's separator; not shown + /* miscellaneous; not display fields */ + cursy(0), + first_set(true), + alreadyfullhp(false), + was_polyd(false), + had_exp(false), + had_score(false) { + if (!qt_compact_mode) { + int w = NetHackQtBind::mainWidget()->width(); + setMaximumWidth(w / 2); + } + p_str = QPixmap(str_xpm); p_str = QPixmap(str_xpm); p_dex = QPixmap(dex_xpm); @@ -78,23 +167,31 @@ NetHackQtStatusWindow::NetHackQtStatusWindow() : p_chaotic = QPixmap(chaotic_xpm); p_neutral = QPixmap(neutral_xpm); p_lawful = QPixmap(lawful_xpm); + p_blank2 = QPixmap(blank_xpm); p_satiated = QPixmap(satiated_xpm); p_hungry = QPixmap(hungry_xpm); - p_confused = QPixmap(confused_xpm); - p_sick_fp = QPixmap(sick_fp_xpm); - p_sick_il = QPixmap(sick_il_xpm); - p_blind = QPixmap(blind_xpm); - p_stunned = QPixmap(stunned_xpm); - p_hallu = QPixmap(hallu_xpm); - p_encumber[0] = QPixmap(slt_enc_xpm); p_encumber[1] = QPixmap(mod_enc_xpm); p_encumber[2] = QPixmap(hvy_enc_xpm); p_encumber[3] = QPixmap(ext_enc_xpm); p_encumber[4] = QPixmap(ovr_enc_xpm); + p_stoned = QPixmap(stone_xpm); + p_slimed = QPixmap(slime_xpm); + p_strngld = QPixmap(strngl_xpm); + p_sick_fp = QPixmap(sick_fp_xpm); + p_sick_il = QPixmap(sick_il_xpm); + p_stunned = QPixmap(stunned_xpm); + p_confused = QPixmap(confused_xpm); + p_hallu = QPixmap(hallu_xpm); + p_blind = QPixmap(blind_xpm); + p_deaf = QPixmap(deaf_xpm); + p_lev = QPixmap(lev_xpm); + p_fly = QPixmap(fly_xpm); + p_ride = QPixmap(ride_xpm); + str.setIcon(p_str); dex.setIcon(p_dex); con.setIcon(p_con); @@ -103,70 +200,135 @@ NetHackQtStatusWindow::NetHackQtStatusWindow() : cha.setIcon(p_cha); align.setIcon(p_neutral); + blank2.setIcon(p_blank2); // used for spacing when Conditions row is empty hunger.setIcon(p_hungry); - - confused.setIcon(p_confused); - sick_fp.setIcon(p_sick_fp); - sick_il.setIcon(p_sick_il); - blind.setIcon(p_blind); - stunned.setIcon(p_stunned); - hallu.setIcon(p_hallu); - encumber.setIcon(p_encumber[0]); - hline1.setFrameStyle(QFrame::HLine|QFrame::Sunken); - hline2.setFrameStyle(QFrame::HLine|QFrame::Sunken); - hline3.setFrameStyle(QFrame::HLine|QFrame::Sunken); + stoned.setIcon(p_stoned); + slimed.setIcon(p_slimed); + strngld.setIcon(p_strngld); + sick_fp.setIcon(p_sick_fp); + sick_il.setIcon(p_sick_il); + stunned.setIcon(p_stunned); + confused.setIcon(p_confused); + hallu.setIcon(p_hallu); + blind.setIcon(p_blind); + deaf.setIcon(p_deaf); + lev.setIcon(p_lev); + fly.setIcon(p_fly); + ride.setIcon(p_ride); + + // separator lines + hline1.setFrameStyle(QFrame::HLine | QFrame::Sunken); + hline2.setFrameStyle(QFrame::HLine | QFrame::Sunken); + hline3.setFrameStyle(QFrame::HLine | QFrame::Sunken); hline1.setLineWidth(1); hline2.setLineWidth(1); hline3.setLineWidth(1); + // vertical separators for condensed layout (statuslines:2) + vline1.setFrameStyle(QFrame::VLine | QFrame::Sunken); + vline2.setFrameStyle(QFrame::VLine | QFrame::Sunken); + vline1.setLineWidth(1); // separates Alignment from Charisma + vline2.setLineWidth(1); + vline2.hide(); // padding to keep row 2 aligned with row 1, never shown + + // set up last but shown first (above name) via layout below */ + QHBoxLayout *hpbar = InitHitpointBar(); + + // 'statuslines' takes a value of 2 or 3; we use 3 as a request to put + // Alignment in front of status conditions so that line is never empty + // and to show Time and/or Score on their own line which might be empty + boolean spreadout = (::iflags.wc2_statuslines != 2); #if 1 //RLC name.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum); dlevel.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum); QVBoxLayout *vbox = new QVBoxLayout(); vbox->setSpacing(0); + vbox->addLayout(hpbar); // when 'hitpointbar' is enabled, it comes first vbox->addWidget(&name); vbox->addWidget(&dlevel); vbox->addWidget(&hline1); - QHBoxLayout *atr1box = new QHBoxLayout(); - atr1box->addWidget(&str); - atr1box->addWidget(&dex); - atr1box->addWidget(&con); - atr1box->addWidget(&intel); - atr1box->addWidget(&wis); - atr1box->addWidget(&cha); - vbox->addLayout(atr1box); + QHBoxLayout *charbox = new QHBoxLayout(); // Characteristics + charbox->addWidget(&str); + charbox->addWidget(&dex); + charbox->addWidget(&con); + charbox->addWidget(&intel); + charbox->addWidget(&wis); + charbox->addWidget(&cha); + if (!spreadout) { + // when condensed, include Alignment with Characteristics + charbox->addWidget(&vline1); // show a short vertical separator + charbox->addWidget(&align); + } + vbox->addLayout(charbox); vbox->addWidget(&hline2); - QHBoxLayout *atr2box = new QHBoxLayout(); - atr2box->addWidget(&gold); - atr2box->addWidget(&hp); - atr2box->addWidget(&power); - atr2box->addWidget(&ac); - atr2box->addWidget(&level); - atr2box->addWidget(&exp); - vbox->addLayout(atr2box); - vbox->addWidget(&hline3); - QHBoxLayout *timebox = new QHBoxLayout(); - timebox->addWidget(&time); - timebox->addWidget(&score); - vbox->addLayout(timebox); - QHBoxLayout *statbox = new QHBoxLayout(); - statbox->addWidget(&align); - statbox->addWidget(&hunger); - statbox->addWidget(&confused); - statbox->addWidget(&sick_fp); - statbox->addWidget(&sick_il); - statbox->addWidget(&blind); - statbox->addWidget(&stunned); - statbox->addWidget(&hallu); - statbox->addWidget(&encumber); - statbox->setAlignment(Qt::AlignLeft|Qt::AlignVCenter); + QHBoxLayout *statbox = new QHBoxLayout(); // core status fields + statbox->addWidget(&hp); + statbox->addWidget(&power); + statbox->addWidget(&ac); + statbox->addWidget(&level); + if (spreadout) { + // when not condensed, put a blank field in front of Gold; + // Time and Score will be shown on their own separate line + statbox->addWidget(&blank1); // empty column #5 of 6 + statbox->addWidget(&gold); + } else { + // when condensed, display Time and Score on HP,...,Gold row +#ifndef SCORE_ON_BOTL + statbox->addWidget(&blank1); // empty column #5 of 7 +#else + statbox->addWidget(&score); // usually empty column #5 +#endif + statbox->addWidget(&gold); // columns 6 and maybe empty 7 + statbox->addWidget(&vline2); // padding between 6 and 7; not shown + statbox->addWidget(&time); + } vbox->addLayout(statbox); + vbox->addWidget(&hline3); // separtor before Time+Score or Conditions + if (spreadout) { + // when not condensed, put Time and Score on an extra row; since + // they're both optionally displayed, their row might be empty + // TODO? when neither will be shown, set their heights smaller + // and if either gets toggled On, set height back to normal + QHBoxLayout *timebox = new QHBoxLayout(); + timebox->addWidget(&time); + timebox->addWidget(&score); + vbox->addLayout(timebox); + } + QHBoxLayout *condbox = new QHBoxLayout(); // Conditions + if (spreadout) { + // when not condensed, include Alignment with Conditions to + // spread things out and also so that their row is never empty + condbox->addWidget(&align); + } else { + // otherwise place a padding widget on this row; it will be + // hidden if any Conditions are shown, or shown (with blank + // icon and empty text) when there aren't any, reserving + // space (the height of the row) for later conditions + condbox->addWidget(&blank2); + } + condbox->addWidget(&hunger); + condbox->addWidget(&encumber); + condbox->addWidget(&stoned); + condbox->addWidget(&slimed); + condbox->addWidget(&strngld); + condbox->addWidget(&sick_fp); + condbox->addWidget(&sick_il); + condbox->addWidget(&stunned); + condbox->addWidget(&confused); + condbox->addWidget(&hallu); + condbox->addWidget(&blind); + condbox->addWidget(&deaf); + condbox->addWidget(&lev); + condbox->addWidget(&fly); + condbox->addWidget(&ride); + condbox->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); + vbox->addLayout(condbox); setLayout(vbox); #endif - connect(qt_settings,SIGNAL(fontChanged()),this,SLOT(doUpdate())); + connect(qt_settings, SIGNAL(fontChanged()), this, SLOT(doUpdate())); doUpdate(); } @@ -183,23 +345,38 @@ void NetHackQtStatusWindow::doUpdate() intel.setFont(normal); wis.setFont(normal); cha.setFont(normal); - gold.setFont(normal); hp.setFont(normal); power.setFont(normal); ac.setFont(normal); level.setFont(normal); - exp.setFont(normal); - align.setFont(normal); + blank1.setFont(normal); // padding + gold.setFont(normal); time.setFont(normal); score.setFont(normal); + align.setFont(normal); + // blank2 is used as a dummy condition when Alignment has been moved + // elsewhere (statuslines:2) and no other conditions currently apply; + // it has a blank icon with a label of a single space (if the label + // is completely empty, the rest of status shifts down a little when + // one or more real conditions replace it and shifts up again when + // all conditions are removed and this one is reinstated--as if "" is + // slightly taller than " ") + blank2.setFont(normal); hunger.setFont(normal); - confused.setFont(normal); + encumber.setFont(normal); + stoned.setFont(normal); + slimed.setFont(normal); + strngld.setFont(normal); sick_fp.setFont(normal); sick_il.setFont(normal); - blind.setFont(normal); stunned.setFont(normal); + confused.setFont(normal); hallu.setFont(normal); - encumber.setFont(normal); + blind.setFont(normal); + deaf.setFont(normal); + lev.setFont(normal); + fly.setFont(normal); + ride.setFont(normal); updateStats(); } @@ -209,14 +386,14 @@ QWidget* NetHackQtStatusWindow::Widget() { return this; } void NetHackQtStatusWindow::Clear() { } -void NetHackQtStatusWindow::Display(bool block) +void NetHackQtStatusWindow::Display(bool block UNUSED) { } void NetHackQtStatusWindow::CursorTo(int,int y) { cursy=y; } -void NetHackQtStatusWindow::PutStr(int attr, const QString& text) +void NetHackQtStatusWindow::PutStr(int attr UNUSED, const QString& text UNUSED) { // do a complete update when line 0 is done (as per X11 fancy status) if (cursy==0) updateStats(); @@ -270,7 +447,7 @@ void NetHackQtStatusWindow::resizeEvent(QResizeEvent*) power.setGeometry(x,y,iw,lh); x+=iw; ac.setGeometry(x,y,iw,lh); x+=iw; level.setGeometry(x,y,iw,lh); x+=iw; - exp.setGeometry(x,y,iw,lh); x+=iw; + //exp.setGeometry(x,y,iw,lh); x+=iw; x=0; y+=lh; lh=int(h*SP_hln3); @@ -286,13 +463,20 @@ void NetHackQtStatusWindow::resizeEvent(QResizeEvent*) iw=width()/9; align.setGeometry(x,y,iw,lh); x+=iw; hunger.setGeometry(x,y,iw,lh); x+=iw; - confused.setGeometry(x,y,iw,lh); x+=iw; + encumber.setGeometry(x,y,iw,lh); x+=iw; + stoned.setGeometry(x,y,iw,lh); x+=iw; + slimed.setGeometry(x,y,iw,lh); x+=iw; + strngld.setGeometry(x,y,iw,lh); x+=iw; sick_fp.setGeometry(x,y,iw,lh); x+=iw; sick_il.setGeometry(x,y,iw,lh); x+=iw; - blind.setGeometry(x,y,iw,lh); x+=iw; stunned.setGeometry(x,y,iw,lh); x+=iw; + confused.setGeometry(x,y,iw,lh); x+=iw; hallu.setGeometry(x,y,iw,lh); x+=iw; - encumber.setGeometry(x,y,iw,lh); x+=iw; + blind.setGeometry(x,y,iw,lh); x+=iw; + deaf.setGeometry(x,y,iw,lh); x+=iw; + lev.setGeometry(x,y,iw,lh); x+=iw; + fly.setGeometry(x,y,iw,lh); x+=iw; + ride.setGeometry(x,y,iw,lh); x+=iw; x=0; y+=lh; #else // This is clumsy. But QLayout objects are proving balky. @@ -310,7 +494,7 @@ void NetHackQtStatusWindow::resizeEvent(QResizeEvent*) /* * Set all widget values to a null string. This is used after all spacings * have been calculated so that when the window is popped up we don't get all - * kinds of funny values being displayed. + * kinds of funny values being displayed. [Actually it isn't used at all.] */ void NetHackQtStatusWindow::nullOut() { @@ -333,20 +517,152 @@ void NetHackQtStatusWindow::fadeHighlighting() power.dissipateHighlight(); ac.dissipateHighlight(); level.dissipateHighlight(); - exp.dissipateHighlight(); align.dissipateHighlight(); - time.dissipateHighlight(); + //time.dissipateHighlight(); score.dissipateHighlight(); hunger.dissipateHighlight(); - confused.dissipateHighlight(); + encumber.dissipateHighlight(); + stoned.dissipateHighlight(); + slimed.dissipateHighlight(); + strngld.dissipateHighlight(); sick_fp.dissipateHighlight(); sick_il.dissipateHighlight(); - blind.dissipateHighlight(); stunned.dissipateHighlight(); + confused.dissipateHighlight(); hallu.dissipateHighlight(); - encumber.dissipateHighlight(); + blind.dissipateHighlight(); + deaf.dissipateHighlight(); + lev.dissipateHighlight(); + fly.dissipateHighlight(); + ride.dissipateHighlight(); +} + +// hitpointbar: two panels: left==current health, right==missing max health +QHBoxLayout *NetHackQtStatusWindow::InitHitpointBar() +{ + hpbar_health.setFrameStyle(QFrame::NoFrame); + hpbar_health.setMaximumHeight(9); + hpbar_health.setAutoFillBackground(true); + if (!iflags.wc2_hitpointbar) + hpbar_health.hide(); + + hpbar_injury.setFrameStyle(QFrame::NoFrame); + /* health portion has thickness 9, injury portion just 3 */ + hpbar_injury.setMaximumHeight(3); + hpbar_injury.setContentsMargins(0, 3, 0, 3); // left,top,right,bottom + hpbar_injury.setAutoFillBackground(true); + hpbar_injury.hide(); // only shown when hitpointbar is On and uhp < uhpmax + + QHBoxLayout *hpbar = new QHBoxLayout; + hpbar->setSpacing(0); + hpbar->setMargin(0); + hpbar->addWidget(&hpbar_health); + hpbar->setAlignment(&hpbar_health, Qt::AlignLeft); + hpbar->addWidget(&hpbar_injury); + hpbar->setAlignment(&hpbar_injury, Qt::AlignRight); + return hpbar; // caller will add our result to vbox layout +} + +// when hitpoint bar is enabled, calculate and draw it, otherwise remove it +void NetHackQtStatusWindow::HitpointBar() +{ + // a style sheet is used to specify color for otherwise blank labels; + // barcolors[][*]: column [0=left] is current health, [1=right] is injury + static const char + *styleformat = "QLabel { background-color : %s ; color : transparent ;" + " min-width : %d ; max-width %d }", + *barcolors[6][2] = { + { "black", "black" }, // 100% /* second black never shown */ + { "blue", "darkBlue" }, //75..99 + /* gray is darker than darkGray for some reason (at least on OSX); + default green is too dark compared to blue, yellow, orange, + and red so is changed here to green.lighter(150) */ + { "#00c000", "gray" }, //50..74 /* "green"=="#008000" */ + { "yellow", "darkGray" }, //25..49 + { "orange", "lightGray" }, //10..24 + { "red", "white" }, // 0..9 + }; + + /* + * tty and curses use inverse video characters in the left portion + * of the name+rank string to reflect hero's health. We draw a + * separate line above the name+rank field instead. The left side + * of the line indicates current health. The right side is only + * shown when injured and indicates missing amount of maximum health. + */ + if (iflags.wc2_hitpointbar) { + int colorindx, w, + ihp = Upolyd ? u.mh : u.uhp, + ihpmax = Upolyd ? u.mhmax : u.uhpmax; + ihp = std::max(std::min(ihp, ihpmax), 0); + int pct = 100 * ihp / ihpmax, + lox = hline1.x(), + hix = lox + hline1.width() - 1; + QRect geoH = hpbar_health.geometry(), + geoI = hpbar_injury.geometry(); + QString styleH, styleI; + + if (ihp < ihpmax) { + // health is less than full; + // use red for extreme low health even if the percentage is + // above the usual threshold (which will happen when maximum + // health is very low); do a similar threshold override for + // orange even though it can be distracting for low level hero + colorindx = (pct < 10 || ihp < 5) ? 5 // red | white + : (pct < 25 || ihp < 10 ) ? 4 // orange | lightGray + : (pct < 50) ? 3 // yellow | darkGray* + : (pct < 75) ? 2 // green | gray* + : 1; // blue | darkBlue + + int pxl_health = (hix - lox + 1) * ihp / ihpmax; + geoH.setRight(std::min(lox + pxl_health - 1, hix)); + hpbar_health.setGeometry(geoH); + w = geoH.right() - geoH.left() + 1; // might yield 0 (ie, if dead) + styleH.sprintf(styleformat, barcolors[colorindx][0], w, w); + hpbar_health.setStyleSheet(styleH); + // when healing, having the old injury-side shown while the new + // health-side expands pushes the injury farther right and it's + // momentarily visible there before it gets recalculated+redrawn + hpbar_injury.hide(); // will re-show below + hpbar_health.show(); // don't need to hide() if/when width is 0 + + int oldleft = geoI.left(); + geoI.setLeft(geoH.right() + 1); + geoI.setRight(hix); + hpbar_injury.setGeometry(geoI); + w = geoI.right() - geoI.left() + 1; + styleI.sprintf(styleformat, barcolors[colorindx][1], w, w); + hpbar_injury.setStyleSheet(styleI); + if (geoI.left() != oldleft) + hpbar_injury.move(geoI.left(), geoI.top()); + hpbar_injury.show(); + + alreadyfullhp = false; + } else if (!alreadyfullhp) { // skip if unchanged + // health is full + colorindx = 0; // black | (not used) + + hpbar_injury.hide(); + geoI.setLeft(hix); // hix + 1 + hpbar_injury.setGeometry(geoI); + + geoH.setRight(hix); + hpbar_health.setGeometry(geoH); + w = geoH.right() - geoH.left() + 1; + styleH.sprintf(styleformat, barcolors[colorindx][0], w, w); + hpbar_health.setStyleSheet(styleH); + hpbar_health.show(); + + alreadyfullhp = true; + } + } else { + // hitpoint bar is disabled + hpbar_health.hide(); + hpbar_injury.hide(); + alreadyfullhp = false; + } } /* @@ -355,56 +671,104 @@ void NetHackQtStatusWindow::fadeHighlighting() * the other. So only do our update when we update the second line. * * Information on the first line: - * name, attributes, alignment, score + * name, Str/Dex/&c characteristics, alignment, score * * Information on the second line: * dlvl, gold, hp, power, ac, {level & exp or HD **} - * status (hunger, conf, halu, stun, sick, blind), time, encumbrance + * status (hunger, encumbrance, sick, stun, conf, halu, blind), time * - * [**] HD is shown instead of level and exp if mtimedone is non-zero. + * [**] HD is shown instead of level and exp when hero is polymorphed. */ void NetHackQtStatusWindow::updateStats() { if (!parentWidget()) return; + if (cursy != 0) return; /* do a complete update when line 0 is done */ QString buf; - const char *text; - if (cursy != 0) return; /* do a complete update when line 0 is done */ - - if (ACURR(A_STR) > 118) { - buf.sprintf("STR:%d",ACURR(A_STR)-100); - } else if (ACURR(A_STR)==118) { - buf.sprintf("STR:18/**"); - } else if(ACURR(A_STR) > 18) { - buf.sprintf("STR:18/%02d",ACURR(A_STR)-18); - } else { - buf.sprintf("STR:%d",ACURR(A_STR)); + if (first_set) { + // set toggle-detection flags for optional fields + was_polyd = Upolyd ? true : false; + had_exp = ::flags.showexp ? true : false; + // not conditionalized upon '#ifdef SCORE_ON_BOTL' here + had_score = ::flags.showscore ? true : false; // false when disabled + score.setLabel(""); // init if enabled, one-time set if disabled } - str.setLabel(buf,NetHackQtLabelledIcon::NoNum,ACURR(A_STR)); + // display hitpoint bar if it is active; it isn't subject to field + // highlighting so we don't track whether it has just been toggled On|Off + HitpointBar(); - dex.setLabel("DEX:",(long)ACURR(A_DEX)); - con.setLabel("CON:",(long)ACURR(A_CON)); - intel.setLabel("INT:",(long)ACURR(A_INT)); - wis.setLabel("WIS:",(long)ACURR(A_WIS)); - cha.setLabel("CHA:",(long)ACURR(A_CHA)); - const char* hung=hu_stat[u.uhs]; + int st = ACURR(A_STR); + if (st > STR18(100)) { + buf.sprintf("Str:%d", st - 100); // 19..25 + } else if (st == STR18(100)) { + buf.sprintf("Str:18/**"); // 18/100 + } else if (st > 18) { + buf.sprintf("Str:18/%02d", st - 18); // 18/01..18/99 + } else { + buf.sprintf("Str:%d", st); // 3..18 + } + str.setLabel(buf, NetHackQtLabelledIcon::NoNum, (long) st); + dex.setLabel("Dex:", (long) ACURR(A_DEX)); + con.setLabel("Con:", (long) ACURR(A_CON)); + intel.setLabel("Int:", (long) ACURR(A_INT)); + wis.setLabel("Wis:", (long) ACURR(A_WIS)); + cha.setLabel("Cha:", (long) ACURR(A_CHA)); + + boolean spreadout = (::iflags.wc2_statuslines != 2); + int k = 0; // number of conditions shown + + long qt_uhs = 0L; + const char *hung = hu_stat[u.uhs]; if (hung[0]==' ') { - hunger.hide(); + if (!hunger.isHidden()) { + hunger.setLabel("", NetHackQtLabelledIcon::NoNum, qt_uhs); + hunger.hide(); + } } else { + // satiated is worse (due to risk of death from overeating) + // than not-hungry and we'll treat it as also worse than hungry, + // but better than weak or fainting; the u.uhs enum values + // order them differently so we jump through a hoop + switch (u.uhs) { + case NOT_HUNGRY: qt_uhs = 0L; break; + case HUNGRY: qt_uhs = 1L; break; + case SATIATED: qt_uhs = 2L; break; + case WEAK: qt_uhs = 3L; break; + case FAINTING: qt_uhs = 4L; break; + default: qt_uhs = 5L; break; // fainted, starved + } hunger.setIcon(u.uhs ? p_hungry : p_satiated); - hunger.setLabel(hung); - hunger.show(); + hunger.setLabel(hung, NetHackQtLabelledIcon::NoNum, qt_uhs); + hunger.ForceResize(); + ++k, hunger.show(); } - if (Confusion) confused.show(); else confused.hide(); + long encindx = (long) near_capacity(); + const char *enc = enc_stat[encindx]; + if (enc[0]==' ' || !enc[0]) { + if (!encumber.isHidden()) { + encumber.setLabel("", NetHackQtLabelledIcon::NoNum, encindx); + encumber.hide(); + } + } else { + encumber.setIcon(p_encumber[encindx - 1]); + encumber.setLabel(enc, NetHackQtLabelledIcon::NoNum, encindx); + encumber.ForceResize(); + ++k, encumber.show(); + } + + if (Stoned) ++k, stoned.show(); else stoned.hide(); + if (Slimed) ++k, slimed.show(); else slimed.hide(); + if (Strangled) ++k, strngld.show(); else strngld.hide(); if (Sick) { - if (u.usick_type & SICK_VOMITABLE) { - sick_fp.show(); + /* FoodPois or TermIll or both */ + if (u.usick_type & SICK_VOMITABLE) { /* food poisoning */ + ++k, sick_fp.show(); } else { sick_fp.hide(); } - if (u.usick_type & SICK_NONVOMITABLE) { - sick_il.show(); + if (u.usick_type & SICK_NONVOMITABLE) { /* terminally ill */ + ++k, sick_il.show(); } else { sick_il.hide(); } @@ -412,94 +776,176 @@ void NetHackQtStatusWindow::updateStats() sick_fp.hide(); sick_il.hide(); } - if (Blind) { - blind.setLabel("Blind"); - blind.show(); - } else { - blind.hide(); - } - if (Stunned) stunned.show(); else stunned.hide(); - if (Hallucination) hallu.show(); else hallu.hide(); - const char* enc=enc_stat[near_capacity()]; - if (enc[0]==' ' || !enc[0]) { - encumber.hide(); - } else { - encumber.setIcon(p_encumber[near_capacity()-1]); - encumber.setLabel(enc); - encumber.show(); - } - if (u.mtimedone) { - buf = nh_capitalize_words(mons[u.umonnum].mname); + if (Stunned) ++k, stunned.show(); else stunned.hide(); + if (Confusion) ++k, confused.show(); else confused.hide(); + if (Hallucination) ++k, hallu.show(); else hallu.hide(); + if (Blind) ++k, blind.show(); else blind.hide(); + if (Deaf) ++k, deaf.show(); else deaf.hide(); + + // flying is blocked when levitating, so Lev and Fly are mutually exclusive + if (Levitation) ++k, lev.show(); else lev.hide(); + if (Flying) ++k, fly.show(); else fly.hide(); + if (u.usteed) ++k, ride.show(); else ride.hide(); + + if (Upolyd) { + buf = nh_capitalize_words(pmname(&mons[u.umonnum], + ::flags.female ? FEMALE : MALE)); } else { buf = rank_of(u.ulevel, g.pl_character[0], ::flags.female); } QString buf2; - buf2.sprintf("%s the %s", g.plname, buf.toLatin1().constData()); + char buf3[BUFSZ]; + buf2.sprintf("%s the %s", upstart(strcpy(buf3, g.plname)), + buf.toLatin1().constData()); name.setLabel(buf2, NetHackQtLabelledIcon::NoNum, u.ulevel); - char buf3[BUFSZ]; - if (describe_level(buf3)) { - dlevel.setLabel(buf3,true); - } else { - buf.sprintf("%s, level ", g.dungeons[u.uz.dnum].dname); - dlevel.setLabel(buf,(long)::depth(&u.uz)); + if (!describe_level(buf3)) { + Sprintf(buf3, "%s, level %d", + g.dungeons[u.uz.dnum].dname, ::depth(&u.uz)); } + dlevel.setLabel(buf3); - gold.setLabel("Au:", money_cnt(g.invent)); - - if (u.mtimedone) { - // You're a monster! - - buf.sprintf("/%d", u.mhmax); - hp.setLabel("HP:", u.mh > 0 ? u.mh : 0, buf); - level.setLabel("HD:",(long)mons[u.umonnum].mlevel); + int poly_toggled = !was_polyd ^ !Upolyd; + int exp_toggled = !had_exp ^ !::flags.showexp; + if (poly_toggled) + // for this update, changed values aren't better|worse, just different + hp.setCompareMode(NeitherIsBetter); + if (poly_toggled || exp_toggled) + level.setCompareMode(NeitherIsBetter); + if (Upolyd) { + // You're a monster! + buf.sprintf("/%d", u.mhmax); + hp.setLabel("HP:", std::max((long) u.mh, 0L), buf); + level.setLabel("HD:", (long) mons[u.umonnum].mlevel); // hit dice + // Exp points are not shown when HD is displayed instead of Xp level } else { - // You're normal. - - buf.sprintf("/%d", u.uhpmax); - hp.setLabel("HP:", u.uhp > 0 ? u.uhp : 0, buf); - level.setLabel("Level:",(long)u.ulevel); + // You're normal. + buf.sprintf("/%d", u.uhpmax); + hp.setLabel("HP:", std::max((long) u.uhp, 0L), buf); + // if Exp points are to be displayed, append them to Xp level; + // up/down highlighting becomes tricky--don't try very hard; + // depending upon font size and status layout, "Level:NN/nnnnnnnn" + // might be too wide to fit + static const char *const lvllbl[3] = { "Level:", "Lvl:", "L:" }; + QFontMetrics fm(level.label->font()); + for (int i = ::flags.showexp ? 0 : 3; i < 4; ++i) { + // passes 0,1,2 are with Exp, 3 is without Exp and always fits + if (i < 3) { + buf.sprintf("%s%ld/%ld", lvllbl[i], (long) u.ulevel, u.uexp); + } else { + buf.sprintf("%s%ld", lvllbl[i - 3], (long) u.ulevel); + } + // +2: allow a couple of pixels at either end to be clipped off + if (fm.size(0, buf).width() <= (2 + level.label->width() + 2)) + break; + } + level.setLabel(buf, NetHackQtLabelledIcon::NoNum, + // if we intended to show Exp but must settle + // for Xp due to width, we still want to use + // Exp for setLabel()'s Up|Down highlighting + ::flags.showexp ? u.uexp : (long) u.ulevel); } + if (poly_toggled) + // for next update, changed values will be better|worse as usual + hp.setCompareMode(BiggerIsBetter); + if (poly_toggled || exp_toggled) + level.setCompareMode(BiggerIsBetter); + was_polyd = Upolyd ? true : false; + had_exp = (::flags.showexp && !was_polyd) ? true : false; + buf.sprintf("/%d", u.uenmax); - power.setLabel("Pow:", u.uen, buf); - ac.setLabel("AC:",(long)u.uac); -#ifdef EXP_ON_BOTL - if (::flags.showexp) { - exp.setLabel("Exp:",(long)u.uexp); - } else -#endif - { - exp.setLabel(""); - } - if (u.ualign.type==A_CHAOTIC) { - align.setIcon(p_chaotic); - text = "Chaotic"; - } else if (u.ualign.type==A_NEUTRAL) { - align.setIcon(p_neutral); - text = "Neutral"; + power.setLabel("Pow:", (long) u.uen, buf); + ac.setLabel("AC:", (long) u.uac); + // gold prefix used to be "Au:", tty uses "$:"; never too wide to fit; + // practical limit due to carrying capacity limit is less than 300K + long goldamt = money_cnt(g.invent); + goldamt = std::max(goldamt, 0L); // sanity; core's botl() does likewise + goldamt = std::min(goldamt, 99999999L); // ditto + gold.setLabel("Gold:", goldamt); + + const char *text = NULL; + if (u.ualign.type == A_LAWFUL) { + align.setIcon(p_lawful); + text = "Lawful"; + } else if (u.ualign.type == A_NEUTRAL) { + align.setIcon(p_neutral); + text = "Neutral"; } else { - align.setIcon(p_lawful); - text = "Lawful"; + // Unaligned should never happen but handle it sanely if it does + align.setIcon(p_chaotic); + text = (u.ualign.type == A_CHAOTIC) ? "Chaotic" + : (u.ualign.type == A_NONE) ? "unaligned" + : "other?"; } - align.setLabel(text); + align.setLabel(QString(text)); + // without this, the ankh pixmap shifts from centered to left + // justified relative to the label text for some unknown reason... + align.ForceResize(); + if (spreadout) + ++k; // when not condensed, Alignment is shown on the Conditions row - if (::flags.time) time.setLabel("Time:",(long)g.moves); - else time.setLabel(""); -#ifdef SCORE_ON_BOTL - if (::flags.showscore) { - score.setLabel("Score:",(long)botl_score()); + if (!k) { + blank2.show(); // for vertical spacing: force the row to be non-empty } else -#endif - { - score.setLabel(""); - } + blank2.hide(); - if (first_set) - { + // Time isn't highlighted (due to constantly changing) so we don't keep + // track of whether it has just been toggled On or Off + if (::flags.time) { + // hypothetically Time could grow to enough digits to have trouble + // fitting, but it's not worth worrying about + time.setLabel("Time:", (long) g.moves); + } else { + time.setLabel(""); + } +#ifdef SCORE_ON_BOTL + int score_toggled = !had_score ^ !::flags.showscore; + if (::flags.showscore) { + if (score_toggled) // toggled On + score.setCompareMode(NeitherIsBetter); + long pts = botl_score(); + if (spreadout) { + // plenty of room; Time and Score both have the width of 3 fields + score.setLabel("Score:", pts); + } else { + // depending upon font size and status layout, "Score:nnnnnnnn" + // might be too wide to fit (simpler version of Level:NN/nnnnnnnn) + static const char *const scrlbl[3] = { "Score:", "Scr:", "S:" }; + QFontMetrics fm(score.label->font()); + for (int i = 0; i < 3; ++i) { + buf.sprintf("%s%ld", scrlbl[i], pts); + // +2: allow couple of pixels at either end to be clipped off + if (fm.size(0, buf).width() <= (2 + score.width() + 2)) + break; + } + score.setLabel(buf, NetHackQtLabelledIcon::NoNum, pts); + // with Xp/Exp, we fallback to Xp if the shortest label prefix + // is still too long; here we just show a clipped value and + // let user either live with it or turn 'showscore' off (or + // set statuslines:3 to take advantage of the extra room that + // the spread out status layout provides) + } + } else { + if (score_toggled) { // toggled Off; if already Off, no need to set "" + score.setCompareMode(NoCompare); + score.setLabel(""); // blank when not active + } + } + if (score_toggled) + score.setCompareMode(BiggerIsBetter); + had_score = ::flags.showscore ? true : false; +#endif /* SCORE_ON_BOTL */ + + if (first_set) { first_set=false; + /* + * Default compareMode is BiggerIsBetter: an increased value + * is an improvement. + */ name.highlightWhenChanging(); - dlevel.highlightWhenChanging(); + dlevel.highlightWhenChanging(); + dlevel.setCompareMode(NeitherIsBetter); str.highlightWhenChanging(); dex.highlightWhenChanging(); @@ -508,25 +954,44 @@ void NetHackQtStatusWindow::updateStats() wis.highlightWhenChanging(); cha.highlightWhenChanging(); - gold.highlightWhenChanging(); hp.highlightWhenChanging(); power.highlightWhenChanging(); - ac.highlightWhenChanging(); ac.lowIsGood(); + ac.highlightWhenChanging(); + ac.setCompareMode(SmallerIsBetter); level.highlightWhenChanging(); - exp.highlightWhenChanging(); - align.highlightWhenChanging(); + gold.highlightWhenChanging(); - //time.highlightWhenChanging(); + // don't highlight 'time' because it changes almost continuously + // [if we did highlight it, we wouldn't show increase as 'Better'] + //time.highlightWhenChanging(); time.setCompareMode(NeitherIsBetter); score.highlightWhenChanging(); + align.highlightWhenChanging(); + align.setCompareMode(NeitherIsBetter); + hunger.highlightWhenChanging(); - confused.highlightWhenChanging(); + hunger.setCompareMode(SmallerIsBetter); + encumber.highlightWhenChanging(); + encumber.setCompareMode(SmallerIsBetter); + stoned.highlightWhenChanging(); + slimed.highlightWhenChanging(); + strngld.highlightWhenChanging(); sick_fp.highlightWhenChanging(); sick_il.highlightWhenChanging(); - blind.highlightWhenChanging(); stunned.highlightWhenChanging(); + confused.highlightWhenChanging(); hallu.highlightWhenChanging(); - encumber.highlightWhenChanging(); + blind.highlightWhenChanging(); + deaf.highlightWhenChanging(); + // the default behavior is to highlight a newly shown condition + // as "worse" but that isn't appropriate for 'other' conds; + // NetHackQtLabelledIcon::show() uses NeitherIsBetter to handle it + lev.highlightWhenChanging(); + lev.setCompareMode(NeitherIsBetter); + fly.highlightWhenChanging(); + fly.setCompareMode(NeitherIsBetter); + ride.highlightWhenChanging(); + ride.setCompareMode(NeitherIsBetter); } } @@ -537,4 +1002,11 @@ void NetHackQtStatusWindow::checkTurnEvents() { } +// clicking on status window runs #attributes (^X) +void NetHackQtStatusWindow::mousePressEvent(QMouseEvent *event UNUSED) +{ + QWidget *main = NetHackQtBind::mainWidget(); + (static_cast (main))->FuncAsCommand(doattributes); +} + } // namespace nethack_qt_ diff --git a/win/Qt/qt_stat.h b/win/Qt/qt_stat.h index 73d7d8eca..c09fae6c4 100644 --- a/win/Qt/qt_stat.h +++ b/win/Qt/qt_stat.h @@ -27,6 +27,7 @@ public: void fadeHighlighting(); protected: + virtual void mousePressEvent(QMouseEvent *event); //RLC void resizeEvent(QResizeEvent*); private slots: @@ -45,22 +46,38 @@ private: QPixmap p_chaotic; QPixmap p_neutral; QPixmap p_lawful; + QPixmap p_blank2; // conditionally used for vertical spacing QPixmap p_satiated; QPixmap p_hungry; - - QPixmap p_confused; - QPixmap p_sick_fp; - QPixmap p_sick_il; - QPixmap p_blind; - QPixmap p_stunned; - QPixmap p_hallu; - QPixmap p_encumber[5]; - NetHackQtLabelledIcon name; - NetHackQtLabelledIcon dlevel; + QPixmap p_stoned; + QPixmap p_slimed; + QPixmap p_strngld; + QPixmap p_sick_fp; + QPixmap p_sick_il; + QPixmap p_stunned; + QPixmap p_confused; + QPixmap p_hallu; + QPixmap p_blind; + QPixmap p_deaf; + QPixmap p_lev; + QPixmap p_fly; + QPixmap p_ride; + /* + * Status fields, in display order (the three separator lines + * are exceptions). Hitpoint bar is optionally displayed and + * contains two side-by-side parts; neither part is labelled. + */ + QLabel hpbar_health; // hit point bar, left half + QLabel hpbar_injury; // hit point bar, right half + NetHackQtLabelledIcon name; // (aka title) centered on its own row + NetHackQtLabelledIcon dlevel; // (aka location) likewise + + /* the six characteristics; each is shown with a 40x40 icon above + and a text label below, so implicitly two rows */ NetHackQtLabelledIcon str; NetHackQtLabelledIcon dex; NetHackQtLabelledIcon con; @@ -68,34 +85,67 @@ private: NetHackQtLabelledIcon wis; NetHackQtLabelledIcon cha; - NetHackQtLabelledIcon gold; - NetHackQtLabelledIcon hp; - NetHackQtLabelledIcon power; - NetHackQtLabelledIcon ac; - NetHackQtLabelledIcon level; - NetHackQtLabelledIcon exp; - NetHackQtLabelledIcon align; + /* five various status fields, some showing two values, shown as + a row of text only; 'exp' used to be a separate field but is + now displayed with 'level', with a blank field where it was so + that there continue to be six columns which line up beneath the + characteristics; gold used to be left-most but doesn't warrant + that position; Xp or Xp/Exp is replaced by HD when polymorphed */ + NetHackQtLabelledIcon hp; // current HP / maximum HP + NetHackQtLabelledIcon power; // current energy / maximum energy + NetHackQtLabelledIcon ac; // armor class + NetHackQtLabelledIcon level; // Xp level / Exp points (if 'showexp') + NetHackQtLabelledIcon blank1; // pads the line to six columns + NetHackQtLabelledIcon gold; // used to come before HP - NetHackQtLabelledIcon time; - NetHackQtLabelledIcon score; + /* next row: two more fields, possibly blank; when present, each + is sized as if for three fields, so their centered values line + up with 2nd and 5th columns of the rows above */ + NetHackQtLabelledIcon time; // moves counter (if 'time' is set) + NetHackQtLabelledIcon score; // tentative score (if compiled with + // SCORE_ON_BOTL and 'showscore' is set) - NetHackQtLabelledIcon hunger; - NetHackQtLabelledIcon confused; + /* last rows: alignment and zero or more status conditions; + like the characteristics, they are shown as if in two rows with + a 40x40 icon above and text lebel below; blank values are omitted + and non-blank values are left justified */ + NetHackQtLabelledIcon align; // w/ alignment-specific ankh icon + NetHackQtLabelledIcon blank2; // used for spacing if Align is moved + NetHackQtLabelledIcon hunger; // blank if 'normal' + NetHackQtLabelledIcon encumber; // blank if 'unencumbered' ('normal') + /* zero or more status conditions; in major, minor, 'other' order */ + NetHackQtLabelledIcon stoned; + NetHackQtLabelledIcon slimed; + NetHackQtLabelledIcon strngld; NetHackQtLabelledIcon sick_fp; NetHackQtLabelledIcon sick_il; - NetHackQtLabelledIcon blind; NetHackQtLabelledIcon stunned; + NetHackQtLabelledIcon confused; NetHackQtLabelledIcon hallu; - NetHackQtLabelledIcon encumber; + NetHackQtLabelledIcon blind; + NetHackQtLabelledIcon deaf; + NetHackQtLabelledIcon lev; + NetHackQtLabelledIcon fly; + NetHackQtLabelledIcon ride; - QFrame hline1; - QFrame hline2; - QFrame hline3; + QFrame hline1; // between dlevel and characteristics + QFrame hline2; // between characteristics and regular status fields + QFrame hline3; // between regular fields and time,score or conditions + QFrame vline1; // for statuslines:2, between Cha and Alignment + QFrame vline2; // for statuslines:2, padding between Gold and Time int cursy; - bool first_set; + bool alreadyfullhp; + // for some fields, we need to know more than just "changed since + // last update"; there's no 'had_time' because Time isn't highlighted + bool was_polyd; + bool had_exp; + bool had_score; + + QHBoxLayout *InitHitpointBar(); + void HitpointBar(); void nullOut(); void updateStats(); void checkTurnEvents(); diff --git a/win/Qt/qt_str.cpp b/win/Qt/qt_str.cpp index fc9cd26d7..1a6de3f90 100644 --- a/win/Qt/qt_str.cpp +++ b/win/Qt/qt_str.cpp @@ -13,14 +13,14 @@ namespace nethack_qt_ { // Bounded string copy size_t str_copy(char *dest, const char *src, size_t max) { - size_t len = strlen(src); + size_t len = 0; if (max != 0) { - size_t csize = len; + len = strlen(src); if (len > max - 1) { len = max - 1; } - memcpy(dest, src, csize); - dest[csize] = '\0'; + memcpy(dest, src, len); + dest[len] = '\0'; } return len; } @@ -35,7 +35,7 @@ QString str_titlecase(const QString& str) QString nh_capitalize_words(const QString& str) { QStringList words = str.split(" "); - for (size_t i = 0; i < words.size(); ++i) { + for (size_t i = 0; i < (size_t) words.size(); ++i) { words[i] = str_titlecase(words[i]); } return words.join(" "); diff --git a/win/Qt/qt_streq.cpp b/win/Qt/qt_streq.cpp index c489e5800..04fed5ca9 100644 --- a/win/Qt/qt_streq.cpp +++ b/win/Qt/qt_streq.cpp @@ -4,23 +4,19 @@ // qt_streq.cpp -- string requestor +extern "C" { #include "hack.h" -#undef Invisible -#undef Warning -#undef index -#undef msleep -#undef rindex -#undef wizard -#undef yn -#undef min -#undef max +} +#include "qt_pre.h" #include #if QT_VERSION >= 0x050000 #include #endif +#include "qt_post.h" #include "qt_streq.h" #include "qt_str.h" +#include "qt_set.h" namespace nethack_qt_ { @@ -28,15 +24,19 @@ namespace nethack_qt_ { void centerOnMain(QWidget *); // end temporary -NetHackQtStringRequestor::NetHackQtStringRequestor(QWidget *parent, const char* p, const char* cancelstr) : +NetHackQtStringRequestor::NetHackQtStringRequestor(QWidget *parent, + const char *p, const char *cancelstr, const char *okaystr) : QDialog(parent), prompt(QString::fromLatin1(p),this), input(this,"input") { + if (qt_settings) + input.setFont(qt_settings->normalFixedFont()); + cancel=new QPushButton(cancelstr,this); connect(cancel,SIGNAL(clicked()),this,SLOT(reject())); - okay=new QPushButton("Okay",this); + okay = new QPushButton(okaystr, this); connect(okay,SIGNAL(clicked()),this,SLOT(accept())); connect(&input,SIGNAL(returnPressed()),this,SLOT(accept())); okay->setDefault(true); @@ -49,50 +49,60 @@ void NetHackQtStringRequestor::resizeEvent(QResizeEvent*) const int margin=5; const int gutter=5; - int h=(height()-margin*2-gutter); - + int h = (height() - margin * 2 - gutter); + int w = (width() - margin * 2 - gutter); + int ifw = input.hasFrame() ? 3 : 0; // hack alert for input.frameWidth() if (prompt.text().size() > 16) { - h/=3; - prompt.setGeometry(margin,margin,width()-margin*2,h); - input.setGeometry(width()*1/5,margin+h+gutter, - (width()-margin-2-gutter)*4/5,h); + h /= 3; + prompt.setGeometry(margin + ifw * 2 + 1, margin, w + gutter, h); + input.setGeometry(width() * 1 / 5 - ifw, margin + h + gutter, + w * 4 / 5, h); } else { - h/=2; - prompt.setGeometry(margin,margin,(width()-margin*2-gutter)*2/5,h); - input.setGeometry(prompt.geometry().right()+gutter,margin, - (width()-margin-2-gutter)*3/5,h); + h /= 2; + prompt.setGeometry(margin + ifw * 2 + 1, margin, w * 2 / 5, h); + input.setGeometry(prompt.geometry().right() + gutter + - (ifw * 2 + 1) - ifw * 2, + margin, w * 3 / 5, h); } - cancel->setGeometry(margin,input.geometry().bottom()+gutter, - (width()-margin*2-gutter)/2,h); - okay->setGeometry(cancel->geometry().right()+gutter,cancel->geometry().y(), - cancel->width(),h); + cancel->setGeometry(margin, input.geometry().bottom() + gutter, w / 2, h); + okay->setGeometry(cancel->geometry().right() + gutter, + cancel->geometry().y(), w / 2, h); } -void NetHackQtStringRequestor::SetDefault(const char* d) +void NetHackQtStringRequestor::SetDefault(const char *d) { input.setText(d); } -bool NetHackQtStringRequestor::Get(char* buffer, int maxchar) +bool NetHackQtStringRequestor::Get(char *buffer, int maxchar, int minchar) { - input.setMaxLength(maxchar); - if (prompt.text().size() > 16) { - resize(fontMetrics().width(prompt.text())+50,fontMetrics().height()*6); - } else { - resize(fontMetrics().width(prompt.text())*2+50,fontMetrics().height()*4); - } + input.setMaxLength(maxchar - 1); + + const QString &txt = prompt.text(); + int pw = fontMetrics().width(txt), + ww = minchar * input.fontMetrics().width(QChar('X')); + int heightfactor = ((txt.size() > 16) ? 3 : 2) * 2; // 2 or 3 lines high + int widthfudge = (((txt.size() > 16) ? 1 : 2) * 5) * 2; // 5: margn, guttr + resize(pw + ww + widthfudge, fontMetrics().height() * heightfactor); #ifdef EDIT_GETLIN input.setText(buffer); #endif centerOnMain(this); show(); + // Make sure that setFocus() really does change keyboard focus. + // This allows typing to go directly to the NetHackQtLineEdit + // widget without clicking on or in it first. Not needed for + // qt_getline() but is needed for menu Search to prevent typed + // characters being treated as making menu selections. + if (!input.isActiveWindow()) + input.activateWindow(); input.setFocus(); exec(); if (result()) { - str_copy(buffer,input.text().toLatin1().constData(),maxchar); + str_copy(buffer, input.text().toLatin1().constData(), maxchar); return true; } else { return false; diff --git a/win/Qt/qt_streq.h b/win/Qt/qt_streq.h index 12fd0a776..89894dc03 100644 --- a/win/Qt/qt_streq.h +++ b/win/Qt/qt_streq.h @@ -19,10 +19,13 @@ private: QPushButton* cancel; public: - NetHackQtStringRequestor(QWidget *parent, const char* p,const char* cancelstr="Cancel"); - void SetDefault(const char*); - bool Get(char* buffer, int maxchar=80); - virtual void resizeEvent(QResizeEvent*); + NetHackQtStringRequestor(QWidget *parent, const char *p, + const char *cancelstr = "Cancel", + const char *okaystr = "Okay"); + void SetDefault(const char *); + // maxchar is size of buffer[], minchar is size of line edit widget + bool Get(char *buffer, int maxchar = 80, int minchar = 20); + virtual void resizeEvent(QResizeEvent *); }; } // namespace nethack_qt_ diff --git a/win/Qt/qt_svsel.cpp b/win/Qt/qt_svsel.cpp index 6950afd79..219fa7d5b 100644 --- a/win/Qt/qt_svsel.cpp +++ b/win/Qt/qt_svsel.cpp @@ -3,69 +3,104 @@ // NetHack may be freely redistributed. See license for details. // qt_svsel.cpp -- saved game selector +// +// Popup's layout: +//---- +// NetHack 3.7.x (literal text w/ dynamic version number) +// /----------------------\ +// | | +// | | +// | splash image | nhsplash.xpm (red dragon w/ rider) +// | | +// | | +// \----------------------/ +// by the NetHack DevTeam (literal text) +// [ Quit ] [New-Game] side-by-side buttons +// Saved characters (literal text in small font) +// [ character one ] button with character name +// [ character two ] button with another character name +// [ character three ] button with yet another character name +// ... 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 +// enchancement: instead of just showing the character name, show +// "name-role-race-gender-alignment". +// +extern "C" { #include "hack.h" -#undef Invisible -#undef Warning -#undef index -#undef msleep -#undef rindex -#undef wizard -#undef yn -#undef min -#undef max +} +#include "qt_pre.h" #include #if QT_VERSION >= 0x050000 #include #endif +#include "qt_post.h" #include "qt_svsel.h" #include "qt_bind.h" #include "qt_str.h" namespace nethack_qt_ { +// +// popup dialog at start of game to choose between a new game or which save +// file to load if user has at least one saved game and either hasn't supplied +// any character name or has supplied one which doesn't have a save file +// NetHackQtSavedGameSelector::NetHackQtSavedGameSelector(const char** saved) : QDialog(NetHackQtBind::mainWidget()) { QVBoxLayout *vbl = new QVBoxLayout(this); QHBoxLayout* hb; - QLabel* logo = new QLabel(this); vbl->addWidget(logo); + char cvers[BUFSZ]; + QString qvers = QString("NetHack ") + QString(version_string(cvers)); + QLabel *vers = new QLabel(qvers, this); + vers->setAlignment(Qt::AlignCenter); + vbl->addWidget(vers); + + QLabel *logo = new QLabel(this); logo->setAlignment(Qt::AlignCenter); logo->setPixmap(QPixmap("nhsplash.xpm")); - QLabel* attr = new QLabel("by the NetHack DevTeam",this); + vbl->addWidget(logo); + + QLabel *attr = new QLabel("by the NetHack DevTeam", this); attr->setAlignment(Qt::AlignCenter); vbl->addWidget(attr); vbl->addStretch(2); - /* - QLabel* logo = new QLabel(hb); - hb = new QHBox(this); - vbl->addWidget(hb, Qt::AlignCenter); - logo->setPixmap(QPixmap(nh_icon)); - logo->setAlignment(AlignRight|Qt::AlignVCenter); - new QLabel(nh_attribution,hb); - */ + /* With Qt5, this next line triggers a complaint to stderr: +QLayout: Attempting to add QLayout "" to QDialog "", which already has a layout hb = new QHBoxLayout(this); + */ + hb = new QHBoxLayout((QWidget *) NULL); vbl->addLayout(hb, Qt::AlignCenter); - QPushButton* q = new QPushButton("Quit",this); + + QPushButton *q = new QPushButton("Quit", this); hb->addWidget(q); connect(q, SIGNAL(clicked()), this, SLOT(reject())); - QPushButton* c = new QPushButton("New Game",this); + QPushButton *c = new QPushButton("New Game", this); hb->addWidget(c); connect(c, SIGNAL(clicked()), this, SLOT(accept())); c->setDefault(true); - QGroupBox* box = new QGroupBox("Saved Characters",this); - QButtonGroup *bg = new QButtonGroup(this); - vbl->addWidget(box); - QVBoxLayout *bgl = new QVBoxLayout(box); + QGroupBox *box = new QGroupBox("Saved Characters", this); + QVBoxLayout *bgl = new QVBoxLayout(); + QButtonGroup *bg = new QButtonGroup(); connect(bg, SIGNAL(buttonPressed(int)), this, SLOT(done(int))); - for (int i=0; saved[i]; i++) { - QPushButton* b = new QPushButton(saved[i],box); - bg->addButton(b, i+2); + for (int i = 0; saved[i]; ++i) { + QPushButton *b = new QPushButton(saved[i]); + bgl->addWidget(b); + bg->addButton(b, i + 2); } + box->setLayout(bgl); + vbl->addWidget(box); } int NetHackQtSavedGameSelector::choose() @@ -74,7 +109,7 @@ int NetHackQtSavedGameSelector::choose() if ( qt_compact_mode ) showMaximized(); #endif - return exec()-2; + return exec() - 2; } } // namespace nethack_qt_ diff --git a/win/Qt/qt_win.cpp b/win/Qt/qt_win.cpp index 8c4ecac04..670ae8da8 100644 --- a/win/Qt/qt_win.cpp +++ b/win/Qt/qt_win.cpp @@ -2,7 +2,7 @@ // Qt4 conversion copyright (c) Ray Chason, 2012-2014. // NetHack may be freely redistributed. See license for details. -// Qt Binding for NetHack 3.4 +// Qt Windowing interface for NetHack 3.7 // // Copyright (C) 1996-2001 by Warwick W. Allison (warwick@troll.no) // @@ -22,7 +22,7 @@ // and also because this is my first major application of Qt. // // The problem of NetHack's getkey requirement is solved by intercepting -// key events by overiding QApplicion::notify(...), and putting them in +// key events by overiding QApplication::notify(...), and putting them in // a buffer. Mouse clicks on the map window are treated with a similar // buffer. When the NetHack engine calls for a key, one is taken from // the buffer, or if that is empty, QApplication::exec() is called. @@ -43,24 +43,22 @@ // This includes all the definitions we need from the NetHack main // engine. We pretend MSC is a STDC compiler, because C++ is close // enough, and we undefine NetHack macros which conflict with Qt -// identifiers. +// identifiers (now done in qt_pre.h). #define QT_DEPRECATED_WARNINGS +extern "C" { #include "hack.h" -#undef Invisible -#undef Warning -#undef index -#undef msleep -#undef rindex -#undef wizard -#undef yn -#undef min -#undef max +} +#include "qt_pre.h" #include #if QT_VERSION >= 0x050000 #include #endif +#include "qt_post.h" + +// Many of these headers are not needed here. It's a holdover +// from when most of the Qt code was in one big file. #include "qt_win.h" #include "qt_bind.h" #include "qt_click.h" @@ -73,30 +71,8 @@ #include "qt_msg.h" #include "qt_set.h" -#include - #include "qt_clust.h" -#include - -#ifdef _WS_X11_ -// For userid control -#include -#endif - -#ifdef USER_SOUNDS -#if QT_VERSION >= 0x050000 -# include -# else -# include -# endif -#endif - - -#ifdef USER_SOUNDS -extern void play_sound_for_message(const std::string& str); -#endif - namespace nethack_qt_ { void @@ -119,18 +95,22 @@ NetHackQtWindow::~NetHackQtWindow() // XXX Use "expected ..." for now, abort or default later. // void NetHackQtWindow::Clear() { puts("unexpected Clear"); } -void NetHackQtWindow::Display(bool block) { puts("unexpected Display"); } +void NetHackQtWindow::Display(bool block UNUSED) { puts("unexpected Display"); } bool NetHackQtWindow::Destroy() { return true; } -void NetHackQtWindow::CursorTo(int x,int y) { puts("unexpected CursorTo"); } -void NetHackQtWindow::PutStr(int attr, const QString& text) { puts("unexpected PutStr"); } -void NetHackQtWindow::StartMenu() { puts("unexpected StartMenu"); } -void NetHackQtWindow::AddMenu(int glyph, const ANY_P* identifier, char ch, char gch, int attr, - const QString& str, unsigned itemflags) { puts("unexpected AddMenu"); } -void NetHackQtWindow::EndMenu(const QString& prompt) { puts("unexpected EndMenu"); } -int NetHackQtWindow::SelectMenu(int how, MENU_ITEM_P **menu_list) { puts("unexpected SelectMenu"); return 0; } -void NetHackQtWindow::ClipAround(int x,int y) { puts("unexpected ClipAround"); } -void NetHackQtWindow::PrintGlyph(int x,int y,int glyph) { puts("unexpected PrintGlyph"); } +void NetHackQtWindow::CursorTo(int x UNUSED,int y UNUSED) { puts("unexpected CursorTo"); } +void NetHackQtWindow::PutStr(int attr UNUSED, const QString& text UNUSED) { puts("unexpected PutStr"); } +void NetHackQtWindow::StartMenu(bool using_WIN_INVEN UNUSED) + { puts("unexpected StartMenu"); } +void NetHackQtWindow::AddMenu(int glyph UNUSED, const ANY_P* identifier UNUSED, + char ch UNUSED, char gch UNUSED, int attr UNUSED, + const QString& str UNUSED, unsigned itemflags UNUSED) + { puts("unexpected AddMenu"); } +void NetHackQtWindow::EndMenu(const QString& prompt UNUSED) { puts("unexpected EndMenu"); } +int NetHackQtWindow::SelectMenu(int how UNUSED, MENU_ITEM_P **menu_list UNUSED) + { puts("unexpected SelectMenu"); return 0; } +void NetHackQtWindow::ClipAround(int x UNUSED,int y UNUSED) { puts("unexpected ClipAround"); } +void NetHackQtWindow::PrintGlyph(int x UNUSED,int y UNUSED,int glyph UNUSED, unsigned *glyphmod UNUSED) { puts("unexpected PrintGlyph"); } //void NetHackQtWindow::PrintGlyphCompose(int x,int y,int,int) { puts("unexpected PrintGlyphCompose"); } -void NetHackQtWindow::UseRIP(int how, time_t when) { puts("unexpected UseRIP"); } +void NetHackQtWindow::UseRIP(int how UNUSED, time_t when UNUSED) { puts("unexpected UseRIP"); } } // namespace nethack_qt_ diff --git a/win/Qt/qt_win.h b/win/Qt/qt_win.h index 486bf4ec6..681b06be1 100644 --- a/win/Qt/qt_win.h +++ b/win/Qt/qt_win.h @@ -2,8 +2,9 @@ // Qt4 conversion copyright (c) Ray Chason, 2012-2014. // NetHack may be freely redistributed. See license for details. -// Qt Binding for NetHack 3.4 +// Qt Binding for NetHack 3.7 // +// [original comment from Warwick] // Unfortunately, this doesn't use Qt as well as I would like, // primarily because NetHack is fundamentally a getkey-type // program rather than being event driven (hence the ugly key @@ -21,24 +22,25 @@ public: NetHackQtWindow(); virtual ~NetHackQtWindow(); - virtual QWidget* Widget() =0; + virtual QWidget* Widget() = 0; virtual void Clear(); virtual void Display(bool block); virtual bool Destroy(); - virtual void CursorTo(int x,int y); + virtual void CursorTo(int x, int y); virtual void PutStr(int attr, const QString& text); void PutStr(int attr, const char *text) { PutStr(attr, QString::fromUtf8(text).replace(QChar(0x200B), "")); } - virtual void StartMenu(); - virtual void AddMenu(int glyph, const ANY_P* identifier, char ch, char gch, int attr, - const QString& str, unsigned itemflags); + virtual void StartMenu(bool using_WIN_INVEN = false); + virtual void AddMenu(int glyph, const ANY_P* identifier, + char ch, char gch, int attr, + const QString& str, unsigned itemflags); virtual void EndMenu(const QString& prompt); virtual int SelectMenu(int how, MENU_ITEM_P **menu_list); - virtual void ClipAround(int x,int y); - virtual void PrintGlyph(int x,int y,int glyph); + virtual void ClipAround(int x, int y); + virtual void PrintGlyph(int x, int y, int glyph, unsigned *glyphmod); virtual void UseRIP(int how, time_t when); int nhid; diff --git a/win/Qt/qt_xcmd.cpp b/win/Qt/qt_xcmd.cpp index a994d4eae..686ce0490 100644 --- a/win/Qt/qt_xcmd.cpp +++ b/win/Qt/qt_xcmd.cpp @@ -3,135 +3,560 @@ // NetHack may be freely redistributed. See license for details. // qt_xcmd.cpp -- extended command widget +// +// TODO: +// Maybe extend filtering to be able to omit commands that can be invoked +// by a 'normal' keystroke (not Meta) with current key bindings, or to +// exclude commands which don't autocomplete to match '#?'. +// Either disable [Layout] when prompt has a partial response, or +// preserve that partial response across widget tear-down/rebuild. +// Maybe make the number of grid columns user settable? Or a way to +// specify a different font (smaller might be necessary for some folks; +// the font set up in "Qt settings" or "Preferences" applies to the +// message and status windows but not to extended command choosing). +// +// +// Widget appearance (excluding window title bar): +// +----------------------------------------------------+ +// | [Cancel] [Filter] [Layout] [Reset] | control buttons +// |# Extended commands | text entry & title +// +----------------------------------------------------+ +// | [cmmnd_1] [cmnd_14] ... [cmnd_92] [cmd_105] | boxed grid of... +// | [cmmnd_2] [cmnd_15] ... [cmnd_93] [cmd_106] | ...command buttons +// ... +// | [cmnd_13] [cmnd_26] ... [cmd_104] blank | +// +----------------------------------------------------+ +// +// Typed input gets appended to "#". When enough to be unambiguous has +// accumulated, the matching command is immediately chosen (except for +// the prefix special case mentioned for [Cancel]); +// Title is centered and describes which [sub]set of commands are shown. +// It shares the prompt line to conserve vertical space. +// [Cancel] is highlighted as the default and applies if is typed, +// with special handling when player has typed up to the end of one +// command which is a prefix of another; there, or is +// used to select the shorter while still providing opportunity to type +// more of the longer command; (there are several such cases: +// "#drop[type]", "#known[class]", "#takeoff[all]", "#version[short]"); +// button is left justitied (prior to addition of the filter/layout/reset +// buttons, [Cancel] stretched all the way across the top of the widget); +// [Filter] is grayed out when outside wizard mode; when in wizard mode, +// it cycles through "all commands", "normal mode commands only", and +// "wizard mode extra commands only"; [if it ever gets extended to do +// anything in normal play, it will need a more substantial interface +// than repeated clicks but those seem adequate for present wizard +// mode-only usage]; +// [Layout] toggles between displaying the command buttons down columns +// (as shown above) versus across rows ([cmd_1][cmd_2]...[cmd_9], &c); +// [Reset] clears typed partial response, if any, and sets filtering back +// to "all commands" and/or toggles layout back to by-column if either +// of those differ from their defaults; +// [cmd_N] are buttons labelled with command names; clicking returns the +// index for the name. +// +// Changing filter or layout returns xcmdNoMatch to qt_get_ext_cmd() which +// then calls us again (current filter and layout are kept in qt_settings +// so persist, not just through return and call back but across games); +// much simpler than reorganizing the button grid's contents on the fly. +// Current grid size with SHELL and SUSPEND enabled is 13x9 for all +// commands, 13x7 for normal mode commands, and 7x4 (when by-column) or +// 4x7 (if by-row) for wizard mode commands. Column counts are hardcoded +// and row counts are adjusted to fit (the command list, not the screen). +// Maybe move prompt and title above control buttons? However, menus have +// their count entry feedback positioned between control buttons and the +// rest of the information--current layout matches that. +// The popup is displayed as full-fledged window but the window title bar +// is blank (at least on OSX). +// If clicking on [Filter] or [Layout] (or [Reset], but there isn't any +// particular reason to try to run it twice in a row) places the pointer +// inside any button, clicking again won't do anything unless the pointer +// is moved (again, at least on OSX); a single pixel probably suffices. +// Possibly because despite not moving it has effectively gone into a +// whole new window since the old one gets torn down and is replaced by +// a new one that uses revised filter or layout settings. +// + +extern "C" { #include "hack.h" #include "func_tab.h" -#undef Invisible -#undef Warning -#undef index -#undef msleep -#undef rindex -#undef wizard -#undef yn -#undef min -#undef max +} +#include "qt_pre.h" #include #if QT_VERSION >= 0x050000 #include #endif +#include "qt_post.h" #include "qt_xcmd.h" #include "qt_xcmd.moc" #include "qt_bind.h" #include "qt_set.h" #include "qt_str.h" +// temporary +extern int qt_compact_mode; +// end temporary + namespace nethack_qt_ { +/* 'wizard' is #undef'd above (now in qt_pre.h) because a Qt header uses + that token, so create our own based on knowledge of 'wizard's internals */ +#define WizardMode (::flags.debug) + +extern uchar keyValue(QKeyEvent *key_event); // from qt_menu.cpp + // temporary void centerOnMain(QWidget *); // end temporary -NetHackQtExtCmdRequestor::NetHackQtExtCmdRequestor(QWidget *parent) : - QDialog(parent) +static inline bool +interesting_command(unsigned indx, int cmds) { - QVBoxLayout *l = new QVBoxLayout(this); + if (!WizardMode) + cmds = normal_cmds; - QPushButton* can = new QPushButton("Cancel", this); - can->setDefault(true); - can->setMinimumSize(can->sizeHint()); - l->addWidget(can); + // entry 0 is a no-op; don't bother displaying it in the command grid + if (indx == 0 && !strcmp("#", extcmdlist[indx].ef_txt)) + return false; + // treat '?' as both normal mode and debug mode + if (!strcmp("?", extcmdlist[indx].ef_txt)) + return true; + // some commands might have been compiled-out; don't show them + if ((extcmdlist[indx].flags & CMD_NOT_AVAILABLE) != 0) + return false; + // if picking from normal mode-only don't show wizard mode commands + // or if picking from wizard mode-only don't show normal commands + if ((cmds == normal_cmds && (extcmdlist[indx].flags & WIZMODECMD) != 0) + || (cmds == wizard_cmds && (extcmdlist[indx].flags & WIZMODECMD) == 0)) + return false; + // if we've gotten here, this command isn't filtered away, so show it + return true; +} - prompt = new QLabel("#", this); - l->addWidget(prompt); +NetHackQtExtCmdRequestor::NetHackQtExtCmdRequestor(QWidget *parent) : + QDialog(parent), + prompt(new QLabel("#", this)), + cancel_btn(new QPushButton("Cancel", this)), + byRow(qt_settings->xcmd_by_row), + set(qt_settings->xcmd_set), + butoffset(0), + exactmatchindx(xcmdNoMatch) +{ + if (!WizardMode) + set = normal_cmds; // {all,wizard}_cmds are wizard mode only - QButtonGroup *group=new QButtonGroup(this); - QGroupBox *grid=new QGroupBox("Extended commands",this); - l->addWidget(grid); + QVBoxLayout *xl = new QVBoxLayout(this); // overall xcmd layout + int butw = 50; // initial button width; will be increased if too small + // should probably use the qt_settings font size as a spacing hint; + // tiny font, tiny internal margins; small font, small margins; + // medium or bigger, default margins (9 or 11?) + int spacing = qt_compact_mode ? 3 : -1; // 0 would abut; -1 gives default - int i; - int butw=50; + // first, the popup's controls: a row of buttons along the top; + // the two padding widgets make the control buttons line up better + // with the grid of xcmd choice buttons (closer but not exactly) + QHBoxLayout *ctrls = new QHBoxLayout(); + ctrls->setSpacing(spacing); // only seems to affect horizontal, not vert. + ctrls->addWidget(new QLabel(" ")); // padding + // Cancel, created during constructor setup (accessed in other routines) + DefaultActionIsCancel(true); /* cancel_btn->setDefault(true); */ + cancel_btn->setMinimumSize(cancel_btn->sizeHint()); + butw = std::max(butw, cancel_btn->width()); + ctrls->addWidget(cancel_btn); + ctrls->addStretch(0); // Cancel will be left justified, others far right + // Filter: change the [sub]set of commands that get shown; + // presently only useful when running in wizard mode + QPushButton *filter_btn = new QPushButton("Filter", this); + if (!WizardMode) { // nothing to filter if not in wizard mode + filter_btn->setEnabled(false); // gray the [Filter] button out +#if 0 /* This works but makes [Reset] seem to be redundant. */ + // graying out may not be adequate; conceal [Filter] so that + // players without access to wizard mode won't become concerned + // about something that seems to them to always be disabled + filter_btn->hide(); +#endif + } + filter_btn->setMinimumSize(filter_btn->sizeHint()); + butw = std::max(butw, filter_btn->width()); + ctrls->addWidget(filter_btn); + // Layout: switch from by-column grid to by-row grid or vice versa + QPushButton *layout_btn = new QPushButton("Layout", this); + layout_btn->setMinimumSize(layout_btn->sizeHint()); + butw = std::max(butw, layout_btn->width()); + ctrls->addWidget(layout_btn); + // Reset: switch filter back to all commands and layout back to by-column + QPushButton *reset__btn = new QPushButton("Reset", this); + reset__btn->setMinimumSize(reset__btn->sizeHint()); + butw = std::max(butw, reset__btn->width()); + ctrls->addWidget(reset__btn); + ctrls->addWidget(new QLabel(" ")); // padding + xl->addLayout(ctrls); + + // text entry takes place below the row of control buttons and above + // the grid of command buttons; show typed text in fixed-width font + prompt->setFont(qt_settings->normalFixedFont()); + + // grid title rather than overall popup title + const char *ctitle = ((set == all_cmds) + ? "All extended commands" + : (set == normal_cmds) + ? (WizardMode ? "Normal mode extended commands" + : "Extended commands") + : (set == wizard_cmds) + ? "Debug mode extended commands" + : "(unknown)"); // won't happen + const QString &qtitle = QString(ctitle); + // rectangular grid to hold a button for each extended command name + QGroupBox *grid = new QGroupBox(); /* new QGroupBox(title, this); */ + // used to connect the buttons with their click handling routine + QButtonGroup *group = new QButtonGroup(this); + + // put grid title on same line as prompt (the padding simplifies centering) + QHBoxLayout *pl = new QHBoxLayout(); // prompt line + pl->addWidget(prompt); + QLabel *tt = new QLabel(qtitle); + tt->setAlignment(Qt::AlignHCenter); // center title horizontally + pl->addWidget(tt); + pl->addWidget(new QLabel(" ")); // padding to balance prompt + xl->addLayout(pl); + xl->addWidget(grid); + + // having the controls in the same button group as the extended command + // choices means that they use the same click callback [a holdover from + // when Cancel was the only one; using a separate group and separate + // click callback would eliminate the need for butoffset in Button()] + group->addButton(cancel_btn, butoffset), ++butoffset; // (,0), 1 + group->addButton(filter_btn, butoffset), ++butoffset; // (,1), 2 + group->addButton(layout_btn, butoffset), ++butoffset; // (,2), 3 + group->addButton(reset__btn, butoffset), ++butoffset; // (,3), 4 + + unsigned i, j, ncmds = 0; QFontMetrics fm = fontMetrics(); - for (i=0; extcmdlist[i].ef_txt; i++) { - butw = std::max(butw,30+fm.width(extcmdlist[i].ef_txt)); + // count the number of commands in current [sub]set and find the size of + // the widest choice button; starting size is from widest control button + for (i = 0; extcmdlist[i].ef_txt; ++i) { + if (interesting_command(i, set)) { + ++ncmds; + butw = std::max(butw, 30 + fm.width(extcmdlist[i].ef_txt)); + } } - int ncols=4; + // if any of the choice buttons were bigger than the control buttons, + // make the control buttons bigger to match + if (cancel_btn->width() < butw) + cancel_btn->setMinimumWidth(butw); + if (filter_btn->width() < butw) + filter_btn->setMinimumWidth(butw); + if (layout_btn->width() < butw) + layout_btn->setMinimumWidth(butw); + if (reset__btn->width() < butw) + reset__btn->setMinimumWidth(butw); - QVBoxLayout* bl = new QVBoxLayout(grid); - bl->addSpacing(fm.height()); - QGridLayout* gl = new QGridLayout(); + QVBoxLayout *bl = new QVBoxLayout(grid); + QGridLayout *gl = new QGridLayout(); + // for qt_compact_mode, put buttons closer together + gl->setSpacing(spacing); bl->addLayout(gl); - for (i=0; extcmdlist[i].ef_txt; i++) { - QPushButton* pb=new QPushButton(extcmdlist[i].ef_txt, grid); - pb->setMinimumSize(butw,pb->sizeHint().height()); - group->addButton(pb, i+1); - gl->addWidget(pb,i/ncols,i%ncols); - buttons.append(pb); + // could grow the buttons[] vector one element at a time but since we + // know the ultimate size, grow to that in one operation + buttons.resize((int) ncmds); + + /* 'ncols' could be calculated to fit (or enable a vertical scrollbar + when resulting 'nrows' is too big, if GroupBox supports that); + it used to be hardcoded 4 but after every command became accessible + as an extended command, that resulted in so many rows that some of + the grid was chopped off at the bottom of the screen and the buttons + in that portion were out of reach */ + unsigned ncols = (set == all_cmds) ? 9 + : (set == normal_cmds) ? 7 + : (set == wizard_cmds) ? (byRow ? 7 : 4) + : 1; // can't happen + unsigned nrows = (ncmds + ncols - 1) / ncols; + /* + * Grid layout: by-column is the default. Can be toggled by clicking + * on the [Layout] control button. + * + * by-row vs by-column + * a b c a e i + * d e f b f j + * g h i c g - + * j - - d h - + */ + for (i = j = 0; extcmdlist[i].ef_txt; ++i) { + if (interesting_command(i, set)) { + QString btn_lbl = extcmdlist[i].ef_txt; + if (btn_lbl == "wait") + btn_lbl += " (rest)"; + QPushButton *pb = new QPushButton(btn_lbl, grid); + pb->setMinimumSize(butw, pb->sizeHint().height()); + // force the button to have fixed width or it can move around a + // pixel or two (tiny but visibly noticeable) when enableButtons() + // hides whole columns [see stretch comment below] + pb->setMaximumSize(pb->minimumSize()); + // i+butoffset is value that will be passed to the click handler + group->addButton(pb, i + butoffset); + /* + * by column: xcmd_by_row==false, the default + * 0..R-1 down first column, R..2*R-1 down second column, ... + * otherwise: by row + * 0..C-1 across first row, C..2*C-1 across second row, ... + */ + unsigned row = !byRow ? j % nrows : j / ncols; + unsigned col = !byRow ? j / nrows : j % ncols; + gl->addWidget(pb, row, col); + // these stretch settings prevent the grid from becoming very + // ugly when enableButtons() disables whole rows and/or columns + // as typed characters reduce the pool of possible matches + if (row == 0) + gl->setColumnStretch(col, 1); + if (col == 0) + gl->setRowStretch(row, 1); + + // buttons[] vector is used by enableButtons() + buttons[j] = pb; // buttons.append(pb); + ++j; + } } - group->addButton(can, 0); - connect(group,SIGNAL(buttonPressed(int)),this,SLOT(done(int))); + + connect(group, SIGNAL(buttonPressed(int)), this, SLOT(Button(int))); bl->activate(); - l->activate(); + xl->activate(); resize(1,1); } -void NetHackQtExtCmdRequestor::cancel() +// Click handler for the ExtCmdRequestor widget +int NetHackQtExtCmdRequestor::Button(int butnum) +{ + // 0..3 are control buttons, 4..N+3 are choice buttons. + // Widget return value is -1 for cancel (via reject), xcmdNoMatch + // for filter, layout, reset (via accept if circumstances warrant), + // 1..N for command choices (choice 0 is '#' and it isn't shown as + // a candidate since picking it is not useful). + switch (butnum) { + case 0: + Cancel(); + /*NOTREACHED*/ + break; + case 1: + Filter(); + break; + case 2: + Layout(); + break; + case 3: + Reset(); + break; + default: + // 4..N-3 are the extended commands + done(butnum - butoffset + 1); + /*NOTREACHED*/ + break; + } + return 0; +} + +// Respond to a click on the [Cancel] button +void NetHackQtExtCmdRequestor::Cancel() { reject(); + /*NOTREACHED*/ } +// Respond to a click on the [Filter] button +void NetHackQtExtCmdRequestor::Filter() +{ + // TEMP: step from one [sub]set to the next, then wrap back to the first. + if (++set > std::max(std::max(all_cmds, normal_cmds), wizard_cmds)) + set = std::min(std::min(all_cmds, normal_cmds), wizard_cmds); + + // TODO: put up a popup--dialog or maybe simple pick-one menu--that + // has player choose between all_cmds, normal_cmds, wizard_cmds. + // Only meaningful for wizard mode so maybe the temp version suffices. + + if (set != qt_settings->xcmd_set) { + Retry(); + /*NOTREACHED*/ + } + return; +} + +// Respond to a click on the [Layout] button +void NetHackQtExtCmdRequestor::Layout() +{ + byRow = !byRow; + Retry(); + /*NOTREACHED*/ +} + +// Respond to a click on the [Reset] button +void NetHackQtExtCmdRequestor::Reset() +{ + // clear any typed text first (in case future changes are made to + // remember it across accept (retry); that would be intended for the + // [Layout] case rather than for [Reset]) + bool clearprompt = (prompt->text() != "#"); + if (clearprompt) + prompt->setText("#"); + + int teardown = 0; + if (set != (WizardMode ? all_cmds : normal_cmds)) + set = all_cmds, ++teardown; + if (byRow) + byRow = false, ++teardown; + if (teardown) { + Retry(); + /*NOTREACHED*/ + } + + if (clearprompt) { // was a subset, now need to show full set + DefaultActionIsCancel(true); // in case keyPressEvent cleared it + enableButtons(); // redraws the grid after discarding typed text above + } +} + +// Return to ExtCmdRequestor::get()'s caller in order to be called back +void NetHackQtExtCmdRequestor::Retry() +{ + // remember the current settings; they'll persist until changed again + qt_settings->updateXcmd(byRow, set); + + // return to qt_get_ext_cmd() and have it run ExtCmdRequestor again; + // current selection grid will be torn down, then new one created; + setResult(xcmdNoMatch); + accept(); + /*NOTREACHED*/ +} + +#define Ctrl(c) (0x1f & (c)) /* ASCII */ +// Note: we don't necessarily have access to a terminal to query +// it for user's preferred kill character, so use hardcoded ^U. +// Player who prefers something else can cope by using ESC instead. +#define KILL_CHAR Ctrl('u') + +// Receive the next character of typed input void NetHackQtExtCmdRequestor::keyPressEvent(QKeyEvent *event) { - QString text = event->text(); - if (text == "\r" || text == "\n" || text == " " || text == "\033") - { - reject(); - } - else if (text == "\b") - { - QString promptstr = prompt->text(); - if (promptstr != "#") - prompt->setText(promptstr.left(promptstr.size()-1)); + /* + * This will select a command outright--as soon as enough chars + * to not be ambiguous are entered--but also narrows down visible + * choices [via enableButtons()] in the grid of clickable command + * buttons as the text-so-far makes many become impossible to match. + * Use of backspace/delete or ESC/kill restores suppressed choices + * to the grid as they become matchable again. + */ + + unsigned saveexactmatchindx = exactmatchindx; + // if previous KeyPressEvent cleared default, restore it now + DefaultActionIsCancel(true); + QString promptstr = prompt->text(); + uchar uc = keyValue(event); + + if (!uc) { + // shift or control or meta, another character should be coming + QWidget::keyPressEvent(event); + } else if (uc == '\033' || uc == KILL_CHAR) { + // when partial response is present kills that text + // but keeps prompting; when response is empty cancels. + // Kill gets rid of pending text, if any, and always re-prompts. + if (uc == '\033' && promptstr == "#") + reject(); // cancel() if ESC used when string is empty + prompt->setText("#"); // reset to empty ('#' is always present) enableButtons(); - } - else - { - QString promptstr = prompt->text() + text; + } else if (uc == '\b' || uc == '\177') { + if (promptstr != "#") + prompt->setText(promptstr.left(promptstr.size() - 1)); + enableButtons(); + } else if ((uc < ' ' && !(uc == '\n' || uc == '\r')) + || uc > std::max('z', 'Z')) { + reject(); // done() + } else { + /* + * or is necessary if one command is a + * leading substring of another and superfluous otherwise. + * (When a command is not a prefix of another, it will have + * been selected before reaching its last letter.) + * + * If we got an exact match with the last key, we're expecting + * a or to explicitly choose it now but might + * get next letter of the longer command (or get a backspace). + * + * If we get an exact match this time, then stop showing + * [Cancel] as the default action for . + * (That's a visual cue for the player, not a requirement to + * prevent from triggering the default action.) + * If it's not the default action upon the next key press, + * we'll change that back (done above). + * + * TODO? + * Implement support: if promptstr matches multiple + * commands but they all have the next one or more letters in + * common, allow to add the common letters to promptstr. + */ + bool checkexact = (uc == '\n' || uc == '\r' || uc == ' '); + if (!checkexact) { + // force lower case instead of rejecting upper case + if (isupper(uc)) + uc = tolower(uc); + promptstr += QChar(uc); // add new char to typed text + } QString typedstr = promptstr.mid(1); // skip the '#' unsigned matches = 0; - unsigned match = 0; - for (unsigned i=0; extcmdlist[i].ef_txt; i++) { - if (QString(extcmdlist[i].ef_txt).startsWith(typedstr)) { - ++matches; - if (matches >= 2) - break; - match = i; + unsigned matchindx = 0; + for (unsigned i = 0; extcmdlist[i].ef_txt; ++i) { + if (!interesting_command(i, set)) + continue; + const QString &cmdtxt = QString(extcmdlist[i].ef_txt); + if (cmdtxt.startsWith(typedstr)) { + bool is_exact = (cmdtxt == typedstr); + if (checkexact) { + if (is_exact) { + matchindx = i; + matches = 1; + break; + } + } else { + if (is_exact) + DefaultActionIsCancel(false, i); // clear default + if (++matches >= 2) + break; + matchindx = i; + } } } - if (matches == 1) - done(match+1); - else if (matches >= 2) + if (matches == 1) { + done(matchindx + 1); + } else if (checkexact) { + // or without a pending exact match; cancel + reject(); + } else if (matches >= 2) { + // update the text-so-far prompt->setText(promptstr); + } else if (saveexactmatchindx != xcmdNoMatch) { + // had a pending exact match but typed something other than + // which didn't yield another match; prompt string + // hasn't been updated so still have a pending exact match + DefaultActionIsCancel(false, saveexactmatchindx); + } enableButtons(); } } +// Actual widget execution, used after calling NetHackQtExtCmdRequestor(). int NetHackQtExtCmdRequestor::get() { - const int none = -10; resize(1,1); // pack centerOnMain(this); // Add any keys presently buffered to the prompt - setResult(none); - while (NetHackQtBind::qt_kbhit() && result() == none) { + setResult(xcmdNone); + while (NetHackQtBind::qt_kbhit() && result() == xcmdNone) { int ch = NetHackQtBind::qt_nhgetch(); QKeyEvent event(QEvent::KeyPress, 0, Qt::NoModifier, QChar(ch)); keyPressEvent(&event); } - if (result() == none) + if (result() == xcmdNone) exec(); - return result()-1; + return result() - 1; } // Enable only buttons that match the current prompt string @@ -140,8 +565,14 @@ void NetHackQtExtCmdRequestor::enableButtons() QString typedstr = prompt->text().mid(1); // skip the '#' std::size_t len = typedstr.size(); + // This used to look really bad when whole rows became empty: the + // grid shrank and the one line prompt area expanded to fill the + // vacated vertical space. Hiding whole columns looked bad too, + // remaining buttons were widened to take the space. Now the grid is + // forced to have fixed layout (via stretch settings in constructor). for (auto b = buttons.begin(); b != buttons.end(); ++b) { - (*b)->setVisible((*b)->text().left(len) == typedstr); + bool showit = ((*b)->text().left(len) == typedstr); + (*b)->setVisible(showit); } } diff --git a/win/Qt/qt_xcmd.h b/win/Qt/qt_xcmd.h index fe8b027a6..52df63a52 100644 --- a/win/Qt/qt_xcmd.h +++ b/win/Qt/qt_xcmd.h @@ -9,6 +9,9 @@ namespace nethack_qt_ { +enum xcmdSets { all_cmds = 0, normal_cmds = 1, wizard_cmds = 2 }; +enum xcmdMisc { xcmdNone = -10, xcmdNoMatch = 9999 }; + class NetHackQtExtCmdRequestor : public QDialog { Q_OBJECT @@ -21,11 +24,33 @@ public: private: QLabel *prompt; + QPushButton *cancel_btn; QVector buttons; + bool byRow; // local copy of qt_settings->xcmd_by_row; + int set; // local copy of qt_settings->xcmd_set; + int butoffset; // number of control buttons (cancel, filter, &c) + unsigned exactmatchindx; + void enableButtons(); + void Cancel(); // not selecting a command after all + void Filter(); // choose command set (all, normal mode, wizard mode) + void Layout(); // by-column vs by-row for button grid + void Reset(); // go back to default filter and layout + + void Retry(); // returns to caller in order to be called back... + // ...and restart with revised settings + + inline void DefaultActionIsCancel(bool make_it_so, + unsigned matchindx = xcmdNoMatch) + { + if (!make_it_so ^ !cancel_btn->isDefault()) { + cancel_btn->setDefault(make_it_so); + exactmatchindx = matchindx; + } + } private slots: - void cancel(); + int Button(int); // click handler }; } // namespace nethack_qt_ diff --git a/win/Qt/qt_xpms.h b/win/Qt/qt_xpms.h index 5667c13c0..43b055e34 100644 --- a/win/Qt/qt_xpms.h +++ b/win/Qt/qt_xpms.h @@ -1,5 +1,65 @@ +// qt_xpms.h - static xpm arrays for use in status display +// +// In alhpabetical order by array name. Probably not the best ordering... + /* clang-format off */ + +// blank icon for use as placeholder /* XPM */ +static const char *blank_xpm[] = { +/* width height ncolors chars_per_pixel */ +"40 40 5 1", +/* colors */ +" c #000000", +". c None", +/* not used here */ +"X c #909090", +"o c #606060", +"O c #303030", +/* pixels */ +"........................................", +"........................................", +"........................................", +"........................................", +"........................................", +"........................................", +"........................................", +"........................................", +"........................................", +"........................................", +"........................................", +"........................................", +"........................................", +"........................................", +"........................................", +"........................................", +"........................................", +"........................................", +"........................................", +"........................................", +"........................................", +"........................................", +"........................................", +"........................................", +"........................................", +"........................................", +"........................................", +"........................................", +"........................................", +"........................................", +"........................................", +"........................................", +"........................................", +"........................................", +"........................................", +"........................................", +"........................................", +"........................................", +"........................................", +"........................................" +}; + +// Characteristics, Alignment, and Conditions static const char *blind_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 5 1", @@ -253,6 +313,49 @@ static const char *confused_xpm[] = { "* c #303030", "= c #6C91B6", /* pixels */ +#if 1 +/* mirror image of original; confused brain is facing the other way */ +"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", +"OOOOOOO+.OO+O+OO.O+.=OO+.=.OOOOOOOOOOOOO", +"OOOOOO+O=++==+O=+=====O=====++OOOOOOOOOO", +"OOOOO+=O+==OO===++++=.=====.=+OOOOOOOOOO", +"OOOO======OoO&+===o==o=+.===+=OOOOOOOOOO", +"O.O.=+==+Oo&o==oO&&&&o=+OO====+O+OOOOOOO", +"O=+=O==Oooo&=ooo&o&oOooo=o&&+==O+=+.+OOO", +"O==++==+o&==o=oo&&o&=&oo=oo===O++OOOOOOO", +"OO=======oo&&o&oo&o&OO&o====O=.o=OOOOOOO", +"OOOO=====O&o=oOOoooo=Ooo=O=O=+===oOOOOOO", +"OOOO+===O=o=O====oo=O=======+==+OOOOOOOO", +"OOOOO======O========O====+=X=#=.OOOOOOOO", +"OOOO+==OO==========O====%#=.++oX#.OOOOOO", +"OOOO+==+=+=O====+====X==.=#.+#+#oX+OOOOO", +"OOOOO.OO+o===##Xo====.X=#.##===O+.+.OOOO", +"OOOO+=oOO=...+#O#X#==+#.o##O#O####+#OOOO", +"OOOOo=OO+==+X+#.X#+#.O#.#++++X+#+o#++OOO", +"OOOOOOO..+##+#XX+..#++#++X##.+X..+.+#OOO", +"OOOOOOO#+#+..X#+#+X+#++.+#++#+O....##OOO", +"OOOOOO$X.++#.##++.#XX#X#X+O#+#.+.+#++OOO", +"OOOOO**+##X+X+###X+##+++.++#+++.+#+#OOOO", +"OOOO@ *#+#+X#+.++..+.###o##.+#OO#..#OOOO", +"OOOO$ *#.+###++##+###.+++.O#+#+O#.#+OOOO", +"OOOO* ###+#.##..+#++##X..o#+#+#+XXOOOOO", +"OOOO %%XX%####+..+#.+#+#+#+X#.#XOOOOOO", +"OOOO* %.=++X.+#+#+#++.#+#+#.X%%.OOOOOOO", +"OOOO$ %#%%%%XX+.####O.+#+##* *.OOOOOOOO", +"OOOO$ X#+++.=XXX+++#.+.X% .OOOOOOOOOO", +"OOOO$ *X%####.=%X#..X%% *.OOOOOOOOOOO", +"OOOOO *=###%X#.=%%%XX* $.OOOOOOOOOOOOO", +"OOOOO@ *=#.+.#%%=%%%+OOOOOOOOOOOOOOOOO", +"OOOOOO *%X##X==%%%=oOOOOOOOOOOOOOOOOO", +"OOOOOO@ *%=X%%%%X+OOOOOOOOOOOOOOOOOO", +"OOOOOOO@* X%%%%XOOOOOOOOOOOOOOOOOOO", +"OOOOOOOOO$$* *X%%%=OOOOOOOOOOOOOOOOOOO", +"OOOOOOOOOOOOO. =%%X+OOOOOOOOOOOOOOOOOOO", +"OOOOOOOOOOOOOO %%%XOOOOOOOOOOOOOOOOOOOO", +"OOOOOOOOOOOOOO$ *%%=OOOOOOOOOOOOOOOOOOOO", +"OOOOOOOOOOOOOO$ %%%=OOOOOOOOOOOOOOOOOOOO", +"OOOOOOOOOOOOOO$ %%%+OOOOOOOOOOOOOOOOOOOO" +#else "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOO.=.+OO=.+O.OO+O+OO.+OOOOOO", "OOOOOOOOOOO++=====O=====+=O+==++=O+OOOOO", @@ -293,6 +396,56 @@ static const char *confused_xpm[] = { "OOOOOOOOOOOOOOOOOOOOO=%%* $OOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOO=%%% $OOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOO+%%% $OOOOOOOOOOOOO" +#endif +}; +/* XPM */ +static const char *deaf_xpm[] = { // placeholder for Deaf condition +/* width height ncolors chars_per_pixel */ +"40 40 2 1", +/* colors */ +"X c None", +"o c #dfdf40", +/* pixels */ +"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooXXXXooooooooooooooooooooooooooooX", +"XooooooXoooXoooooooooooooooooooooooooooX", +"XooooooXoooXoooooooooooooooooooooooooooX", +"XooooooXoooXoooooooooooooooooooooooooooX", +"XooooooXoooXoooooooooooooooooooooooooooX", +"XooooooXoooXooXXXXXooooooooooooooooooooX", +"XooooooXXXXoooXooooooooooooooooooooooooX", +"XoooooooooooooXooooooooooooooooooooooooX", +"XoooooooooooooXXXXoooooooooooooooooooooX", +"XoooooooooooooXooooooooooooooooooooooooX", +"XoooooooooooooXooooooooXoooooooooooooooX", +"XoooooooooooooXXXXXoooXoXooooooooooooooX", +"XooooooooooooooooooooXoooXoooooooooooooX", +"XooooooooooooooooooooXoooXoooooooooooooX", +"XooooooooooooooooooooXXXXXoooooooooooooX", +"XooooooooooooooooooooXoooXooXXXXXooooooX", +"XooooooooooooooooooooXoooXooXooooooooooX", +"XoooooooooooooooooooooooooooXooooooooooX", +"XoooooooooooooooooooooooooooXXXXoooooooX", +"XoooooooooooooooooooooooooooXooooooooooX", +"XoooooooooooooooooooooooooooXooooooooooX", +"XoooooooooooooooooooooooooooXooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" }; /* XPM */ static const char *dex_xpm[] = { @@ -421,6 +574,104 @@ static const char *ext_enc_xpm[] = { "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO" }; /* XPM */ +static const char *fly_xpm[] = { // placeholder for Flying condition +/* width height ncolors chars_per_pixel */ +"40 40 2 1", +/* colors */ +"X c None", +"o c #7fefef", +/* pixels */ +"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooXoooXoooooooooooX", +"XooooooooooooooooooooooXoooXoooooooooooX", +"XoooooooooooooooooXoooooXoXooooooooooooX", +"XoooooooooooooooooXoooooXoXooooooooooooX", +"XooooooooooXXXXXooXooooooXoooooooooooooX", +"XooooooooooXooooooXooooooXoooooooooooooX", +"XooooooooooXooooooXooooooXoooooooooooooX", +"XooooooooooXXXXoooXooooooooooooooooooooX", +"XooooooooooXooooooXXXXoooooooooooooooooX", +"XooooooooooXoooooooooooooooooooooooooooX", +"XooooooooooXoooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" +}; +/* XPM */ +static const char *lev_xpm[] = { // placeholder for Levitating condition +/* width height ncolors chars_per_pixel */ +"40 40 2 1", +/* colors */ +"X c None", +"o c #df1010", +/* pixels */ +"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooXoooooXoooooooooX", +"XooooooooooooooooooooooXoooooXoooooooooX", +"XoooooooooooooooXXXXXoooXoooXooooooooooX", +"XoooooooooooooooXoooooooXoooXooooooooooX", +"XoooooooooXoooooXooooooooXoXoooooooooooX", +"XoooooooooXoooooXXXXoooooXoXoooooooooooX", +"XoooooooooXoooooXoooooooooXooooooooooooX", +"XoooooooooXoooooXooooooooooooooooooooooX", +"XoooooooooXoooooXXXXXooooooooooooooooooX", +"XoooooooooXooooooooooooooooooooooooooooX", +"XoooooooooXXXXoooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" +}; +/* XPM */ static const char *hallu_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 30 1", @@ -917,47 +1168,53 @@ static const char *ovr_enc_xpm[] = { "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO" }; /* XPM */ -static const char *pet_mark_xpm[] = { +static const char *ride_xpm[] = { // placeholder for Riding condition /* width height ncolors chars_per_pixel */ -"8 7 2 1", +"40 40 2 1", /* colors */ -". c None", -" c #FF0000", +"X c None", +"o c #df7f00", /* pixels */ -"........", -".. . .", -". ", -". ", -".. .", -"... ..", -".... ..." -}; -/* XPM */ -static const char *pet_mark_small_xpm[] = { -/* width height ncolors chars_per_pixel */ -"5 5 2 1", -/* colors */ -". c None", -"X c #FF0000", -/* pixels */ -".X.X.", -"XXXXX", -".XXX.", -"..X.." -}; -/* XPM */ -static const char *pile_mark_xpm[] = { -/* width height ncolors chars_per_pixel */ -"5 5 2 1", -/* colors */ -". c None", -"X c #00FF00", -/* pixels */ -"..X..", -"..X..", -"XXXXX", -"..X..", -"..X.." +"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XoooooooXXXXoooXXXooXXXXoooXXXXXoooooooX", +"XoooooooXoooXoooXoooXoooXooXoooooooooooX", +"XoooooooXoooXoooXoooXoooXooXoooooooooooX", +"XoooooooXXXXooooXoooXoooXooXXXXooooooooX", +"XoooooooXoXoooooXoooXoooXooXoooooooooooX", +"XoooooooXooXooooXoooXoooXooXoooooooooooX", +"XoooooooXoooXooXXXooXXXXoooXXXXXoooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" }; /* XPM */ static const char *satiated_xpm[] = { @@ -1177,6 +1434,55 @@ static const char *sick_il_xpm[] = { "#################$#$####################" }; /* XPM */ +static const char *slime_xpm[] = { // placeholder for Slimed condition +/* width height ncolors chars_per_pixel */ +"40 40 2 1", +/* colors */ +"X c None", +"o c #40df40", +/* pixels */ +"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooXXXoooooooooooooooooooooooooooooooX", +"XoooXooooooooooooooooooooooooooooooooooX", +"XoooXooooooooooooooooooooooooooooooooooX", +"XooooXXXoooooooooooooooooooooooooooooooX", +"XoooooooXooooooooooooooooooooooooooooooX", +"XoooooooXooXoooooooooooooooooooooooooooX", +"XooooXXXoooXoooooooooooooooooooooooooooX", +"XooooooooooXoooooooooooooooooooooooooooX", +"XooooooooooXoooooooooooooooooooooooooooX", +"XooooooooooXooooooXXXooooooooooooooooooX", +"XooooooooooXoooooooXoooooooooooooooooooX", +"XooooooooooXXXXXoooXoooooooooooooooooooX", +"XooooooooooooooooooXoooooooooooooooooooX", +"XooooooooooooooooooXoooooooooooooooooooX", +"XooooooooooooooooooXoooXoooooXoooooooooX", +"XoooooooooooooooooXXXooXXoooXXoooooooooX", +"XooooooooooooooooooooooXXXoXXXoooooooooX", +"XooooooooooooooooooooooXoXXXoXoooooooooX", +"XooooooooooooooooooooooXooXooXoooooooooX", +"XooooooooooooooooooooooXoooooXooXXXXXooX", +"XooooooooooooooooooooooXoooooXooXooooooX", +"XoooooooooooooooooooooooooooooooXooooooX", +"XoooooooooooooooooooooooooooooooXXXXoooX", +"XoooooooooooooooooooooooooooooooXooooooX", +"XoooooooooooooooooooooooooooooooXooooooX", +"XoooooooooooooooooooooooooooooooXXXXXooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" +}; +/* XPM */ static const char *slt_enc_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 13 1", @@ -1237,6 +1543,55 @@ static const char *slt_enc_xpm[] = { "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO" }; /* XPM */ +static const char *stone_xpm[] = { // placeholder for Stoned condition +/* width height ncolors chars_per_pixel */ +"40 40 2 1", +/* colors */ +"X c None", +"o c #6c91b6", +/* pixels */ +"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooXXXoooooooooooooooooooooooooooooooX", +"XoooXooooooooooooooooooooooooooooooooooX", +"XoooXooooooooooooooooooooooooooooooooooX", +"XooooXXXoooooooooooooooooooooooooooooooX", +"XoooooooXooooooooooooooooooooooooooooooX", +"XoooooooXooXXXXXoooooooooooooooooooooooX", +"XooooXXXoooooXoooooooooooooooooooooooooX", +"XooooooooooooXoooooooooooooooooooooooooX", +"XooooooooooooXoooooooooooooooooooooooooX", +"XooooooooooooXooooXXXooooooooooooooooooX", +"XooooooooooooXoooXoooXoooooooooooooooooX", +"XooooooooooooXoooXoooXoooooooooooooooooX", +"XooooooooooooooooXoooXoooooooooooooooooX", +"XooooooooooooooooXoooXoooooooooooooooooX", +"XooooooooooooooooXoooXooXoooXooooooooooX", +"XoooooooooooooooooXXXoooXXooXooooooooooX", +"XoooooooooooooooooooooooXXooXooooooooooX", +"XoooooooooooooooooooooooXoXoXooooooooooX", +"XoooooooooooooooooooooooXooXXooooooooooX", +"XoooooooooooooooooooooooXooXXooXXXXXoooX", +"XoooooooooooooooooooooooXoooXooXoooooooX", +"XooooooooooooooooooooooooooooooXoooooooX", +"XooooooooooooooooooooooooooooooXXXXooooX", +"XooooooooooooooooooooooooooooooXoooooooX", +"XooooooooooooooooooooooooooooooXoooooooX", +"XooooooooooooooooooooooooooooooXXXXXoooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" +}; +/* XPM */ static const char *str_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 17 1", @@ -1301,6 +1656,55 @@ static const char *str_xpm[] = { "++++++++++++++++++++++++++++++++++++++++" }; /* XPM */ +static const char *strngl_xpm[] = { // placeholder for Strangled condition +/* width height ncolors chars_per_pixel */ +"40 40 2 1", +/* colors */ +"X c None", +"o c #bf40ff", +/* pixels */ +"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooXXXoooooooooooooooooooooooooooooooooX", +"XoXooooooooooooooooooooooooooooooooooooX", +"XoXooooooooooooooooooooooooooooooooooooX", +"XoXXXXoooooooooooooooooooooooooooooooooX", +"XoooooXooooooooooooooooooooooooooooooooX", +"XoooooXooXXXXXoooooooooooooooooooooooooX", +"XooXXXoooooXoooooooooooooooooooooooooooX", +"XooooooooooXoooooooooooooooooooooooooooX", +"XooooooooooXoooooooooooooooooooooooooooX", +"XooooooooooXoooooooooooooooooooooooooooX", +"XooooooooooXooXXXXoooooooooooooooooooooX", +"XooooooooooXooXoooXooooooooooooooooooooX", +"XoooooooooooooXoooXooooooooooooooooooooX", +"XoooooooooooooXXXXoooooooooooooooooooooX", +"XoooooooooooooXoXooooooooooooooooooooooX", +"XoooooooooooooXooXoooXoooXoooooooooooooX", +"XoooooooooooooXoooXooXXooXoooooooooooooX", +"XooooooooooooooooooooXXooXoooooooooooooX", +"XooooooooooooooooooooXoXoXoooooooooooooX", +"XooooooooooooooooooooXooXXoooooooooooooX", +"XooooooooooooooooooooXooXXoooXXXoooooooX", +"XooooooooooooooooooooXoooXooXooooooooooX", +"XoooooooooooooooooooooooooooXooooooooooX", +"XoooooooooooooooooooooooooooXoXXXooooooX", +"XoooooooooooooooooooooooooooXoooXooooooX", +"XoooooooooooooooooooooooooooXoooXooXoooX", +"XooooooooooooooooooooooooooooXXXoooXoooX", +"XooooooooooooooooooooooooooooooooooXoooX", +"XooooooooooooooooooooooooooooooooooXoooX", +"XooooooooooooooooooooooooooooooooooXoooX", +"XooooooooooooooooooooooooooooooooooXoooX", +"XooooooooooooooooooooooooooooooooooXXXXX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XooooooooooooooooooooooooooooooooooooooX", +"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" +}; +/* XPM */ static const char *stunned_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 12 1", @@ -1419,4 +1823,5 @@ static const char *wis_xpm[] = { "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo" }; + /* clang-format on */ diff --git a/win/Qt/qt_yndlg.cpp b/win/Qt/qt_yndlg.cpp index 8d1caf400..836e13042 100644 --- a/win/Qt/qt_yndlg.cpp +++ b/win/Qt/qt_yndlg.cpp @@ -4,21 +4,16 @@ // qt_yndlg.cpp -- yes/no dialog +extern "C" { #include "hack.h" -#undef Invisible -#undef Warning -#undef index -#undef msleep -#undef rindex -#undef wizard -#undef yn -#undef min -#undef max +} +#include "qt_pre.h" #include #if QT_VERSION >= 0x050000 #include #endif +#include "qt_post.h" #include "qt_yndlg.h" #include "qt_yndlg.moc" #include "qt_str.h" @@ -29,16 +24,53 @@ extern int qt_compact_mode; namespace nethack_qt_ { +static const char lrq[] = "lr\033LRq"; +char altchoices[BUFSZ + 12]; + // temporary void centerOnMain(QWidget *); // end temporary -NetHackQtYnDialog::NetHackQtYnDialog(QWidget *parent,const QString& q,const char* ch,char df) : +NetHackQtYnDialog::NetHackQtYnDialog(QWidget *parent, const QString &q, + const char *ch, char df) : QDialog(parent), question(q), choices(ch), def(df), - keypress('\033') + keypress('\033'), + allow_count(false), + le((QLineEdit *) NULL), + y_btn((QPushButton *) NULL) { setWindowTitle("NetHack: Question"); + + // plain prompt doesn't show any room for an answer (answer won't be + // echoed but the fact that a prompt is pending and accepts typed + // input as an alternative to mouse click seems clearer when there + // is some space available to accept it) + if (!question.endsWith(" ") && !question.endsWith("_")) + question += " _"; // an underlined space would be better + + if (choices) { + // special handling for wearing rings; prompt asks "right or left?" + // but side-by-side buttons look better with [left][right] instead + // (assumes that we're using left to right layout) + if (!strcmp(choices, "rl")) { + choices = lrq; + if (!def) + def = 'r'; + + // if count is allowed, explicitly add the digits as valid + } else if (!strncmp(choices, "yn#", (size_t) 3)) { + ::yn_number = 0L; + allow_count = true; + + if (!strchr(choices, '9')) { + copynchars(altchoices, choices, BUFSZ - 1); + // duplicate # is intentional; explicitly separates \... and 0 + choices = strcat(altchoices, "\033#0123456789"); + } + } + } + alt_answer[0] = alt_result[0] = '\0'; } char NetHackQtYnDialog::Exec() @@ -58,9 +90,10 @@ char NetHackQtYnDialog::Exec() if ( question[c] == '-' ) ch.append(question[c++]); unsigned from=0; - while ( c < question.size() && question[c] != ']' && question[c] != ' ' ) { + while (c < question.size() + && question[c] != ']' && question[c] != ' ') { if ( question[c] == '-' ) { - from = question[c-1].unicode(); + from = question[c - 1].cell(); } else if ( from != 0 ) { for (unsigned f=from+1; f<=question[c]; f++) ch.append(QChar(f)); @@ -106,9 +139,9 @@ char NetHackQtYnDialog::Exec() } if (!ch.isNull()) { QVBoxLayout *vb = new QVBoxLayout; - bool bigq = qlabel.length()>40; - if ( bigq ) { - QLabel* q = new QLabel(qlabel,this); + bool bigq = (qlabel.length() > (qt_compact_mode ? 40 : 60)); + if (bigq) { + QLabel *q = new QLabel(qlabel, this); q->setAlignment(Qt::AlignLeft); q->setWordWrap(true); q->setMargin(4); @@ -121,60 +154,152 @@ char NetHackQtYnDialog::Exec() QButtonGroup *bgroup = new QButtonGroup(group); int nchoices=ch.length(); - - bool allow_count=ch.contains('#'); - QString yn = "yn", ynq = "ynq"; - bool is_ynq = ch == yn || ch == ynq; + // note: is_ynaq covers nyaq too because the choices string is + // "ynaq" for both; only the default differs; likewise for nyNaq + bool is_ynaq = (ch == QString("ynaq") // [Yes ][ No ][All ][Stop] + || ch == QString("yn#aq") + || ch == altchoices), // alternate "yn#aq" + is_ynq = (ch == QString("ynq")), // [ Yes ][ No ][Cancel] + is_yn = (ch == QString("yn")), // [Yes ][ No ] + is_lr = (ch == QString(lrq)); // [ Left ][Right ] const int margin=8; const int gutter=8; const int extra=fontMetrics().height(); // Extra for group int x=margin, y=extra+margin; - int butsize=fontMetrics().height()*2+5; + int butheight = fontMetrics().height() * 2 + 5, + butwidth = (butheight - 5) * ((is_ynq || is_lr) ? 3 + : (is_ynaq || is_yn) ? 2 : 1) + 5; + if (butwidth == butheight) { // square, enough room for C or ^C + // some characters will be labelled by name rather than by + // keystroke so will need wider buttons + for (int i = 0; i < nchoices; ++i) { + if (ch[i] == '\033') + break; // ESC and anything after are hidden + if (ch[i] == ' ' || ch[i] == '\n' || ch[i] == '\r') { + butwidth = (butheight - 5) * 2 + 5; + break; + } + } + } - QPushButton* button; - for (int i=0; isetEnabled(false); - } - button->setFixedSize(butsize,butsize); // Square - if (ch[i]==def) button->setDefault(true); - if (i%10==9) { - // last in row - x=margin; - y+=butsize+gutter; - } else { - x+=butsize+gutter; - } + QPushButton *button; + for (int i = 0; i < nchoices; ++i) { + bool making_y = false; + if (ch[i] == '\033') + break; // ESC and anything after are hidden + if (ch[i] == '#' && allow_count) + continue; // don't show a button for '#'; has Count box instead + QString button_name = QString(visctrl((char) ch[i].cell())); + if (is_yn || is_ynq || is_ynaq || is_lr) { + // FIXME: a better way to recognize which labels should + // use alterate text is needed + switch (ch[i].cell()) { + case 'y': + button_name = "Yes"; + making_y = true; + break; + case 'n': + button_name = "No"; + break; + case 'a': + // the display of vanquished monsters uses "ynaq" for + // convenience, where 'a' requests a sort-by menu; + // show "sort" instead of "all" and allow player to + // type either 'a' or 's' when not clicking on button + if (question.contains(QString("vanquished?"))) + button_name = "Sort", AltChoice('s', 'a'); + else + button_name = "All"; + break; + case 'q': + // most 'q' replies are actually for "cancel" but + // for "ynaq" (where "all" is a choice) it's "stop" + // and for end of game disclosure it really is "quit" + if (question.left(10) == QString("Dump core?") + || (::g.program_state.gameover + && question.left(11) == QString("Do you want"))) + button_name = "Quit"; + else if (is_ynaq) + button_name = "Stop", AltChoice('s', 'q'); + else + button_name = "Cancel", AltChoice('c', 'q'); + break; + case 'l': + button_name = "Left"; + break; + case 'r': + button_name = "Right"; + break; + } + } else { + // special characters usually aren't listed among choices + // but if they are, label the buttons for them with sensible + // names; we want to avoid "^J" and "^M" for \n and \r; + // and are equivalent to each other but + // labelling \n as newline or line-feed seems confusing; + switch (ch[i].cell()) { + case ' ': + button_name = "Spc"; + break; + case '\n': + button_name = "Ent"; + break; + case '\r': + button_name = "Ret"; + break; + case '\033': // won't happen; ESC is hidden + button_name = "Esc"; + break; + case '&': + // ampersand is used as a hidden quote char to flag + // next character as a keyboard shortcut associated + // with the current action--that's inappropriate here; + // two consecutive ampersands are needed to display + // one in a button label; first check whether caller + // has already done that, skip this one if so + if (i > 0 && ch[i - 1].cell() == QChar('&')) + continue; // next i + button_name = "&&"; + break; + } + } + button=new QPushButton(button_name); + if (making_y && allow_count) + y_btn = button; // to change default in keyPressEvent() + if (!enable.isNull()) { + if (!enable.contains(ch[i])) + button->setEnabled(false); + } + button->setFixedSize(butwidth, butheight); + if (ch[i] == def) + button->setDefault(true); + // 'x' and 'y' don't seem to actually used anywhere + // and limit of 10 buttons per row isn't enforced + if (i % 10 == 9) { + // last in row + x = margin; + y += butheight + gutter; + } else { + x += butwidth + gutter; + } groupbox->addWidget(button); bgroup->addButton(button, i); } - connect(bgroup,SIGNAL(buttonClicked(int)),this,SLOT(doneItem(int))); + connect(bgroup, SIGNAL(buttonClicked(int)), this, SLOT(doneItem(int))); - QLabel* lb=0; - QLineEdit* le=0; - - if (allow_count) { - QHBoxLayout *hb = new QHBoxLayout(this); - lb=new QLabel("Count: "); - hb->addWidget(lb); - le=new QLineEdit(); - hb->addWidget(le); - vb->addLayout(hb); + QLabel *lb = 0; + if (allow_count) { + // insert Count widget in front of [n], between [y] and [n][a][q] + lb = new QLabel("Count:"); + groupbox->insertWidget(1, lb); // [y] button is item #0, [n] is #1 + le = new QLineEdit(); + groupbox->insertWidget(2, le); // [n] became #2, Count label is #1 + le->setPlaceholderText(QString("#")); // grayed out } + // add an invisible right-most field to left justify the buttons + groupbox->addStretch(80); setLayout(vb); adjustSize(); @@ -182,23 +307,43 @@ char NetHackQtYnDialog::Exec() show(); char choice=0; char ch_esc=0; - for (uint i=0; i= 1000 ) { - choice = ch[result() - 1000].unicode(); - } - if (allow_count && !le->text().isEmpty()) { - yn_number=le->text().toInt(); - choice='#'; - } - return choice; + + // + // When a count is allowed, clicking on the count widget then + // typing in digits followed by is 'normal' operation. + // However, typing a digit without clicking first will set focus + // to the count widget with that typed digit preloaded. + // + exec(); + int res = result(); + if (res == 0) { + choice = is_lr ? '\033' : ch_esc ? ch_esc : def ? def : ' '; + } else if (res == 1) { + if (keypress) + choice = keypress; + else + choice = def ? def : ch_esc ? ch_esc : ' '; + } else if (res >= 1000) { + choice = (char) ch[res - 1000].cell(); + } + + // non-Null 'le' implies 'allow_count'; having a grayed-out '#' + // present in the QLineEdit widget doesn't affect its isEmpty() test + if (le && !le->text().isEmpty()) { + QString text(le->text()); + if (text.at(0) == QChar('#')) + text = text.mid(1); // rest of string past [0] + ::yn_number = text.toLong(); + choice = '#'; + } + keypress = choice; + } else { QLabel label(qlabel,this); QPushButton cancel("Dismiss",this); @@ -212,24 +357,56 @@ char NetHackQtYnDialog::Exec() show(); keypress = '\033'; exec(); - return keypress; + } + return keypress; +} + +void NetHackQtYnDialog::AltChoice(char ans, char res) +{ + if (ans && !strchr(alt_answer, ans)) { + (void) strkitten(alt_answer, ans); + (void) strkitten(alt_result, res); } } void NetHackQtYnDialog::keyPressEvent(QKeyEvent* event) { - // Don't want QDialog's Return/Esc behaviour - //RLC ...or do we? + keypress = '\0'; QString text(event->text()); - if (choices == NULL || choices[0] == 0) { - if (text != "") { - keypress = text.toUcs4()[0]; - done(1); - } + if (text.isEmpty()) /* && event->modifiers()) */ + return; + + keypress = text.at(0).cell(); + char *p = NULL; + if (*alt_answer && (p = strchr(alt_answer, keypress)) != 0) + keypress = alt_result[p - alt_answer]; + + if (!choices || !*choices || !keypress) { + this->done(1); + } else { - int where = QString::fromLatin1(choices).indexOf(text); - if (where != -1 && text != "#") { - done(where+1000); + int where = QString::fromLatin1(choices).indexOf(QChar(keypress)); + + if (allow_count && strchr("#0123456789", keypress)) { + if (text == "#") { + // 0 will be preselected; typing anything replaces it + le->setText(QString("0")); + le->home(true); + } else { + // digit will not be preselected; typing another appends + le->setText(text); + le->end(false); + } + // (don't know whether this actually does anything useful) + le->setAttribute(Qt::WA_KeyboardFocusChange, true); + // this is definitely useful... + le->setFocus(Qt::ActiveWindowFocusReason); + // change default button from 'n' to 'y' + if (y_btn) + y_btn->setDefault(true); + } else if (where != -1) { + this->done(where + 1000); + } else { QDialog::keyPressEvent(event); } @@ -238,7 +415,7 @@ void NetHackQtYnDialog::keyPressEvent(QKeyEvent* event) void NetHackQtYnDialog::doneItem(int i) { - done(i+1000); + this->done(i + 1000); } } // namespace nethack_qt_ diff --git a/win/Qt/qt_yndlg.h b/win/Qt/qt_yndlg.h index 079d7119f..e6c1bcdef 100644 --- a/win/Qt/qt_yndlg.h +++ b/win/Qt/qt_yndlg.h @@ -16,9 +16,16 @@ private: const char* choices; char def; char keypress; + bool allow_count; + QLineEdit *le; + QPushButton *y_btn; + + // abritrary size; might need to be more sophisicated someday + char alt_answer[26 + 1], alt_result[26 + 1]; protected: virtual void keyPressEvent(QKeyEvent*); + void AltChoice(char answer, char result); private slots: void doneItem(int); diff --git a/win/X11/Window.c b/win/X11/Window.c index 37e5ef0d6..75598dba1 100644 --- a/win/X11/Window.c +++ b/win/X11/Window.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 Window.c $NHDT-Date: 1432512808 2015/05/25 00:13:28 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ */ +/* NetHack 3.7 Window.c $NHDT-Date: 1596498371 2020/08/03 23:46:11 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.12 $ */ /* Copyright (c) Dean Luick, 1992 */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/win/X11/nh32icon b/win/X11/nh32icon index 422ad63db..cdacc920b 100644 --- a/win/X11/nh32icon +++ b/win/X11/nh32icon @@ -1,4 +1,4 @@ -/* NetHack 3.6 nh32icon $NHDT-Date: 1446457887 2015/11/02 09:51:27 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ */ +/* NetHack 3.7 nh32icon $NHDT-Date: 1597001766 2020/08/09 19:36:06 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.12 $ */ /* Copyright (C) 1993,1995,2015 by Robert Patrick Rankin */ /* NetHack may be freely redistributed. See license for details. */ @@ -10,8 +10,8 @@ static unsigned char nh32icon_bits[] = { 0xff, 0x7f, 0xfe, 0xff, 0x01, 0xc0, 0x03, 0x80, 0x01, 0x00, 0x40, 0x82, 0x21, 0x25, 0xc0, 0x83, 0x61, 0x25, 0x80, 0x81, 0xe1, 0x3d, 0x80, 0x81, 0xa1, 0x25, 0x80, 0x81, 0x21, 0x25, 0x80, 0x81, 0x01, 0x00, 0xe0, 0x87, - 0x71, 0x08, 0x90, 0x89, 0x81, 0x08, 0x80, 0x81, 0x61, 0x38, 0x80, 0x81, - 0x81, 0x48, 0x80, 0x81, 0x71, 0x32, 0x84, 0x81, 0x03, 0x00, 0x8a, 0xc1, + 0x71, 0x78, 0x90, 0x89, 0x81, 0x40, 0x80, 0x81, 0x61, 0x20, 0x80, 0x81, + 0x81, 0x10, 0x80, 0x81, 0x71, 0x12, 0x84, 0x81, 0x03, 0x00, 0x8a, 0xc1, 0x02, 0x00, 0x84, 0x41, 0x32, 0x67, 0x80, 0x41, 0xf3, 0x7f, 0x80, 0xc1, 0xf1, 0x7f, 0x84, 0x81, 0x71, 0x77, 0x8a, 0x81, 0xb1, 0x68, 0x84, 0x81, 0x71, 0x77, 0x80, 0x81, 0x71, 0x77, 0x80, 0x81, 0xb1, 0x68, 0x84, 0x81, diff --git a/win/X11/nh56icon b/win/X11/nh56icon index 69b4e8248..5de4aa8bf 100644 --- a/win/X11/nh56icon +++ b/win/X11/nh56icon @@ -1,4 +1,4 @@ -/* NetHack 3.6 nh56icon $NHDT-Date: 1446457887 2015/11/02 09:51:27 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ */ +/* NetHack 3.7 nh56icon $NHDT-Date: 1597001767 2020/08/09 19:36:07 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.11 $ */ /* Copyright (c) 1993,1995,2015 by M. Stephenson */ /* NetHack may be freely redistributed. See license for details. */ @@ -25,12 +25,12 @@ static unsigned char nh56icon_bits[] = { 0x00, 0xc0, 0x03, 0x00, 0x00, 0x38, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x38, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x38, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x38, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x38, 0x00, 0x00, - 0xc0, 0x43, 0x10, 0x21, 0x38, 0x70, 0x40, 0xc0, 0xc3, 0x10, 0x21, 0x38, - 0x88, 0x20, 0xc0, 0xc3, 0x10, 0x21, 0x38, 0x80, 0x20, 0xc0, 0x43, 0x11, - 0x21, 0x38, 0x80, 0x20, 0xc0, 0x43, 0x12, 0x3f, 0x38, 0x70, 0xe0, 0xc1, - 0x43, 0x12, 0x21, 0x38, 0x80, 0x20, 0xc2, 0x43, 0x14, 0x21, 0x38, 0x80, - 0x20, 0xc2, 0x43, 0x18, 0x21, 0x38, 0x80, 0x20, 0xc2, 0x43, 0x18, 0x21, - 0x38, 0x88, 0x2c, 0xc2, 0x43, 0x10, 0x21, 0x38, 0x70, 0xcc, 0xc1, 0x03, + 0xc0, 0x43, 0x10, 0x21, 0x38, 0x70, 0xe0, 0xc3, 0xc3, 0x10, 0x21, 0x38, + 0x88, 0x00, 0xc2, 0xc3, 0x10, 0x21, 0x38, 0x80, 0x00, 0xc2, 0x43, 0x11, + 0x21, 0x38, 0x80, 0x00, 0xc1, 0x43, 0x12, 0x3f, 0x38, 0x70, 0x00, 0xc1, + 0x43, 0x12, 0x21, 0x38, 0x80, 0x80, 0xc0, 0x43, 0x14, 0x21, 0x38, 0x80, + 0x80, 0xc0, 0x43, 0x18, 0x21, 0x38, 0x80, 0x40, 0xc0, 0x43, 0x18, 0x21, + 0x38, 0x88, 0x4c, 0xc0, 0x43, 0x10, 0x21, 0x38, 0x70, 0x4c, 0xc0, 0x03, 0x00, 0x00, 0x38, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x38, 0x00, 0x00, 0xc0, 0xfb, 0xff, 0xff, 0x39, 0xff, 0xff, 0xdf, 0x0b, 0x00, 0x80, 0x7c, 0x02, 0x00, 0xd0, 0x0b, 0x00, 0x80, 0xee, 0x02, 0x00, 0xd0, 0xfb, 0xff, diff --git a/win/X11/nh72icon b/win/X11/nh72icon index acc824d01..60043a5f2 100644 --- a/win/X11/nh72icon +++ b/win/X11/nh72icon @@ -1,4 +1,4 @@ -/* NetHack 3.6 nh72icon $NHDT-Date: 1446457888 2015/11/02 09:51:28 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ +/* NetHack 3.7 nh72icon $NHDT-Date: 1596498370 2020/08/03 23:46:10 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.9 $ */ /* Copyright (c) 1993 by M. Stephenson */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/win/X11/tile2x11.c b/win/X11/tile2x11.c index 774b6e636..762f95ba2 100644 --- a/win/X11/tile2x11.c +++ b/win/X11/tile2x11.c @@ -22,6 +22,9 @@ unsigned char tile_bytes[TILE_X * TILE_Y * (MAX_GLYPH + TILES_PER_ROW)]; unsigned char *curr_tb = tile_bytes; unsigned char x11_colormap[MAXCOLORMAPSIZE][3]; +extern void NDECL(monst_globals_init); +extern void NDECL(objects_globals_init); + /* Look up the given pixel and return its colormap index. */ static unsigned char pix_to_colormap(pix) @@ -187,6 +190,10 @@ char **argv; exit(1); } + /* without this, the comparisons check uninitialized data and won't pass */ + objects_globals_init(); + monst_globals_init(); + fp = fopen(OUTNAME, "w"); if (!fp) { Fprintf(stderr, "can't open output file\n"); diff --git a/win/X11/winX.c b/win/X11/winX.c index de4849ab7..8130c5fc6 100644 --- a/win/X11/winX.c +++ b/win/X11/winX.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 winX.c $NHDT-Date: 1577063125 2019/12/23 01:05:25 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.79 $ */ +/* NetHack 3.7 winX.c $NHDT-Date: 1596498377 2020/08/03 23:46:17 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.87 $ */ /* Copyright (c) Dean Luick, 1992 */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/win/X11/winmap.c b/win/X11/winmap.c index 2d40dd6e5..19cbe0400 100644 --- a/win/X11/winmap.c +++ b/win/X11/winmap.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 winmap.c $NHDT-Date: 1586202188 2020/04/06 19:43:08 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.35 $ */ +/* NetHack 3.7 winmap.c $NHDT-Date: 1596498372 2020/08/03 23:46:12 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.38 $ */ /* Copyright (c) Dean Luick, 1992 */ /* NetHack may be freely redistributed. See license for details. */ @@ -73,11 +73,12 @@ static void FDECL(display_cursor, (struct xwindow *)); /* Global functions ======================================================= */ void -X11_print_glyph(window, x, y, glyph, bkglyph) +X11_print_glyph(window, x, y, glyph, bkglyph, glyphmod) winid window; xchar x, y; int glyph; int bkglyph UNUSED; +unsigned *glyphmod UNUSED; { struct map_info_t *map_info; boolean update_bbox = FALSE; @@ -1295,6 +1296,8 @@ boolean inverted; int dest_x = (cur_col - COL0_OFFSET) * tile_map->square_width; int dest_y = row * tile_map->square_height; + if ((tile_map->glyphs[row][cur_col].special & MG_FEMALE)) + tile++; /* advance to the female tile variation */ src_x = (tile % TILES_PER_ROW) * tile_width; src_y = (tile / TILES_PER_ROW) * tile_height; XCopyArea(dpy, tile_pixmap, XtWindow(wp->w), diff --git a/win/X11/winmenu.c b/win/X11/winmenu.c index 9d09867ad..4390efeda 100644 --- a/win/X11/winmenu.c +++ b/win/X11/winmenu.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 winmenu.c $NHDT-Date: 1577063136 2019/12/23 01:05:36 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.35 $ */ +/* NetHack 3.7 winmenu.c $NHDT-Date: 1596498373 2020/08/03 23:46:13 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.39 $ */ /* Copyright (c) Dean Luick, 1992 */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/win/X11/winmesg.c b/win/X11/winmesg.c index 32f3909b2..67d5f457c 100644 --- a/win/X11/winmesg.c +++ b/win/X11/winmesg.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 winmesg.c $NHDT-Date: 1454811935 2016/02/07 02:25:35 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.10 $ */ +/* NetHack 3.7 winmesg.c $NHDT-Date: 1596498373 2020/08/03 23:46:13 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.12 $ */ /* Copyright (c) Dean Luick, 1992 */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/win/X11/winmisc.c b/win/X11/winmisc.c index 2f2c7684c..726ec3003 100644 --- a/win/X11/winmisc.c +++ b/win/X11/winmisc.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 winmisc.c $NHDT-Date: 1554135506 2019/04/01 16:18:26 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.44 $ */ +/* NetHack 3.7 winmisc.c $NHDT-Date: 1596498374 2020/08/03 23:46:14 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.49 $ */ /* Copyright (c) Dean Luick, 1992 */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/win/X11/winstat.c b/win/X11/winstat.c index 866d93a34..cbc0ce078 100644 --- a/win/X11/winstat.c +++ b/win/X11/winstat.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 winstat.c $NHDT-Date: 1584582374 2020/03/19 01:46:14 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.27 $ */ +/* NetHack 3.7 winstat.c $NHDT-Date: 1596498375 2020/08/03 23:46:15 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.28 $ */ /* Copyright (c) Dean Luick, 1992 */ /* NetHack may be freely redistributed. See license for details. */ @@ -1453,15 +1453,15 @@ long new_value; buf[0] = highc(buf[0]); Strcat(buf, " the "); if (Upolyd) { - char mname[BUFSZ]; + char mnam[BUFSZ]; int k; - Strcpy(mname, mons[u.umonnum].mname); - for (k = 0; mname[k] != '\0'; k++) { - if (k == 0 || mname[k - 1] == ' ') - mname[k] = highc(mname[k]); + Strcpy(mnam, pmname(&mons[u.umonnum], Ugender)); + for (k = 0; mnam[k] != '\0'; k++) { + if (k == 0 || mnam[k - 1] == ' ') + mnam[k] = highc(mnam[k]); } - Strcat(buf, mname); + Strcat(buf, mnam); } else Strcat(buf, rank_of(u.ulevel, g.pl_character[0], flags.female)); diff --git a/win/X11/wintext.c b/win/X11/wintext.c index 88ad40f18..a6c2737b8 100644 --- a/win/X11/wintext.c +++ b/win/X11/wintext.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 wintext.c $NHDT-Date: 1552422654 2019/03/12 20:30:54 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.18 $ */ +/* NetHack 3.7 wintext.c $NHDT-Date: 1597967808 2020/08/20 23:56:48 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.22 $ */ /* Copyright (c) Dean Luick, 1992 */ /* NetHack may be freely redistributed. See license for details. */ @@ -489,14 +489,20 @@ calculate_rip_text(int how, time_t when) char buf[BUFSZ]; char *dpx; - int line; - long year; + int line, year; + long cash; /* Put name on stone */ Sprintf(rip_line[NAME_LINE], "%s", g.plname); /* Put $ on stone */ - Sprintf(rip_line[GOLD_LINE], "%ld Au", g.done_money); + cash = max(g.done_money, 0L); + /* arbitrary upper limit; practical upper limit is quite a bit less */ + if (cash > 999999999L) + cash = 999999999L; + Sprintf(buf, "%ld Au", cash); + Sprintf(rip_line[GOLD_LINE], "%ld Au", cash); + /* Put together death description */ formatkiller(buf, sizeof buf, how, FALSE); @@ -523,8 +529,8 @@ calculate_rip_text(int how, time_t when) } /* Put year on stone */ - year = yyyymmdd(when) / 10000L; - Sprintf(rip_line[YEAR_LINE], "%4ld", year); + year = (int) ((yyyymmdd(when) / 10000L) % 10000L); + Sprintf(rip_line[YEAR_LINE], "%4d", year); } /* diff --git a/win/X11/winval.c b/win/X11/winval.c index 66de17926..dd041012b 100644 --- a/win/X11/winval.c +++ b/win/X11/winval.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 winval.c $NHDT-Date: 1432512808 2015/05/25 00:13:28 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ */ +/* NetHack 3.7 winval.c $NHDT-Date: 1596498377 2020/08/03 23:46:17 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.10 $ */ /* Copyright (c) Dean Luick, 1992 */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/win/chain/wc_chainin.c b/win/chain/wc_chainin.c index 03c2e8142..fb84ab32a 100644 --- a/win/chain/wc_chainin.c +++ b/win/chain/wc_chainin.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 wc_chainin.c $NHDT-Date: 1433806610 2015/06/08 23:36:50 $ $NHDT-Branch: master $:$NHDT-Revision: 1.7 $ */ +/* NetHack 3.7 wc_chainin.c $NHDT-Date: 1596498323 2020/08/03 23:45:23 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.12 $ */ /* Copyright (c) Kenneth Lorber, 2012 */ /* NetHack may be freely redistributed. See license for details. */ @@ -272,12 +272,13 @@ char *posbar; /* XXX can we decode the glyph in a meaningful way? */ void -chainin_print_glyph(window, x, y, glyph, bkglyph) +chainin_print_glyph(window, x, y, glyph, bkglyph, glyphmod) winid window; xchar x, y; int glyph, bkglyph; +int glyphmod[NUM_GLYPHMOD]; { - (*cibase->nprocs->win_print_glyph)(cibase->ndata, window, x, y, glyph, bkglyph); + (*cibase->nprocs->win_print_glyph)(cibase->ndata, window, x, y, glyph, bkglyph, glyphmod); } void diff --git a/win/chain/wc_chainout.c b/win/chain/wc_chainout.c index 08c2992fa..3ad84aa45 100644 --- a/win/chain/wc_chainout.c +++ b/win/chain/wc_chainout.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 wc_chainout.c $NHDT-Date: 1433806611 2015/06/08 23:36:51 $ $NHDT-Branch: master $:$NHDT-Revision: 1.7 $ */ +/* NetHack 3.7 wc_chainout.c $NHDT-Date: 1596498324 2020/08/03 23:45:24 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.13 $ */ /* Copyright (c) Kenneth Lorber, 2012 */ /* NetHack may be freely redistributed. See license for details. */ @@ -336,15 +336,16 @@ char *posbar; #endif void -chainout_print_glyph(vp, window, x, y, glyph, bkglyph) +chainout_print_glyph(vp, window, x, y, glyph, bkglyph, glyphmod) void *vp; winid window; xchar x, y; int glyph, bkglyph; +int glyphmod[NUM_GLYPHMOD]; { struct chainout_data *tdp = vp; - (*tdp->nprocs->win_print_glyph)(window, x, y, glyph, bkglyph); + (*tdp->nprocs->win_print_glyph)(window, x, y, glyph, bkglyph, glyphmod); } void diff --git a/win/chain/wc_trace.c b/win/chain/wc_trace.c index 8af083a40..b6519e443 100644 --- a/win/chain/wc_trace.c +++ b/win/chain/wc_trace.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 wc_trace.c $NHDT-Date: 1501464799 2017/07/31 01:33:19 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.8 $ */ +/* NetHack 3.7 wc_trace.c $NHDT-Date: 1596498324 2020/08/03 23:45:24 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.14 $ */ /* Copyright (c) Kenneth Lorber, 2012 */ /* NetHack may be freely redistributed. See license for details. */ @@ -578,19 +578,20 @@ char *posbar; /* XXX can we decode the glyph in a meaningful way? see mapglyph()? genl_putmixed? */ void -trace_print_glyph(vp, window, x, y, glyph, bkglyph) +trace_print_glyph(vp, window, x, y, glyph, bkglyph, glyphmod) void *vp; winid window; xchar x, y; int glyph, bkglyph; +int glyphmod[NUM_GLYPHMOD]; { struct trace_data *tdp = vp; - fprintf(wc_tracelogf, "%sprint_glyph(%d, %d, %d, %d, %d)\n", INDENT, window, - x, y, glyph, bkglyph); + fprintf(wc_tracelogf, "%sprint_glyph(%d, %d, %d, %d, %d, %lu)\n", INDENT, window, + x, y, glyph, bkglyph, glyphmod); PRE; - (*tdp->nprocs->win_print_glyph)(tdp->ndata, window, x, y, glyph, bkglyph); + (*tdp->nprocs->win_print_glyph)(tdp->ndata, window, x, y, glyph, bkglyph, glyphmod); POST; } diff --git a/win/curses/cursdial.c b/win/curses/cursdial.c index d29722bb5..df0f38c34 100644 --- a/win/curses/cursdial.c +++ b/win/curses/cursdial.c @@ -1,5 +1,5 @@ /* vim:set cin ft=c sw=4 sts=4 ts=8 et ai cino=Ls\:0t0(0 : -*- mode:c;fill-column:80;tab-width:8;c-basic-offset:4;indent-tabs-mode:nil;c-file-style:"k&r" -*-*/ -/* NetHack 3.6 cursdial.c */ +/* NetHack 3.7 cursdial.c */ /* Copyright (c) Karl Garrison, 2010. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1182,7 +1182,8 @@ menu_display_page(nhmenu *menu, WINDOW * win, int page_num, char *selectors) if (menu_item_ptr->glyph != NO_GLYPH && iflags.use_menu_glyphs) { unsigned special; /*notused */ - mapglyph(menu_item_ptr->glyph, &curletter, &color, &special, 0, 0, 0); + /*mapglyph(menu_item_ptr->glyph, &curletter, &color, &special, + 0, 0, 0);*/ curses_toggle_color_attr(win, color, NONE, ON); mvwaddch(win, menu_item_ptr->line_num + 1, start_col, curletter); curses_toggle_color_attr(win, color, NONE, OFF); diff --git a/win/curses/cursdial.h b/win/curses/cursdial.h index e75a55b30..3bcd7dee2 100644 --- a/win/curses/cursdial.h +++ b/win/curses/cursdial.h @@ -1,5 +1,5 @@ /* vim:set cin ft=c sw=4 sts=4 ts=8 et ai cino=Ls\:0t0(0 : -*- mode:c;fill-column:80;tab-width:8;c-basic-offset:4;indent-tabs-mode:nil;c-file-style:"k&r" -*-*/ -/* NetHack 3.6 cursdial.h */ +/* NetHack 3.7 cursdial.h */ /* Copyright (c) Karl Garrison, 2010. */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/win/curses/cursinit.c b/win/curses/cursinit.c index ee93313eb..07513a7e1 100644 --- a/win/curses/cursinit.c +++ b/win/curses/cursinit.c @@ -1,5 +1,5 @@ /* vim:set cin ft=c sw=4 sts=4 ts=8 et ai cino=Ls\:0t0(0 : -*- mode:c;fill-column:80;tab-width:8;c-basic-offset:4;indent-tabs-mode:nil;c-file-style:"k&r" -*-*/ -/* NetHack 3.6 cursinit.c */ +/* NetHack 3.7 cursinit.c */ /* Copyright (c) Karl Garrison, 2010. */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/win/curses/cursinit.h b/win/curses/cursinit.h index c611d59f6..ba3b5a7ee 100644 --- a/win/curses/cursinit.h +++ b/win/curses/cursinit.h @@ -1,5 +1,5 @@ /* vim:set cin ft=c sw=4 sts=4 ts=8 et ai cino=Ls\:0t0(0 : -*- mode:c;fill-column:80;tab-width:8;c-basic-offset:4;indent-tabs-mode:nil;c-file-style:"k&r" -*-*/ -/* NetHack 3.6 cursinit.h */ +/* NetHack 3.7 cursinit.h */ /* Copyright (c) Karl Garrison, 2010. */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/win/curses/cursinvt.c b/win/curses/cursinvt.c index 64fd0197d..0da9b6251 100644 --- a/win/curses/cursinvt.c +++ b/win/curses/cursinvt.c @@ -1,5 +1,5 @@ /* vim:set cin ft=c sw=4 sts=4 ts=8 et ai cino=Ls\:0t0(0 : -*- mode:c;fill-column:80;tab-width:8;c-basic-offset:4;indent-tabs-mode:nil;c-file-style:"k&r" -*-*/ -/* NetHack 3.6 cursinvt.c */ +/* NetHack 3.7 cursinvt.c */ /* Copyright (c) Fredrik Ljungdahl, 2017. */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/win/curses/cursinvt.h b/win/curses/cursinvt.h index db2df6586..fc367ab2b 100644 --- a/win/curses/cursinvt.h +++ b/win/curses/cursinvt.h @@ -1,5 +1,5 @@ /* vim:set cin ft=c sw=4 sts=4 ts=8 et ai cino=Ls\:0t0(0 : -*- mode:c;fill-column:80;tab-width:8;c-basic-offset:4;indent-tabs-mode:nil;c-file-style:"k&r" -*-*/ -/* NetHack 3.6 cursinvt.h */ +/* NetHack 3.7 cursinvt.h */ /* Copyright (c) Fredrik Ljungdahl, 2017. */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/win/curses/cursmain.c b/win/curses/cursmain.c index fe9ebafc6..0ee3c7f43 100644 --- a/win/curses/cursmain.c +++ b/win/curses/cursmain.c @@ -1,5 +1,5 @@ /* vim:set cin ft=c sw=4 sts=4 ts=8 et ai cino=Ls\:0t0(0 : -*- mode:c;fill-column:80;tab-width:8;c-basic-offset:4;indent-tabs-mode:nil;c-file-style:"k&r" -*-*/ -/* NetHack 3.6 cursmain.c */ +/* NetHack 3.7 cursmain.c */ /* Copyright (c) Karl Garrison, 2010. */ /* NetHack may be freely redistributed. See license for details. */ @@ -646,25 +646,34 @@ curses_cliparound(int x, int y) } /* -print_glyph(window, x, y, glyph, bkglyph) +print_glyph(window, x, y, glyph, bkglyph, glyphmod) -- Print the glyph at (x,y) on the given window. Glyphs are integers at the interface, mapped to whatever the window- port wants (symbol, font, color, attributes, ...there's a 1-1 map between glyphs and distinct things on the map). bkglyph is to render the background behind the glyph. It's not used here. + -- glyphmod (glyphmod[NUM_GLYPHNOD]) provides extended + information about the glyph that window ports can use to + enhance the display in various ways. + */ void curses_print_glyph(winid wid, XCHAR_P x, XCHAR_P y, int glyph, - int bkglyph UNUSED) + int bkglyph UNUSED, unsigned *glyphmod) { int ch; int color; unsigned int special; int attr = -1; +#if 0 /* map glyph to character and color */ - mapglyph(glyph, &ch, &color, &special, x, y, 0); + mapglyph(glyph, &ch, &color, &special, x, y, 0); */ +#endif + special = glyphmod[GM_FLAGS]; + ch = (int) glyphmod[GM_TTYCHAR]; + color = (int) glyphmod[GM_COLOR]; if ((special & MG_PET) && iflags.hilite_pet) { attr = iflags.wc2_petattr; } @@ -689,7 +698,7 @@ curses_print_glyph(winid wid, XCHAR_P x, XCHAR_P y, int glyph, /* water and lava look the same except for color; when color is off, render lava in inverse video so that they look different */ if ((special & (MG_BW_LAVA | MG_BW_ICE)) != 0 && iflags.use_inverse) { - attr = A_REVERSE; /* mapglyph() only sets this if color is off */ + attr = A_REVERSE; /* map_glyphmod() only sets this if color is off */ } } @@ -898,12 +907,13 @@ curses_end_screen() /* outrip(winid, int) - -- The tombstone code. If you want the traditional code use - genl_outrip for the value and check the #if in rip.c. + -- The tombstone code. We use genl_outrip() from rip.c + instead of rolling our own. */ void curses_outrip(winid wid UNUSED, - int how UNUSED) + int how UNUSED, + time_t when UNUSED) { return; } diff --git a/win/curses/cursmesg.c b/win/curses/cursmesg.c index 6300ca1fc..c789393ec 100644 --- a/win/curses/cursmesg.c +++ b/win/curses/cursmesg.c @@ -1,5 +1,5 @@ /* vim:set cin ft=c sw=4 sts=4 ts=8 et ai cino=Ls\:0t0(0 : -*- mode:c;fill-column:80;tab-width:8;c-basic-offset:4;indent-tabs-mode:nil;c-file-style:"k&r" -*-*/ -/* NetHack 3.6 cursmesg.c */ +/* NetHack 3.7 cursmesg.c */ /* Copyright (c) Karl Garrison, 2010. */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/win/curses/cursmesg.h b/win/curses/cursmesg.h index ca0752eea..f5cee192e 100644 --- a/win/curses/cursmesg.h +++ b/win/curses/cursmesg.h @@ -1,5 +1,5 @@ /* vim:set cin ft=c sw=4 sts=4 ts=8 et ai cino=Ls\:0t0(0 : -*- mode:c;fill-column:80;tab-width:8;c-basic-offset:4;indent-tabs-mode:nil;c-file-style:"k&r" -*-*/ -/* NetHack 3.6 cursmesg.h */ +/* NetHack 3.7 cursmesg.h */ /* Copyright (c) Karl Garrison, 2010. */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/win/curses/cursmisc.c b/win/curses/cursmisc.c index 902dbda08..0914400ea 100644 --- a/win/curses/cursmisc.c +++ b/win/curses/cursmisc.c @@ -1,5 +1,5 @@ /* vim:set cin ft=c sw=4 sts=4 ts=8 et ai cino=Ls\:0t0(0 : -*- mode:c;fill-column:80;tab-width:8;c-basic-offset:4;indent-tabs-mode:nil;c-file-style:"k&r" -*-*/ -/* NetHack 3.6 cursmisc.c */ +/* NetHack 3.7 cursmisc.c */ /* Copyright (c) Karl Garrison, 2010. */ /* NetHack may be freely redistributed. See license for details. */ @@ -691,7 +691,8 @@ curses_rtrim(char *str) char *s; for (s = str; *s != '\0'; ++s); - for (--s; isspace(*s) && s > str; --s); + if (s > str) + for (--s; isspace(*s) && s > str; --s); if (s == str) *s = '\0'; else diff --git a/win/curses/cursmisc.h b/win/curses/cursmisc.h index d76346184..51c5aa841 100644 --- a/win/curses/cursmisc.h +++ b/win/curses/cursmisc.h @@ -1,5 +1,5 @@ /* vim:set cin ft=c sw=4 sts=4 ts=8 et ai cino=Ls\:0t0(0 : -*- mode:c;fill-column:80;tab-width:8;c-basic-offset:4;indent-tabs-mode:nil;c-file-style:"k&r" -*-*/ -/* NetHack 3.6 cursmisc.h */ +/* NetHack 3.7 cursmisc.h */ /* Copyright (c) Karl Garrison, 2010. */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/win/curses/cursstat.c b/win/curses/cursstat.c index aeddddfb1..63c188886 100644 --- a/win/curses/cursstat.c +++ b/win/curses/cursstat.c @@ -1,5 +1,5 @@ /* vim:set cin ft=c sw=4 sts=4 ts=8 et ai cino=Ls\:0t0(0 : -*- mode:c;fill-column:80;tab-width:8;c-basic-offset:4;indent-tabs-mode:nil;c-file-style:"k&r" -*-*/ -/* NetHack 3.6 cursstat.c */ +/* NetHack 3.7 cursstat.c */ /* Copyright (c) Andy Thomson, 2018. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1468,7 +1468,7 @@ get_playerrank(char *rank) if (Upolyd) { int k = 0; - Strcpy(buf, mons[u.umonnum].mname); + Strcpy(buf, pmname(&mons[u.umonnum], flags.female ? FEMALE : MALE)); while(buf[k] != 0) { if ((k == 0 || (k > 0 && buf[k-1] == ' ')) && 'a' <= buf[k] && buf[k] <= 'z') diff --git a/win/curses/cursstat.h b/win/curses/cursstat.h index e10977bb2..3d5d856dc 100644 --- a/win/curses/cursstat.h +++ b/win/curses/cursstat.h @@ -1,5 +1,5 @@ /* vim:set cin ft=c sw=4 sts=4 ts=8 et ai cino=Ls\:0t0(0 : -*- mode:c;fill-column:80;tab-width:8;c-basic-offset:4;indent-tabs-mode:nil;c-file-style:"k&r" -*-*/ -/* NetHack 3.6 cursstat.h */ +/* NetHack 3.7 cursstat.h */ /* Copyright (c) Karl Garrison, 2010. */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/win/curses/curswins.c b/win/curses/curswins.c index 901320b0c..ee5eb42e8 100644 --- a/win/curses/curswins.c +++ b/win/curses/curswins.c @@ -1,5 +1,5 @@ /* vim:set cin ft=c sw=4 sts=4 ts=8 et ai cino=Ls\:0t0(0 : -*- mode:c;fill-column:80;tab-width:8;c-basic-offset:4;indent-tabs-mode:nil;c-file-style:"k&r" -*-*/ -/* NetHack 3.6 curswins.c */ +/* NetHack 3.7 curswins.c */ /* Copyright (c) Karl Garrison, 2010. */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/win/curses/curswins.h b/win/curses/curswins.h index ad2e5902f..616024818 100644 --- a/win/curses/curswins.h +++ b/win/curses/curswins.h @@ -1,5 +1,5 @@ /* vim:set cin ft=c sw=4 sts=4 ts=8 et ai cino=Ls\:0t0(0 : -*- mode:c;fill-column:80;tab-width:8;c-basic-offset:4;indent-tabs-mode:nil;c-file-style:"k&r" -*-*/ -/* NetHack 3.6 curswins.h */ +/* NetHack 3.7 curswins.h */ /* Copyright (c) Karl Garrison, 2010. */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/win/macosx/NetHackGuidebook.applescript b/win/macosx/NetHackGuidebook.applescript index 977d4d713..71f59f031 100644 --- a/win/macosx/NetHackGuidebook.applescript +++ b/win/macosx/NetHackGuidebook.applescript @@ -1,5 +1,5 @@ #!/usr/bin/osascript -# NetHack 3.6 NetHackGuidebook.applescript $NHDT-Date: 1575245175 2019/12/02 00:06:15 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.10 $ +# NetHack 3.7 NetHackGuidebook.applescript $NHDT-Date: 1596498328 2020/08/03 23:45:28 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.13 $ # Copyright (c) Kenneth Lorber, Kensington, Maryland, 2011 # NetHack may be freely redistributed. See license for details. diff --git a/win/macosx/NetHackRecover.applescript b/win/macosx/NetHackRecover.applescript index c1db10171..097894e76 100644 --- a/win/macosx/NetHackRecover.applescript +++ b/win/macosx/NetHackRecover.applescript @@ -1,5 +1,5 @@ #!/usr/bin/osascript -# NetHack 3.6 NetHackRecover.applescript $NHDT-Date: 1524684596 2018/04/25 19:29:56 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.9 $ +# NetHack 3.7 NetHackRecover.applescript $NHDT-Date: 1596498329 2020/08/03 23:45:29 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.10 $ # Copyright (c) Kenneth Lorber, Kensington, Maryland, 2009 # NetHack may be freely redistributed. See license for details. diff --git a/win/macosx/recover.pl b/win/macosx/recover.pl index bb66c8d89..ba9df67c0 100755 --- a/win/macosx/recover.pl +++ b/win/macosx/recover.pl @@ -1,6 +1,6 @@ #!/usr/bin/perl -# NetHack 3.6 recover.pl $NHDT-Date: 1524684612 2018/04/25 19:30:12 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.12 $ +# NetHack 3.7 recover.pl $NHDT-Date: 1596498329 2020/08/03 23:45:29 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.13 $ # Copyright (c) Kenneth Lorber, Kensington, Maryland, 2009 # NetHack may be freely redistributed. See license for details. diff --git a/win/share/bmptiles.c b/win/share/bmptiles.c index b75bbdc54..f3475b1bf 100644 --- a/win/share/bmptiles.c +++ b/win/share/bmptiles.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 bmptiles.c $NHDT-Date: 1457207054 2016/03/05 19:44:14 $ $NHDT-Branch: chasonr $:$NHDT-Revision: 1.0 $ */ +/* NetHack 3.7 bmptiles.c $NHDT-Date: 1596498334 2020/08/03 23:45:34 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.1 $ */ /* Copyright (c) Ray Chason, 2016. */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/win/share/giftiles.c b/win/share/giftiles.c index 911ea3c21..bb5c81c07 100644 --- a/win/share/giftiles.c +++ b/win/share/giftiles.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 giftiles.c $NHDT-Date: 1457358406 2016/03/07 13:46:46 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.0 $ */ +/* NetHack 3.7 giftiles.c $NHDT-Date: 1596498335 2020/08/03 23:45:35 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.1 $ */ /* Copyright (c) Ray Chason, 2016. */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/win/share/monsters.txt b/win/share/monsters.txt index 6a69c8de6..a7e97fa09 100644 --- a/win/share/monsters.txt +++ b/win/share/monsters.txt @@ -27,7 +27,7 @@ Y = (149, 149, 149) Z = (195, 195, 195) 0 = (100, 100, 100) 1 = (72, 108, 108) -# tile 0 (giant ant) +# tile 0 (giant ant,male) { ................ ................ @@ -46,7 +46,26 @@ Z = (195, 195, 195) ......JA.JA..... ................ } -# tile 1 (killer bee) +# tile 1 (giant ant,female) +{ + ................ + ................ + ................ + ................ + ................ + ................ + ......J......... + ......AJAJKKA... + ....JJAAAKJJJA.. + ....AAKJJAJJAA.. + ...KKAJJJAAA.... + ..BJJAAAAAJJ.... + ..JBJAJAJAAAJ... + .....AJA.JA..... + ......JA.JA..... + ................ +} +# tile 2 (killer bee,male) { ................ ................ @@ -65,7 +84,26 @@ Z = (195, 195, 195) .....AAAAAA..... ................ } -# tile 2 (soldier ant) +# tile 3 (killer bee,female) +{ + ................ + ................ + .PPP.....PP..... + PPPPP...PBPP.... + PBPPP..PBPPP.... + .PPBP.PPLPLL.... + ...PP.PLLALHAH.. + ...AKKKLAHAAHH.. + BBJJJJJJJAHHAA.. + ABJBBJJJJAHAHH.. + .JJABJAJ.J.HH... + .......J.J...... + ................ + ...AAAAAAAAAAA.. + .....AAAAAA..... + ................ +} +# tile 4 (soldier ant,male) { ................ ................ @@ -84,7 +122,26 @@ Z = (195, 195, 195) ..JJAAJA.JA..... ................ } -# tile 3 (fire ant) +# tile 5 (soldier ant,female) +{ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ......JJAJKKA... + ....JJAAAKJJJA.. + ....AAKJJAJJAA.. + .JJKKAJJJAAA.... + JBJJJAAAAAJJ.... + JJJBJAJAJAAAJ... + JAAJJAJA.JA..... + ..JJAAJA.JA..... + ................ +} +# tile 6 (fire ant,male) { ................ ................ @@ -103,7 +160,26 @@ Z = (195, 195, 195) ......DA.DA..... ................ } -# tile 4 (giant beetle) +# tile 7 (fire ant,female) +{ + ................ + ................ + ................ + ................ + ................ + ................ + ......D......... + ......ADACCCA... + ....DDAAACDDDA.. + ....AACDDADDAA.. + ...CCADDDAAA.... + ..GDDAAAAADD.... + ..DGDADADAAAD... + .....ADA.DA..... + ......DA.DA..... + ................ +} +# tile 8 (giant beetle,male) { ................ ................ @@ -122,7 +198,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 5 (queen bee) +# tile 9 (giant beetle,female) +{ + ................ + ................ + ................ + ................ + ................ + ................ + ......KKDKK..... + ....KACLCJJD.... + ...KCLCJJDDDK... + ...DCCJDADDAD... + ...ADJDDDDDDD... + ...BAKDDAADKAA.. + ...ABAKDDK...... + ......AA.AA..... + ................ + ................ +} +# tile 10 (queen bee,male) { ................ .PPP.....PP..... @@ -141,7 +236,26 @@ Z = (195, 195, 195) .....AAAAAA..... ................ } -# tile 6 (acid blob) +# tile 11 (queen bee,female) +{ + ................ + .PPP.....PP..... + PPPPP...PPPP.... + PPPPP..PPBPP.... + PBPPP..PBPPP.... + .PPBP.PPLPLL.... + ...PP.PLLALHAH.. + ...AKKKLAHAAHH.. + BBJJJJJJJAHHAAH. + ABJBBJJJJAHAHHH. + .JJABJAJ.JHHHAA. + ...J...J.JAAAHH. + ..JJ..JJ.J.HHAH. + ..JAAAJAAJ..HH.. + .....AAAAAA..... + ................ +} +# tile 12 (acid blob,male) { ................ ................ @@ -160,7 +274,26 @@ Z = (195, 195, 195) ..IA............ ................ } -# tile 7 (quivering blob) +# tile 13 (acid blob,female) +{ + ................ + ................ + ................ + .....KDDA....... + ...DDKDDKA...... + .DDDIIIDJDA..... + D.IIOOIIDAIA.... + .DKNNNODIDA..IA. + IDJNANOJDDJA.... + ADIDNOIDIDDDA... + ...JDIKIADKIA... + .IA.IDID.JDA.... + ...I.DDA....DA.. + .........IA..... + ..IA............ + ................ +} +# tile 14 (quivering blob,male) { ................ ................ @@ -179,7 +312,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 8 (gelatinous cube) +# tile 15 (quivering blob,female) +{ + ................ + ................ + .....PPPP....... + .........P...... + .P.OOOPPE..AAA.. + P.OPBBBPOEAEAA.. + P.PBNNNP.OEAAEA. + P.PNNNNNPOEEAEA. + POPNAANNEO.OAEA. + .OPNAANNE..OAAA. + .OPBNNNEPP.OEAA. + BPOPEEEBBPO.EEA. + BBBPBBBBBBPPPPA. + ..BBBBBBBBBBPA.. + ................ + ................ +} +# tile 16 (gelatinous cube,male) { ................ ................ @@ -198,7 +350,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 9 (chickatrice) +# tile 17 (gelatinous cube,female) +{ + ................ + ................ + ................ + ................ + ................ + .......LLL...... + .....LLLLLLLL... + ...LLLLLLLLLD... + ...CLLLLLLLDDA.. + ...CGGCLLLDDDAA. + ...CAGCGGDDDDAAA + ...CCCCAGDDDAAAA + .....CCCCDDAAAA. + .......CCDAAA... + ................ + ................ +} +# tile 18 (chickatrice,male) { ................ ................ @@ -217,7 +388,26 @@ Z = (195, 195, 195) ........AA...... ................ } -# tile 10 (cockatrice) +# tile 19 (chickatrice,female) +{ + ................ + ................ + ................ + ................ + .......OO....... + ......HAOO...... + .....HHOOH.HHA.. + ........OOHOA... + ........OOFA.... + ........FGGFA... + ........AGFGAA.. + ...........GA... + .......F..FFA... + .......AFFAA.... + ........AA...... + ................ +} +# tile 20 (cockatrice,male) { ................ ...D.DD......... @@ -236,7 +426,26 @@ Z = (195, 195, 195) .....FFFFA...... ................ } -# tile 11 (pyrolisk) +# tile 21 (cockatrice,female) +{ + ................ + ...D.DD......... + ....DD.......... + ....NL..AA...... + ..HHAN.AAA...... + .HH.NO..AAAA.... + ...AOOLFFFAA.... + ...OOLKGGFFAA... + ...AOAGGFGFFAA.. + .......GFFGFAA.. + .........FGGAA.. + .....FA...FFA... + ....FA....FFA... + ....FA..FFFA.... + .....FFFFA...... + ................ +} +# tile 22 (pyrolisk,male) { ................ ...D.DD......... @@ -255,7 +464,26 @@ Z = (195, 195, 195) .....JKKKA...... ................ } -# tile 12 (jackal) +# tile 23 (pyrolisk,female) +{ + ................ + ...D.DD......... + ....DD.......... + ....NB..AA...... + ..HHAN.AAA...... + .HH.NB..AAAA.... + ...APBBJJJAA.... + ...PPPKDDKJAA... + ...APADDKDKJAA.. + .......DJKDJAA.. + .........JDDAA.. + .....JA...JJA... + ....JA....JJA... + ....KA..KKKA.... + .....JKKKA...... + ................ +} +# tile 24 (jackal,male) { ................ ................ @@ -274,7 +502,26 @@ Z = (195, 195, 195) .....OO..OOA.... ................ } -# tile 13 (fox) +# tile 25 (jackal,female) +{ + ................ + ................ + ................ + ................ + ...O..O......... + ...O.OO...O..... + ..OOOO.....O.... + ..IOIOO....O.A.. + .OLLOOOL...O.A.. + DOOOAOOOOOOOAA.. + ..AAOOOOOOOOAA.. + ....OJOOOOOLAA.. + ....OJOLKALKAA.. + ...OOAOAAAOAA... + .....OO..OOA.... + ................ +} +# tile 26 (fox,male) { ................ ................ @@ -293,7 +540,26 @@ Z = (195, 195, 195) ...AC.ACA....... ................ } -# tile 14 (coyote) +# tile 27 (fox,female) +{ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ....C........... + ....C........... + ..CCAC...CCC.... + ..ACCCCCCACCC... + ...AACCCC.ACC... + ....ACAAC..AA... + ...AC.ACA....... + ................ +} +# tile 28 (coyote,male) { ................ ................ @@ -312,7 +578,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 15 (werejackal) +# tile 29 (coyote,female) +{ + ................ + ................ + ................ + ...K..K......... + ...K.KK......KKK + ..KKKK......KKKA + ..NCNK.KKKKKAAA. + .KCCKKKKKKKKK... + KKCKAKKKKKKKK... + DKKKAKAKKKKAK... + ..AAKAAKAAAAK... + ....AKAKAAAAK... + ...AKKAKA.AKK... + .....AKK........ + ................ + ................ +} +# tile 30 (werejackal,male) { ................ ................ @@ -331,7 +616,26 @@ Z = (195, 195, 195) ...L.LL..OOA.... ......L......... } -# tile 16 (little dog) +# tile 31 (werejackal,female) +{ + ................ + ................ + ................ + ................ + ...O..O......... + ...O.OO...O..... + ..OOOO.....O.... + ..IOIOO....O.A.. + .OLLOOOL...O.A.. + DOOOALLOOOOOAA.. + ..AALLLLOOOOAA.. + ....LJLLLOOLAA.. + ....LJLLKALKAA.. + ..LLLALAAAOAA... + ...L.LL..OOA.... + ......L......... +} +# tile 32 (little dog,male) { ................ ................ @@ -350,7 +654,26 @@ Z = (195, 195, 195) .....KK...KA.... ................ } -# tile 17 (dingo) +# tile 33 (little dog,female) +{ + ................ + ................ + ................ + ................ + ...J..J......... + ...J.JJ...K..... + ..JJJJ.....K.... + ..NJNKK....K.A.. + .JJJCKK....K.A.. + .PJJAKCKKCKKAA.. + .DDAACKKCKKKAA.. + ....KJKJCJKJAA.. + ....KJKJJAJJAA.. + ...KKAKAAAKAA... + .....KK...KA.... + ................ +} +# tile 34 (dingo,male) { ................ ................ @@ -369,7 +692,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 18 (dog) +# tile 35 (dingo,female) +{ + ................ + ................ + ................ + .............C.. + ...C..C.......C. + ...C.CC.......CA + ..CCCCK.......CA + ..ACACCKCCCCCCAA + ..LLCCCKCCCLCCCA + .KCCACKCLLLLACCA + ..AACAACLLAAACCA + ....ACACAAAAAACA + ....CCACAAA..CCA + .....ACCA....... + ................ + ................ +} +# tile 36 (dog,male) { ................ ................ @@ -388,7 +730,26 @@ Z = (195, 195, 195) .....KKAA...KA.. ................ } -# tile 19 (large dog) +# tile 37 (dog,female) +{ + ................ + ................ + ................ + ...J..J.....K... + ...J.JJ......K.. + ..JJJJ.......K.. + ..NJNKK......K.A + .JJJCKKKK....K.A + .PJCAKCKKKKCKKAA + .DDAACKKKKCKKKAA + ..AAKJKKJJCJKJAA + ....KJKKJJJAJJAA + ....KAKJAAAAKJA. + ...KKAKAAAAAKAA. + .....KKAA...KA.. + ................ +} +# tile 38 (large dog,male) { ................ ................ @@ -407,7 +768,26 @@ Z = (195, 195, 195) .....KKAA...KA.. ................ } -# tile 20 (wolf) +# tile 39 (large dog,female) +{ + ................ + ................ + ...J..J.....K... + ...J.JJ......K.. + ..JJJJ.......K.. + ..NJNKKK.....K.A + .JJJCKKKKK..JK.A + .PJCAKCKKKKCKKAA + .DDAACKKKKCKKKAA + ..AAKJKKJJCJKJAA + ...JKJKKJJJAJJAA + ....KAKJAAAAKJA. + ....KAKJAAAAKJA. + ...KKAKAAAAAKAA. + .....KKAA...KA.. + ................ +} +# tile 40 (wolf,male) { ................ ................ @@ -426,7 +806,26 @@ Z = (195, 195, 195) .....PPAA..PPA.. ................ } -# tile 21 (werewolf) +# tile 41 (wolf,female) +{ + ................ + ................ + ................ + ...P..P......... + ...P.PP......P.. + ..PPPP.......P.. + ..N.NPP......P.A + .P..PPPPP....P.A + PP.PAPPPPPPPPPAA + DPPPAPPPPPPPPPAA + ..AAP.PP..P.P.AA + ....P.PP...A.PAA + ....PAP.AAAAP.A. + ...PPAPAAAAAPAA. + .....PPAA..PPA.. + ................ +} +# tile 42 (werewolf,male) { ................ ................ @@ -445,7 +844,26 @@ Z = (195, 195, 195) ...L.LLAA..PP... .....LL......... } -# tile 22 (winter wolf cub) +# tile 43 (werewolf,female) +{ + ................ + ................ + ................ + ...P..P......... + ...P.PP......P.. + ..PPPP.......P.. + ..N.NPP......P.A + .P..PPPPP....P.A + PP.PAPPPPPPPPPAA + DPPPALPPPPPPPPAA + ..AALLPL..P.P.AA + ....L.LL...A.PAA + ....LAL.AAAAP.A. + ..LLLALAAAAAPPA. + ...L.LLAA..PP... + .....LL......... +} +# tile 44 (winter wolf cub,male) { ................ ................ @@ -464,7 +882,26 @@ Z = (195, 195, 195) .....NB..NBA.... ................ } -# tile 23 (warg) +# tile 45 (winter wolf cub,female) +{ + ................ + ................ + ................ + ................ + ...N..N......... + ...N.NB......... + ..NNNN.....N.... + ..DNDNB....N.A.. + ..NNNNB....N.A.. + .NNNNNNNNNNNAA.. + .DNBBNNNNNNBAA.. + ....NNNNNNNBAA.. + ....NNNBBANBAA.. + ...NBANAAANAA... + .....NB..NBA.... + ................ +} +# tile 46 (warg,male) { ................ ...P..P....PP... @@ -483,7 +920,26 @@ Z = (195, 195, 195) ....PPPAA.PPPA.. ................ } -# tile 24 (winter wolf) +# tile 47 (warg,female) +{ + ................ + ...P..P.....P... + ...P.PP......P.. + ..PPPP.......P.A + ..N.NPP......P.A + .P..PPPPP....P.A + PPPPDPPPPPPPPPAA + DPPNDPPPPPPPPPAA + ..DDDPPPPPPPPPAA + PNDNP.PPPPPPPPAA + .PPPPAPPPPAPP.A. + ...PAAPPAAAAPPAA + ...PAAP.AAAAP.A. + .PPPAAPAAAAAPAA. + ....PPPAA.PPPA.. + ................ +} +# tile 48 (winter wolf,male) { ................ ................ @@ -502,7 +958,26 @@ Z = (195, 195, 195) .....NNAA..NNA.. ................ } -# tile 25 (hell hound pup) +# tile 49 (winter wolf,female) +{ + ................ + ................ + ................ + ...N..N......... + ...N.NN......N.. + ..NNNN.......N.. + ..DODNN......N.A + .NOONNNNN....N.A + NNONANNNNNNNNNAA + DNNBANNNNNNNNNAA + ..AANNNNNNNBNNAA + ....NBNNNBBANNAA + ....NANBAAAANBA. + ...NNANAAAAANAA. + .....NNAA..NNA.. + ................ +} +# tile 50 (hell hound pup,male) { ................ ................ @@ -521,7 +996,26 @@ Z = (195, 195, 195) .....CC...CA.... ................ } -# tile 26 (hell hound) +# tile 51 (hell hound pup,female) +{ + ................ + ................ + ................ + ................ + ...C..C......... + ...C.CC...C..... + ..CCCC.....C.... + ..DCDCC....C.A.. + .CCCCCC....C.A.. + .PCCACCCCCCCAA.. + .CHAACCCCCCCAA.. + CHC.CCCCCCCCAA.. + .D..CCCCCACCAA.. + ...CCACAAACAA... + .....CC...CA.... + ................ +} +# tile 52 (hell hound,male) { ................ ...C..C....CC... @@ -540,7 +1034,26 @@ Z = (195, 195, 195) ....CCCAA.CCCA.. ................ } -# tile 27 (Cerberus) +# tile 53 (hell hound,female) +{ + ................ + ...C..C....CC... + ...C.CC......C.. + ..CCCC.......C.A + ..DJDCC......C.A + .CCCCCCCC....C.A + CCCCDCCCCCCCCCAA + .CHC.CCCCCCCCCAA + CHC..CCCCCCCCCAA + .D..CCCCCCCCCCAA + ...CCACCCCACC.A. + ...CAACCAAAACCAA + ...CAAC.AAAAC.A. + .CCCAACAAAAACAA. + ....CCCAA.CCCA.. + ................ +} +# tile 54 (Cerberus,male) { ................ ..J..J.......... @@ -559,7 +1072,26 @@ Z = (195, 195, 195) .....JJAA...JA.. ................ } -# tile 28 (gas spore) +# tile 55 (Cerberus,female) +{ + ................ + ..J..J.......... + ..JJJJ.J..J..... + .NJNJ..J.JJ..... + JJJJKAJJJJ....J. + PJJJJANJNKK...J. + DJKJAJJJKJJK..J. + ..AAJPJKAJKJKJJ. + ..JJJDDAJKJJJJJA + ..JJJAAJJJJJJJJA + .JKKKJJJKJJKJJAA + .JJAAKJJKJJJKJAA + JJAAAAJJAAAAJJA. + JAAAAAJAAAAAJAA. + .....JJAA...JA.. + ................ +} +# tile 56 (gas spore,male) { ................ ................ @@ -578,7 +1110,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 29 (floating eye) +# tile 57 (gas spore,female) +{ + ................ + ................ + ................ + .....PFGGFP..... + ....PGFFFFFP.... + ...PFFFFFGGFP... + ...FFGGFFGGFF... + ...GFGGFFFFFG... + ...GFFFFFFFFG... + ...FFFFGGFFFF... + ...PGGFGGFGGP... + ....PGFFFFGP.... + .....PFGGFP..... + ................ + ................ + ................ +} +# tile 58 (floating eye,male) { ................ ................ @@ -597,7 +1148,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 30 (freezing sphere) +# tile 59 (floating eye,female) +{ + ................ + ................ + ......ONNNO..... + ....PNNNNNNNP... + ....NNNNNNNNN... + ...ONNBBBBNNNO.. + ...NNBBEEBBNNN.. + ...NNBEAAEBNNN.. + ...ONBEAAEBNNO.. + ....NBBEEBBNN... + ....PNBBBBNNPAA. + ......ONNNOAAAA. + ......AAAAAAAAA. + .......AAAAAAA.. + ................ + ................ +} +# tile 60 (freezing sphere,male) { ................ ................ @@ -616,7 +1186,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 31 (flaming sphere) +# tile 61 (freezing sphere,female) +{ + ................ + ................ + ......PBBBP..... + ....PBBBBBBBP... + ....BBBBBBBBB... + ...PBPPPBBBBBP.. + ...BBNNBBPPPBB.. + ...BBANPBNNBBB.. + ...PBBPPBANPBP.. + ....BBBBBBPPB... + ....PBBBBBBBPAA. + ......PBBBPAAAA. + ......AAAAAAAAA. + .......AAAAAAA.. + ................ + ................ +} +# tile 62 (flaming sphere,male) { ................ ....C...H....... @@ -635,7 +1224,26 @@ Z = (195, 195, 195) ......JJJJJ..... ................ } -# tile 32 (shocking sphere) +# tile 63 (flaming sphere,female) +{ + ................ + ....C...H....... + ....C....O...C.. + ...C..H.CC...C.. + ...C..C.CC..CC.. + ...DCA.DDC.ACC.. + .AHCDCADDCAADC.. + .AACDCDDDDDADD.. + ..ACDDDJJJDDDD.. + ..ADDCAKDDACDD.. + ...ADAKDDCDAD... + ...ADADHCHCAD... + ....DADDDCDAD... + .....DADDDAD.... + ......JJJJJ..... + ................ +} +# tile 64 (shocking sphere,male) { ................ .....PPPPPP..... @@ -654,7 +1262,26 @@ Z = (195, 195, 195) ......PPPPP..... ................ } -# tile 33 (beholder) +# tile 65 (shocking sphere,female) +{ + ................ + .....PPPPPP..... + ...PPIAAADAPP... + ..PAAAIAAADDAP.. + ..PHAAAPBOAAAP.. + .PAHHAPBBBOAAAP. + .PHAAAPBBBBAHHP. + .PAAAAPPBBBAAAP. + .PAAAIAPPPAAAIP. + .PIIIAAAAAAIIAP. + ..PIAANAAPAAAIP. + ..PIAANAAAPAAP.. + ...PANANAPAPAP.. + ....PPAIAPAPP... + ......PPPPP..... + ................ +} +# tile 66 (beholder,male) { ....OA..OA...... ..OA.DADA.OA.OA. @@ -673,7 +1300,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 34 (kitten) +# tile 67 (beholder,female) +{ + ....OA..OA...... + ..OA.DADA.OA.OA. + ...DA.DADADADD.. + ..OADDOOOODDADO. + ...DDHOAAOHDDA.. + ...JDHOAAOHDDJ.. + ...DDDOOOODDDD.. + ...DDDDDDDDDDD.. + ...JDAOAAAOADJ.. + ....DDAAOAADD... + ....PDDDDDDDPAA. + ......JDDDJAAAA. + ......AAAAAAAAA. + .......AAAAAAA.. + ................ + ................ +} +# tile 68 (kitten,male) { ................ ................ @@ -692,7 +1338,26 @@ Z = (195, 195, 195) ......CCA..CA... ................ } -# tile 35 (housecat) +# tile 69 (kitten,female) +{ + ................ + ................ + ................ + ................ + ................ + ................ + ...........N.... + ............N... + ....N.N.....C.A. + ...NNNNC....C.A. + ...ENENNNJJNC.A. + ...NNNNNJJJNNAA. + ....IANNJJNNNAA. + .....NANNWNNWA.. + ......NNA..NA... + ................ +} +# tile 70 (housecat,male) { ................ ................ @@ -711,7 +1376,26 @@ Z = (195, 195, 195) .....CCA...CA... ................ } -# tile 36 (jaguar) +# tile 71 (housecat,female) +{ + ................ + ................ + ................ + ................ + ................ + ...........N.... + ............N... + ...N.N......C.A. + ..NNNNC.....C.A. + .NANANCNJJJNN.A. + .NNNNNNNJJNNNAA. + ..NINWNJJJNNNAA. + ...AANNNNNNNNAA. + ...NNANNWWNNWA.. + .....NNA...NA... + ................ +} +# tile 72 (jaguar,male) { ................ ................ @@ -730,7 +1414,26 @@ Z = (195, 195, 195) .....CCAA...CA.. ................ } -# tile 37 (lynx) +# tile 73 (jaguar,female) +{ + ................ + ................ + ................ + ................ + ..C..C......C... + ..CC.CJ......C.A + .CCCCCJ......C.A + .GCGCCJCAACCJC.A + .CCCCCJCCCCCCCAA + .CDDDJCAACCAJCAA + ..CCACCAJCCAACAA + ....CACCJJJCCJA. + ....CACAAAAACJA. + ...CKACAAAAACAA. + .....CCAA...CA.. + ................ +} +# tile 74 (lynx,male) { ................ ................ @@ -749,7 +1452,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 38 (panther) +# tile 75 (lynx,female) +{ + ................ + ................ + ................ + ................ + O....O.......... + AC.CCA.......... + .CCCA........CA. + .GCGCOAKKKKK.LA. + .CKCCAJCCCCCKA.. + LLDDLLACLLLCCAA. + ..CC.AACLLLCCAA. + .......CAAAACAA. + ....CACAAAACCA.. + ................ + ................ + ................ +} +# tile 76 (panther,male) { ................ ................ @@ -768,7 +1490,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 39 (large cat) +# tile 77 (panther,female) +{ + ................ + ................ + ............AA.. + ..............A. + ..............A. + .A...A........A. + .EA.AE........A. + .AAAAAEAAAAAAA.. + .AAAAAEAAAAAAA.. + .HAHAA.AAAAAAAA. + .AAAA.AAAAAEAAA. + .AAA..AAAAAEAAA. + .....AA....AAA.. + ..AAAA..AAAA.... + ................ + ................ +} +# tile 78 (large cat,male) { ................ ................ @@ -787,7 +1528,26 @@ Z = (195, 195, 195) .....CCAA...CA.. ................ } -# tile 40 (tiger) +# tile 79 (large cat,female) +{ + ................ + ................ + ................ + ................ + ............N... + .............N.. + ...N.N.......C.A + ..NNNNC......C.A + .NANANCNJJJJNN.A + .NNNNNNNJJJNNNAA + ..NDNWNJJJNNNNAA + ...AANNNNNNNNNAA + ....NANNWWWNNWA. + ...NJANAAAAANAA. + .....NNAA...NA.. + ................ +} +# tile 80 (tiger,male) { ................ ................ @@ -806,7 +1566,26 @@ Z = (195, 195, 195) .....CCAA..CCA.. ................ } -# tile 41 (displacer beast) +# tile 81 (tiger,female) +{ + ................ + ................ + ................ + ................ + ..C..C......C... + .CCJCC.......C.A + .CAACCJ......A.A + .GAGCCJACACAJC.A + .CCCCCACACACACAA + .ODOCACCACACACAA + .OCOACCJACACACAA + ....CACJAJAJCAA. + ....AACAAAAAAJA. + ...CKACAAAAACAA. + .....CCAA..CCA.. + ................ +} +# tile 82 (displacer beast,male) { ................ ........E....... @@ -825,7 +1604,26 @@ Z = (195, 195, 195) ...AE.AE.EA.EA.. ................ } -# tile 42 (gremlin) +# tile 83 (displacer beast,female) +{ + ................ + ........E....... + .......E.E..AA.. + DEEEA..A.E....A. + ....EA.E.D....A. + .A...A.E......A. + .EA.AEAAA.....A. + .AAAAAAAAAA..A.. + .AAAAEAAAAAAAA.. + .HAHAEAAAAAAAAA. + .AAAAEAAAAAAAAA. + .AAA.AAAAAAAAAA. + .....AE.AEEA.EA. + ....AE.AE.EA.EA. + ...AE.AE.EA.EA.. + ................ +} +# tile 84 (gremlin,male) { ................ ................ @@ -844,7 +1642,26 @@ Z = (195, 195, 195) ...GFA.FGA...... ................ } -# tile 43 (gargoyle) +# tile 85 (gremlin,female) +{ + ................ + ................ + ................ + GGGA....AGGG.... + .GGGFAAAGGG..... + ..FFFFFFFF...... + ...NDFFDNA...... + ...GNFFNGA...... + ...GFFFFGA..AA.. + ...AGFFFAFAAAAA. + ..GFAGFAFFFAAAA. + .GFGFAAFFAFAAAA. + .GF.GFAGAAFAAAA. + ....FFAGFAA.AA.. + ...GFA.FGA...... + ................ +} +# tile 86 (gargoyle,male) { ................ ................ @@ -863,7 +1680,26 @@ Z = (195, 195, 195) ....PFA.FPA..... ................ } -# tile 44 (winged gargoyle) +# tile 87 (gargoyle,female) +{ + ................ + ................ + ...PAPPPPAP..... + ..PA......AP.... + ..P.DD..DDAP.... + ....PD..DPA..... + ....P....PA..AA. + ....AP...A.AAAAA + ...P.AP.A...AAAA + ..P.P.AA..A.AAAA + ..PA.P.APAA.AAAA + ..PA.P....A.AA.. + .....P....AAAA.. + .....P.AP.AA.... + ....PFA.FPA..... + ................ +} +# tile 88 (winged gargoyle,male) { ...K......K..... ...KJ....KJ..... @@ -882,7 +1718,26 @@ Z = (195, 195, 195) ....PFA.FPA..... ................ } -# tile 45 (hobbit) +# tile 89 (winged gargoyle,female) +{ + ...K......K..... + ...KJ....KJ..... + ..KJAPPPPAJJ.... + ..KJ......AJ.... + ..KJDD..DDAJ.... + .KJAPD..DPAJJ... + .KJAP....PAAJAA. + KJA.AP...A.AJJAA + J..P.AP.A...AJAA + ..P.P.AA..A.AAAA + ..PA.P.APAA.AAAA + ..PA.P....A.AA.. + .....P....AAAA.. + .....P.AP.AA.... + ....PFA.FPA..... + ................ +} +# tile 90 (hobbit,male) { ................ ................ @@ -901,7 +1756,26 @@ Z = (195, 195, 195) ....LLL.LLL..... ................ } -# tile 46 (dwarf) +# tile 91 (hobbit,female) +{ + ................ + ................ + ................ + ................ + ......JJA....... + .....JJJJA...... + ....JLFLFJ...... + ....JLLLLJ...... + ....JKLLKJJ.AA.. + ...CLLLLLLCAAA.. + ..CLALJKJALCA... + ..LLAJJKJALLA... + ...L.LKJLALAA... + .....LLALLA.A... + ....LLL.LLL..... + ................ +} +# tile 92 (dwarf,male) { ................ ................ @@ -920,7 +1794,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 47 (bugbear) +# tile 93 (dwarf,female) +{ + ................ + ................ + ................ + ................ + ......B......... + .....BEE........ + ....BBEEE....... + ....BLLLE....... + .....OLO...AAA.. + ...BBOOOEEAAAA.. + ...BABOEAEAAAA.. + ....LBBELAAAA... + ....EBAEEAA..... + ....BEAEB.A..... + ................ + ................ +} +# tile 94 (bugbear,male) { ................ ................ @@ -939,7 +1832,26 @@ Z = (195, 195, 195) ........CCA..... ................ } -# tile 48 (dwarf lord) +# tile 95 (bugbear,female) +{ + ................ + ................ + ......K......... + .K..KKK......... + .KKKKKK......... + KADKADKKK....... + KKKKKKKJKK...... + KAPAPAKJJKJ..... + KAAAAAKKJKJJ.... + .KKKKKJKAKKJ.... + ..KAJJCAKKKJ.AA. + ..KK.KKKKKJJAA.. + ...C..KJAKJAA... + .....CCAAKJA.... + ........CCA..... + ................ +} +# tile 96 (dwarf leader,male) { ................ ................ @@ -958,7 +1870,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 49 (dwarf king) +# tile 97 (dwarf leader,female) +{ + ................ + ................ + ................ + ................ + ......B......... + .....BEE........ + ....HHHHH....... + ....BLLLE....... + ....BOLOE..AAA.. + ...BBOOOEEAAAA.. + ...BABOEAEAAAA.. + ....LBBELAAAA... + ....EBAEEAA..... + ....BEAEB.A..... + ................ + ................ +} +# tile 98 (dwarf ruler,male) { ................ ................ @@ -977,7 +1908,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 50 (mind flayer) +# tile 99 (dwarf ruler,female) +{ + ................ + ................ + ................ + ................ + ....H.C.H....... + ....HCHCH....... + ....HHHHH....... + ....BLLLE...A... + .....OLO...AAAA. + ...EBOOOEEAAAA.. + ...BABOEAEAAAA.. + ....LBBELAAAA... + ....EBAEEAA..... + ....BEAEB.A..... + ................ + ................ +} +# tile 100 (mind flayer,male) { ................ .......IIIIC.... @@ -996,7 +1946,26 @@ Z = (195, 195, 195) ......CFFCAA.... ....IIC.IIA..... } -# tile 51 (master mind flayer) +# tile 101 (mind flayer,female) +{ + ................ + .......IIIIC.... + .....IIIIIIC.... + ....IIIIIIIC.... + ...IGIIIIGC..... + ...IIGINGIC..... + ....IIIIIC...... + ....IAIAIF...... + ....IAIAIF...... + ....IAIAIFI..... + .....FIFIFIC.AA. + ....CBIBBF.CAAA. + ...IIIBBFFACAAA. + ......BBFCAAAA.. + ......CFFCAA.... + ....IIC.IIA..... +} +# tile 102 (master mind flayer,male) { ................ .......IIIIC.... @@ -1015,7 +1984,26 @@ Z = (195, 195, 195) ...EEECEEEAA.... ....IIC.IIA..... } -# tile 52 (manes) +# tile 103 (master mind flayer,female) +{ + ................ + .......IIIIC.... + .....IIIIIIC.... + ....IIIIIIIC.... + ...IGIIIIGC..... + ...IIGINGIC..... + .EEEIIIIICEEEE.. + ..EEIAIAIEEEE... + ...EIAIAIEEE.... + ....IAIAIEEE.... + ....EFIFIEEE.AA. + ....CBIBBEEEAAA. + ...IIIBBEEEEAAA. + ....EEBEEEEAAA.. + ...EEECEEEAA.... + ....IIC.IIA..... +} +# tile 104 (manes,male) { ................ ................ @@ -1034,7 +2022,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 53 (homunculus) +# tile 105 (manes,female) +{ + ................ + ................ + ....PP.......... + ...PPPP......... + ..PAPAP......... + ..PPPPP.PPP.P... + ..P..PPPP....... + ..P..PPPPP...P.. + ..PPPPP.PPP..... + ..P.P.P.PP.P.... + .P...P.PPPP..... + .P....PPP.PP.... + ..P....P.P.P.P.. + ........P....... + ................ + ................ +} +# tile 106 (homunculus,male) { ................ ................ @@ -1053,7 +2060,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 54 (imp) +# tile 107 (homunculus,female) +{ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ......JJJ....... + ......LLC....... + ......LLC....... + .....BBPPPAA.... + ....L.BPPACAA... + ......BAPAAAA... + .....LLALCA..... + ................ + ................ +} +# tile 108 (imp,male) { ................ ................ @@ -1072,7 +2098,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 55 (lemure) +# tile 109 (imp,female) +{ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + .....O.D.O...... + .....OCDDO...... + ......CDD....... + .....GGFFFAA.... + ....C.GFFADAA... + ......GAFAAAA... + .....CDADDA..... + ................ + ................ +} +# tile 110 (lemure,male) { ................ ................ @@ -1091,7 +2136,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 56 (quasit) +# tile 111 (lemure,female) +{ + ................ + ................ + ....PP.......... + ...PPPP......... + ..PAPAP....P.... + ..PPPPP..PP.P... + ..P..PPPPPPPP... + ..P..PPPPPPP.... + ..PPPPPPPPP..... + ....PPPPPPPP.... + ..PPPPPPPPPP.... + ...PPPPPPPPPP... + ..P.P..PPPP.PP.. + ........P.PP.... + ................ + ................ +} +# tile 112 (quasit,male) { ................ ................ @@ -1110,7 +2174,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 57 (tengu) +# tile 113 (quasit,female) +{ + ................ + ................ + ................ + ................ + ................ + ................ + .....O.D.O...... + .....OCDDOD..... + ......CDD.D..... + .....GGFFFAA.... + ....C.GFFAAADA.. + ....C.GFFJJDA... + ......GAFAAAA... + .....CDADDA..... + ................ + ................ +} +# tile 114 (tengu,male) { ................ .......PP....... @@ -1129,7 +2212,26 @@ Z = (195, 195, 195) .....LLA.LLA.... ................ } -# tile 58 (blue jelly) +# tile 115 (tengu,female) +{ + ................ + .......PP....... + ......PPPP...... + .....DPPNP...... + ....DDDPPP...... + ....DDPPPP...... + ....D..PPA...... + .....PIAAIP.AAA. + ....PPPIIPPPAAA. + ....PAPPPPAPAAA. + ....PAHHHHAPAAA. + ....LAPPPPALAAA. + ......PPPPAAAA.. + ......PPPPAA.A.. + .....LLA.LLA.... + ................ +} +# tile 116 (blue jelly,male) { ................ ................ @@ -1148,7 +2250,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 59 (spotted jelly) +# tile 117 (blue jelly,female) +{ + ................ + ................ + ................ + .......E........ + ......OBE....... + ...BE.OBEBOE.... + ..OBEOBBEOBBE... + ..OBEOBBEOBBE... + ..BBBGGBGGBEEE.. + ..BBBAGBAGEEEEA. + ..BBBBBBEBEEEEAA + ...BBBBBBBEEEAAA + ....BBBBBEEEAAA. + ......BBBEEAA... + ................ + ................ +} +# tile 118 (spotted jelly,male) { ................ ................ @@ -1167,7 +2288,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 60 (ochre jelly) +# tile 119 (spotted jelly,female) +{ + ................ + ................ + ................ + .......E........ + ......OBE....... + ...BE.OCEBOE.... + ..OCEOCCEOBCE... + ..OCEOBCEOCBD... + ..BBBHHBHHBEDD.. + ..CCBAHBAHEEEEA. + ..BBCBBBEBEEDEAA + ...BBBCBBBEEDAAA + ....BCCCBEEDAAA. + ......CCBEEAA... + ................ + ................ +} +# tile 120 (ochre jelly,male) { ................ ................ @@ -1186,7 +2326,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 61 (kobold) +# tile 121 (ochre jelly,female) +{ + ................ + ................ + ................ + .......D........ + ......LCD....... + ...CD.LCDCLD.... + ..LCDLCCDLCCD... + ..LCDLCCDLCCD... + ..CCCGGCGGCDDD.. + ..CCCAGCAGDDDDA. + ..CCCCCCDCDDDDAA + ...CCCCCCCDDDAAA + ....CCCCCDDDAAA. + ......CCCDDAA... + ................ + ................ +} +# tile 122 (kobold,male) { ................ ................ @@ -1205,7 +2364,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 62 (large kobold) +# tile 123 (kobold,female) +{ + ................ + ................ + ................ + ................ + ...N...N........ + ...NBPBN........ + ...BABAB........ + ....BBPA..A..... + ...BBABPA.AA.A.. + ..BPBBBBPAAAAA.. + ..BAPBPAPAAAAA.. + ....PBPAAAAAA... + ....BABAAAA..... + ...BBABBA....... + ................ + ................ +} +# tile 124 (large kobold,male) { ................ ................ @@ -1224,7 +2402,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 63 (kobold lord) +# tile 125 (large kobold,female) +{ + ................ + ................ + ................ + ...N...N........ + ...NBPBN........ + ...BABAB........ + ....BBPA..A..... + ...BBABPA.AA.... + ..BPBBBBPAAA.A.. + ..BAPBPAPAAAAA.. + ..BAPBPAPAAAAA.. + ....PBPAAAAAA... + ....BABAAAA..... + ...BBABBA....... + ................ + ................ +} +# tile 126 (kobold leader,male) { ................ ................ @@ -1243,7 +2440,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 64 (kobold shaman) +# tile 127 (kobold leader,female) +{ + ................ + ................ + ................ + ...N...N........ + ...NCCCN........ + ...CABAC........ + ...CBBPC..A..... + ..CCBABCC.AA.... + ..CCBBBCCAAA.A.. + ..BCCBCCPAAAAA.. + ..BACBCAPAAAAA.. + ....BBBAAAAAA... + ....BABAAAA..... + ...BBABBA....... + ................ + ................ +} +# tile 128 (kobold shaman,male) { ................ ................ @@ -1262,7 +2478,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 65 (leprechaun) +# tile 129 (kobold shaman,female) +{ + ................ + ................ + ................ + ...N...N........ + ...NHHHN........ + ...HABAH........ + ...HBBPH..A..... + ..HHBABHH.AA.... + .HHHBBBHHHAA.A.. + .HBHHBHHPHAAAA.. + ..BAHBHAPAAAAA.. + ....BBBAAAAAA... + ....BABAAAA..... + ...BBABBA....... + ................ + ................ +} +# tile 130 (leprechaun,male) { ................ ................ @@ -1281,7 +2516,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 66 (small mimic) +# tile 131 (leprechaun,female) +{ + ................ + ................ + ................ + ................ + ......G......... + ......F....K.... + .....GFF..KLK... + ....GFFFF..K.... + .....KLKA.GLAA.. + ...FGFLFFFAKA.A. + ...GAGFFAAAK.AA. + ....LKHKKJAKAA.. + ....GFAGKJAKA... + ...GFAA.GFAK.... + ................ + ................ +} +# tile 132 (small mimic,male) { ................ ................ @@ -1300,7 +2554,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 67 (large mimic) +# tile 133 (small mimic,female) +{ + ................ + ................ + ................ + ................ + ......POP....... + ......NNO....... + ......NNO....... + .......OA....... + .....NNNNN..AA.. + ....OONNNOO.AA.. + ....NANOOANAAA.. + ......NAOAAAA... + ......NAOAA.A... + .....NN.OOA..... + ................ + ................ +} +# tile 134 (large mimic,male) { ................ ................ @@ -1319,7 +2592,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 68 (giant mimic) +# tile 135 (large mimic,female) +{ + ................ + ................ + ................ + ......LLOA...... + ......NNOA...... + ......NNOA...... + ......ONOA...... + .....NNNNO..AAA. + ....OONNNOO.AAA. + ...NOANNNAOOAAA. + ...NAONONOANAAA. + .....NO.NOAAAA.. + .....NO.NOAA.A.. + ....NNO.NOOA.... + ................ + ................ +} +# tile 136 (giant mimic,male) { ................ ......NNO....... @@ -1338,7 +2630,26 @@ Z = (195, 195, 195) ...NNNO.NNOOA... ................ } -# tile 69 (wood nymph) +# tile 137 (giant mimic,female) +{ + ................ + ......NNO....... + .....NNNNOA..... + .....NNNNOA..... + .....NNNNOA..... + .....ONNNOA..... + ..PONNOOONOOPAAA + .PONONNNNOONOPAA + .ONOANNNNOAONOAA + .NNOANNNNOAOOOAA + ...AANNONNAAAAAA + ....PNO.NNPAAAAA + ....ONO.NNOAA..A + ....NNO.NNOAA..A + ...NNNO.NNOOA... + ................ +} +# tile 138 (wood nymph,male) { ................ ................ @@ -1357,7 +2668,26 @@ Z = (195, 195, 195) ....KJKJKJKJ.... ................ } -# tile 70 (water nymph) +# tile 139 (wood nymph,female) +{ + ................ + ................ + ...OH........... + ..OHHL.......... + ..OHLL.......... + ..HHLA.......... + .OHLLFKKKKLA.... + .HKFLFKKKKA..... + OHKJFKKJJK.A.... + HKKLJJGKAAAAAAA. + .JJAJGDKJAAAAA.. + ..JA.KKJJAAAA... + ...J.KKKKJAA.... + ....JKKKKKJA.... + ....KJKJKJKJ.... + ................ +} +# tile 140 (water nymph,male) { ................ ................ @@ -1376,7 +2706,26 @@ Z = (195, 195, 195) ....BPBPBPBP.... ................ } -# tile 71 (mountain nymph) +# tile 141 (water nymph,female) +{ + ................ + ................ + ...OH........... + ..OHHL.......... + ..OHLL.......... + ..HHLA.......... + .OHLLJBBBBLA.... + .HBJLJBBBBA..... + OHBPJBBPPB.A.... + HBBLPPNBAAAAAAA. + .PPAPNDB.AAAAA.. + ..PA.BBPPAAAA... + ...P.BBBBPAA.... + ....PBBBBBPA.... + ....BPBPBPBP.... + ................ +} +# tile 142 (mountain nymph,male) { ................ ................ @@ -1395,7 +2744,26 @@ Z = (195, 195, 195) ....OLOLOLOL.... ................ } -# tile 72 (goblin) +# tile 143 (mountain nymph,female) +{ + ................ + ................ + ...OH........... + ..OHHL.......... + ..OHLL.......... + ..HHLA.......... + .OHLLCOOOOLA.... + .HOCLCOOOOA..... + OHOLCOOLLO.A.... + HOOKLLIOAAAAAAA. + .LLALIBOKAAAAA.. + ..LA.OOLLAAAA... + ...L.OOOOLAA.... + ....LOOOOOLA.... + ....OLOLOLOL.... + ................ +} +# tile 144 (goblin,male) { ................ ................ @@ -1414,7 +2782,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 73 (hobgoblin) +# tile 145 (goblin,female) +{ + ................ + ................ + ................ + ....LK.......... + ...CJA.......... + ..KJA........... + .JJA.IIK...AA... + .IK.IGIGIJAA.... + J.ICKIIIJK...... + ...IIJJJK.A..... + ....KICJAAAAA... + ....ICKKJA...... + ....IKAIJA...... + ...IKAA.IK...... + ................ + ................ +} +# tile 146 (hobgoblin,male) { ................ .....LK......... @@ -1433,7 +2820,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 74 (orc) +# tile 147 (hobgoblin,female) +{ + ................ + .....LK......... + ....CKA......... + ...CJA.......... + ..KJA........... + .JJA.IIK...AA... + .IK.IHIHIJAA.... + J.ICKIIIJK...... + ...IIJJJK.A..... + ....KICCAAAAA... + ....IIIIJA...... + ....ICKKJA...... + ....IKAIJA...... + ...IKAA.IK...... + ................ + ................ +} +# tile 148 (orc,male) { ................ ................ @@ -1452,7 +2858,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 75 (hill orc) +# tile 149 (orc,female) +{ + ................ + ................ + ................ + .....OA......... + ....NOPA........ + ....LPLA........ + .....P.A........ + ..KCCAKKKA.AA... + ..BPCKJ.P.AAA... + ..BAGGFAAPNO.... + ..BAJJPNOAAA.... + ....BNOJAAAAAA.. + ...BJACPAAAA.... + ..BPPABPPA...... + ................ + ................ +} +# tile 150 (hill orc,male) { ................ ................ @@ -1471,7 +2896,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 76 (Mordor orc) +# tile 151 (hill orc,female) +{ + ................ + ................ + ................ + .....OA......... + ....NOPA........ + ....LKLA........ + .....K.A........ + ..KGGAFFKA.AA... + ..JKGFF.K.AAA... + ..JAHHFAAKNO.... + ..JAGFFNOAAA.... + ....GNNFAAAAAA.. + ...GGAGFAAAA.... + ..KJJAKJJA...... + ................ + ................ +} +# tile 152 (Mordor orc,male) { ................ ................ @@ -1490,7 +2934,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 77 (Uruk-hai) +# tile 153 (Mordor orc,female) +{ + ................ + ................ + ................ + .....OA......... + ....NOPA........ + ....LPLA........ + .....P.A........ + ..KIIAIIKA.AA... + ..BPIDD.P.AAA... + ..BAGGFAAP.O.... + ..BAIDDNOAAA.... + ....BNOJAAAAAA.. + ...BIAIPAAAA.... + ..BPPABPPA...... + ................ + ................ +} +# tile 154 (Uruk-hai,male) { ................ ................ @@ -1509,7 +2972,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 78 (orc shaman) +# tile 155 (Uruk-hai,female) +{ + ................ + ................ + .....OA......... + ....NOPA........ + ....LPLA........ + .....P.A........ + ..IIIAIIIA...... + ..BPIKI.BAAAA... + ..BIG.PPPPAAA... + .NBAD.PDDPAA.... + ..BNNJPDDPAA.... + ....INPPPPAAAA.. + ...BIAK.AAAA.... + ..BPPABPPA...... + ................ + ................ +} +# tile 156 (orc shaman,male) { ................ ................ @@ -1528,7 +3010,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 79 (orc-captain) +# tile 157 (orc shaman,female) +{ + ................ + ................ + .....OA......... + ....NOPA........ + ....LPLA........ + .....P.A........ + ..CCCACCCA...... + ..BPCKC.BAAAA... + ..BCGGFJBAAAA... + ..BAJJCJBAAA.... + ..BAJJCJBAAA.... + ....CACJAAAAAA.. + ...BCACPAAAA.... + ..BPPABPPA...... + ................ + ................ +} +# tile 158 (orc-captain,male) { ................ ................ @@ -1547,7 +3048,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 80 (rock piercer) +# tile 159 (orc-captain,female) +{ + ................ + ................ + .....OA......... + ...NNOOPA....... + ....LPLA........ + ...IPPPA........ + ..DIIPADDA.AA... + ..BPIAD.P.AAA... + ..BAGGFAAP.O.... + ..BAGGFAAP.O.... + ..BAJJPNOAAA.... + ....BNOJAAAAAA.. + ...BDAIPAAAA.... + ..BPPABPPA...... + ................ + ................ +} +# tile 160 (rock piercer,male) { .JKKKKKKKKJAAA.. ..JJGKGKJJAAAA.. @@ -1566,7 +3086,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 81 (iron piercer) +# tile 161 (rock piercer,female) +{ + .JKKKKKKKKJAAA.. + ..JJGKGKJJAAAA.. + ...JKKKJJAAAA... + ...JJKKJJAAAA... + ....JKKJAAAA.... + ....JJKJ.AAA.... + ....JJKJ.AAA.... + ....JJJJ..A..... + .....JJ...A..... + .....JJ...A..... + .....JJ......... + .....JJ......... + .....J.......... + .....J.......... + ................ + ................ +} +# tile 162 (iron piercer,male) { .BPPPPPPPP.AAA.. ..BBDPDP..AAAA.. @@ -1585,7 +3124,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 82 (glass piercer) +# tile 163 (iron piercer,female) +{ + .BPPPPPPPP.AAA.. + ..BBDPDP..AAAA.. + ...BPPP..AAAA... + ...PBPP..AAAA... + ....BPP.AAAA.... + ....BBP.AAAA.... + ....PBP.AAAA.... + ....PBP...A..... + .....BP...A..... + .....BP...A..... + .....BP......... + .....BP......... + .....B.......... + .....P.......... + ................ + ................ +} +# tile 164 (glass piercer,male) { .NBBBBBBBBPAAA.. ..NNDBDBPPAAAA.. @@ -1604,7 +3162,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 83 (rothe) +# tile 165 (glass piercer,female) +{ + .NBBBBBBBBPAAA.. + ..NNDBDBPPAAAA.. + ...NBBBPPAAAA... + ...PNBBPPAAAA... + ....NBBPAAAA.... + ....NNBPAAAA.... + ....PNBPAAAA.... + ....PNBP..A..... + .....NB...A..... + .....NB...A..... + .....NB......... + .....NB......... + .....N.......... + .....P.......... + ................ + ................ +} +# tile 166 (rothe,male) { ................ ...........K.... @@ -1623,7 +3200,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 84 (mumak) +# tile 167 (rothe,female) +{ + ................ + ...........K.... + ............K... + ............K... + .......JJJKKJ... + .....JKKKKKKK... + ..AAAKKKKKKKK... + .AAAAAKKKKKKKA.. + AAKKAAKKKKKAKA.. + .KEKKAKKKJAAKA.. + .KKKJAKKAJAAK... + ..KJAAAKAAA..... + ..AAKA.KA....... + ..A..A.K........ + ................ + ................ +} +# tile 168 (mumak,male) { ................ ...........P.... @@ -1642,7 +3238,26 @@ Z = (195, 195, 195) PPPA............ .AA............. } -# tile 85 (leocrotta) +# tile 169 (mumak,female) +{ + ................ + ...........P.... + .PP.........P... + PPP...PPPPP.P... + PPPPPPPPP.PP.... + PPPPBPPBBP.PP... + PPPBPPPPPP.PP... + .PDPPDDPP.PPP... + ..BPPDDP.PPPPA.. + ..PPPPPPPPPPPA.. + ..PPPPO..PAPPA.. + .OOPPOOAPPAPPA.. + OOPPOOAAPPA..... + .PPPAPA.PP...... + PPPA............ + .AA............. +} +# tile 170 (leocrotta,male) { ................ ..A..A.......... @@ -1661,7 +3276,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 86 (wumpus) +# tile 171 (leocrotta,female) +{ + ................ + ..A..A.......... + ..AOOA....J..... + ..AOOAA....J.... + .APOAFA....J.... + .APOAAA.JJJJ.... + .AOPAAJKKKKKJ... + .AOAAKJJKKJKJA.. + ...JKKKKKJAKKA.. + ...JKJKKJAAKKA.. + ..JKJAKKAAPAPA.. + ..KKAAKKAAPAPA.. + .PAPAAPAPA...... + .PAPA.PAPA...... + ................ + ................ +} +# tile 172 (wumpus,male) { ................ ............B... @@ -1680,7 +3314,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 87 (titanothere) +# tile 173 (wumpus,female) +{ + ................ + ............B... + .............B.. + .......BBBBB.B.. + ....BBBPPBBBB... + ...BOOBBBPBBBB.. + ...OOBBBBBPBBB.. + ..DABBAABBPBBBA. + .BOOBBDABEBBEBAA + .BOBBBBBBEBEBBAA + .BBBBBBBEBBABBAA + .EBBBBBEABBABBAA + ..EEEEEAABBA.... + .....BBA.BB..... + ................ + ................ +} +# tile 174 (titanothere,male) { ................ ................ @@ -1699,7 +3352,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 88 (baluchitherium) +# tile 175 (titanothere,female) +{ + ................ + ................ + ................ + ..........PPP.P. + .......PPPPPPPAP + .....PPPPPPPPP.A + ..P.P.PPPPPPPP.A + ..PPP.PPPPPPPPPA + ..PPPP.PPPPPPPPA + .PPPPP.PPPPPPP.. + .PPEPP.PPPP.PPA. + PBPPP.PPP.AAPPA. + PPPP.AAPPAA..... + .PP.PPAPPA...... + ................ + ................ +} +# tile 176 (baluchitherium,male) { ................ ................ @@ -1718,7 +3390,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 89 (mastodon) +# tile 177 (baluchitherium,female) +{ + ................ + ................ + ................ + ..........PPP.P. + .......PPPPPPPAP + .....PPPPPPPPP.A + ..P.P.PPPPPPPP.A + ..PPP.PPPPPPPPPA + ..PPPP.PPPPPPPPA + BPPPPP.PPPPPPP.. + B.PEPP.PPPP.PPA. + PB.PP.PPP.AAPPA. + PPPP.AAPPAA..... + .PP.PPAPPA...... + ................ + ................ +} +# tile 178 (mastodon,male) { ................ ................ @@ -1737,7 +3428,26 @@ Z = (195, 195, 195) .......PPA...... ................ } -# tile 90 (sewer rat) +# tile 179 (mastodon,female) +{ + ................ + ................ + ................ + ................ + ................ + ..O...O......... + .N..POP.P....... + N..PNPPPPP...... + O.PNPPPPPP.PP... + O.POPEPPP.PPPPP. + .OPOPOP..PPPPPAP + ..PPOPP.PPPPPPAA + ..PPAAAPPPPAPPA. + ..P...APPAAAPPA. + .......PPA...... + ................ +} +# tile 180 (sewer rat,male) { ................ ................ @@ -1756,7 +3466,26 @@ Z = (195, 195, 195) .........JJA.... ................ } -# tile 91 (giant rat) +# tile 181 (sewer rat,female) +{ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ..K..K.JKKKK.... + ..KKKKJKKJKKK... + ..JAKAKJJJKKKJ.. + ..GKGKJKAKKAKKA. + .KKJJJJKAKAAKKA. + .PJJAAKKAJAJKA.. + ..AA.KKA..JKA... + .........JJA.... + ................ +} +# tile 182 (giant rat,male) { ................ ................ @@ -1775,7 +3504,26 @@ Z = (195, 195, 195) ..........JJA... ................ } -# tile 92 (rabid rat) +# tile 183 (giant rat,female) +{ + ................ + ................ + ................ + ................ + ................ + ................ + ..K..K.JKKKKK... + ..KKKKJKKKJKKK.. + ..JAKAKJKJJKKKJ. + ..GAGAKJKJJKKKK. + ..AKAKJKKAKKAKKA + .KKJJJJKAJKAAKKA + .PJJAAKKAJJAJKA. + ..AA.KKAA..JKA.. + ..........JJA... + ................ +} +# tile 184 (rabid rat,male) { ................ ................ @@ -1794,7 +3542,26 @@ Z = (195, 195, 195) .OOOOOOOO.JJA... ................ } -# tile 93 (wererat) +# tile 185 (rabid rat,female) +{ + ................ + ................ + ................ + ................ + ................ + ................ + ..K..K.JKKKKK... + ..KKKKJKKKJKKK.. + ..JAKAKJKJJKKKJ. + ..GAGAKJKJJKKKK. + ..AKAKJKKAKKAKKA + .KKJOOOKAJKAAKKA + .PJOOAKKAJJAJKA. + ..AOOOKAA..JKA.. + .OOOOOOOO.JJA... + ................ +} +# tile 186 (wererat,male) { ................ ................ @@ -1813,7 +3580,26 @@ Z = (195, 195, 195) ..........JJA... ................ } -# tile 94 (rock mole) +# tile 187 (wererat,female) +{ + ................ + ................ + ................ + ................ + ................ + ................ + ..K..K.JKKKKK... + ..KKKKJKKKJKKK.. + ..LLLLKJKJJKKKJ. + ..FLFLLJKJJKKKK. + ..LLLLJKKAKKAKKA + .KKJJJJKAJKAAKKA + .PJJAAKKAJJAJKA. + ..AA.KKAA..JKA.. + ..........JJA... + ................ +} +# tile 188 (rock mole,male) { ................ ................ @@ -1832,7 +3618,26 @@ Z = (195, 195, 195) AN.NAA.AA...AA.. .AAAA........... } -# tile 95 (woodchuck) +# tile 189 (rock mole,female) +{ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + .......AAAAA.... + ...AAAAAAAAAA... + ..AAAAAAAAAAAA.. + ..JAJAAAAAAAAAA. + .AAAAAAAAAAAAAA. + AN.NAAAAAAAAAAA. + A...AAAA...AAA.. + AN.NAA.AA...AA.. + .AAAA........... +} +# tile 190 (woodchuck,male) { ................ ................ @@ -1851,7 +3656,26 @@ Z = (195, 195, 195) .....JJAAJJAA... ................ } -# tile 96 (cave spider) +# tile 191 (woodchuck,female) +{ + ................ + ................ + ................ + ................ + ................ + ................ + .......KJA...... + ......NKKNA..... + ......KNOJA..... + ......KNOJA..... + .....KKKKKJA.... + ....JJKLLJJJAA.. + ......KLLJAAAAA. + ......KJJJAAAA.. + .....JJAAJJAA... + ................ +} +# tile 192 (cave spider,male) { ................ ................ @@ -1870,7 +3694,26 @@ Z = (195, 195, 195) .....PAA.APA.... ................ } -# tile 97 (centipede) +# tile 193 (cave spider,female) +{ + ................ + ................ + ................ + ................ + ................ + ........PA...... + .......PA....... + ......PAPBBA.... + ...PA.APBPPPA... + ...ABBPPAPPAA.PA + ...GPPPPAAAPPPAA + ...PPGPAAPPAAAA. + ..D.PAPAPAAPPA.. + ....D.PAAPA.APA. + .....PAA.APA.... + ................ +} +# tile 194 (centipede,male) { ................ ................ @@ -1889,7 +3732,26 @@ Z = (195, 195, 195) ...B............ ................ } -# tile 98 (giant spider) +# tile 195 (centipede,female) +{ + ................ + ................ + ......PBPP...... + ....BBPAAA...... + ..PPBAAA........ + .PAPBBBPPPP..... + ..PAAPPBBBA..... + ....PAAPAPBPP... + ......AABBPP.... + ......BB.PPAP... + ....PBBPPAP.A... + ...GPPPAP.AP.... + ...PPGPAAP...... + ..B.PAA......... + ...B............ + ................ +} +# tile 196 (giant spider,male) { ................ ................ @@ -1908,7 +3770,26 @@ Z = (195, 195, 195) .....JAA.AJA.... ................ } -# tile 99 (scorpion) +# tile 197 (giant spider,female) +{ + ................ + ................ + ................ + ................ + ................ + ........JA...... + .......JA....... + ......JAJKKA.... + ...JA.AJKJJJA... + ...AKKJJAJJAA.JA + ...GJJJJAAAJJJAA + ...JJGJAAJJAAAA. + ..D.JAJAJAAJJA.. + ....D.JAAJA.AJA. + .....JAA.AJA.... + ................ +} +# tile 198 (scorpion,male) { ................ ................ @@ -1927,7 +3808,26 @@ Z = (195, 195, 195) .......JAAJA.... ................ } -# tile 100 (lurker above) +# tile 199 (scorpion,female) +{ + ................ + ................ + .......JKJKJAA.. + ......JA.JKJKKA. + .......KA...JJJA + ......JA....KKJA + ...........JJJKA + .......AJKKAJJA. + .....AAJKJJJAA.. + ...AKKJJAJJAA... + ...GJJJJAAAJJJA. + ...JJGJAAJJAAAJ. + ..D.JAJAJAAJJA.. + ....D.JAAJA.JAA. + .......JAAJA.... + ................ +} +# tile 200 (lurker above,male) { .AAAAAAAAAAAAAAA ...AAGFAAGFAAA.. @@ -1946,7 +3846,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 101 (trapper) +# tile 201 (lurker above,female) +{ + .AAAAAAAAAAAAAAA + ...AAGFAAGFAAA.. + ...AAAAAAAAAAA.. + ....AODODODOA... + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ................ +} +# tile 202 (trapper,male) { ................ ................ @@ -1965,7 +3884,26 @@ Z = (195, 195, 195) ...AAGFAAGFAAA.. .AAAAAAAAAAAAAAA } -# tile 102 (pony) +# tile 203 (trapper,female) +{ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ....AODODODOA... + ...AAAAAAAAAAA.. + ...AAGFAAGFAAA.. + .AAAAAAAAAAAAAAA +} +# tile 204 (pony,male) { ................ ................ @@ -1984,7 +3922,26 @@ Z = (195, 195, 195) .....LA...L..... ................ } -# tile 103 (white unicorn) +# tile 205 (pony,female) +{ + ................ + ................ + .....JJ......... + ....KKKJ........ + ...KKEKJ........ + ..KKJKKJ........ + ..JJAKKJAA...... + ...AKKKJA....... + ...KKKKKKKJ..... + ...KKKKKKKJJAAA. + ...KJKJJJJJAJA.. + ...JAJAAAAJAA... + ...JAJAAJAJA.... + ...L.JAALAJ..... + .....LA...L..... + ................ +} +# tile 206 (white unicorn,male) { ................ ..HP............ @@ -2003,7 +3960,26 @@ Z = (195, 195, 195) .....LA...L..... ................ } -# tile 104 (gray unicorn) +# tile 207 (white unicorn,female) +{ + ................ + ..HP............ + ..PHO.NN........ + ...PHNNB........ + ...ONENB........ + ..ONNNNB........ + ..NOANNBAA...... + ...AONNBA....... + ...ONNNONNN..... + ..NONNNNONNOAAA. + ..N.ONONNONAOA.. + ..OAANAAAAOAA... + ...LAOAAOAOA.... + .....OAALAO..... + .....LA...L..... + ................ +} +# tile 208 (gray unicorn,male) { ................ ..HP............ @@ -2022,7 +3998,26 @@ Z = (195, 195, 195) .....LA...L..... ................ } -# tile 105 (black unicorn) +# tile 209 (gray unicorn,female) +{ + ................ + ..HP............ + ..PHO.PP........ + ...PHPPN........ + ....PGPN........ + ...PPPPN........ + ..PPAPPNAA...... + ...APPPNA....... + ....PPP.PPP..... + ..P.PPPP.PP.AAA. + ..P..P.PP.PA.A.. + ..PAAPAAAA.AA... + ...LA.AA.A.A.... + ......AALA...... + .....LA...L..... + ................ +} +# tile 210 (black unicorn,male) { ................ ..HP............ @@ -2041,7 +4036,26 @@ Z = (195, 195, 195) .....LP...L..... ................ } -# tile 106 (horse) +# tile 211 (black unicorn,female) +{ + ................ + ..HP............ + ..PHO.AA........ + ...PHAAJ........ + ...AADAJ........ + ..AAAAAJ........ + ..AAPAAJPP...... + ...PAAAJP....... + ...AAAAAAAA..... + ..AAAAAAAAAAPPP. + ..A.AAAAAAAPAP.. + ..APPAPPAPAPP... + ...LPAPPAPAP.... + .....APPLPA..... + .....LP...L..... + ................ +} +# tile 212 (horse,male) { ................ ................ @@ -2060,7 +4074,26 @@ Z = (195, 195, 195) .....LA....L.... ................ } -# tile 107 (warhorse) +# tile 213 (horse,female) +{ + ................ + ................ + .....JJ......... + ....KKKJ........ + ..KKKEKJ........ + .KKKJKKJAA...... + .JJJAKKJAA...... + ...AKKKJA....... + ...KKKKKKKKJA... + ..KKKKKKKKKKJA.. + ..KJJKJJJJJKAJA. + ..JAAJAAAAAJAJA. + ..JAAJAAAJAJAA.. + ..LA.JAA.L.JA... + .....LA....L.... + ................ +} +# tile 214 (warhorse,male) { ................ .....JJJ........ @@ -2079,7 +4112,26 @@ Z = (195, 195, 195) .....LC....LC... ................ } -# tile 108 (fog cloud) +# tile 215 (warhorse,female) +{ + ................ + .....JJJ........ + ...KKKKJJ....... + .KKKKEKJJ....... + KKKKKKKJJAA..... + JKKKJKKJJAA..... + .JJJAKKJJAA..... + ...AKKKJJA...... + ...KKKKKKKKKJA.. + ..KKKKKKKKKKKJA. + ..KKJKKJKKJKKJJA + ..KJAKJAKJAKJAJA + ..KJAKJAKJAKJA.. + ..LC.KJALC.KJ... + .....LC....LC... + ................ +} +# tile 216 (fog cloud,male) { .......P........ ....P..P........ @@ -2098,7 +4150,26 @@ Z = (195, 195, 195) ..P..P.P..P..... ................ } -# tile 109 (dust vortex) +# tile 217 (fog cloud,female) +{ + .......P........ + ....P..P........ + .....P.P...P.... + ...P.......P.... + ..P..P.P.P...... + ....PP.PP.P.P... + .P..APAPPP..P... + ...P.PPPP.PP.... + ......PPPPP.P.P. + ...P.PPPPP..P... + ....P..P.PP.P... + .P...P.P...PPP.. + ..P.P....PP..... + .......P....P... + ..P..P.P..P..... + ................ +} +# tile 218 (dust vortex,male) { ................ ................ @@ -2117,7 +4188,26 @@ Z = (195, 195, 195) ....KKKK..K..... ................ } -# tile 110 (ice vortex) +# tile 219 (dust vortex,female) +{ + ................ + ................ + ....K..KKKK..... + ...K..KKJJJK.... + ..K..KJJJJ..K... + .KJ.KJJ.JKK..K.. + .KJJKJ.JJJJK.... + .KJJJJ....JJK... + .KKJ.J...J.JKK.. + ..KJJ....JJJJK.. + ...KJJJJ.JKJJK.. + .K..KKJ.JJK.JK.. + ..K..JJJJK..K... + ...KJJJKK..K.... + ....KKKK..K..... + ................ +} +# tile 220 (ice vortex,male) { ................ ................ @@ -2136,7 +4226,26 @@ Z = (195, 195, 195) ....NNNN..N..... ................ } -# tile 111 (energy vortex) +# tile 221 (ice vortex,female) +{ + ................ + ................ + ....N..NNNN..... + ...N..NNOOON.... + ..N..NOOOO..N... + .NO.NOO.ONN..N.. + .NOONO.OOOON.... + .NOOOO....OON... + .NNO.O...O.ONN.. + ..NOO....OOOON.. + ...NOOOO.ONOON.. + .N..NNO.OON.ON.. + ..N..OOOON..N... + ...NOOONN..N.... + ....NNNN..N..... + ................ +} +# tile 222 (energy vortex,male) { ................ ................ @@ -2155,7 +4264,26 @@ Z = (195, 195, 195) ....EEEE..E..... ................ } -# tile 112 (steam vortex) +# tile 223 (energy vortex,female) +{ + ................ + ................ + ....E..EEEE..... + ...E..EEAAAE.... + ..E..EAAAA..E... + .EA.EAAAAIE..E.. + .EAAIAAAAAAE.... + .EAAAAAAAAAAE... + .EEAAAAAAAAAEE.. + ..EAAAAAAAAAAE.. + ...EAAAAAAIAAE.. + .E..EIAAAAE.AE.. + ..E..AAAAE..E... + ...EAAAEE..E.... + ....EEEE..E..... + ................ +} +# tile 224 (steam vortex,male) { ................ ................ @@ -2174,7 +4302,26 @@ Z = (195, 195, 195) ....PPPP..P..... ................ } -# tile 113 (fire vortex) +# tile 225 (steam vortex,female) +{ + ................ + ................ + ....P..PPPP..... + ...P..PPBBBP.... + ..P..PBBBB..P... + .PB.PBBPBPP..P.. + .PBBPBPBBBBP.... + .PBBBBP.PPBBP... + .PPBPB...BPBPP.. + ..PBBPP.PBBBBP.. + ...PBBBBPBPBBP.. + .P..PPBPBBP.BP.. + ..P..BBBBP..P... + ...PBBBPP..P.... + ....PPPP..P..... + ................ +} +# tile 226 (fire vortex,male) { ................ ................ @@ -2193,7 +4340,26 @@ Z = (195, 195, 195) ....DDDD..D..... ................ } -# tile 114 (baby long worm) +# tile 227 (fire vortex,female) +{ + ................ + ................ + ....D..DDDD..... + ...D..DDCCCD.... + ..D..DCCCC..D... + .DC.DCCHCDD..D.. + .DCCDCHCCCCD.... + .DCCCCHHHHCCD... + .DDCHCHHHCHCDD.. + ..DCCHHHHCCCCD.. + ...DCCCCHCDCCD.. + .D..DDCHCCD.CD.. + ..D..CCCCD..D... + ...DCCCDD..D.... + ....DDDD..D..... + ................ +} +# tile 228 (baby long worm,male) { ................ ................ @@ -2212,7 +4378,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 115 (baby purple worm) +# tile 229 (baby long worm,female) +{ + ................ + ................ + ................ + ................ + ......CLC....... + ......LLL....... + .....GGAGG.A.... + .....GGAGGAAA... + ......LLLAAA.C.. + ......LLLAA.CC.. + ......CLLCCCCA.. + .......LLLCCA... + ........CLL..... + ................ + ................ + ................ +} +# tile 230 (baby purple worm,male) { ................ ................ @@ -2231,7 +4416,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 116 (long worm) +# tile 231 (baby purple worm,female) +{ + ................ + ................ + ................ + .......I........ + ......III....... + ......III....... + .....GGAGG.A.... + .....GGAGGAAA... + ......IIIAAA.D.. + ......IIIAA.DD.. + ......IIIDDDDA.. + .......IIIDDA... + ........III..... + ................ + ................ + ................ +} +# tile 232 (long worm,male) { ................ ................ @@ -2250,7 +4454,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 117 (purple worm) +# tile 233 (long worm,female) +{ + ................ + ................ + .....CLC........ + ....CLLLC....... + ....LLLLL....... + ...GGGLGGGAA.... + ...GAGLGAGAAA... + ...GGGLGGGAAA... + ....LLLLLAAACC.. + ....LLLLLAACCC.. + ....CLLLLCCCCA.. + .....LLLLLCCA... + ......CLLLL..... + ................ + ................ + ................ +} +# tile 234 (purple worm,male) { ................ ................ @@ -2269,7 +4492,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 118 (grid bug) +# tile 235 (purple worm,female) +{ + ................ + ................ + .....DID........ + ....DIIID....... + ....IIIII....... + ...GGGIGGGAA.... + ...GAGIGAGAAA... + ...GGGIGGGAAA... + ....IIIIIAAADD.. + ....IIIIIAADDD.. + ....DIIIIDDDDA.. + .....IIIIIDDA... + ......DIIII..... + ................ + ................ + ................ +} +# tile 236 (grid bug,male) { ................ ................ @@ -2288,7 +4530,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 119 (xan) +# tile 237 (grid bug,female) +{ + ................ + ................ + ................ + ................ + ..D....NHCN..D.. + .D.D..NHDNCNDED. + D.D.D.NNHCND.DED + .D...D.NNHDND... + .DDD..ENNG.D.DE. + ..DDDDEEEEGD..DE + D.....DEHEE.D... + .D.......H...... + ................ + ................ + ................ + ................ +} +# tile 238 (xan,male) { ................ ................ @@ -2307,7 +4568,26 @@ Z = (195, 195, 195) ..G..AAAAAA..... ......AA.AA..... } -# tile 120 (yellow light) +# tile 239 (xan,female) +{ + ................ + ................ + ..........GG.... + ...HHH...GOGG... + .....HH..GGGG... + ...HHHHH.GGG.... + .......GG...AAA. + .....GOGGHHAAAA. + ....GOGG..HHAAA. + NNNGOGG.AAHHHA.. + NANGGGG.AAHAH... + NNNGGNNNAAAAAA.. + ..GGGNANAA.AAA.. + .GGGANNNAA.A.A.. + ..G..AAAAAA..... + ......AA.AA..... +} +# tile 240 (yellow light,male) { ................ ......NA........ @@ -2326,7 +4606,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 121 (black light) +# tile 241 (yellow light,female) +{ + ................ + ......NA........ + ......HA........ + ..NA.NHNA.NA.... + ...LALHLALA..... + ....NHHHNA...... + ..NLHHHHHLNA.... + NHHHHHHHHHHHNA.. + ..NLHHHHHLNA.... + ....NHHHNA...... + ...LALHLALA..... + ..NA.NNNA.NA.... + ......HA........ + ......NA........ + ................ + ................ +} +# tile 242 (black light,male) { ................ ......AA........ @@ -2345,7 +4644,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 122 (zruty) +# tile 243 (black light,female) +{ + ................ + ......AA........ + ......AA........ + ..AA.AAAA.AA.... + ...AAAAAAAA..... + ....AAAAAA...... + ..AAAAAAAAAA.... + AAAAAAAAAAAAAA.. + ..AAAAAAAAAA.... + ....AAAAAA...... + ...AAAAAAAA..... + ..AA.AAAA.AA.... + ......AA........ + ......AA........ + ................ + ................ +} +# tile 244 (zruty,male) { ................ ......FFGF...... @@ -2364,7 +4682,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 123 (couatl) +# tile 245 (zruty,female) +{ + ................ + ......FFGF...... + ....OOFGFFFF.... + ...AOFGFOOKFF... + ...FFGFAOAJKKF.. + ..FFFFFFJAAJKK.. + ..ODOFFJAJJKKJA. + ..DDDDJAJJKJJAA. + ..JODOAJJJAJJAAA + .KKJAJJJKJAJJAAA + .KKAAJKKKKJAAAAA + ...AJJKKKKJJAAAA + ...KJJAAAAKJAAA. + ..JKJJJAAJJJJ... + ................ + ................ +} +# tile 246 (couatl,male) { ................ ................ @@ -2383,7 +4720,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 124 (Aleax) +# tile 247 (couatl,female) +{ + ................ + ................ + ........I....I.. + ....KKAIII..III. + ...NAOJAKI.IIIII + ...KKJAJJKKK..II + ...KKAAIJJJJJ..I + ...FAA.I...KJ..I + ..FAFA..AAAKJAA. + .......AAAJJAAA. + ......AKKJJAAA.. + ......KJAAAAAJA. + .....JJAA...JA.. + ......JJJJJJA... + ................ + ................ +} +# tile 248 (Aleax,male) { ................ ......BBBB..I... @@ -2402,7 +4758,26 @@ Z = (195, 195, 195) ..BF.LLAALLAFB.. ................ } -# tile 125 (Angel) +# tile 249 (Aleax,female) +{ + ................ + ......BBBB..I... + ..I..BF...B..... + ....BF.HHA.B.... + ...BF.HHHHA.B.I. + ...BF.LFLFA.FB.. + .I.BF.LLLLA.FB.. + ...BF.ALLA.FB... + ..BF.LJAAJL.ABA. + .BF.LLJJJJLLAFB. + .BF.LAJKJJALAFB. + .BF.LAJJKJALAFB. + ..BF..LJJLAAABA. + ...BF.LLALAABA.. + ..BF.LLAALLAFB.. + ................ +} +# tile 250 (Angel,male) { ................ ................ @@ -2421,7 +4796,26 @@ Z = (195, 195, 195) ....BNNNNNNP.... ................ } -# tile 126 (ki-rin) +# tile 251 (Angel,female) +{ + ................ + ................ + ......HHHH...... + ................ + .......CC....... + ......CLLC..AA.. + ......PLLP....A. + ......NPPPA.A... + .....BBLLPPAAA.. + .....NNLLPPAAA.. + ......BNNPAAAA.. + ......BNNPAAAA.. + .....BNNNPAA.A.. + .....BNNNNPA.... + ....BNNNNNNP.... + ................ +} +# tile 252 (ki-rin,male) { ................ ................ @@ -2440,7 +4834,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 127 (Archon) +# tile 253 (ki-rin,female) +{ + ................ + ................ + ..LP............ + ..PLO.C.C....... + ...PLCCD........ + ...KCIKD........ + ..KCCCCD........ + ..CKACCDA....... + ...ACCCCCC...A.. + ...KCCCKCCKAA... + ..CAKCKCKCAKA... + ..CAAKAKAKA..... + ...L.KALAK...... + .....LA..L...... + ................ + ................ +} +# tile 254 (Archon,male) { ................ ......OOOO...... @@ -2459,7 +4872,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 128 (bat) +# tile 255 (Archon,female) +{ + ................ + ......OOOO...... + .....OOOOOO..... + .....OJLLJO..... + .....OLLLLO..... + ....OOKLLKOO.... + ......AKKA...... + .....AAAAAAA.... + ....AAAAAAAAA... + ...OAAOAAAJLJ... + ..OOAOAAAACJC... + ....LAAAACCJCC.. + .....AAAAAJJJ... + ....AAAAAAAA.... + ................ + ................ +} +# tile 256 (bat,male) { ................ ................ @@ -2478,7 +4910,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 129 (giant bat) +# tile 257 (bat,female) +{ + ................ + ................ + ................ + ................ + ...JJJCACJJJ.... + ..JJAAHJHAAJJ... + ..JA...JA..AJ... + ................ + ................ + ......AAAA...... + ....AAAAAAAA.... + ...AAA.AA.AAA... + .......AA....... + ................ + ................ + ................ +} +# tile 258 (giant bat,male) { ................ ................ @@ -2497,7 +4948,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 130 (raven) +# tile 259 (giant bat,female) +{ + ................ + ................ + ................ + ...JK.J.J.JK.... + ..KJJJCACJJKJ... + .JJJAAHJHAAJJK.. + .KJA...JA..AJJ.. + ..JA.......AJ... + ................ + .....AAAAAA..... + ...AAAAAAAAAA... + ..AAAA.AA.AAAA.. + .......AA....... + ................ + ................ + ................ +} +# tile 260 (raven,male) { ..AAAA...AAA.... .AAAAAA.AAA..... @@ -2516,7 +4986,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 131 (vampire bat) +# tile 261 (raven,female) +{ + ..AAAA...AAA.... + .AAAAAA.AAA..... + AAAAAAAAAAA.AA.. + A...AAAAAAAAAAA. + ......AAAAAAAAA. + .....AAAA.....AA + .....ADA.......A + .....PA......... + .....P.......... + .........P.P.P.. + ........P.P.P.P. + .......P.P.P.... + ........P.P.P... + ...........P.... + ................ + ................ +} +# tile 262 (vampire bat,male) { ................ ................ @@ -2535,7 +5024,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 132 (plains centaur) +# tile 263 (vampire bat,female) +{ + ................ + ................ + ................ + ...AA.A.A.AA.... + ..AAAAAAAAAAA... + .AAAA.DAD.AAAA.. + .AAA...A...AAA.. + ..A.........A... + ................ + .....AAAAAA..... + ...AAAAAAAAAA... + ..AAAA.AA.AAAA.. + .......AA....... + ................ + ................ + ................ +} +# tile 264 (plains centaur,male) { ................ ...KKA.......... @@ -2554,7 +5062,26 @@ Z = (195, 195, 195) ....CA...C...... ................ } -# tile 133 (forest centaur) +# tile 265 (plains centaur,female) +{ + ................ + ...KKA.......... + ...LLAA......... + .AAKKAA......... + .LLAALLA........ + LALLLLALA....... + LALLLKALA.A..... + ..LKLKAAAAA..... + ..KLKJKJJKAA.... + .KJKJKJKJAKAAAA. + .KAKJJJJKJAAA.A. + .KAAKAAAAKAA.... + ..CAKAAJAKA..... + ....KAAKAK...... + ....CA...C...... + ................ +} +# tile 266 (forest centaur,male) { ................ ................ @@ -2573,7 +5100,26 @@ Z = (195, 195, 195) ....CA...C...... ................ } -# tile 134 (mountain centaur) +# tile 267 (forest centaur,female) +{ + ................ + ................ + ................ + ...KKA.......... + LA.LLAALA....... + LAALLAALA....... + .LLAALLA........ + ..LLLLA.A....... + ..LKLKAAAAA..... + ..KLKJKJJKAA.... + .KJKJKJKJAKA.A.. + .KAKJJJJKJAAAA.. + .KAAKAAJAKA..... + ..C.KAAKAK...... + ....CA...C...... + ................ +} +# tile 268 (mountain centaur,male) { ................ ................ @@ -2592,7 +5138,26 @@ Z = (195, 195, 195) ....CA...C...... ................ } -# tile 135 (baby gray dragon) +# tile 269 (mountain centaur,female) +{ + ................ + ................ + ...KKA.......... + ...LLAA......... + ..AKKAA......... + .LJJJJLA........ + LAJKKJALA.A..... + LAKKKKALAAA..... + ..JJJJKJJKAA.... + .KJJJKJKJAKAAAA. + .KAKJJJJKJAAA.A. + .KAAKAAAAKAA.... + ..CAKAAJAKA..... + ....KAAKAK...... + ....CA...C...... + ................ +} +# tile 270 (baby gray dragon,male) { ................ ................ @@ -2611,7 +5176,26 @@ Z = (195, 195, 195) .....BPAA..PPAA. ...........PAA.. } -# tile 136 (baby silver dragon) +# tile 271 (baby gray dragon,female) +{ + ................ + ................ + ................ + .....BBBA....... + ....NPNPPA...... + ...BPPPPPA...... + ..CHHPABPA.AAA.. + .CHCDA.BPAAAAAA. + ..D..BPPAAAAAAA. + ....BBPPPPPAAAA. + ...BOOPPPPPPAAA. + ..BPOBPPPPPPPAA. + ..BPPBPPOBPAPPA. + ..BPABP.ABPAPPA. + .....BPAA..PPAA. + ...........PAA.. +} +# tile 272 (baby silver dragon,male) { ................ ................ @@ -2630,7 +5214,26 @@ Z = (195, 195, 195) .....PBAA..BBAA. ...........BAA.. } -# tile 137 (baby shimmering dragon) +# tile 273 (baby silver dragon,female) +{ + ................ + ................ + ................ + .....PPPA....... + ....OBOBBA...... + ...PBBBBBA...... + ..CHHBAPBA.AAA.. + .CHCDA.PBAAAAAA. + ..D..PBBAAAAAAA. + ....PPBBBBBAAAA. + ...PNNBBBBBBAAA. + ..PBNPBBBBBBBAA. + ..PBBPBBNPBABBA. + ..PBAPB.APBABBA. + .....PBAA..BBAA. + ...........BAA.. +} +# tile 274 (baby shimmering dragon,male) { .I.............. ...BBBBBBB.I.... @@ -2649,7 +5252,26 @@ Z = (195, 195, 195) B....BPAA..PPAAB .B.........PAAB. } -# tile 138 (baby red dragon) +# tile 275 (baby shimmering dragon,female) +{ + .I.............. + ...BBBBBBB.I.... + ..BF.FFF.FB...I. + .BF..BBBA.FB.... + BF..NPNPPAFB.I.. + BF.BPPPPPA.B.... + B.CHHPABPAFBAAI. + BCHCDA.BPAAFBAA. + B.D..BPPAAAAFBA. + B...BBPPPPPAAFB. + BF.BOOPPPPPPAAAB + BFBPOBPPPPPPPAFB + BFBPPBPPOBPAPPFB + B.BPABP.ABPAPPFB + B....BPAA..PPAAB + .B.........PAAB. +} +# tile 276 (baby red dragon,male) { ................ ................ @@ -2668,7 +5290,26 @@ Z = (195, 195, 195) .....IDAA..DDAA. ...........DAA.. } -# tile 139 (baby white dragon) +# tile 277 (baby red dragon,female) +{ + ................ + ................ + ................ + .....IIIA....... + ....NDNDDA...... + ...IDDDDDA...... + ..CHHDAIDA.AAA.. + .CHCDA.IDAAAAAA. + ..D..IDDAAAAAAA. + ....IIDDDDDAAAA. + ...IHHDDDDDDAAA. + ..IDHIDDDDDDDAA. + ..IDDIDDHIDADDA. + ..IDAID.AIDADDA. + .....IDAA..DDAA. + ...........DAA.. +} +# tile 278 (baby white dragon,male) { ................ ................ @@ -2687,7 +5328,26 @@ Z = (195, 195, 195) .....NOAA..OOAA. ...........OAA.. } -# tile 140 (baby orange dragon) +# tile 279 (baby white dragon,female) +{ + ................ + ................ + ................ + .....NNNA....... + ....IOIOOA...... + ...NOOOOOA...... + ..CHHOANOA.AAA.. + .CHCDA.NOAAAAAA. + ..D..NOOAAAAAAA. + ....NNOOOOOAAAA. + ...NOOOOOOOOAAA. + ..NOONOOOOOOOAA. + ..NOONOOONOAOOA. + ..NOANO.ANOAOOA. + .....NOAA..OOAA. + ...........OAA.. +} +# tile 280 (baby orange dragon,male) { ................ ................ @@ -2706,7 +5366,26 @@ Z = (195, 195, 195) .....LCAA..CCAA. ...........CAA.. } -# tile 141 (baby black dragon) +# tile 281 (baby orange dragon,female) +{ + ................ + ................ + ................ + .....LLLA....... + ....NCNCCA...... + ...LCCCCCA...... + ..CHHCALCA.AAA.. + .CHCDA.LCAAAAAA. + ..D..LCCAAAAAAA. + ....LLCCCCCAAAA. + ...LOOCCCCCCAAA. + ..LCOLCCCCCCCAA. + ..LCCLCCOLCACCA. + ..LCALC.ALCACCA. + .....LCAA..CCAA. + ...........CAA.. +} +# tile 282 (baby black dragon,male) { ................ ................ @@ -2725,7 +5404,26 @@ Z = (195, 195, 195) .....AAP...AAPP. ...........APP.. } -# tile 142 (baby blue dragon) +# tile 283 (baby black dragon,female) +{ + ................ + ................ + ................ + .....AAA........ + ....NANAA....... + ...AAAAAA....... + ..CHHA.AA..PPP.. + .CHCD..AA.PPPPP. + ..D..AAAPPP.PPP. + ....AAAAAAAPPPP. + ...AAAAAAAAAPPP. + ..AAAAAAAAAAAPP. + ..AAAAAAAAAPAAP. + ..AAPAA.PAAPAAP. + .....AAP...AAPP. + ...........APP.. +} +# tile 284 (baby blue dragon,male) { ................ ................ @@ -2744,7 +5442,26 @@ Z = (195, 195, 195) .....BEAA..EEAA. ...........EAA.. } -# tile 143 (baby green dragon) +# tile 285 (baby blue dragon,female) +{ + ................ + ................ + ................ + .....BBBA....... + ....NENEEA...... + ...BEEEEEA...... + ..CHHEABEA.AAA.. + CCHCDA.BEAAAAAA. + ..D..BEEAAAAAAA. + ....BBEEEEEAAAA. + ...BOOEEEEEEAAA. + ..BEOBEEEEEEEAA. + ..BEEBEEOBEAEEA. + ..BEABE.ABEAEEA. + .....BEAA..EEAA. + ...........EAA.. +} +# tile 286 (baby green dragon,male) { ................ ................ @@ -2763,7 +5480,26 @@ Z = (195, 195, 195) .....GFAA..FFAA. ...........FAA.. } -# tile 144 (baby yellow dragon) +# tile 287 (baby green dragon,female) +{ + ................ + ................ + ................ + .....GGGA....... + ....NFNFFA...... + ...GFFFFFA...... + ..CHHFAGFA.AAA.. + .CHCDA.GFAAAAAA. + ..D..GFFAAAAAAA. + ....GGFFFFFAAAA. + ...GOOFFFFFFAAA. + ..GFOGFFFFFFFAA. + ..GFFGFFOGFAFFA. + ..GFAGF.AGFAFFA. + .....GFAA..FFAA. + ...........FAA.. +} +# tile 288 (baby yellow dragon,male) { ................ ................ @@ -2782,7 +5518,26 @@ Z = (195, 195, 195) .....NHAA..HHAA. ...........HAA.. } -# tile 145 (gray dragon) +# tile 289 (baby yellow dragon,female) +{ + ................ + ................ + ................ + .....NNNA....... + ....DHDHHA...... + ...NHHHHHA...... + ..CHHHANHA.AAA.. + .CHCDA.NHAAAAAA. + ..D..NHHAAAAAAA. + ....NNHHHHHAAAA. + ...NOOHHHHHHAAA. + ..NHONHHHHHHHAA. + ..NHHNHHONHAHHA. + ..NHANH.ANHAHHA. + .....NHAA..HHAA. + ...........HAA.. +} +# tile 290 (gray dragon,male) { ......BBBPA..... .....NPNPPPA.... @@ -2801,7 +5556,26 @@ Z = (195, 195, 195) ....BPAA...PP.A. ........PPPP.A.. } -# tile 146 (silver dragon) +# tile 291 (gray dragon,female) +{ + ......BBBPA..... + .....NPNPPPA.... + ....BPPPPPPA.... + ..DCHHP..PPA.... + CHCHCD..BPPA.... + HD.D...BPPA..... + ......OBPAAAAAA. + ....BOBPAAAAAAAA + ..BOOBPA.PP.AAA. + .BOOOBPPPPPP.AA. + .BOOOBPPPPPPPAA. + PPOOBBPPPPPPPPA. + BP.OBPPOOPP.P.A. + BPAABP.AAPPAPPA. + ....BPAA...PP.A. + ........PPPP.A.. +} +# tile 292 (silver dragon,male) { ......PPPBA..... .....OBOBBBA.... @@ -2820,7 +5594,26 @@ Z = (195, 195, 195) ....PBAA...BB.A. ........BBBB.A.. } -# tile 147 (shimmering dragon) +# tile 293 (silver dragon,female) +{ + ......PPPBA..... + .....OBOBBBA.... + ....PBBBBBBA.... + ..DCHHB..BBA.... + CHCHCD..PBBA.... + HD.D...PBBA..... + ......NPBAAAAAA. + ....PNPBAAAAAAAA + ..PNNPBA.BB.AAA. + .PNNNPBBBBBB.AA. + .PNNNPBBBBBBBAA. + BBNNPPBBBBBBBBA. + PB.NPBBNNBB.B.A. + PBAAPB.AABBABBA. + ....PBAA...BB.A. + ........BBBB.A.. +} +# tile 294 (shimmering dragon,male) { .I.BF.BBBPAFB... ..BF.NPNPPPAFB.I @@ -2839,7 +5632,26 @@ Z = (195, 195, 195) ....BPAA...PP.AB ........PPPP.AB. } -# tile 148 (red dragon) +# tile 295 (shimmering dragon,female) +{ + .I.BF.BBBPAFB... + ..BF.NPNPPPAFB.I + .BF.BPPPPPPAFB.. + .BDCHHP..PPAFBI. + CBCHCD..BPPAFB.. + HDBB...BPPA.B..I + ..BF..OBPAAAABA. + .BF.BOBPAAAAAFBA + BFBOOBPA.PP.AAFB + .BOOOBPPPPPP.AFB + .BOOOBPPPPPPPAFB + PPOOBBPPPPPPPPFB + BP.OBPPOOPP.P.FB + BPAABP.AAPPAPPFB + ....BPAA...PP.AB + ........PPPP.AB. +} +# tile 296 (red dragon,male) { ......IIIDA..... .....NDNDDDA.... @@ -2858,7 +5670,26 @@ Z = (195, 195, 195) ....IDAAJJJDDJA. ........DDDDJA.. } -# tile 149 (white dragon) +# tile 297 (red dragon,female) +{ + ......IIIDA..... + .....NDNDDDA.... + ....IDDDDDDA.... + ..DCHHD..DDA.... + CHCHCD..IDDA.... + HD.D...IDDA..... + ......HIDAAAAAA. + ....IHIDAAAAAAAA + ..IHHIDAJDDJAAA. + .IHHHIDDDDDDJAA. + .IHHHIDDDDDDDAA. + DDHHIIDDDDDDDDA. + ID.HIDDHHDDJDJA. + IDAAID.AADDADDA. + ....IDAAJJJDDJA. + ........DDDDJA.. +} +# tile 298 (white dragon,male) { ......NNNOA..... .....IOIOOOA.... @@ -2877,7 +5708,26 @@ Z = (195, 195, 195) ....NOAA...OOJA. ........OOOOJA.. } -# tile 150 (orange dragon) +# tile 299 (white dragon,female) +{ + ......NNNOA..... + .....IOIOOOA.... + ....NOOOOOOA.... + ..DCHHO..OOA.... + CHCHCD..NOOA.... + HD.D...NOOA..... + ......ONOAAAAAA. + ....NONOAAAAAAAA + ..NOONOA.OO.AAA. + .NOOONOOOOOOJAA. + .NOOONOOOOOOOAA. + OOOONNOOOOOOOOA. + NO.ONOOOOOO.OJA. + NOAANO.AAOOAOOA. + ....NOAA...OOJA. + ........OOOOJA.. +} +# tile 300 (orange dragon,male) { ......LLLCA..... .....NCNCCCA.... @@ -2896,7 +5746,26 @@ Z = (195, 195, 195) ....LCAA.KKCCJA. ........CCCCJA.. } -# tile 151 (black dragon) +# tile 301 (orange dragon,female) +{ + ......LLLCA..... + .....NCNCCCA.... + ....LCCCCCCA.... + ..DCHHC..CCA.... + CHCHCD..LCCA.... + HD.D...LCCA..... + ......OLCAAAAAA. + ....LOLCAAAAAAAA + ..LOOLCA.CCKAAA. + .LOOOLCCCCCCJAA. + .LOOOLCCCCCCCAA. + CCOOLLCCCCCCCCA. + LC.OLCCOOCCKCJA. + LCAALC.AACCACCA. + ....LCAA.KKCCJA. + ........CCCCJA.. +} +# tile 302 (black dragon,male) { ......AAAA...... .....NANAAA..... @@ -2915,7 +5784,26 @@ Z = (195, 195, 195) ....AAPP...AAAP. ........AAAAA... } -# tile 152 (blue dragon) +# tile 303 (black dragon,female) +{ + ......AAAA...... + .....NANAAA..... + ....AAAAAAA..... + ..DCHHA..AA..... + CHCHCD..AAA..... + HD.D...AAA...... + ......AAA..PPPP. + ....AAAAPPPPPPPP + ..AAAAAAAAA.PPP. + .AAAAAAAAAAAAPP. + .AAAAAAAAAAAAPP. + AAAAAAAAAAAAAAP. + AA.AAAAAAAA.AAP. + AAPPAA.PPAAPAAP. + ....AAPP...AAAP. + ........AAAAA... +} +# tile 304 (blue dragon,male) { ......BBBEA..... .....NENEEEA.... @@ -2934,7 +5822,26 @@ Z = (195, 195, 195) ....BEAA...EEJA. ...P....EEEEJA.. } -# tile 153 (green dragon) +# tile 305 (blue dragon,female) +{ + ......BBBEA..... + .....NENEEEA.... + ....BEEEEEEA.... + ..DCHHE..EEA.... + CHCHCD..BEEA.... + HD.D...BEEA..... + ......OBEAAAAAA. + ....BOBEAAAAAAAA + ..BOOBEA.EE.AAA. + .BOOOBEEEEEEJAA. + .BOOOBEEEEEEEAA. + EEOOBBEEEEEEEEA. + BE.OBEEOOEE.EJA. + BEAABE.AAEEAEEA. + ....BEAA...EEJA. + ...P....EEEEJA.. +} +# tile 306 (green dragon,male) { ......GGGFA..... .....NFNFFFA.... @@ -2953,7 +5860,26 @@ Z = (195, 195, 195) ....GFAA...FFJA. ........FFFFJA.. } -# tile 154 (yellow dragon) +# tile 307 (green dragon,female) +{ + ......GGGFA..... + .....NFNFFFA.... + ....GFFFFFFA.... + ..DCHHF..FFA.... + CHCHCD..GFFA.... + HD.D...GFFA..... + ......OGFAAAAAA. + ....GOGFAAAAAAAA + ..GOOGFA.FF.AAA. + .GOOOGFFFFFFJAA. + .GOOOGFFFFFFFAA. + FFOOGGFFFFFFFFA. + GF.OGFFOOFF.FJA. + GFAAGF.AAFFAFFA. + ....GFAA...FFJA. + ........FFFFJA.. +} +# tile 308 (yellow dragon,male) { ......NNNHA..... .....DHDHHHA.... @@ -2972,7 +5898,26 @@ Z = (195, 195, 195) ....NHAAJJJHHJA. ........HHHHJA.. } -# tile 155 (stalker) +# tile 309 (yellow dragon,female) +{ + ......NNNHA..... + .....DHDHHHA.... + ....NHHHHHHA.... + ..DCHHH..HHA.... + CHCHCD..NHHA.... + HD.D...NHHA..... + ......ONHAAAAAA. + ....NONHAAAAAAAA + ..NOONHAJHHJAAA. + .NOOONHHHHHHJAA. + .NOOONHHHHHHHAA. + HHOONNHHHHHHHHA. + NH.ONHHOOHHJHJA. + NHAANH.AAHHAHHA. + ....NHAAJJJHHJA. + ........HHHHJA.. +} +# tile 310 (stalker,male) { ................ .......PPP...... @@ -2991,7 +5936,26 @@ Z = (195, 195, 195) .....PP..PP..... ................ } -# tile 156 (air elemental) +# tile 311 (stalker,female) +{ + ................ + .......PPP...... + ......P.P.P..... + .....PPPPPP..... + .....PP..PPP.... + ....PPPPPP.P.... + ....P.PPPP.P.... + ....P.PPP..P.... + ....P..PP..P.... + ....P.PPPP.P.... + ....P.P..P.P.... + ....P.P..P.P.... + ......P..P...... + ......P..P...... + .....PP..PP..... + ................ +} +# tile 312 (air elemental,male) { ................ ...P.PPP..P..... @@ -3010,7 +5974,26 @@ Z = (195, 195, 195) ...PP.APPPA..... ................ } -# tile 157 (fire elemental) +# tile 313 (air elemental,female) +{ + ................ + ...P.PPP..P..... + ..P.PAPA.P...... + P..PPPPPP..P.... + .P.PPAAPPP...P.. + ..PPPAAP.P.P.... + ..PAPAAPAP...... + P.PAPPP.AP.P.AA. + ..PA.PP.AP.AAAA. + ..PAPPPPAPAAAA.. + ..PAP.APAPAAAA.. + ..PAP.APAPAAAAA. + ....P.APAAAAAAA. + ..P.P.APPAAAAAA. + ...PP.APPPA..... + ................ +} +# tile 314 (fire elemental,male) { ................ .H..LDDD........ @@ -3029,7 +6012,26 @@ Z = (195, 195, 195) ..LDDCADDDA..... ................ } -# tile 158 (earth elemental) +# tile 315 (fire elemental,female) +{ + ................ + .H..LDDD........ + ...LDADAC.H..... + H..DDDDDD..H.H.. + ..LDDAADDD...... + ..DDDAADCD.H.... + ..DADAACAD...... + H.DADDDCAD...AA. + ..DACDDCAD.AAAA. + ..DADDDDADAAAA.. + ..DADCADADAAAA.. + H.DADCADADAAAAA. + ....DCADAAAAAAA. + .H.LDCADDAAAAAA. + ..LDDCADDDA..... + ................ +} +# tile 316 (earth elemental,male) { ..F............. ....CKKK..F..... @@ -3048,7 +6050,26 @@ Z = (195, 195, 195) ..CKKJAKKKA..... ................ } -# tile 159 (water elemental) +# tile 317 (earth elemental,female) +{ + ..F............. + ....CKKK..F..... + ...CKAKAJ....F.. + ...KKKKKK....... + ..CKKAAKKK.F..F. + .FKKKAAKJK...... + ..KAKAAJAK..F... + ..KAKJJJAK...AA. + F.KAJKKJAK.AAAA. + ..KAKKKKAKAAAA.. + ..KAKJAKAKAAAA.. + ..KAKJAKAKAAAAA. + ....KJAKAAAAAAA. + .F.CKJAKKAAAAAA. + ..CKKJAKKKA..... + ................ +} +# tile 318 (water elemental,male) { ................ ....PBBB..E..... @@ -3067,7 +6088,26 @@ Z = (195, 195, 195) ..PBBEABBBA..... ................ } -# tile 160 (lichen) +# tile 319 (water elemental,female) +{ + ................ + ....PBBB..E..... + .E.PBABAE...E... + ...BBBBBB....... + ..PBBAABBB.E..E. + E.BBBAABEB...... + ..BABAABEB.E.... + ..BABBBBEB...AA. + ..BAPBBEAB.AAAA. + E.BABBBBABAAAA.. + ..BABEABABAAAA.. + ..BABEABABAAAAA. + ....BEABAAAAAAA. + .E.PBEABBAAAAAA. + ..PBBEABBBA..... + ................ +} +# tile 320 (lichen,male) { ................ ................ @@ -3086,7 +6126,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 161 (brown mold) +# tile 321 (lichen,female) +{ + ................ + ................ + ...FFF...FFF.... + ..FCFFFFFCCFA... + .FCOOFFFCOFFFA.. + .FCOOFFFCFFFFA.. + ..FFFFFFFFFFA... + ...AFFFCCFFFA... + ...FFFFCOFFAA... + ..FCCFFCOFCFA... + ..FCOFFCFFOCFA.. + ..FFCFFFCFFFFA.. + ...FFFAAFFFFFA.. + .....AA.AAAAA... + ................ + ................ +} +# tile 322 (brown mold,male) { ................ ................ @@ -3105,7 +6164,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 162 (yellow mold) +# tile 323 (brown mold,female) +{ + ................ + ................ + ...JJJ...JJJ.... + ..JKJJJJJKKJA... + .JKCCJJJKCJJJA.. + .JKCCJJJKJJJJA.. + ..JJJJJJJJJJA... + ...AJJJKKJJJA... + ...JJJJKCJJAA... + ..JKKJJKCJKJA... + ..JKCJJKJJCKJA.. + ..JJKJJJKJJJJA.. + ...JJJAAJJJJJA.. + .....AA.AAAAA... + ................ + ................ +} +# tile 324 (yellow mold,male) { ................ ................ @@ -3124,7 +6202,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 163 (green mold) +# tile 325 (yellow mold,female) +{ + ................ + ................ + ...HHH...HHH.... + ..HHHHHHHNHHA... + .HHNNOHHNNOHHA.. + .HHNNOOHHOOHHA.. + ..HHOOHHHHHHA... + ...AHHHHHHHHA... + ...HHHHNNOHAA... + ..HHHHHNNOHHA... + ..HNNOHHHONOHA.. + ..HHOHHHHHOOHA.. + ...HHHAAHHHHHA.. + .....AA.AAAAA... + ................ + ................ +} +# tile 326 (green mold,male) { ................ ................ @@ -3143,7 +6240,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 164 (red mold) +# tile 327 (green mold,female) +{ + ................ + ................ + ...FFF...FFF.... + ..FGFFFFFGGFA... + .FGOOFFFGOFFFA.. + .FGOOFFFGFFFFA.. + ..FFFFFFFFFFA... + ...AFFFGGFFFA... + ...FFFFGOFFAA... + ..FGGFFGOFGFA... + ..FGOFFGFFOGFA.. + ..FFGFFFGFFFFA.. + ...FFFAAFFFFFA.. + .....AA.AAAAA... + ................ + ................ +} +# tile 328 (red mold,male) { ................ ................ @@ -3162,7 +6278,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 165 (shrieker) +# tile 329 (red mold,female) +{ + ................ + ................ + ...DDD...DDD.... + ..DCDDDDDCCDA... + .DLLCDDDCLDDDA.. + .DCCCDDDCDDDDA.. + ..DDDDDDDDDDA... + ...ADDDCCDDDA... + ...DDDDCLDDAA... + ..DCCDDCLDCDA... + ..DCLDDCDDLCDA.. + ..DDCDDDCDDDDA.. + ...DDDAADDDDDA.. + .....AA.AAAAA... + ................ + ................ +} +# tile 330 (shrieker,male) { ................ ................ @@ -3181,7 +6316,26 @@ Z = (195, 195, 195) ...AAAAAAAAAA... ................ } -# tile 166 (violet fungus) +# tile 331 (shrieker,female) +{ + ................ + ................ + ................ + ................ + .....GGGGFF..... + ...GGGGIGIDFF... + .GGGIIGGGIIFFFF. + GIIGIIGGGGGGGDDF + GIIGGGGIIGIIGIDF + GGGGIGGIIGIIGGFF + ..GGGGGGGGGGG... + ......FFF..AAAAA + ....AGGGFFAAAAAA + ...AGGGGGGFAAAA. + ...AAAAAAAAAA... + ................ +} +# tile 332 (violet fungus,male) { ................ ................ @@ -3200,7 +6354,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 167 (gnome) +# tile 333 (violet fungus,female) +{ + ................ + ................ + ...III...III.... + ..ILIIIIILLIA... + .IOOLIIILOIIIA.. + .ILLLIIILIIIIA.. + ..IIIIIIIIIIA... + ...AIIILLIIIA... + ...IIIILOIIAA... + ..ILLIILOILIA... + ..ILOIILIIOLIA.. + ..IILIIILIIIIA.. + ...IIIAAIIIIIA.. + .....AA.AAAAA... + ................ + ................ +} +# tile 334 (gnome,male) { ................ ................ @@ -3219,7 +6392,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 168 (gnome lord) +# tile 335 (gnome,female) +{ + ................ + ................ + ................ + .....DF......... + ......G......... + .....GFF........ + ....GGFFF....... + ....GLLLF....... + .....LLL...AAA.. + ...FGGGGFFAAAA.. + ...GAGFFAFAAAA.. + ....LKNKFAAAA... + ....FGAFFAA..... + ....GFAFG.A..... + ................ + ................ +} +# tile 336 (gnome leader,male) { ................ ................ @@ -3238,7 +6430,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 169 (gnomish wizard) +# tile 337 (gnome leader,female) +{ + ................ + ................ + ......D......... + ......G......... + ......G......... + .....GFF........ + ....HHHHH....... + ....GLLLF.....A. + .....LLL...AAA.. + ...FGGGGFFAAAA.. + ...GAGGFAFAAAA.. + ....LKNKFAAAA... + ....FGAFFAA..... + ....GFAFG.A..... + ................ + ................ +} +# tile 338 (gnomish wizard,male) { ................ ................ @@ -3257,7 +6468,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 170 (gnome king) +# tile 339 (gnomish wizard,female) +{ + ................ + ................ + ................ + ................ + ......G......... + .....GFF........ + ....GGFFF....... + ....GLLLF....... + ...FFLLLFF.AAA.. + ...GFGFGFFAAAA.. + ...FAGGFAFAAAA.. + ...GLKNKFFAAA... + ...FFGFFFFA..... + ...GFFFFGFA..... + ................ + ................ +} +# tile 340 (gnome ruler,male) { ................ ................ @@ -3276,7 +6506,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 171 (giant) +# tile 341 (gnome ruler,female) +{ + ................ + ................ + ................ + ................ + ....H.C.H....... + ....HCHCH....... + ....HHHHH....... + ....GLLLF...A... + .....LLL...AAAA. + ...FGGGGFFAAAA.. + ...GAGFFAFAAAA.. + ....LKNKFAAAA... + ....FGAFFAA..... + ....GFAFG.A..... + ................ + ................ +} +# tile 342 (giant,male) { ......JJJJAA.... ....JJJJJJJJA... @@ -3295,7 +6544,26 @@ Z = (195, 195, 195) .....CLJACLJAAAA ...LLLLJ.CLLLKAA } -# tile 172 (stone giant) +# tile 343 (giant,female) +{ + ......JJJJAA.... + ....JJJJJJJJA... + ....JJLLLLJJA... + ....JFFLLFFJA... + ....JLLLLLLJA... + ....ALLAALLAAA.. + .....ALLLLJAAAA. + ..CCLLJJJJLLCCAA + .CLLLCCKCKCLLLCA + .LLLKLKCKCLKLLLA + .LLAALLCCLLAALLA + .LLAAJJJKKJAALLA + .CLC.JJJJJKKCLAA + ..LL.CLJACLJLLAA + .....CLJACLJAAAA + ...LLLLJ.CLLLKAA +} +# tile 344 (stone giant,male) { ......JJJJAA.... ....JJJJJJJJA... @@ -3314,7 +6582,26 @@ Z = (195, 195, 195) .....ALJACLJAAAA ...LLLLJ.CLLLKAA } -# tile 173 (hill giant) +# tile 345 (stone giant,female) +{ + ......JJJJAA.... + ....JJJJJJJJA... + ....JJLLLLJJA... + ....JFFLLFFJA... + ....JLLLLLLJA... + ....ALLAALLAAA.. + .....ALLLLJAAAA. + ..CCLLJJJJLLCCAA + .CLLLCCKCKCLLLCA + .LLLAAKCKCLKLLLA + .LLPPPACCLLAALLA + .LLPPPPAKKJAALLA + .CLCPPPAJJKKCLAA + ..LLPPALACLJLLAA + .....ALJACLJAAAA + ...LLLLJ.CLLLKAA +} +# tile 346 (hill giant,male) { ......JJJJAA.... ....JJJJJJJJA... @@ -3333,7 +6620,26 @@ Z = (195, 195, 195) .....CLJACLJAAAA ...LLLLJ.LLLLKAA } -# tile 174 (fire giant) +# tile 347 (hill giant,female) +{ + ......JJJJAA.... + ....JJJJJJJJA... + ....JJLLLLJJA... + ....JFFLLFFJA... + ....JLLLLLLJA... + ....ALLAALLAAA.. + .....ALLLLJAAAA. + ...JJKJJJJJJJAA. + ..LJJCCKCKCJJLA. + ..JLKKKCKCKKLJA. + ..LAAKKCCKJAALAA + ..LAAJJJKKJAALAA + ..LC.JJJJJKKCLAA + ..LL.CLJACLJLLAA + .....CLJACLJAAAA + ...LLLLJ.LLLLKAA +} +# tile 348 (fire giant,male) { ....PPDDDDAA.... ....PDDDDDDDA... @@ -3352,7 +6658,26 @@ Z = (195, 195, 195) .....CLJACLJAAAA ...LLLLJ.LLLLKAA } -# tile 175 (frost giant) +# tile 349 (fire giant,female) +{ + ....PPDDDDAA.... + ....PDDDDDDDA... + ...PPDLLLLDDA... + ...PDPFLLFFDA... + ...PPPLLLLLDA... + ....PLLAALLAAA.. + ...PPALLLLJAAAA. + ...JPDJJJJJJJAA. + ..LDDHDKCKCJJLA. + ..JLHDDCKCKKLJA. + ..LAHDHCCKJAALAA + JLAADDHJKKJAALAA + JJLJDHHJJJKKCLAA + ..LLJJJJACLJLLAA + .....CLJACLJAAAA + ...LLLLJ.LLLLKAA +} +# tile 350 (frost giant,male) { .....KJJJJAA.... ....KJJJJJJJA... @@ -3371,7 +6696,26 @@ Z = (195, 195, 195) .....CLJACLJAAAA ...LLLLJ.CLLLKAA } -# tile 176 (ettin) +# tile 351 (frost giant,female) +{ + .....KJJJJAA.... + ....KJJJJJJJA... + ....JJLLLLJJA... + ....JEELLEEJA... + ....JLLLLLLJA... + ....ALLLLLLAAA.. + .....LLAALLAAAA. + ....KKLLLLKKAAAA + ...KJKKKKKKJJAAA + ..KJKKJJJJKKJJAA + ..KAAJKJJKJAAJAA + ..JAAJKKKKJAAJAA + ..LC.JJJJJKKCLAA + ..LL.CJJAJLJLLAA + .....CLJACLJAAAA + ...LLLLJ.CLLLKAA +} +# tile 352 (ettin,male) { ....NN..ONOP.... ..NNOOPNNOOPP... @@ -3390,7 +6734,26 @@ Z = (195, 195, 195) .....BPAABPAAAAA ...PPPPA.BPPPFAA } -# tile 177 (storm giant) +# tile 353 (ettin,female) +{ + ....NN..ONOP.... + ..NNOOPNNOOPP... + ..NPP..NPP..P... + ..ALPPLALPPLA... + ..APPPPAPPPPA... + ..APAAPAPAAPAA.. + ..APPPPAPPPPAAA. + ..BIIIIJJJIIIBAA + .BPPPIIIIIIPPPBA + .PPPFPIIIIPFPPPA + .PPAAPIIIIPAAPPA + .PPAAIIIIIIAAPPA + .BPB.IIFFIIABPAA + ..PP.BPAABPAPPAA + .....BPAABPAAAAA + ...PPPPA.BPPPFAA +} +# tile 354 (storm giant,male) { ......JJJJAA.... ....JJJJJJJJA... @@ -3409,7 +6772,26 @@ Z = (195, 195, 195) .....CLJACCJAAAA ...LLLLJ.LLLLKAA } -# tile 178 (titan) +# tile 355 (storm giant,female) +{ + ......JJJJAA.... + ....JJJJJJJJA... + ....JJLLLLJJA... + ....JFFLLFFJA... + ....JLLLLLLJA... + ....ALLAALLAAH.. + .....ALLLLJAHAA. + ...JJKJJJJJHHAA. + ..LJJCCKCKHHLAA. + ..JLKKKCKHHHHHH. + ..LAAKKCCKJAHHAA + ..LAAJJJKKJHHALA + ..LC.JJJJJKHAAAA + ..LL.CLJACHAAAAA + .....CLJACCJAAAA + ...LLLLJ.LLLLKAA +} +# tile 356 (titan,male) { .....AAAAAAA.... ....AALLLLAAA... @@ -3428,7 +6810,26 @@ Z = (195, 195, 195) .....CLJACLJAAAA ...LLLLJ.CLLLKAA } -# tile 179 (minotaur) +# tile 357 (titan,female) +{ + .....AAAAAAA.... + ....AALLLLAAA... + ....A..LL..AA... + ....ALLLLLLAA... + ....ALLAALLAAA.. + .....ALLLLJAAAA. + ..CCJJJJJJJJCCA. + .CLLLCCKCKCLLLCA + .LLLKJKCKCJKLLLA + .LLAAJJCCJJAALLA + .LLAAJJCCJJAALLA + .LLAAJJJKKJAALLA + .CLC.JJJJJKKCLAA + ..LL.CLJACLJLLAA + .....CLJACLJAAAA + ...LLLLJ.CLLLKAA +} +# tile 358 (minotaur,male) { ................ .O..........O... @@ -3447,7 +6848,26 @@ Z = (195, 195, 195) ....CLCACLCAAAAA ..LLLLL.LLLLLAA. } -# tile 180 (jabberwock) +# tile 359 (minotaur,female) +{ + ................ + .O..........O... + .OOOJJJJJJOOO... + ..OOJJKJJJOO.... + ...JGAKJGAJA.... + ...JJJKJJJJA.... + ....JJKJJJAAA... + ....JKKKJAAAA... + ..CLJAJAKALCAA.A + .CLLJJJJJALLCAAA + .LLCLAAAALCLLAA. + .LAAJLLLLJAALAA. + .LL.JJJJJJJLLAAA + .LL.JJJJJJJLLAAA + ....CLCACLCAAAAA + ..LLLLL.LLLLLAA. +} +# tile 360 (jabberwock,male) { ................ ...DP........... @@ -3466,7 +6886,26 @@ Z = (195, 195, 195) ...IDAA..ID..... ................ } -# tile 181 (vorpal jabberwock) +# tile 361 (jabberwock,female) +{ + ................ + ...DP........... + ....DP.ADOO..... + ..DAIDADIPAD.... + ...DIAPIPA...... + ...DBDDDA....... + ..IBBDADDA..AA.. + .DDDDAODDIAAAA.. + ..OAOA.DDAIAAA.. + ..IOAODDAAADDAA. + ..DDDADDDDAIDA.. + ...AAADDIDIDDD.. + ....IDDAIDDDDA.. + ....IDAAIDAA.... + ...IDAA..ID..... + ................ +} +# tile 362 (vorpal jabberwock,male) { ................ ...GP........... @@ -3485,7 +6924,26 @@ Z = (195, 195, 195) ...FGAA..FG..... ................ } -# tile 182 (Keystone Kop) +# tile 363 (vorpal jabberwock,female) +{ + ................ + ...GP........... + ....GP.AGOO..... + ..GAFGAGFPAG.... + ...GFAPFPA...... + ...GHGGGA....... + ..FHHGAGGA..AA.. + .GGGGAOGGFAAAA.. + ..OAOA.GGAFAAA.. + ..FOAOGGAAAGGAA. + ..GGGAGGGGAFGA.. + ...AAAGGFGFGGG.. + ....FGGAFGGGGA.. + ....FGAAFGAA.... + ...FGAA..FG..... + ................ +} +# tile 364 (Keystone Kop,male) { ................ ....AA.......... @@ -3504,7 +6962,26 @@ Z = (195, 195, 195) ..AA....AA...... ................ } -# tile 183 (Kop Sergeant) +# tile 365 (Keystone Kop,female) +{ + ................ + ....AA.......... + ...AAAA......... + ...AOAA...C..... + ..AAAAAA..C..... + ...LLLL...C..... + ....LL....C..... + ...AAAA.AAA..... + ..AAAAAAAAC.P... + .AA.AAAAA.PPPP.. + ..AAAAAA.PPPPPP. + ....AAAAPPPAPP.. + .A.AAAAAAPAAA... + AAAAA.PAAAAA.... + ..AA....AA...... + ................ +} +# tile 366 (Kop Sergeant,male) { ................ ....AA.......... @@ -3523,7 +7000,26 @@ Z = (195, 195, 195) ..AA....AA...... ................ } -# tile 184 (Kop Lieutenant) +# tile 367 (Kop Sergeant,female) +{ + ................ + ....AA.......... + ...AOOA......... + ...AOOA...C..... + ..AAAAAA..C..... + ...LLLL...C..... + ....LL....C..... + ...AAAA.AAA..... + ..AAAAAAAAC.P... + .AA.AAAAA.CPPP.. + ..AAAAAA.PPPPPP. + ....AAAAPPPAPP.. + .A.AAAAAAPAAA... + AAAAA.PAAAAA.... + ..AA....AA...... + ................ +} +# tile 368 (Kop Lieutenant,male) { ................ ....AA.......... @@ -3542,7 +7038,26 @@ Z = (195, 195, 195) ..AA....AA...... ................ } -# tile 185 (Kop Kaptain) +# tile 369 (Kop Lieutenant,female) +{ + ................ + ....AA.......... + ...AOOA...C..... + ...AOOA...C..... + ..AAAAAA..C..... + ...LLLL...C..... + ....LL....C..... + ..OAAAO.AAA..... + .OAAAAA.AAC.P... + .AA.AAAAA.CPPP.. + ..AAAAAA.PPPPPP. + ....AAAAPPPAPP.. + .A.AAAAAAPAAA... + AAAAA.PAAAAA.... + ..AA....AA...... + ................ +} +# tile 370 (Kop Kaptain,male) { ................ ....AA....C..... @@ -3561,7 +7076,26 @@ Z = (195, 195, 195) ..AA....AA...... ................ } -# tile 186 (lich) +# tile 371 (Kop Kaptain,female) +{ + ................ + ....AA....C..... + ...AHHA...C..... + ...AHHA...C..... + ..AAAAAA..C..... + ...LLLL...C..... + ....LL....C..... + .HHAAAAHHAA..... + .AAAAHAAAACCC... + .AA.AHAAA.CPPP.. + ..AAAHAA.PCPPPP. + ....AAAAPPPAPP.. + .A.AAAAAAPAAA... + AAAAA.PAAAAA.... + ..AA....AA...... + ................ +} +# tile 372 (lich,male) { ................ ................ @@ -3580,7 +7114,26 @@ Z = (195, 195, 195) ......OOO....... ................ } -# tile 187 (demilich) +# tile 373 (lich,female) +{ + ................ + ................ + ...OOO.......... + ..AOAOO......... + ..OOOOO......... + ..OO.O.......... + .....PPP........ + ...OOPPP....AAA. + ..O.PPPPPA..AAA. + .O...PPPP.AAAAA. + ....O.PPPAAAA.A. + ......PPPAAA.A.. + .....OPAP.A..... + ...OOOA.OA...... + ......OOO....... + ................ +} +# tile 374 (demilich,male) { ................ ................ @@ -3599,7 +7152,26 @@ Z = (195, 195, 195) ......LLL....... ................ } -# tile 188 (master lich) +# tile 375 (demilich,female) +{ + ................ + ................ + ...OOO.......... + ..AOAOO......... + ..OOOOO......... + ..OO.O.......... + .....PPP........ + ...OOPPP....AAA. + ..O.PPPPPA..AAA. + .O...PPPP.AAAAA. + ....L.PPPAAAA.A. + ......LPPAAA.A.. + .....LLAL.A..... + ...LLLA.LA...... + ......LLL....... + ................ +} +# tile 376 (master lich,male) { ...H............ ...HCH.H........ @@ -3618,7 +7190,26 @@ Z = (195, 195, 195) ......OOO....... ................ } -# tile 189 (arch-lich) +# tile 377 (master lich,female) +{ + ...H............ + ...HCH.H........ + ...HHHCH........ + ..AOAOHH........ + ..OOOOO......... + ..OO.O.......... + .....PPP........ + ...PPPPP....AAA. + ..PPPPPPPA..AAA. + .O..PPPPP.AAAAA. + ....OPPPPAAAA.A. + ......PPPAAA.A.. + .....OPAP.A..... + ...OOOA.OA...... + ......OOO....... + ................ +} +# tile 378 (arch-lich,male) { ................ ................ @@ -3637,7 +7228,26 @@ Z = (195, 195, 195) ......OOO....... ................ } -# tile 190 (kobold mummy) +# tile 379 (arch-lich,female) +{ + ................ + ................ + ...OOO.......... + ..DODOO......... + ..OOOOO......... + H.OO.O.......... + A....PPP........ + A..OOPPP....AAA. + .AO.PPPPPA..AAA. + .O...PPPP.AAAAA. + .A..O.PPPAAAA.A. + ..A...PPPAAA.A.. + ..A..OPAP.A..... + ..AOOOA.OA...... + ......OOO....... + ................ +} +# tile 380 (kobold mummy,male) { ................ ................ @@ -3656,7 +7266,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 191 (gnome mummy) +# tile 381 (kobold mummy,female) +{ + ................ + ................ + ................ + ...N...N........ + ...NONONO....... + ...OAOAO.OP..... + ....ONN...A..... + ...ONODNA.AA.... + ..OLONNONAAA.A.. + ..NALONANAAAAA.. + ..NAOLOAOAAAAA.. + ....NOLAAAAAA... + ....NANAAAA..... + ...OOANOA....... + ................ + ................ +} +# tile 382 (gnome mummy,male) { ................ ................ @@ -3675,7 +7304,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 192 (orc mummy) +# tile 383 (gnome mummy,female) +{ + ................ + ................ + ................ + ................ + ......G......... + .....GGFO....... + ....GGFFOOP..... + ....GDODF....... + .....ONO...AAA.. + ...NONOONOAAAA.. + ...OANLOAOAAAA.. + ....NNOLOAAAA... + ....NOANDAA..... + ....NOAOO.A..... + ................ + ................ +} +# tile 384 (orc mummy,male) { ................ ................ @@ -3694,7 +7342,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 193 (dwarf mummy) +# tile 385 (orc mummy,female) +{ + ................ + ................ + ................ + .....OA......... + ....NOOP........ + ....DODPOP...... + ....OOOA........ + ..OOOOOOOA.AA... + ..OOOOOOO.AAA... + ..OAOOOAACCC.... + ..OAOOOCCAAA.... + ....OCCOAAAAAA.. + ...CCAOOAAAA.... + ..OOOAOOOA...... + ................ + ................ +} +# tile 386 (dwarf mummy,male) { ................ ................ @@ -3713,7 +7380,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 194 (elf mummy) +# tile 387 (dwarf mummy,female) +{ + ................ + ................ + ................ + ................ + ......B......... + .....BBEO....... + ....BBEEEOP..... + ....BDODE....... + .....ONO...AAA.. + ...NONOONOAAAA.. + ...OANLOAOAAAA.. + ....NNOLOAAAA... + ....NOANDAA..... + ....NOAOO.A..... + ................ + ................ +} +# tile 388 (elf mummy,male) { ................ ................ @@ -3732,7 +7418,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 195 (human mummy) +# tile 389 (elf mummy,female) +{ + ................ + ................ + .........O...... + .......OOOP..... + ......OOOOP..... + ......OEOEAP.... + ......OOOOA..... + ......AOOA....A. + ......OAAO..AAA. + .....OOOOOOAAAA. + ....OALOOLAOAAA. + ....OADOOOAOAA.. + ......OOAOAA.A.. + .....OOA.OOA.... + ................ + ................ +} +# tile 390 (human mummy,male) { ................ ................ @@ -3751,7 +7456,26 @@ Z = (195, 195, 195) ..NNN.NNNA...... ................ } -# tile 196 (ettin mummy) +# tile 391 (human mummy,female) +{ + ................ + ................ + ...ONNO......... + ...NNNNOP....... + ..PANAN.OPP..... + ..PNNNN......... + ..ONOONNP....... + .ONLNNOOO....... + .NJNOOOOO..AAA.. + .OJOOOODN.AAAA.. + .NJOLNOAOAAAAAA. + .OCNO.NKNAAAAA.. + .N.OO.OLAAAAAAA. + ...OOAOOAAA..... + ..NNN.NNNA...... + ................ +} +# tile 392 (ettin mummy,male) { .....NN..ONOO... ...NNOOONNOOOO.. @@ -3770,7 +7494,26 @@ Z = (195, 195, 195) .....NOOANOOAAAA ...OOOOO.OOOOKAA } -# tile 197 (giant mummy) +# tile 393 (ettin mummy,female) +{ + .....NN..ONOO... + ...NNOOONNOOOO.. + ...NOOOONOOOOOO. + ...OFOFOLOFOFO.O + ...OOOOOLOOOOO.P + ...NOOOOLNNOOOA. + ...ONOOOLOOOOAAA + ..OOOONNNNNNNOAA + .ONNNNNNOONOOOOA + .ONODNNOOOOOOOOA + .NNAAONNONOAAOOA + .NOAAONOONLAAOOA + .OOO.ONOONOOOOAA + ..OO.NNOANOLOOAA + .....NOOANOOAAAA + ...OOOOO.OOOOKAA +} +# tile 394 (giant mummy,male) { ......ONOOAA.... ....ONNNOOOOA... @@ -3789,7 +7532,26 @@ Z = (195, 195, 195) .....NOOANOOAAAA ...OOOOO.OOOOKAA } -# tile 198 (red naga hatchling) +# tile 395 (giant mummy,female) +{ + ......ONOOAA.... + ....ONNNOOOOA... + ....NNOOOOOOO... + ....NFFOOFFOOP.. + ....NONOOOOOAOP. + ....AONOOOOAAAP. + .....ANOOODAAAA. + ..OOOONOOONNNOAA + .ONNNNNOOOOOOOOA + .ONODNNLOOOOOOOA + .NNAAONOLNOAAOOA + .NOAAONOONLAAOOA + .OOO.ONOONOOOOAA + ..OO.NNOANOLOOAA + .....NOOANOOAAAA + ...OOOOO.OOOOKAA +} +# tile 396 (red naga hatchling,male) { ................ ................ @@ -3808,7 +7570,26 @@ Z = (195, 195, 195) ....IIDDDDDA.... ................ } -# tile 199 (black naga hatchling) +# tile 397 (red naga hatchling,female) +{ + ................ + ................ + ................ + ................ + ....K........... + ...KLK.......... + ...LLLA......... + ...ALAA......... + ...LALA......... + ...LLLA......... + ...LLLAA........ + ...LDLAA........ + ...IDDAAAAADA... + ...IDDDAAADDA... + ....IIDDDDDA.... + ................ +} +# tile 398 (black naga hatchling,male) { ................ ................ @@ -3827,7 +7608,26 @@ Z = (195, 195, 195) ....AAAAAAAA.... ................ } -# tile 200 (golden naga hatchling) +# tile 399 (black naga hatchling,female) +{ + ................ + ................ + ................ + ................ + ....K........... + ...KLK.......... + ...LLLA......... + ...ALAA......... + ...LALA......... + ...LLLA......... + ...LLLA......... + ...LALAA........ + ...AAAPA..PAA... + ...AAAAPPPAAA... + ....AAAAAAAA.... + ................ +} +# tile 400 (golden naga hatchling,male) { ................ ................ @@ -3846,7 +7646,26 @@ Z = (195, 195, 195) ....NNHHHHHA.... ................ } -# tile 201 (guardian naga hatchling) +# tile 401 (golden naga hatchling,female) +{ + ................ + ................ + ................ + ................ + ....K........... + ...KLK.......... + ...LLLA......... + ...ALAA......... + ...LALA......... + ...LLLA......... + ...LLLAA........ + ...LHLAA........ + ...NHHAAAAAHA... + ...NHHHAAAHHA... + ....NNHHHHHA.... + ................ +} +# tile 402 (guardian naga hatchling,male) { ................ ................ @@ -3865,7 +7684,26 @@ Z = (195, 195, 195) ....GGFFFFFA.... ................ } -# tile 202 (red naga) +# tile 403 (guardian naga hatchling,female) +{ + ................ + ................ + ................ + ................ + ....K........... + ...KLK.......... + ...LLLA......... + ...ALAA......... + ...LALA......... + ...LLLA......... + ...LLLAA........ + ...LFLAA........ + ...GFFAAAAAFA... + ...GFFFAAAFFA... + ....GGFFFFFA.... + ................ +} +# tile 404 (red naga,male) { ................ ....KK.......... @@ -3884,7 +7722,26 @@ Z = (195, 195, 195) .....DDAA..DDA.. ..........DA.... } -# tile 203 (black naga) +# tile 405 (red naga,female) +{ + ................ + ....KK.......... + ...KLLK......... + ...LLLLA........ + ...ALLAA........ + ...LAALA........ + ...LLLLA........ + ...LLLDA..AA.... + ...LDLDA.AAAA... + ...IDDDAAAIIA... + ...IDDDAIDDDIDA. + ...IDDDIDDDDDDDA + ...IDDDDDDAA.DDA + ....DDDDDA..DDA. + .....DDAA..DDA.. + ..........DA.... +} +# tile 406 (black naga,male) { ................ ....KK.......... @@ -3903,7 +7760,26 @@ Z = (195, 195, 195) .....AAPP..AAP.. ..........AP.... } -# tile 204 (golden naga) +# tile 407 (black naga,female) +{ + ................ + ....KK.......... + ...KLLK......... + ...LLLLA........ + ...ALLAA........ + ...LAALA........ + ...LLLLA........ + ...LLLAA........ + ...LALAA..PPP... + ...AAAAPPPAAP... + ...AAAAPAAAAAAP. + ...AAAAAAAAAAAAP + ...AAAAAAAPP.AAP + ....AAAAAP..AAP. + .....AAPP..AAP.. + ..........AP.... +} +# tile 408 (golden naga,male) { ................ ....KK.......... @@ -3922,7 +7798,26 @@ Z = (195, 195, 195) .....HHAA..HHA.. ..........HA.... } -# tile 205 (guardian naga) +# tile 409 (golden naga,female) +{ + ................ + ....KK.......... + ...KLLK......... + ...LLLLA........ + ...ALLAA........ + ...LAALA........ + ...LLLLA........ + ...LLLHA..AA.... + ...LHLHA.AAAA... + ...NHHHAAANNA... + ...NHHHANHHHNHA. + ...NHHHNHHHHHHHA + ...NHHHHHHAA.HHA + ....HHHHHA..HHA. + .....HHAA..HHA.. + ..........HA.... +} +# tile 410 (guardian naga,male) { ................ ....KK.......... @@ -3941,7 +7836,26 @@ Z = (195, 195, 195) .....FFAA..FFA.. ..........FA.... } -# tile 206 (ogre) +# tile 411 (guardian naga,female) +{ + ................ + ....KK.......... + ...KLLK......... + ...LLLLA........ + ...ALLAA........ + ..CLAALC........ + ..LLLLLL........ + ..CLLCLC..AA.... + ...CLLCA.AAAA... + ...GLFCAAAGGA... + ...GFFFAAFFFGFA. + ...GFFFGFFFFFFFA + ...GFFFFFFAA.FFA + ....FFFFFA..FFA. + .....FFAA..FFA.. + ..........FA.... +} +# tile 412 (ogre,male) { ................ ................ @@ -3960,7 +7874,26 @@ Z = (195, 195, 195) ....CJJJCLAAAAAA ..LLLLL.LLLLLAA. } -# tile 207 (ogre lord) +# tile 413 (ogre,female) +{ + ................ + ................ + ....CLLLC....... + ..LCKKLKKCL..... + ...LAALAALJA.... + ...CLLLLLCJA.... + ....CAAACJAAA... + ....LDDDLAAAA... + ..CLJLLLKALCAA.A + .CLLAJJJJALLCAAA + .LLCLAAAALCLLAA. + .LAACLLLLCAALAA. + .LC.HHHBHHACLAAA + .LL.JJJJJJALLAAA + ....CJJJCLAAAAAA + ..LLLLL.LLLLLAA. +} +# tile 414 (ogre leader,male) { ................ ................ @@ -3979,7 +7912,26 @@ Z = (195, 195, 195) ....CJJJCLAAAAAA ..LLLLL.LLLLLAA. } -# tile 208 (ogre king) +# tile 415 (ogre leader,female) +{ + ................ + ................ + ....CLLLC....... + ..LCKKLKKCL..... + ...LAALAALJA.... + ...CLLLLLCJA.... + ....CLLLCJAAA... + ....LAAALAAAA... + ..JKJLLLKAKJAA.A + .CLKAJJJJAKLCAAA + .LLJKAAAAKJLLAA. + .LAAJKKKKJAALAA. + .LC.HHHBHHACLAAA + .LL.JJJJJJALLAAA + ....CJJJCLAAAAAA + ..LLLLL.LLLLLAA. +} +# tile 416 (ogre tyrant,male) { ...H..C..H...... ...HDCHCDH...... @@ -3998,7 +7950,26 @@ Z = (195, 195, 195) ....CJJJCLAAAAAA ..LLLLL.LLLLLAA. } -# tile 209 (gray ooze) +# tile 417 (ogre tyrant,female) +{ + ...HH.C.HH...... + ...HDCHCDH...... + ...HHHHHHH...... + ..LCKKLKKCL..... + ...LAALAALJA.... + ...CLLLLLCJA.... + ....CLLLCJAAA... + ....LAAALAAAA... + ..JKJLLLKAKJAA.A + .CJKAJJJJAKJCAAA + .LJJKAAAAKJJLAA. + .LAAJKKKKJAALAA. + .LC.HHHBHHACLAAA + .LL.JJJJJJALLAAA + ....CJJJCLAAAAAA + ..LLLLL.LLLLLAA. +} +# tile 418 (gray ooze,male) { ................ ................ @@ -4017,7 +7988,26 @@ Z = (195, 195, 195) .........KCCCJ.. ................ } -# tile 210 (brown pudding) +# tile 419 (gray ooze,female) +{ + ................ + ................ + ................ + .....PBPA....... + ...PBBBPBA...... + ..BBNNBPPBAA.... + .BBNNPPPBBPAAA.. + PBBBPPPBPBBAAA.. + BBBPBPPPPPBPAAA. + BBPBPPPPPPPBAAA. + PBPPBPPPBBPPAAA. + .PBBPPPBAAPPPAA. + ...PBBBAAAKPPJ.. + ........ACPPAK.. + .........KCCCJ.. + ................ +} +# tile 420 (brown pudding,male) { ................ ................ @@ -4036,7 +8026,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 211 (green slime) +# tile 421 (brown pudding,female) +{ + ................ + ................ + ................ + ................ + ............J... + ....JKKJJJ..JJ.. + ...KKKCJJJJJ.... + ..KKNNJNNJJJ.... + ..KJANJANJJJA... + ..KKJJJJJCJJAA.. + ..JKJJCJJJJJAA.. + ...JJJJJJJJAAA.. + ....JJJJJJAAA... + .....AAAAAAA.... + ................ + ................ +} +# tile 422 (green slime,male) { ................ ................ @@ -4055,7 +8064,26 @@ Z = (195, 195, 195) NGGFGGF..GF..... ..GGF..GGF..G... } -# tile 212 (black pudding) +# tile 423 (green slime,female) +{ + ................ + ................ + ................ + ................ + ................ + ................ + ............G... + .....G......G..G + .G....G..G.NGN.G + ..NG.NGGNGGGGGGG + ..GGNGGNGGGFGGF. + GGNGGGGGGGGGFF.G + .NGGGGGFGFG..... + NGGGGFGGFG.G..GF + NGGFGGF..GF..... + ..GGF..GGF..G... +} +# tile 424 (black pudding,male) { ........A....... ........AA...... @@ -4074,7 +8102,26 @@ Z = (195, 195, 195) ........AAAAAAAA ..........AAAA.. } -# tile 213 (quantum mechanic) +# tile 425 (black pudding,female) +{ + ........A....... + ........AA...... + .....AAA........ + ....AAAAA....... + ....CACAA....... + ....DADAA....... + ....AAAAA....... + ....AAAAA....... + ....AAAAA....... + .....AAAAA...... + .....AAAAA...... + ......AAAAA..... + ......AAAAAA.... + .......AAAAAA.A. + ........AAAAAAAA + ..........AAAA.. +} +# tile 426 (quantum mechanic,male) { ................ ......LLLL...... @@ -4093,7 +8140,26 @@ Z = (195, 195, 195) ....NAAEBAANN... ................ } -# tile 214 (genetic engineer) +# tile 427 (quantum mechanic,female) +{ + ................ + ......JJJJJ..... + ...FGGCLCGGF.... + ...GNNGLGNNGJ... + B.BGANGGGANGL... + B.BFGGCLCGGFLJ.. + BIB.JCLLLCCLJJ.. + BILN.LLAALLAAAA. + BILNN.LLLLCAAAA. + BIB.NNCCCCNAAA.. + BIB.BNNNONNNAA.. + .B...NNNONNLAA.. + .....NBEBENA.A.. + .....NBEBENN.... + ....NAAEBAANN... + ................ +} +# tile 428 (genetic engineer,male) { ................ ......LLLL...... @@ -4112,7 +8178,26 @@ Z = (195, 195, 195) ..AANAAEPAANN... ................ } -# tile 215 (rust monster) +# tile 429 (genetic engineer,female) +{ + ................ + ......LLLL...... + ...LAALLLAAL.... + ...LNNLLLNNLL... + ...LANLLLANLL... + ...LLLLLLLLLL... + .....CLLLCCL.... + ..LN.LLAALL..... + ..LNN.LLLLJ..... + ..A.NNLLLLN..... + .A.ABNNNONNN.... + .AA..NNNONNL.... + .A.A.NPEPENA.... + .AA..NPEPENN.... + ..AANAAEPAANN... + ................ +} +# tile 430 (rust monster,male) { ................ ....EEEE........ @@ -4131,7 +8216,26 @@ Z = (195, 195, 195) ......AAAA...... ................ } -# tile 216 (disenchanter) +# tile 431 (rust monster,female) +{ + ................ + ....EEEE........ + ...EEHEHE....... + ...EEEAEE....... + ...EEPAPE....... + ...EPEAEP...E... + ....EEEE.AAEE... + ....EEEEEAAEEE.. + ...EEEEEEEAEAEE. + ..EEEEEEAAAAE... + ..EEAEEEEAEEEA.. + ..AAEEEEEEEEEAA. + ....AEEEEEEEAAA. + .....EEEEEAA..A. + ......AAAA...... + ................ +} +# tile 432 (disenchanter,male) { ................ ....PPPP........ @@ -4150,7 +8254,26 @@ Z = (195, 195, 195) ......AAAA...... ................ } -# tile 217 (garter snake) +# tile 433 (disenchanter,female) +{ + ................ + ....PPPP........ + ...PPDPDP....... + ...PPPAPP....... + ...PPOAOP....... + ...POPAPO...P... + ....PPPP.AAPP... + ....PPPPPAAPPP.. + ...PPPPPPPAPAPP. + ..PPPPPPAAAAP... + ..PPAPPPPAPPPA.. + ..AAPPPPPPPPPAA. + ....APPPPPPPAAA. + .....PPPPPAA..A. + ......AAAA...... + ................ +} +# tile 434 (garter snake,male) { ................ ................ @@ -4169,7 +8292,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 218 (snake) +# tile 435 (garter snake,female) +{ + ................ + ................ + ................ + ....KKA......... + ...NAOKA........ + ...KKAKA........ + ...KKAKA....KA.. + ....APKAP..KAPP. + .....PKAPP.KAP.. + .....KAAP..KAP.. + ....KAAP..KAAP.. + ....KAAPPKAAP... + ....KAAKKAAP.... + .....KAAAAP..... + ................ + ................ +} +# tile 436 (snake,male) { ................ ................ @@ -4188,7 +8330,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 219 (water moccasin) +# tile 437 (snake,female) +{ + ................ + ................ + ................ + ....KKA......... + ...NAOJA........ + ...KKJAJ........ + ...KKAAJ....KK.. + ...FAAKJ...KJAA. + ..FAFAKJAA.KJA.. + .....KJAA..KJA.. + ....KJAA..KJJA.. + ....KJAAAKJJA... + ....KJJJJJJA.... + .....KJJJJA..... + ................ + ................ +} +# tile 438 (water moccasin,male) { ................ ................ @@ -4207,7 +8368,26 @@ Z = (195, 195, 195) .....AAAAA...... ................ } -# tile 220 (python) +# tile 439 (water moccasin,female) +{ + ................ + ................ + ................ + ....AAA......... + ...AAAAA...AA... + ...OAOAAA.AA.... + ...AAA.AA.AA.... + ...DA..AA.AA.... + ..D.D.AAA..AA... + .....AAA...AA... + .....AAA...AA... + ....AAA...AAA... + ....AAAAAAAA.... + ....AAAAAAA..... + .....AAAAA...... + ................ +} +# tile 440 (python,male) { ................ ................ @@ -4226,7 +8406,26 @@ Z = (195, 195, 195) .....JJJJJAA.... ................ } -# tile 221 (pit viper) +# tile 441 (python,female) +{ + ................ + ................ + ................ + ...KKKA.....JJ.. + ...GAGJA...JJJ.. + ..JKKJAJ..KJJ... + ..KKKAJJ..KJJ.AA + ..KKAAKJA.KKJAA. + .....AKJAA.KJAA. + ....JKJAA..KJJA. + ...JJJAA..KJJJA. + ...JJJAAAKJJJA.. + ...JJJJJJJJJAA.. + ....JJJJJJJAA... + .....JJJJJAA.... + ................ +} +# tile 442 (pit viper,male) { ................ ................ @@ -4245,7 +8444,26 @@ Z = (195, 195, 195) ......AAAA...... ................ } -# tile 222 (cobra) +# tile 443 (pit viper,female) +{ + ................ + ................ + ................ + ....AAA......... + ...AAAAA...AAA.. + ...OAAAAA.AA.AA. + ...AA..AA.AA.AA. + ...D...AA.AA..A. + ......AAA..AA.A. + ......AA...AA... + .....AAA...AA... + .....AA...AAA... + .....AA..AAA.... + .....AAAAAA..... + ......AAAA...... + ................ +} +# tile 444 (cobra,male) { ................ ................ @@ -4264,7 +8482,26 @@ Z = (195, 195, 195) .....AAAAAAAAA.. ................ } -# tile 223 (troll) +# tile 445 (cobra,female) +{ + ................ + ................ + ................ + ....AAA......... + ...AAAAAA....... + ..PA..AAAA...... + ..A..AAAAA..AA.. + ..D..AAAAA....A. + ......AAA.....A. + ......AA..AAAA.. + .....AA..AA..... + ....AA...AA..... + ....AA....AAAA.. + ....AAA......AA. + .....AAAAAAAAA.. + ................ +} +# tile 446 (troll,male) { ................ ..AAAAAA........ @@ -4283,7 +8520,26 @@ Z = (195, 195, 195) ..KJA..KA....... ................ } -# tile 224 (ice troll) +# tile 447 (troll,female) +{ + ................ + ..AAAAAA........ + AAAANANA........ + .AAKKKJJA....... + AAAKAAAKA....... + AKAKAAAKAA...... + KJJAKKKAJKA..... + KJAJAAAJJJA..... + KJAJKKJJKJA..... + .KJJAFGFJJAAAA.. + ..KJA.PFJAAAA... + ...AFAGFAAAAAA.. + ...GFAGP.AA.AA.. + ..KJJAKJAA.AA... + ..KJA..KA....... + ................ +} +# tile 448 (ice troll,male) { ................ ..OONOOO........ @@ -4302,7 +8558,26 @@ Z = (195, 195, 195) ..KJA..KA....... ................ } -# tile 225 (rock troll) +# tile 449 (ice troll,female) +{ + ................ + ..OONOOO........ + NONOAOAOO....... + .NOKKKJJO....... + NOJKAAAKOO...... + OKJKAAAKAO...... + KJJAKKKAJKA..... + KJAJAAAJJJA..... + KJAJKKJJKJA..... + .KJJAEBEJJAAAA.. + ..KJA.PEJAAAA... + ...AEABEAAAAAA.. + ...BEABP.AA.AA.. + ..KJJAKJAA.AA... + ..KJA..KA....... + ................ +} +# tile 450 (rock troll,male) { ................ ...AAAAA........ @@ -4321,7 +8596,26 @@ Z = (195, 195, 195) ..KJA..KA....... ................ } -# tile 226 (water troll) +# tile 451 (rock troll,female) +{ + ................ + ...AAAAA........ + .AAANANAAAA..... + .AAKKKJJAA...... + AAAKAAAKAAAA.... + AKAKAAAKAAA..... + KJJAKKKAJKAA.... + KJAJAAAJJJA..... + KJAPAKJJKJA..... + PKJPPAGFJJAAAA.. + PPPPPAFFJAAAA... + .PPPAAGFAAAAAA.. + ...AFAGF.AA.AA.. + ..KJJAKJAA.AA... + ..KJA..KA....... + ................ +} +# tile 452 (water troll,male) { ................ ...AAAAA........ @@ -4340,7 +8634,26 @@ Z = (195, 195, 195) ..KJA..KA....... ................ } -# tile 227 (Olog-hai) +# tile 453 (water troll,female) +{ + ................ + ...AAAAA........ + ..AANANAA....... + .AAKKKJJAA...... + .AAKAAAKAA...... + .KAKAAAKAA...... + KJJAKKKAJKA..... + KJAJAAAJJJA..... + KJAJKKJJKJA..... + .KJJAEBEJJAAAA.. + ..KJA.PEJAAAA... + ...AEABEAAAAAA.. + ...BEABP.AA.AA.. + ..KJJAKJAA.AA... + ..KJA..KA....... + ................ +} +# tile 454 (Olog-hai,male) { ...PPPPP........ ..PPAAAPP....... @@ -4359,7 +8672,26 @@ Z = (195, 195, 195) ..AAA.AAA....... ................ } -# tile 228 (umber hulk) +# tile 455 (Olog-hai,female) +{ + ...PPPPP........ + ..PPAAAPP....... + ..PANANAP....... + ..PAAAAAP....... + .PPAAAAAPP...... + PPPAAAAAPPP..... + AAPPAAAPPAA..... + AAAPPPPPAAA..... + AAAPPPPPAAA..... + .AAAAPPPAAAPPP.. + PONNNNNNAACPP... + ...APAPPAPPPPP.. + ...PPAPP.PP.PP.. + ..AAAAAAAP.PP... + ..AAA.AAA....... + ................ +} +# tile 456 (umber hulk,male) { ................ ...AAAAA........ @@ -4378,7 +8710,26 @@ Z = (195, 195, 195) .AAAP..AAP...... ................ } -# tile 229 (vampire) +# tile 457 (umber hulk,female) +{ + ................ + ...AAAAA........ + ..AAAAAAA....... + .ADADADADA...... + .AAAAAAAAA.A.... + .AAAOAOAAA.AA... + .A.AOAOA.AAA.... + .A.AAAAAPAA..... + .AAAAAAAP....... + .A.AAAAA.PPPPPP. + ...AA.AA.PPPPP.. + ...AA.AAPPPPPPP. + ...AAPAAPPPP.... + ..AAAPAAAPP..... + .AAAP..AAP...... + ................ +} +# tile 458 (vampire,male) { ................ ................ @@ -4397,7 +8748,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 230 (vampire lord) +# tile 459 (vampire,female) +{ + ................ + ................ + .....AAA........ + ....AAOAA....... + .ADDAGAGADA..... + ..ADALLOAD...... + .AAAAAAAAA...... + ..AAAAAAAA...... + ...AAAAAAA...... + ..ADAAAAAAPPPPP. + ..ADDAAAAAPPPP.. + ..AAAAAAAAPPP... + .....AAPAAPP.... + ....AAP..AP..... + ................ + ................ +} +# tile 460 (vampire leader,male) { ................ .....AAAA....... @@ -4416,7 +8786,26 @@ Z = (195, 195, 195) .N..AAPP..AP.... ................ } -# tile 231 (vampire mage) +# tile 461 (vampire leader,female) +{ + ................ + .....AAAA....... + .N..AAOOAA...... + .NDDAGAAGADA.... + .NADALLLOAD..... + AAAAAAAAAAA..... + AAAAAAAAAAA..... + .AAAAAAAAAA..... + .NAAAAAAAAA..... + .N.AAAAAAAAPPPPP + .NADAAAAAAAPPPPP + .NADDAAAAAAPPPP. + .NAAAAAAAAAPPP.. + .N...AAAPAAPP... + .N..AAPP..AP.... + ................ +} +# tile 462 (vampire mage,male) { ................ ................ @@ -4435,7 +8824,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 232 (Vlad the Impaler) +# tile 463 (vampire mage,female) +{ + ................ + ................ + .....AAA........ + ....AAOAA....... + .ADDAGAGADA..... + ..ADALLOAD...... + .AAAA.A.AA...... + ..AAAACAAA...... + ...AAADAAA...... + ..ADAAAAAAPPPPP. + ..ADDAAAAAPPPP.. + ..AAAAAAAAPPP... + .....AAPAAPP.... + ....AAP..AP..... + ................ + ................ +} +# tile 464 (Vlad the Impaler,male) { ................ ..N..AAAA....... @@ -4454,7 +8862,26 @@ Z = (195, 195, 195) ..N.AAPP..AP.... ................ } -# tile 233 (barrow wight) +# tile 465 (Vlad the Impaler,female) +{ + ................ + ..N..AAAA....... + ADNDAAOOAADDDA.. + .ANDAGAAGADDA... + ..NDALLLOADA.... + ..NAAAAAAAAAAAAA + .HHHDAAAAADDDDDA + HEHEHJAAAADDDAA. + LLLLLJAAAADDAAPP + .LLLJAAAAADDAPPP + ..NJDAAAAADAPPPP + .ANDDAAAAAAAPPPP + .ANAAAAAAAAPPPP. + ..N..AAAPAAPPP.. + ..N.AAPP..AP.... + ................ +} +# tile 466 (barrow wight,male) { ................ ................ @@ -4473,7 +8900,26 @@ Z = (195, 195, 195) .J.....LLAA..... ................ } -# tile 234 (wraith) +# tile 467 (barrow wight,female) +{ + ................ + .......OOOOO.... + ..OOOOOOO....... + .ODLDLOO.OOO.... + .OLLLLOOOOOOO... + .OLJLLOPOO...... + .OPLLL.POOOAAAA. + ..PPP.PP.AAAAAA. + .LPPPPPP.PAAAA.. + .JJ.PPPP.PAAAA.. + .J...PPL.PPAAA.. + .J...PPPPPPAAA.. + .J...PPPPPPPAA.. + .J..LLPPPPPPA... + .J.....LLAA..... + ................ +} +# tile 468 (wraith,male) { ................ ................ @@ -4492,7 +8938,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 235 (Nazgul) +# tile 469 (wraith,female) +{ + ................ + ................ + ...PPPPP........ + ...PAAPPP....... + ....PAAPP....... + ....PAAPP....... + ..PP.PPP.P...... + .OLAPPP.PP...... + ..AAPPPPAP..AAA. + ..PPPPPOLPAAAAA. + ...A.PPAAAAPPA.. + .....PPAPPPPA... + ......PPPPA..... + ................ + ................ + ................ +} +# tile 470 (Nazgul,male) { ................ ................ @@ -4511,7 +8976,26 @@ Z = (195, 195, 195) ......PPPPA..... ................ } -# tile 236 (xorn) +# tile 471 (Nazgul,female) +{ + ................ + ................ + ...PPPPP........ + ...PAAPPP....... + ....PAAPP....... + ....PAAPP....... + ..PP.PPP.P...... + .OLAPPP.PP...... + .OPAPPPPAP..AAA. + ..PAPPPPAP..AAA. + ..PA.PPPLP..AAA. + ..PP.PPOLPAAAAA. + ...AAPPOAAAPPA.. + .....PPAPPPPA... + ......PPPPA..... + ................ +} +# tile 472 (xorn,male) { ................ ................ @@ -4530,7 +9014,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 237 (monkey) +# tile 473 (xorn,female) +{ + ................ + ................ + ................ + ...OB.OP.BP..... + ...BBBBPPPP..... + ...B............ + ...DDBB.BDDA.A.. + ...DDBB.PDDAAAA. + ...B.......AAAA. + ...BOB.BPP.AAAA. + ...BBB.PPP.AAAA. + ...B.......AAA.. + ...BOBBPPBPAA... + ...BO.BP.PPA.... + ................ + ................ +} +# tile 474 (monkey,male) { ................ ................ @@ -4549,7 +9052,26 @@ Z = (195, 195, 195) .....JJA.JJA.... ................ } -# tile 238 (ape) +# tile 475 (monkey,female) +{ + ................ + ................ + ................ + ................ + ................ + .......KKA...... + ......KLLJA..... + ......KLLJA..... + .......KJA...... + .....KKKKKJAA... + ....KJKLLJJJAA.. + ....LAKLLJALAA.. + ......KJJJAAAA.. + ......JAAJAAA... + .....JJA.JJA.... + ................ +} +# tile 476 (ape,male) { ................ ................ @@ -4568,7 +9090,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 239 (owlbear) +# tile 477 (ape,female) +{ + ................ + ................ + ......KKKJ...... + .....JJJJJJ..... + ....KCELECJJ.AA. + ....KLLLLCAJAAAA + ...KKCLACCAJJAAA + ..KKKKCCCAJKJJAA + ..KKAKJAAJJAJJAA + ..KAAKJJJJJAAJAA + ..LC.KJJJJJKCLAA + ..LL.CJJAKLJLLAA + .....CLJACLJAAAA + ...LLLLJACLLLKA. + ................ + ................ +} +# tile 478 (owlbear,male) { ................ ....K.....K..... @@ -4587,7 +9128,26 @@ Z = (195, 195, 195) ...PJPJAJPJPA... ................ } -# tile 240 (yeti) +# tile 479 (owlbear,female) +{ + ................ + ....K.....K..... + ....CK...KK..... + ....CKKKKKK..... + ...KOOOKOOOK.... + ...KOOOKOOOKA..A + ...KOOAJAOOKAAAA + ..CKCJJHJJKAKAAA + .CKKKCKLKKAJJKAA + .KJJJJCKKJJJJJAA + .KJJJPAKJPJJJJAA + ..KJJJAKJJJJJAAA + ...JJPAKJPJJAAA. + ...JAAJAJAAJAA.. + ...PJPJAJPJPA... + ................ +} +# tile 480 (yeti,male) { ................ ....BNNN........ @@ -4606,7 +9166,26 @@ Z = (195, 195, 195) ..BNNA..NNA..... ................ } -# tile 241 (carnivorous ape) +# tile 481 (yeti,female) +{ + ................ + ....BNNN........ + ...BNANAP....... + ..BNNNNNNP...... + ..NNNADANN...... + ..NNNNNNPN...... + ..N.NNBPPNP..... + ..N.NNNNANP..AA. + ..NNBNNNPN.AAAA. + ....NNNNP.KAAA.. + ....NN.NPAKKAA.. + ....NB.NPAACKAA. + ....NNANPAAKKJA. + ...BNNANNPAACKA. + ..BNNA..NNA..... + ................ +} +# tile 482 (carnivorous ape,male) { ................ ................ @@ -4625,7 +9204,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 242 (sasquatch) +# tile 483 (carnivorous ape,female) +{ + ................ + ................ + ......KKKJ...... + .....JJJJJJ..... + ....KCELECJJ.AA. + ....KLLLLCAJAAAA + ...KKCAAACAJJAAA + ..KKKCDDDCAKJJAA + ..KKAKCCCAJAJJAA + ..KAAKJAAJJAAJAA + ..LC.AJJJJJKCLAA + ..LLDDAJAKLJLLAA + ...DDALJACLJAAAA + ..DDALLJACLLLKA. + ................ + ................ +} +# tile 484 (sasquatch,male) { ................ ....CCCCC....... @@ -4644,7 +9242,26 @@ Z = (195, 195, 195) .CJJJKACKJJKA... ................ } -# tile 243 (kobold zombie) +# tile 485 (sasquatch,female) +{ + ................ + ....CCCCC....... + ...CGAJGAJ...... + ..CKKKKJJJ...... + ..CKKAAAKJJ..... + .CKKKAAAKKJ..... + .CKJKKKKKKKJ.... + .CKAJJJJJAKJ.... + .CKAJKKKJAKJ.AA. + .CKJAJKJACKJAAAA + .CKJAJJJACKJAAA. + ..J.AJAKKAJAAAAA + ...CKJAKKJAAAAA. + .KCKJJACKJKJAA.. + .CJJJKACKJJKA... + ................ +} +# tile 486 (kobold zombie,male) { ................ ................ @@ -4663,7 +9280,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 244 (gnome zombie) +# tile 487 (kobold zombie,female) +{ + ................ + ................ + ................ + ...N...N........ + ...NGFBN........ + ...GABAB........ + ....GBFA..A..... + ...GBABFA.AA.... + ..GFBBBIKAAA.A.. + ..BAFBFFEAAAAA.. + ..BAFBFFAAAAAA.. + ....FBFAAAAAA... + ....BABAAAA..... + ...BBABBA....... + ................ + ................ +} +# tile 488 (gnome zombie,male) { ................ ................ @@ -4682,7 +9318,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 245 (orc zombie) +# tile 489 (gnome zombie,female) +{ + ................ + ................ + ................ + ................ + ......G......... + .....GFF........ + ....GGFFF....... + ....GDFDF....... + .....GFF...AAA.. + ...FGFFFEGAAAA.. + ..GAAGFFFAGAAA.. + ....AKNKFAAAA... + ....FGAFFAA..... + ....GFAFG.A..... + ................ + ................ +} +# tile 490 (orc zombie,male) { ................ ................ @@ -4701,7 +9356,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 246 (dwarf zombie) +# tile 491 (orc zombie,female) +{ + ................ + ................ + ................ + .....OA......... + ....NOPA........ + ....GPGA........ + .....PFA........ + ..KCCAKKKA.AA... + .BBPCKJ.BBAAA... + BB.AGGFAABBA.... + B..AJJPAAABA.... + ....BAPPPAAAAA.. + ...BJAAEPAAA.... + ..BPPAAAPP...... + ................ + ................ +} +# tile 492 (dwarf zombie,male) { ................ ................ @@ -4720,7 +9394,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 247 (elf zombie) +# tile 493 (dwarf zombie,female) +{ + ................ + ................ + ................ + ................ + ......B......... + .....BEE........ + ....BBEEE....... + ....BFFFE....... + .....PFP...AAA.. + ...BBPPPEEAAAA.. + ..FBABPEAEAAAA.. + ..F.EBBEFAAAA... + ....EBAEEAA..... + ....BEAEB.A..... + ................ + ................ +} +# tile 494 (elf zombie,male) { ................ ................ @@ -4739,7 +9432,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 248 (human zombie) +# tile 495 (elf zombie,female) +{ + ................ + ................ + .........G...... + .......GGF...... + ......GGGGA..... + ......FEFEA..... + ......FFFFA..... + ......AFDA....A. + ......GAAG..AAA. + ....FFGGGFFFAAA. + ...FAAAGFAAAFAA. + .....AGGGFAAAA.. + ......GFAFAA.A.. + .....KDA.FKA.... + ................ + ................ +} +# tile 496 (human zombie,male) { ......AAA....... .....FFGAA...... @@ -4758,7 +9470,26 @@ Z = (195, 195, 195) ....GGAGGA...... ................ } -# tile 249 (ettin zombie) +# tile 497 (human zombie,female) +{ + ......AAA....... + .....FFGAA...... + .....AGAFA...... + .....FFGFA...... + ....FKF..JJ..... + ....JJJFJKJ..... + ...FJ.KJJAKJ.... + ..FK..KFJFFJ.... + ..G...KKJG...... + .....BP.BPAAAAA. + .....FPAPFAAAA.. + .....BFABFAAAA.. + .....PFABPAA.... + .....BFABFA..... + ....GGAGGA...... + ................ +} +# tile 498 (ettin zombie,male) { ....NN..ONOP.... ..NNOOPNNOOPP... @@ -4777,7 +9508,26 @@ Z = (195, 195, 195) .....GFAAGFAAAAA ...FFFFA.GFFFFAA } -# tile 250 (ghoul) +# tile 499 (ettin zombie,female) +{ + ....NN..ONOP.... + ..NNOOPNNOOPP... + ..NFF..NFF..P... + ..ADFFDADFFDA... + ..AFFFFAFFFFA... + ..AFAAFAFAAFAA.. + ..AFFFFAFFFFAAA. + ..GIIIIJJJIIIGAA + .GFFFIIIIIIFFFGA + .GFFFFIIIIFFFFFA + .FFAAFIIIIFAAFFA + .FFAAIIIIIIAAFFA + .FFF.IIFFIIAGFAA + ..FF.GFAAGFAFFAA + .....GFAAGFAAAAA + ...FFFFA.GFFFFAA +} +# tile 500 (ghoul,male) { ......AAA....... .....OOOAA...... @@ -4796,7 +9546,26 @@ Z = (195, 195, 195) ....OOAOOA...... ................ } -# tile 251 (giant zombie) +# tile 501 (ghoul,female) +{ + ......AAA....... + .....OOOAA...... + .....DODOA...... + .....OOOOA...... + ....PPOOOPP..... + ....PPPPPPP..... + ...PP.PPPAPP.... + ..PP..PPPOOP.... + ..O...PPPO...... + .....PP.PPAAAAA. + .....PPAPPAAAA.. + .....PPAPPAAAA.. + .....PPAPPAA.... + .....PPAPPA..... + ....OOAOOA...... + ................ +} +# tile 502 (giant zombie,male) { ......JJJJAA.... ....JJJJJJJJA... @@ -4815,7 +9584,26 @@ Z = (195, 195, 195) ....GFFAGFFAAAAA ...GFFAAGFFFAAAA } -# tile 252 (skeleton) +# tile 503 (giant zombie,female) +{ + ......JJJJAA.... + ....JJJJJJJJA... + ....JJFFFFJJA... + ....JDDFFDDJA... + ....JFFFFFFJA... + ....AFFAAFFAAA.. + .....AFFFFJAAAA. + ..GGFFJJJJFFGGAA + .GFFFGGFFFFFFFCA + .FFFKFFFFFFKFFFA + FFFAAFFFFFFAAFFA + FFAA.JJJKKJAAFFA + FFA..JJJJJKAGFAA + .....GFAGFFAFFAA + ....GFFAGFFAAAAA + ...GFFAAGFFFAAAA +} +# tile 504 (skeleton,male) { ................ ................ @@ -4834,7 +9622,26 @@ Z = (195, 195, 195) ......OOO....... ................ } -# tile 253 (straw golem) +# tile 505 (skeleton,female) +{ + ................ + ................ + ...OOO.......... + ..AOAOO......... + ..OOOOO......... + ..OO.O.......... + ......O......... + ....OOOOO...AAA. + ...OA.OOOA..AAA. + ..OA.OAAO.AAAAA. + ....OA.OOOAAA.A. + ......OOOAAA.A.. + .....O.AO.A..... + ...OOOA.OA...... + ......OOO....... + ................ +} +# tile 506 (straw golem,male) { ......LJ........ ......LJHJ...... @@ -4853,7 +9660,26 @@ Z = (195, 195, 195) ....HALA.AHAAL.. ..........L..... } -# tile 254 (paper golem) +# tile 507 (straw golem,female) +{ + ......LJ........ + ......LJHJ...... + ....HJLJH...A... + ....AAAAAL.....A + ....DAADAL.A.AA. + ....LJHJL..AAAA. + ....LLHJLHHCHHL. + ...HHLJL.AJLJL.A + .HHJJLLLLAAA.AA. + ..JL..LALHAAAAAA + .LL..CJLHJHAAAAA + .....HJLAHJHAAA. + .....HJAACALHAAA + ....CJLAAJHALHA. + ....HALA.AHAAL.. + ..........L..... +} +# tile 508 (paper golem,male) { ................ .......OA....... @@ -4872,7 +9698,26 @@ Z = (195, 195, 195) ....OOA...OOA... ................ } -# tile 255 (rope golem) +# tile 509 (paper golem,female) +{ + ................ + .......OA....... + .....NNNOA...... + .....ONNNOA..... + ......ONNOA..... + .......NOA...... + ..NNOA.NOA...... + ..NONOAOAONNOA.. + ..OAOANNOAOOOA.. + ......NNNOAAAAA. + ......ONOAAAAAA. + .......OOAAAAAA. + .....NOAAOAAAAA. + .....NOA..NOAA.. + ....OOA...OOA... + ................ +} +# tile 510 (rope golem,male) { ................ ................ @@ -4891,7 +9736,26 @@ Z = (195, 195, 195) ...O.A....OAA... ....OA.......... } -# tile 256 (gold golem) +# tile 511 (rope golem,female) +{ + ................ + ................ + ......OOO....... + .....O...O...... + .....O...O...AA. + .OO...O..O..A..A + O..O...LL..OO..A + ...O...LOOO.AOA. + ....OOOOOAAAAO.. + .......OO..AA.A. + .......LO.AA...A + ......O..OOAA..A + ....OO..A..O.A.. + ...O..AA...O.A.. + ...O.A....OAA... + ....OA.......... +} +# tile 512 (gold golem,male) { ................ ......HNH....... @@ -4910,7 +9774,26 @@ Z = (195, 195, 195) H...HNC.AHNC.A.H ..H............. } -# tile 257 (leather golem) +# tile 513 (gold golem,female) +{ + ................ + ......HNH....... + ......DND...N... + ......HNH...JC.. + ......HNH...NC.. + ...HHHAAAAHANC.. + ..HNJNHNHNJNAC.A + ..HHHHHHHHHHHA.A + .NCACCCCCCCCA..A + .HH.AAAAAAAAA.AA + .NH.ANC.AHNC.AAA + .NJ.AHC.AHHC.AAA + ..H.ANC.AHNC.AAA + ....HJC.AHJC.AA. + H...HNC.AHNC.A.H + ..H............. +} +# tile 514 (leather golem,male) { ......KKKK...... .....KHKHJ...... @@ -4929,7 +9812,26 @@ Z = (195, 195, 195) ...KJJA..KJJA... ....KA....KA.... } -# tile 258 (wood golem) +# tile 515 (leather golem,female) +{ + ......KKKK...... + .....KHKHJ...... + ....KAKKJJA..... + ...KKAJJJJAJ.... + ..KKJJAJAAKJJ... + .KKKJJAAKKKJJJ.. + ..KKJJJAKKJJJJ.. + ...KKJJJA.AAA.A. + ....AAAA.KJAAAA. + ....KJAAAKKAAAAA + ...KJJAA.KJJAAA. + ...KKJA..KKJAAA. + ..KKJJJAKKJJJAA. + ..KKKJJAKKKJJA.. + ...KJJA..KJJA... + ....KA....KA.... +} +# tile 516 (wood golem,male) { ................ ......KCKJ...... @@ -4948,7 +9850,26 @@ Z = (195, 195, 195) ....KCKJAKCKJA.. ................ } -# tile 259 (flesh golem) +# tile 517 (wood golem,female) +{ + ................ + ......KCKJ...... + ......HCHJ..C... + ......KCKJ..CK.. + ......KCKJ..CKJ. + ...KKKAAAAKACKJ. + ..KCCCCCCCCCAKJA + ..KKKKKKKKKKKAJA + .CJAJJJJJJJJA..A + .CKJAAAAAAAAA.AA + .CKJACKJAKCKJAAA + .CKJACKJAKCKJAAA + ..KJACKJAKCKJAAA + ....KCKJAKCKJAA. + ....KCKJAKCKJA.. + ................ +} +# tile 518 (flesh golem,male) { ................ ................ @@ -4967,7 +9888,26 @@ Z = (195, 195, 195) ..LLDDD..DDDDD.. ................ } -# tile 260 (clay golem) +# tile 519 (flesh golem,female) +{ + ................ + ................ + ...D..DDC....... + .....DLDDL...... + ..DD..LLLLC.D... + ...CDL.LLLLADL.. + ..CLDLA.CLLA.LL. + ..LLLAA.LLCA..L. + .CLLAA.CLLAA..CA + .LLA..CLLALLAAAA + ..LA.CLCAALCAAAA + ...A..LLCACLCAAA + ....LLALLAALLAAA + ..CLLLAAAADLLA.. + ..LLDDD..DDDDD.. + ................ +} +# tile 520 (clay golem,male) { ................ ................ @@ -4986,7 +9926,26 @@ Z = (195, 195, 195) ..CKKKA.CKKKAA.. ................ } -# tile 261 (stone golem) +# tile 521 (clay golem,female) +{ + ................ + ................ + ................ + ....LCCCCK...... + ...LKKKKKKK..... + ...CKAKKAKK..... + ...CKAKKAKK..... + .LCKKKKKKKKLC... + CKKJKKKKKKCKKJ.. + KKKJKKJJKKJKKJAA + .JJAKKJAKKAJJAAA + ..AKKKJAKKKAAAAA + ..CKKKKKKKKKAAAA + ..CKKKAACKKKAA.. + ..CKKKA.CKKKAA.. + ................ +} +# tile 522 (stone golem,male) { ................ ................ @@ -5005,7 +9964,26 @@ Z = (195, 195, 195) ...PPAA.PPPA.... ................ } -# tile 262 (glass golem) +# tile 523 (stone golem,female) +{ + ................ + ................ + ................ + ....BBBPP....... + ...BBPPPPP...... + ...BHAPHAP...... + ...PPPPPPP...... + .BBPPPPPP.BPA... + BPPPP....PPPPAA. + BPP.BPPPP.PPPAAA + .PP.BP.PP.PPPAAA + ...BPP.PPPAAAAAA + ..BPPPAPPPAAAAA. + ..PPPPAPPPPAAA.. + ...PPAA.PPPA.... + ................ +} +# tile 524 (glass golem,male) { ................ .....BBBBBBA.... @@ -5024,7 +10002,26 @@ Z = (195, 195, 195) ..BNPA....NPAA.. ...BA.....BPA... } -# tile 263 (iron golem) +# tile 525 (glass golem,female) +{ + ................ + .....BBBBBBA.... + .....BPNPPPA.... + .....BNPPPNA.... + .....NPPPNPA.... + .....BPPNPPA.... + .......BA...BA.. + .BNBBABPBA.BPNA. + .NPPNABPNBBANPBA + .....BPNPPPAABAA + .....BNPPPAAAAAA + ......BPPNAAAAAA + ....BNABNABPAAA. + ...BNPA...BNAAA. + ..BNPA....NPAA.. + ...BA.....BPA... +} +# tile 526 (iron golem,male) { ................ ......PBP....... @@ -5043,7 +10040,26 @@ Z = (195, 195, 195) ....PBP.APBP.A.. ................ } -# tile 264 (human) +# tile 527 (iron golem,female) +{ + ................ + ......PBP....... + ......HBH...B... + ......PBP...JP.. + ......PBP...BP.. + ...PPPAAAAPABP.. + ..PBJBBBBBJBAP.A + ..PPPPPPPPPPPA.A + .B.A........A..A + .BP.AAAAAAAAA.AA + .BP.ABP.APBP.AAA + .BJ.ABP.APBP.AAA + ..P.ABP.APBP.AAA + ....PJP.APJP.AA. + ....PBP.APBP.A.. + ................ +} +# tile 528 (human,male) { ................ ................ @@ -5062,7 +10078,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 265 (wererat) +# tile 529 (human,female) +{ + ................ + ................ + .......JJA...... + ......JJJJA..... + ......ELELA..... + ......LLLLA..... + ......ALLA...... + .....CJAAJC.AAA. + ....CLJLLJLCAAA. + ....LAKJJJALAAA. + ....LAJJKJALAAA. + ......JJJKAAAA.. + ......JJAJAA.A.. + .....KLA.LKA.... + ................ + ................ +} +# tile 530 (wererat,male) { ................ ................ @@ -5081,7 +10116,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 266 (werejackal) +# tile 531 (wererat,female) +{ + ................ + ................ + .......JJA...... + ......JJJJA..... + ......GJGJA..... + ......LLLLA..... + ......ALLA...... + .....CJAAJC.AAA. + ....CLJLLJLCAAA. + ....LAKJJJALAAA. + ....LAJJKJALAAA. + ......JJJKAAAA.. + ......JJAJAA.A.. + .....KLA.LKA.... + ................ + ................ +} +# tile 532 (werejackal,male) { ................ ................ @@ -5100,7 +10154,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 267 (werewolf) +# tile 533 (werejackal,female) +{ + ................ + ................ + .......JJA...... + ......JJJJA..... + ......IPIPA..... + ......LLLLA..... + ......ALLA...... + .....CJAAJC.AAA. + ....CLJLLJLCAAA. + ....LAKJJJALAAA. + ....LAJJKJALAAA. + ......JJJKAAAA.. + ......JJAJAA.A.. + .....KLA.LKA.... + ................ + ................ +} +# tile 534 (werewolf,male) { ................ ................ @@ -5119,7 +10192,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 268 (elf) +# tile 535 (werewolf,female) +{ + ................ + ................ + ......JJA....... + .....JJJJA...... + .....NJNJA...... + .....LLLLA...... + .....ALLA....... + ....CJAAJC.AAA.. + ...CLJLLJLCAAA.. + ...LAKJJJALAAA.. + ...LAJJKJALAAA.. + .....JJJKAAAA... + .....JJAJAA.A... + ....KLA.LKA..... + ................ + ................ +} +# tile 536 (elf,male) { ................ .........G...... @@ -5138,7 +10230,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 269 (Woodland-elf) +# tile 537 (elf,female) +{ + ................ + .........G...... + .......GGF...... + ......GGGGA..... + ......LELEA..... + ......LLLLA..... + ......ALLA....A. + ......GAAG..AAA. + .....LGGGFLAAAA. + ....LAAGFAALAAA. + ....LAGGGFALAA.. + ......GFAFAA.A.. + ......GFAFAA.A.. + .....KLA.LKA.... + ................ + ................ +} +# tile 538 (Woodland-elf,male) { ................ ................ @@ -5157,7 +10268,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 270 (Green-elf) +# tile 539 (Woodland-elf,female) +{ + ................ + ................ + .........K...... + .......KKJ...... + ......KKKKA..... + ......LELEA..... + ......LLLLA..... + ......ALLA....A. + ......KAAK..AAA. + .....LKKKJLAAAA. + ....LAPPJAALAAA. + ..KKLKKKKJALAA.. + ......PPAJAA.A.. + .....KLA.LKA.... + ................ + ................ +} +# tile 540 (Green-elf,male) { ................ ................ @@ -5176,7 +10306,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 271 (Grey-elf) +# tile 541 (Green-elf,female) +{ + ................ + ................ + .........G...... + .......GGF...... + ......GGGGA..... + ......LELEA..... + ......LLLLA..... + ......ALLA....A. + ......GAAG..AAA. + .....LGGGFLAAAA. + ....LAAGFAALAAA. + ....LAGGGFALAA.. + ......GFAFAA.A.. + .....KLA.LKA.... + ................ + ................ +} +# tile 542 (Grey-elf,male) { ................ ................ @@ -5195,7 +10344,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 272 (elf-lord) +# tile 543 (Grey-elf,female) +{ + ................ + ................ + .........P...... + .......PP....... + ......PPPPA..... + ......LELEA..... + ......LLLLA..... + ......ALLA....A. + ......PAAP..AAA. + .....LPPP.LAAAA. + ....LAAP.AALAAA. + ....LAPPP.ALAA.. + ......P.A.AA.A.. + .....KLA.LKA.... + ................ + ................ +} +# tile 544 (elf-leader,male) { ................ ................ @@ -5214,7 +10382,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 273 (Elvenking) +# tile 545 (elf-leader,female) +{ + ................ + ................ + ........II...... + .......HGF...... + ......HGGGA..... + ......LELEA..... + ......LLLLA..... + ......ALLA....A. + ......HAAH..AAA. + .....LHHHFLAAAA. + ....LAAIIAALAAA. + ....LAHGGFALAA.. + ......HFAFAA.A.. + .....KLA.LKA.... + ................ + ................ +} +# tile 546 (elven monarch,male) { ................ ................ @@ -5233,7 +10420,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 274 (doppelganger) +# tile 547 (elven monarch,female) +{ + ................ + ......H..H...... + ......H..H...... + ......HCHH...... + ......HHHHA..... + ......LELEA..... + ......LLLLA..... + .....IALLAI...A. + ....IIIAAIDIAAA. + .....LIIGDLAAAAA + ....LADIFDALAAAA + ....LAIIGDALAAA. + .....IIFAFDAAA.. + ...IIKLAILKDI... + ................ + ................ +} +# tile 548 (doppelganger,male) { ................ ......CCCC..I... @@ -5252,7 +10458,26 @@ Z = (195, 195, 195) ..CD.LLAALLADC.. ................ } -# tile 275 (shopkeeper) +# tile 549 (doppelganger,female) +{ + ................ + ......CCCC..I... + ..I..CD...C..... + ....CD.HHA.C.... + ...CD.HHHHA.C.I. + ...CD.LFLFA.DC.. + .I.CD.LLLLA.DC.. + ...CD.ALLA.DC... + ..CD.LLAALL.ACA. + .CD.LLLLLLLLADC. + .CD.LALLLLALADC. + .CD.LAJJKJALADC. + ..CD..LJJLAAACA. + ...CD.LLALAACA.. + ..CD.LLAALLADC.. + ................ +} +# tile 550 (shopkeeper,male) { ................ ................ @@ -5271,7 +10496,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 276 (guard) +# tile 551 (shopkeeper,female) +{ + ................ + ................ + ......AAAA...... + .....AAAAAA..... + ......JLJL...... + ......LLLL...... + ......ALLA...... + .....EBAABEA.AA. + ....EBBBBBBEAAA. + ....BAEBBEABAAA. + ....LAGFFFALAAA. + ......GFAFAAAA.. + ......GFAFAA.A.. + .....JJA.JJA.... + ................ + ................ +} +# tile 552 (guard,male) { ................ .....BBPPPAA.... @@ -5290,7 +10534,26 @@ Z = (195, 195, 195) .....BPPABPPAAAA ....BPPP.BPPPAAA } -# tile 277 (prisoner) +# tile 553 (guard,female) +{ + ................ + .....BBPPPAA.... + ....BNPPPPPPA... + ....BPPBPPPPA... + ....BAABPAAPA... + ....BCLBPCLPA... + ....JCLPPCLJAA.. + ....BPLLLLAPAAAA + ...BPPLAALAPPAAA + ..BPPPPLLPPPPPAA + ..PPABPPPPPPAPPA + ..PPABPPPPPPAPPA + ..LC.BPPPPPPCLAA + ..LL.BPPABPPLLAA + .....BPPABPPAAAA + ....BPPP.BPPPAAA +} +# tile 554 (prisoner,male) { ................ ................ @@ -5309,7 +10572,26 @@ Z = (195, 195, 195) .....LLA.LLA.... ................ } -# tile 278 (Oracle) +# tile 555 (prisoner,female) +{ + ................ + ................ + .......NOA...... + .......LLA...... + .......LLA...... + .......NOA...... + ......NOONA..... + .....NOOOONA.... + ....NANOOOANAA.. + ....PANOOOAPAAA. + ....LANOOOALAAA. + ......NOOOAAAA.. + ......NAANAAA... + ......PAAPAA.... + .....LLA.LLA.... + ................ +} +# tile 556 (Oracle,male) { ................ ................ @@ -5328,7 +10610,26 @@ Z = (195, 195, 195) ....LELLLLELAA.. ................ } -# tile 279 (aligned priest) +# tile 557 (Oracle,female) +{ + ................ + ................ + .......NN....... + LLL...GLLG...LLL + ..L..NLLLLN..L.. + ...L.NLAALN.L... + ....LNLLLLNL.... + .....LNLLNL..AA. + .....NBBEEN.AAAA + ......BBEEAAAAAA + .LLA..BBBEAAALL. + .LLLLBBBEBELLLLA + ..LLCLBLLELLCLAA + ...CLLLLLLLCLAA. + ....LELLLLELAA.. + ................ +} +# tile 558 (aligned priest,male) { ................ INI............. @@ -5347,7 +10648,26 @@ Z = (195, 195, 195) .JACCCJJCCCAA... ................ } -# tile 280 (high priest) +# tile 559 (aligned priest,female) +{ + ................ + INI............. + III..KCCK....... + .J..KCCCCK...... + .J..CAAKCC...... + .LC.CAAACC...... + CLLC.CAACJKC.... + CJLACCCCJKCCC... + .JAACCJJCKCCCK.. + .JKCCCJCCJCCK.AA + .J..CCJCCLJCAAAA + .J..CCJCLLCAAAA. + .J..KCJCCCJAAAA. + .J.ACCJCCCJAAA.. + .JACCCJJCCCAA... + ................ +} +# tile 560 (high priest,male) { .INI............ IIIII.KCCK...... @@ -5366,7 +10686,26 @@ Z = (195, 195, 195) ..HACCCJJCCCAA.. ................ } -# tile 281 (soldier) +# tile 561 (high priest,female) +{ + .INI............ + IIIII.KCCK...... + .IHI.KCAACK..... + ..H..CGAGAC..... + ..LC.CAAAAC..... + .CLLC.CAACJCK... + .CHLACCCCJCCCK.. + ..HAACCJJCCCCCK. + ..HCCCCJCCJCCC.A + ..H..CCJCCLJCAAA + ..H..CCJCLLCAAAA + ..H..KCJCCCJAAAA + ..H..KCJCCCJAAAA + ..H.ACCJCCCJAAA. + ..HACCCJJCCCAA.. + ................ +} +# tile 562 (soldier,male) { .....J.......... .....JAAA....... @@ -5385,7 +10724,26 @@ Z = (195, 195, 195) .....JJ.JJ...... ................ } -# tile 282 (sergeant) +# tile 563 (soldier,female) +{ + .....J.......... + .....JAAA....... + .....ALLLA...... + .....LLLLC...... + .....JLLC....... + .....JF..F...... + ....FJFFFFF..A.. + ....FJFFFAF.A... + ....FLFFFFFAAA.. + ....FJFFAAAAAAA. + .....LFAFFAAAA.. + .....FFAF.AAAA.. + ......FAF.AA.... + .....FFAFFA..... + .....JJ.JJ...... + ................ +} +# tile 564 (sergeant,male) { .....J.......... .....JFFF....... @@ -5404,7 +10762,26 @@ Z = (195, 195, 195) .....AA.AA...... ................ } -# tile 283 (nurse) +# tile 565 (sergeant,female) +{ + .....J.......... + .....JFFF....... + ....FFFFFF...... + .....LLLLC...... + .....JLLC....... + .....JF..G...... + ....FJFFFFF..A.. + ....FJFFFAF.A... + ....FLFFFFFAAA.. + ....FJFFAAAAAAA. + .....LFAFFAAAA.. + .....FFAF.AAAA.. + ......FAF.AA.... + .....FFAFFA..... + .....AA.AA...... + ................ +} +# tile 566 (nurse,male) { ................ .......NO....... @@ -5423,7 +10800,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 284 (lieutenant) +# tile 567 (nurse,female) +{ + ................ + .......NO....... + ......NDDO...... + ......NNOOA..... + .....DBLBLD..... + .....CLLLLDC.... + .....DALLACD.... + .....CNAAODCAAA. + .....NNNOOLAAAA. + ....LANNDOALAAA. + ....LANNOOALAAA. + ......NNOOAAAA.. + ......NNAOAA.A.. + .....LLA.LLA.... + ................ + ................ +} +# tile 568 (lieutenant,male) { ................ .......FFF...... @@ -5442,7 +10838,26 @@ Z = (195, 195, 195) .....AA.AA...... ................ } -# tile 285 (captain) +# tile 569 (lieutenant,female) +{ + ................ + .......FFF...... + .....FFFFFF..... + ......LLLL...... + .......LLCA..... + .....GF.FGA..... + ....FFFFFFFF.... + ....FAFFFFAFAAA. + ....FAFFFFAFAAAA + ....FAFFFFAFAAA. + ....LFFAFFJLJA.. + .....FFAFFJJJA.. + ......FAF.AA.... + .....FFAFFA..... + .....AA.AA...... + ................ +} +# tile 570 (captain,male) { ................ ......FHHF...... @@ -5461,7 +10876,26 @@ Z = (195, 195, 195) .....AA.AAAAA... ................ } -# tile 286 (watchman) +# tile 571 (captain,female) +{ + ................ + ......FHHF...... + .....FFFFFF..... + ......LLLL...... + .......LLCA..... + .....HF.FHF..... + ....FFFFFFFFAA.. + ....FAFFIFAFAAAA + ....FAFFFFAFAAA. + ....FAFFFFAFAAA. + ....LFFAFFJLJA.. + .....FFAFFJJJA.. + ......FAF.JJJA.. + .....FFAFFJJJA.. + .....AA.AAAAA... + ................ +} +# tile 572 (watchman,male) { ................ ......PPP....... @@ -5480,7 +10914,26 @@ Z = (195, 195, 195) ....JJJ.JJJ..... ................ } -# tile 287 (watch captain) +# tile 573 (watchman,female) +{ + ................ + ......PPP....... + ....PPPPPP...... + .....LLLLC...... + ......LLC....... + .....PP..P...... + ....PPPPPPP..... + ....PAPPHAPPA... + ....PAPPPANNAAA. + ....PJPPAPNNAAA. + ....JLPAPPAAAA.. + .....JPAP.AAAA.. + ......PAP.AA.... + .....PPAPPA..... + ....JJJ.JJJ..... + ................ +} +# tile 574 (watch captain,male) { ......PPP....... .....PHHHP...... @@ -5499,7 +10952,26 @@ Z = (195, 195, 195) ....JJJ.JJJ..... ................ } -# tile 288 (Medusa) +# tile 575 (watch captain,female) +{ + ......PPP....... + .....PHHHP...... + ....PPPPPPP..... + .....LLLLC...... + ......LLC....... + .....HP..H...... + ....PPPPPPP..... + ....PAPPHAPPA... + ....PAPPPANNAAA. + ....PJPPAPNNAAA. + ....JLPAPPAAAA.. + .....JPAP.AAAA.. + .....JPAP.AA.... + .....PPAPPA..... + ....JJJ.JJJ..... + ................ +} +# tile 576 (Medusa,male) { ................ ..GA...GA....... @@ -5518,7 +10990,26 @@ Z = (195, 195, 195) ..IIKIKIKIA..... ................ } -# tile 289 (Wizard of Yendor) +# tile 577 (Medusa,female) +{ + ................ + ..GA...GA....... + ...FA.FA..GA.... + ....FJFFFF...... + ..FAFLLFA....A.. + .GAFLLLLA..A..A. + ....JLLKA.A.A.A. + ...KBLLBKAAAAA.. + ..KIIBBIIIAAA.A. + ..IIIKKILLIAAA.. + ..KIILLIALIAA... + ...KIALKAAIAA... + ...IKAAKIIAAA... + ...IIKKIIIAA.... + ..IIKIKIKIA..... + ................ +} +# tile 578 (Wizard of Yendor,male) { .EEE.......EEE.. EFFAE..E..EAFFE. @@ -5537,7 +11028,26 @@ Z = (195, 195, 195) .EEEEEEEEEEEAAA. EEEEEEEEEEEEEEA. } -# tile 290 (Croesus) +# tile 579 (Wizard of Yendor,female) +{ + .EEE.......EEE.. + EFFAE..E..EAFFE. + EAAAE.EEE.EAAAE. + EAAAEEEAEEEAAAE. + EEAAEEDADEEAAEE. + .EEEEAAAAAEEEE.. + ..EEEEAAAEEEE... + ..EEEEEEEEEE.... + ...EEEEEEEE..... + ...EEEEEEEE....A + ....EEEEEE...AAA + ....EEEEEEAAAAAA + ...EEEEEEEEAAAAA + ..EEEEEEEEEAAAAA + .EEEEEEEEEEEAAA. + EEEEEEEEEEEEEEA. +} +# tile 580 (Croesus,male) { ....H..H..H..... ....HCHEHCH..... @@ -5556,7 +11066,26 @@ Z = (195, 195, 195) .GIIIKJJKKIIIGG. ................ } -# tile 291 (Charon) +# tile 581 (Croesus,female) +{ + ....H..H..H..... + ....HCHEHCH..... + ....HHHHHHH..... + ....ALLLLLA..... + ....LLALALL..... + .....LLLLL...... + ....HLLDLLH..... + ...HIALLLAIH.A.A + ...HIHAAAHIHAAAA + ..IIIEHHHIIIIAAA + ..IIIIEHIIIIIAA. + ..ILLIHHHILLIAAA + ...LIIKHIIILAAAA + ..GIIIKJIIIIGAA. + .GIIIKJJKKIIIGG. + ................ +} +# tile 582 (Charon,male) { ................ .......J........ @@ -5575,7 +11104,26 @@ Z = (195, 195, 195) .JJJJJJJJJJJAAA. JJJJJJJJJJJJJJA. } -# tile 292 (ghost) +# tile 583 (Charon,female) +{ + ................ + .......J........ + ......JJJ....... + ....JJJAJJJ..... + ....JJDADJJ..... + ...JJAAAAAJJ.... + ...JJJAAAJJJ.... + ..JJJJJJJJJJ.... + .JJJJJJJJJJJJ... + JJJJJJJJJJJJJJ.A + .OO.JJJJJJ.OOAAA + ....JJJJJJAAAAAA + ...JJJJJJJJAAAAA + ..JJJJJJJJJAAAAA + .JJJJJJJJJJJAAA. + JJJJJJJJJJJJJJA. +} +# tile 584 (ghost,male) { ................ ................ @@ -5594,7 +11142,26 @@ Z = (195, 195, 195) .O...P....P..... ........P....... } -# tile 293 (shade) +# tile 585 (ghost,female) +{ + ................ + ................ + ...NNN.......... + ..NANANN........ + .NNNNNNNNN...... + .NNPAAPNNNNN.... + .NNAAAANNNOONO.. + .NNAAAANONNNPNNO + .NNPAAPNONNOOOP. + .NNNNNNONOPNPPO. + .NNONNOPNNOPOOP. + .NOPNNOOOPPOOP.. + .OOOPOPPOPPP.PP. + .PP.PPOPPP...P.. + .O...P....P..... + ........P....... +} +# tile 586 (shade,male) { ................ ................ @@ -5613,7 +11180,26 @@ Z = (195, 195, 195) AAAA.AAAAJA..... ................ } -# tile 294 (water demon) +# tile 587 (shade,female) +{ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ........AAAAAAA. + ....AAAAAAAA.... + ..AAAAAAAAAAAA.. + AAAAAAAAAAAAAAA. + ..AAAAAAAAAAAAAA + .AAAAAAAAAAAAA.. + AAAA.AAAAJA..... + ................ +} +# tile 588 (water demon,male) { ................ ................ @@ -5632,45 +11218,26 @@ Z = (195, 195, 195) ....EEAEEA...... ................ } -# tile 295 (succubus) -{ - DD.OHHD......... - DDOHHDGD........ - DDOHDDDDD....... - DDHHDDDA........ - DHHHDJADDDD..... - .HHJJDDDJDDD.... - OHDDCDCDDJDD.... - HHHCDDCDLJ.DD... - HHHCDLJJJAADDA.. - HHHDJJDDDAADAA.. - HHHHDDAADAAAA... - HHHH.DKJDDAA.... - H.H..DDAADDAA... - ..H..DDAA.DAA... - ....DDAA..DDAA.. - ...DDJA...DDDA.. -} -# tile 296 (horned devil) +# tile 589 (water demon,female) { ................ ................ - ..O.......O..... - ..OO.....OO..... - ...LOCDCOL...... - ...CDDDDDC...... - ...DAADAADA..D.. - ...DDDDDDDA.D... - ..CCDDFDDCCAD.A. - ..CDKDDDKCDADA.. - ..CDAKKKACDAAAA. - ..DDADDDADDAAAA. - ....CDDDKAAAAA.. - ...CDDADDKAA.... - ..CDDAA.DDK..... + ................ + ................ + ..EE.....EE..... + .E.EE...EE.E.... + ....EEEEE....... + ....EBEBE..A.... + ...EEEEEEEAAAA.. + ..EEE...EEEAA.A. + ..EEEEEEEEEAAA.. + ..EEAEEEAEEAAA.. + ...AAEEEAAAAA... + ....EEAEEAA..... + ....EEAEEA...... ................ } -# tile 297 (incubus) +# tile 590 (amorous demon,male) { DD.OHHD......... DDOHHDGD........ @@ -5689,7 +11256,64 @@ Z = (195, 195, 195) ...DDKAA..DDAA.. ..DDKAA...DDDA.. } -# tile 298 (erinys) +# tile 595 (amorous demon,female) +{ + DD.OHHD......... + DDOHHDGD........ + DDOHDDDDD....... + DDHHDDDA........ + DHHHDJADDDD..... + .HHJJDDDJDDD.... + OHDDCDCDDJDD.... + HHHCDDCDLJ.DD... + HHHCDLJJJAADDA.. + HHHDJJDDDAADAA.. + HHHHDDAADAAAA... + HHHH.DKJDDAA.... + H.H..DDAADDAA... + ..H..DDAA.DAA... + ....DDAA..DDAA.. + ...DDJA...DDDA.. +} +# tile 592 (horned devil,male) +{ + ................ + ................ + ..O.......O..... + ..OO.....OO..... + ...LOCDCOL...... + ...CDDDDDC...... + ...DAADAADA..D.. + ...DDDDDDDA.D... + ..CCDDFDDCCAD.A. + ..CDKDDDKCDADA.. + ..CDAKKKACDAAAA. + ..DDADDDADDAAAA. + ....CDDDKAAAAA.. + ...CDDADDKAA.... + ..CDDAA.DDK..... + ................ +} +# tile 593 (horned devil,female) +{ + ................ + ................ + ..O.......O..... + ..OO.....OO..... + ...LOCDCOL...... + ...CDDDDDC...... + ...DAADAADA..D.. + ...DDDDDDDA.D... + ..CCDDFDDCCAD.A. + ..CDKDDDKCDADA.. + ..CDAKKKACDAAAA. + ..DDADDDADDAAAA. + ....CDDDKAAAAA.. + ...CDDADDKAA.... + ..CDDAA.DDK..... + ................ +} +# tile 596 (erinys,male) { ..GA...GA....... ...FA.FA..GA.... @@ -5708,7 +11332,26 @@ Z = (195, 195, 195) ..BBEBEBEBA..... ................ } -# tile 299 (barbed devil) +# tile 597 (erinys,female) +{ + ..GA...GA....... + ...FA.FA..GA.... + ....FJFFFF...... + ..FAFLLFA....... + .GAFDLDLA..A.A.. + ....LLLEA.A.A.A. + ...EBLLBEAAAA.A. + ..EBBBBBBBAAAA.. + ..BBBEBBLLBAA.A. + ..EBBLLBALBAAA.. + ...EBALBAABAA... + ...BEAABBBAAA... + ...BBBBBBBAAA... + ...BBBBBBBAA.... + ..BBEBEBEBA..... + ................ +} +# tile 598 (barbed devil,male) { ................ ................ @@ -5727,7 +11370,26 @@ Z = (195, 195, 195) .CCDDAA.DDKK.... ................ } -# tile 300 (marilith) +# tile 599 (barbed devil,female) +{ + ................ + ................ + ..O.......O..... + ..OO.....OO..... + .O.LOCDCOL.O.... + ...CDDDDDC....DD + ...DAADAADA..D.D + ...DDDDDDDA.D... + ..CCDDFDDCCAD.A. + ..CDKDDDKCDADA.. + .C.DAKKKACDKAAA. + ..DDADDDADDAAAA. + ....CDDDKAAAAA.. + .K.CDDADDKAAK... + .CCDDAA.DDKK.... + ................ +} +# tile 600 (marilith,male) { .D..HHH.....D... DD.HHHHHA...DD.. @@ -5746,7 +11408,26 @@ Z = (195, 195, 195) ..FGFFFFFFFFFA.. ....GFFFFFFAA... } -# tile 301 (vrock) +# tile 601 (marilith,female) +{ + .D..HHH.....D... + DD.HHHHHA...DD.. + .DCHDDDHHAAD..A. + ..HDBDBDHDDAAAA. + .CHKDDDKHAAADD.. + CDDDKKKDHDDDDFF. + D..CDDCDKAAFFFAA + D.KDDKDDDDDDFAA. + D.DKDDKDKAFDFAA. + ..D.GDDFAAFDFFAA + .D.GGFFFAAAFFFFA + ...GFFFFFAAAFFFA + ..FGFFFFFFAFFFFA + ..FGFFFFFFFFFFA. + ..FGFFFFFFFFFA.. + ....GFFFFFFAA... +} +# tile 602 (vrock,male) { ................ ......OPP.O..... @@ -5765,7 +11446,26 @@ Z = (195, 195, 195) .....DDA.DDA.... ................ } -# tile 302 (hezrou) +# tile 603 (vrock,female) +{ + ................ + ......OPP.O..... + ......PPPP...... + .....CPPDP...... + ....CCCPPP...... + ....CCPPPP...... + ....C..PPA...... + .....DDAADD.AAA. + ....DDDDDDDDAAA. + ....DADDDDADAAA. + ....DADDDDADAAA. + ....DADDDDADAAA. + ......DAADAAAA.. + ......DAADAA.A.. + .....DDA.DDA.... + ................ +} +# tile 604 (hezrou,male) { ................ ................ @@ -5784,7 +11484,26 @@ Z = (195, 195, 195) ...........FFFA. ................ } -# tile 303 (bone devil) +# tile 605 (hezrou,female) +{ + ................ + ................ + ....GGGFF....... + ..NGFFNNFFF..... + .DFFFDDNFF.F.... + .GFFFDNFF.FFFAA. + .AFAFFFFFFFFFFAA + .GFFFF.FFF.FGFAA + .GAAAFF..LFGFFAA + ..FFFF.FFLFGFFFA + ..LLA.FLLLJJG.FA + .LLAFFLLFJJGFFFA + ..LAFLLLAAGF.FAA + .....L.LAGFFFFAA + ...........FFFA. + ................ +} +# tile 606 (bone devil,male) { ................ ................ @@ -5803,7 +11522,26 @@ Z = (195, 195, 195) ..NOOAA.OOL..... ................ } -# tile 304 (ice devil) +# tile 607 (bone devil,female) +{ + ................ + ................ + ..O.......O..... + ..OO.....OO..O.. + ...LNLOLOL....O. + ...LOOOOOL....O. + ...NAAOAAOA..O.. + ...NOOOOOOA.O... + ..NOOOFOOOOAO.A. + ..OOKNOOKOOALA.. + ..OOANOOAOOAKAA. + ..LLANOOALLAAAA. + ....NOOOLAAAAA.. + ...NOOAOOLAA.... + ..NOOAA.OOL..... + ................ +} +# tile 608 (ice devil,male) { ................ ................ @@ -5822,7 +11560,26 @@ Z = (195, 195, 195) ..BNNAA.NNP..... ................ } -# tile 305 (nalfeshnee) +# tile 609 (ice devil,female) +{ + ................ + ................ + ..N.......N..... + ..NN.....NN..... + ...PBPNPNP..BNB. + ...PNNNNNP..N.N. + ...BAANAANA...N. + ...BNNNNNNA.BNB. + ..BNNNFNNNNAN.A. + ..NNKBNNKNNABA.. + ..NNABNNANNA.AA. + ..PPABNNAPPAAAA. + ....BNNNPAAAAA.. + ...BNNANNPAA.... + ..BNNAA.NNP..... + ................ +} +# tile 610 (nalfeshnee,male) { ................ ................ @@ -5841,7 +11598,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 306 (pit fiend) +# tile 611 (nalfeshnee,female) +{ + ................ + ................ + ......BB...BB... + ..KKKKKBB.BB.... + .KADKADKKKB..... + .KKKKKKKDKK..... + .OKDKOKKDDKD.... + .OKDKOKKKDKDD... + .KAAAKKDKAKKD... + ..KKKDDLAKKKD.A. + ...KK.KKKKKDDA.. + ....L..KDAKDAA.. + ......LLAAKDA... + .........LLA.... + ................ + ................ +} +# tile 612 (pit fiend,male) { ................ .K.O.......O.K.. @@ -5860,7 +11636,26 @@ Z = (195, 195, 195) ...CDDAA.DDK.... ................ } -# tile 307 (sandestin) +# tile 613 (pit fiend,female) +{ + ................ + .K.O.......O.K.. + .K.OO.....OO.KJ. + KJJ.LOCDCOL.KJJ. + KJJJKDDDDDKKJJJ. + KJJCKDNDNDKCJJJA + JJCCKDDDDDJCCJJA + JJCCCKDIDJDCCJJA + JACCDDKJJDDCDAJA + JACCKDDDDDKCDAJA + ...CDKDDDKCDDAAA + ....DKDDDKCDAAAA + .....CDDDKAAAA.. + ....CDDADDKA.... + ...CDDAA.DDK.... + ................ +} +# tile 614 (sandestin,male) { .....CCCCC..I... .I..CD....C..... @@ -5879,7 +11674,26 @@ Z = (195, 195, 195) .CD.DDAADDDADC.. ................ } -# tile 308 (balrog) +# tile 615 (sandestin,female) +{ + .....CCCCC..I... + .I..CD....C..... + ...CD.DDD..C..I. + ..CD.DDDDD..C... + ..CD.DNDNDA.DC.. + I.CD.DDDDDA.DC.. + ..CD.ADDDA.DC..A + .CD.DDAAADD.DCAA + CD.DDDDDDDDDADCA + CD.DADDDDDADADCA + CD.DADDDDDADADCA + CD.DADDDDDADADC. + .CD..DDJDDAADCA. + ..CD.DDADDADCA.. + .CD.DDAADDDADC.. + ................ +} +# tile 616 (balrog,male) { ................ .K..O.....O..K.. @@ -5898,7 +11712,26 @@ Z = (195, 195, 195) ..CDDDAA.DDDK.AA ................ } -# tile 309 (Juiblex) +# tile 617 (balrog,female) +{ + ................ + .K..O.....O..K.. + .KJ.O.....O.KJ.. + KJJLOOCDCOOLJJJ. + JJJDDDDDDDDDDKJ. + JCCDDDNDNDDDCCJA + CCDKDDDDDDDJCCCA + CDDKKKDIDJJDCCDA + CDDKDDKJJDDDCDDA + CCDKDDDDDDDKCDDA + JCCDKKDDDKKCDDDA + JJCDKKDDDKKCDDJA + JJ..CCDDDKKAAJJA + J..CDDDADDDKAAJA + ..CDDDAA.DDDK.AA + ................ +} +# tile 618 (Juiblex,male) { ................ DD.........DD... @@ -5917,7 +11750,26 @@ Z = (195, 195, 195) .CCCCCCCCCCCKA.. ................ } -# tile 310 (Yeenoghu) +# tile 619 (Juiblex,female) +{ + ................ + DD.........DD... + NDC.KKKKJ.CND... + .CCKCCCKKCCAA... + ..KCCCCKCCJAA... + ..KCCCCCK.JJAA.. + ..KCCFCCK..JAA.. + ..FKCFCCKK.JAAA. + .FKKFCCKFK..JAA. + .FKCFCCFKFK.JAA. + .FCFCCKFCFK.JAA. + FKCFCFCFCKK.JAA. + CKFCCFCCKKFKJJA. + CCKKCFCKFFKKKKA. + .CCCCCCCCCCCKA.. + ................ +} +# tile 620 (Yeenoghu,male) { ....B.HHP....... ....BPPPP....... @@ -5936,7 +11788,26 @@ Z = (195, 195, 195) ...BPAA.PPA..... ................ } -# tile 311 (Orcus) +# tile 621 (Yeenoghu,female) +{ + ....B.HHP....... + ....BPPPP....... + ...BPLCPPH...... + .KBPPCCPPH...... + .PPPPPPP.H...... + .PP...P.PH...... + ....BPPPPPAAA... + ..BPPPPPPPPAAAA. + .BP.PPPPPAPPAAAA + .B...BPP.AAPAAAA + .B...BPP.AAPAAA. + .....BPPAAAAA.A. + ....BP.PPAA...A. + ...BP.AAPPA..A.. + ...BPAA.PPA..... + ................ +} +# tile 622 (Orcus,male) { ................ .K..O.....O..K.. @@ -5955,7 +11826,26 @@ Z = (195, 195, 195) ...OOPPAOOPPAGA. ................ } -# tile 312 (Geryon) +# tile 623 (Orcus,female) +{ + ................ + .K..O.....O..K.. + KJJO..BBB..O.KJ. + KJJLOBPPPPOLKJJ. + JKJJ.PGPGP.JJKJA + JJKJKPPPPPJJKJJJ + JBPPB.BPPABBPPJJ + PJJPP.BPPAPPJJPA + PJBPPP.AAPPPPJPA + .JBP.PPPP.P.PJAA + .JBPPPP.PPPPPJAA + ..PPP.PPP.PPPAAA + ...P.PPPPPPP.P.A + ...BPPPAPPPPAAPA + ...OOPPAOOPPAGA. + ................ +} +# tile 624 (Geryon,male) { .K...........K.. .K....JJJ....KJ. @@ -5974,7 +11864,26 @@ Z = (195, 195, 195) ....FGGGFFFFFFFA .....FFFFFFFFFA. } -# tile 313 (Dispater) +# tile 625 (Geryon,female) +{ + .K...........K.. + .K....JJJ....KJ. + KJJ..JJJJJ..KJJ. + KJJJKLLLLLKKJJJ. + KJJJKLBLBLKJJJJA + JJJJKLLLLLJJJJJA + JJALLKLLLJLLAJJA + JA.LLLKJJLLLAAJA + ...LJLLLLLKLAAAA + ...LCKLLLKCLAFGF + ...LLGLLFALLFFFA + .....GFFFAAAFFAA + ....GGGGFFAAFFAA + ....GFFFFFAAFGFA + ....FGGGFFFFFFFA + .....FFFFFFFFFA. +} +# tile 626 (Dispater,male) { ................ ......OJJO...... @@ -5993,7 +11902,26 @@ Z = (195, 195, 195) .....PPA.PPA.... ................ } -# tile 314 (Baalzebub) +# tile 627 (Dispater,female) +{ + ................ + ......OJJO...... + ......JJJJA..... + ......BLBLA..... + ......LLLLA..... + ......ALLA...... + .....CKAAKK.AAA. + ....CKKKKKKKAAA. + ....KACKKJAKAAA. + ....KACKKJAKAAJA + ....KACKKJAKAAJA + ....LACKKJJLAJA. + ......CKAJAJJA.. + ......CKAPAAAA.. + .....PPA.PPA.... + ................ +} +# tile 628 (Baalzebub,male) { ......F...F..... .......F.F...... @@ -6012,7 +11940,26 @@ Z = (195, 195, 195) .....FFA..FF.... ................ } -# tile 315 (Asmodeus) +# tile 629 (Baalzebub,female) +{ + ......F...F..... + .......F.F...... + ......BFFFB..... + .....BPPFBPP.... + .....PPPFPPP.... + ......PPFPP..... + .....CAFFFAK.... + ....CKKAFAKKKAA. + ....CAKJFAKAKAA. + ....FACJDAJAFAA. + ....FACKJJJAFAA. + ....FACKKKJAFAA. + ......CKKKJAAA.. + ......CKAKJA.A.. + .....FFA..FF.... + ................ +} +# tile 630 (Asmodeus,male) { ................ ......OJJO...... @@ -6031,7 +11978,26 @@ Z = (195, 195, 195) .....PPA.PPA.... ................ } -# tile 316 (Demogorgon) +# tile 631 (Asmodeus,female) +{ + ................ + ......OJJO...... + ......JJJJA..... + ......BLBLA..... + ......LLLLA..... + ......ALLA...... + .....CKAAKK.AAA. + ....CKKKKKKKAAA. + ...KKCKKKKJKKAA. + ...KKAKKKJAKKAJA + ...KA.CKKJAAKAJA + ...LA.CKKJJALJA. + ......CKAJAJJA.. + ......CKAPAAAA.. + .....PPA.PPA.... + ................ +} +# tile 632 (Demogorgon,male) { ...KKK..KKK..... ..KBKBK.BKBK.... @@ -6050,7 +12016,26 @@ Z = (195, 195, 195) ..GAGFAFFFAFA... ................ } -# tile 317 (Death) +# tile 633 (Demogorgon,female) +{ + ...KKK..KKK..... + ..KBKBK.BKBK.... + ..KDKKK.KKDK.... + ..DKKFA.GKKD.... + ....GFAAGFAAA... + ...GFFFJFFFA.AAA + ..GFAGFFFAFFAAAA + .GJFAGJFJAFFFAA. + .GFAAGFFFAAFJA.. + .GJA.GFJFAAFFAA. + .GFA.GFFFA.FJAA. + .GJA.GJFJA.FFAA. + .GFAGFAAFFAFFA.. + ..GAGJAAJFAFAA.. + ..GAGFAFFFAFA... + ................ +} +# tile 634 (Death,male) { .BBBB....JJJ.... .BPPPP.JJJJ..... @@ -6069,7 +12054,26 @@ Z = (195, 195, 195) .CJJAAAAAAAAJJA. ACJAAAAAAAAAAAJ. } -# tile 318 (Pestilence) +# tile 635 (Death,female) +{ + .BBBB....JJJ.... + .BPPPP.JJJJ..... + .C....JJJJJ..... + .C....JAAAJ..... + .C...JADADAJ.AAA + OOJ..JAAAAAJAAA. + OOOJJJAAAAAJJJA. + OOJJJJAAAAJOOJJA + .CJJJJAAAJOOOOJA + .C.JJAAAAJAOAAJA + .C..JAAAAJAOAAJA + .C..JAAAAAJOAJAA + .C..JAAAAAJJJAAA + .C.JAAAAAAAJJAA. + .CJJAAAAAAAAJJA. + ACJAAAAAAAAAAAJ. +} +# tile 636 (Pestilence,male) { F........JJJ.... ..F....JJJJ..... @@ -6088,7 +12092,26 @@ Z = (195, 195, 195) ..JJFBFAFFAJJJA. .JJAAFAFAAAAAAJ. } -# tile 319 (Famine) +# tile 637 (Pestilence,female) +{ + F........JJJ.... + ..F....JJJJ..... + B...F.JJJJJ..... + ...B..JAAAJ..... + .F...JADADAJ.... + ...F.JAAAAAJ.AA. + .B..JFAAAAFJAA.. + ...FJJAFABJJAA.. + ..F.JFFBAJJJAAA. + ....FAFFJJJJAAA. + ....JABAJJJJAAA. + ...FJFFJJJJJJAA. + ...JJBFJJJJJJAA. + ...JAABFBJJJJAA. + ..JJFBFAFFAJJJA. + .JJAAFAFAAAAAAJ. +} +# tile 638 (Famine,male) { .........JJJ.... .......JJJ...... @@ -6107,7 +12130,26 @@ Z = (195, 195, 195) K...JJAAAJJAA... K..JJAAAAAJJJA.. } -# tile 320 (mail daemon) +# tile 639 (Famine,female) +{ + .........JJJ.... + .......JJJ...... + K.....JJJJJ..... + K.....JAAAJ..... + K....JADADAJ.... + K....JAAAAAJ...A + K.....JAAAJJ..AA + OOJJJJJJAAJAJ.AA + K...JJJAAJJAJAAA + K.....JAJJJOJAA. + K.....JAOOOAAA.. + K.....JAJJAAA... + K.....JAJJAA.... + K.....JAAJAA.... + K...JJAAAJJAA... + K..JJAAAAAJJJA.. +} +# tile 640 (mail daemon,male) { ...OP.BEEE.PO... ...OOEBEEEEOOD.. @@ -6126,7 +12168,26 @@ Z = (195, 195, 195) ..CDDDAAA.DDDK.. ................ } -# tile 321 (djinni) +# tile 641 (mail daemon,female) +{ + ...OP.BEEE.PO... + ...OOEBEEEEOOD.. + ..DLOBEEEEOOLDD. + .DDDLDDDDDDLDDD. + .CCDDDNDDNDDDCC. + CCDKDDDDDDDDJCCC + CDDKKDDIIDDJJCCD + CDDK.KDAADJJECDD + CCDKEEKKKJEEKCDD + .CCDK.EEEE..CDDD + .CCDAE.EENNNCDD. + .DDDAEEEENDNDDD. + ....BBEEENNNNN.. + ...BEEEAANNNNNA. + ..CDDDAAA.DDDK.. + ................ +} +# tile 642 (djinni,male) { .LL..NNN..LL.... ..L..NGNA.L..... @@ -6145,7 +12206,26 @@ Z = (195, 195, 195) .........IFED... ................ } -# tile 322 (jellyfish) +# tile 643 (djinni,female) +{ + .LL..NNN..LL.... + ..L..NGNA.L..... + ..LAALLLAALA.... + ..LAAKKKAALA.... + ...LCKKKCLA..... + ....LCKCLA...... + ....LICLIA..A... + ....IIIIEA.AA..A + ....EIEEIA.AAAAA + ....IEFEAAAAAAAA + .....DEAIAAAAA.. + .....IGIFAAAA... + .......FEDAAA... + .......I.GEA.A.. + .........IFED... + ................ +} +# tile 644 (jellyfish,male) { ................ .....PBPA....... @@ -6164,7 +12244,26 @@ Z = (195, 195, 195) ..PEE.P.E..E.... .P..E.P..E...... } -# tile 323 (piranha) +# tile 645 (jellyfish,female) +{ + ................ + .....PBPA....... + ...PBBBPBA...... + ..BBNNBPPBAA.... + .BBNNPPPBBPAA... + PBBBPPPBPBBAAA.. + BBBPBPPPPPBPAAA. + BBPBPPPPPPPBAAA. + PBPPBPPPPEPEEE.. + .PBBPPPEPEPPEE.. + .PEPBBEEPEEPEE.. + .PEEEPEEPEEPE... + ..PEEPE..PE.P... + ..P.EP.EEP..P... + ..PEE.P.E..E.... + .P..E.P..E...... +} +# tile 646 (piranha,male) { ................ ................ @@ -6183,7 +12282,26 @@ Z = (195, 195, 195) .....E..P....... ....E..E...E.... } -# tile 324 (shark) +# tile 647 (piranha,female) +{ + ................ + ................ + ................ + ................ + ................ + ....OPP......... + .....OPP........ + ..O..PPAP.....E. + ..POPPPPPA...EEE + ..PPPPP.PPA.E... + ...PP..PPPAAAEE. + ..E.PPPPPPPPPE.. + ..E...PPPPPAA.E. + .....E..PPAE.... + .....E..P....... + ....E..E...E.... +} +# tile 648 (shark,male) { ................ ................ @@ -6202,7 +12320,26 @@ Z = (195, 195, 195) PDNPPEE..EE..... .PPPE..EEE..E... } -# tile 325 (giant eel) +# tile 649 (shark,female) +{ + ................ + ................ + ................ + ...............P + ........P.....PP + ....E..PP....PP. + ...E...PPA..PPP. + ..EEEEPPPA.PPPPP + .E.EEPPP.PPPPPPE + ...EP.P.PPPPPEEE + ..PPPPPPPPPPEEE. + .APPPPPPPPEEEE.E + PPPPPPP..EE..... + NDPPAPEPPP.E..EE + PDNPPEE..EE..... + .PPPE..EEE..E... +} +# tile 650 (giant eel,male) { ................ ................ @@ -6221,7 +12358,26 @@ Z = (195, 195, 195) ...EE.AAAAE.E... ..E...EE.E...E.. } -# tile 326 (electric eel) +# tile 651 (giant eel,female) +{ + ................ + ................ + ................ + ....AAA......... + ...AAOAA...AAA.. + ..AAAAAAA.AA.AA. + ..AAAA.AA.AA.AA. + ...AA..AA.AA..A. + ......AAA..AA.A. + ......AA...AA... + .....AAA.E.AA.E. + ...E.AAEE.AAAE.. + ...E.AAEEAAAEE.. + ..E..AAAAAAE.E.. + ...EE.AAAAE.E... + ..E...EE.E...E.. +} +# tile 652 (electric eel,male) { ................ ................ @@ -6240,7 +12396,26 @@ Z = (195, 195, 195) ...EE.AAADE.E... ..E...EE.E...E.. } -# tile 327 (kraken) +# tile 653 (electric eel,female) +{ + ................ + ................ + ................ + ....AAA......... + ...AAOAA........ + ..AAAAAAA....... + ..AAAA.AA....... + ...AA..AA...DD.. + ......AAA..DD... + ......AA...DD... + .....AAA.E.DD.E. + ...E.AAEE.DD.E.. + ...E.AAEEDD.EE.. + ..E..AAADDDE.E.. + ...EE.AAADE.E... + ..E...EE.E...E.. +} +# tile 654 (kraken,male) { ................ ................ @@ -6259,7 +12434,26 @@ Z = (195, 195, 195) EEEEEEE..EE..... ..EEE..EEE..E... } -# tile 328 (newt) +# tile 655 (kraken,female) +{ + ................ + ................ + ..FF..FF........ + ..DDFDDF........ + ..FFFFF.....GG.. + ..NCNFF......GFA + ..CC.FF.....EGFA + ....GFAA.GFAEGFE + ...GFFAGFFFFAGFE + ...GFAAFFAGFAEEE + ..GFFAGFFAGFEEE. + EEGFFAGFFAEEEE.E + .EGFFAGFFEE..... + EEGFFEEEEE.E..EE + EEEEEEE..EE..... + ..EEE..EEE..E... +} +# tile 656 (newt,male) { ................ ................ @@ -6278,7 +12472,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 329 (gecko) +# tile 657 (newt,female) +{ + ................ + ................ + ................ + ................ + ................ + ......JKKJ...... + .....CLCCLLC.... + ....LAAAACCLCA.. + .......LCCLLLCA. + ....LCCCLLLAALA. + ....CALLLLAAAA.. + ...LLLLCLAAA.... + ...LLAAALLA..... + ................ + ................ + ................ +} +# tile 658 (gecko,male) { ................ ................ @@ -6297,7 +12510,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 330 (iguana) +# tile 659 (gecko,female) +{ + ................ + ................ + ...........LLP.. + ..........LLOOA. + ......PO.LLOOOA. + ......OOALOOOA.. + .......LLOOOA... + ...POALOOOAA.... + ...OOLOOOOOOA... + ....ALOOOAOPA... + ...DOOOOA.AA.... + ...OOOAOOA...... + ...OODAOPA...... + ..F.AA.AA....... + ................ + ................ +} +# tile 660 (iguana,male) { ................ ................ @@ -6316,7 +12548,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 331 (baby crocodile) +# tile 661 (iguana,female) +{ + ................ + ................ + ................ + ................ + ................ + ....GPGPGGPF.... + ..GPAAAAFFGPF... + .GPAA.PFFGPPPAA. + ......FGGPPFPPAA + .PFGGGGPPPFAAPPA + .FGPAPPPPFAAAAA. + .GPPPPFPFAAA.A.. + .PPFFAFPPAA..... + D.AAAAAAPPA..... + ................ + ................ +} +# tile 662 (baby crocodile,male) { ................ ................ @@ -6335,7 +12586,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 332 (lizard) +# tile 663 (baby crocodile,female) +{ + ................ + ................ + ................ + ................ + ................ + .....FFOFOFA.... + ....FOGFGGOFF... + ....GAAAAFOGFA.. + ...FAA.GFOGGGFA. + ...GFOOOGGGFAGA. + ...FGAGGGGFAAA.. + ..FGGGGFGFAA.... + ..GGDFAFGGA..... + ...D............ + ................ + ................ +} +# tile 664 (lizard,male) { ................ ................ @@ -6354,7 +12624,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 333 (chameleon) +# tile 665 (lizard,female) +{ + ................ + ................ + ................ + ................ + ................ + ................ + ....FFFFGFJ..... + ..FFAAAJJGFJ.... + ......JGFFJFAA.. + ...JGGGFFJAAFA.. + ..JFAFFFJAAAA... + ..FFFFJJAAA..... + .JFAAAAFAA...... + .D.............. + ................ + ................ +} +# tile 666 (chameleon,male) { ................ ................ @@ -6373,7 +12662,26 @@ Z = (195, 195, 195) .DD............. ................ } -# tile 334 (crocodile) +# tile 667 (chameleon,female) +{ + ................ + ................ + ................ + .....GGGG....... + ...GGGGGGGG..... + ...GGFFFFGGFA... + ..GPAAAGFFGGFA.. + .GPAA.PFFGGGGAA. + ...GGGGGGGGFGGAA + .PGGBBGGGGFAAGGA + .FGGABGGGFAAAAA. + .GGGGGFGFAAA.A.. + .DGFFAFGGAA..... + D.AAAAAAGGA..... + .DD............. + ................ +} +# tile 668 (crocodile,male) { ................ ................ @@ -6392,7 +12700,26 @@ Z = (195, 195, 195) .DF............. ................ } -# tile 335 (salamander) +# tile 669 (crocodile,female) +{ + ................ + ................ + ................ + ................ + ....FFOFOOFA.... + ...FOGFGFGOFFA.. + ..FGAAAAFFOGFFA. + .FFAA.GFFOGGGGFA + ......FOOGGGGGGA + .G.OOOOGGGGFAGGA + .FOGAGGGGGFAAAA. + FGGGGGFGGFAA.... + GGDDFAFGGGA..... + GDDFAAAAGGA..... + .DF............. + ................ +} +# tile 670 (salamander,male) { ................ ................ @@ -6411,7 +12738,26 @@ Z = (195, 195, 195) ..ACCA.......... ...AAA.......... } -# tile 336 (long worm tail) +# tile 671 (salamander,female) +{ + ................ + ................ + ................ + ......CCC....... + ....CCCCCCC..... + ...CCDDDDCCDA... + ....AAAADDCCDA.. + ......KDDCCCCAA. + ..LLLCCCCCCDCCAA + .KLCCCLLLCDAACCA + .DCEECLKKDAAAAA. + DCCAECDKDAAA.A.. + CCCCCCDCCAA..... + .DAADAAACCA..... + ..ACCA.......... + ...AAA.......... +} +# tile 672 (long worm tail,male) { ........ILLLL... ......IILLAA.... @@ -6430,7 +12776,26 @@ Z = (195, 195, 195) .LLLIIIILLLA.... ...LLLLLAAA..... } -# tile 337 (archeologist) +# tile 673 (long worm tail,female) +{ + ........ILLLL... + ......IILLAA.... + .....ILLAA...... + .....ILA........ + .....ILA........ + ......LLA...II.. + .......LLIIILLLL + ........ILLAAA.L + ...IIIILLALL.... + .ILLLLLAA..LL... + ILLAAAA.....LA.. + ILA.........LA.. + LLA........LLA.. + LILA......LLA... + .LLLIIIILLLA.... + ...LLLLLAAA..... +} +# tile 674 (archeologist,male) { ................ ................ @@ -6449,7 +12814,26 @@ Z = (195, 195, 195) .....CJJ.JKJ.... ................ } -# tile 338 (barbarian) +# tile 675 (archeologist,female) +{ + ................ + ................ + ................ + ......KJJJ...... + ......KKLJ...... + .....KLELE...... + ....KJLLLL...... + ....JJALLA...... + ...JJLBAAPL.AAA. + ...JLLBBBPLLAAA. + ....LABPPPALAAA. + ....LALLLLALAAA. + .....AOJJOAAAA.. + .....KCJAJJA.A.. + .....CJJ.JKJ.... + ................ +} +# tile 676 (barbarian,male) { ................ ................ @@ -6468,7 +12852,26 @@ Z = (195, 195, 195) .....LLA.LLA.... ................ } -# tile 339 (caveman) +# tile 677 (barbarian,female) +{ + ................ + ................ + .......HHA...... + ......HHHHA..... + ......LFLFA..... + ......LLLLA..... + ......ALLA...... + .....LLAALL.AAA. + ....LLLLLLLLAAA. + ....LALLLLALAAA. + ....LAALLAALAAA. + ....LAJJKJALAAA. + ......LJJLAAAA.. + ......LLALAA.A.. + .....LLA.LLA.... + ................ +} +# tile 678 (cave dweller,male) { ................ ................ @@ -6487,7 +12890,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 340 (cavewoman) +# tile 679 (cave dweller,female) { ................ ................ @@ -6506,7 +12909,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 341 (healer) +# tile 680 (healer,male) { ................ .......NN....... @@ -6525,7 +12928,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 342 (knight) +# tile 681 (healer,female) +{ + ................ + .......NN....... + ......NDDO...... + ......NNNN...... + ......ELEP...... + ......LLLP...... + .......LLP...... + ......O..PA.AAA. + .....NNOOPPAAAA. + ....OOONOPPPAA.. + ....LANOOPALAA.. + ......NOOPAAAA.. + .....NOOOPAA.A.. + ....NOOOOOPA.... + ................ + ................ +} +# tile 682 (knight,male) { ................ ................ @@ -6544,7 +12966,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 343 (monk) +# tile 683 (knight,female) +{ + ................ + ................ + .......BPA...... + ......BPPPA..... + ......PEEPA..... + ......PLLPA..... + ......ALLAA..... + .....BBAABB.AAA. + ....BPPPPPPPAAA. + ....PABPPPAPAAA. + ....LA.PP.ALAAA. + ......BP.PAAAA.. + ......BPAPAA.A.. + .....PPA.PPA.... + ................ + ................ +} +# tile 684 (monk,male) { ................ ................ @@ -6563,7 +13004,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 344 (priest) +# tile 685 (monk,female) +{ + ................ + ................ + .......CCC...... + ......JCJJJA.... + ......CAAAJA.... + ......CAAAJA.... + ......CKLKCAAAA. + .....CDDDDDDAAAA + ....CDDLALDDDAAA + ....DALLALLADAA. + ....DDDDCDDDDAA. + .....AACCCDAAAA. + .....CDCCCDDA.A. + ....CCCCCCCDD... + ................ + ................ +} +# tile 686 (cleric,male) { ................ ................ @@ -6573,16 +13033,16 @@ Z = (195, 195, 195) ......ALLJA..... ......IJJIAAAA.. .....ODDDDDAAAA. - ....IDNDDDDDAAA. - ...NLNNNDDALAA.. - ......NDDDAAAA.. + ....INNDDDDDAAA. + ...NLNNDDDALAA.. + ......DDDDAAAA.. ......DIIDAAAA.. .....DDIIDDA.A.. ....DIIIIIDD.... ................ ................ } -# tile 345 (priestess) +# tile 687 (cleric,female) { ................ .......JJ....... @@ -6592,16 +13052,16 @@ Z = (195, 195, 195) .....JJLLJJ..... .....JEJJEJAAA.. .....ODEEDDAAAA. - ....IDINDDDDAAA. - ....L.NNNDALAA.. - ......INDDAAAA.. - ......INDDAAAA.. + ....IDINNDDDAAA. + ....L.DNNDALAA.. + ......IDDDAAAA.. + ......IDDDAAAA.. .....DDIIDDA.A.. ....DIIIIIDD.... ................ ................ } -# tile 346 (ranger) +# tile 688 (ranger,male) { ................ ................ @@ -6620,7 +13080,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 347 (rogue) +# tile 689 (ranger,female) +{ + ................ + ................ + ........CJA..... + .......CJJJA.... + .......JEEJA.... + .......JLLJA.... + .......ALLAA.... + ......GGAAGG.AAA + .....BPFFFFPPAAA + .....PAGFFFAPAAA + .....LA.FF.ALAAA + .......BP.PAAAA. + .......BPAPAA.A. + ......PPA.PPA... + ................ + ................ +} +# tile 690 (rogue,male) { ................ ................ @@ -6639,7 +13118,26 @@ Z = (195, 195, 195) .....KKA.KKA.... ................ } -# tile 348 (samurai) +# tile 691 (rogue,female) +{ + ................ + ................ + ................ + .....OA...OA.... + .....OOIDPPA.... + ......IDDDA..... + ......LKLKA..... + ......LLLLA..... + ......ALLA...... + ......BAABAA..A. + .....KEBBEJAAAA. + ....KAAEEAAKAA.. + ....LAJJHJALAA.. + ......KKJKAAAA.. + .....KKA.KKA.... + ................ +} +# tile 692 (samurai,male) { ................ ................ @@ -6658,7 +13156,26 @@ Z = (195, 195, 195) .....IIA.IIA.... ................ } -# tile 349 (tourist) +# tile 693 (samurai,female) +{ + ................ + ................ + .........AA..... + .......AAA...... + ......AAAAA..... + .....ALFLFA..... + .....ALLLLA..... + ......ALLA...... + ....IIIAAIIIAAA. + ....LDIIIIDLAAA. + ....LABBBBALAAA. + ....LABBBBALAAA. + ......IDDDAAAA.. + ......IDADAA.A.. + .....IIA.IIA.... + ................ +} +# tile 694 (tourist,male) { ................ ................ @@ -6677,7 +13194,45 @@ Z = (195, 195, 195) .....LLA.LLA.... ................ } -# tile 350 (valkyrie) +# tile 695 (tourist,female) +{ + ................ + ................ + ......JKJJA..... + ......KJJJA..... + ...JJJJJJJJJJ... + ......LFLFAA.... + ......LLLLA..... + ......ALLA...... + .....HGAAGH.AAA. + ....LLGHHGLLAAA. + ....LAHGHGALAAA. + ....LAHHGHALAAA. + ......JJJKAAAA.. + ......LLALAA.A.. + .....LLA.LLA.... + ................ +} +# tile 696 (valkyrie,male) +{ + D..............D + .D............D. + ..D...LHHL...D.. + ...D.HHHHHL.D... + ....DHELELHD.... + ....HDLLLLD..... + ...HHHDLLD...... + ...HJKJDDKJJAAA. + ..HHLJJDDJJLAAA. + ..H.LADKDCALAAA. + ....LDAKKDALAAA. + ....D.KKJKDAAA.. + ...D..KJAJAD.A.. + ..D..KLA.LKAD... + .D...........D.. + D.............D. +} +# tile 697 (valkyrie,female) { ................ ................ @@ -6696,7 +13251,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 351 (wizard) +# tile 698 (wizard,male) { ................ .........BP..... @@ -6715,7 +13270,26 @@ Z = (195, 195, 195) ....BPPPPPPE.... ................ } -# tile 352 (Lord Carnarvon) +# tile 699 (wizard,female) +{ + ................ + .........BP..... + .......BBPE..... + ......BPPEA..... + ......BAAEA..... + ......BAAEA..... + ......PLLE...... + ......PAAEA.AAA. + .....BBPBEEAAAA. + ....PPPBEEEEAA.. + ....LABPPEALAA.. + ......BPPEAAAA.. + .....BPPPEAA.A.. + .....BPPPPEA.... + ....BPPPPPPE.... + ................ +} +# tile 700 (Lord Carnarvon,male) { .......JJ....... ......KJJJ...... @@ -6734,7 +13308,26 @@ Z = (195, 195, 195) .....PPA.PPA.... ................ } -# tile 353 (Pelias) +# tile 701 (Lord Carnarvon,female) +{ + .......JJ....... + ......KJJJ...... + ....KCKKKJJJ.... + ......LELEA..... + ......LLLLA..... + ......ALLA...... + .....CIAAIK.AAA. + ....CKKIIKKKAAA. + ...KKCKKHKJKKAA. + ...KKAKHKJAKKAA. + ...KAIHKKJIAKA.. + ...LAICKKJIALA.. + .....ICKAJIAAA.. + ......CKAPAAAA.. + .....PPA.PPA.... + ................ +} +# tile 702 (Pelias,male) { ................ .......JJ....... @@ -6753,7 +13346,26 @@ Z = (195, 195, 195) .....PPA.PPA.... ................ } -# tile 354 (Shaman Karnov) +# tile 703 (Pelias,female) +{ + ................ + .......JJ....... + ......KKKJ...... + ......LELEA..... + ......LLLLA..... + ......ALLA...... + .....CKAAKK.AAA. + ....CKKKKKKKAAA. + ...KKCKKKKJKKAA. + ...KKAKKKKAKKAA. + ...KA.CKKJAAKA.. + ...LA.CKAJAALA.. + ......CKAJAAAA.. + ......CKAPAAAA.. + .....PPA.PPA.... + ................ +} +# tile 704 (Shaman Karnov,male) { ................ .......JJA...... @@ -6772,7 +13384,26 @@ Z = (195, 195, 195) .....LLA.LLA.... ................ } -# tile 355 (Earendil) +# tile 705 (Shaman Karnov,female) +{ + ................ + .......JJA...... + ......JJJJA..... + .....JFLFLJ..... + .....JLLLLJ..... + .....JJDDJA..... + ....LHAJJAHLAA.. + ...LLLHAAHLLLAA. + ...LLLLHHLLLLAA. + ...LLALHHLALLAA. + ...LLALLLLALLAA. + ....LACKKJALAAA. + ......CKKJAAAA.. + ......LA.LAA.A.. + .....LLA.LLA.... + ................ +} +# tile 706 (Earendil,male) { .........G...... ....B..GGF..B... @@ -6791,7 +13422,26 @@ Z = (195, 195, 195) .....AAAAAA..... ................ } -# tile 356 (Elwing) +# tile 707 (Earendil,female) +{ + .........G...... + ....B..GGF..B... + ...BB.GGGGABB... + ..BPBPLELEABPB.. + ..BBBPLLLLABBB.. + ..PBPPALLAPPP... + ...PPBGAAGBBB... + ...BBLGGGFLBBB.. + ..BBLAAGFAALBB.. + ...BLAGGGFALB... + ......GFAF...... + ......L..L.AAA.. + ......AAAAAAAA.. + ....AAAAAAAA.... + .....AAAAAA..... + ................ +} +# tile 708 (Elwing,male) { .........G...... ....B..GGF..B... @@ -6810,7 +13460,26 @@ Z = (195, 195, 195) .....AAAAAA..... ................ } -# tile 357 (Hippocrates) +# tile 709 (Elwing,female) +{ + .........G...... + ....B..GGF..B... + ...BB.GGGGABB... + ..BPBHLELEHBPB.. + ..BBBHLLLLHBBB.. + ..PBHHALLAHHP... + ...PHHGAAGHHB... + ...BBLGGGFLBBB.. + ..BBLAAGFAALBB.. + ...BLAGGGFALB... + ......GFAF...... + ......L..L.AAA.. + ......AAAAAAAA.. + ....AAAAAAAA.... + .....AAAAAA..... + ................ +} +# tile 710 (Hippocrates,male) { ................ ....LLLCCD...... @@ -6829,7 +13498,26 @@ Z = (195, 195, 195) .LCCCCCCCDA..... ................ } -# tile 358 (King Arthur) +# tile 711 (Hippocrates,female) +{ + ................ + ....LLLCCD...... + ...LLCCDDA...... + ...LAAAADA...... + ...LBABADA...... + ...LAAAADA...... + ...CCLLDD.B..... + ....CKKDDFBFAAA. + ..LLLCLDDDBFAAA. + .CCCCLDDDFBAAA.. + .LALLCCDDFBDAA.. + ...LCCCCDABFAA.. + ...LCCCCDABAAA.. + ..LLCCCCDAA.AA.. + .LCCCCCCCDA..... + ................ +} +# tile 712 (King Arthur,male) { ................ ................ @@ -6848,7 +13536,26 @@ Z = (195, 195, 195) ....PPAA.PPA.... ................ } -# tile 359 (Grand Master) +# tile 713 (King Arthur,female) +{ + ................ + ................ + ......OHHA...... + .....OHHHHA..... + .....HBLBHA..... + .....HLLLHA..... + .....ALLLAA..... + ....BBAAABB.AAA. + ...BPPPPPPPPAAA. + ...PABPPPPACPAA. + ..NNNNNNNNNCLCA. + .....BPP.PACAA.. + .....BPAPPAA.A.. + .....BPAPPAA.A.. + ....PPAA.PPA.... + ................ +} +# tile 714 (Grand Master,male) { ................ .......LL....... @@ -6867,7 +13574,26 @@ Z = (195, 195, 195) ..JACCCCCCCCAA.. ................ } -# tile 360 (Arch Priest) +# tile 715 (Grand Master,female) +{ + ................ + .......LL....... + ......LLLL...... + ......LLLL...... + ..LC.CALLAC..... + .CLLC.CAACCCC... + .CJLACCCCCCCCC.. + ..JAACCCCCCCCCC. + ..JCCCCCCCCCCC.A + ..J..PPPPPLCCAAA + ..J..CCCCLLCAAAA + ..J..CCCCCCCAAAA + ..J..CCCCCCCAAAA + ..J.ACCCCCCCAAA. + ..JACCCCCCCCAA.. + ................ +} +# tile 716 (Arch Priest,male) { ..N............. .NNN..JLLJ...... @@ -6886,7 +13612,26 @@ Z = (195, 195, 195) ..HACCCJJCCCAA.. ................ } -# tile 361 (Orion) +# tile 717 (Arch Priest,female) +{ + ..N............. + .NNN..JLLJ...... + ..N...JLLJ...... + ..N...LLLL...... + ..LC.CALLAC..... + .CLLC.CAACJDK... + .CHLACCCCJCCDK.. + ..HAACCJJCCCCDK. + ..HCCCCJCCJCCC.A + ..H..DCJCCLJCAAA + ..H..DCJCLLCAAAA + ..H..KCJCCDJAAAA + ..H..KCJCCDJAAAA + ..H.ACCJCCDJAAA. + ..HACCCJJCCCAA.. + ................ +} +# tile 718 (Orion,male) { ................ ................ @@ -6905,7 +13650,26 @@ Z = (195, 195, 195) ......BPAPAA.A.. .....PPA.PPA.... } -# tile 362 (Master of Thieves) +# tile 719 (Orion,female) +{ + ................ + ................ + .......CJA...... + ......CJJJA..... + ......JEEJA..... + ......JLLJA..... + ......ALLAA..... + .....GGAAGG..... + ....BGFFFFFP.... + ....BPFFFFPPAAA. + ....PAGFFFAPAAA. + ....LANNNNALAAA. + ......BP.PAAAAA. + ......BP.PAAAA.. + ......BPAPAA.A.. + .....PPA.PPA.... +} +# tile 720 (Master of Thieves,male) { ................ ...H.....H...... @@ -6924,7 +13688,26 @@ Z = (195, 195, 195) ...JJA..JJA..... ................ } -# tile 363 (Lord Sato) +# tile 721 (Master of Thieves,female) +{ + ................ + ...H.....H...... + ...HHIDKHH...... + ....IDDDD....... + ....LLLLLA...... + ....LBLBLA...... + ....LLLLLA...... + .....LLLA....... + ....B.AABAA..... + ...KEBBBEJAAA... + ..KAEEEEEAJAAA.. + ..LAJJHHJALAAA.. + ....JKKKJAAAAA.. + ....KJAJKAAAA... + ...JJA..JJA..... + ................ +} +# tile 722 (Lord Sato,male) { .....AAA........ .....AAA........ @@ -6943,7 +13726,26 @@ Z = (195, 195, 195) ..IIIA.IIIAA.... ................ } -# tile 364 (Twoflower) +# tile 723 (Lord Sato,female) +{ + .....AAA........ + .....AAA........ + ...AAAAAAA...... + ..AALLLLLAA..... + ..ALFFLFFLA..... + ..ALLLLLLLA..... + ...AALLLA....... + IIIIIAAAIIIIAAA. + LLDIIIIIIDLLAAA. + LLABBBBBBALLAAA. + LLABBBBBBALLAAA. + LLABBBBBBALLAAA. + ...IIDDDDAAAAAA. + ...IIAAIDAAA..A. + ..IIIA.IIIAA.... + ................ +} +# tile 724 (Twoflower,male) { ................ ................ @@ -6962,7 +13764,26 @@ Z = (195, 195, 195) .....LLA.LLA.... ................ } -# tile 365 (Norn) +# tile 725 (Twoflower,female) +{ + ................ + ................ + ......JKJJA..... + ......KJJJA..... + ....JJJJJJJJ.... + .....NNLNNA..... + ....NALNALNA.... + .....NNANNAA.... + .....AAAAAA.AAA. + ....LLHGHGLLAAA. + ....LAGGGGALAAA. + ....LAHGHGALAAA. + ......JJJKAAAA.. + ......JJAKAA.A.. + .....LLA.LLA.... + ................ +} +# tile 726 (Norn,male) { ................ ................ @@ -6981,7 +13802,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 366 (Neferet the Green) +# tile 727 (Norn,female) +{ + ................ + ................ + ......NNN....... + .....NNNNN...... + .....NELELN..... + ....NNLLLLN..... + ...NNNALLA...... + ...NJKJAAKJJAAA. + ..NNLJJKKJJLAAA. + ..N.LACKJCALAAA. + ....LAKKKKALAAA. + ......KKJKAAAA.. + ......KJAJAA.A.. + .....KLA.LKA.... + ................ + ................ +} +# tile 728 (Neferet the Green,male) { ................ ................ @@ -7000,7 +13840,26 @@ Z = (195, 195, 195) ...BPPPPPPPE.... ................ } -# tile 367 (Minion of Huhetotl) +# tile 729 (Neferet the Green,female) +{ + ................ + ................ + ......GGG....... + .....GFFFG...... + ....GFEFEG...... + ....GFFFFEG..... + .N.GPEFFFEE..... + .I..BBEAAEA.AA.. + .I.BBPPBBEEAAAA. + .IGBPPPPPEEEAA.. + .I.PP.EPEAAGAA.. + .I...BPPPAAAAA.. + .N...BPPPEAA.A.. + ....BPPPPPEA.... + ...BPPPPPPPE.... + ................ +} +# tile 730 (Minion of Huhetotl,male) { ...OP......PO... ...OODDDDDDOOD.. @@ -7019,7 +13878,26 @@ Z = (195, 195, 195) ..CDDDAAA.DDDK.. ................ } -# tile 368 (Thoth Amon) +# tile 731 (Minion of Huhetotl,female) +{ + ...OP......PO... + ...OODDDDDDOOD.. + ..DLOOCDDCOOLDD. + .DDDLDDDDDDLDDD. + .CCDDDNDDNDDDCC. + CCDKDDDDDDDDJCCC + CDDKKDDIIDDJJCCD + CDDKKKDAADJJDCDD + CCDKDDKKKJDDKCDD + .CCDKKDDDDKKCDDD + .CCDADKDDKDACDD. + .DDDADDDDDDADDD. + ....CCDDDDKKAA.. + ...CDDDAADDDKAA. + ..CDDDAAA.DDDK.. + ................ +} +# tile 732 (Thoth Amon,male) { ................ ......OJJO...... @@ -7038,7 +13916,26 @@ Z = (195, 195, 195) .....PPA.PPA.... ................ } -# tile 369 (Chromatic Dragon) +# tile 733 (Thoth Amon,female) +{ + ................ + ......OJJO...... + ......JJJJA..... + ......BLBLA..... + ......LLLLA..... + ......ALLA...... + .....BPAAPP.AAA. + ....BPPPPPPPAAA. + ...PPBPPPPJPPAA. + ...PPAPPP.APPA.A + ...PA.BPP.AAPA.A + ...LA.BPP..AL.A. + ......BPA.A..A.. + ......BPAPAAAA.. + .....PPA.PPA.... + ................ +} +# tile 734 (Chromatic Dragon,male) { ......GGGFA..... .....NFNFEEA.... @@ -7057,7 +13954,26 @@ Z = (195, 195, 195) ....GFAA...CCJA. ........FFFFJA.. } -# tile 370 (Goblin King) +# tile 735 (Chromatic Dragon,female) +{ + ......GGGFA..... + .....NFNFEEA.... + ....GFFFEECA.... + ..DCHHF..CCA.... + CHCHCD..BCCA.... + HD.D...BFFA..... + ......OBFAAAAAA. + ....HOGFAAAAAAAA + ..HOOIEA.EF.AAA. + .HOOOIEEEEFFJAA. + .HOOOIEEFFFDDAA. + HBOOIIEFFFDDCCA. + HB.OIEFOODD.CJA. + HBAAGE.AADDACCA. + ....GFAA...CCJA. + ........FFFFJA.. +} +# tile 736 (Goblin King,male) { ................ ................ @@ -7076,7 +13992,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 371 (Cyclops) +# tile 737 (Goblin King,female) +{ + ................ + ................ + .H..H...H....... + CLC.HCHCH....... + CLC.HHHHH....... + .H..IIIII....... + .HK.IHIHI.I..... + .HICKIIIJKK..... + .H.IIJJJK.AA.... + .H..JICJJAAAAA.. + .H..IIIIJAAAAA.. + ....JIIJJAA..... + ....IJKJJA...... + ...IKAA.IK...... + ................ + ................ +} +# tile 738 (Cyclops,male) { ................ ....LLLLL....... @@ -7095,7 +14030,26 @@ Z = (195, 195, 195) ....CJJJCLAAAAAA ..LLLLL.LLLLLAA. } -# tile 372 (Ixoth) +# tile 739 (Cyclops,female) +{ + ................ + ....LLLLL....... + ...CLLLLLC...... + ...LBABNNL...... + ...LBBBNNLJA.... + ...CLNNNLCJA.... + ....LLLLLJAAA... + ....LAALLAAAA... + ..JKJLLLKAKJAA.A + .CLKAJJJJAKLCAAA + .LLJKAAAAKJLLAA. + .LAAJKKKKJAALAA. + .LC.GGGHGGACLAAA + .LL.JJJJJJALLAAA + ....CJJJCLAAAAAA + ..LLLLL.LLLLLAA. +} +# tile 740 (Ixoth,male) { ....O......O.... ....O......O.... @@ -7114,7 +14068,26 @@ Z = (195, 195, 195) ..CDDDAAA.DDDK.. ................ } -# tile 373 (Master Kaen) +# tile 741 (Ixoth,female) +{ + ....O......O.... + ....O......O.... + ...LOOCDDCOOL... + ...DDDDDDDDDDD.. + .CCDDDGDDGDDDCC. + CCDKDDDDDDDDJCCC + CDDKKKDIIDJJDCCD + CDDKDDKJJJDDDCDD + CCDKDDDDDDDDKCDD + .CCDKKDDDDKKCDDD + .CCDADKDDKDACDD. + .DDDADDDDDDADDD. + ....CCDDDDKKAA.. + ...CDDDAADDDKAA. + ..CDDDAAA.DDDK.. + ................ +} +# tile 742 (Master Kaen,male) { ................ .......KKA...... @@ -7133,7 +14106,26 @@ Z = (195, 195, 195) ...KJJJJJJJJJA.. ................ } -# tile 374 (Nalzok) +# tile 743 (Master Kaen,female) +{ + ................ + .......KKA...... + ......KJJKA..... + ..KKA.KAAKA.KKA. + .KAAKAKDDKAKAAKA + .KOOJKKOOKKKOOJA + .KJJJJJJJJJKJJJA + ..KJJJJJJJJJJJA. + ....KJJJJJJJA... + ......KJJJAAAAAA + .....KJJJJKAAAAA + .....KJJJJJAAAAA + ....KJJJJJJKAAA. + ...KJJJJJJJJKAA. + ...KJJJJJJJJJA.. + ................ +} +# tile 744 (Nalzok,male) { ....O......O.... ....O......O.... @@ -7152,7 +14144,26 @@ Z = (195, 195, 195) ..CDDDAAA.DDDK.. ................ } -# tile 375 (Scorpius) +# tile 745 (Nalzok,female) +{ + ....O......O.... + ....O......O.... + ...LOOCDDCOOL... + ...DDDDDDDDDDD.. + .CCDDDBDDBDDDCC. + CCDKDDDDDDDDJCCC + CDDKKKDIIDJJDCCD + CDDKDDKJJJDDDCDD + CCDKDDDDDDDDKCDD + .CCDKKDDDDKKCDDD + .CCDADKDDKDACDD. + .DDDADDDDDDADDD. + ....CCDDDDKKAA.. + ...CDDDAADDDKAA. + ..CDDDAAA.DDDK.. + ................ +} +# tile 746 (Scorpius,male) { .....JLJLJAA.... ....JA.JCJCKAA.. @@ -7171,7 +14182,26 @@ Z = (195, 195, 195) ...D...JAAJA.JJ. ........JA.JA... } -# tile 376 (Master Assassin) +# tile 747 (Scorpius,female) +{ + .....JLJLJAA.... + ....JA.JCJCKAA.. + ....AJ.....JJJA. + ....LA......LCKA + .JAKJA......JJJA + ..JJA......ALCJA + .......ALLAJCJKA + ....JJALCCAAJJA. + .JJALLAJCJJJAA.. + JA.LCCAJAJJAAAA. + ..JACJJJAAACCJAA + GGJJJJJAACCAAAJA + .JJGGAJACAAJJAAA + D.JJAAJAACA.JAA. + ...D...JAAJA.JJ. + ........JA.JA... +} +# tile 748 (Master Assassin,male) { ................ ................ @@ -7190,7 +14220,26 @@ Z = (195, 195, 195) .....AAA.AAA.... ................ } -# tile 377 (Ashikaga Takauji) +# tile 749 (Master Assassin,female) +{ + ................ + ................ + ................ + .......AA....... + ......AAAA...... + .....ABLBLA..... + .....AAAAAA..... + ......AAAA...... + .....AAAAAA..PP. + ....AAAAAAAAPPP. + ....AAAAAAAAPPP. + ....LAAAAAALPPP. + ......AAAAAPPP.. + ......AAAAAP.P.. + .....AAA.AAA.... + ................ +} +# tile 750 (Ashikaga Takauji,male) { ................ ................ @@ -7209,7 +14258,26 @@ Z = (195, 195, 195) .....IIA.IIA.... ................ } -# tile 378 (Lord Surtur) +# tile 751 (Ashikaga Takauji,female) +{ + ................ + ................ + ......AA........ + .......AAA...... + ......AAAAA..... + .....ALFLFA..... + .....ALLLLA..... + ......ALLA...... + ....IIIAAIIIAAA. + ....LDIIIIDLAAA. + ....LAIIIIALAAA. + ....LALHHLALAAA. + ......IIIIAAAA.. + ......IIAIAA.A.. + .....IIA.IIA.... + ................ +} +# tile 752 (Lord Surtur,male) { ....PPDDDDAA.... ....PDDDDDDDA... @@ -7228,7 +14296,26 @@ Z = (195, 195, 195) .....BPPABPPAAAA ...LLLLJ.BLLLKAA } -# tile 379 (Dark One) +# tile 753 (Lord Surtur,female) +{ + ....PPDDDDAA.... + ....PDDDDDDDA... + ...PPDLLLLDDA... + ...PDPFLLFFDA... + ...PPPLLLLLDA... + ....PLLAALLAAA.. + ...PPALLLLBAAAA. + ...PPDBBBBBBBAA. + ..BDDHDPBPPPPPA. + ..PPHDDPBPPPPPA. + ..LAHDHPBPPAALAA + JLAADDHBBBBAALAA + JJLJDHHPBPPPCLAA + ..LLJBPPABPPLLAA + .....BPPABPPAAAA + ...LLLLJ.BLLLKAA +} +# tile 754 (Dark One,male) { ................ ......AAA....... @@ -7247,7 +14334,26 @@ Z = (195, 195, 195) AAAAAAAAAAAAAAAA ................ } -# tile 380 (student) +# tile 755 (Dark One,female) +{ + ................ + ......AAA....... + .....AAAAA...... + .....ADADA...... + .....AAAAA...... + ....AAAAAAA..... + ....AAAAAAA..... + ...AAAAAAAAA.... + ...AAAAAAAAA.... + ..AAAAAAAAAAA... + ..AAAAAAAAAAA... + ...AAAAAAAAA.... + ...AAAAAAAAAA... + ..AAAAAAAAAAAA.. + AAAAAAAAAAAAAAAA + ................ +} +# tile 756 (student,male) { ................ ................ @@ -7266,7 +14372,26 @@ Z = (195, 195, 195) .....CJJ.JKJ.... ................ } -# tile 381 (chieftain) +# tile 757 (student,female) +{ + ................ + ................ + .....GGFGG...... + .......G........ + ......NDND...... + ...DDDDDDDD..... + ......LELEA..... + ......LLLLA..... + ......ALLA...... + .....CKAAKJ.AAA. + ....CKKKJJJJAAA. + ....KACKJJAJAAA. + ....LACJKJALAAA. + .....KCJAJJA.A.. + .....CJJ.JKJ.... + ................ +} +# tile 758 (chieftain,male) { ................ ................ @@ -7285,7 +14410,26 @@ Z = (195, 195, 195) .....LLA.LLA.... ................ } -# tile 382 (neanderthal) +# tile 759 (chieftain,female) +{ + ................ + ................ + .......HHA...... + ......HHHHA..... + ......LFLFA..... + ......LLLLA..... + .....HALLAH..... + ....LLHAAHLLAAA. + ....LLLIILLLAAA. + ....LALIILALAAA. + ....LAALLAALAAA. + ....LAJJKJALAAA. + ......LJJLAAAA.. + ......LLALAA.A.. + .....LLA.LLA.... + ................ +} +# tile 760 (neanderthal,male) { ................ ................ @@ -7304,7 +14448,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 383 (High-elf) +# tile 761 (neanderthal,female) +{ + ................ + ................ + ................ + ......JJJJ...... + .....JJJJJJ..... + .....JFLFLJ..... + .....JLLLLJ..... + .....JJDDJA..... + ....JJAJJAJJ.AA. + ...JLLJAAJLLJAA. + ...LLALJJLALLAA. + ....LALCCLALAAA. + ......LA.LAA.A.. + .....LLA.LLA.... + ................ + ................ +} +# tile 762 (High-elf,male) { .........G...... .......GGF...... @@ -7323,7 +14486,26 @@ Z = (195, 195, 195) ......GFAFAA.... .....KLA.LKA.... } -# tile 384 (attendant) +# tile 763 (High-elf,female) +{ + .........G...... + .......GGF...... + ......GGGGA..... + ......LILIA..... + ......LLLLA..... + ......ALLA...... + ......GAAG..AA.. + .....LGGGFLAAAA. + ....LAAGFAALAAA. + ....LA.GFAALAA.. + ....LA.GFAALAA.. + ....LAGGGFAL.A.. + ......GFAFAA.A.. + ......GFAFAA.... + ......GFAFAA.... + .....KLA.LKA.... +} +# tile 764 (attendant,male) { ................ ................ @@ -7342,7 +14524,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 385 (page) +# tile 765 (attendant,female) +{ + ................ + ................ + ................ + ......JJJ....... + .....JLLLJ...... + ......BLB....... + .....CLLLD...... + .....CCKKDA.AAA. + .....LLCLDDAAAA. + ....CCCLDDDDAA.. + ....LALCCDALAA.. + ......LCCDAAAA.. + .....LCCCDAA.A.. + ....LCCCCCDA.... + ................ + ................ +} +# tile 766 (page,male) { ................ ................ @@ -7361,7 +14562,26 @@ Z = (195, 195, 195) ................ ................ } -# tile 386 (abbot) +# tile 767 (page,female) +{ + ................ + ................ + .......BPA...... + ......BPPPA..... + ......PEEPA..... + ......PLLPA..... + .......LLAA..... + ......BAABA.AAA. + .....BPPPPPAAAA. + ....PABPPPAPAAA. + ....LA.PP.ALAAA. + ......BP.PAAAA.. + ......LLALAA.A.. + .....LLA.LLA.... + ................ + ................ +} +# tile 768 (abbot,male) { ................ ................ @@ -7380,7 +14600,26 @@ Z = (195, 195, 195) ....CDCCCDDA.A.. ...CCCCCCCDD.... } -# tile 387 (acolyte) +# tile 769 (abbot,female) +{ + ................ + ................ + ................ + ................ + ................ + ......KLK....... + ......LLL....... + ....CCLLLJJ..... + ....KCKLKKJAAA.. + ....CDDDDDDAAAA. + ...CDDLALDDDAAA. + ...DALLALLADAA.. + ...DDDDCDDDDAA.. + ....AACCCDAAAA.. + ....CDCCCDDA.A.. + ...CCCCCCCDD.... +} +# tile 770 (acolyte,male) { ................ ................ @@ -7399,7 +14638,26 @@ Z = (195, 195, 195) ....LCCCCCDD.... ................ } -# tile 388 (hunter) +# tile 771 (acolyte,female) +{ + ................ + ................ + ................ + ......JJJJ...... + ......JLLJA..... + ......LLLLA..... + ......ALLJA..... + ......CJJCAAAA.. + .....LDDDDDAAAA. + ....CDCCDDDDAAA. + ....L.LCCDALAA.. + ......LCCDAAAA.. + ......LCCDAAAA.. + .....LDCCDDA.A.. + ....LCCCCCDD.... + ................ +} +# tile 772 (hunter,male) { ................ ................ @@ -7418,7 +14676,26 @@ Z = (195, 195, 195) ....JPPA.PPA.... ................ } -# tile 389 (thug) +# tile 773 (hunter,female) +{ + ................ + ................ + ................ + ....J..CJA...... + ...J..CJJJA..... + ...J..JEEJA..... + ..J...JLLJA..... + ..J...ALLAA..... + ..J..GGAAGG.AAA. + ..LPBPFFFFPPAAA. + ..J..AGFFFAPAAA. + ..J....FF.ALAAA. + ...J..BP.PAAAA.. + ...J..BPAPAA.A.. + ....JPPA.PPA.... + ................ +} +# tile 774 (thug,male) { ................ ................ @@ -7437,7 +14714,26 @@ Z = (195, 195, 195) .....KKA.KKA.... ................ } -# tile 390 (ninja) +# tile 775 (thug,female) +{ + ................ + ................ + ................ + .......ID....... + ......IDDDA..... + ......LKLKA..... + ......LLLLA..... + ......ALLA...... + .....KKAAKKA..A. + ....KKJKKJJKAAA. + ....KAAJJAAKAA.. + ....LAJJJJALAA.. + ......KKJKAAAA.. + ......KAAKAAAA.. + .....KKA.KKA.... + ................ +} +# tile 776 (ninja,male) { ................ ................ @@ -7456,7 +14752,26 @@ Z = (195, 195, 195) .....AAA.AAA.... ................ } -# tile 391 (roshi) +# tile 777 (ninja,female) +{ + ................ + ................ + .........AA..... + .......AAA...... + ......AAAAA..... + .....AFLFLA..... + .....AAAAAA..... + ......AAAA...... + ....AAAAAAAA.PP. + ....AAAAAAAAPPP. + ....AAAAAAAAPPP. + ....LAAAAAALPPP. + ......AAAAAPPP.. + ......AAAAAP.P.. + .....AAA.AAA.... + ................ +} +# tile 778 (roshi,male) { ................ ................ @@ -7475,7 +14790,26 @@ Z = (195, 195, 195) .....PPA.PPA.... ................ } -# tile 392 (guide) +# tile 779 (roshi,female) +{ + ................ + ................ + ................ + .......AAAAA.... + ......AAAAA..... + .....ALFLFA..... + .....ALLLLA..... + ......ALLA...... + ....PPPAAPPPAAA. + ....L.PPPP.LAAA. + ....LAOOOOALAAA. + ....LAOOOOALAAA. + ......P...AAAA.. + ......P.A.AA.A.. + .....PPA.PPA.... + ................ +} +# tile 780 (guide,male) { ................ ................ @@ -7494,7 +14828,26 @@ Z = (195, 195, 195) .....LLA.LLA.... ................ } -# tile 393 (warrior) +# tile 781 (guide,female) +{ + ................ + ................ + ......JKJJA..... + ......KJJJA..... + ....JJJJJJJJ.... + ......LFLFAA.... + ......LLLLA..... + ......ALLA...... + .....HHAAHH.AAA. + ....LLHHHHLLAAA. + ....LAHHHHALAAA. + ....LAHHHHALAAA. + ......JJJKAAAA.. + ......JJAKAA.A.. + .....LLA.LLA.... + ................ +} +# tile 782 (warrior,male) { .....O....O..... .....NO..ON..... @@ -7513,7 +14866,26 @@ Z = (195, 195, 195) .....KLA.LKA.... ................ } -# tile 394 (apprentice) +# tile 783 (warrior,female) +{ + .....O....O..... + .....NO..ON..... + ......NPPN...... + .....PPPPPP..... + .....PELELP..... + ....HHLLLLH..... + ...HHHALLA...... + ...HJKJAAKJJAAA. + ..HHLJJKKJJLAAA. + ..H.LACKJCALAAA. + ....LAAKKAALAAA. + ......KKJKAAAA.. + ......KJAJAA.A.. + ......KJAJAA.A.. + .....KLA.LKA.... + ................ +} +# tile 784 (apprentice,male) { ................ ................ @@ -7532,7 +14904,26 @@ Z = (195, 195, 195) ....BPPPPPPE.... ................ } -# tile 395 (invisible monster) +# tile 785 (apprentice,female) +{ + ................ + ................ + ................ + ......JJJ....... + .....JLLLJ...... + ......GLG....... + .....BLLLE...... + .....BBEEEA.AAA. + .....BBPBEEAAAA. + ....PPPBEEEEAA.. + ....LABPPEALAA.. + ......BPPEAAAA.. + .....BPPPEAA.A.. + .....BPPPPEA.... + ....BPPPPPPE.... + ................ +} +# tile 786 (invisible monster, nogender) { ................ ................ diff --git a/win/share/objects.txt b/win/share/objects.txt index 6cc337be3..094c7c14a 100644 --- a/win/share/objects.txt +++ b/win/share/objects.txt @@ -8692,7 +8692,7 @@ Z = (195, 195, 195) ...........PP.PA ............AA.. } -# tile 456 (splash of venom / blinding venom) +# tile 456 (splash of venom / splash of blinding venom) { ................ ................ @@ -8711,7 +8711,7 @@ Z = (195, 195, 195) ................ ................ } -# tile 457 (splash of venom / acid venom) +# tile 457 (splash of venom / splash of acid venom) { ................ ................ diff --git a/win/share/ppmwrite.c b/win/share/ppmwrite.c index 9fd052c6e..b379ece22 100644 --- a/win/share/ppmwrite.c +++ b/win/share/ppmwrite.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 ppmwrite.c $NHDT-Date: 1432512803 2015/05/25 00:13:23 $ $NHDT-Branch: master $:$NHDT-Revision: 1.6 $ */ +/* NetHack 3.7 ppmwrite.c $NHDT-Date: 1596498336 2020/08/03 23:45:36 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.7 $ */ /* this produces a raw ppm file, with a 15-character header of * "P6 3-digit-width 3-digit-height 255\n" */ diff --git a/win/share/safeproc.c b/win/share/safeproc.c index f17345321..6811721e3 100644 --- a/win/share/safeproc.c +++ b/win/share/safeproc.c @@ -1,12 +1,9 @@ -/* NetHack 3.6 safeproc.c */ +/* NetHack 3.7 safeproc.c */ /* Copyright (c) Michael Allison, 2018 */ /* NetHack may be freely redistributed. See license for details. */ /* must #define SAFEPROCS in xxxconf.h or via CFLAGS or this won't compile */ -#include "config.h" -#include "color.h" -#include "wintype.h" -#include "winprocs.h" +#include "hack.h" /* * *********************************************************** @@ -324,11 +321,12 @@ int x, y; * Print the glyph to the output device. Don't flush the output device. */ void -safe_print_glyph(window, x, y, glyph, bkglyph) +safe_print_glyph(window, x, y, glyph, bkglyph, glyphmod) winid window; xchar x, y; int glyph; int bkglyph UNUSED; +int glyphmod[NUM_GLYPHMOD] UNUSED; { return; } diff --git a/win/share/thintile.c b/win/share/thintile.c index 4d6793c46..32b2cfa8b 100644 --- a/win/share/thintile.c +++ b/win/share/thintile.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 thintile.c $NHDT-Date: 1457207049 2016/03/05 19:44:09 $ $NHDT-Branch: chasonr $:$NHDT-Revision: 1.10 $ */ +/* NetHack 3.7 thintile.c $NHDT-Date: 1596498337 2020/08/03 23:45:37 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.11 $ */ /* Copyright (c) NetHack Development Team 1995 */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/win/share/tile.doc b/win/share/tile.doc index baa7bd266..1ee5539f2 100644 --- a/win/share/tile.doc +++ b/win/share/tile.doc @@ -1,4 +1,4 @@ -NetHack 3.6 tile.doc $NHDT-Date: 1524684654 2018/04/25 19:30:54 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.7 $ +NetHack 3.7 tile.doc $NHDT-Date: 1596498338 2020/08/03 23:45:38 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.8 $ Window ports can optionally make use of the tiles (pictures for NetHack symbols) found in this directory. They are distributed in a text format diff --git a/win/share/tile.h b/win/share/tile.h index 0313ac07c..79e7e8a2e 100644 --- a/win/share/tile.h +++ b/win/share/tile.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 tile.h $NHDT-Date: 1524689272 2018/04/25 20:47:52 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.13 $ */ +/* NetHack 3.7 tile.h $NHDT-Date: 1596498339 2020/08/03 23:45:39 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.14 $ */ /* Copyright (c) 2016 by Michael Allison */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/win/share/tile2bmp.c b/win/share/tile2bmp.c index bc7d61ca5..3e66b6e5a 100644 --- a/win/share/tile2bmp.c +++ b/win/share/tile2bmp.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 tile2bmp.c $NHDT-Date: 1451442061 2015/12/30 02:21:01 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.15 $ */ +/* NetHack 3.7 tile2bmp.c $NHDT-Date: 1596498340 2020/08/03 23:45:40 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.32 $ */ /* Copyright (c) NetHack PC Development Team 1995 */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/win/share/tilemap.c b/win/share/tilemap.c index fd889114e..550a90288 100644 --- a/win/share/tilemap.c +++ b/win/share/tilemap.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 tilemap.c $NHDT-Date: 1589064692 2020/05/09 22:51:32 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.46 $ */ +/* NetHack 3.7 tilemap.c $NHDT-Date: 1596498340 2020/08/03 23:45:40 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.47 $ */ /* Copyright (c) 2016 by Michael Allison */ /* NetHack may be freely redistributed. See license for details. */ @@ -18,10 +18,22 @@ #define Fprintf (void) fprintf -const char *FDECL(tilename, (int, int)); +/* + * Defining OBTAIN_TILEMAP to get a listing of the tile-mappings + * for debugging purposes requires that your link to produce + * the tilemap utility must also include: + * objects.o, monst.o drawing.o + */ +/* #define OBTAIN_TILEMAP */ + +#if defined(OBTAIN_TILEMAP) && !defined(TILETEXT) +FILE *tilemap_file; +#endif + +const char *FDECL(tilename, (int, int, int)); void NDECL(init_tilemap); void FDECL(process_substitutions, (FILE *)); -boolean FDECL(acceptable_tilename, (int, const char *, const char *)); +boolean FDECL(acceptable_tilename, (int, int, const char *, const char *)); #if defined(MICRO) || defined(WIN32) #undef exit @@ -30,21 +42,14 @@ extern void FDECL(exit, (int)); #endif #endif -#if defined(MSDOS) || defined(WIN32) || defined(X11_GRAPHICS) -#define STATUES_LOOK_LIKE_MONSTERS -#endif - -#define MON_GLYPH 1 -#define OBJ_GLYPH 2 -#define OTH_GLYPH 3 /* fortunately unnecessary */ - +enum {MON_GLYPH, OBJ_GLYPH, OTH_GLYPH, TERMINATOR = -1}; #define EXTRA_SCROLL_DESCR_COUNT ((SCR_BLANK_PAPER - SCR_STINKING_CLOUD) - 1) /* note that the ifdefs here should be the opposite sense from monst.c/ * objects.c/rm.h */ -struct conditionals { +struct conditionals_t { int sequence, predecessor; const char *name; } conditionals[] = { @@ -56,7 +61,7 @@ struct conditionals { { MON_GLYPH, PM_BABY_SILVER_DRAGON, "baby shimmering dragon" }, { MON_GLYPH, PM_SILVER_DRAGON, "shimmering dragon" }, { MON_GLYPH, PM_JABBERWOCK, "vorpal jabberwock" }, - { MON_GLYPH, PM_VAMPIRE_LORD, "vampire mage" }, + { MON_GLYPH, PM_VAMPIRE_LEADER, "vampire mage" }, #ifndef CHARON /* not supported yet */ { MON_GLYPH, PM_CROESUS, "Charon" }, #endif @@ -79,7 +84,7 @@ struct conditionals { { OBJ_GLYPH, SCR_STINKING_CLOUD + EXTRA_SCROLL_DESCR_COUNT, "stamped / mail" }, #endif - { 0, 0, 0 } + { TERMINATOR, 0, 0 } }; /* @@ -103,42 +108,42 @@ struct substitute { { GLYPH_CMAP_OFF + S_vwall, GLYPH_CMAP_OFF + S_trwall, "sokoban walls", "In_sokoban(plev)" } }; -#ifdef TILETEXT - +#if defined(TILETEXT) || defined(OBTAIN_TILEMAP) /* - * entry is the position of the tile within the monsters/objects/other set + * file_entry is the position of the tile within the monsters/objects/other set */ const char * -tilename(set, entry) -int set, entry; +tilename(set, file_entry, gend) +int set, file_entry, gend; { - int i, j, condnum, tilenum; + int i, j, condnum, tilenum, gendnum; static char buf[BUFSZ]; (void) def_char_to_objclass(']'); - condnum = tilenum = 0; + condnum = tilenum = gendnum = 0; for (i = 0; i < NUMMONS; i++) { - if (set == MON_GLYPH && tilenum == entry) - return mons[i].mname; - tilenum++; - while (conditionals[condnum].sequence == MON_GLYPH - && conditionals[condnum].predecessor == i) { - if (set == MON_GLYPH && tilenum == entry) - return conditionals[condnum].name; - condnum++; - tilenum++; + if (set == MON_GLYPH && tilenum == file_entry && gend == 0) + return mons[i].pmnames[NEUTRAL]; + for (condnum = 0; conditionals[condnum].sequence != -1; ++condnum) { + if (conditionals[condnum].sequence == MON_GLYPH + && conditionals[condnum].predecessor == i) { + tilenum += 2; + if (set == MON_GLYPH && tilenum == file_entry) + return conditionals[condnum].name; + } } + tilenum += 2; } - if (set == MON_GLYPH && tilenum == entry) + if (set == MON_GLYPH && tilenum == file_entry) return "invisible monster"; tilenum = 0; /* set-relative number */ for (i = 0; i < NUM_OBJECTS; i++) { /* prefer to give the description - that's all the tile's * appearance should reveal */ - if (set == OBJ_GLYPH && tilenum == entry) { + if (set == OBJ_GLYPH && tilenum == file_entry) { if (!obj_descr[i].oc_descr) return obj_descr[i].oc_name; if (!obj_descr[i].oc_name) @@ -148,20 +153,20 @@ int set, entry; obj_descr[i].oc_name); return buf; } - - tilenum++; - while (conditionals[condnum].sequence == OBJ_GLYPH - && conditionals[condnum].predecessor == i) { - if (set == OBJ_GLYPH && tilenum == entry) - return conditionals[condnum].name; - condnum++; - tilenum++; + for (condnum = 0; conditionals[condnum].sequence != -1; ++condnum) { + if (conditionals[condnum].sequence == OBJ_GLYPH + && conditionals[condnum].predecessor == i) { + tilenum++; + if (set == OBJ_GLYPH && tilenum == file_entry) + return conditionals[condnum].name; + } } + tilenum++; } tilenum = 0; /* set-relative number */ for (i = 0; i < (MAXPCHARS - MAXEXPCHARS); i++) { - if (set == OTH_GLYPH && tilenum == entry) { + if (set == OTH_GLYPH && tilenum == file_entry) { if (*defsyms[i].explanation) { return defsyms[i].explanation; } else { @@ -169,18 +174,19 @@ int set, entry; return buf; } } - tilenum++; - while (conditionals[condnum].sequence == OTH_GLYPH - && conditionals[condnum].predecessor == i) { - if (set == OTH_GLYPH && tilenum == entry) - return conditionals[condnum].name; - condnum++; - tilenum++; + for (condnum = 0; conditionals[condnum].sequence != -1; ++condnum) { + if (conditionals[condnum].sequence == OTH_GLYPH + && conditionals[condnum].predecessor == i) { + tilenum++; + if (set == OTH_GLYPH && tilenum == file_entry) + return conditionals[condnum].name; + } } + tilenum++; } /* explosions */ tilenum = MAXPCHARS - MAXEXPCHARS; - i = entry - tilenum; + i = file_entry - tilenum; if (i < (MAXEXPCHARS * EXPL_MAX)) { if (set == OTH_GLYPH) { static const char *explosion_types[] = { @@ -195,7 +201,7 @@ int set, entry; } tilenum += (MAXEXPCHARS * EXPL_MAX); - i = entry - tilenum; + i = file_entry - tilenum; if (i < (NUM_ZAP << 2)) { if (set == OTH_GLYPH) { Sprintf(buf, "zap %d %d", i / 4, i % 4); @@ -204,7 +210,7 @@ int set, entry; } tilenum += (NUM_ZAP << 2); - i = entry - tilenum; + i = file_entry - tilenum; if (i < WARNCOUNT) { if (set == OTH_GLYPH) { Sprintf(buf, "warning %d", i); @@ -213,7 +219,7 @@ int set, entry; } tilenum += WARNCOUNT; - i = entry - tilenum; + i = file_entry - tilenum; if (i < 1) { if (set == OTH_GLYPH) { Sprintf(buf, "unexplored"); @@ -222,17 +228,17 @@ int set, entry; } tilenum += 1; - i = entry - tilenum; + i = file_entry - tilenum; if (i < 1) { if (set == OTH_GLYPH) { Sprintf(buf, "nothing"); return buf; } } - tilenum += 1; + tilenum++; for (i = 0; i < SIZE(substitutes); i++) { - j = entry - tilenum; + j = file_entry - tilenum; if (j <= substitutes[i].last_glyph - substitutes[i].first_glyph) { if (set == OTH_GLYPH) { Sprintf(buf, "sub %s %d", substitutes[i].sub_name, j); @@ -242,12 +248,12 @@ int set, entry; tilenum += substitutes[i].last_glyph - substitutes[i].first_glyph + 1; } - Sprintf(buf, "unknown %d %d", set, entry); + Sprintf(buf, "unknown %d %d", set, file_entry); return buf; } +#endif -#else /* TILETEXT */ - +#ifndef TILETEXT #define TILE_FILE "tile.c" #ifdef AMIGA @@ -260,9 +266,16 @@ int set, entry; #endif #endif -short tilemap[MAX_GLYPH]; +struct tilemap_t { + short tilenum; +#ifdef OBTAIN_TILEMAP + char name[80]; + int glyph; +#endif +} tilemap[MAX_GLYPH]; -#ifdef STATUES_LOOK_LIKE_MONSTERS + +#ifndef STATUES_DONT_LOOK_LIKE_MONSTERS int lastmontile, lastobjtile, lastothtile, laststatuetile; #else int lastmontile, lastobjtile, lastothtile; @@ -275,7 +288,8 @@ int lastmontile, lastobjtile, lastothtile; * set up array to map glyph numbers to tile numbers * * assumes tiles are numbered sequentially through monsters/objects/other, - * with entries for all supported compilation options + * with entries for all supported compilation options. monsters have two + * tiles for each (male + female). * * "other" contains cmap and zaps (the swallow sets are a repeated portion * of cmap), as well as the "flash" glyphs for the new warning system @@ -286,20 +300,21 @@ init_tilemap() { int i, j, condnum, tilenum; int corpsetile, swallowbase; + int file_entry = 0; for (i = 0; i < MAX_GLYPH; i++) { - tilemap[i] = -1; + tilemap[i].tilenum = -1; } - corpsetile = NUMMONS + NUM_INVIS_TILES + CORPSE; - swallowbase = NUMMONS + NUM_INVIS_TILES + NUM_OBJECTS + S_sw_tl; + corpsetile = NUMMONS + NUMMONS + NUM_INVIS_TILES + CORPSE; + swallowbase = NUMMONS + NUMMONS + NUM_INVIS_TILES + NUM_OBJECTS + S_sw_tl; /* add number compiled out */ - for (i = 0; conditionals[i].sequence; i++) { + for (i = 0; conditionals[i].sequence != TERMINATOR; i++) { switch (conditionals[i].sequence) { case MON_GLYPH: - corpsetile++; - swallowbase++; + corpsetile += 2; + swallowbase += 2; break; case OBJ_GLYPH: if (conditionals[i].predecessor < CORPSE) @@ -313,116 +328,239 @@ init_tilemap() } } - condnum = tilenum = 0; +#ifdef OBTAIN_TILEMAP + tilemap_file = fopen("tilemappings.lst", "w"); +#endif + tilenum = 0; for (i = 0; i < NUMMONS; i++) { - tilemap[GLYPH_MON_OFF + i] = tilenum; - tilemap[GLYPH_PET_OFF + i] = tilenum; - tilemap[GLYPH_DETECT_OFF + i] = tilenum; - tilemap[GLYPH_RIDDEN_OFF + i] = tilenum; - tilemap[GLYPH_BODY_OFF + i] = corpsetile; +#ifdef OBTAIN_TILEMAP + char buf[256]; +#endif + tilemap[GLYPH_MON_OFF + i].tilenum = tilenum; + tilemap[GLYPH_PET_OFF + i].tilenum = tilenum; + tilemap[GLYPH_DETECT_OFF + i].tilenum = tilenum; + tilemap[GLYPH_RIDDEN_OFF + i].tilenum = tilenum; + tilemap[GLYPH_BODY_OFF + i].tilenum = corpsetile; j = GLYPH_SWALLOW_OFF + 8 * i; - tilemap[j] = swallowbase; - tilemap[j + 1] = swallowbase + 1; - tilemap[j + 2] = swallowbase + 2; - tilemap[j + 3] = swallowbase + 3; - tilemap[j + 4] = swallowbase + 4; - tilemap[j + 5] = swallowbase + 5; - tilemap[j + 6] = swallowbase + 6; - tilemap[j + 7] = swallowbase + 7; - tilenum++; - while (conditionals[condnum].sequence == MON_GLYPH - && conditionals[condnum].predecessor == i) { - condnum++; - tilenum++; + tilemap[j].tilenum = swallowbase; + tilemap[j + 1].tilenum = swallowbase + 1; + tilemap[j + 2].tilenum = swallowbase + 2; + tilemap[j + 3].tilenum = swallowbase + 3; + tilemap[j + 4].tilenum = swallowbase + 4; + tilemap[j + 5].tilenum = swallowbase + 5; + tilemap[j + 6].tilenum = swallowbase + 6; + tilemap[j + 7].tilenum = swallowbase + 7; +#ifdef OBTAIN_TILEMAP + Sprintf(buf, "%s (%d)", tilename(MON_GLYPH, file_entry, 0), file_entry); + Sprintf(tilemap[GLYPH_MON_OFF + i].name, + "%s (%d)", buf, i); + Sprintf(tilemap[GLYPH_PET_OFF + i].name, + "%s %s (%d)", buf, "pet", i); + Sprintf(tilemap[GLYPH_DETECT_OFF + i].name, + "%s %s (%d)", buf, "detected", i); + Sprintf(tilemap[GLYPH_RIDDEN_OFF + i].name, + "%s %s (%d)", buf, "ridden", i); + Sprintf(tilemap[GLYPH_BODY_OFF + i].name, + "%s %s (%d)", buf, "corpse", i); + Sprintf(tilemap[j + 0].name, "%s swallow0 (%d)", buf, i); + Sprintf(tilemap[j + 1].name, "%s swallow1 (%d)", buf, i); + Sprintf(tilemap[j + 2].name, "%s swallow2 (%d)", buf, i); + Sprintf(tilemap[j + 3].name, "%s swallow3 (%d)", buf, i); + Sprintf(tilemap[j + 4].name, "%s swallow4 (%d)", buf, i); + Sprintf(tilemap[j + 5].name, "%s swallow5 (%d)", buf, i); + Sprintf(tilemap[j + 6].name, "%s swallow6 (%d)", buf, i); + Sprintf(tilemap[j + 7].name, "%s swallow7 (%d)", buf, i); +#endif + for (condnum = 0; conditionals[condnum].sequence != -1; condnum++) { + if (conditionals[condnum].sequence == MON_GLYPH + && conditionals[condnum].predecessor == i) { + tilenum += 2; + file_entry += 2; +#ifdef OBTAIN_TILEMAP + Fprintf(tilemap_file, "skipping monst %s (%d)\n", + tilename(MON_GLYPH, file_entry, 0), file_entry); +#endif + } } + tilenum += 2; /* male + female tiles for each */ + file_entry += 2; } - tilemap[GLYPH_INVISIBLE] = tilenum++; + tilemap[GLYPH_INVISIBLE].tilenum = tilenum++; + file_entry++; +#ifdef OBTAIN_TILEMAP + Sprintf(tilemap[GLYPH_INVISIBLE].name, + "%s (%d)", "invisible mon", file_entry); +#endif lastmontile = tilenum - 1; + file_entry = 0; for (i = 0; i < NUM_OBJECTS; i++) { - tilemap[GLYPH_OBJ_OFF + i] = tilenum; - tilenum++; - while (conditionals[condnum].sequence == OBJ_GLYPH - && conditionals[condnum].predecessor == i) { - condnum++; - tilenum++; + tilemap[GLYPH_OBJ_OFF + i].tilenum = tilenum; +#ifdef OBTAIN_TILEMAP + Sprintf(tilemap[GLYPH_OBJ_OFF + i].name, "%s (%d)", + tilename(OBJ_GLYPH, file_entry, 0), file_entry); +#endif + for (condnum = 0; conditionals[condnum].sequence != -1; condnum++) { + if (conditionals[condnum].sequence == OBJ_GLYPH + && conditionals[condnum].predecessor == i) { + tilenum++; + file_entry++; +#ifdef OBTAIN_TILEMAP + Fprintf(tilemap_file, "skipping obj %s (%d)\n", + tilename(OBJ_GLYPH, file_entry, 0), file_entry); +#endif + } } + tilenum++; + file_entry++; } lastobjtile = tilenum - 1; + file_entry = 0; for (i = 0; i < (MAXPCHARS - MAXEXPCHARS); i++) { - tilemap[GLYPH_CMAP_OFF + i] = tilenum; + tilemap[GLYPH_CMAP_OFF + i].tilenum = tilenum; +#ifdef OBTAIN_TILEMAP + Sprintf(tilemap[GLYPH_CMAP_OFF + i].name, "cmap %s (%d)", + tilename(OTH_GLYPH, file_entry, 0), file_entry); +#endif tilenum++; - while (conditionals[condnum].sequence == OTH_GLYPH - && conditionals[condnum].predecessor == i) { - condnum++; - tilenum++; + file_entry++; + for (condnum = 0; conditionals[condnum].sequence != -1; condnum++) { + if (conditionals[condnum].sequence == OTH_GLYPH + && conditionals[condnum].predecessor == i) { + tilenum++; + file_entry++; +#ifdef OBTAIN_TILEMAP + Fprintf(tilemap_file, "skipping cmap %s (%d)\n", + tilename(OTH_GLYPH, file_entry, 0), file_entry); +#endif + } } } for (i = 0; i < (MAXEXPCHARS * EXPL_MAX); i++) { - tilemap[GLYPH_EXPLODE_OFF + i] = tilenum; - tilenum++; - while (conditionals[condnum].sequence == OTH_GLYPH - && conditionals[condnum].predecessor == (i + MAXPCHARS)) { - condnum++; - tilenum++; + tilemap[GLYPH_EXPLODE_OFF + i].tilenum = tilenum; +#ifdef OBTAIN_TILEMAP + Sprintf(tilemap[GLYPH_EXPLODE_OFF + i].name, "explosion %s (%d)", + tilename(OTH_GLYPH, file_entry, 0), file_entry); +#endif + for (condnum = 0; conditionals[condnum].sequence != -1; condnum++) { + if (conditionals[condnum].sequence == OTH_GLYPH + && conditionals[condnum].predecessor == i + MAXPCHARS) { + tilenum++; + file_entry++; +#ifdef OBTAIN_TILEMAP + Fprintf(tilemap_file, "skipping explosion %s (%d)\n", + tilename(OTH_GLYPH, file_entry, 0), file_entry); +#endif + } } + tilenum++; + file_entry++; } for (i = 0; i < NUM_ZAP << 2; i++) { - tilemap[GLYPH_ZAP_OFF + i] = tilenum; + tilemap[GLYPH_ZAP_OFF + i].tilenum = tilenum; +#ifdef OBTAIN_TILEMAP + Sprintf(tilemap[GLYPH_ZAP_OFF + i].name, "zap %s (%d)", + tilename(OTH_GLYPH, file_entry, 0), file_entry); +#endif tilenum++; - while (conditionals[condnum].sequence == OTH_GLYPH + file_entry++; + for (condnum = 0; conditionals[condnum].sequence != -1; condnum++) { + if (conditionals[condnum].sequence == OTH_GLYPH && conditionals[condnum].predecessor == (i + MAXEXPCHARS)) { - condnum++; - tilenum++; +#ifdef OBTAIN_TILEMAP + Fprintf(tilemap_file, "skipping zap %s (%d)\n", + tilename(OTH_GLYPH, file_entry, 0), file_entry); +#endif + file_entry++; + tilenum++; + } } } for (i = 0; i < WARNCOUNT; i++) { - tilemap[GLYPH_WARNING_OFF + i] = tilenum; + tilemap[GLYPH_WARNING_OFF + i].tilenum = tilenum; +#ifdef OBTAIN_TILEMAP + Sprintf(tilemap[GLYPH_WARNING_OFF + i].name, "%s (%d)", + tilename(OTH_GLYPH, file_entry, 0), file_entry); +#endif tilenum++; + file_entry++; } for (i = 0; i < 1; i++) { - tilemap[GLYPH_UNEXPLORED_OFF + i] = tilenum; + tilemap[GLYPH_UNEXPLORED_OFF + i].tilenum = tilenum; +#ifdef OBTAIN_TILEMAP + Sprintf(tilemap[GLYPH_UNEXPLORED_OFF + i].name, "unexplored %s (%d)", + tilename(OTH_GLYPH, file_entry, 0), file_entry); +#endif tilenum++; + file_entry++; } for (i = 0; i < 1; i++) { - tilemap[GLYPH_NOTHING + i] = tilenum; + tilemap[GLYPH_NOTHING + i].tilenum = tilenum; +#ifdef OBTAIN_TILEMAP + Sprintf(tilemap[GLYPH_NOTHING + i].name, " nothing %s (%d)", + tilename(OTH_GLYPH, file_entry, 0), file_entry); +#endif tilenum++; + file_entry++; } -#ifndef STATUES_LOOK_LIKE_MONSTERS - /* statue patch: statues still use the same glyph as in vanilla */ +#ifdef STATUES_DONT_LOOK_LIKE_MONSTERS + /* statue patch: statues still use the same glyph as in 3.4.x */ for (i = 0; i < NUMMONS; i++) { - tilemap[GLYPH_STATUE_OFF + i] = tilemap[GLYPH_OBJ_OFF + STATUE]; + tilemap[GLYPH_STATUE_OFF + i].tilenum + = tilemap[GLYPH_OBJ_OFF + STATUE].tilenum; +#ifdef OBTAIN_TILEMAP + Sprintf(tilemap[GLYPH_STATUE_OFF + i].name, "%s (%d)", + tilename(OTH_GLYPH, file_entry, 0), file_entry); +#endif } #endif lastothtile = tilenum - 1; -#ifdef STATUES_LOOK_LIKE_MONSTERS - /* skip over the substitutes to get to the grayscale statues */ +#ifndef STATUES_DONT_LOOK_LIKE_MONSTERS + file_entry = 0; + /* fast-forward over the substitutes to grayscale statues loc */ for (i = 0; i < SIZE(substitutes); i++) { tilenum += substitutes[i].last_glyph - substitutes[i].first_glyph + 1; } /* statue patch: statues look more like the monster */ - condnum = 0; /* doing monsters again, so reset */ for (i = 0; i < NUMMONS; i++) { - tilemap[GLYPH_STATUE_OFF + i] = tilenum; - tilenum++; - while (conditionals[condnum].sequence == MON_GLYPH - && conditionals[condnum].predecessor == i) { - condnum++; - tilenum++; + tilemap[GLYPH_STATUE_OFF + i].tilenum = tilenum; +#ifdef OBTAIN_TILEMAP + Sprintf(tilemap[GLYPH_STATUE_OFF + i].name, "statue of %s (%d)", + tilename(MON_GLYPH, file_entry, 0), file_entry); +#endif + for (condnum = 0; conditionals[condnum].sequence != -1; condnum++) { + if (conditionals[condnum].sequence == MON_GLYPH + && conditionals[condnum].predecessor == i) { + file_entry += 2; /* skip female tile too */ + tilenum += 2; +#ifdef OBTAIN_TILEMAP + Fprintf(tilemap_file, "skipping statue of %s (%d)\n", + tilename(MON_GLYPH, file_entry, 0), file_entry); +#endif + } } + tilenum += 2; + file_entry += 2; } - laststatuetile = tilenum - 1; + laststatuetile = tilenum - 2; +#endif /* STATUES_DONT_LOOK_LIKE_MONSTERS */ +#ifdef OBTAIN_TILEMAP + for (i = 0; i < MAX_GLYPH; ++i) { + Fprintf(tilemap_file, "[%04d] [%04d] %-80s\n", + i, tilemap[i].tilenum, tilemap[i].name); + } + fclose(tilemap_file); #endif } @@ -451,8 +589,8 @@ FILE *ofp; Fprintf(ofp, "short std_tiles%d[] = { ", span); for (k = substitutes[i].first_glyph; k < substitutes[i].last_glyph; k++) - Fprintf(ofp, "%d, ", tilemap[k]); - Fprintf(ofp, "%d };\n", tilemap[substitutes[i].last_glyph]); + Fprintf(ofp, "%d, ", tilemap[k].tilenum); + Fprintf(ofp, "%d };\n", tilemap[substitutes[i].last_glyph].tilenum); } } @@ -497,12 +635,17 @@ FILE *ofp; } lastothtile = start - 1; -#ifdef STATUES_LOOK_LIKE_MONSTERS +#ifndef STATUES_DONT_LOOK_LIKE_MONSTERS start = laststatuetile + 1; #endif Fprintf(ofp, "\nint total_tiles_used = %d;\n", start); } +#ifdef OBTAIN_TILEMAP +extern void NDECL(monst_globals_init); +extern void NDECL(objects_globals_init); +#endif + int main() { @@ -510,6 +653,11 @@ main() char filename[30]; FILE *ofp; +#ifdef OBTAIN_TILEMAP + objects_globals_init(); + monst_globals_init(); +#endif + init_tilemap(); /* @@ -526,7 +674,7 @@ main() Fprintf(ofp, "\nshort glyph2tile[MAX_GLYPH] = {\n"); for (i = 0; i < MAX_GLYPH; i++) { - Fprintf(ofp, " %4d,", tilemap[i]); + Fprintf(ofp, " %4d,", tilemap[i].tilenum); if ((i % 12) == 11 || i == MAX_GLYPH - 1) Fprintf(ofp, "\n"); } @@ -537,7 +685,7 @@ main() Fprintf(ofp, "\n#define MAXMONTILE %d\n", lastmontile); Fprintf(ofp, "#define MAXOBJTILE %d\n", lastobjtile); Fprintf(ofp, "#define MAXOTHTILE %d\n", lastothtile); -#ifdef STATUES_LOOK_LIKE_MONSTERS +#ifndef STATUES_DONT_LOOK_LIKE_MONSTERS Fprintf(ofp, "/* #define MAXSTATUETILE %d */\n", laststatuetile); #endif Fprintf(ofp, "\n/*tile.c*/\n"); @@ -654,17 +802,20 @@ struct { }; boolean -acceptable_tilename(idx, encountered, expected) -int idx; +acceptable_tilename(glyph_set, idx, encountered, expected) +int glyph_set, idx; const char *encountered, *expected; { - if (idx >= 0 && idx < SIZE(altlabels)) { - if (!strcmp(altlabels[idx].expectedlabel, expected)) { - if (!strcmp(altlabels[idx].betterlabel, encountered)) - return TRUE; + if (glyph_set == OTH_GLYPH) { + if (idx >= 0 && idx < SIZE(altlabels)) { + if (!strcmp(altlabels[idx].expectedlabel, expected)) { + if (!strcmp(altlabels[idx].betterlabel, encountered)) + return TRUE; + } } + return FALSE; } - return FALSE; + return TRUE; } /*tilemap.c*/ diff --git a/win/share/tileset.c b/win/share/tileset.c index 2dd8ebefe..6006d1f44 100644 --- a/win/share/tileset.c +++ b/win/share/tileset.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 tileset.c $NHDT-Date: 1501463811 2017/07/31 01:16:51 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.0 $ */ +/* NetHack 3.7 tileset.c $NHDT-Date: 1596498341 2020/08/03 23:45:41 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.3 $ */ /* Copyright (c) Ray Chason, 2016. */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/win/share/tiletext.c b/win/share/tiletext.c index 480698c01..c07c96431 100644 --- a/win/share/tiletext.c +++ b/win/share/tiletext.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 tiletext.c $NHDT-Date: 1524689272 2018/04/25 20:47:52 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.16 $ */ +/* NetHack 3.7 tiletext.c $NHDT-Date: 1596498342 2020/08/03 23:45:42 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.17 $ */ /* Copyright (c) 2016 by Pasi Kallinen */ /* NetHack may be freely redistributed. See license for details. */ @@ -26,13 +26,15 @@ static const char *text_sets[] = { "monsters.txt", "objects.txt", "other.txt" }; #endif -extern const char *FDECL(tilename, (int, int)); -extern boolean FDECL(acceptable_tilename, (int, const char *, const char *)); +extern const char *FDECL(tilename, (int, int, int)); +extern boolean FDECL(acceptable_tilename, (int, int, const char *, const char *)); static void FDECL(read_text_colormap, (FILE *)); static boolean FDECL(write_text_colormap, (FILE *)); static boolean FDECL(read_txttile, (FILE *, pixel (*)[TILE_X])); static void FDECL(write_txttile, (FILE *, pixel (*)[TILE_X])); +enum { MONSTER_SET, OBJECT_SET, OTHER_SET}; + /* Ugh. DICE doesn't like %[A-Z], so we have to spell it out... */ #define FORMAT_STRING \ "%[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.] = " \ @@ -42,7 +44,9 @@ static int grayscale = 0; /* grayscale color mapping */ static const int graymappings[] = { /* . A B C D E F G H I J K L M N O P */ - 0, 1, 17, 18, 19, 20, 27, 22, 23, 24, 25, 26, 21, 15, 13, 14, 14 + 0, 1, 17, 18, 19, 20, 27, 22, 23, 24, 25, 26, 21, 15, 13, 14, 14, + /* Q R S T U V W */ + 1, 17, 18, 19, 20, 27, 22 }; void @@ -108,29 +112,37 @@ read_txttile(txtfile, pixels) FILE *txtfile; pixel (*pixels)[TILE_X]; { - int ph, i, j, k; - char buf[BUFSZ], ttype[BUFSZ]; + int ph, i, j, k, reslt; + char buf[BUFSZ], ttype[BUFSZ], gend[BUFSZ]; const char *p; char c[2]; + static int gidx = 0; - if (fscanf(txtfile, "# %s %d (%[^)])", ttype, &i, buf) <= 0) + gend[0] = '\0'; + if (tile_set == MONSTER_SET) + reslt = fscanf(txtfile, "# %s %d (%[^,],%[^)])", ttype, &i, buf, gend); + else + reslt = fscanf(txtfile, "# %s %d (%[^)])", ttype, &i, buf); + if (reslt <= 0) return FALSE; + if (tile_set == MONSTER_SET && gend[0] == 'f') + gidx = 1; + ph = strcmp(ttype, "placeholder") == 0; if (!ph && strcmp(ttype, "tile") != 0) Fprintf(stderr, "Keyword \"%s\" unexpected for entry %d\n", ttype, i); - if (tile_set != 0) { - /* check tile name, but not relative number, which will - * change when tiles are added - */ - p = tilename(tile_set, tile_set_indx); - if (p && strcmp(p, buf) && !acceptable_tilename(tile_set_indx,buf,p)) { - Fprintf(stderr, "warning: for tile %d (numbered %d) of %s,\n", - tile_set_indx, i, text_sets[tile_set - 1]); - Fprintf(stderr, "\tfound '%s' while expecting '%s'\n", buf, p); - } + /* check tile name, but not relative number, which will + * change when tiles are added + */ + p = tilename(tile_set, tile_set_indx, gidx); + if (p && strcmp(p, buf) + && !acceptable_tilename(tile_set, tile_set_indx, buf, p)) { + Fprintf(stderr, "warning: for tile %d (numbered %d) of %s,\n", + tile_set_indx, i, text_sets[tile_set]); + Fprintf(stderr, "\tfound '%s' while expecting '%s'\n", buf, p); } tile_set_indx++; @@ -196,21 +208,26 @@ pixel (*pixels)[TILE_X]; { const char *p; const char *type; - int i, j, k; + int i = 0, j, k; if (memcmp(placeholder, pixels, sizeof(placeholder)) == 0) type = "placeholder"; else type = "tile"; - if (tile_set == 0) - Fprintf(txtfile, "# %s %d (unknown)\n", type, tile_set_indx); - else { - p = tilename(tile_set, tile_set_indx); - if (p) - Fprintf(txtfile, "# %s %d (%s)\n", type, tile_set_indx, p); - else - Fprintf(txtfile, "# %s %d (null)\n", type, tile_set_indx); + if (tile_set == MONSTER_SET) { + for (i = 0; i < 2; ++i) { + Fprintf(txtfile, "# %s %d (unknown,%s)\n", type, tile_set_indx, + i ? "female" : "male"); + if (i == 0) + tile_set_indx++; + } + } else { + p = tilename(tile_set, tile_set_indx, i); + if (p) + Fprintf(txtfile, "# %s %d (%s)\n", type, tile_set_indx, p); + else + Fprintf(txtfile, "# %s %d (null)\n", type, tile_set_indx); } tile_set_indx++; @@ -302,7 +319,7 @@ const char *type; tile_set = 0; for (i = 0; i < SIZE(text_sets); i++) { if (!strcmp(p, text_sets[i])) - tile_set = i + 1; + tile_set = i; } tile_set_indx = 0; diff --git a/win/shim/winshim.c b/win/shim/winshim.c new file mode 100644 index 000000000..c6e425d70 --- /dev/null +++ b/win/shim/winshim.c @@ -0,0 +1,314 @@ +/* NetHack 3.7 winshim.c $NHDT-Date: 1596498345 2020/08/03 23:45:45 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.259 $ */ +/* Copyright (c) Adam Powers, 2020 */ +/* NetHack may be freely redistributed. See license for details. */ + +/* not an actual windowing port, but a fake win port for libnethack */ + +#include "hack.h" +#include + +#ifdef SHIM_GRAPHICS +#include +/* for cross-compiling to WebAssembly (WASM) */ +#ifdef __EMSCRIPTEN__ +#include +#endif + +#undef SHIM_DEBUG + +#ifdef SHIM_DEBUG +#define debugf printf +#else /* !SHIM_DEBUG */ +#define debugf(...) +#endif /* SHIM_DEBUG */ + + +/* shim_graphics_callback is the primary interface to shim graphics, + * call this function with your declared callback function + * and you will receive all the windowing calls + */ +#ifdef __EMSCRIPTEN__ +/************ + * WASM interface + ************/ +EMSCRIPTEN_KEEPALIVE +static char *shim_callback_name = NULL; +void shim_graphics_set_callback(char *cbName) { + if (shim_callback_name != NULL) free(shim_callback_name); + if(cbName && strlen(cbName) > 0) { + debugf("setting shim_callback_name: %s\n", cbName); + shim_callback_name = strdup(cbName); + } else { + debugf("un-setting shim_callback_name\n"); + shim_callback_name = NULL; + } + /* TODO: free(shim_callback_name) during shutdown? */ +} +void local_callback (const char *cb_name, const char *shim_name, void *ret_ptr, const char *fmt_str, void *args); + +/* A2P = Argument to Pointer */ +#define A2P & +/* P2V = Pointer to Void */ +#define P2V (void *) +#define DECLCB(ret_type, name, fn_args, fmt, ...) \ +ret_type name fn_args { \ + void *args[] = { __VA_ARGS__ }; \ + ret_type ret = (ret_type) 0; \ + debugf("SHIM GRAPHICS: " #name "\n"); \ + if (!shim_callback_name) return ret; \ + local_callback(shim_callback_name, #name, (void *)&ret, fmt, args); \ + debugf("SHIM GRAPHICS: " #name " done.\n"); \ + return ret; \ +} + +#define VDECLCB(name, fn_args, fmt, ...) \ +void name fn_args { \ + void *args[] = { __VA_ARGS__ }; \ + debugf("SHIM GRAPHICS: " #name "\n"); \ + if (!shim_callback_name) return; \ + local_callback(shim_callback_name, #name, NULL, fmt, args); \ + debugf("SHIM GRAPHICS: " #name " done.\n"); \ +} + +#else /* !__EMSCRIPTEN__ */ + +/************ + * libnethack.a interface + ************/ +typedef void(*shim_callback_t)(const char *name, void *ret_ptr, const char *fmt, ...); +static shim_callback_t shim_graphics_callback = NULL; +void shim_graphics_set_callback(shim_callback_t cb) { + shim_graphics_callback = cb; +} + +#define A2P +#define P2V +#define DECLCB(ret_type, name, fn_args, fmt, ...) \ +ret_type name fn_args { \ + ret_type ret = (ret_type) 0; \ + debugf("SHIM GRAPHICS: " #name "\n"); \ + if (!shim_graphics_callback) return ret; \ + shim_graphics_callback(#name, (void *)&ret, fmt, ## __VA_ARGS__); \ + debugf("SHIM GRAPHICS: " #name " done.\n"); \ + return ret; \ +} + +#define VDECLCB(name, fn_args, fmt, ...) \ +void name fn_args { \ + debugf("SHIM GRAPHICS: " #name "\n"); \ + if (!shim_graphics_callback) return; \ + shim_graphics_callback(#name, NULL, fmt, ## __VA_ARGS__); \ + debugf("SHIM GRAPHICS: " #name " done.\n"); \ +} +#endif /* __EMSCRIPTEN__ */ + +VDECLCB(shim_init_nhwindows,(int *argcp, char **argv), "vpp", P2V argcp, P2V argv) +VDECLCB(shim_player_selection,(void), "v") +VDECLCB(shim_askname,(void), "v") +VDECLCB(shim_get_nh_event,(void), "v") +VDECLCB(shim_exit_nhwindows,(const char *str), "vs", P2V str) +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_P blocking), "vii", 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_P complain), "vsi", P2V name, A2P complain) +VDECLCB(shim_start_menu,(winid window, unsigned long mbehavior), "vii", A2P window, A2P mbehavior) +VDECLCB(shim_add_menu, + (winid window, int glyph, const ANY_P *identifier, CHAR_P ch, CHAR_P gch, int attr, const char *str, unsigned int itemflags), + "viipiiisi", + A2P window, A2P glyph, P2V identifier, A2P ch, A2P gch, A2P attr, 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(char, shim_message_menu,(CHAR_P 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, int x, int y, int glyph, int bkglyph, int glyphmod[NUM_GLYPHMOD]), "viiiii", A2P w, A2P x, A2P y, A2P glyph, A2P bkglyph, A2P glyphmod) +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,(int *x, int *y, int *mod), "iooo", 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_P def), "cssi", P2V query, P2V resp, A2P def) +VDECLCB(shim_getlin,(const char *query, char *bufp), "vso", 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") +VDECLCB(shim_change_color,(int color, long rgb, int reverse), "viii", A2P color, A2P rgb, A2P reverse) +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_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_P init), "si", A2P init) +VDECLCB(shim_putmsghistory, (const char *msg, BOOLEAN_P restoring_msghist), "vsi", P2V msg, A2P restoring_msghist) +VDECLCB(shim_status_init, (void), "v") +VDECLCB(shim_status_enablefield, + (int fieldidx, const char *nm, const char *fmt, BOOLEAN_P enable), + "vippi", + 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", + 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() */ +void shim_update_inventory() { + if(iflags.perm_invent) { + display_inventory(NULL, FALSE); + } +} +#else /* !__EMSCRIPTEN__ */ +VDECLCB(shim_update_inventory,(void), "v") +#endif + +/* Interface definition used in windows.c */ +struct window_procs shim_procs = { + "shim", + (0 + | WC_ASCII_MAP + | 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_STATUSLINES), +#ifdef TEXTCOLOR + {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, /* color availability */ +#else + {1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1}, +#endif + shim_init_nhwindows, shim_player_selection, shim_askname, shim_get_nh_event, + shim_exit_nhwindows, shim_suspend_nhwindows, shim_resume_nhwindows, + shim_create_nhwindow, shim_clear_nhwindow, shim_display_nhwindow, + shim_destroy_nhwindow, shim_curs, shim_putstr, genl_putmixed, + shim_display_file, shim_start_menu, shim_add_menu, shim_end_menu, + shim_select_menu, shim_message_menu, shim_update_inventory, shim_mark_synch, + shim_wait_synch, +#ifdef CLIPPING + shim_cliparound, +#endif +#ifdef POSITIONBAR + shim_update_positionbar, +#endif + shim_print_glyph, shim_raw_print, shim_raw_print_bold, shim_nhgetch, + shim_nh_poskey, shim_nhbell, shim_doprev_message, shim_yn_function, + shim_getlin, shim_get_ext_cmd, shim_number_pad, shim_delay_output, +#ifdef CHANGE_COLOR /* the Mac uses a palette device */ + shim_change_color, +#ifdef MAC + shim_change_background, set_shim_font_name, +#endif + shim_get_color_string, +#endif + + /* other defs that really should go away (they're tty specific) */ + shim_start_screen, shim_end_screen, genl_outrip, + shim_preference_update, + shim_getmsghistory, shim_putmsghistory, + shim_status_init, + genl_status_finish, genl_status_enablefield, +#ifdef STATUS_HILITES + shim_status_update, +#else + genl_status_update, +#endif + genl_can_suspend_yes, +}; + +#ifdef __EMSCRIPTEN__ +/* convert the C callback to a JavaScript callback */ +EM_JS(void, local_callback, (const char *cb_name, const char *shim_name, void *ret_ptr, const char *fmt_str, void *args), { + // Asyncify.handleAsync() is the more logical choice here; however, the stack unrolling in Asyncify is performed by + // function call analysis during compilation. Since we are using an indirect callback (cb_name), it can't predict the stack + // 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 + let name = UTF8ToString(shim_name); + let fmt = UTF8ToString(fmt_str); + let cbName = UTF8ToString(cb_name); + // console.log("local_callback:", cbName, fmt, name); + + // get pointer / type conversion helpers + let getPointerValue = globalThis.nethackGlobal.helpers.getPointerValue; + let setPointerValue = globalThis.nethackGlobal.helpers.setPointerValue; + + reentryMutexLock(name); + + let argTypes = fmt.split(""); + let retType = argTypes.shift(); + + // build array of JavaScript args from WASM parameters + let jsArgs = []; + for (let i = 0; i < argTypes.length; i++) { + let ptr = args + (4*i); + let val = getArg(name, ptr, argTypes[i]); + jsArgs.push(val); + } + + // do the callback + let userCallback = globalThis[cbName]; + runJsEventLoop(() => userCallback.call(this, name, ... jsArgs)).then((retVal) => { + // save the return value + setPointerValue(name, ret_ptr, retType, retVal); + // return + setTimeout(() => { + reentryMutexUnlock(); + wakeUp(); + }, 0); + }); + + 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); + }); + } + + 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`); + } + globalThis.nethackGlobal.shimFunctionRunning = name; + } + + function reentryMutexUnlock() { + globalThis.nethackGlobal.shimFunctionRunning = null; + } + }); +}) +#endif /* __EMSCRIPTEN__ */ + +#endif /* SHIM_GRAPHICS */ diff --git a/win/tty/getline.c b/win/tty/getline.c index 754dbeff4..8925f6b4a 100644 --- a/win/tty/getline.c +++ b/win/tty/getline.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 getline.c $NHDT-Date: 1543830347 2018/12/03 09:45:47 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.37 $ */ +/* NetHack 3.7 getline.c $NHDT-Date: 1596498343 2020/08/03 23:45:43 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.44 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2006. */ /* NetHack may be freely redistributed. See license for details. */ @@ -52,10 +52,10 @@ getlin_hook_proc hook; struct WinDesc *cw = wins[WIN_MESSAGE]; boolean doprev = 0; - if (ttyDisplay->toplin == 1 && !(cw->flags & WIN_STOP)) + if (ttyDisplay->toplin == TOPLINE_NEED_MORE && !(cw->flags & WIN_STOP)) more(); cw->flags &= ~WIN_STOP; - ttyDisplay->toplin = 3; /* special prompt state */ + ttyDisplay->toplin = TOPLINE_SPECIAL_PROMPT; ttyDisplay->inread++; /* issue the prompt */ @@ -193,7 +193,7 @@ getlin_hook_proc hook; } else tty_nhbell(); } - ttyDisplay->toplin = 2; /* nonempty, no --More-- required */ + ttyDisplay->toplin = TOPLINE_NON_EMPTY; ttyDisplay->inread--; clear_nhwindow(WIN_MESSAGE); /* clean up after ourselves */ diff --git a/win/tty/termcap.c b/win/tty/termcap.c index 37de8ff98..d13eca893 100644 --- a/win/tty/termcap.c +++ b/win/tty/termcap.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 termcap.c $NHDT-Date: 1562056615 2019/07/02 08:36:55 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.31 $ */ +/* NetHack 3.7 termcap.c $NHDT-Date: 1596498343 2020/08/03 23:45:43 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.39 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Pasi Kallinen, 2018. */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/win/tty/topl.c b/win/tty/topl.c index 042d1fd20..1802d6944 100644 --- a/win/tty/topl.c +++ b/win/tty/topl.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 topl.c $NHDT-Date: 1560608320 2019/06/15 14:18:40 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.47 $ */ +/* NetHack 3.7 topl.c $NHDT-Date: 1596498344 2020/08/03 23:45:44 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.72 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2009. */ /* NetHack may be freely redistributed. See license for details. */ @@ -138,8 +138,8 @@ const char *str; end_glyphout(); /* in case message printed during graphics output */ putsyms(str); cl_end(); - ttyDisplay->toplin = 1; - if (ttyDisplay->cury && otoplin != 3) + ttyDisplay->toplin = TOPLINE_NEED_MORE; + if (ttyDisplay->cury && otoplin != TOPLINE_SPECIAL_PROMPT) more(); } @@ -151,7 +151,7 @@ const char *str; struct WinDesc *cw = wins[WIN_MESSAGE]; if (!(cw->flags & WIN_STOP)) { - if (ttyDisplay->cury && ttyDisplay->toplin == 2) + if (ttyDisplay->cury && ttyDisplay->toplin == TOPLINE_NON_EMPTY) tty_clear_nhwindow(WIN_MESSAGE); cw->curx = cw->cury = 0; @@ -159,8 +159,8 @@ const char *str; cl_end(); addtopl(str); - if (ttyDisplay->cury && ttyDisplay->toplin != 3) - ttyDisplay->toplin = 2; + if (ttyDisplay->cury && ttyDisplay->toplin != TOPLINE_SPECIAL_PROMPT) + ttyDisplay->toplin = TOPLINE_NON_EMPTY; } } @@ -196,7 +196,7 @@ const char *s; tty_curs(BASE_WINDOW, cw->curx + 1, cw->cury); putsyms(s); cl_end(); - ttyDisplay->toplin = 1; + ttyDisplay->toplin = TOPLINE_NEED_MORE; } void @@ -204,12 +204,15 @@ more() { struct WinDesc *cw = wins[WIN_MESSAGE]; - /* avoid recursion -- only happens from interrupts */ - if (ttyDisplay->inmore++) - return; if (iflags.debug_fuzzer) return; + /* avoid recursion -- only happens from interrupts */ + if (ttyDisplay->inmore) + return; + + ttyDisplay->inmore++; + if (ttyDisplay->toplin) { tty_curs(BASE_WINDOW, cw->curx + 1, cw->cury); if (cw->curx >= CO - 8) @@ -236,7 +239,7 @@ more() home(); cl_end(); } - ttyDisplay->toplin = 0; + ttyDisplay->toplin = TOPLINE_EMPTY; ttyDisplay->inmore = 0; } @@ -252,7 +255,7 @@ register const char *bp; /* If there is room on the line, print message on same line */ /* But messages like "You die..." deserve their own line */ n0 = strlen(bp); - if ((ttyDisplay->toplin == 1 || (cw->flags & WIN_STOP)) + if ((ttyDisplay->toplin == TOPLINE_NEED_MORE || (cw->flags & WIN_STOP)) && cw->cury == 0 && n0 + (int) strlen(g.toplines) + 3 < CO - 8 /* room for --More-- */ && (notdied = strncmp(bp, "You die", 7)) != 0) { @@ -263,9 +266,9 @@ register const char *bp; addtopl(bp); return; } else if (!(cw->flags & WIN_STOP)) { - if (ttyDisplay->toplin == 1) { + if (ttyDisplay->toplin == TOPLINE_NEED_MORE) { more(); - } else if (cw->cury) { /* for when flags.toplin == 2 && cury > 1 */ + } else if (cw->cury) { /* for toplin == TOPLINE_NON_EMPTY && cury > 1 */ docorner(1, cw->cury + 1); /* reset cury = 0 if redraw screen */ cw->curx = cw->cury = 0; /* from home--cls() & docorner(1,n) */ } @@ -309,6 +312,7 @@ char c; if (ttyDisplay->curx == 0 && ttyDisplay->cury > 0) tty_curs(BASE_WINDOW, CO, (int) ttyDisplay->cury - 1); backsp(); + nhassert(ttyDisplay->curx > 0); ttyDisplay->curx--; cw->curx = ttyDisplay->curx; return; @@ -381,10 +385,10 @@ char def; char prompt[BUFSZ]; yn_number = 0L; - if (ttyDisplay->toplin == 1 && !(cw->flags & WIN_STOP)) + if (ttyDisplay->toplin == TOPLINE_NEED_MORE && !(cw->flags & WIN_STOP)) more(); cw->flags &= ~WIN_STOP; - ttyDisplay->toplin = 3; /* special prompt state */ + ttyDisplay->toplin = TOPLINE_SPECIAL_PROMPT; ttyDisplay->inread++; if (resp) { char *rb, respbuf[QBUFSZ]; @@ -531,7 +535,7 @@ char def; dumplogmsg(g.toplines); #endif ttyDisplay->inread--; - ttyDisplay->toplin = 2; + ttyDisplay->toplin = TOPLINE_NON_EMPTY; if (ttyDisplay->intr) ttyDisplay->intr--; if (wins[WIN_MESSAGE]->cury) @@ -686,6 +690,13 @@ boolean restoring_msghist; } if (msg) { + /* Caller is asking us to remember a top line that needed more. + Should we call more? This can happen when the player has set + iflags.force_invmenu and they attempt to shoot with nothing in + the quiver. */ + if (ttyDisplay && ttyDisplay->toplin == TOPLINE_NEED_MORE) + ttyDisplay->toplin = TOPLINE_NON_EMPTY; + /* move most recent message to history, make this become most recent */ remember_topl(); Strcpy(g.toplines, msg); @@ -693,6 +704,9 @@ boolean restoring_msghist; dumplogmsg(g.toplines); #endif } else if (snapshot_mesgs) { + nhassert(ttyDisplay == NULL || + ttyDisplay->toplin != TOPLINE_NEED_MORE); + /* done putting arbitrary messages in; put the snapshot ones back */ for (idx = 0; snapshot_mesgs[idx]; ++idx) { remember_topl(); diff --git a/win/tty/wintty.c b/win/tty/wintty.c index bf63421ed..e68e40272 100644 --- a/win/tty/wintty.c +++ b/win/tty/wintty.c @@ -1,4 +1,4 @@ - /* NetHack 3.6 wintty.c $NHDT-Date: 1587110794 2020/04/17 08:06:34 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.256 $ */ +/* NetHack 3.7 wintty.c $NHDT-Date: 1608861214 2020/12/25 01:53:34 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.264 $ */ /* Copyright (c) David Cohrs, 1991 */ /* NetHack may be freely redistributed. See license for details. */ @@ -294,7 +294,7 @@ const char *mesg; /*NOTREACHED*/ } -#if defined(SIGWINCH) && defined(CLIPPING) +#if defined(SIGWINCH) && defined(CLIPPING) && !defined(NO_SIGNAL) static void FDECL(winch_handler, (int)); /* @@ -348,7 +348,7 @@ int sig_unused UNUSED; new_status_window(); if (u.ux) { i = ttyDisplay->toplin; - ttyDisplay->toplin = 0; + ttyDisplay->toplin = TOPLINE_EMPTY; docrt(); bot(); ttyDisplay->toplin = i; @@ -369,7 +369,7 @@ int sig_unused UNUSED; } } } -#endif +#endif /* SIGWINCH && CLIPPING && !NO_SIGNAL */ /* destroy and recreate status window; extracted from winch_handler() and augmented for use by tty_preference_update() */ @@ -436,7 +436,7 @@ char **argv UNUSED; /* set up tty descriptor */ ttyDisplay = (struct DisplayDesc *) alloc(sizeof (struct DisplayDesc)); - ttyDisplay->toplin = 0; + ttyDisplay->toplin = TOPLINE_EMPTY; ttyDisplay->rows = hgt; ttyDisplay->cols = wid; ttyDisplay->curx = ttyDisplay->cury = 0; @@ -1652,12 +1652,12 @@ winid window; switch (cw->type) { case NHW_MESSAGE: - if (ttyDisplay->toplin) { + if (ttyDisplay->toplin != TOPLINE_EMPTY) { home(); cl_end(); if (cw->cury) docorner(1, cw->cury + 1); - ttyDisplay->toplin = 0; + ttyDisplay->toplin = TOPLINE_EMPTY; } break; case NHW_STATUS: @@ -1922,7 +1922,12 @@ struct WinDesc *cw; if (n > 0) /* at least one group accelerator found */ for (rp = gacc, curr = cw->mlist; curr; curr = curr->next) - if (curr->gselector && curr->gselector != curr->selector + if (curr->gselector + && (curr->gselector != curr->selector + /* '$' is both a selector "letter" and a group + accelerator; including it in gacc allows gold to + be selected via group when not on current page */ + || curr->gselector == GOLD_SYM) && !index(gacc, curr->gselector) && (cw->how == PICK_ANY || gcnt[GSELIDX(curr->gselector)] == 1)) { @@ -2353,12 +2358,13 @@ boolean blocking; /* with ttys, all windows are blocking */ switch (cw->type) { case NHW_MESSAGE: - if (ttyDisplay->toplin == 1) { + if (ttyDisplay->toplin == TOPLINE_NEED_MORE) { more(); - ttyDisplay->toplin = 1; /* more resets this */ + ttyDisplay->toplin = TOPLINE_NEED_MORE; /* more resets this */ tty_clear_nhwindow(window); + nhassert(ttyDisplay->toplin == TOPLINE_EMPTY); } else - ttyDisplay->toplin = 0; + ttyDisplay->toplin = TOPLINE_EMPTY; cw->curx = cw->cury = 0; if (!cw->active) iflags.window_inited = TRUE; @@ -2366,8 +2372,8 @@ boolean blocking; /* with ttys, all windows are blocking */ case NHW_MAP: end_glyphout(); if (blocking) { - if (!ttyDisplay->toplin) - ttyDisplay->toplin = 1; + if (ttyDisplay->toplin != TOPLINE_EMPTY) + ttyDisplay->toplin = TOPLINE_NEED_MORE; tty_display_nhwindow(WIN_MESSAGE, TRUE); return; } @@ -2397,7 +2403,7 @@ boolean blocking; /* with ttys, all windows are blocking */ cw->offx = 0; if (cw->type == NHW_MENU) cw->offy = 0; - if (ttyDisplay->toplin == 1) + if (ttyDisplay->toplin == TOPLINE_NEED_MORE) tty_display_nhwindow(WIN_MESSAGE, TRUE); #ifdef H2344_BROKEN if (cw->maxrow >= (int) ttyDisplay->rows @@ -2413,7 +2419,7 @@ boolean blocking; /* with ttys, all windows are blocking */ cl_eos(); } else clear_screen(); - ttyDisplay->toplin = 0; + ttyDisplay->toplin = TOPLINE_EMPTY; } else { if (WIN_MESSAGE != WIN_ERR) tty_clear_nhwindow(WIN_MESSAGE); @@ -2442,8 +2448,9 @@ winid window; switch (cw->type) { case NHW_MESSAGE: - if (ttyDisplay->toplin) + if (ttyDisplay->toplin != TOPLINE_EMPTY) tty_display_nhwindow(WIN_MESSAGE, TRUE); + nhassert(ttyDisplay->toplin == TOPLINE_EMPTY); /*FALLTHRU*/ case NHW_STATUS: case NHW_BASE: @@ -3194,10 +3201,11 @@ const char *mesg; response to a prompt, we'll assume that the display is up to date */ tty_putstr(WIN_MESSAGE, 0, mesg); /* if `mesg' didn't wrap (triggering --More--), force --More-- now */ - if (ttyDisplay->toplin == 1) { + if (ttyDisplay->toplin == TOPLINE_NEED_MORE) { more(); - ttyDisplay->toplin = 1; /* more resets this */ + ttyDisplay->toplin = TOPLINE_NEED_MORE; /* more resets this */ tty_clear_nhwindow(WIN_MESSAGE); + nhassert(ttyDisplay->toplin == TOPLINE_EMPTY); } /* normally means skip further messages, but in this case it means cancel the current prompt; any other messages should @@ -3237,7 +3245,7 @@ tty_wait_synch() (void) fflush(stdout); } else if (ttyDisplay->inread > g.program_state.gameover) { /* this can only happen if we were reading and got interrupted */ - ttyDisplay->toplin = 3; + ttyDisplay->toplin = TOPLINE_SPECIAL_PROMPT; /* do this twice; 1st time gets the Quit? message again */ (void) tty_doprev_message(); (void) tty_doprev_message(); @@ -3407,15 +3415,19 @@ int x, y; */ void -tty_print_glyph(window, x, y, glyph, bkglyph) +tty_print_glyph(window, x, y, glyph, bkglyph, glyphmod) winid window; xchar x, y; +#ifdef TTY_TILES_ESCCODES int glyph; +#else +int glyph UNUSED; +#endif int bkglyph UNUSED; +unsigned *glyphmod; /* don't mark UNUSED as we need to revisit */ { - int ch; boolean inverse_on = FALSE; - int color; + int ch, color; unsigned special; HUPSKIP(); @@ -3425,8 +3437,10 @@ int bkglyph UNUSED; return; } #endif - /* map glyph to character and color */ - (void) mapglyph(glyph, &ch, &color, &special, x, y, 0); + /* get glyph ttychar, color, and special flags */ + ch = (int) glyphmod[GM_TTYCHAR]; + color = (int) glyphmod[GM_COLOR]; + special = glyphmod[GM_FLAGS]; print_vt_code2(AVTC_SELECT_WINDOW, window); @@ -3443,7 +3457,14 @@ int bkglyph UNUSED; #endif #ifdef TEXTCOLOR - if (color != ttyDisplay->color) { + if (iflags.wizmgender && (special & MG_FEMALE) && iflags.use_inverse) { + if (ttyDisplay->color != NO_COLOR) + term_end_color(); + term_start_attr(ATR_INVERSE); + inverse_on = TRUE; + ttyDisplay->color = CLR_RED; + term_start_color(ttyDisplay->color); + } else if (color != ttyDisplay->color) { if (ttyDisplay->color != NO_COLOR) term_end_color(); ttyDisplay->color = color; @@ -3570,8 +3591,9 @@ tty_nhgetch() i = '\033'; /* map NUL to ESC since nethack doesn't expect NUL */ else if (i == EOF) i = '\033'; /* same for EOF */ - if (ttyDisplay && ttyDisplay->toplin == 1) - ttyDisplay->toplin = 2; + /* topline has been seen - we can clear need for more */ + if (ttyDisplay && ttyDisplay->toplin == TOPLINE_NEED_MORE) + ttyDisplay->toplin = TOPLINE_NON_EMPTY; #ifdef TTY_TILES_ESCCODES { /* hack to force output of the window select code */ @@ -3592,7 +3614,11 @@ tty_nhgetch() /*ARGSUSED*/ int tty_nh_poskey(x, y, mod) +#if defined(WIN32CON) int *x, *y, *mod; +#else +int *x UNUSED, *y UNUSED, *mod UNUSED; +#endif { int i; @@ -3609,13 +3635,10 @@ int *x, *y, *mod; i = ntposkey(x, y, mod); if (!i && mod && (*mod == 0 || *mod == EOF)) i = '\033'; /* map NUL or EOF to ESC, nethack doesn't expect either */ - if (ttyDisplay && ttyDisplay->toplin == 1) - ttyDisplay->toplin = 2; + /* topline has been seen - we can clear need for more */ + if (ttyDisplay && ttyDisplay->toplin == TOPLINE_NEED_MORE) + ttyDisplay->toplin = TOPLINE_NON_EMPTY; #else /* !WIN32CON */ - nhUse(x); - nhUse(y); - nhUse(mod); - i = tty_nhgetch(); #endif /* ?WIN32CON */ return i; diff --git a/win/win32/NetHackW.c b/win/win32/NetHackW.c index 497e5274a..b86109500 100644 --- a/win/win32/NetHackW.c +++ b/win/win32/NetHackW.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 winhack.c $NHDT-Date: 1449488876 2015/12/07 11:47:56 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.44 $ */ +/* NetHack 3.7 winhack.c $NHDT-Date: 1596498365 2020/08/03 23:46:05 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.72 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/win/win32/mhaskyn.c b/win/win32/mhaskyn.c index 396025fb0..bcbf48a97 100644 --- a/win/win32/mhaskyn.c +++ b/win/win32/mhaskyn.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 mhaskyn.c $NHDT-Date: 1432512812 2015/05/25 00:13:32 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ */ +/* NetHack 3.7 mhaskyn.c $NHDT-Date: 1596498346 2020/08/03 23:45:46 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.11 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/win/win32/mhaskyn.h b/win/win32/mhaskyn.h index 700107a41..2591f34dd 100644 --- a/win/win32/mhaskyn.h +++ b/win/win32/mhaskyn.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 mhaskyn.h $NHDT-Date: 1432512811 2015/05/25 00:13:31 $ $NHDT-Branch: master $:$NHDT-Revision: 1.8 $ */ +/* NetHack 3.7 mhaskyn.h $NHDT-Date: 1596498347 2020/08/03 23:45:47 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.9 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/win/win32/mhdlg.c b/win/win32/mhdlg.c index 732b50698..c6c747ff9 100644 --- a/win/win32/mhdlg.c +++ b/win/win32/mhdlg.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 mhdlg.c $NHDT-Date: 1544695946 2018/12/13 10:12:26 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.30 $ */ +/* NetHack 3.7 mhdlg.c $NHDT-Date: 1596498347 2020/08/03 23:45:47 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.36 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/win/win32/mhdlg.h b/win/win32/mhdlg.h index c028fc82b..0b08e8fcb 100644 --- a/win/win32/mhdlg.h +++ b/win/win32/mhdlg.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 mhdlg.h $NHDT-Date: 1432512812 2015/05/25 00:13:32 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ */ +/* NetHack 3.7 mhdlg.h $NHDT-Date: 1596498348 2020/08/03 23:45:48 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.12 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/win/win32/mhfont.c b/win/win32/mhfont.c index 18e09082e..8fb512496 100644 --- a/win/win32/mhfont.c +++ b/win/win32/mhfont.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 mhfont.c $NHDT-Date: 1432512812 2015/05/25 00:13:32 $ $NHDT-Branch: master $:$NHDT-Revision: 1.23 $ */ +/* NetHack 3.7 mhfont.c $NHDT-Date: 1596498349 2020/08/03 23:45:49 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.29 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/win/win32/mhfont.h b/win/win32/mhfont.h index 9402d54a9..5c4c8f4e1 100644 --- a/win/win32/mhfont.h +++ b/win/win32/mhfont.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 mhfont.h $NHDT-Date: 1432512810 2015/05/25 00:13:30 $ $NHDT-Branch: master $:$NHDT-Revision: 1.12 $ */ +/* NetHack 3.7 mhfont.h $NHDT-Date: 1596498350 2020/08/03 23:45:50 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.17 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/win/win32/mhinput.c b/win/win32/mhinput.c index 4a9b15b61..de67b08e5 100644 --- a/win/win32/mhinput.c +++ b/win/win32/mhinput.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 mhinput.c $NHDT-Date: 1432512810 2015/05/25 00:13:30 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ */ +/* NetHack 3.7 mhinput.c $NHDT-Date: 1596498350 2020/08/03 23:45:50 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.13 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/win/win32/mhinput.h b/win/win32/mhinput.h index f8e58f054..67ff97347 100644 --- a/win/win32/mhinput.h +++ b/win/win32/mhinput.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 mhinput.h $NHDT-Date: 1432512812 2015/05/25 00:13:32 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ */ +/* NetHack 3.7 mhinput.h $NHDT-Date: 1596498351 2020/08/03 23:45:51 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.11 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/win/win32/mhmain.c b/win/win32/mhmain.c index a0c158e37..1d9b84c10 100644 --- a/win/win32/mhmain.c +++ b/win/win32/mhmain.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 mhmain.c $NHDT-Date: 1432512811 2015/05/25 00:13:31 $ $NHDT-Branch: master $:$NHDT-Revision: 1.62 $ */ +/* NetHack 3.7 mhmain.c $NHDT-Date: 1596498352 2020/08/03 23:45:52 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.76 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/win/win32/mhmain.h b/win/win32/mhmain.h index 9ace851ea..e25bd5145 100644 --- a/win/win32/mhmain.h +++ b/win/win32/mhmain.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 mhmain.h $NHDT-Date: 1432512811 2015/05/25 00:13:31 $ $NHDT-Branch: master $:$NHDT-Revision: 1.14 $ */ +/* NetHack 3.7 mhmain.h $NHDT-Date: 1596498352 2020/08/03 23:45:52 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.15 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/win/win32/mhmap.c b/win/win32/mhmap.c index e13b67ac0..4a84e190a 100644 --- a/win/win32/mhmap.c +++ b/win/win32/mhmap.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 mhmap.c $NHDT-Date: 1435002695 2015/06/22 19:51:35 $ $NHDT-Branch: master $:$NHDT-Revision: 1.56 $ */ +/* NetHack 3.7 mhmap.c $NHDT-Date: 1596498353 2020/08/03 23:45:53 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.85 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ @@ -37,8 +37,8 @@ typedef struct mswin_nethack_map_window { int map[COLNO][ROWNO]; /* glyph map */ int bkmap[COLNO][ROWNO]; /* backround glyph map */ + unsigned glyphmod[COLNO][ROWNO][NUM_GLYPHMOD]; boolean mapDirty[COLNO][ROWNO]; /* dirty flag for map */ - int mapMode; /* current map mode */ boolean bAsciiMode; /* switch ASCII/tiled mode */ boolean bFitToScreenMode; /* switch Fit map to screen mode on/off */ @@ -86,7 +86,7 @@ static void nhcoord2display(PNHMapWindow data, int x, int y, LPRECT lpOut); static void paint(PNHMapWindow data, int i, int j); static void dirtyAll(PNHMapWindow data); static void dirty(PNHMapWindow data, int i, int j); -static void setGlyph(PNHMapWindow data, int i, int j, int fg, int bg); +static void setGlyph(PNHMapWindow data, int i, int j, int fg, int bg, unsigned *glyphmod); static void clearAll(PNHMapWindow data); #if (VERSION_MAJOR < 4) && (VERSION_MINOR < 4) && (PATCHLEVEL < 2) @@ -639,7 +639,7 @@ onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) case MSNH_MSG_PRINT_GLYPH: { PMSNHMsgPrintGlyph msg_data = (PMSNHMsgPrintGlyph) lParam; setGlyph(data, msg_data->x, msg_data->y, - msg_data->glyph, msg_data->bkglyph); + msg_data->glyph, msg_data->bkglyph, msg_data->glyphmod); } break; case MSNH_MSG_CLIPAROUND: { @@ -708,8 +708,10 @@ onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) PMSNHMsgGetText msg_data = (PMSNHMsgGetText) lParam; size_t index; int col, row; +#if 0 int color; - unsigned special; + unsigned special = 0U; +#endif int mgch; index = 0; @@ -717,13 +719,14 @@ onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) for (col = 0; col < COLNO; col++) { if (index >= msg_data->max_size) break; - if (data->map[col][row] == NO_GLYPH) { + if (data->map[col][row] == NO_GLYPH) mgch = ' '; - } else { - (void) mapglyph(data->map[col][row], &mgch, &color, - &special, col, row, 0); - } - msg_data->buffer[index] = mgch; + +// } else { +// (void) mapglyph(data->map[col][row], &mgch, &color, +// &special, col, row, 0); +// } + msg_data->buffer[index] = data->glyphmod[col][row][GM_TTYCHAR]; index++; } if (index >= msg_data->max_size - 1) @@ -785,9 +788,9 @@ paintTile(PNHMapWindow data, int i, int j, RECT * rect) int glyph, bkglyph; int layer; #ifdef USE_PILEMARK - int color; - unsigned special; - int mgch; +// int color; +// unsigned special = 0U; +// int mgch; #endif layer = 0; glyph = data->map[i][j]; @@ -811,8 +814,16 @@ paintTile(PNHMapWindow data, int i, int j, RECT * rect) layer++; } +// (void) mapglyph(glyph, &mgch, &color, &special, i, j, 0); +// mgch = (int) data.glyphmod[GM_TTYCHAR]; +// color = (int) data.glyphmod[GM_COLOR]; +// special = glyphmod[GM_FLAGS]; + if ((glyph != NO_GLYPH) && (glyph != bkglyph)) { + /* rely on NetHack core helper routine */ ntile = glyph2tile[glyph]; + if (data->glyphmod[i][j][GM_FLAGS] & MG_FEMALE) + ntile++; t_x = TILEBMP_X(ntile); t_y = TILEBMP_Y(ntile); @@ -834,9 +845,9 @@ paintTile(PNHMapWindow data, int i, int j, RECT * rect) #ifdef USE_PILEMARK /* rely on NetHack core helper routine */ - (void) mapglyph(data->map[i][j], &mgch, &color, &special, - i, j, 0); - if ((glyph != NO_GLYPH) && (special & MG_PET) +// (void) mapglyph(data->map[i][j], &mgch, &color, &special, +// i, j, 0); + if ((glyph != NO_GLYPH) && (data->glyphmod[i][j][GM_FLAGS] & MG_PET) #else if ((glyph != NO_GLYPH) && glyph_is_pet(glyph) #endif @@ -859,7 +870,7 @@ paintTile(PNHMapWindow data, int i, int j, RECT * rect) DeleteDC(hdcPetMark); } #ifdef USE_PILEMARK - if ((glyph != NO_GLYPH) && (special & MG_OBJPILE) + if ((glyph != NO_GLYPH) && (data->glyphmod[i][j][GM_FLAGS] & MG_OBJPILE) && iflags.hilite_pile) { /* apply pilemark transparently over other image */ HDC hdcPileMark; @@ -893,8 +904,8 @@ paintGlyph(PNHMapWindow data, int i, int j, RECT * rect) char ch; WCHAR wch; int color; - unsigned special; - int mgch; +// unsigned special; +// int mgch; HBRUSH back_brush; COLORREF OldFg; @@ -909,11 +920,12 @@ paintGlyph(PNHMapWindow data, int i, int j, RECT * rect) OldFg = SetTextColor(hDC, nhcolor_to_RGB(color)); #else /* rely on NetHack core helper routine */ - (void) mapglyph(data->map[i][j], &mgch, &color, - &special, i, j, 0); - ch = (char) mgch; - if (((special & MG_PET) && iflags.hilite_pet) - || ((special & (MG_DETECT | MG_BW_LAVA)) +// (void) mapglyph(data->map[i][j], &mgch, &color, +// &special, i, j, 0); + ch = (char) data->glyphmod[i][j][GM_TTYCHAR]; + color = (int) data->glyphmod[i][j][GM_COLOR]; + if (((data->glyphmod[i][j][GM_FLAGS] & MG_PET) && iflags.hilite_pet) + || ((data->glyphmod[i][j][GM_FLAGS] & (MG_DETECT | MG_BW_LAVA)) && iflags.use_inverse)) { back_brush = CreateSolidBrush(nhcolor_to_RGB(CLR_GRAY)); @@ -972,13 +984,19 @@ paintGlyph(PNHMapWindow data, int i, int j, RECT * rect) } } -static void setGlyph(PNHMapWindow data, int i, int j, int fg, int bg) +static void setGlyph(PNHMapWindow data, int i, int j, int fg, int bg, unsigned *glyphmod) { - if ((data->map[i][j] != fg) || (data->bkmap[i][j] != bg)) { + int gm; + + if ((data->map[i][j] != fg) || (data->bkmap[i][j] != bg) + || data->glyphmod[i][j][GM_TTYCHAR] != glyphmod[GM_TTYCHAR] + || data->glyphmod[i][j][GM_COLOR] != glyphmod[GM_COLOR] + || data->glyphmod[i][j][GM_FLAGS] != glyphmod[GM_FLAGS]) { data->map[i][j] = fg; data->bkmap[i][j] = bg; data->mapDirty[i][j] = TRUE; - + for (gm = 0; gm < NUM_GLYPHMOD; ++gm) + data->glyphmod[i][j][gm] = glyphmod[gm]; RECT rect; nhcoord2display(data, i, j, &rect); InvalidateRect(data->hWnd, &rect, FALSE); @@ -991,6 +1009,9 @@ static void clearAll(PNHMapWindow data) for (int y = 0; y < ROWNO; y++) { data->map[x][y] = NO_GLYPH; data->bkmap[x][y] = NO_GLYPH; + data->glyphmod[x][y][GM_TTYCHAR] = ' '; + data->glyphmod[x][y][GM_COLOR] = NO_COLOR; + data->glyphmod[x][y][GM_FLAGS] = 0U; data->mapDirty[x][y] = TRUE; } InvalidateRect(data->hWnd, NULL, FALSE); diff --git a/win/win32/mhmap.h b/win/win32/mhmap.h index 695749431..240d33bd3 100644 --- a/win/win32/mhmap.h +++ b/win/win32/mhmap.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 mhmap.h $NHDT-Date: 1432512810 2015/05/25 00:13:30 $ $NHDT-Branch: master $:$NHDT-Revision: 1.15 $ */ +/* NetHack 3.7 mhmap.h $NHDT-Date: 1596498354 2020/08/03 23:45:54 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.17 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/win/win32/mhmenu.c b/win/win32/mhmenu.c index 0150e559c..0e5ba537d 100644 --- a/win/win32/mhmenu.c +++ b/win/win32/mhmenu.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 mhmenu.c $NHDT-Date: 1432512811 2015/05/25 00:13:31 $ $NHDT-Branch: master $:$NHDT-Revision: 1.48 $ */ +/* NetHack 3.7 mhmenu.c $NHDT-Date: 1596498354 2020/08/03 23:45:54 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.74 $ */ /* Copyright (c) Alex Kompel, 2002 */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/win/win32/mhmenu.h b/win/win32/mhmenu.h index 200dc3e15..42efb30c8 100644 --- a/win/win32/mhmenu.h +++ b/win/win32/mhmenu.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 mhmenu.h $NHDT-Date: 1432512813 2015/05/25 00:13:33 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ */ +/* NetHack 3.7 mhmenu.h $NHDT-Date: 1596498355 2020/08/03 23:45:55 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.10 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/win/win32/mhmsg.h b/win/win32/mhmsg.h index 3962fb608..431d426ca 100644 --- a/win/win32/mhmsg.h +++ b/win/win32/mhmsg.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 mhmsg.h $NHDT-Date: 1432512811 2015/05/25 00:13:31 $ $NHDT-Branch: master $:$NHDT-Revision: 1.15 $ */ +/* NetHack 3.7 mhmsg.h $NHDT-Date: 1596498356 2020/08/03 23:45:56 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.21 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ @@ -38,6 +38,7 @@ typedef struct mswin_nhmsg_print_glyph { XCHAR_P y; int glyph; int bkglyph; + int glyphmod[NUM_GLYPHMOD]; } MSNHMsgPrintGlyph, *PMSNHMsgPrintGlyph; typedef struct mswin_nhmsg_cliparound { diff --git a/win/win32/mhmsgwnd.c b/win/win32/mhmsgwnd.c index 58df28c63..c821583cc 100644 --- a/win/win32/mhmsgwnd.c +++ b/win/win32/mhmsgwnd.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 mhmsgwnd.c $NHDT-Date: 1432512812 2015/05/25 00:13:32 $ $NHDT-Branch: master $:$NHDT-Revision: 1.32 $ */ +/* NetHack 3.7 mhmsgwnd.c $NHDT-Date: 1596498357 2020/08/03 23:45:57 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.40 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ @@ -769,7 +769,7 @@ mswin_message_window_size(HWND hWnd, LPSIZE sz) sz->cx = rt.right - rt.left; sz->cy = rt.bottom - rt.top; - /* set size to accomodate MSG_VISIBLE_LINES and + /* set size to accommodate MSG_VISIBLE_LINES and horizontal scroll bar (difference between window rect and client rect */ GetClientRect(hWnd, &client_rt); diff --git a/win/win32/mhmsgwnd.h b/win/win32/mhmsgwnd.h index ac780b5eb..37a68abc8 100644 --- a/win/win32/mhmsgwnd.h +++ b/win/win32/mhmsgwnd.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 mhmsgwnd.h $NHDT-Date: 1432512810 2015/05/25 00:13:30 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ */ +/* NetHack 3.7 mhmsgwnd.h $NHDT-Date: 1596498358 2020/08/03 23:45:58 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.10 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/win/win32/mhrip.c b/win/win32/mhrip.c index a7cfcde69..84f7f7788 100644 --- a/win/win32/mhrip.c +++ b/win/win32/mhrip.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 mhrip.c $NHDT-Date: 1432512812 2015/05/25 00:13:32 $ $NHDT-Branch: master $:$NHDT-Revision: 1.19 $ */ +/* NetHack 3.7 mhrip.c $NHDT-Date: 1596498358 2020/08/03 23:45:58 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.24 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/win/win32/mhrip.h b/win/win32/mhrip.h index f463d0c85..54a74fff5 100644 --- a/win/win32/mhrip.h +++ b/win/win32/mhrip.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 mhrip.h $NHDT-Date: 1432512813 2015/05/25 00:13:33 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ */ +/* NetHack 3.7 mhrip.h $NHDT-Date: 1596498359 2020/08/03 23:45:59 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.11 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/win/win32/mhsplash.c b/win/win32/mhsplash.c index aa676c226..b53899189 100644 --- a/win/win32/mhsplash.c +++ b/win/win32/mhsplash.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 mhsplash.c $NHDT-Date: 1449751714 2015/12/10 12:48:34 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.27 $ */ +/* NetHack 3.7 mhsplash.c $NHDT-Date: 1596498360 2020/08/03 23:46:00 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.36 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/win/win32/mhstatus.c b/win/win32/mhstatus.c index 20b09f094..53d1b1a78 100644 --- a/win/win32/mhstatus.c +++ b/win/win32/mhstatus.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 mhstatus.c $NHDT-Date: 1536411224 2018/09/08 12:53:44 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.29 $ */ +/* NetHack 3.7 mhstatus.c $NHDT-Date: 1596498360 2020/08/03 23:46:00 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.35 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/win/win32/mhstatus.h b/win/win32/mhstatus.h index fc62ec423..a70a90f6e 100644 --- a/win/win32/mhstatus.h +++ b/win/win32/mhstatus.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 mhstatus.h $NHDT-Date: 1432512812 2015/05/25 00:13:32 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ */ +/* NetHack 3.7 mhstatus.h $NHDT-Date: 1596498361 2020/08/03 23:46:01 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.15 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/win/win32/mhtext.c b/win/win32/mhtext.c index 0ff816f8a..56c2a8179 100644 --- a/win/win32/mhtext.c +++ b/win/win32/mhtext.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 mhtext.c $NHDT-Date: 1432512813 2015/05/25 00:13:33 $ $NHDT-Branch: master $:$NHDT-Revision: 1.25 $ */ +/* NetHack 3.7 mhtext.c $NHDT-Date: 1596498362 2020/08/03 23:46:02 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.31 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/win/win32/mhtext.h b/win/win32/mhtext.h index edcea4be8..bacc47643 100644 --- a/win/win32/mhtext.h +++ b/win/win32/mhtext.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 mhtext.h $NHDT-Date: 1432512811 2015/05/25 00:13:31 $ $NHDT-Branch: master $:$NHDT-Revision: 1.9 $ */ +/* NetHack 3.7 mhtext.h $NHDT-Date: 1596498363 2020/08/03 23:46:03 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.10 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ diff --git a/win/win32/mswproc.c b/win/win32/mswproc.c index ab5fa0095..efebf6160 100644 --- a/win/win32/mswproc.c +++ b/win/win32/mswproc.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 mswproc.c $NHDT-Date: 1575245201 2019/12/02 00:06:41 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.137 $ */ +/* NetHack 3.7 mswproc.c $NHDT-Date: 1596498364 2020/08/03 23:46:04 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.153 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ @@ -1281,7 +1281,7 @@ mswin_cliparound(int x, int y) } /* -print_glyph(window, x, y, glyph, bkglyph) +print_glyph(window, x, y, glyph, bkglyph, glyphmod) -- Print the glyph at (x,y) on the given window. Glyphs are integers at the interface, mapped to whatever the window- port wants (symbol, font, color, attributes, ...there's @@ -1290,12 +1290,15 @@ print_glyph(window, x, y, glyph, bkglyph) graphical or tiled environments to allow the depiction to fall against a background consistent with the grid around x,y. + -- glyphmod provides extended information about the glyph + that window ports can use to enhance the display in + various ways. */ void -mswin_print_glyph(winid wid, XCHAR_P x, XCHAR_P y, int glyph, int bkglyph) +mswin_print_glyph(winid wid, XCHAR_P x, XCHAR_P y, int glyph, int bkglyph, unsigned *glyphmod) { - logDebug("mswin_print_glyph(%d, %d, %d, %d, %d)\n", wid, x, y, glyph, bkglyph); + logDebug("mswin_print_glyph(%d, %d, %d, %d, %d, %lu)\n", wid, x, y, glyph, bkglyph, glyphmod); if ((wid >= 0) && (wid < MAXWINDOWS) && (GetNHApp()->windowlist[wid].win != NULL)) { @@ -1306,6 +1309,9 @@ mswin_print_glyph(winid wid, XCHAR_P x, XCHAR_P y, int glyph, int bkglyph) data.y = y; data.glyph = glyph; data.bkglyph = bkglyph; + data.glyphmod[GM_TTYCHAR] = glyphmod[GM_TTYCHAR]; + data.glyphmod[GM_COLOR] = glyphmod[GM_COLOR]; + data.glyphmod[GM_FLAGS] = glyphmod[GM_FLAGS]; SendMessage(GetNHApp()->windowlist[wid].win, WM_MSNH_COMMAND, (WPARAM) MSNH_MSG_PRINT_GLYPH, (LPARAM) &data); } @@ -2796,6 +2802,8 @@ int NHMessageBox(HWND hWnd, LPCTSTR text, UINT type) { TCHAR title[MAX_LOADSTRING]; + if (g.program_state.exiting && !strcmp(text, "\n")) + text = "Press Enter to exit"; LoadString(GetNHApp()->hApp, IDS_APP_TITLE_SHORT, title, MAX_LOADSTRING); diff --git a/win/win32/vs/.gitattributes b/win/win32/vs/.gitattributes new file mode 100644 index 000000000..f9d4fff5d --- /dev/null +++ b/win/win32/vs/.gitattributes @@ -0,0 +1 @@ +* NH_filestag=(file%s_for_Visual_Studio_2017_or_2019_Community_Edition_builds) diff --git a/win/win32/vs2017/.gitignore b/win/win32/vs/.gitignore similarity index 100% rename from win/win32/vs2017/.gitignore rename to win/win32/vs/.gitignore diff --git a/win/win32/vs2017/Images/BadgeLogo.scale-100.png b/win/win32/vs/Images/BadgeLogo.scale-100.png similarity index 100% rename from win/win32/vs2017/Images/BadgeLogo.scale-100.png rename to win/win32/vs/Images/BadgeLogo.scale-100.png diff --git a/win/win32/vs2017/Images/BadgeLogo.scale-125.png b/win/win32/vs/Images/BadgeLogo.scale-125.png similarity index 100% rename from win/win32/vs2017/Images/BadgeLogo.scale-125.png rename to win/win32/vs/Images/BadgeLogo.scale-125.png diff --git a/win/win32/vs2017/Images/BadgeLogo.scale-150.png b/win/win32/vs/Images/BadgeLogo.scale-150.png similarity index 100% rename from win/win32/vs2017/Images/BadgeLogo.scale-150.png rename to win/win32/vs/Images/BadgeLogo.scale-150.png diff --git a/win/win32/vs2017/Images/BadgeLogo.scale-200.png b/win/win32/vs/Images/BadgeLogo.scale-200.png similarity index 100% rename from win/win32/vs2017/Images/BadgeLogo.scale-200.png rename to win/win32/vs/Images/BadgeLogo.scale-200.png diff --git a/win/win32/vs2017/Images/BadgeLogo.scale-400.png b/win/win32/vs/Images/BadgeLogo.scale-400.png similarity index 100% rename from win/win32/vs2017/Images/BadgeLogo.scale-400.png rename to win/win32/vs/Images/BadgeLogo.scale-400.png diff --git a/win/win32/vs2017/Images/LargeTile.scale-100.png b/win/win32/vs/Images/LargeTile.scale-100.png similarity index 100% rename from win/win32/vs2017/Images/LargeTile.scale-100.png rename to win/win32/vs/Images/LargeTile.scale-100.png diff --git a/win/win32/vs2017/Images/LargeTile.scale-125.png b/win/win32/vs/Images/LargeTile.scale-125.png similarity index 100% rename from win/win32/vs2017/Images/LargeTile.scale-125.png rename to win/win32/vs/Images/LargeTile.scale-125.png diff --git a/win/win32/vs2017/Images/LargeTile.scale-150.png b/win/win32/vs/Images/LargeTile.scale-150.png similarity index 100% rename from win/win32/vs2017/Images/LargeTile.scale-150.png rename to win/win32/vs/Images/LargeTile.scale-150.png diff --git a/win/win32/vs2017/Images/LargeTile.scale-200.png b/win/win32/vs/Images/LargeTile.scale-200.png similarity index 100% rename from win/win32/vs2017/Images/LargeTile.scale-200.png rename to win/win32/vs/Images/LargeTile.scale-200.png diff --git a/win/win32/vs2017/Images/LargeTile.scale-400.png b/win/win32/vs/Images/LargeTile.scale-400.png similarity index 100% rename from win/win32/vs2017/Images/LargeTile.scale-400.png rename to win/win32/vs/Images/LargeTile.scale-400.png diff --git a/win/win32/vs2017/Images/LockScreenLogo.scale-200.png b/win/win32/vs/Images/LockScreenLogo.scale-200.png similarity index 100% rename from win/win32/vs2017/Images/LockScreenLogo.scale-200.png rename to win/win32/vs/Images/LockScreenLogo.scale-200.png diff --git a/win/win32/vs2017/Images/SmallTile.scale-100.png b/win/win32/vs/Images/SmallTile.scale-100.png similarity index 100% rename from win/win32/vs2017/Images/SmallTile.scale-100.png rename to win/win32/vs/Images/SmallTile.scale-100.png diff --git a/win/win32/vs2017/Images/SmallTile.scale-125.png b/win/win32/vs/Images/SmallTile.scale-125.png similarity index 100% rename from win/win32/vs2017/Images/SmallTile.scale-125.png rename to win/win32/vs/Images/SmallTile.scale-125.png diff --git a/win/win32/vs2017/Images/SmallTile.scale-150.png b/win/win32/vs/Images/SmallTile.scale-150.png similarity index 100% rename from win/win32/vs2017/Images/SmallTile.scale-150.png rename to win/win32/vs/Images/SmallTile.scale-150.png diff --git a/win/win32/vs2017/Images/SmallTile.scale-200.png b/win/win32/vs/Images/SmallTile.scale-200.png similarity index 100% rename from win/win32/vs2017/Images/SmallTile.scale-200.png rename to win/win32/vs/Images/SmallTile.scale-200.png diff --git a/win/win32/vs2017/Images/SmallTile.scale-400.png b/win/win32/vs/Images/SmallTile.scale-400.png similarity index 100% rename from win/win32/vs2017/Images/SmallTile.scale-400.png rename to win/win32/vs/Images/SmallTile.scale-400.png diff --git a/win/win32/vs2017/Images/SplashScreen.scale-100.png b/win/win32/vs/Images/SplashScreen.scale-100.png similarity index 100% rename from win/win32/vs2017/Images/SplashScreen.scale-100.png rename to win/win32/vs/Images/SplashScreen.scale-100.png diff --git a/win/win32/vs2017/Images/SplashScreen.scale-125.png b/win/win32/vs/Images/SplashScreen.scale-125.png similarity index 100% rename from win/win32/vs2017/Images/SplashScreen.scale-125.png rename to win/win32/vs/Images/SplashScreen.scale-125.png diff --git a/win/win32/vs2017/Images/SplashScreen.scale-150.png b/win/win32/vs/Images/SplashScreen.scale-150.png similarity index 100% rename from win/win32/vs2017/Images/SplashScreen.scale-150.png rename to win/win32/vs/Images/SplashScreen.scale-150.png diff --git a/win/win32/vs2017/Images/SplashScreen.scale-200.png b/win/win32/vs/Images/SplashScreen.scale-200.png similarity index 100% rename from win/win32/vs2017/Images/SplashScreen.scale-200.png rename to win/win32/vs/Images/SplashScreen.scale-200.png diff --git a/win/win32/vs2017/Images/SplashScreen.scale-400.png b/win/win32/vs/Images/SplashScreen.scale-400.png similarity index 100% rename from win/win32/vs2017/Images/SplashScreen.scale-400.png rename to win/win32/vs/Images/SplashScreen.scale-400.png diff --git a/win/win32/vs2017/Images/Square150x150Logo.scale-100.png b/win/win32/vs/Images/Square150x150Logo.scale-100.png similarity index 100% rename from win/win32/vs2017/Images/Square150x150Logo.scale-100.png rename to win/win32/vs/Images/Square150x150Logo.scale-100.png diff --git a/win/win32/vs2017/Images/Square150x150Logo.scale-125.png b/win/win32/vs/Images/Square150x150Logo.scale-125.png similarity index 100% rename from win/win32/vs2017/Images/Square150x150Logo.scale-125.png rename to win/win32/vs/Images/Square150x150Logo.scale-125.png diff --git a/win/win32/vs2017/Images/Square150x150Logo.scale-150.png b/win/win32/vs/Images/Square150x150Logo.scale-150.png similarity index 100% rename from win/win32/vs2017/Images/Square150x150Logo.scale-150.png rename to win/win32/vs/Images/Square150x150Logo.scale-150.png diff --git a/win/win32/vs2017/Images/Square150x150Logo.scale-200.png b/win/win32/vs/Images/Square150x150Logo.scale-200.png similarity index 100% rename from win/win32/vs2017/Images/Square150x150Logo.scale-200.png rename to win/win32/vs/Images/Square150x150Logo.scale-200.png diff --git a/win/win32/vs2017/Images/Square150x150Logo.scale-400.png b/win/win32/vs/Images/Square150x150Logo.scale-400.png similarity index 100% rename from win/win32/vs2017/Images/Square150x150Logo.scale-400.png rename to win/win32/vs/Images/Square150x150Logo.scale-400.png diff --git a/win/win32/vs2017/Images/Square44x44Logo.altform-unplated_targetsize-16.png b/win/win32/vs/Images/Square44x44Logo.altform-unplated_targetsize-16.png similarity index 100% rename from win/win32/vs2017/Images/Square44x44Logo.altform-unplated_targetsize-16.png rename to win/win32/vs/Images/Square44x44Logo.altform-unplated_targetsize-16.png diff --git a/win/win32/vs2017/Images/Square44x44Logo.altform-unplated_targetsize-256.png b/win/win32/vs/Images/Square44x44Logo.altform-unplated_targetsize-256.png similarity index 100% rename from win/win32/vs2017/Images/Square44x44Logo.altform-unplated_targetsize-256.png rename to win/win32/vs/Images/Square44x44Logo.altform-unplated_targetsize-256.png diff --git a/win/win32/vs2017/Images/Square44x44Logo.altform-unplated_targetsize-32.png b/win/win32/vs/Images/Square44x44Logo.altform-unplated_targetsize-32.png similarity index 100% rename from win/win32/vs2017/Images/Square44x44Logo.altform-unplated_targetsize-32.png rename to win/win32/vs/Images/Square44x44Logo.altform-unplated_targetsize-32.png diff --git a/win/win32/vs2017/Images/Square44x44Logo.altform-unplated_targetsize-48.png b/win/win32/vs/Images/Square44x44Logo.altform-unplated_targetsize-48.png similarity index 100% rename from win/win32/vs2017/Images/Square44x44Logo.altform-unplated_targetsize-48.png rename to win/win32/vs/Images/Square44x44Logo.altform-unplated_targetsize-48.png diff --git a/win/win32/vs2017/Images/Square44x44Logo.scale-100.png b/win/win32/vs/Images/Square44x44Logo.scale-100.png similarity index 100% rename from win/win32/vs2017/Images/Square44x44Logo.scale-100.png rename to win/win32/vs/Images/Square44x44Logo.scale-100.png diff --git a/win/win32/vs2017/Images/Square44x44Logo.scale-125.png b/win/win32/vs/Images/Square44x44Logo.scale-125.png similarity index 100% rename from win/win32/vs2017/Images/Square44x44Logo.scale-125.png rename to win/win32/vs/Images/Square44x44Logo.scale-125.png diff --git a/win/win32/vs2017/Images/Square44x44Logo.scale-150.png b/win/win32/vs/Images/Square44x44Logo.scale-150.png similarity index 100% rename from win/win32/vs2017/Images/Square44x44Logo.scale-150.png rename to win/win32/vs/Images/Square44x44Logo.scale-150.png diff --git a/win/win32/vs2017/Images/Square44x44Logo.scale-200.png b/win/win32/vs/Images/Square44x44Logo.scale-200.png similarity index 100% rename from win/win32/vs2017/Images/Square44x44Logo.scale-200.png rename to win/win32/vs/Images/Square44x44Logo.scale-200.png diff --git a/win/win32/vs2017/Images/Square44x44Logo.scale-400.png b/win/win32/vs/Images/Square44x44Logo.scale-400.png similarity index 100% rename from win/win32/vs2017/Images/Square44x44Logo.scale-400.png rename to win/win32/vs/Images/Square44x44Logo.scale-400.png diff --git a/win/win32/vs2017/Images/Square44x44Logo.targetsize-16.png b/win/win32/vs/Images/Square44x44Logo.targetsize-16.png similarity index 100% rename from win/win32/vs2017/Images/Square44x44Logo.targetsize-16.png rename to win/win32/vs/Images/Square44x44Logo.targetsize-16.png diff --git a/win/win32/vs2017/Images/Square44x44Logo.targetsize-24.png b/win/win32/vs/Images/Square44x44Logo.targetsize-24.png similarity index 100% rename from win/win32/vs2017/Images/Square44x44Logo.targetsize-24.png rename to win/win32/vs/Images/Square44x44Logo.targetsize-24.png diff --git a/win/win32/vs2017/Images/Square44x44Logo.targetsize-24_altform-unplated.png b/win/win32/vs/Images/Square44x44Logo.targetsize-24_altform-unplated.png similarity index 100% rename from win/win32/vs2017/Images/Square44x44Logo.targetsize-24_altform-unplated.png rename to win/win32/vs/Images/Square44x44Logo.targetsize-24_altform-unplated.png diff --git a/win/win32/vs2017/Images/Square44x44Logo.targetsize-256.png b/win/win32/vs/Images/Square44x44Logo.targetsize-256.png similarity index 100% rename from win/win32/vs2017/Images/Square44x44Logo.targetsize-256.png rename to win/win32/vs/Images/Square44x44Logo.targetsize-256.png diff --git a/win/win32/vs2017/Images/Square44x44Logo.targetsize-32.png b/win/win32/vs/Images/Square44x44Logo.targetsize-32.png similarity index 100% rename from win/win32/vs2017/Images/Square44x44Logo.targetsize-32.png rename to win/win32/vs/Images/Square44x44Logo.targetsize-32.png diff --git a/win/win32/vs2017/Images/Square44x44Logo.targetsize-48.png b/win/win32/vs/Images/Square44x44Logo.targetsize-48.png similarity index 100% rename from win/win32/vs2017/Images/Square44x44Logo.targetsize-48.png rename to win/win32/vs/Images/Square44x44Logo.targetsize-48.png diff --git a/win/win32/vs2017/Images/StoreLogo.backup.png b/win/win32/vs/Images/StoreLogo.backup.png similarity index 100% rename from win/win32/vs2017/Images/StoreLogo.backup.png rename to win/win32/vs/Images/StoreLogo.backup.png diff --git a/win/win32/vs2017/Images/StoreLogo.scale-100.png b/win/win32/vs/Images/StoreLogo.scale-100.png similarity index 100% rename from win/win32/vs2017/Images/StoreLogo.scale-100.png rename to win/win32/vs/Images/StoreLogo.scale-100.png diff --git a/win/win32/vs2017/Images/StoreLogo.scale-125.png b/win/win32/vs/Images/StoreLogo.scale-125.png similarity index 100% rename from win/win32/vs2017/Images/StoreLogo.scale-125.png rename to win/win32/vs/Images/StoreLogo.scale-125.png diff --git a/win/win32/vs2017/Images/StoreLogo.scale-150.png b/win/win32/vs/Images/StoreLogo.scale-150.png similarity index 100% rename from win/win32/vs2017/Images/StoreLogo.scale-150.png rename to win/win32/vs/Images/StoreLogo.scale-150.png diff --git a/win/win32/vs2017/Images/StoreLogo.scale-200.png b/win/win32/vs/Images/StoreLogo.scale-200.png similarity index 100% rename from win/win32/vs2017/Images/StoreLogo.scale-200.png rename to win/win32/vs/Images/StoreLogo.scale-200.png diff --git a/win/win32/vs2017/Images/StoreLogo.scale-400.png b/win/win32/vs/Images/StoreLogo.scale-400.png similarity index 100% rename from win/win32/vs2017/Images/StoreLogo.scale-400.png rename to win/win32/vs/Images/StoreLogo.scale-400.png diff --git a/win/win32/vs2017/Images/Wide310x150Logo.scale-100.png b/win/win32/vs/Images/Wide310x150Logo.scale-100.png similarity index 100% rename from win/win32/vs2017/Images/Wide310x150Logo.scale-100.png rename to win/win32/vs/Images/Wide310x150Logo.scale-100.png diff --git a/win/win32/vs2017/Images/Wide310x150Logo.scale-125.png b/win/win32/vs/Images/Wide310x150Logo.scale-125.png similarity index 100% rename from win/win32/vs2017/Images/Wide310x150Logo.scale-125.png rename to win/win32/vs/Images/Wide310x150Logo.scale-125.png diff --git a/win/win32/vs2017/Images/Wide310x150Logo.scale-150.png b/win/win32/vs/Images/Wide310x150Logo.scale-150.png similarity index 100% rename from win/win32/vs2017/Images/Wide310x150Logo.scale-150.png rename to win/win32/vs/Images/Wide310x150Logo.scale-150.png diff --git a/win/win32/vs2017/Images/Wide310x150Logo.scale-200.png b/win/win32/vs/Images/Wide310x150Logo.scale-200.png similarity index 100% rename from win/win32/vs2017/Images/Wide310x150Logo.scale-200.png rename to win/win32/vs/Images/Wide310x150Logo.scale-200.png diff --git a/win/win32/vs2017/Images/Wide310x150Logo.scale-400.png b/win/win32/vs/Images/Wide310x150Logo.scale-400.png similarity index 100% rename from win/win32/vs2017/Images/Wide310x150Logo.scale-400.png rename to win/win32/vs/Images/Wide310x150Logo.scale-400.png diff --git a/win/win32/vs2017/NetHack.sln b/win/win32/vs/NetHack.sln similarity index 100% rename from win/win32/vs2017/NetHack.sln rename to win/win32/vs/NetHack.sln diff --git a/win/win32/vs2017/NetHack.vcxproj b/win/win32/vs/NetHack.vcxproj similarity index 96% rename from win/win32/vs2017/NetHack.vcxproj rename to win/win32/vs/NetHack.vcxproj index d31325331..6103c7d87 100644 --- a/win/win32/vs2017/NetHack.vcxproj +++ b/win/win32/vs/NetHack.vcxproj @@ -57,8 +57,8 @@ - true - false + true + false @@ -299,6 +299,9 @@ + + + diff --git a/win/win32/vs2017/NetHackPackage.appxmanifest b/win/win32/vs/NetHackPackage.appxmanifest similarity index 89% rename from win/win32/vs2017/NetHackPackage.appxmanifest rename to win/win32/vs/NetHackPackage.appxmanifest index 12b8d3ad1..54140a413 100644 --- a/win/win32/vs2017/NetHackPackage.appxmanifest +++ b/win/win32/vs/NetHackPackage.appxmanifest @@ -2,7 +2,7 @@ - NetHack 3.6 + NetHack 3.7 NetHack DevTeam Images\StoreLogo.png @@ -15,7 +15,7 @@ - + @@ -26,4 +26,4 @@ - \ No newline at end of file + diff --git a/win/win32/vs2017/NetHackPackage.wapproj b/win/win32/vs/NetHackPackage.wapproj similarity index 100% rename from win/win32/vs2017/NetHackPackage.wapproj rename to win/win32/vs/NetHackPackage.wapproj diff --git a/win/win32/vs2017/NetHackProperties.props b/win/win32/vs/NetHackProperties.props similarity index 96% rename from win/win32/vs2017/NetHackProperties.props rename to win/win32/vs/NetHackProperties.props index 8c3665ce3..25f634a7b 100644 --- a/win/win32/vs2017/NetHackProperties.props +++ b/win/win32/vs/NetHackProperties.props @@ -5,7 +5,7 @@ 3 7 0 - 5.4.0 + 5.4.2 true diff --git a/win/win32/vs2017/NetHackW.vcxproj b/win/win32/vs/NetHackW.vcxproj similarity index 73% rename from win/win32/vs2017/NetHackW.vcxproj rename to win/win32/vs/NetHackW.vcxproj index 5f8f7a415..ff9571efd 100644 --- a/win/win32/vs2017/NetHackW.vcxproj +++ b/win/win32/vs/NetHackW.vcxproj @@ -51,8 +51,8 @@ - true - false + true + false @@ -190,7 +190,6 @@ - @@ -244,6 +243,88 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -257,6 +338,9 @@ + + + diff --git a/win/win32/vs2017/PDCurses.vcxproj b/win/win32/vs/PDCurses.vcxproj similarity index 100% rename from win/win32/vs2017/PDCurses.vcxproj rename to win/win32/vs/PDCurses.vcxproj diff --git a/win/win32/vs2017/Package.StoreAssociation.xml b/win/win32/vs/Package.StoreAssociation.xml similarity index 99% rename from win/win32/vs2017/Package.StoreAssociation.xml rename to win/win32/vs/Package.StoreAssociation.xml index 1200895f3..24422d2fd 100644 --- a/win/win32/vs2017/Package.StoreAssociation.xml +++ b/win/win32/vs/Package.StoreAssociation.xml @@ -363,11 +363,11 @@ 30485NetHackDevTeam.NetHack3.6 - NetHack 3.6 + NetHack 3.7 30485NetHackDevTeam.NetHackBeta - \ No newline at end of file + diff --git a/win/win32/vs2017/ScreenShot.PNG b/win/win32/vs/ScreenShot.PNG similarity index 100% rename from win/win32/vs2017/ScreenShot.PNG rename to win/win32/vs/ScreenShot.PNG diff --git a/win/win32/vs2017/afterdlb.proj b/win/win32/vs/afterdlb.proj similarity index 86% rename from win/win32/vs2017/afterdlb.proj rename to win/win32/vs/afterdlb.proj index 807fdf7c7..56ea03350 100644 --- a/win/win32/vs2017/afterdlb.proj +++ b/win/win32/vs/afterdlb.proj @@ -4,8 +4,8 @@ - - + + diff --git a/win/win32/vs2017/aftermakedefs.proj b/win/win32/vs/aftermakedefs.proj similarity index 91% rename from win/win32/vs2017/aftermakedefs.proj rename to win/win32/vs/aftermakedefs.proj index af5fd489c..4ce136bb9 100644 --- a/win/win32/vs2017/aftermakedefs.proj +++ b/win/win32/vs/aftermakedefs.proj @@ -7,7 +7,6 @@ - diff --git a/win/win32/vs2017/afternethack.proj b/win/win32/vs/afternethack.proj similarity index 100% rename from win/win32/vs2017/afternethack.proj rename to win/win32/vs/afternethack.proj diff --git a/win/win32/vs2017/afterrecover.proj b/win/win32/vs/afterrecover.proj similarity index 100% rename from win/win32/vs2017/afterrecover.proj rename to win/win32/vs/afterrecover.proj diff --git a/win/win32/vs2017/aftertile2bmp.proj b/win/win32/vs/aftertile2bmp.proj similarity index 100% rename from win/win32/vs2017/aftertile2bmp.proj rename to win/win32/vs/aftertile2bmp.proj diff --git a/win/win32/vs2017/aftertilemap.proj b/win/win32/vs/aftertilemap.proj similarity index 100% rename from win/win32/vs2017/aftertilemap.proj rename to win/win32/vs/aftertilemap.proj diff --git a/win/win32/vs2017/afteruudecode.proj b/win/win32/vs/afteruudecode.proj similarity index 100% rename from win/win32/vs2017/afteruudecode.proj rename to win/win32/vs/afteruudecode.proj diff --git a/win/win32/vs2017/build.bat b/win/win32/vs/build.bat similarity index 100% rename from win/win32/vs2017/build.bat rename to win/win32/vs/build.bat diff --git a/win/win32/vs2017/common.props b/win/win32/vs/common.props similarity index 100% rename from win/win32/vs2017/common.props rename to win/win32/vs/common.props diff --git a/win/win32/vs2017/config.props b/win/win32/vs/config.props similarity index 100% rename from win/win32/vs2017/config.props rename to win/win32/vs/config.props diff --git a/win/win32/vs2017/console.props b/win/win32/vs/console.props similarity index 100% rename from win/win32/vs2017/console.props rename to win/win32/vs/console.props diff --git a/win/win32/vs/cpp.hint b/win/win32/vs/cpp.hint new file mode 100644 index 000000000..4f77429fe --- /dev/null +++ b/win/win32/vs/cpp.hint @@ -0,0 +1,6 @@ +// Hint files help the Visual Studio IDE interpret Visual C++ identifiers +// such as names of functions and macros. +// For more information see https://go.microsoft.com/fwlink/?linkid=865984 +#define E +#define NDECL(x) x +#define FDECL(x, y) x y diff --git a/win/win32/vs2017/default.props b/win/win32/vs/default.props similarity index 91% rename from win/win32/vs2017/default.props rename to win/win32/vs/default.props index e0bc58136..a8b166609 100644 --- a/win/win32/vs2017/default.props +++ b/win/win32/vs/default.props @@ -4,7 +4,7 @@ Application false MultiByte - v141 + $(DefaultPlatformToolset) $(BinDir) @@ -14,5 +14,4 @@ false true - diff --git a/win/win32/vs2017/default_dll.props b/win/win32/vs/default_dll.props similarity index 90% rename from win/win32/vs2017/default_dll.props rename to win/win32/vs/default_dll.props index 51d90a3ee..cf1306958 100644 --- a/win/win32/vs2017/default_dll.props +++ b/win/win32/vs/default_dll.props @@ -4,7 +4,7 @@ DynamicLibrary false MultiByte - v141 + $(DefaultPlatformToolset) true diff --git a/win/win32/vs2017/default_lib.props b/win/win32/vs/default_lib.props similarity index 90% rename from win/win32/vs2017/default_lib.props rename to win/win32/vs/default_lib.props index 61bf2ecaa..ce33f4abc 100644 --- a/win/win32/vs2017/default_lib.props +++ b/win/win32/vs/default_lib.props @@ -4,7 +4,7 @@ StaticLibrary false MultiByte - v141 + $(DefaultPlatformToolset) true diff --git a/win/win32/vs2017/dirs.props b/win/win32/vs/dirs.props similarity index 95% rename from win/win32/vs2017/dirs.props rename to win/win32/vs/dirs.props index 05b6543ac..ed8a7554f 100644 --- a/win/win32/vs2017/dirs.props +++ b/win/win32/vs/dirs.props @@ -10,7 +10,7 @@ $(RootDir)dat\ $(RootDir)doc\ $(RootDir)include\ - $(RootDir)lib\lua-$(LUA_VERSION)\src\ + $(RootDir)submodules\lua\ $(RootDir)src\ $(RootDir)sys\ $(RootDir)util\ diff --git a/win/win32/vs2017/dlb.vcxproj b/win/win32/vs/dlb.vcxproj similarity index 100% rename from win/win32/vs2017/dlb.vcxproj rename to win/win32/vs/dlb.vcxproj diff --git a/win/win32/vs2017/dll.props b/win/win32/vs/dll.props similarity index 100% rename from win/win32/vs2017/dll.props rename to win/win32/vs/dll.props diff --git a/win/win32/vs2017/files.props b/win/win32/vs/files.props similarity index 98% rename from win/win32/vs2017/files.props rename to win/win32/vs/files.props index c388b6898..5aeae719e 100644 --- a/win/win32/vs2017/files.props +++ b/win/win32/vs/files.props @@ -8,9 +8,6 @@ - - - diff --git a/win/win32/vs2017/makedefs.vcxproj b/win/win32/vs/makedefs.vcxproj similarity index 88% rename from win/win32/vs2017/makedefs.vcxproj rename to win/win32/vs/makedefs.vcxproj index 190952a6a..f82bb2c9a 100644 --- a/win/win32/vs2017/makedefs.vcxproj +++ b/win/win32/vs/makedefs.vcxproj @@ -55,10 +55,10 @@ Outputs="$(IncDir)\nhlua.h"> - + - - + + diff --git a/win/win32/vs2017/nh340key.def b/win/win32/vs/nh340key.def similarity index 100% rename from win/win32/vs2017/nh340key.def rename to win/win32/vs/nh340key.def diff --git a/win/win32/vs2017/nh340key.vcxproj b/win/win32/vs/nh340key.vcxproj similarity index 100% rename from win/win32/vs2017/nh340key.vcxproj rename to win/win32/vs/nh340key.vcxproj diff --git a/win/win32/vs2017/nhdefkey.def b/win/win32/vs/nhdefkey.def similarity index 100% rename from win/win32/vs2017/nhdefkey.def rename to win/win32/vs/nhdefkey.def diff --git a/win/win32/vs2017/nhdefkey.vcxproj b/win/win32/vs/nhdefkey.vcxproj similarity index 100% rename from win/win32/vs2017/nhdefkey.vcxproj rename to win/win32/vs/nhdefkey.vcxproj diff --git a/win/win32/vs2017/nhraykey.def b/win/win32/vs/nhraykey.def similarity index 100% rename from win/win32/vs2017/nhraykey.def rename to win/win32/vs/nhraykey.def diff --git a/win/win32/vs2017/nhraykey.vcxproj b/win/win32/vs/nhraykey.vcxproj similarity index 100% rename from win/win32/vs2017/nhraykey.vcxproj rename to win/win32/vs/nhraykey.vcxproj diff --git a/win/win32/vs2017/recover.vcxproj b/win/win32/vs/recover.vcxproj similarity index 100% rename from win/win32/vs2017/recover.vcxproj rename to win/win32/vs/recover.vcxproj diff --git a/win/win32/vs2017/tile2bmp.vcxproj b/win/win32/vs/tile2bmp.vcxproj similarity index 100% rename from win/win32/vs2017/tile2bmp.vcxproj rename to win/win32/vs/tile2bmp.vcxproj diff --git a/win/win32/vs2017/tilemap.vcxproj b/win/win32/vs/tilemap.vcxproj similarity index 96% rename from win/win32/vs2017/tilemap.vcxproj rename to win/win32/vs/tilemap.vcxproj index 139dd17a2..8ab1ab1db 100644 --- a/win/win32/vs2017/tilemap.vcxproj +++ b/win/win32/vs/tilemap.vcxproj @@ -67,7 +67,6 @@ - @@ -86,4 +85,4 @@ - \ No newline at end of file + diff --git a/win/win32/vs2017/tiles.vcxproj b/win/win32/vs/tiles.vcxproj similarity index 100% rename from win/win32/vs2017/tiles.vcxproj rename to win/win32/vs/tiles.vcxproj diff --git a/win/win32/vs2017/travisci.sh b/win/win32/vs/travisci.sh similarity index 99% rename from win/win32/vs2017/travisci.sh rename to win/win32/vs/travisci.sh index 6eb4fa64a..d7d48e3f0 100644 --- a/win/win32/vs2017/travisci.sh +++ b/win/win32/vs/travisci.sh @@ -24,7 +24,7 @@ export LIB=/c/Program\ Files\ \(x86\)/Microsoft\ Visual\ Studio/$VSVER/$TOOLSVER export LIB=/c/Program\ Files\ \(x86\)/Microsoft\ Visual\ Studio/$VSVER/$TOOLSVER/VC/Tools/MSVC/$MSVER/lib/x86:$LIB export LIB=/c/Program\ Files\ \(x86\)/Windows\ Kits/10/lib/$WKITVER/ucrt/x86:$LIB export LIB=/c/Program\ Files\ \(x86\)/Windows\ Kits/10/lib/$WKITVER/um/x86:$LIB -export LUA_VERSION=5.4.0 +export LUA_VERSION=5.4.2 mkdir -p lib cd lib git clone --depth 1 https://github.com/wmcbrine/PDCurses.git pdcurses diff --git a/win/win32/vs2017/uudecode.vcxproj b/win/win32/vs/uudecode.vcxproj similarity index 100% rename from win/win32/vs2017/uudecode.vcxproj rename to win/win32/vs/uudecode.vcxproj diff --git a/win/win32/vs2017/.gitattributes b/win/win32/vs2017/.gitattributes deleted file mode 100644 index 041653ea8..000000000 --- a/win/win32/vs2017/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -* NH_filestag=(file%s_for_Visual_Studio_2017_Community_Edition_builds) diff --git a/win/win32/winMS.h b/win/win32/winMS.h index 0e5b82097..6ec4e9c3b 100644 --- a/win/win32/winMS.h +++ b/win/win32/winMS.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 winMS.h $NHDT-Date: 1434804346 2015/06/20 12:45:46 $ $NHDT-Branch: win32-x64-working $:$NHDT-Revision: 1.41 $ */ +/* NetHack 3.7 winMS.h $NHDT-Date: 1596498367 2020/08/03 23:46:07 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.53 $ */ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ @@ -162,7 +162,7 @@ void mswin_update_inventory(void); void mswin_mark_synch(void); void mswin_wait_synch(void); void mswin_cliparound(int x, int y); -void mswin_print_glyph(winid wid, XCHAR_P x, XCHAR_P y, int glyph, int bkglyph); +void mswin_print_glyph(winid wid, XCHAR_P x, XCHAR_P y, int glyph, int bkglyph, unsigned *glyphmod); void mswin_raw_print(const char *str); void mswin_raw_print_bold(const char *str); void mswin_raw_print_flush();