diff --git a/DEVEL/Developer.txt b/DEVEL/Developer.txt index 4167bc753..c1c46209e 100644 --- a/DEVEL/Developer.txt +++ b/DEVEL/Developer.txt @@ -4,7 +4,7 @@ |___/\___|\_/\___|_\___/ .__/\___|_| |_| -$NHDT-Date: 1518800857 2018/02/16 17:07:37 $ +$NHDT-Date: 1519228647 2018/02/21 15:57:27 $ Welcome to the NetHack Infrastructure Developer's Guide. @@ -25,6 +25,7 @@ CONTENTS 5. variable expansion 6. reserved names 7. nhadd/nhcommit +8. hooks ------------------------------------------------------------------------------ 1. email Email to devteam@nethack.org will usually get a response, but it may take a @@ -37,7 +38,8 @@ The public NetHack git repository is available (read-only) at: or https://github.com/NetHack/NetHack.git -XXX need to discuss what branches are available +Branches: +NetHack-3.6.0 The 3.6.0 release code and subsequent fixes and additions. ------------------------------------------------------------------------------ 3. bug reporting Please use the form at http://www.nethack.org/common/contact.html (or send @@ -94,7 +96,8 @@ C. Configure the repository: -v verbose -n dry run You can re-run nhgitset.pl as often as needed; occasionally we will - update it and ask you to run it again. + update it (or something it installs) and you will need to run it again + so the changes take effect. D. aliases Two aliases are installed by nhgitset.pl: nhadd @@ -211,3 +214,19 @@ D. Using your own hooks "perldoc DEVEL/hooksdir/nhsub". ------------------------------------------------------------------------------ +8. hooks + + nhgitset.pl also installs hooks into .git/hooks. These hooks provide + a framework which allows local hook code to co-exist with hook code we + supply - see DEVEL/hooksdir/NHgithook.pm for details. + + We currently use the following hooks: + post-checkout + post-commit + post-merge + These are used to generate dat/gitinfo.txt which provides the data that + ends up available through the game command #version and the command line + option --version. + +------------------------------------------------------------------------------ + diff --git a/DEVEL/gitinfo.pl b/DEVEL/gitinfo.pl new file mode 100644 index 000000000..d62f1a588 --- /dev/null +++ b/DEVEL/gitinfo.pl @@ -0,0 +1,33 @@ +#!/usr/bin/perl + +#STARTUP-START +BEGIN { + # OS hackery has to be duplicated in each of the hooks :/ + # first the directory separator + my $DS = quotemeta('/'); + my $PDS = '/'; + # msys: POSIXish over a Windows filesystem (so / not \ but \r\n not \n). + # temporarily removed because inconsistent behavior + # if ($^O eq "msys") + # { + # $/ = "\r\n"; + # $\ = "\r\n"; + # } + if($^O eq "MSWin32"){ + $DS = quotemeta('\\'); + $PDS = '\\'; + } + $gitdir = `git rev-parse --git-dir`; + chomp $gitdir; + push(@INC, $gitdir.$PDS."hooks"); + + # special case for this script only: allow + # it to run from DEVEL or $TOP + if (-f "hooksdir/NHgithook.pm" || -f "DEVEL/hooksdir/NHgithook.pm"){ + push(@INC, "DEVEL/hooksdir"); + } + chdir("..") if (-f "hooksdir/NHgithook.pm"); +} +use NHgithook; + +&NHgithook::nhversioning; diff --git a/DEVEL/hooksdir/NHgithook.pm b/DEVEL/hooksdir/NHgithook.pm index 6024c1c03..435fe6c8d 100644 --- a/DEVEL/hooksdir/NHgithook.pm +++ b/DEVEL/hooksdir/NHgithook.pm @@ -1,7 +1,7 @@ # # NHgithook.pm # NetHack Git Hook Module -# $NHDT-Date$ +# $NHDT-Date: 1519164205 2018/02/20 22:03:25 $ package NHgithook; use Cwd; @@ -60,6 +60,51 @@ sub POST { &do_hook("POST"); } +### +### store githash and gitbranch in dat/gitinfo.txt +### + +sub nhversioning { + use strict; + use warnings; + + my $git_sha = `git rev-parse HEAD`; + $git_sha =~ s/\s+//g; + my $git_branch = `git rev-parse --abbrev-ref HEAD`; + $git_branch =~ s/\s+//g; + die "git rev-parse failed" unless(length $git_sha and length $git_branch); + my $exists = 0; + + if (open my $fh, '<', 'dat/gitinfo.txt') { + $exists = 1; + my $hashok = 0; + my $branchok = 0; + while (my $line = <$fh>) { + if ((index $line, $git_sha) >= 0) { + $hashok++; + } + if ((index $line, $git_branch) >= 0) { + $branchok++; + } + } + close $fh; + if ($hashok && $branchok) { + print "dat/gitinfo.txt unchanged, githash=".$git_sha."\n"; + return; + } + } else { + print "WARNING: Can't find dat directory\n" unless(-d "dat"); + } + if (open my $fh, '>', 'dat/gitinfo.txt') { + my $how = ($exists ? "updated" : "created"); + print $fh 'githash='.$git_sha."\n"; + print $fh 'gitbranch='.$git_branch."\n"; + print "dat/gitinfo.txt ".$how.", githash=".$git_sha."\n"; + } else { + print "WARNING: Unable to open dat/gitinfo.txt: $!\n"; + } +} + # PRIVATE sub do_hook { my($p) = @_; diff --git a/DEVEL/hooksdir/post-checkout b/DEVEL/hooksdir/post-checkout index b5bf990fe..2df107a2f 100755 --- a/DEVEL/hooksdir/post-checkout +++ b/DEVEL/hooksdir/post-checkout @@ -26,5 +26,6 @@ use NHgithook; #STARTUP-END &NHgithook::PRE; +&NHgithook::nhversioning; &NHgithook::POST; exit 0; diff --git a/DEVEL/hooksdir/post-commit b/DEVEL/hooksdir/post-commit index b5bf990fe..2df107a2f 100755 --- a/DEVEL/hooksdir/post-commit +++ b/DEVEL/hooksdir/post-commit @@ -26,5 +26,6 @@ use NHgithook; #STARTUP-END &NHgithook::PRE; +&NHgithook::nhversioning; &NHgithook::POST; exit 0; diff --git a/DEVEL/hooksdir/post-merge b/DEVEL/hooksdir/post-merge index b5bf990fe..2dc7f3628 100755 --- a/DEVEL/hooksdir/post-merge +++ b/DEVEL/hooksdir/post-merge @@ -22,9 +22,11 @@ BEGIN { chomp $gitdir; push(@INC, $gitdir.$PDS."hooks"); } + use NHgithook; #STARTUP-END &NHgithook::PRE; +&NHgithook::nhversioning; &NHgithook::POST; exit 0; diff --git a/Files b/Files index c6a2a5c0c..f2bb266aa 100644 --- a/Files +++ b/Files @@ -169,9 +169,9 @@ wdnflute.uu wdnharp.uu sys/unix: (files for UNIX versions) Install.unx Makefile.dat Makefile.doc Makefile.src Makefile.top -Makefile.utl README.linux depend.awk mkmkfile.sh nethack.sh -NewInstall.unx setup.sh sysconf unixmain.c unixres.c -unixunix.c +Makefile.utl README.linux depend.awk gitinfo.sh mkmkfile.sh +nethack.sh NewInstall.unx 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 (file for sound driver for 386 UNIX) @@ -179,8 +179,9 @@ snd86unx.shr sys/unix/hints: (files for configuring UNIX NetHack versions) -linux linux-chroot linux-x11 macosx macosx10.5 -macosx10.7 macosx10.8 macosx10.10 macosx.sh unix +linux linux-chroot linux-qt4 linux-x11 macosx +macosx10.5 macosx10.7 macosx10.8 macosx10.10 macosx.sh +unix sys/vms: (files for VMS version) diff --git a/README b/README index 5c4117f46..1fe8f8146 100644 --- a/README +++ b/README @@ -1,24 +1,39 @@ NetHack 3.6.1 -- General information -NetHack 3.6 is an enhancement to the dungeon exploration game NetHack. -It is a distant descendent of Rogue and Hack, and a direct descendent of -NetHack 3.4. In order to avoid confusion with interim development code -that was posted online in 2014 by others, there is no NetHack 3.5 release. +NetHack 3.6 is an enhancement to the dungeon exploration game NetHack, +which is a distant descendent of Rogue and Hack, and a direct descendent of +NetHack 3.4 as there was no NetHack 3.5 release. -NetHack 3.6.1 contains several dozen bugfixes. - -The file doc/fixes36.1 in the source distribution has a full list of each. +NetHack 3.6.1 contains several hundred bug fixes to NetHack 3.6.0. The +file doc/fixes36.1 in the source distribution has a full list of them. 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 "new features" section. -Here are some additional general notes that are not considered spoilers: - * Some code paths and long-established game features have been made - part of the base build and no longer conditional on compile settings. - * Several treasured NetHack community patches, or a variation of - them, have been rolled in to the base NetHack source tree, incuding: - menucolors, pickup thrown, statue glyphs, dungeon overview, sortloot. +Below you will find some other general notes that were not considered +spoilers: +* additional Terry Pratchett tribute passages +* enhanced map position picking +* new status line conditions Stone Strngl Deaf Lev Fly Ride +* updated status hilites and several interface enhancements +* new paranoid_confirm settings +* a new extended command #kick +* the vanquished monsters list can be sorted during end of game disclosure +* fountains are bright blue +* travel accepts 'm' (request menu) prefix +* pressing a or A when cursor positioning shows menu of "interesting" features +* pressing z or Z when cursor positioning can cycle through valid locations +* add option herecmd_menu to make a mouse click on your character pop up a menu +* #adjust's behavior altered when collecting compatible stacks +* Some community patches that were included: + - Malcolm Ryan's improved tin opener + - Ray Chason's MSDOS port support for some VESA modes + - Ray Chason's Qt4 windowport + - Darshan Shaligram's pet ranged attack + - Jason Dorje Short's key rebinding + - Maxime Bacoux's new DUMPLOG +* updated database entries for several things - - - - - - - - - - - @@ -66,6 +81,9 @@ Please read items (1), (2) and (3) BEFORE doing anything with your new code. Mac OS X 10.9 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 + Previous versions of NetHack were tested and known to run on the following systems, but it is unknown if they can still build and execute NetHack 3.6: @@ -122,7 +140,10 @@ Please read items (1), (2) and (3) BEFORE doing anything with your new code. If you have problems building the game, or you find bugs in it, we recommend filing a bug report from our "Contact Us" web page at: - http://www.nethack.org/ + https://www.nethack.org/common/contact.html or + http://www.nethack.org/common/contact.html +Please include the version information from #version or the command line +option --version in the apropriate field. A public repository of the latest NetHack code that we've made available can be obtained via git here: diff --git a/dat/data.base b/dat/data.base index ad7c61477..e07ab954e 100644 --- a/dat/data.base +++ b/dat/data.base @@ -54,6 +54,7 @@ suit or piece of armor [ When Help Collides, by J. D. Berry ] aclys aklys +thonged club A short studded or spiked club attached to a cord allowing it to be drawn back to the wielder after having been thrown. It should not be confused with the atlatl, which is a device @@ -3182,12 +3183,12 @@ mars martial arts unarmed combat bare*handed combat - "What else can we do? None of this is fast enough." "It will have - to be." He stood up, a tall, broad wall of a man. "Why don't you - ask around, see if anyone in the neighborhoods knows anything - about martial arts. You need more than a book or two to learn - good dependable unarmed combat." - [ Parable of the Sower, by Octavia Butler ] + "What else can we do? None of this is fast enough." "It will have + to be." He stood up, a tall, broad wall of a man. "Why don't you + ask around, see if anyone in the neighborhoods knows anything + about martial arts. You need more than a book or two to learn + good dependable unarmed combat." + [ Parable of the Sower, by Octavia Butler ] master assassin He strolled down the stairs, followed by a number of assassins. When he was directly in front of Ymor he said: "I've come for @@ -3942,6 +3943,30 @@ user Might just kill you. [ It's a Jungle Out There, by Randy Newman ] # [ theme song from "Monk" ] +polearm +* polearm +partisan +ranseur +spetum +glaive +halberd +bardiche +angled poleaxe +long poleaxe +voulge +pole cleaver +fauchard +pole sickle +guisarme +bill-guisarme +lucern hammer +bec de corbin + Many of the weapons of the Middle Ages were poled or long-shafted + arms. Unlike the ancient spear or javelin, however, they were not + intended to be thrown. Some were devices with simple single- or + double-edged blades and nothing more, while others combined + the pick, spear, and hammer or axe all in one weapon. + [ Heraldry and Armor of the Middle Ages, by Marvin H. Pakula ] polymorph trap One morning, as Gregor Samsa was waking up from anxious dreams, he discovered that in bed he had been changed into a monstrous @@ -5053,6 +5078,8 @@ tourist Tourist, Rincewind had decided, meant "idiot". [ The Colour of Magic, by Terry Pratchett ] towel +wet towel +moist towel The Hitchhiker's Guide to the Galaxy has a few things to say on the subject of towels. A towel, it says, is about the most massively useful thing diff --git a/doc/Guidebook.mn b/doc/Guidebook.mn index 3989cec93..ef2bfd9c4 100644 --- a/doc/Guidebook.mn +++ b/doc/Guidebook.mn @@ -4292,46 +4292,36 @@ in this, the list of Dungeoneers: center; c c c. .\"TABLE_START -Adam Aronow Janet Walz Nathan Eady -Alex Kompel Janne Salmijarvi Norm Meluch -Andreas Dorn Jean-Christophe Collet Olaf Seibert -Andy Church Jeff Bailey Pasi Kallinen -Andy Swanson Jochen Erwied Pat Rankin -Ari Huttunen John Kallen Paul Winner -Barton House John Rupley Pierre Martineau -Benson I. Margulies John S. Bien Ralf Brown -Bill Dyer Johnny Lee Ray Chason -Boudewijn Waijers Jon W{tte Richard Addison -Bruce Cox Jonathan Handler Richard Beigel -Bruce Holloway Joshua Delahunty Richard P. Hughey -Bruce Mewborne Keizo Yamamoto Rob Menke -Carl Schelin Ken Arnold Robin Bandy -Chris Russo Ken Arromdee Robin Johnson -David Cohrs Ken Lorber Roderick Schertler -David Damerell Ken Washikita Roland McGrath -David Gentzel Kevin Darcy Ron Van Iwaarden -David Hairston Kevin Hugo Ronnen Miller -Dean Luick Kevin Sitze Ross Brown -Del Lamb Kevin Smolkowski Sascha Wostmann -Derek S. Ray Kevin Sweet Scott Bigham -Deron Meranda Lars Huttar Scott R. Turner -Dion Nicolaas Leon Arnott Sean Hunt -Dylan O'Donnell M. Drew Streib Stephen Spackman -Eric Backus Malcolm Ryan Stefan Thielscher -Eric Hendrickson Mark Gooderum Stephen White -Eric R. Smith Mark Modrall Steve Creps -Eric S. Raymond Marvin Bressler Steve Linhart -Erik Andersen Matthew Day Steve VanDevender -Frederick Roeber Merlyn LeRoy Teemu Suikki -Gil Neiger Michael Allison Tim Lennan -Greg Laskin Michael Feir Timo Hakulinen -Greg Olson Michael Hamel Tom Almy -Gregg Wonderly Michael Sokolov Tom West -Hao-yang Wang Mike Engber Warren Cheung -Helge Hafting Mike Gallop Warwick Allison -Irina Rempt-Drijfhout Mike Passaretti Yitzhak Sapir -Izchak Miller Mike Stephenson -J. Ali Harlow Mikko Juola +Adam Aronow Erik Andersen Kevin Sitze Ray Chason +Alex Kompel Frederick Roeber Kevin Smolkowski Richard Addison +Alex Smith Gil Neiger Kevin Sweet Richard Beigel +Andreas Dorn Greg Laskin Lars Huttar Richard P. Hughey +Andy Church Greg Olson Leon Arnott Rob Menke +Andy Swanson Gregg Wonderly M. Drew Streib Robin Bandy +Ari Huttunen Hao-yang Wang Malcolm Ryan Robin Johnson +Barton House Helge Hafting Mark Gooderum Roderick Schertler +Benson I. Margulies Irina Rempt-Drijfhout Mark Modrall Roland McGrath +Bill Dyer Izchak Miller Marvin Bressler Ron Van Iwaarden +Boudewijn Waijers J. Ali Harlow Matthew Day Ronnen Miller +Bruce Cox Janet Walz Merlyn LeRoy Ross Brown +Bruce Holloway Janne Salmijarvi Michael Allison Sascha Wostmann +Bruce Mewborne Jean-Christophe Collet Michael Feir Scott Bigham +Carl Schelin Jeff Bailey Michael Hamel Scott R. Turner +Chris Russo Jochen Erwied Michael Sokolov Sean Hunt +David Cohrs John Kallen Mike Engber Stephen Spackman +David Damerell John Rupley Mike Gallop Stefan Thielscher +David Gentzel John S. Bien Mike Passaretti Stephen White +David Hairston Johnny Lee Mike Stephenson Steve Creps +Dean Luick Jon W{tte Mikko Juola Steve Linhart +Del Lamb Jonathan Handler Nathan Eady Steve VanDevender +Derek S. Ray Joshua Delahunty Norm Meluch Teemu Suikki +Deron Meranda Keizo Yamamoto Olaf Seibert Tim Lennan +Dion Nicolaas Ken Arnold Pasi Kallinen Timo Hakulinen +Dylan O'Donnell Ken Arromdee Pat Rankin Tom Almy +Eric Backus Ken Lorber Patric Mueller Tom West +Eric Hendrickson Ken Washikita Paul Winner Warren Cheung +Eric R. Smith Kevin Darcy Pierre Martineau Warwick Allison +Eric S. Raymond Kevin Hugo Ralf Brown Yitzhak Sapir .\"TABLE_END Do not delete this line. .TE diff --git a/doc/Guidebook.tex b/doc/Guidebook.tex index ea948813b..48c122a7e 100644 --- a/doc/Guidebook.tex +++ b/doc/Guidebook.tex @@ -5236,36 +5236,36 @@ in this, the list of Dungeoneers: \begin{center} \begin{tabular}{llll} %TABLE_START -Adam Aronow & Frederick Roeber & Kevin Smolkowski & Richard Beigel\\ -Alex Kompel & Gil Neiger & Kevin Sweet & Richard P. Hughey\\ -Andreas Dorn & Greg Laskin & Lars Huttar & Rob Menke\\ -Andy Church & Greg Olson & Leon Arnott & Robin Bandy\\ -Andy Swanson & Gregg Wonderly & M. Drew Streib & Robin Johnson\\ -Ari Huttunen & Hao-yang Wang & Malcolm Ryan & Roderick Schertler\\ -Barton House & Helge Hafting & Mark Gooderum & Roland McGrath\\ -Benson I. Margulies & Irina Rempt-Drijfhout & Mark Modrall & Ron Van Iwaarden\\ -Bill Dyer & Izchak Miller & Marvin Bressler & Ronnen Miller\\ -Boudewijn Waijers & J. Ali Harlow & Matthew Day & Ross Brown\\ -Bruce Cox & Janet Walz & Merlyn LeRoy & Sascha Wostmann\\ -Bruce Holloway & Janne Salmij\"{a}rvi & Michael Allison & Scott Bigham\\ -Bruce Mewborne & Jean-Christophe Collet & Michael Feir & Scott R. Turner\\ -Carl Schelin & Jeff Bailey & Michael Hamel & Sean Hunt\\ -Chris Russo & Jochen Erwied & Michael Sokolov & Stephen Spackman\\ -David Cohrs & John Kallen & Mike Engber & Stefan Thielscher\\ -David Damerell & John Rupley & Mike Gallop & Stephen White\\ -David Gentzel & John S. Bien & Mike Passaretti & Steve Creps\\ -David Hairston & Johnny Lee & Mike Stephenson & Steve Linhart\\ -Dean Luick & Jon W\{tte & Mikko Juola & Steve VanDevender\\ -Del Lamb & Jonathan Handler & Nathan Eady & Teemu Suikki\\ -Derek S. Ray & Joshua Delahunty & Norm Meluch & Tim Lennan\\ -Deron Meranda & Keizo Yamamoto & Olaf Seibert & Timo Hakulinen\\ -Dion Nicolaas & Ken Arnold & Pasi Kallinen & Tom Almy\\ -Dylan O'Donnell & Ken Arromdee & Pat Rankin & Tom West\\ -Eric Backus & Ken Lorber & Paul Winner & Warren Cheung\\ -Eric Hendrickson & Ken Washikita & Pierre Martineau & Warwick Allison\\ -Eric R. Smith & Kevin Darcy & Ralf Brown & Yitzhak Sapir\\ -Eric S. Raymond & Kevin Hugo & Ray Chason\\ -Erik Andersen & Kevin Sitze & Richard Addison +Adam Aronow & Erik Andersen & Kevin Sitze & Ray Chason\\ +Alex Kompel & Frederick Roeber & Kevin Smolkowski & Richard Addison\\ +Alex Smith & Gil Neiger & Kevin Sweet & Richard Beigel\\ +Andreas Dorn & Greg Laskin & Lars Huttar & Richard P. Hughey\\ +Andy Church & Greg Olson & Leon Arnott & Rob Menke\\ +Andy Swanson & Gregg Wonderly & M. Drew Streib & Robin Bandy\\ +Ari Huttunen & Hao-yang Wang & Malcolm Ryan & Robin Johnson\\ +Barton House & Helge Hafting & Mark Gooderum & Roderick Schertler\\ +Benson I. Margulies & Irina Rempt-Drijfhout & Mark Modrall & Roland McGrath\\ +Bill Dyer & Izchak Miller & Marvin Bressler & Ron Van Iwaarden\\ +Boudewijn Waijers & J. Ali Harlow & Matthew Day & Ronnen Miller\\ +Bruce Cox & Janet Walz & Merlyn LeRoy & Ross Brown\\ +Bruce Holloway & Janne Salmij\"{a}rvi & Michael Allison & Sascha Wostmann\\ +Bruce Mewborne & Jean-Christophe Collet & Michael Feir & Scott Bigham\\ +Carl Schelin & Jeff Bailey & Michael Hamel & Scott R. Turner\\ +Chris Russo & Jochen Erwied & Michael Sokolov & Sean Hunt\\ +David Cohrs & John Kallen & Mike Engber & Stephen Spackman\\ +David Damerell & John Rupley & Mike Gallop & Stefan Thielscher\\ +David Gentzel & John S. Bien & Mike Passaretti & Stephen White\\ +David Hairston & Johnny Lee & Mike Stephenson & Steve Creps\\ +Dean Luick & Jon W\{tte & Mikko Juola & Steve Linhart\\ +Del Lamb & Jonathan Handler & Nathan Eady & Steve VanDevender\\ +Derek S. Ray & Joshua Delahunty & Norm Meluch & Teemu Suikki\\ +Deron Meranda & Keizo Yamamoto & Olaf Seibert & Tim Lennan\\ +Dion Nicolaas & Ken Arnold & Pasi Kallinen & Timo Hakulinen\\ +Dylan O'Donnell & Ken Arromdee & Pat Rankin & Tom Almy\\ +Eric Backus & Ken Lorber & Patric Mueller & Tom West\\ +Eric Hendrickson & Ken Washikita & Paul Winner & Warren Cheung\\ +Eric R. Smith & Kevin Darcy & Pierre Martineau & Warwick Allison\\ +Eric S. Raymond & Kevin Hugo & Ralf Brown & Yitzhak Sapir %TABLE_END Do not delete this line. \end{tabular} \end{center} diff --git a/doc/fixes36.1 b/doc/fixes36.1 index 2e697c5ab..bb8c17505 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -190,7 +190,7 @@ grammar bit when hallucinating: "you kill poor goblin" ('the' missing for pet) some blindness cures ignored u.ucreamed some instances of stun or confusion timers were being overridden rather than incremented when new stun or confusion damage was suffered -female gnome who gains level can grow up into male-only gnome lord; give an +female gnome who gains level can grow up into male-only gnome lord; give an alternate message instead of prohibiting the promotion kicked weapon which successfully hits monster vanishes from play unseen landmine explosion could result in "The statue crumbles." @@ -295,7 +295,7 @@ don't give "you cannot pass through the bars" when travel is testing possible paths in the vicinity of iron bars if blind and no gloves, using 'm' to move and then 'e' could be used to locate cockatrice corpse without fatal touching (by declining to eat) -it's cannabilism for a were to eat a corpse +it's cannibalism for a were to eat a corpse conduct: wishing for an artifact and not getting it because it already exists counts as wishing for an artifact, just like when not getting it because of quest restrictions or too many artifacts in play does @@ -304,7 +304,7 @@ gelatinous cube shouldn't be able to eat a scroll of scare monster make fireballs or cones of cold cast at skilled or higher not go through walls prevent flying monsters from hovering over unreachable underwater objects lembas wafer gives increased nutrition to elves, reduced nutrition to orcs; - cram ration gives increase nutrition to dwarves + cram ration gives increased nutrition to dwarves when #tip's terse object drop format got interrupted by a regular message, it continued using "obj2, obj3, ..." for subsequent objects, where the sentence grammar no longer made sense (the interrupting message @@ -414,6 +414,7 @@ surviving a gas spore's explosion would leave that explosion as a stale reason for death which might show up strangely ("crushed to death by a gas spore's explosion" when killed by an opening drawbridge) add database entry for "martial arts" +add catch-all database entry for the polearms starting inventory for rogues specified +9 lock pick, where +/-N is meaningless fix pile mark when picking up all-but-one items while invisible improve config file error reporting @@ -509,8 +510,17 @@ the Wizard, Angels and lawful minions, the Riders, shopkeep/priest in own room are never frightened by tooled horns 'Iu' would reveal unknown container contents if carrying one unpaid item inside a hero-owned container whose contents weren't known -docall wasn't taking the space allocation needed for the object name + "Call :" - into account in the prompt string +docall for type of object could overflow its prompt buffer if there was a very + long type name previously assigned +whatis lookup for 'more info?' would behave strangely for plural names, either + entered by player or from "N foo" stacks on the map +you should not hear a whistle if you are deaf +change the deity's "congratulations" message upon ascension to something which + sounds a bit more archaic to fit better with the other messages +prayer boon of 'fix all troubles' could get stuck in an infinite loop for + TROUBLE_STUCK_IN_WALL if there was no spot to teleport into available +It shouldn't be considered hypocrisy if you speed up your pet while standing + on Elbereth Fixes to Post-3.6.0 Problems that Were Exposed Via git Repository @@ -576,6 +586,9 @@ try again to fix achievement recording bug with mines and sokoban prizes the fix for secret doors on special levels always having vertical orientation resulted in some--but not all--secret doors within vertical walls being displayed as horizontal walls while still hidden +and the previous fix for the for secret doors didn't work if the level hadn't + been wallified yet (Cav quest) so horizontal wall with secret door + mis-displayed as a vertical wall segment could occur the fix intended for "a shop object stolen from outside the shop (via grappling hook) would be left marked as 'unpaid'" broke normal pickup, preventing any picked up item from merging with compatible stack @@ -584,6 +597,11 @@ unix: fix for freeing MAIL introduced a one-byte buffer overrun which could interfere with malloc/free operation unix: fix for freeing MAIL also introduced a memory leak whenever new mail is detected and MAIL comes from the environment +when clairvoyance lets you move the cursor to examine the map (if it occurs + when engulfed or underwater or when blessed clairvoyance finds a + monster), the "for instructions type '?'" prompt could be confusing +prevent Mjollnir from being auto-quivered if it's been thrown without return + and then picked back up while quiver slot is empty Platform- and/or Interface-Specific Fixes @@ -621,6 +639,8 @@ unix: race condition with parallel make: src/Makefile might start building unix: Makefile.{src,utl} ignored CPPFLAGS which is expanded by the default .c rule by GNU make so if user had a value for that in the environment, it would apply to some files but not others; explicitly override it +unix: enable code guarded by USE_WIN_IOCTL by default unless prevented by + uncommenting #define AVOID_WIN_IOCTL in include/unixconf.h win32gui: getversionstring() was overflowing the provided Help About buffer win32gui: guard against buffer overflow in in mswin_getlin() win32gui: handle menu_color attribute @@ -774,6 +794,9 @@ change #adjust's behavior when collecting compatible stacks; that used to a prayer result which results in uncursing some or all of the hero's items won't uncurse a worn helm of opposite alignment since that would facilitate the hero switching to another god by taking it off +wielded aklys behaves like Mjollnir when thrown--it usually returns; unlike + Mjollnir, it isn't limited to Valkyries or need gauntlets of power + (so far, hero-only; an aklys won't return if thrown by a monster) Platform- and/or Interface-Specific New Features diff --git a/doc/makedefs.6 b/doc/makedefs.6 index 822e445f3..eb1df4baf 100644 --- a/doc/makedefs.6 +++ b/doc/makedefs.6 @@ -85,6 +85,14 @@ Generate .I date.h and .I options +file. It will read +.I dat/gitinfo.txt +,only if it is present, to obtain +.B githash= +and +.B gitbranch= + info and include related preprocessor #defines in +.I date.h file. .br .TP diff --git a/doc/nethack.6 b/doc/nethack.6 index 3803ae583..f2ef799f1 100644 --- a/doc/nethack.6 +++ b/doc/nethack.6 @@ -1,5 +1,5 @@ .TH NETHACK 6 "7 December 2015" -.\" NetHack 3.6 nethack.6 $NHDT-Date: 1449616496 2015/12/08 23:14:56 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.11 $ +.\" NetHack 3.6 nethack.6 $NHDT-Date: 1519228609 2018/02/21 15:56:49 $ $NHDT-Branch: githash $:$NHDT-Revision: 1.13 $ .SH NAME nethack \- Exploring The Mazes of Menace .SH SYNOPSIS @@ -34,6 +34,9 @@ nethack \- Exploring The Mazes of Menace [ .B \-ibm ] +[ +.BR \-\-version [ :paste ] +] .PP .B nethack [ @@ -207,6 +210,17 @@ The playground must contain several auxiliary files such as help files, the list of top scorers, and a subdirectory .I save where games are saved. +.PP +.B \-\-version +can be used to cause NetHack to show the version information it +was compiled with, then exit. That will include the +.I git +commit hash if the information was available when the game was compiled. +On some platforms, such as windows and macosx, a variation +.B \-\-version:paste +can be used to cause NetHack to show the version information, then exit, +while also leaving a copy of the version information in the paste buffer +or clipboard for potential insertion into things like bug reports. .SH AUTHORS .PP Jay Fenlason (+ Kenny Woodland, Mike Thome and Jon Payne) wrote the diff --git a/doc/nethack.txt b/doc/nethack.txt index 9e6275edf..4c9986349 100644 --- a/doc/nethack.txt +++ b/doc/nethack.txt @@ -7,7 +7,7 @@ NAME SYNOPSIS nethack [ -d directory ] [ -n ] [ -p profession ] [ -r race ] [ -[DX] ] - [ -u playername ] [ -dec ] [ -ibm ] + [ -u playername ] [ -dec ] [ -ibm ] [ --version[:paste] ] nethack [ -d directory ] -s [ -v ] [ -p profession ] [ -r race ] [ playernames ] diff --git a/include/decl.h b/include/decl.h index b36c730f6..736068427 100644 --- a/include/decl.h +++ b/include/decl.h @@ -426,6 +426,15 @@ E const char *ARGV0; E void NDECL((*dropleveltempsfn)); #endif +enum earlyarg {ARG_DEBUG, ARG_VERSION}; + +struct early_opt { + enum earlyarg e; + const char *name; + int minlength; + boolean valallowed; +}; + #undef E #endif /* DECL_H */ diff --git a/include/extern.h b/include/extern.h index 8a03a4735..e8d850875 100644 --- a/include/extern.h +++ b/include/extern.h @@ -26,6 +26,7 @@ E void NDECL(display_gamewindows); E void NDECL(newgame); E void FDECL(welcome, (BOOLEAN_P)); E time_t NDECL(get_realtime); +E boolean FDECL(argcheck, (int, char **, enum earlyarg)); /* ### apply.c ### */ @@ -1919,6 +1920,7 @@ E const char *NDECL(bottlename); /* ### pray.c ### */ E boolean FDECL(critically_low_hp, (BOOLEAN_P)); +E boolean NDECL(stuck_in_wall); #ifdef USE_TRAMPOLI E int NDECL(prayer_done); #endif @@ -2570,10 +2572,14 @@ E void FDECL(store_version, (int)); E unsigned long FDECL(get_feature_notice_ver, (char *)); E unsigned long NDECL(get_current_feature_ver); E const char *FDECL(copyright_banner_line, (int)); +E void FDECL(early_version_info, (BOOLEAN_P)); #ifdef RUNTIME_PORT_ID E char *FDECL(get_port_id, (char *)); #endif +#ifdef RUNTIME_PASTEBUF_SUPPORT +E void FDECL(port_insert_pastebuf, (char *)); +#endif /* ### video.c ### */ diff --git a/include/ntconf.h b/include/ntconf.h index a096a2ff1..534fa6e5d 100644 --- a/include/ntconf.h +++ b/include/ntconf.h @@ -69,6 +69,12 @@ #define PORT_DEBUG /* include ability to debug international keyboard issues \ */ +#define RUNTIME_PORT_ID /* trigger run-time port identification for \ + * identification of exe CPU architecture \ + */ +#define RUNTIME_PASTEBUF_SUPPORT + + #define SAFERHANGUP /* Define SAFERHANGUP to delay hangup processing \ * until the main command loop. 'safer' because it \ * avoids certain cheats and also avoids losing \ @@ -117,11 +123,6 @@ extern void FDECL(interject, (int)); #endif #endif /* _MSC_VER */ - -#define RUNTIME_PORT_ID /* trigger run-time port identification for \ - * identification of exe CPU architecture \ - */ - /* The following is needed for prototypes of certain functions */ #if defined(_MSC_VER) #include /* Provides prototypes of exit(), spawn() */ diff --git a/include/unixconf.h b/include/unixconf.h index 0d4fbce17..cec8c709a 100644 --- a/include/unixconf.h +++ b/include/unixconf.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 unixconf.h $NHDT-Date: 1451342112 2015/12/28 22:35:12 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.25 $ */ +/* NetHack 3.6 unixconf.h $NHDT-Date: 1520099325 2018/03/03 17:48:45 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.30 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -136,6 +136,8 @@ #define TIMED_DELAY #endif +/* #define AVOID_WIN_IOCTL */ /* ensure USE_WIN_IOCTL remains undefined */ + /* * If you define MAIL, then the player will be notified of new mail * when it arrives. If you also define DEF_MAILREADER then this will @@ -387,5 +389,9 @@ #endif /* LINUX */ #endif /* GNOME_GRAPHICS */ +#ifdef __APPLE__ +# define RUNTIME_PASTEBUF_SUPPORT +#endif + #endif /* UNIXCONF_H */ #endif /* UNIX */ diff --git a/include/winprocs.h b/include/winprocs.h index 4d0d395a1..3c19d4f03 100644 --- a/include/winprocs.h +++ b/include/winprocs.h @@ -359,7 +359,7 @@ struct chain_procs { void FDECL((*win_status_finish), (CARGS)); void FDECL((*win_status_enablefield), (CARGS, int, const char *, const char *, BOOLEAN_P)); - void FDECL((*win_status_update), (CARGS, int, genericptr_t, int, int, int, unsigned long)); + void FDECL((*win_status_update), (CARGS, int, genericptr_t, int, int, int, unsigned long *)); boolean FDECL((*win_can_suspend), (CARGS)); }; #endif /* WINCHAIN */ diff --git a/src/allmain.c b/src/allmain.c index f4eee4fd1..cea196c09 100644 --- a/src/allmain.c +++ b/src/allmain.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 allmain.c $NHDT-Date: 1513130016 2017/12/13 01:53:36 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.81 $ */ +/* NetHack 3.6 allmain.c $NHDT-Date: 1518193644 2018/02/09 16:27:24 $ $NHDT-Branch: githash $:$NHDT-Revision: 1.86 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -745,5 +745,88 @@ const char *msg; } } +/* + * Argument processing helpers - for xxmain() to share + * and call. + * + * These should return TRUE if the argument matched, + * whether the processing of the argument was + * successful or not. + * + * Most of these do their thing, then after returning + * to xxmain(), the code exits without starting a game. + * + */ + +static struct early_opt earlyopts[] = { + {ARG_DEBUG, "debug", 5, FALSE}, + {ARG_VERSION, "version", 4, TRUE}, +}; + +boolean +argcheck(argc, argv, e_arg) +int argc; +char *argv[]; +enum earlyarg e_arg; +{ + int i, idx; + boolean match = FALSE; + char *userea = (char *)0; + const char *dashdash = ""; + + for (idx = 0; idx < SIZE(earlyopts); idx++) { + if (earlyopts[idx].e == e_arg) + break; + } + if ((idx >= SIZE(earlyopts)) || (argc <= 1)) + return FALSE; + + for (i = 1; i < argc; ++i) { + if (argv[i][0] != '-') + continue; + if (argv[i][1] == '-') { + userea = &argv[i][2]; + dashdash = "-"; + } else { + userea = &argv[i][1]; + } + match = match_optname(userea, earlyopts[idx].name, + earlyopts[idx].minlength, earlyopts[idx].valallowed); + if (match) break; + } + + if (match) { + switch(e_arg) { + case ARG_DEBUG: + break; + case ARG_VERSION: { + boolean insert_into_pastebuf = FALSE; + const char *extended_opt = index(userea,':'); + + if (!extended_opt) + extended_opt = index(userea, '='); + + if (extended_opt) { + extended_opt++; + if (match_optname(extended_opt, "paste", + 5, FALSE)) { + insert_into_pastebuf = TRUE; + } else { + raw_printf( + "-%sversion can only be extended with -%sversion:paste.\n", + dashdash, dashdash); + return TRUE; + } + } + early_version_info(insert_into_pastebuf); + return TRUE; + break; + } + default: + break; + } + }; + return FALSE; +} /*allmain.c*/ diff --git a/src/apply.c b/src/apply.c index 130a53d33..c28e01087 100644 --- a/src/apply.c +++ b/src/apply.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 apply.c $NHDT-Date: 1496619131 2017/06/04 23:32:11 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.232 $ */ +/* NetHack 3.6 apply.c $NHDT-Date: 1519598527 2018/02/25 22:42:07 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.243 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -442,7 +442,11 @@ struct obj *obj; } else if (Underwater) { You("blow bubbles through %s.", yname(obj)); } else { - You(whistle_str, obj->cursed ? "shrill" : "high"); + if (Deaf) + You_feel("rushing air tickle your %s.", + body_part(NOSE)); + else + You(whistle_str, obj->cursed ? "shrill" : "high"); wake_nearby(); if (obj->cursed) vault_summon_gd(); diff --git a/src/botl.c b/src/botl.c index f0ee33fd0..78e9b7e59 100644 --- a/src/botl.c +++ b/src/botl.c @@ -1296,9 +1296,8 @@ merge_bestcolor(bestcolor, newcolor) int *bestcolor; int newcolor; { - int batr, bclr, natr, nclr; + int natr = HL_UNDEF, nclr = NO_COLOR; - split_clridx(*bestcolor, &bclr, &batr); split_clridx(newcolor, &nclr, &natr); if (nclr != NO_COLOR) diff --git a/src/detect.c b/src/detect.c index 1c5f35203..d835bd86d 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 detect.c $NHDT-Date: 1495346103 2017/05/21 05:55:03 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.77 $ */ +/* NetHack 3.6 detect.c $NHDT-Date: 1519281847 2018/02/22 06:44:07 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.80 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1324,6 +1324,10 @@ struct obj *sobj; /* scroll--actually fake spellbook--object */ if (!level.flags.hero_memory || unconstrained || mdetected) { flush_screen(1); /* flush temp screen */ + /* the getpos() prompt from browse_map() is only shown when + flags.verbose is set, but make this unconditional so that + not-verbose users become aware of the prompting situation */ + You("sense your surroundings."); if (extended || glyph_is_monster(glyph_at(u.ux, u.uy))) ter_typ |= TER_MON; if (extended) diff --git a/src/dig.c b/src/dig.c index 0886ed477..d1a557648 100644 --- a/src/dig.c +++ b/src/dig.c @@ -1714,36 +1714,47 @@ struct obj * buried_ball(cc) coord *cc; { - xchar check_x, check_y; - struct obj *otmp, *otmp2; + int odist, bdist = COLNO; + struct obj *otmp, *ball = 0; - if (u.utraptype == TT_BURIEDBALL) - for (otmp = level.buriedobjlist; otmp; otmp = otmp2) { - otmp2 = otmp->nobj; + /* FIXME: + * This is just approximate; if multiple buried balls meet the + * criterium (within 2 steps of tethered hero's present location) + * it will find an arbitrary one rather than the one which used + * to be uball. Once 3.6.{0,1} save file compatibility is broken, + * we should add context.buriedball_oid and then we can find the + * actual former uball, which might be extra heavy or christened + * or not the one buried directly underneath the target spot. + * + * [Why does this search within a radius of two when trapmove() + * only lets hero get one step away from the buried ball?] + */ + + if (u.utrap && u.utraptype == TT_BURIEDBALL) + for (otmp = level.buriedobjlist; otmp; otmp = otmp->nobj) { if (otmp->otyp != HEAVY_IRON_BALL) continue; - /* try the exact location first */ + /* if found at the target spot, we're done */ if (otmp->ox == cc->x && otmp->oy == cc->y) return otmp; - /* Now try the vicinity */ - /* - * (x-2,y-2) (x+2,y-2) - * (x,y) - * (x-2,y+2) (x+2,y+2) + /* find nearest within allowable vicinity: +/-2 + * 4 5 8 + * 1 2 5 + * 0 1 4 */ - for (check_x = cc->x - 2; check_x <= cc->x + 2; ++check_x) - for (check_y = cc->y - 2; check_y <= cc->y + 2; ++check_y) { - if (check_x == cc->x && check_y == cc->y) - continue; - if (isok(check_x, check_y) - && (otmp->ox == check_x && otmp->oy == check_y)) { - cc->x = check_x; - cc->y = check_y; - return otmp; - } - } + odist = dist2(otmp->ox, otmp->oy, cc->x, cc->y); + if (odist <= 8 && (!ball || odist < bdist)) { + /* remember nearest buried ball but keep checking others */ + ball = otmp; + bdist = odist; + } } - return (struct obj *) 0; + if (ball) { + /* found, but not at < cc->x, cc->y > */ + cc->x = ball->ox; + cc->y = ball->oy; + } + return ball; } void @@ -1751,6 +1762,7 @@ buried_ball_to_punishment() { coord cc; struct obj *ball; + cc.x = u.ux; cc.y = u.uy; ball = buried_ball(&cc); @@ -1774,6 +1786,7 @@ buried_ball_to_freedom() { coord cc; struct obj *ball; + cc.x = u.ux; cc.y = u.uy; ball = buried_ball(&cc); @@ -1913,7 +1926,8 @@ int x, y; for (otmp = level.buriedobjlist; otmp; otmp = otmp2) { otmp2 = otmp->nobj; if (otmp->ox == x && otmp->oy == y) { - if (bball && otmp == bball && u.utraptype == TT_BURIEDBALL) { + if (bball && otmp == bball + && u.utrap && u.utraptype == TT_BURIEDBALL) { buried_ball_to_punishment(); } else { obj_extract_self(otmp); diff --git a/src/do_name.c b/src/do_name.c index db226a548..ae57474f9 100644 --- a/src/do_name.c +++ b/src/do_name.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 do_name.c $NHDT-Date: 1496531112 2017/06/03 23:05:12 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.119 $ */ +/* NetHack 3.6 do_name.c $NHDT-Date: 1519420054 2018/02/23 21:07:34 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.128 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -6,8 +6,7 @@ STATIC_DCL char *NDECL(nextmbuf); STATIC_DCL void FDECL(getpos_help, (BOOLEAN_P, const char *)); -STATIC_DCL int FDECL(CFDECLSPEC cmp_coord_distu, (const void *, - const void *)); +STATIC_DCL int FDECL(CFDECLSPEC cmp_coord_distu, (const void *, const void *)); STATIC_DCL boolean FDECL(gather_locs_interesting, (int, int, int)); STATIC_DCL void FDECL(gather_locs, (coord **, int *, int)); STATIC_DCL int FDECL(gloc_filter_floodfill_matcharea, (int, int)); @@ -15,6 +14,7 @@ STATIC_DCL void FDECL(auto_describe, (int, int)); STATIC_DCL void NDECL(do_mname); STATIC_DCL boolean FDECL(alreadynamed, (struct monst *, char *, char *)); STATIC_DCL void FDECL(do_oname, (struct obj *)); +STATIC_PTR char *FDECL(docall_xname, (struct obj *)); STATIC_DCL void NDECL(namefloorobj); STATIC_DCL char *FDECL(bogusmon, (char *,char *)); @@ -37,12 +37,13 @@ nextmbuf() * parameter value 0 = initialize, 1 = highlight, 2 = done */ static void FDECL((*getpos_hilitefunc), (int)) = (void FDECL((*), (int))) 0; -static boolean FDECL((*getpos_getvalid), (int,int)) = (boolean FDECL((*), (int,int))) 0; +static boolean FDECL((*getpos_getvalid), (int, int)) = + (boolean FDECL((*), (int, int))) 0; void getpos_sethilite(gp_hilitef, gp_getvalidf) void FDECL((*gp_hilitef), (int)); -boolean FDECL((*gp_getvalidf), (int,int)); +boolean FDECL((*gp_getvalidf), (int, int)); { getpos_hilitefunc = gp_hilitef; getpos_getvalid = gp_getvalidf; @@ -138,16 +139,18 @@ const char *goal; visctrl(Cmd.spkeys[NHKF_GETPOS_MOVESKIP]), fastmovemode[!iflags.getloc_moveskip]); putstr(tmpwin, 0, sbuf); - - Sprintf(sbuf, "Use '%s' to toggle menu listing for possible targets.", - visctrl(Cmd.spkeys[NHKF_GETPOS_MENU])); - putstr(tmpwin, 0, sbuf); - Sprintf(sbuf, - "Use '%s' to change the mode of limiting possible targets.", - visctrl(Cmd.spkeys[NHKF_GETPOS_LIMITVIEW])); - putstr(tmpwin, 0, sbuf); + if (!iflags.terrainmode || (iflags.terrainmode & TER_DETECT) == 0) { + Sprintf(sbuf, "Use '%s' to toggle menu listing for possible targets.", + visctrl(Cmd.spkeys[NHKF_GETPOS_MENU])); + putstr(tmpwin, 0, sbuf); + Sprintf(sbuf, + "Use '%s' to change the mode of limiting possible targets.", + visctrl(Cmd.spkeys[NHKF_GETPOS_LIMITVIEW])); + putstr(tmpwin, 0, sbuf); + } if (!iflags.terrainmode) { char kbuf[BUFSZ]; + if (getpos_getvalid) { Sprintf(sbuf, "Use '%s' or '%s' to move to valid locations.", visctrl(Cmd.spkeys[NHKF_GETPOS_VALID_NEXT]), @@ -282,20 +285,21 @@ int x,y; if (glyph == gloc_filter_floodfill_match_glyph) return TRUE; - if (gloc_filter_classify_glyph(glyph) == gloc_filter_classify_glyph(gloc_filter_floodfill_match_glyph)) + if (gloc_filter_classify_glyph(glyph) + == gloc_filter_classify_glyph(gloc_filter_floodfill_match_glyph)) return TRUE; return FALSE; } void -gloc_filter_floodfill(x,y) -int x,y; +gloc_filter_floodfill(x, y) +int x, y; { - gloc_filter_floodfill_match_glyph = back_to_glyph(x,y); + gloc_filter_floodfill_match_glyph = back_to_glyph(x, y); set_selection_floodfillchk(gloc_filter_floodfill_matcharea); - selection_floodfill(gloc_filter_map, x,y, FALSE); + selection_floodfill(gloc_filter_map, x, y, FALSE); } void @@ -330,23 +334,20 @@ gloc_filter_done() } } - STATIC_OVL boolean -gather_locs_interesting(x,y, gloc) -int x,y, gloc; +gather_locs_interesting(x, y, gloc) +int x, y, gloc; { /* TODO: if glyph is a pile glyph, convert to ordinary one * in order to keep tail/boulder/rock check simple. */ int glyph = glyph_at(x, y); - if (iflags.getloc_filter == GFILTER_VIEW && !cansee(x,y)) + if (iflags.getloc_filter == GFILTER_VIEW && !cansee(x, y)) return FALSE; - if (iflags.getloc_filter == GFILTER_AREA && !GLOC_SAME_AREA(x,y) - && !GLOC_SAME_AREA(x-1,y) - && !GLOC_SAME_AREA(x,y-1) - && !GLOC_SAME_AREA(x+1,y) - && !GLOC_SAME_AREA(x,y+1)) + if (iflags.getloc_filter == GFILTER_AREA && !GLOC_SAME_AREA(x, y) + && !GLOC_SAME_AREA(x - 1, y) && !GLOC_SAME_AREA(x, y - 1) + && !GLOC_SAME_AREA(x + 1, y) && !GLOC_SAME_AREA(x, y + 1)) return FALSE; switch (gloc) { @@ -480,7 +481,8 @@ boolean fulldir; if (dx) { if (abs(dx) > 9999) dx = sgn(dx) * 9999; - Sprintf(eos(buf), "%d%s", abs(dx), dirnames[2 + (dx > 0)][fulldir]); + Sprintf(eos(buf), "%d%s", abs(dx), + dirnames[2 + (dx > 0)][fulldir]); } } return buf; @@ -544,8 +546,9 @@ int cx, cy; (void) coord_desc(cx, cy, tmpbuf, iflags.getpos_coords); custompline(SUPPRESS_HISTORY, "%s%s%s%s%s", firstmatch, *tmpbuf ? " " : "", tmpbuf, - (iflags.autodescribe && getpos_getvalid && !getpos_getvalid(cx,cy)) - ? " (illegal)" : "", + (iflags.autodescribe + && getpos_getvalid && !getpos_getvalid(cx, cy)) + ? " (illegal)" : "", (iflags.getloc_travelmode && !is_valid_travelpt(cx, cy)) ? " (no travel path)" : ""); curs(WIN_MAP, cx, cy); @@ -590,8 +593,10 @@ int gloc; tmpcc.x = garr[i].x; tmpcc.y = garr[i].y; if (do_screen_description(tmpcc, TRUE, sym, tmpbuf, &firstmatch)) { - (void) coord_desc(garr[i].x, garr[i].y, tmpbuf, iflags.getpos_coords); - Sprintf(fullbuf, "%s%s%s", firstmatch, (*tmpbuf ? " " : ""), tmpbuf); + (void) coord_desc(garr[i].x, garr[i].y, tmpbuf, + iflags.getpos_coords); + Sprintf(fullbuf, "%s%s%s", firstmatch, + (*tmpbuf ? " " : ""), tmpbuf); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, fullbuf, MENU_UNSELECTED); } @@ -738,8 +743,9 @@ const char *goal; dy = ydir[i]; while (isok(cx + dx, cy + dy) && glyph == glyph_at(cx + dx, cy + dy) - && isok(cx + dx+xdir[i], cy+dy+ydir[i]) - && glyph == glyph_at(cx + dx+xdir[i], cy + dy+ydir[i])) { + && isok(cx + dx + xdir[i], cy + dy + ydir[i]) + && glyph == glyph_at(cx + dx + xdir[i], + cy + dy + ydir[i])) { dx += xdir[i]; dy += ydir[i]; } @@ -928,10 +934,9 @@ const char *goal; if (!force) Strcpy(note, "aborted"); - else - Sprintf(note, "use '%c', '%c', '%c', '%c' or '%s'", /* hjkl */ - Cmd.move_W, Cmd.move_S, Cmd.move_N, - Cmd.move_E, + else /* hjkl */ + Sprintf(note, "use '%c', '%c', '%c', '%c' or '%s'", + Cmd.move_W, Cmd.move_S, Cmd.move_N, Cmd.move_E, visctrl(Cmd.spkeys[NHKF_GETPOS_PICK])); pline("Unknown direction: '%s' (%s).", visctrl((char) c), note); @@ -966,7 +971,7 @@ const char *goal; if (garr[i]) free((genericptr_t) garr[i]); getpos_hilitefunc = (void FDECL((*), (int))) 0; - getpos_getvalid = (boolean FDECL((*), (int,int))) 0; + getpos_getvalid = (boolean FDECL((*), (int, int))) 0; return result; } @@ -1401,33 +1406,56 @@ docallcmd() return 0; } +/* for use by safe_qbuf() */ +STATIC_PTR char * +docall_xname(obj) +struct obj *obj; +{ + struct obj otemp; + + otemp = *obj; + otemp.oextra = (struct oextra *) 0; + otemp.quan = 1L; + /* in case water is already known, convert "[un]holy water" to "water" */ + otemp.blessed = otemp.cursed = 0; + /* remove attributes that are doname() caliber but get formatted + by xname(); most of these fixups aren't really needed because the + relevant type of object isn't callable so won't reach this far */ + if (otemp.oclass == WEAPON_CLASS) + otemp.opoisoned = 0; /* not poisoned */ + else if (otemp.oclass == POTION_CLASS) + otemp.odiluted = 0; /* not diluted */ + else if (otemp.otyp == TOWEL || otemp.otyp == STATUE) + otemp.spe = 0; /* not wet or historic */ + else if (otemp.otyp == TIN) + otemp.known = 0; /* suppress tin type (homemade, &c) and mon type */ + else if (otemp.otyp == FIGURINE) + otemp.corpsenm = NON_PM; /* suppress mon type */ + else if (otemp.otyp == HEAVY_IRON_BALL) + otemp.owt = objects[HEAVY_IRON_BALL].oc_weight; /* not "very heavy" */ + else if (otemp.oclass == FOOD_CLASS && otemp.globby) + otemp.owt = 120; /* 6*20, neither a small glob nor a large one */ + + return an(xname(&otemp)); +} + void docall(obj) -register struct obj *obj; +struct obj *obj; { char buf[BUFSZ], qbuf[QBUFSZ]; - struct obj otemp; - register char **str1; + char **str1; if (!obj->dknown) return; /* probably blind */ - otemp = *obj; - otemp.quan = 1L; - otemp.oextra = (struct oextra *) 0; - if (objects[otemp.otyp].oc_class == POTION_CLASS && otemp.fromsink) { + if (obj->oclass == POTION_CLASS && obj->fromsink) /* kludge, meaning it's sink water */ Sprintf(qbuf, "Call a stream of %s fluid:", - OBJ_DESCR(objects[otemp.otyp])); - } else { - char tmpbuf[BUFSZ], *tmpname = an(xname(&otemp)); - - if (strlen(tmpname) < (BUFSZ - 1)) { - Strcpy(tmpbuf, tmpname); - tmpbuf[QBUFSZ - 7] = '\0'; /* need room for "Call :"*/ - Sprintf(qbuf, "Call %s:", tmpbuf); - } - } + OBJ_DESCR(objects[obj->otyp])); + else + (void) safe_qbuf(qbuf, "Call ", ":", obj, + docall_xname, simpleonames, "thing"); getlin(qbuf, buf); if (!*buf || *buf == '\033') return; diff --git a/src/dothrow.c b/src/dothrow.c index 0b1539454..0c889cd29 100644 --- a/src/dothrow.c +++ b/src/dothrow.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 dothrow.c $NHDT-Date: 1502243899 2017/08/09 01:58:19 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.125 $ */ +/* NetHack 3.6 dothrow.c $NHDT-Date: 1520103267 2018/03/03 18:54:27 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.133 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1068,8 +1068,7 @@ void throwit(obj, wep_mask, twoweap) struct obj *obj; long wep_mask; /* used to re-equip returning boomerang */ -boolean - twoweap; /* used to restore twoweapon mode if wielded weapon returns */ +boolean twoweap; /* used to restore twoweapon mode if wielded weapon returns */ { register struct monst *mon; register int range, urange; @@ -1079,6 +1078,7 @@ boolean notonhead = FALSE; /* reset potentially stale value */ if ((obj->cursed || obj->greased) && (u.dx || u.dy) && !rn2(7)) { boolean slipok = TRUE; + if (ammo_and_launcher(obj, uwep)) pline("%s!", Tobjnam(obj, "misfire")); else { @@ -1120,12 +1120,18 @@ boolean bhitpos.x = mon->mx; bhitpos.y = mon->my; } else if (u.dz) { - if (u.dz < 0 && Role_if(PM_VALKYRIE) && obj->oartifact == ART_MJOLLNIR + if (u.dz < 0 + /* Mjollnir must we wielded to be thrown--caller verifies this; + aklys must we wielded as primary to return when thrown */ + && ((Role_if(PM_VALKYRIE) && obj->oartifact == ART_MJOLLNIR) + || (obj->otyp == AKLYS && (wep_mask & W_WEP) != 0)) && !impaired) { pline("%s the %s and returns to your hand!", Tobjnam(obj, "hit"), ceiling(u.ux, u.uy)); obj = addinv(obj); (void) encumber_msg(); + if (obj->owornmask & W_QUIVER) /* in case addinv() autoquivered */ + setuqwep((struct obj *) 0); setuwep(obj); u.twoweap = twoweap; } else if (u.dz < 0) { @@ -1203,6 +1209,10 @@ boolean range = 20; /* you must be giant */ else if (obj->oartifact == ART_MJOLLNIR) range = (range + 1) / 2; /* it's heavy */ + else if (obj->otyp == AKLYS && (wep_mask & W_WEP) != 0) + /* if an aklys is going to return, range is limited by the + length of the attached cord [implicit aspect of item] */ + range = min(range, BOLT_LIM / 2); else if (obj == uball && u.utrap && u.utraptype == TT_INFLOOR) range = 1; @@ -1253,47 +1263,65 @@ boolean (void) mpickobj(u.ustuck, obj); thrownobj = (struct obj *) 0; } else { - /* the code following might become part of dropy() */ - if (obj->oartifact == ART_MJOLLNIR && Role_if(PM_VALKYRIE) - && rn2(100)) { - /* we must be wearing Gauntlets of Power to get here */ - sho_obj_return_to_u(obj); /* display its flight */ + /* Mjollnir must we wielded to be thrown--caller verifies this; + aklys must we wielded as primary to return when thrown */ + if ((obj->oartifact == ART_MJOLLNIR && Role_if(PM_VALKYRIE)) + || (obj->otyp == AKLYS && (wep_mask & W_WEP) != 0)) { + if (rn2(100)) { + sho_obj_return_to_u(obj); /* display its flight */ - if (!impaired && rn2(100)) { - pline("%s to your hand!", Tobjnam(obj, "return")); - obj = addinv(obj); - (void) encumber_msg(); - setuwep(obj); - u.twoweap = twoweap; - if (cansee(bhitpos.x, bhitpos.y)) - newsym(bhitpos.x, bhitpos.y); - } else { - int dmg = rn2(2); - if (!dmg) { - pline(Blind ? "%s lands %s your %s." - : "%s back to you, landing %s your %s.", - Blind ? Something : Tobjnam(obj, "return"), - Levitation ? "beneath" : "at", - makeplural(body_part(FOOT))); + if (!impaired && rn2(100)) { + pline("%s to your hand!", Tobjnam(obj, "return")); + obj = addinv(obj); + (void) encumber_msg(); + /* addinv autoquivers an aklys if quiver is empty; + if obj is quivered, remove it before wielding */ + if (obj->owornmask & W_QUIVER) + setuqwep((struct obj *) 0); + setuwep(obj); + u.twoweap = twoweap; + if (cansee(bhitpos.x, bhitpos.y)) + newsym(bhitpos.x, bhitpos.y); } else { - dmg += rnd(3); - pline(Blind ? "%s your %s!" - : "%s back toward you, hitting your %s!", - Tobjnam(obj, Blind ? "hit" : "fly"), - body_part(ARM)); - (void) artifact_hit((struct monst *) 0, &youmonst, obj, - &dmg, 0); - losehp(Maybe_Half_Phys(dmg), killer_xname(obj), - KILLED_BY); + int dmg = rn2(2); + + if (!dmg) { + pline(Blind ? "%s lands %s your %s." + : "%s back to you, landing %s your %s.", + Blind ? Something : Tobjnam(obj, "return"), + Levitation ? "beneath" : "at", + makeplural(body_part(FOOT))); + } else { + dmg += rnd(3); + pline(Blind ? "%s your %s!" + : "%s back toward you, hitting your %s!", + Tobjnam(obj, Blind ? "hit" : "fly"), + body_part(ARM)); + if (obj->oartifact) + (void) artifact_hit((struct monst *) 0, &youmonst, + obj, &dmg, 0); + losehp(Maybe_Half_Phys(dmg), killer_xname(obj), + KILLED_BY); + } + if (ship_object(obj, u.ux, u.uy, FALSE)) { + thrownobj = (struct obj *) 0; + return; + } + dropy(obj); } - if (ship_object(obj, u.ux, u.uy, FALSE)) { - thrownobj = (struct obj *) 0; - return; - } - dropy(obj); + thrownobj = (struct obj *) 0; + return; + } else { + /* when this location is stepped on, the weapon will be + auto-picked up due to 'obj->was_thrown' of 1; + addinv() prevents thrown Mjollnir from being placed + into the quiver slot, but an aklys will end up there if + that slot is empty at the time; since hero will need to + explicitly rewield the weapon to get throw-and-return + capability back anyway, quivered or not shouldn't matter */ + pline("%s to return!", Tobjnam(obj, "fail")); + /* continue below with placing 'obj' at target location */ } - thrownobj = (struct obj *) 0; - return; } if (!IS_SOFT(levl[bhitpos.x][bhitpos.y].typ) && breaktest(obj)) { diff --git a/src/files.c b/src/files.c index 4c46d23d0..f1bb770b2 100644 --- a/src/files.c +++ b/src/files.c @@ -1977,7 +1977,7 @@ int src; set_configfile_name(fqname(backward_compat_configfile, CONFIGPREFIX, 0)); if ((fp = fopenp(configfile, "r")) != (FILE *) 0) { return fp; - } else if (strcmp(backwad_compat_configfile, configfile)) { + } else if (strcmp(backward_compat_configfile, configfile)) { set_configfile_name(backward_compat_configfile); if ((fp = fopenp(configfile, "r")) != (FILE *) 0) return fp; diff --git a/src/invent.c b/src/invent.c index 828a947df..1cd0cdd1a 100644 --- a/src/invent.c +++ b/src/invent.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 invent.c $NHDT-Date: 1518053384 2018/02/08 01:29:44 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.224 $ */ +/* NetHack 3.6 invent.c $NHDT-Date: 1519672703 2018/02/26 19:18:23 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.225 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -598,6 +598,11 @@ struct obj *obj; /* fill empty quiver if obj was thrown */ if (flags.pickup_thrown && !uquiver && obj_was_thrown + /* if Mjollnir is thrown and fails to return, we want to + auto-pick it when we move to its spot, but not into quiver; + aklyses behave like Mjollnir when thrown while wielded, but + we lack sufficient information here make them exceptions */ + && obj->oartifact != ART_MJOLLNIR && (throwing_weapon(obj) || is_ammo(obj))) setuqwep(obj); added: diff --git a/src/mhitm.c b/src/mhitm.c index 16ca8085e..f920bb0d5 100644 --- a/src/mhitm.c +++ b/src/mhitm.c @@ -410,8 +410,9 @@ register struct monst *magr, *mdef; if (strike) { res[i] = hitmm(magr, mdef, mattk); if ((mdef->data == &mons[PM_BLACK_PUDDING] - || mdef->data == &mons[PM_BROWN_PUDDING]) && otmp - && objects[otmp->otyp].oc_material == IRON + || mdef->data == &mons[PM_BROWN_PUDDING]) + && (otmp && (objects[otmp->otyp].oc_material == IRON + || objects[otmp->otyp].oc_material == METAL)) && mdef->mhp > 1 && !mdef->mcan) { if (clone_mon(mdef, 0, 0)) { @@ -906,10 +907,17 @@ register struct attack *mattk; tmp = 0; } else if (mattk->aatyp == AT_WEAP) { if (otmp) { + struct obj *marmg; + if (otmp->otyp == CORPSE && touch_petrifies(&mons[otmp->corpsenm])) goto do_stone; tmp += dmgval(otmp, 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 (otmp->oartifact) { (void) artifact_hit(magr, mdef, otmp, &tmp, dieroll); if (mdef->mhp <= 0) diff --git a/src/mhitu.c b/src/mhitu.c index fb483b811..8bd4c33e1 100644 --- a/src/mhitu.c +++ b/src/mhitu.c @@ -972,6 +972,7 @@ register struct attack *mattk; struct obj *otmp = mon_currwep; if (mattk->aatyp == AT_WEAP && otmp) { + struct obj *marmg; int tmp; if (otmp->otyp == CORPSE @@ -983,6 +984,9 @@ register struct attack *mattk; goto do_stone; } dmg += dmgval(otmp, &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 @@ -1003,7 +1007,10 @@ register struct attack *mattk; tmp -= rnd(-u.uac); if (tmp < 1) tmp = 1; - if (u.mh - tmp > 1 && objects[otmp->otyp].oc_material == IRON + 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) diff --git a/src/mon.c b/src/mon.c index 62fb34a8f..7e82ba651 100644 --- a/src/mon.c +++ b/src/mon.c @@ -2751,7 +2751,6 @@ boolean via_attack; } } } - } /* wake up a monster, possibly making it angry in the process */ @@ -2761,9 +2760,6 @@ register struct monst *mtmp; boolean via_attack; { mtmp->msleeping = 0; - finish_meating(mtmp); - if (via_attack) - setmangry(mtmp, TRUE); if (mtmp->m_ap_type) { seemimic(mtmp); } else if (context.forcefight && !context.mon_moving @@ -2771,6 +2767,9 @@ boolean via_attack; mtmp->mundetected = 0; newsym(mtmp->mx, mtmp->my); } + finish_meating(mtmp); + if (via_attack) + setmangry(mtmp, TRUE); } /* Wake up nearby monsters without angering them. */ diff --git a/src/mplayer.c b/src/mplayer.c index ec895546c..dfb97ab85 100644 --- a/src/mplayer.c +++ b/src/mplayer.c @@ -285,7 +285,9 @@ register boolean special; mk_mplayer_armor(mtmp, cloak); mk_mplayer_armor(mtmp, helm); mk_mplayer_armor(mtmp, shield); - if (rn2(8)) + if (weapon == WAR_HAMMER) /* valkyrie: wimpy weapon or Mjollnir */ + mk_mplayer_armor(mtmp, GAUNTLETS_OF_POWER); + else if (rn2(8)) mk_mplayer_armor(mtmp, rnd_class(LEATHER_GLOVES, GAUNTLETS_OF_DEXTERITY)); if (rn2(8)) @@ -337,7 +339,7 @@ boolean special; int tryct = 0; /* roll for character class */ - pm = PM_ARCHEOLOGIST + rn2(PM_WIZARD - PM_ARCHEOLOGIST + 1); + pm = rn1(PM_WIZARD - PM_ARCHEOLOGIST + 1, PM_ARCHEOLOGIST); set_mon_data(&fakemon, &mons[pm], -1); /* roll for an available location */ diff --git a/src/objnam.c b/src/objnam.c index 5daead647..90c96e156 100644 --- a/src/objnam.c +++ b/src/objnam.c @@ -2033,14 +2033,18 @@ static struct sing_plur one_off[] = { { "erinys", "erinyes" }, { "foot", "feet" }, { "fungus", "fungi" }, + { "goose", "geese" }, { "knife", "knives" }, { "labrum", "labra" }, /* candelabrum */ { "louse", "lice" }, { "mouse", "mice" }, { "mumak", "mumakil" }, { "nemesis", "nemeses" }, + { "ovum", "ova" }, + { "ox", "oxen" }, { "rtex", "rtices" }, /* vortex */ { "tooth", "teeth" }, + { "serum", "sera" }, { "staff", "staves" }, { 0, 0 } }; @@ -2050,10 +2054,11 @@ static const char *const as_is[] = { "boots", "shoes", "gloves", "lenses", "scales", "eyes", "gauntlets", "iron bars", /* both singular and plural are spelled the same */ - "deer", "fish", "tuna", "yaki", "-hai", - "krill", "manes", "ninja", "sheep", "ronin", - "roshi", "shito", "tengu", "ki-rin", "Nazgul", - "gunyoki", "piranha", "samurai", "shuriken", 0, + "deer", "elk", "fish", "tuna", "yaki", + "-hai", "krill", "manes", "moose", "ninja", + "sheep", "ronin", "roshi", "shito", "tengu", + "ki-rin", "Nazgul", "gunyoki", "piranha", "samurai", + "shuriken", 0, /* Note: "fish" and "piranha" are collective plurals, suitable for "wiped out all ". For "3 ", they should be "fishes" and "piranhas" instead. We settle for collective @@ -2089,7 +2094,8 @@ const char *const *alt_as_is; /* another set like as_is[] */ if more of these turn up, one_off[] entries will need to flagged as to which are whole words and which are matchable as suffices then matching in the loop below will end up becoming more complex */ - if (!strcmpi(basestr, "slice")) { + if (!strcmpi(basestr, "slice") + || !strcmpi(basestr, "mongoose")) { if (to_plural) (void) strkitten(basestr, 's'); return TRUE; diff --git a/src/pager.c b/src/pager.c index 5d9f4ddc1..5b57c27d4 100644 --- a/src/pager.c +++ b/src/pager.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 pager.c $NHDT-Date: 1505299155 2017/09/13 10:39:15 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.118 $ */ +/* NetHack 3.6 pager.c $NHDT-Date: 1519529752 2018/02/25 03:35:52 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.120 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -510,8 +510,6 @@ boolean user_typed_name, without_asking; char buf[BUFSZ], newstr[BUFSZ], givenname[BUFSZ]; char *ep, *dbase_str; unsigned long txt_offset = 0L; - int chk_skip, pass = 1; - boolean found_in_file = FALSE, skipping_entry = FALSE, yes_to_moreinfo; winid datawin = WIN_ERR; fp = dlb_fopen(DATAFILE, "r"); @@ -519,12 +517,10 @@ boolean user_typed_name, without_asking; pline("Cannot open data file!"); return; } - - /* - * If someone passed us garbage, prevent fault. - */ - if (!inp || (inp && strlen(inp) > (BUFSZ - 1))) { - pline("bad do_look buffer passed!"); + /* If someone passed us garbage, prevent fault. */ + if (!inp || strlen(inp) > (BUFSZ - 1)) { + impossible("bad do_look buffer passed (%s)!", + !inp ? "null" : "too long"); return; } @@ -538,6 +534,18 @@ boolean user_typed_name, without_asking; dbase_str = strcpy(newstr, inp); (void) lcase(dbase_str); + /* + * TODO: + * The switch from xname() to doname_vague_quan() in look_at_obj() + * had the unintendded side-effect of making names picked from + * pointing at map objects become harder to simplify for lookup. + * We should split the prefix and suffix handling used by wish + * parsing and also wizmode monster generation out into separate + * routines and use those routines here. This currently lacks + * erosion handling and probably lots of other bits and pieces + * that wishing already understands and most of this duplicates + * stuff already done for wish handling or monster generation. + */ if (!strncmp(dbase_str, "interior of ", 12)) dbase_str += 12; if (!strncmp(dbase_str, "a ", 2)) @@ -546,6 +554,15 @@ boolean user_typed_name, without_asking; dbase_str += 3; else if (!strncmp(dbase_str, "the ", 4)) dbase_str += 4; + else if (!strncmp(dbase_str, "some ", 5)) + dbase_str += 5; + else if (digit(*dbase_str)) { + /* remove count prefix ("2 ya") which can come from looking at map */ + while (digit(*dbase_str)) + ++dbase_str; + if (*dbase_str == ' ') + ++dbase_str; + } if (!strncmp(dbase_str, "tame ", 5)) dbase_str += 5; else if (!strncmp(dbase_str, "peaceful ", 9)) @@ -554,29 +571,65 @@ boolean user_typed_name, without_asking; dbase_str += 10; if (!strncmp(dbase_str, "saddled ", 8)) dbase_str += 8; + if (!strncmp(dbase_str, "blessed ", 8)) + dbase_str += 8; + else if (!strncmp(dbase_str, "uncursed ", 9)) + dbase_str += 9; + else if (!strncmp(dbase_str, "cursed ", 7)) + dbase_str += 7; + if (!strncmp(dbase_str, "empty ", 6)) + dbase_str += 6; + if (!strncmp(dbase_str, "partly used ", 12)) + dbase_str += 12; + else if (!strncmp(dbase_str, "partly eaten ", 13)) + dbase_str += 13; if (!strncmp(dbase_str, "statue of ", 10)) dbase_str[6] = '\0'; else if (!strncmp(dbase_str, "figurine of ", 12)) dbase_str[8] = '\0'; + /* remove enchantment ("+0 aklys"); [for 3.6.0 and earlier, this wasn't + needed because looking at items on the map used xname() rather than + doname() hence known enchantment was implicitly suppressed] */ + if (*dbase_str && index("+-", dbase_str[0]) && digit(dbase_str[1])) { + ++dbase_str; /* skip sign */ + while (digit(*dbase_str)) + ++dbase_str; + if (*dbase_str == ' ') + ++dbase_str; + } + /* "towel", "wet towel", and "moist towel" share one data.base entry; + for "wet towel", we keep prefix so that the prompt will ask about + "wet towel"; for "moist towel", we also want to ask about "wet towel". + (note: strncpy() only terminates output string if the specified + count is bigger than the length of the substring being copied) */ + if (!strncmp(dbase_str, "moist towel", 11)) + (void) strncpy(dbase_str += 2, "wet", 3); /* skip "mo" replace "ist" */ /* Make sure the name is non-empty. */ if (*dbase_str) { - /* adjust the input to remove "named " and convert to lower case */ - char *alt = 0; /* alternate description */ + long pass1offset = -1L; + int chk_skip, pass = 1; + boolean yes_to_moreinfo, found_in_file, pass1found_in_file, + skipping_entry; + char *ap, *alt = 0; /* alternate description */ - if ((ep = strstri(dbase_str, " named ")) != 0) + /* adjust the input to remove "named " and "called " */ + if ((ep = strstri(dbase_str, " named ")) != 0) { alt = ep + 7; - else if ((ep = strstri(dbase_str, " called ")) != 0) { - if (strlen(ep + 8) < BUFSZ - 1) { - Strcpy(givenname, ep + 8); - givenname[BUFSZ-1] = '\0'; - alt = &givenname[0]; - } - } - if (!ep) + if ((ap = strstri(dbase_str, " called ")) != 0 && ap < ep) + ep = ap; /* "named" is alt but truncate at "called" */ + } else if ((ep = strstri(dbase_str, " called ")) != 0) { + copynchars(givenname, ep + 8, BUFSZ - 1); + alt = givenname; + } else ep = strstri(dbase_str, ", "); if (ep && ep > dbase_str) *ep = '\0'; + /* remove charges or "(lit)" or wizmode "(N aum)" */ + if ((ep = strstri(dbase_str, " (")) != 0 && ep > dbase_str) + *ep = '\0'; + if (alt && (ap = strstri(alt, " (")) != 0 && ap > alt) + *ap = '\0'; /* * If the object is named, then the name is the alternate description; @@ -588,21 +641,18 @@ boolean user_typed_name, without_asking; if (!alt) alt = makesingular(dbase_str); - if (!strcmp(alt, dbase_str)) - pass = 0; - - for (; pass >= 0; pass--) { + pass1found_in_file = FALSE; + for (pass = !strcmp(alt, dbase_str) ? 0 : 1; pass >= 0; --pass) { + found_in_file = skipping_entry = FALSE; txt_offset = 0L; if (dlb_fseek(fp, txt_offset, SEEK_SET) < 0 ) { impossible("can't get to start of 'data' file"); - dlb_fclose(fp); - return; + goto checkfile_done; } /* skip first record; read second */ if (!dlb_fgets(buf, BUFSZ, fp) || !dlb_fgets(buf, BUFSZ, fp)) { impossible("can't read 'data' file"); - (void) dlb_fclose(fp); - return; + goto checkfile_done; } else if (sscanf(buf, "%8lx\n", &txt_offset) < 1 || txt_offset == 0L) goto bad_data_file; @@ -629,13 +679,15 @@ boolean user_typed_name, without_asking; continue; } else { found_in_file = TRUE; + if (pass == 1) + pass1found_in_file = TRUE; break; } } } } if (found_in_file) { - long entry_offset; + long entry_offset, fseekoffset; int entry_count; int i; @@ -644,37 +696,33 @@ boolean user_typed_name, without_asking; if (!dlb_fgets(buf, BUFSZ, fp)) goto bad_data_file; } while (!digit(*buf)); - if (sscanf(buf, "%ld,%d\n", &entry_offset, &entry_count) < 2) { - bad_data_file: - impossible("'data' file in wrong format or corrupted"); - /* window will exist if came here from below via 'goto' */ - if (datawin != WIN_ERR) - destroy_nhwindow(datawin); - (void) dlb_fclose(fp); - return; - } + if (sscanf(buf, "%ld,%d\n", &entry_offset, &entry_count) < 2) + goto bad_data_file; + fseekoffset = (long) txt_offset + entry_offset; + if (pass == 1) + pass1offset = fseekoffset; + else if (fseekoffset == pass1offset) + goto checkfile_done; yes_to_moreinfo = FALSE; if (!user_typed_name && !without_asking) { - unsigned maxt = strlen("More info about \"\"?"); char *entrytext = pass ? alt : dbase_str; - char question[BUFSZ]; + char question[QBUFSZ]; - if (strlen(entrytext) < BUFSZ - maxt) { - Strcpy(question, "More info about \""); - Strcat(question, entrytext); - Strcat(question, "\"?"); - } + Strcpy(question, "More info about \""); + /* +2 => length of "\"?" */ + copynchars(eos(question), entrytext, + (int) (sizeof question - 1 + - (strlen(question) + 2))); + Strcat(question, "\"?"); if (yn(question) == 'y') yes_to_moreinfo = TRUE; } if (user_typed_name || without_asking || yes_to_moreinfo) { - if (dlb_fseek(fp, (long) txt_offset + entry_offset, - SEEK_SET) < 0) { + if (dlb_fseek(fp, fseekoffset, SEEK_SET) < 0) { pline("? Seek error on 'data' file!"); - (void) dlb_fclose(fp); - return; + goto checkfile_done; } datawin = create_nhwindow(NHW_MENU); for (i = 0; i < entry_count; i++) { @@ -686,13 +734,21 @@ boolean user_typed_name, without_asking; putstr(datawin, 0, buf + 1); } display_nhwindow(datawin, FALSE); - destroy_nhwindow(datawin); + destroy_nhwindow(datawin), datawin = WIN_ERR; } - } else if (user_typed_name && pass == 0) + } else if (user_typed_name && pass == 0 && !pass1found_in_file) pline("I don't have any information on those things."); } } + goto checkfile_done; /* skip error feedback */ + + bad_data_file: + impossible("'data' file in wrong format or corrupted"); + checkfile_done: + if (datawin != WIN_ERR) + destroy_nhwindow(datawin); (void) dlb_fclose(fp); + return; } int @@ -1133,10 +1189,8 @@ coord *click_cc; pline("Pick an object."); ans = getpos(&cc, quick, what_is_an_unknown_object); - if (ans < 0 || cc.x < 0) { - flags.verbose = save_verbose; - return 0; /* done */ - } + if (ans < 0 || cc.x < 0) + break; /* done */ flags.verbose = FALSE; /* only print long question once */ } } @@ -1146,8 +1200,7 @@ coord *click_cc; /* Finally, print out our explanation. */ if (found) { - /* Used putmixed() because there may be an encoded glyph present - */ + /* use putmixed() because there may be an encoded glyph present */ putmixed(WIN_MESSAGE, 0, out_str); /* check the data file for information about this thing */ diff --git a/src/pline.c b/src/pline.c index d6ee70266..319f13946 100644 --- a/src/pline.c +++ b/src/pline.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 pline.c $NHDT-Date: 1510990667 2017/11/18 07:37:47 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.64 $ */ +/* NetHack 3.6 pline.c $NHDT-Date: 1519183957 2018/02/21 03:32:37 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.65 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -129,14 +129,7 @@ VA_DECL(const char *, line) pbuf[BUFSZ - 1] = '\0'; line = pbuf; } - if (!iflags.window_inited) { - raw_print(line); - iflags.last_msg = PLNMSG_UNKNOWN; - return; - } - msgtyp = MSGTYP_NORMAL; - no_repeat = (pline_flags & PLINE_NOREPEAT) ? TRUE : FALSE; #ifdef DUMPLOG /* We hook here early to have options-agnostic output. * Unfortunately, that means Norep() isn't honored (general issue) and @@ -145,10 +138,26 @@ VA_DECL(const char *, line) if ((pline_flags & SUPPRESS_HISTORY) == 0) dumplogmsg(line); #endif + + if (!iflags.window_inited) { + raw_print(line); + iflags.last_msg = PLNMSG_UNKNOWN; + return; + } + + msgtyp = MSGTYP_NORMAL; + no_repeat = (pline_flags & PLINE_NOREPEAT) ? TRUE : FALSE; if ((pline_flags & OVERRIDE_MSGTYPE) == 0) { msgtyp = msgtype_type(line, no_repeat); if (msgtyp == MSGTYP_NOSHOW || (msgtyp == MSGTYP_NOREP && !strcmp(line, prevmsg))) + /* FIXME: we need a way to tell our caller that this message + * was suppressed so that caller doesn't set iflags.last_msg + * for something that hasn't been shown, otherwise a subsequent + * message which uses alternate wording based on that would be + * doing so out of context and probably end up seeming silly. + * (Not an issue for no-repeat but matters for no-show.) + */ return; } diff --git a/src/pray.c b/src/pray.c index 0e74bb98a..646de494c 100644 --- a/src/pray.c +++ b/src/pray.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 pray.c $NHDT-Date: 1514593198 2017/12/30 00:19:58 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.95 $ */ +/* NetHack 3.6 pray.c $NHDT-Date: 1519662898 2018/02/26 16:34:58 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.96 $ */ /* Copyright (c) Benson I. Margulies, Mike Stephenson, Steve Linhart, 1989. */ /* NetHack may be freely redistributed. See license for details. */ @@ -140,6 +140,31 @@ boolean only_if_injured; /* determines whether maxhp <= 5 matters */ return (boolean) (curhp <= 5 || curhp * divisor <= maxhp); } +/* return True if surrounded by impassible rock, regardless of the state + of your own location (for example, inside a doorless closet) */ +boolean +stuck_in_wall() +{ + int i, j, x, y, count = 0; + + if (Passes_walls) + return FALSE; + for (i = -1; i <= 1; i++) { + x = u.ux + i; + for (j = -1; j <= 1; j++) { + if (!i && !j) + continue; + y = u.uy + j; + if (!isok(x, y) + || (IS_ROCK(levl[x][y].typ) + && (levl[x][y].typ != SDOOR || levl[x][y].typ != SCORR)) + || (blocked_boulder(i, j) && !throws_rocks(youmonst.data))) + ++count; + } + } + return (count == 8) ? TRUE : FALSE; +} + /* * Return 0 if nothing particular seems wrong, positive numbers for * serious trouble, and negative numbers for comparative annoyances. @@ -158,7 +183,7 @@ STATIC_OVL int in_trouble() { struct obj *otmp; - int i, j, count = 0; + int i; /* * major troubles @@ -183,19 +208,8 @@ in_trouble() return TROUBLE_LYCANTHROPE; if (near_capacity() >= EXT_ENCUMBER && AMAX(A_STR) - ABASE(A_STR) > 3) return TROUBLE_COLLAPSING; - - for (i = -1; i <= 1; i++) - for (j = -1; j <= 1; j++) { - if (!i && !j) - continue; - if (!isok(u.ux + i, u.uy + j) - || IS_ROCK(levl[u.ux + i][u.uy + j].typ) - || (blocked_boulder(i, j) && !throws_rocks(youmonst.data))) - count++; - } - if (count == 8 && !Passes_walls) + if (stuck_in_wall()) return TROUBLE_STUCK_IN_WALL; - if (Cursed_obj(uarmf, LEVITATION_BOOTS) || stuck_ring(uleft, RIN_LEVITATION) || stuck_ring(uright, RIN_LEVITATION)) @@ -396,9 +410,22 @@ int trouble; } break; case TROUBLE_STUCK_IN_WALL: - Your("surroundings change."); /* no control, but works on no-teleport levels */ - (void) safe_teleds(FALSE); + if (safe_teleds(FALSE)) { + Your("surroundings change."); + } else { + /* safe_teleds() couldn't find a safe place; perhaps the + level is completely full. As a last resort, confer + intrinsic wall/rock-phazing. Hero might get stuck + again fairly soon.... + Without something like this, fix_all_troubles can get + stuck in an infinite loop trying to fix STUCK_IN_WALL + and repeatedly failing. */ + set_itimeout(&HPasses_walls, (long) (d(4, 4) + 4)); /* 8..20 */ + /* how else could you move between packed rocks or among + lattice forming "solid" rock? */ + You_feel("much slimmer."); + } break; case TROUBLE_CURSED_LEVITATION: if (Cursed_obj(uarmf, LEVITATION_BOOTS)) { @@ -1496,7 +1523,7 @@ dosacrifice() u.uachieve.ascended = 1; pline( "An invisible choir sings, and you are bathed in radiance..."); - godvoice(altaralign, "Congratulations, mortal!"); + godvoice(altaralign, "Mortal, thou hast done well!"); display_nhwindow(WIN_MESSAGE, FALSE); verbalize( "In return for thy service, I grant thee the gift of Immortality!"); diff --git a/src/sp_lev.c b/src/sp_lev.c index 5fc103a1b..9ddce65cd 100644 --- a/src/sp_lev.c +++ b/src/sp_lev.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 sp_lev.c $NHDT-Date: 1514769572 2018/01/01 01:19:32 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.95 $ */ +/* NetHack 3.6 sp_lev.c $NHDT-Date: 1519399521 2018/02/23 15:25:21 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.96 $ */ /* Copyright (c) 1989 by Jean-Christophe Collet */ /* NetHack may be freely redistributed. See license for details. */ @@ -4213,7 +4213,7 @@ genericptr_t arg; { xchar typ = *(xchar *) arg; xchar x = dx, y = dy; - boolean left_or_right, up_and_down; + boolean wleft, wright, wup, wdown; if (!IS_DOOR(levl[x][y].typ) && levl[x][y].typ != SDOOR) levl[x][y].typ = (typ & D_SECRET) ? SDOOR : DOOR; @@ -4237,21 +4237,31 @@ genericptr_t arg; * * A secret door with no adjacent walls is also feasible and makes * even less sense. It will be displayed as a vertical wall while - * hidden and become a vertical door when found. + * hidden and become a vertical door when found. Before resorting + * to that, we check for solid rock which hasn't been wallified + * yet (cf lower leftside of leader's room in Cav quest). */ - left_or_right = ((isok(x - 1, y) && (IS_WALL(levl[x - 1][y].typ) - || IS_DOOR(levl[x - 1][y].typ) - || levl[x - 1][y].typ == SDOOR)) - || (isok(x + 1, y) && (IS_WALL(levl[x + 1][y].typ) - || IS_DOOR(levl[x + 1][y].typ) - || levl[x + 1][y].typ == SDOOR))); - up_and_down = ((isok(x, y - 1) && (IS_WALL(levl[x][y - 1].typ) - || IS_DOOR(levl[x][y - 1].typ) - || levl[x][y - 1].typ == SDOOR)) - && (isok(x, y + 1) && (IS_WALL(levl[x][y + 1].typ) - || IS_DOOR(levl[x][y + 1].typ) - || levl[x][y + 1].typ == SDOOR))); - levl[x][y].horizontal = (left_or_right && !up_and_down) ? 1 : 0; + wleft = (isok(x - 1, y) && (IS_WALL(levl[x - 1][y].typ) + || IS_DOOR(levl[x - 1][y].typ) + || levl[x - 1][y].typ == SDOOR)); + wright = (isok(x + 1, y) && (IS_WALL(levl[x + 1][y].typ) + || IS_DOOR(levl[x + 1][y].typ) + || levl[x + 1][y].typ == SDOOR)); + wup = (isok(x, y - 1) && (IS_WALL(levl[x][y - 1].typ) + || IS_DOOR(levl[x][y - 1].typ) + || levl[x][y - 1].typ == SDOOR)); + wdown = (isok(x, y + 1) && (IS_WALL(levl[x][y + 1].typ) + || IS_DOOR(levl[x][y + 1].typ) + || levl[x][y + 1].typ == SDOOR)); + if (!wleft && !wright && !wup && !wdown) { + /* out of bounds is treated as implicit wall; should be academic + because we don't expect to have doors so near the level's edge */ + wleft = (!isok(x - 1, y) || IS_DOORJOIN(levl[x - 1][y].typ)); + wright = (!isok(x + 1, y) || IS_DOORJOIN(levl[x + 1][y].typ)); + wup = (!isok(x, y - 1) || IS_DOORJOIN(levl[x][y - 1].typ)); + wdown = (!isok(x, y + 1) || IS_DOORJOIN(levl[x][y + 1].typ)); + } + levl[x][y].horizontal = ((wleft || wright) && !(wup && wdown)) ? 1 : 0; levl[x][y].doormask = typ; SpLev_Map[x][y] = 1; } diff --git a/src/teleport.c b/src/teleport.c index 8fb3f8c84..bd3ada997 100644 --- a/src/teleport.c +++ b/src/teleport.c @@ -198,6 +198,8 @@ STATIC_OVL boolean tele_jump_ok(x1, y1, x2, y2) int x1, y1, x2, y2; { + if (!isok(x2, y2)) + return FALSE; if (dndest.nlx > 0) { /* if inside a restricted region, can't teleport outside */ if (within_bounded_area(x1, y1, dndest.nlx, dndest.nly, dndest.nhx, @@ -1135,8 +1137,7 @@ struct trap *trap; boolean force_it; int in_sight; { - int tt = trap->ttyp; - struct permonst *mptr = mtmp->data; + int tt = (trap ? trap->ttyp : NO_TRAP); if (mtmp == u.ustuck) /* probably a vortex */ return 0; /* temporary? kludge */ @@ -1157,8 +1158,8 @@ int in_sight; } } else if (tt == MAGIC_PORTAL) { if (In_endgame(&u.uz) - && (mon_has_amulet(mtmp) || is_home_elemental(mptr))) { - if (in_sight && mptr->mlet != S_ELEMENTAL) { + && (mon_has_amulet(mtmp) || is_home_elemental(mtmp->data))) { + if (in_sight && mtmp->data->mlet != S_ELEMENTAL) { pline("%s seems to shimmer for a moment.", Monnam(mtmp)); seetrap(trap); } @@ -1167,27 +1168,44 @@ int in_sight; assign_level(&tolevel, &trap->dst); migrate_typ = MIGR_PORTAL; } - } else { /* (tt == LEVEL_TELEP) */ + } else if (tt == LEVEL_TELEP || tt == NO_TRAP) { int nlev; - if (mon_has_amulet(mtmp) || In_endgame(&u.uz)) { + if (mon_has_amulet(mtmp) || In_endgame(&u.uz) + /* NO_TRAP is used when forcing a monster off the level; + onscary(0,0,) is true for the Wizard, Riders, lawful + minions, Angels of any alignment, shopkeeper or priest + currently inside his or her own special room */ + || (tt == NO_TRAP && onscary(0, 0, mtmp))) { if (in_sight) pline("%s seems very disoriented for a moment.", Monnam(mtmp)); return 0; } - nlev = random_teleport_level(); - if (nlev == depth(&u.uz)) { - if (in_sight) - pline("%s shudders for a moment.", Monnam(mtmp)); - return 0; + if (tt == NO_TRAP) { + /* creature is being forced off the level to make room; + it will try to return to this level (at a random spot + rather than its current one) if the level is left by + the hero and then revisited */ + assign_level(&tolevel, &u.uz); + } else { + nlev = random_teleport_level(); + if (nlev == depth(&u.uz)) { + if (in_sight) + pline("%s shudders for a moment.", Monnam(mtmp)); + return 0; + } + get_level(&tolevel, nlev); } - get_level(&tolevel, nlev); + } else { + impossible("mlevel_tele_trap: unexpected trap type (%d)", tt); + return 0; } if (in_sight) { pline("Suddenly, %s disappears out of sight.", mon_nam(mtmp)); - seetrap(trap); + if (trap) + seetrap(trap); } migrate_to_level(mtmp, ledger_no(&tolevel), migrate_typ, (coord *) 0); return 3; /* no longer on this level */ diff --git a/src/timeout.c b/src/timeout.c index b8535bbd5..86e01ae5f 100644 --- a/src/timeout.c +++ b/src/timeout.c @@ -275,6 +275,7 @@ levitation_dialogue() if (((HLevitation & TIMEOUT) % 2L) && i > 0L && i <= SIZE(levi_texts)) { const char *s = levi_texts[SIZE(levi_texts) - i]; + if (index(s, '%')) { boolean danger = (is_pool_or_lava(u.ux, u.uy) && !Is_waterlevel(&u.uz)); @@ -336,6 +337,30 @@ burn_away_slime() } } +/* Intrinsic Passes_walls is temporary when your god is trying to fix + all troubles and then TROUBLE_STUCK_IN_WALL calls safe_teleds() but + it can't find anywhere to place you. If that happens you get a small + value for (HPasses_walls & TIMEOUT) to move somewhere yourself. + Message given is "you feel much slimmer" as a joke hint that you can + move between things which are closely packed--like the substance of + solid rock! */ +static NEARDATA const char *const phaze_texts[] = { + "You start to feel bloated.", + "You are feeling rather flabby.", +}; + +STATIC_OVL void +phaze_dialogue() +{ + long i = ((HPasses_walls & TIMEOUT) / 2L); + + if (EPasses_walls || (HPasses_walls & ~TIMEOUT)) + return; + + if (((HPasses_walls & TIMEOUT) % 2L) && i > 0L && i <= SIZE(phaze_texts)) + pline1(phaze_texts[SIZE(phaze_texts) - i]); +} + void nh_timeout() { @@ -373,8 +398,10 @@ nh_timeout() vomiting_dialogue(); if (Strangled) choke_dialogue(); - if (Levitation) + if (HLevitation & TIMEOUT) levitation_dialogue(); + if (HPasses_walls & TIMEOUT) + phaze_dialogue(); if (u.mtimedone && !--u.mtimedone) { if (Unchanging) u.mtimedone = rnd(100 * youmonst.data->mlevel + 1); @@ -526,6 +553,15 @@ nh_timeout() case LEVITATION: (void) float_down(I_SPECIAL | TIMEOUT, 0L); break; + case PASSES_WALLS: + if (!Passes_walls) { + if (stuck_in_wall()) + You_feel("hemmed in again."); + else + pline("You're back to your %s self again.", + !Upolyd ? "normal" : "unusual"); + } + break; case STRANGLED: killer.format = KILLED_BY; Strcpy(killer.name, diff --git a/src/uhitm.c b/src/uhitm.c index daa069cc4..bfc103e0a 100644 --- a/src/uhitm.c +++ b/src/uhitm.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 uhitm.c $NHDT-Date: 1517128664 2018/01/28 08:37:44 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.173 $ */ +/* NetHack 3.6 uhitm.c $NHDT-Date: 1520043553 2018/03/03 02:19:13 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.175 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -14,8 +14,7 @@ STATIC_DCL boolean FDECL(hmon_hitmon, (struct monst *, struct obj *, int, int)); STATIC_DCL int FDECL(joust, (struct monst *, struct obj *)); STATIC_DCL void NDECL(demonpet); -STATIC_DCL boolean FDECL(m_slips_free, (struct monst * mtmp, - struct attack *mattk)); +STATIC_DCL boolean FDECL(m_slips_free, (struct monst *, struct attack *)); STATIC_DCL int FDECL(explum, (struct monst *, struct attack *)); STATIC_DCL void FDECL(start_engulf, (struct monst *)); STATIC_DCL void NDECL(end_engulf); @@ -489,63 +488,85 @@ int dieroll; return malive; } -/* hit the monster next to you and the monsters to the left and right of it */ +/* hit the monster next to you and the monsters to the left and right of it; + return False if the primary target is killed, True otherwise */ STATIC_OVL boolean -hitum_cleave(mon, uattk) -struct monst *mon; -struct attack *uattk; +hitum_cleave(target, uattk) +struct monst *target; /* non-Null; forcefight at nothing doesn't cleave... */ +struct attack *uattk; /* ... but we don't enforce that here; Null works ok */ { - int i = 0; - int x = u.ux; - int y = u.uy; - int count = 3; - boolean malive = TRUE; - struct monst *mtmp; + /* swings will be delivered in alternate directions; with consecutive + attacks it will simulate normal swing and backswing; when swings + are non-consecutive, hero will sometimes start a series of attacks + with a backswing--that doesn't impact actual play, just spoils the + simulation attempt a bit */ + static boolean clockwise = FALSE; + unsigned i; + int count, umort, x = u.ux, y = u.uy; - /* find the direction we're swinging */ - while (i < 8) { + /* find the direction toward primary target */ + for (i = 0; i < 8; ++i) if (xdir[i] == u.dx && ydir[i] == u.dy) break; - i++; - } - if (i == 8) { - impossible("hitum_cleave: failed to find target monster?"); - return TRUE; + impossible("hitum_cleave: unknown target direction [%d,%d,%d]?", + u.dx, u.dy, u.dz); + return TRUE; /* target hasn't been killed */ } - i = (i + 2) % 8; + clockwise = !clockwise; /* alternate */ + /* adjust direction by two so that loop's increment (for clockwise) + or decrement (for counter-clockwise) will point at the spot next + to primary target */ + if (clockwise) + i = (i + 6) % 8; + else + i = (i + 2) % 8; + umort = u.umortality; /* used to detect life-saving */ - /* swing from right to left */ - while (count-- && uwep) { - boolean result; - int tmp, dieroll, mhit, attknum, armorpenalty; + /* + * Three attacks: adjacent to primary, primary, adjacent on other + * side. Primary target must be present or we wouldn't have gotten + * here (forcefight at thin air won't 'cleave'). However, the + * first attack might kill it (gas spore explosion, weak long worm + * occupying both spots) so we don't assume that it's still present + * on the second attack. + */ + for (count = 3; count > 0; --count) { + struct monst *mtmp; + int tx, ty, tmp, dieroll, mhit, attknum, armorpenalty; - if (!i) - i = 7; + if (clockwise) + i = (i + 1) % 8; /* ++i, wrap 8 to i=0 */ else - i--; + i = (i + 7) % 8; /* --i, wrap -1 to i=7 */ - mtmp = NULL; - if (isok(x + xdir[i], y + ydir[i])) - mtmp = m_at(x + xdir[i], y + ydir[i]); + tx = x + xdir[i], ty = y + ydir[i]; /* current target location */ + if (!isok(tx, ty)) + continue; + mtmp = m_at(tx, ty); if (!mtmp) { - (void) unmap_invisible(x + xdir[i], y + ydir[i]); + if (glyph_is_invisible(levl[tx][ty].glyph)) + (void) unmap_invisible(tx, ty); continue; } - tmp = find_roll_to_hit(mtmp, uattk->aatyp, uwep, &attknum, &armorpenalty); dieroll = rnd(20); mhit = (tmp > dieroll); - result = known_hitum(mtmp, uwep, &mhit, tmp, armorpenalty, - uattk, dieroll); - (void) passive(mtmp, uwep, mhit, DEADMONSTER(mtmp), AT_WEAP, !uwep); - if (mon == mtmp) - malive = result; + (void) known_hitum(mtmp, uwep, &mhit, tmp, armorpenalty, + uattk, dieroll); + (void) passive(mtmp, uwep, mhit, !DEADMONSTER(mtmp), AT_WEAP, !uwep); + + /* stop attacking if weapon is gone or hero got killed and + life-saved after passive counter-attack */ + if (!uwep || u.umortality > umort) + break; } - return malive; + /* return False if primary target died, True otherwise; note: if 'target' + was nonNull upon entry then it's still nonNull even if *target died */ + return (target && DEADMONSTER(target)) ? FALSE : TRUE; } /* hit target monster; returns TRUE if it still lives */ @@ -562,7 +583,10 @@ struct attack *uattk; int dieroll = rnd(20); int mhit = (tmp > dieroll || u.uswallow); - if (uwep && uwep->oartifact == ART_CLEAVER + /* Cleaver attacks three spots, one on either side of 'mon'; + it can't we part of dual-wielding but we guard against that anyway; + cleave return value reflects status of primary target ('mon') */ + if (uwep && uwep->oartifact == ART_CLEAVER && !u.twoweap && !u.uswallow && !u.ustuck && !NODIAG(u.umonnum)) return hitum_cleave(mon, uattk); @@ -718,7 +742,10 @@ int dieroll; 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) { + if (!valid_weapon_attack || 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)) { ; /* no special bonuses */ } else if (mon->mflee && Role_if(PM_ROGUE) && !Upolyd /* multi-shot throwing is too powerful here */ diff --git a/src/version.c b/src/version.c index 19f74c265..30e4ce75f 100644 --- a/src/version.c +++ b/src/version.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 version.c $NHDT-Date: 1506993902 2017/10/03 01:25:02 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.44 $ */ +/* NetHack 3.6 version.c $NHDT-Date: 1519155525 2018/02/20 19:38:45 $ $NHDT-Branch: githash $:$NHDT-Revision: 1.47 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -15,6 +15,13 @@ #include "patchlevel.h" #endif +#if defined(NETHACK_GIT_SHA) +const char * NetHack_git_sha = NETHACK_GIT_SHA; +#endif +#if defined(NETHACK_GIT_BRANCH) +const char * NetHack_git_branch = NETHACK_GIT_BRANCH; +#endif + STATIC_DCL void FDECL(insert_rtoption, (char *)); /* fill buffer with short version (so caller can avoid including date.h) */ @@ -30,23 +37,36 @@ char * getversionstring(buf) char *buf; { - int details = 0; + boolean details = FALSE; Strcpy(buf, VERSION_ID); -#if defined(RUNTIME_PORT_ID) - details++; +#if defined(RUNTIME_PORT_ID) || \ + defined(NETHACK_GIT_SHA) || defined(NETHACK_GIT_BRANCH) + details = TRUE; #endif if (details) { +#if defined(RUNTIME_PORT_ID) || defined(NETHACK_GIT_SHA) || defined(NETHACK_GIT_BRANCH) int c = 0; +#endif +#if defined(RUNTIME_PORT_ID) char tmpbuf[BUFSZ]; char *tmp = (char *)0; +#endif Sprintf(eos(buf), " ("); #if defined(RUNTIME_PORT_ID) tmp = get_port_id(tmpbuf); if (tmp) Sprintf(eos(buf), "%s%s", c++ ? "," : "", tmp); +#endif +#if defined(NETHACK_GIT_SHA) + if (NetHack_git_sha) + Sprintf(eos(buf), "%s%s", c++ ? "," : "", NetHack_git_sha); +#endif +#if defined(NETHACK_GIT_BRANCH) + if (NetHack_git_branch) + Sprintf(eos(buf), "%s%s", c++ ? "," : "", NetHack_git_branch); #endif Sprintf(eos(buf), ")"); } @@ -130,6 +150,37 @@ doextversion() return 0; } +void early_version_info(pastebuf) +boolean pastebuf; +{ + char buf[BUFSZ], buf2[BUFSZ]; + char *tmp = getversionstring(buf); + + /* this is early enough that we have to do + our own line-splitting */ + if (tmp) { + tmp = strstri(buf," ("); + if (tmp) *tmp++ = '\0'; + } + + Sprintf(buf2, "%s\n", buf); + if (tmp) Sprintf(eos(buf2), "%s\n", tmp); + raw_printf("%s", buf2); + + if (pastebuf) { +#ifdef RUNTIME_PASTEBUF_SUPPORT + /* + * Call a platform/port-specific routine to insert the + * version information into a paste buffer. Useful for + * easy inclusion in bug reports. + */ + port_insert_pastebuf(buf2); +#else + raw_printf("%s", "Paste buffer copy is not available.\n"); +#endif + } +} + extern const char regex_id[]; /* diff --git a/src/zap.c b/src/zap.c index 4ab138938..233ebfee7 100644 --- a/src/zap.c +++ b/src/zap.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 zap.c $NHDT-Date: 1513297348 2017/12/15 00:22:28 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.270 $ */ +/* NetHack 3.6 zap.c $NHDT-Date: 1520705645 2018/03/10 18:14:05 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.271 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -137,6 +137,7 @@ struct obj *otmp; boolean wake = TRUE; /* Most 'zaps' should wake monster */ boolean reveal_invis = FALSE, learn_it = FALSE; boolean dbldam = Role_if(PM_KNIGHT) && u.uhave.questart; + boolean helpful_gesture = FALSE; int dmg, otyp = otmp->otyp; const char *zap_type_text = "spell"; struct obj *obj; @@ -192,6 +193,8 @@ struct obj *otmp; mon_adjust_speed(mtmp, 1, otmp); m_dowear(mtmp, FALSE); /* might want speed boots */ } + if (mtmp->mtame) + helpful_gesture = TRUE; break; case WAN_UNDEAD_TURNING: case SPE_TURN_UNDEAD: @@ -426,7 +429,7 @@ struct obj *otmp; } if (wake) { if (mtmp->mhp > 0) { - wakeup(mtmp, TRUE); + wakeup(mtmp, helpful_gesture ? FALSE : TRUE); m_respond(mtmp); if (mtmp->isshk && !*u.ushops) hot_pursuit(mtmp); diff --git a/sys/msdos/Makefile.GCC b/sys/msdos/Makefile.GCC index 68265b6c2..3126d7622 100644 --- a/sys/msdos/Makefile.GCC +++ b/sys/msdos/Makefile.GCC @@ -1,4 +1,4 @@ -# NetHack 3.6 Makefile.GCC $NHDT-Date: 1457207036 2016/03/05 19:43:56 $ $NHDT-Branch: chasonr $:$NHDT-Revision: 1.29 $ +# NetHack 3.6 Makefile.GCC $NHDT-Date: 1519600525 2018/02/25 23:15:25 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.34 $ # Copyright (c) NetHack PC Development Team 1996-2006. # PC NetHack 3.6 Makefile for djgpp V2 # @@ -308,6 +308,9 @@ PPMWRITERS = $(O)ppmwrite.o $(O)alloc.o $(O)panic.o PPMWRIT2 = $(O)ppmwrit2.o $(O)alloc.o $(O)panic.o endif +#REGEX = $(O)pmatchregex.o +#REGEX = $(O)cppregex.o +REGEX = $(O)posixreg.o DLBOBJ = $(O)dlb.o @@ -336,7 +339,7 @@ VOBJ19 = $(O)trap.o $(O)u_init.o $(O)uhitm.o $(O)vault.o $(O)vision.o VOBJ20 = $(O)vis_tab.o $(O)weapon.o $(O)were.o $(O)wield.o $(O)windows.o VOBJ21 = $(O)wintty.o $(O)wizard.o $(O)worm.o $(O)worn.o $(O)write.o VOBJ22 = $(O)zap.o $(O)light.o $(O)dlb.o $(O)dig.o $(O)teleport.o -VOBJ23 = $(O)region.o $(O)sys.o $(O)pmatchre.o $(O)string.o $(O)unicode.o +VOBJ23 = $(O)region.o $(O)sys.o $(REGEX) SOBJ = $(O)msdos.o $(O)sound.o $(O)pcsys.o $(O)tty.o $(O)unix.o \ $(O)video.o $(O)vidtxt.o $(O)pckeys.o @@ -648,7 +651,7 @@ $(O)makedefs.o: $(CONFIG_H) $(PERMONST_H) $(INCL)/objclass.h \ #========================================== $(U)lev_comp.exe: $(SPLEVOBJS) - @rm -f temp.a + -rm -f temp.a @ar ru temp.a $(SPLEVOBJS) $(LINK) $(LFLAGS) -o$@ temp.a @@ -813,17 +816,17 @@ $(DAT)/nhtiles.bmp: $(TILEFILES) $(U)tile2bmp.exe @$(subst /,\,chdir $(SRC)) $(U)tile2bmp.exe: $(O)tile2bmp.o $(TEXTIO) - @rm -f temp.a + -rm -f temp.a @ar ru temp.a $(TEXTIO) $(LINK) $(LFLAGS) -o$@ $(O)tile2bmp.o temp.a $(U)tile2bin.exe: $(O)tile2bin.o $(TEXTIO) - @rm -f temp.a + -rm -f temp.a @ar ru temp.a $(TEXTIO) $(LINK) $(LFLAGS) -o$@ $(O)tile2bin.o temp.a $(U)til2bin2.exe: $(O)til2bin2.o $(TEXTIO2) - @rm -f temp.a + -rm -f temp.a @ar ru temp.a $(TEXTIO2) $(LINK) $(LFLAGS) -o$@ $(O)til2bin2.o temp.a @@ -1035,6 +1038,15 @@ $(O)unix.o: $(HACK_H) $(SSHR)/pcunix.c $(O)pcsys.o : $(HACK_H) $(SSHR)/pcsys.c $(CC) $(cflags) -o$@ $(SSHR)/pcsys.c +$(O)posixreg.o : $(HACK_H) $(SSHR)/posixreg.c + $(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 + $(CC) $(cflags) -o$@ $(SSHR)/pmatchre.c + # sys/msdos $(O)msdos.o : $(HACK_H) $(MSYS)/msdos.c # $(CC) $(cflags) -o$@ $(MSYS)/msdos.c @@ -1084,8 +1096,6 @@ $(O)tos.o: ../sys/atari/tos.c $(HACK_H) $(INCL)/tcap.h $(O)pcmain.o: ../sys/share/pcmain.c $(HACK_H) $(INCL)/dlb.h \ #$(INCL)/win32api.h $(CC) $(cflags) -o$@ ../sys/share/pcmain.c -$(O)pcsys.o: ../sys/share/pcsys.c $(HACK_H) - $(CC) $(cflags) -o$@ ../sys/share/pcsys.c $(O)pctty.o: ../sys/share/pctty.c $(HACK_H) $(CC) $(cflags) -o$@ ../sys/share/pctty.c $(O)pcunix.o: ../sys/share/pcunix.c $(HACK_H) diff --git a/sys/msdos/setup.bat b/sys/msdos/setup.bat index 63e9de9d6..34e0f8133 100755 --- a/sys/msdos/setup.bat +++ b/sys/msdos/setup.bat @@ -1,10 +1,10 @@ @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 Copyright (c) NetHack PC Development Team 1990 - 2012 +REM Copyright (c) NetHack PC Development Team 1990 - 2018 REM NetHack may be freely redistributed. See license for details. echo. -echo Copyright (c) NetHack PC Development Team 1990 - 2012 +echo Copyright (c) NetHack PC Development Team 1990 - 2018 echo NetHack may be freely redistributed. See license for details. echo. REM setup batch file for msdos, see Install.dos for details. @@ -59,6 +59,12 @@ echo "Copying ..\..\include\patchl~1.h -> ..\..\include\patchlev.h" copy ..\..\include\patchl~1.h ..\..\include\patchlev.h if exist ..\..\include\patchlev.old del /Q ..\..\include\patchlev.old ren ..\..\include\patchl~1.h patchlev.old +:long2c +echo "Copying ..\..\sys\share\pmatch~1.c -> ..\..\sys\share\pmatchre.c" +copy ..\..\sys\share\pmatch~1.c ..\..\sys\share\pmatchre.c +:long2d +echo "Copying ..\..\sys\share\posixr~1.c -> ..\..\sys\share\posixreg.c" +copy ..\..\sys\share\posixr~1.c ..\..\sys\share\posixreg.c :long2ok REM Missing guidebook is not fatal to the build process diff --git a/sys/msdos/vidvesa.c b/sys/msdos/vidvesa.c index 4f497ef9b..e9b7bb183 100644 --- a/sys/msdos/vidvesa.c +++ b/sys/msdos/vidvesa.c @@ -766,7 +766,7 @@ vesa_Init(void) * */ tile_file = iflags.wc_tile_file; - if (tile_file == NULL || tile_file == '\0') { + if (tile_file == NULL || *tile_file == '\0') { tile_file = "nhtiles.bmp"; } if (!read_tiles(tile_file, FALSE)) diff --git a/sys/msdos/vidvga.c b/sys/msdos/vidvga.c index 888010d4b..4e8a18206 100644 --- a/sys/msdos/vidvga.c +++ b/sys/msdos/vidvga.c @@ -758,7 +758,7 @@ vga_Init(void) * */ tile_file = iflags.wc_tile_file; - if (tile_file == NULL || tile_file == '\0') { + if (tile_file == NULL || *tile_file == '\0') { tile_file = "nhtiles.bmp"; } if (!read_tiles(tile_file, FALSE)) diff --git a/sys/share/ioctl.c b/sys/share/ioctl.c index 3da74b81a..138d02b5c 100644 --- a/sys/share/ioctl.c +++ b/sys/share/ioctl.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 ioctl.c $NHDT-Date: 1432512788 2015/05/25 00:13:08 $ $NHDT-Branch: master $:$NHDT-Revision: 1.12 $ */ +/* NetHack 3.6 ioctl.c $NHDT-Date: 1520099308 2018/03/03 17:48:28 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.13 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -63,9 +63,12 @@ struct termio termio; #include #endif -#if defined(TIOCGWINSZ) \ - && (defined(BSD) || defined(ULTRIX) || defined(AIX_31) \ - || defined(_BULL_SOURCE) || defined(SVR4)) +/* AVOID_WIN_IOCTL can be uncommented in unixconf.h + * to force USE_WIN_IOTCL to remain undefined, + * instead of the restricted explicit opt-in + * logic that used to be here. + */ +#if defined(TIOCGWINSZ) && !defined(AVOID_WIN_IOCTL) #define USE_WIN_IOCTL #include "tcap.h" /* for LI and CO */ #endif diff --git a/sys/share/pcmain.c b/sys/share/pcmain.c index a18157639..64a175c14 100644 --- a/sys/share/pcmain.c +++ b/sys/share/pcmain.c @@ -329,6 +329,9 @@ _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);*/ Strcpy(hackdir, HACKDIR); #endif if (argc > 1) { + if (argcheck(argc, argv, ARG_VERSION)) + nethack_exit(EXIT_SUCCESS); + if (!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 diff --git a/sys/unix/Makefile.dat b/sys/unix/Makefile.dat index a2f27116e..98a2b6ddb 100644 --- a/sys/unix/Makefile.dat +++ b/sys/unix/Makefile.dat @@ -169,3 +169,4 @@ spotless: -rm -f spec_levs quest_levs *.lev $(VARDAT) dungeon dungeon.pdf -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 diff --git a/sys/unix/Makefile.src b/sys/unix/Makefile.src index 451067a93..56fef8b86 100644 --- a/sys/unix/Makefile.src +++ b/sys/unix/Makefile.src @@ -1,5 +1,5 @@ # NetHack Makefile. -# NetHack 3.6 Makefile.src $NHDT-Date: 1459122529 2016/03/27 23:48:49 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.46 $ +# NetHack 3.6 Makefile.src $NHDT-Date: 1520201829 2018/03/04 22:17:09 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.52 $ # Root of source tree: NHSROOT=.. @@ -332,6 +332,14 @@ RANDOBJ = # used by `make depend' to reconstruct this Makefile; you shouldn't need this AWK = nawk +# 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 +# it doesn't already exist; to skip it completely, create an empty file +# of that name and also set this to 0; there shouldn't be any need to +# skip it--if nethack's sources don't reside in a git repository than +# the script which creates that file will fail benignly and 'makedefs -v' +# will proceed without it +GITINFO=1 #VERBOSEMAKE = 1 @@ -606,10 +614,13 @@ tile.c: ../win/share/tilemap.c $(HACK_H) # file far more complex. Since "hack.h" depends on most of the include # files, we kludge around this by making date.h dependent on hack.h, # even though it doesn't include this file. +# Do NOT include ../dat/gitinfo.txt as either a prerequisite or target. +# 'makedefs -v' processes it when present and ignores it if not. # # hack.h depends on makedefs' output, so we know makedefs will be # up to date before being executed ../include/date.h: $(VERSOURCES) $(HACK_H) + -$(SHELL) ../sys/unix/gitinfo.sh $(GITINFO) #before 'makedefs -v' ../util/makedefs -v diff --git a/sys/unix/Makefile.utl b/sys/unix/Makefile.utl index 224df10a7..ca7124a40 100644 --- a/sys/unix/Makefile.utl +++ b/sys/unix/Makefile.utl @@ -481,4 +481,4 @@ spotless: clean -rm -f ../include/tile.h tiletxt.c -rm -f makedefs lev_comp dgn_comp recover dlb -rm -f gif2txt txt2ppm tile2x11 tile2img.ttp xpm2img.ttp \ - tilemap tileedit + tilemap tileedit tile2bmp diff --git a/sys/unix/gitinfo.sh b/sys/unix/gitinfo.sh new file mode 100755 index 000000000..5cdb34715 --- /dev/null +++ b/sys/unix/gitinfo.sh @@ -0,0 +1,28 @@ +#!/bin/sh +# NetHack 3.6 gitinfo.sh $NHDT-Date: 1520201830 2018/03/04 22:17:10 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.0 $ + +# bring dat/gitinfo.txt up to date; called from Makefile.src + +# +# gitinfo.txt is used during development to augment the version number +# (for nethack's 'v' command) with more specific information. That is not +# necessary when building a released version and it is perfectly OK for +# this script to be skipped or to run but fail to generate dat/gitinfo.txt. +# + +always=0 +if [[ $1 -eq 1 || $1 == "force" || $1 == "always" ]]; then always=1; fi + +# try to figure out where we are: top, one level down (expected), or sys/unix +prefix=. +if [ -f ../sys/unix/gitinfo.sh ]; then prefix=..; fi +if [ -f ../../sys/unix/gitinfo.sh ]; then prefix=../..; fi + +# try to run a perl script which is part of nethack's git repository +if [[ $always -eq 1 || ! -f $prefix/dat/gitinfo.txt ]]; then + ( cd $prefix; \ + perl -IDEVEL/hooksdir -MNHgithook -e '&NHgithook::nhversioning' \ + 2> /dev/null ) \ + || true +fi +exit 0 diff --git a/sys/unix/hints/macosx.sh b/sys/unix/hints/macosx.sh index 93e28ca51..c6cf10c31 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: 1518800856 2018/02/16 17:07:36 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.19 $ +# NetHack 3.6 macosx.sh $NHDT-Date: 1517231957 2018/01/29 13:19:17 $ $NHDT-Branch: githash $:$NHDT-Revision: 1.20 $ # Copyright (c) Kenneth Lorber, Kensington, Maryland, 2007. # NetHack may be freely redistributed. See license for details. # diff --git a/sys/unix/unixmain.c b/sys/unix/unixmain.c index b9ab44526..95e48cc14 100644 --- a/sys/unix/unixmain.c +++ b/sys/unix/unixmain.c @@ -110,6 +110,9 @@ char *argv[]; dir = nh_getenv("HACKDIR"); if (argc > 1) { + if (argcheck(argc, argv, ARG_VERSION)) + exit(EXIT_SUCCESS); + if (!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 @@ -720,4 +723,40 @@ get_login_name() return buf; } +#ifdef __APPLE__ +extern int errno; + +void +port_insert_pastebuf(buf) +char *buf; +{ + /* This should be replaced when there is a Cocoa port. */ + const char *errfmt; + size_t len; + FILE *PB = popen("/usr/bin/pbcopy","w"); + if(!PB){ + errfmt = "Unable to start pbcopy (%d)\n"; + goto error; + } + + len = strlen(buf); + /* Remove the trailing \n, carefully. */ + if(buf[len-1] == '\n') len--; + + /* XXX Sorry, I'm too lazy to write a loop for output this short. */ + if(len!=fwrite(buf,1,len,PB)){ + errfmt = "Error sending data to pbcopy (%d)\n"; + goto error; + } + + if(pclose(PB)!=-1){ + return; + } + errfmt = "Error finishing pbcopy (%d)\n"; + +error: + raw_printf(errfmt,strerror(errno)); +} +#endif + /*unixmain.c*/ diff --git a/sys/winnt/Makefile.msc b/sys/winnt/Makefile.msc index 588a393b2..585f8c29a 100644 --- a/sys/winnt/Makefile.msc +++ b/sys/winnt/Makefile.msc @@ -1,4 +1,4 @@ -# NetHack 3.6 Makefile.msc $NHDT-Date: 1518220654 2018/02/09 23:57:34 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.105 $ */ +# NetHack 3.6 Makefile.msc $NHDT-Date: 1520177858 2018/03/04 15:37:38 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.111 $ */ # Copyright (c) NetHack PC Development Team 1993-2018 # #============================================================================== @@ -569,7 +569,7 @@ default : install all : install -install: envchk $(O)obj.tag $(O)utility.tag $(GAMEDIR)\NetHack.exe $(GAMEDIR)\NetHackW.exe $(O)install.tag +install: $(O)envchk.tag $(O)obj.tag $(O)utility.tag $(GAMEDIR)\NetHack.exe $(GAMEDIR)\NetHackW.exe $(O)install.tag @echo Done. $(O)install.tag: $(DAT)\data $(DAT)\rumors $(DAT)\dungeon \ @@ -913,14 +913,19 @@ $(MSWIN)\splash.bmp: $(U)uudecode.exe $(MSWIN)\splash.uu # defer to the steps in ..\win\win32\levstuff.mak # -$(U)lev_yacc.c $(INCL)\lev_comp.h: $(U)lev_comp.y - nmake -nologo -f ..\win\win32\levstuff.mak default +$(U)lev_yacc.c: $(U)lev_comp.y + nmake -nologo -f ..\win\win32\levstuff.mak $(U)lev_yacc.c + +$(U)lev_lex.c: $(U)lev_comp.l + nmake -nologo -f ..\win\win32\levstuff.mak $(U)lev_lex.c + +$(INCL)\lev_comp.h: + nmake -nologo -f ..\win\win32\levstuff.mak $(INCL)\lev_comp.h $(O)lev_yacc.o: $(HACK_H) $(SP_LEV_H) $(INCL)\lev_comp.h $(U)lev_yacc.c @$(cc) $(cflagsBuild) -Fo$@ $(U)lev_yacc.c -$(O)lev_lex.o: $(HACK_H) $(INCL)\lev_comp.h $(SP_LEV_H) \ - $(U)lev_lex.c +$(O)lev_lex.o: $(HACK_H) $(INCL)\lev_comp.h $(SP_LEV_H) $(U)lev_lex.c @$(cc) $(cflagsBuild) -Fo$@ $(U)lev_lex.c $(O)lev_main.o: $(U)lev_main.c $(HACK_H) $(SP_LEV_H) @@ -939,8 +944,14 @@ $(U)levcomp.exe: $(LEVCOMPOBJS) # # defer to the steps in ..\win\win32\dgnstuff.mak # -$(U)dgn_yacc.c $(INCL)\dgn_comp.h : $(U)dgn_comp.y - nmake -nologo -f ..\win\win32\dgnstuff.mak default +$(U)dgn_yacc.c: $(U)dgn_comp.y + nmake -nologo -f ..\win\win32\dgnstuff.mak $(U)dgn_yacc.c + +$(INCL)\dgn_comp.h: + nmake -nologo -f ..\win\win32\dgnstuff.mak $(INCL)\dgn_comp.h + +$(U)dgn_lex.c: $(U)dgn_comp.l + nmake -nologo -f ..\win\win32\dgnstuff.mak $(U)dgn_lex.c $(O)dgn_yacc.o: $(HACK_H) $(DGN_FILE_H) $(INCL)\dgn_comp.h $(U)dgn_yacc.c @$(cc) $(cflagsBuild) -Fo$@ $(U)dgn_yacc.c @@ -974,7 +985,7 @@ $(O)obj.tag: # options. #========================================== -envchk: +$(O)envchk.tag: $(O)obj.tag ! IF "$(TARGET_CPU)"=="x64" @echo Windows x64 64-bit target build ! ELSE @@ -984,6 +995,7 @@ envchk: # @echo Warning, the CL Environment variable is defined: # @echo CL=$(CL) ! ENDIF + echo envchk >$@ #========================================== #=========== SECONDARY TARGETS ============ @@ -1170,63 +1182,77 @@ spotless: clean if exist $(GAMEDIR)\NetHack.pdb del $(GAMEDIR)\NetHack.pdb if exist $(GAMEDIR)\nhdat del $(GAMEDIR)\nhdat ! ENDIF - 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 - if exist $(DAT)\data del $(DAT)\data - if exist $(DAT)\rumors del $(DAT)\rumors - if exist $(DAT)\engrave del $(DAT)\engrave - if exist $(DAT)\epitaph del $(DAT)\epitaph - if exist $(DAT)\bogusmon del $(DAT)\bogusmon - if exist $(DAT)\???-fil?.lev del $(DAT)\???-fil?.lev - if exist $(DAT)\???-goal.lev del $(DAT)\???-goal.lev - if exist $(DAT)\???-loca.lev del $(DAT)\???-loca.lev - if exist $(DAT)\???-strt.lev del $(DAT)\???-strt.lev - if exist $(DAT)\air.lev del $(DAT)\air.lev - if exist $(DAT)\asmodeus.lev del $(DAT)\asmodeus.lev - if exist $(DAT)\astral.lev del $(DAT)\astral.lev - if exist $(DAT)\baalz.lev del $(DAT)\baalz.lev - if exist $(DAT)\bigrm-*.lev del $(DAT)\bigrm-*.lev - if exist $(DAT)\castle.lev del $(DAT)\castle.lev - if exist $(DAT)\data del $(DAT)\data - if exist $(DAT)\dungeon del $(DAT)\dungeon - if exist $(DAT)\dungeon.pdf del $(DAT)\dungeon.pdf - if exist $(DAT)\earth.lev del $(DAT)\earth.lev - if exist $(DAT)\fakewiz?.lev del $(DAT)\fakewiz?.lev - if exist $(DAT)\fire.lev del $(DAT)\fire.lev - if exist $(DAT)\juiblex.lev del $(DAT)\juiblex.lev - if exist $(DAT)\knox.lev del $(DAT)\knox.lev - if exist $(DAT)\medusa-?.lev del $(DAT)\medusa-?.lev - if exist $(DAT)\mine*.lev del $(DAT)\mine*.lev - if exist $(DAT)\options del $(DAT)\options - if exist $(DAT)\ttyoptions del $(DAT)\ttyoptions - if exist $(DAT)\guioptions del $(DAT)\guioptions - if exist $(DAT)\oracle.lev del $(DAT)\oracle.lev - if exist $(DAT)\oracles del $(DAT)\oracles - if exist $(DAT)\orcus.lev del $(DAT)\orcus.lev - if exist $(DAT)\rumors del $(DAT)\rumors - if exist $(DAT)\quest.dat del $(DAT)\quest.dat - if exist $(DAT)\sanctum.lev del $(DAT)\sanctum.lev - if exist $(DAT)\soko?-?.lev del $(DAT)\soko?-?.lev - if exist $(DAT)\tower?.lev del $(DAT)\tower?.lev - if exist $(DAT)\valley.lev del $(DAT)\valley.lev - if exist $(DAT)\water.lev del $(DAT)\water.lev - if exist $(DAT)\wizard?.lev del $(DAT)\wizard?.lev - if exist $(DAT)\dlb.lst del $(DAT)\dlb.lst - if exist $(O)sp_lev.tag del $(O)sp_lev.tag - if exist $(SRC)\monstr.c del $(SRC)\monstr.c - if exist $(SRC)\vis_tab.c del $(SRC)\vis_tab.c - if exist $(U)recover.exe del $(U)recover.exe - if exist nhdat. del nhdat. - if exist $(O)obj.tag del $(O)obj.tag - if exist $(O)gamedir.tag del $(O)gamedir.tag - if exist $(O)nh*key.lib del $(O)nh*key.lib - if exist $(O)nh*key.exp del $(O)nh*key.exp + 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 + if exist $(DAT)\data del $(DAT)\data + if exist $(DAT)\rumors del $(DAT)\rumors + if exist $(DAT)\engrave del $(DAT)\engrave + if exist $(DAT)\epitaph del $(DAT)\epitaph + if exist $(DAT)\bogusmon del $(DAT)\bogusmon + if exist $(DAT)\???-fil?.lev del $(DAT)\???-fil?.lev + if exist $(DAT)\???-goal.lev del $(DAT)\???-goal.lev + if exist $(DAT)\???-loca.lev del $(DAT)\???-loca.lev + if exist $(DAT)\???-strt.lev del $(DAT)\???-strt.lev + if exist $(DAT)\air.lev del $(DAT)\air.lev + if exist $(DAT)\asmodeus.lev del $(DAT)\asmodeus.lev + if exist $(DAT)\astral.lev del $(DAT)\astral.lev + if exist $(DAT)\baalz.lev del $(DAT)\baalz.lev + if exist $(DAT)\bigrm-*.lev del $(DAT)\bigrm-*.lev + if exist $(DAT)\castle.lev del $(DAT)\castle.lev + if exist $(DAT)\data del $(DAT)\data + if exist $(DAT)\dungeon del $(DAT)\dungeon + if exist $(DAT)\dungeon.pdf del $(DAT)\dungeon.pdf + if exist $(DAT)\earth.lev del $(DAT)\earth.lev + if exist $(DAT)\fakewiz?.lev del $(DAT)\fakewiz?.lev + if exist $(DAT)\fire.lev del $(DAT)\fire.lev + if exist $(DAT)\juiblex.lev del $(DAT)\juiblex.lev + if exist $(DAT)\knox.lev del $(DAT)\knox.lev + if exist $(DAT)\medusa-?.lev del $(DAT)\medusa-?.lev + if exist $(DAT)\mine*.lev del $(DAT)\mine*.lev + if exist $(DAT)\options del $(DAT)\options + if exist $(DAT)\ttyoptions del $(DAT)\ttyoptions + if exist $(DAT)\guioptions del $(DAT)\guioptions + if exist $(DAT)\oracle.lev del $(DAT)\oracle.lev + if exist $(DAT)\oracles del $(DAT)\oracles + if exist $(DAT)\orcus.lev del $(DAT)\orcus.lev + if exist $(DAT)\rumors del $(DAT)\rumors + if exist $(DAT)\quest.dat del $(DAT)\quest.dat + if exist $(DAT)\sanctum.lev del $(DAT)\sanctum.lev + if exist $(DAT)\soko?-?.lev del $(DAT)\soko?-?.lev + if exist $(DAT)\tower?.lev del $(DAT)\tower?.lev + if exist $(DAT)\valley.lev del $(DAT)\valley.lev + if exist $(DAT)\water.lev del $(DAT)\water.lev + if exist $(DAT)\wizard?.lev del $(DAT)\wizard?.lev + 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)\monstr.c del $(SRC)\monstr.c + if exist $(SRC)\vis_tab.c del $(SRC)\vis_tab.c + if exist nhdat. del nhdat. + if exist $(O)obj.tag del $(O)obj.tag + if exist $(O)gamedir.tag del $(O)gamedir.tag + if exist $(O)nh*key.lib del $(O)nh*key.lib + if exist $(O)nh*key.exp del $(O)nh*key.exp + if exist $(MSWIN)\mnsel.bmp del $(MSWIN)\mnsel.bmp + if exist $(MSWIN)\mnselcnt.bmp del $(MSWIN)\mnselcnt.bmp + if exist $(MSWIN)\mnunsel.bmp del $(MSWIN)\mnunsel.bmp + if exist $(MSWIN)\petmark.bmp del $(MSWIN)\petmark.bmp + if exist $(MSWIN)\pilemark.bmp del $(MSWIN)\pilemark.bmp + if exist $(MSWIN)\rip.bmp del $(MSWIN)\rip.bmp + if exist $(MSWIN)\splash.bmp del $(MSWIN)\splash.bmp + if exist $(MSWIN)\nethack.ico del $(MSWIN)\nethack.ico + if exist $(MSWSYS)\nethack.ico del $(MSWSYS)\nethack.ico + if exist $(U)recover.exe del $(U)recover.exe + if exist $(U)tile2bmp.exe del $(U)tile2bmp.exe + if exist $(U)tilemap.exe del $(U)tilemap.exe + if exist $(U)uudecode.exe del $(U)uudecode.exe + if exist $(U)dlb_main.exe del $(U)dlb_main.exe clean: if exist $(O)*.o del $(O)*.o if exist $(O)utility.tag del $(O)utility.tag @@ -1262,6 +1288,7 @@ clean: if exist $(O)nhraykey.lib del $(O)nhraykey.lib if exist $(O)nhraykey.map del $(O)nhraykey.map if exist $(O)nhraykey.PDB del $(O)nhraykey.PDB + if exist $(O)envchk.tag del $(O)envchk.tag if exist $(O)obj.tag del $(O)obj.tag if exist $(O)sp_lev.tag del $(O)sp_lev.tag if exist $(O)uudecode.MAP del $(O)uudecode.MAP @@ -1274,7 +1301,6 @@ clean: rem defer to the steps in ..\win\win32\dgnstuff.mak rem nmake -nologo -f ..\win\win32\dgnstuff.mak clean - if exist $(TILEBMP16) del $(TILEBMP16) if exist $(TILEBMP32) del $(TILEBMP32) diff --git a/sys/winnt/console.rc b/sys/winnt/console.rc index 20570522d..1c35e16bd 100644 --- a/sys/winnt/console.rc +++ b/sys/winnt/console.rc @@ -12,8 +12,8 @@ // VS_VERSION_INFO VERSIONINFO - FILEVERSION 3,5,0,0 - PRODUCTVERSION 3,5,0,0 + FILEVERSION 3,6,1,0 + PRODUCTVERSION 3,6,1,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.5.0\0" + VALUE "FileVersion", "3.6.1\0" VALUE "InternalName", "NetHack\0" - VALUE "LegalCopyright", "Copyright (C) 1985 - 2005. By Stichting Mathematisch Centrum and M. Stephenson. See license for details.\0" + VALUE "LegalCopyright", "Copyright (C) 1985 - 2018. 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.5.0\0" + VALUE "ProductVersion", "3.6.1\0" END END BLOCK "VarFileInfo" diff --git a/sys/winnt/winnt.c b/sys/winnt/winnt.c index 842bfd036..cfd27acac 100644 --- a/sys/winnt/winnt.c +++ b/sys/winnt/winnt.c @@ -35,6 +35,9 @@ /* globals required within here */ HANDLE ffhandle = (HANDLE) 0; WIN32_FIND_DATA ffd; +typedef HWND(WINAPI *GETCONSOLEWINDOW)(); +static HWND GetConsoleHandle(void); +static HWND GetConsoleHwnd(void); /* The function pointer nt_kbhit contains a kbhit() equivalent * which varies depending on which window port is active. @@ -316,6 +319,119 @@ int interjection_type; msmsg(interjection_buf[interjection_type]); } +#ifdef RUNTIME_PASTEBUF_SUPPORT + +void port_insert_pastebuf(buf) +char *buf; +{ + /* This implementation will utilize the windows clipboard + * to accomplish this. + */ + + char *tmp = buf; + HWND hwndConsole = GetConsoleHandle(); + HGLOBAL hglbCopy; + WCHAR *w, w2[2]; + int cc, rc, abytes; + LPWSTR lpwstrCopy; + HANDLE hresult; + + if (!buf || (hwndConsole == NULL)) + return; + + cc = strlen(buf); + /* last arg=0 means "tell me the size of the buffer that I need" */ + rc = MultiByteToWideChar(GetConsoleOutputCP(), 0, buf, -1, w2, 0); + if (!rc) return; + + abytes = rc * sizeof(WCHAR); + w = (WCHAR *)alloc(abytes); + /* Housekeeping need: +free(w) */ + + rc = MultiByteToWideChar(GetConsoleOutputCP(), 0, buf, -1, w, rc); + if (!rc) { + free(w); + return; + } + if (!OpenClipboard(hwndConsole)) { + free(w); + return; + } + /* Housekeeping need: +CloseClipboard(), free(w) */ + + EmptyClipboard(); + + /* allocate global mem obj to hold the text */ + + hglbCopy = GlobalAlloc(GMEM_MOVEABLE, abytes); + if (hglbCopy == NULL) { + CloseClipboard(); + free(w); + return; + } + /* Housekeeping need: +GlobalFree(hglbCopy), CloseClipboard(), free(w) */ + + lpwstrCopy = (LPWSTR)GlobalLock(hglbCopy); + /* Housekeeping need: +GlobalUnlock(hglbCopy), GlobalFree(hglbCopy), + CloseClipboard(), free(w) */ + + memcpy(lpwstrCopy, w, abytes); + GlobalUnlock(hglbCopy); + /* Housekeeping need: GlobalFree(hglbCopy), CloseClipboard(), free(w) */ + + /* put it on the clipboard */ + hresult = SetClipboardData(CF_UNICODETEXT, hglbCopy); + if (!hresult) { + raw_printf("Error copying to clipboard.\n"); + GlobalFree(hglbCopy); /* only needed if clipboard didn't accept data */ + } + /* Housekeeping need: CloseClipboard(), free(w) */ + + CloseClipboard(); + free(w); + return; +} + +static HWND +GetConsoleHandle(void) +{ + HMODULE hMod = GetModuleHandle("kernel32.dll"); + GETCONSOLEWINDOW pfnGetConsoleWindow = + (GETCONSOLEWINDOW) GetProcAddress(hMod, "GetConsoleWindow"); + if (pfnGetConsoleWindow) + return pfnGetConsoleWindow(); + else + return GetConsoleHwnd(); +} + +static HWND +GetConsoleHwnd(void) +{ + int iterations = 0; + HWND hwndFound = 0; + char OldTitle[1024], NewTitle[1024], TestTitle[1024]; + + /* Get current window title */ + GetConsoleTitle(OldTitle, sizeof OldTitle); + + (void) sprintf(NewTitle, "NETHACK%d/%d", GetTickCount(), + GetCurrentProcessId()); + SetConsoleTitle(NewTitle); + + GetConsoleTitle(TestTitle, sizeof TestTitle); + while (strcmp(TestTitle, NewTitle) != 0) { + iterations++; + /* sleep(0); */ + GetConsoleTitle(TestTitle, sizeof TestTitle); + } + hwndFound = FindWindow(NULL, NewTitle); + SetConsoleTitle(OldTitle); + /* printf("%d iterations\n", iterations); */ + return hwndFound; +} + +#endif + #ifdef RUNTIME_PORT_ID /* * _M_IX86 is Defined for x86 processors. This is not defined for x64 diff --git a/util/makedefs.c b/util/makedefs.c index 29f6c3dc3..48a906846 100644 --- a/util/makedefs.c +++ b/util/makedefs.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 makedefs.c $NHDT-Date: 1516697571 2018/01/23 08:52:51 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.118 $ */ +/* NetHack 3.6 makedefs.c $NHDT-Date: 1520022901 2018/03/02 20:35:01 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.121 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* Copyright (c) M. Stephenson, 1990, 1991. */ /* Copyright (c) Dean Luick, 1990. */ @@ -52,7 +52,7 @@ #endif #if defined(UNIX) && !defined(LINT) && !defined(GCC_WARN) -static const char SCCS_Id[] = "@(#)makedefs.c\t3.6\t2016/02/12"; +static const char SCCS_Id[] = "@(#)makedefs.c\t3.6\t2018/03/02"; #endif /* names of files to be generated */ @@ -72,6 +72,7 @@ static const char SCCS_Id[] = "@(#)makedefs.c\t3.6\t2016/02/12"; #define QTXT_O_FILE "quest.dat" #define VIS_TAB_H "vis_tab.h" #define VIS_TAB_C "vis_tab.c" +#define GITINFO_FILE "gitinfo.txt" /* locations for those files */ #ifdef AMIGA #define FILE_PREFIX @@ -177,6 +178,7 @@ static char *FDECL(bannerc_string, (char *, const char *)); static char *FDECL(xcrypt, (const char *)); static unsigned long FDECL(read_rumors_file, (const char *, int *, long *, unsigned long)); +static boolean FDECL(get_gitinfo, (char *, char *)); static void FDECL(do_rnd_access_file, (const char *)); static boolean FDECL(d_filter, (char *)); static boolean FDECL(h_filter, (char *)); @@ -209,6 +211,7 @@ static char *FDECL(fgetline, (FILE*)); static char *FDECL(tmpdup, (const char *)); static char *FDECL(limit, (char *, int)); static char *FDECL(eos, (char *)); +static int FDECL(case_insensitive_comp, (const char *, const char *)); /* input, output, tmp */ static FILE *ifp, *ofp, *tfp; @@ -1253,6 +1256,7 @@ do_date() #else time_t clocktim = 0; #endif + char githash[BUFSZ], gitbranch[BUFSZ]; char *c, cbuf[60], buf[BUFSZ]; const char *ul_sfx; @@ -1386,6 +1390,10 @@ do_date() Fprintf(ofp, "#define COPYRIGHT_BANNER_C \\\n \"%s\"\n", bannerc_string(buf, cbuf)); Fprintf(ofp, "\n"); + if (get_gitinfo(githash, gitbranch)) { + Fprintf(ofp, "#define NETHACK_GIT_SHA \"%s\"\n", githash); + Fprintf(ofp, "#define NETHACK_GIT_BRANCH \"%s\"\n", gitbranch); + } #ifdef AMIGA { struct tm *tm = localtime((time_t *) &clocktim); @@ -1400,6 +1408,84 @@ do_date() return; } +boolean +get_gitinfo(githash, gitbranch) +char *githash, *gitbranch; +{ + FILE *gifp; + size_t len; + char infile[600]; + char *line, *strval, *opt, *c, *end; + boolean havebranch = FALSE, havehash = FALSE; + + if (!githash || !gitbranch) return FALSE; + + Sprintf(infile, DATA_IN_TEMPLATE, GITINFO_FILE); + if (!(gifp = fopen(infile, RDTMODE))) { + /* perror(infile); */ + return FALSE; + } + + /* read the gitinfo file */ + while ((line = fgetline(gifp)) != 0) { + strval = index(line, '='); + if (strval && strlen(strval) < (BUFSZ-1)) { + opt = line; + *strval++ = '\0'; + /* strip off the '\n' */ + if ((c = index(strval, '\n')) != 0) + *c = '\0'; + if ((c = index(opt, '\n')) != 0) + *c = '\0'; + /* strip leading and trailing white space */ + while (*strval == ' ' || *strval == '\t') + strval++; + end = eos(strval); + while (--end >= strval && (*end == ' ' || *end == '\t')) + *end = '\0'; + while (*opt == ' ' || *opt == '\t') + opt++; + end = eos(opt); + while (--end >= opt && (*end == ' ' || *end == '\t')) + *end = '\0'; + + len = strlen(opt); + if ((len >= strlen("gitbranch")) && !case_insensitive_comp(opt, "gitbranch")) { + Strcpy(gitbranch, strval); + havebranch = TRUE; + } + if ((len >= strlen("githash")) && !case_insensitive_comp(opt, "githash")) { + Strcpy(githash, strval); + havehash = TRUE; + } + } + } + Fclose(gifp); + if (havebranch && havehash) + return TRUE; + return FALSE; +} + +static int +case_insensitive_comp(s1, s2) +const char *s1; +const char *s2; +{ + uchar u1, u2; + + for (;; s1++, s2++) { + u1 = (uchar) *s1; + if (isupper(u1)) + u1 = tolower(u1); + u2 = (uchar) *s2; + if (isupper(u2)) + u2 = tolower(u2); + if (u1 == '\0' || u1 != u2) + break; + } + return u1 - u2; +} + static char save_bones_compat_buf[BUFSZ]; static void diff --git a/win/chain/wc_chainout.c b/win/chain/wc_chainout.c index 593bd6cd8..af964438c 100644 --- a/win/chain/wc_chainout.c +++ b/win/chain/wc_chainout.c @@ -620,7 +620,7 @@ boolean enable; void chainout_status_update(vp, idx, ptr, chg, percent, color, colormasks) void *vp; -int idx, chg, percent; +int idx, chg, percent, color; genericptr_t ptr; unsigned long *colormasks; { diff --git a/win/chain/wc_trace.c b/win/chain/wc_trace.c index 60877623d..ec81f0a8b 100644 --- a/win/chain/wc_trace.c +++ b/win/chain/wc_trace.c @@ -1083,9 +1083,9 @@ boolean enable; } void -trace_status_update(vp, idx, ptr, chg, color, colormasks) +trace_status_update(vp, idx, ptr, chg, percent, color, colormasks) void *vp; -int idx, chg, percent; +int idx, chg, percent, color; genericptr_t ptr; unsigned long *colormasks; { @@ -1095,7 +1095,7 @@ unsigned long *colormasks; ptr, chg, percent); PRE; - (*tdp->nprocs->win_status_update)(tdp->ndata, idx, ptr, chg, color colormasks); + (*tdp->nprocs->win_status_update)(tdp->ndata, idx, ptr, chg, percent, color, colormasks); POST; } diff --git a/win/win32/dgnstuff.mak b/win/win32/dgnstuff.mak index 9196c5c53..0965501fe 100644 --- a/win/win32/dgnstuff.mak +++ b/win/win32/dgnstuff.mak @@ -41,11 +41,30 @@ tools: # Dungeon Compiler Stuff #========================================== -..\util\dgn_yacc.c ..\include\dgn_comp.h : ..\util\dgn_comp.y +..\include\dgn_comp.h : ..\util\dgn_comp.y !IF "$(YACC)"=="" - @echo Using pre-built dgn_yacc.c and dgn_comp.h - @copy ..\sys\share\dgn_yacc.c ..\util\dgn_yacc.c - @copy ..\sys\share\dgn_comp.h ..\include\dgn_comp.h + @echo Using pre-built dgn_comp.h + chdir ..\include + copy /y ..\sys\share\dgn_comp.h + copy /b dgn_comp.h+,, + chdir ..\src +!ELSE + chdir ..\util + $(YACC) -d dgn_comp.y + copy $(YTABC) $@ + copy $(YTABH) ..\include\dgn_comp.h + @del $(YTABC) + @del $(YTABH) + chdir ..\build +!ENDIF + +..\util\dgn_yacc.c : ..\util\dgn_comp.y +!IF "$(YACC)"=="" + @echo Using pre-built dgn_yacc.c + chdir ..\util + copy /y ..\sys\share\dgn_yacc.c + copy /b dgn_yacc.c+,, + chdir ..\src !ELSE chdir ..\util $(YACC) -d dgn_comp.y @@ -59,7 +78,10 @@ tools: ..\util\dgn_lex.c: ..\util\dgn_comp.l !IF "$(LEX)"=="" @echo Using pre-built dgn_lex.c - @copy ..\sys\share\dgn_lex.c $@ + chdir ..\util + copy /y ..\sys\share\dgn_lex.c + copy /b dgn_lex.c+,, + chdir ..\src !ELSE chdir ..\util $(LEX) dgn_comp.l diff --git a/win/win32/levstuff.mak b/win/win32/levstuff.mak index 1e92cd69e..2072c2cc0 100644 --- a/win/win32/levstuff.mak +++ b/win/win32/levstuff.mak @@ -40,11 +40,13 @@ tools: # Level Compiler Stuff #========================================== -..\util\lev_yacc.c ..\include\lev_comp.h: ..\util\lev_comp.y +..\include\lev_comp.h: ..\util\lev_comp.y !IFNDEF YACC - @echo Using pre-built lev_yacc.c and lev_comp.h - @copy ..\sys\share\lev_yacc.c ..\util\lev_yacc.c - @copy ..\sys\share\lev_comp.h ..\include\lev_comp.h + @echo Using pre-built lev_comp.h + chdir ..\include + copy /y ..\sys\share\lev_comp.h + copy /b lev_comp.h+,, + chdir ..\src !ELSE @echo Generating lev_yacc.c and lev_comp.h chdir ..\util @@ -53,19 +55,40 @@ tools: copy $(YTABH) ..\include\lev_comp.h @del $(YTABC) @del $(YTABH) - chdir ..\build + chdir ..\src +!ENDIF + +..\util\lev_yacc.c: ..\util\lev_comp.y +!IFNDEF YACC + @echo Using pre-built lev_yacc.c + chdir ..\util + copy /y ..\sys\share\lev_yacc.c + copy /b lev_yacc.c+,, + chdir ..\src +!ELSE + @echo Generating lev_yacc.c and lev_comp.h + chdir ..\util + $(YACC) -d lev_comp.y + copy $(YTABC) $@ + copy $(YTABH) ..\include\lev_comp.h + @del $(YTABC) + @del $(YTABH) + chdir ..\src !ENDIF ..\util\lev_lex.c: ..\util\lev_comp.l !IFNDEF LEX @echo Using pre-built lev_lex.c - @copy ..\sys\share\lev_lex.c $@ + chdir ..\util + copy /y ..\sys\share\lev_lex.c + copy /b lev_lex.c+,, + chdir ..\src !ELSE @echo Generating lev_lex.c chdir ..\util $(LEX) lev_comp.l copy $(LEXYYC) $@ @del $(LEXYYC) - chdir ..\build + chdir ..\src !ENDIF diff --git a/win/win32/nethack.rc b/win/win32/nethack.rc index 72ce4e0df..04ff88d55 100644 --- a/win/win32/nethack.rc +++ b/win/win32/nethack.rc @@ -79,7 +79,7 @@ BEGIN VALUE "FileDescription", "NetHack for Windows - TTY Interface" VALUE "FileVersion", "3.6.1" VALUE "InternalName", "NetHack" - VALUE "LegalCopyright", "Copyright (C) 1985 - 2017. By Stichting Mathematisch Centrum and M. Stephenson. See license for details." + VALUE "LegalCopyright", "Copyright (C) 1985 - 2018. By Stichting Mathematisch Centrum and M. Stephenson. See license for details." VALUE "OriginalFilename", "NetHack.exe" VALUE "ProductName", "NetHack" VALUE "ProductVersion", "3.6.1" diff --git a/win/win32/winhack.rc b/win/win32/winhack.rc index 06876aecf..aa8c23e9a 100644 --- a/win/win32/winhack.rc +++ b/win/win32/winhack.rc @@ -339,7 +339,7 @@ BEGIN VALUE "FileDescription", "NetHack for Windows - Graphical Interface" VALUE "FileVersion", "3.6.1" VALUE "InternalName", "NetHackW" - VALUE "LegalCopyright", "Copyright (C) 1985 - 2017. By Stichting Mathematisch Centrum and M. Stephenson. See license for details." + VALUE "LegalCopyright", "Copyright (C) 1985 - 2018. By Stichting Mathematisch Centrum and M. Stephenson. See license for details." VALUE "OriginalFilename", "NetHackW.exe" VALUE "PrivateBuild", "140606" VALUE "ProductName", "NetHack"