Merge branch 'NetHack-3.6'

This commit is contained in:
Bart House
2019-10-31 20:46:54 -07:00
9 changed files with 507 additions and 230 deletions
+6 -3
View File
@@ -57,7 +57,7 @@ Spackman, Steve VanDevender, and Paul Winner, ported NetHack 3.1 to the PC.
Jon W{tte and Hao-yang Wang, with help from Ross Brown, Mike Engber, David Jon W{tte and Hao-yang Wang, with help from Ross Brown, Mike Engber, David
Hairston, Michael Hamel, Jonathan Handler, Johnny Lee, Tim Lennan, Rob Menke, Hairston, Michael Hamel, Jonathan Handler, Johnny Lee, Tim Lennan, Rob Menke,
and Andy Swanson developed NetHack 3.1 for the Macintosh, porting it for and Andy Swanson developed NetHack 3.1 for the Macintosh, porting it for
MPW. Building on their development, Barton House added a Think C port. MPW. Building on their development, Bart House added a Think C port.
Timo Hakulinen ported NetHack 3.1 to OS/2. Eric Smith ported NetHack 3.1 Timo Hakulinen ported NetHack 3.1 to OS/2. Eric Smith ported NetHack 3.1
to the Atari. Pat Rankin, with help from Joshua Delahunty, is responsible to the Atari. Pat Rankin, with help from Joshua Delahunty, is responsible
@@ -195,7 +195,7 @@ Unix flavors as well as maintaining the X11 interface.
Ken Lorber, Haoyang Wang, Pat Rankin, and Dean Luick maintained the port Ken Lorber, Haoyang Wang, Pat Rankin, and Dean Luick maintained the port
of NetHack 3.6.1 for Mac OSX. of NetHack 3.6.1 for Mac OSX.
Michael Allison, David Cohrs, Barton House, Pasi Kallinen, Alex Kompel, Michael Allison, David Cohrs, Bart House, Pasi Kallinen, Alex Kompel,
Dion Nicolaas, Derek S. Ray and Yitzhak Sapir maintained the port of Dion Nicolaas, Derek S. Ray and Yitzhak Sapir maintained the port of
NetHack 3.6 for Microsoft Windows. NetHack 3.6 for Microsoft Windows.
@@ -217,6 +217,9 @@ Derek S. Ray, Alex Smith, Mike Stephenson, Janet Walz and Paul Winner.
In early May 2019, another 320 bug fixes along with some enhancements and In early May 2019, another 320 bug fixes along with some enhancements and
the adopted curses window port, were released as 3.6.2. the adopted curses window port, were released as 3.6.2.
Bart House, who had contributed to the game as a porting team participant
for decades, joined the NetHack Development Team in late May 2019.
The official NetHack web site is maintained by Ken Lorber at The official NetHack web site is maintained by Ken Lorber at
http://www.nethack.org/. http://www.nethack.org/.
@@ -241,7 +244,7 @@ of these miscreants in this, the list of Dungeoneers:
Andy Church Jochen Erwied Pat Rankin Andy Church Jochen Erwied Pat Rankin
Andy Swanson John Kallen Patric Mueller Andy Swanson John Kallen Patric Mueller
Ari Huttunen John Rupley Paul Winner Ari Huttunen John Rupley Paul Winner
Barton House John S. Bien Pierre Martineau Bart House John S. Bien Pierre Martineau
Benson I. Margulies Johnny Lee Ralf Brown Benson I. Margulies Johnny Lee Ralf Brown
Bill Dyer Jon W{tte Ray Chason Bill Dyer Jon W{tte Ray Chason
Boudewijn Waijers Jonathan Handler Richard Addison Boudewijn Waijers Jonathan Handler Richard Addison
+7 -4
View File
@@ -24,7 +24,7 @@
.ds vr "NetHack 3.7 .ds vr "NetHack 3.7
.ds f0 "\*(vr .ds f0 "\*(vr
.ds f1 .ds f1
.ds f2 "October 27, 2019 .ds f2 "October 31, 2019
. .
.\" A note on some special characters: .\" A note on some special characters:
.\" \(lq = left double quote .\" \(lq = left double quote
@@ -4911,7 +4911,7 @@ and \fBPaul Winner\fP, ported NetHack 3.1 to the PC.
\fBMike Engber\fP, \fBDavid Hairston\fP, \fBMichael Hamel\fP, \fBMike Engber\fP, \fBDavid Hairston\fP, \fBMichael Hamel\fP,
\fBJonathan Handler\fP, \fBJohnny Lee\fP, \fBTim Lennan\fP, \fBRob Menke\fP, \fBJonathan Handler\fP, \fBJohnny Lee\fP, \fBTim Lennan\fP, \fBRob Menke\fP,
and \fBAndy Swanson\fP, developed NetHack 3.1 for the Macintosh, and \fBAndy Swanson\fP, developed NetHack 3.1 for the Macintosh,
porting it for MPW. Building on their development, \fBBarton House\fP porting it for MPW. Building on their development, \fBBart House\fP
added a Think C port. added a Think C port.
.pg .pg
\fBTimo Hakulinen\fP ported NetHack 3.1 to OS/2. \fBEric Smith\fP \fBTimo Hakulinen\fP ported NetHack 3.1 to OS/2. \fBEric Smith\fP
@@ -5070,7 +5070,7 @@ flavors and maintained the X11 interface.
\fBKen Lorber\fP, \fBHaoyang Wang\fP, \fBPat Rankin\fP, and \fBDean Luick\fP \fBKen Lorber\fP, \fBHaoyang Wang\fP, \fBPat Rankin\fP, and \fBDean Luick\fP
maintained the port of NetHack 3.6 for Mac OSX. maintained the port of NetHack 3.6 for Mac OSX.
.pg .pg
\fBMichael Allison\fP, \fBDavid Cohrs\fP, \fBBarton House\fP, \fBMichael Allison\fP, \fBDavid Cohrs\fP, \fBBart House\fP,
\fBPasi Kallinen\fP, \fBAlex Kompel\fP, \fBDion Nicolaas\fP, \fBPasi Kallinen\fP, \fBAlex Kompel\fP, \fBDion Nicolaas\fP,
\fBDerek S. Ray\fP and \fBYitzhak Sapir\fP maintained the port of \fBDerek S. Ray\fP and \fBYitzhak Sapir\fP maintained the port of
NetHack 3.6 for Microsoft Windows. NetHack 3.6 for Microsoft Windows.
@@ -5095,6 +5095,9 @@ The NetHack Development Team at the time of release of 3.6.1 consisted of
In early May 2019, another 320 bug fixes along with some enhancements and In early May 2019, another 320 bug fixes along with some enhancements and
the adopted curses window port, were released as 3.6.2. the adopted curses window port, were released as 3.6.2.
.pg .pg
\fBBart House\fP, who had contributed to the game as a porting team
participant for decades, joined the NetHack Development Team in late May 2019.
.pg
The official NetHack web site is maintained by \fBKen Lorber\fP The official NetHack web site is maintained by \fBKen Lorber\fP
at at
.UR http://www.nethack.org/ . .UR http://www.nethack.org/ .
@@ -5130,7 +5133,7 @@ Andreas Dorn Jeff Bailey Pasi Kallinen
Andy Church Jochen Erwied Pat Rankin Andy Church Jochen Erwied Pat Rankin
Andy Swanson John Kallen Patric Mueller Andy Swanson John Kallen Patric Mueller
Ari Huttunen John Rupley Paul Winner Ari Huttunen John Rupley Paul Winner
Barton House John S. Bien Pierre Martineau Bart House John S. Bien Pierre Martineau
Benson I. Margulies Johnny Lee Ralf Brown Benson I. Margulies Johnny Lee Ralf Brown
Bill Dyer Jon W{tte Ray Chason Bill Dyer Jon W{tte Ray Chason
Boudewijn Waijers Jonathan Handler Richard Addison Boudewijn Waijers Jonathan Handler Richard Addison
+70 -67
View File
@@ -45,7 +45,7 @@
%.au %.au
\author{Original version - Eric S. Raymond\\ \author{Original version - Eric S. Raymond\\
(Edited and expanded for 3.6 by Mike Stephenson and others)} (Edited and expanded for 3.6 by Mike Stephenson and others)}
\date{October 22, 2019} \date{October 31, 2019}
\maketitle \maketitle
@@ -1130,7 +1130,7 @@ slot to another so that it has a letter which is more meaningful for you
or that it will appear in a particular location when inventory listings or that it will appear in a particular location when inventory listings
are displayed. are displayed.
You can move to a currently empty slot, or if the destination is You can move to a currently empty slot, or if the destination is
occupied--and won't merge--the item there will swap slots with the one occupied---and won't merge---the item there will swap slots with the one
being moved. being moved.
``{\tt \#adjust}'' can also be used to split a stack of objects; when ``{\tt \#adjust}'' can also be used to split a stack of objects; when
choosing the item to adjust, enter a count prior to its letter.\\ choosing the item to adjust, enter a count prior to its letter.\\
@@ -2044,9 +2044,9 @@ will result in it disappearing from your map, similarly if it is the
one who moved rather than you. one who moved rather than you.
%.pg %.pg
However, if you encounter a monster which you can't see or sense-- However, if you encounter a monster which you can't see or
perhaps it is invisible and has just tapped you on the noggin-- sense---perhaps it is invisible and has just tapped you on the
a special ``remembered, unseen monster'' marker will be displayed at noggin---a special ``remembered, unseen monster'' marker will be displayed at
the location where you think it is. the location where you think it is.
That will persist until you have That will persist until you have
proven that there is no monster there, even if the unseen monster proven that there is no monster there, even if the unseen monster
@@ -2326,7 +2326,7 @@ But first you need to have a weapon in each hand.
(Note that your two weapons are not fully equal; the one in the (Note that your two weapons are not fully equal; the one in the
hand you normally wield with is considered primary and the other hand you normally wield with is considered primary and the other
one is considered secondary. The most noticeable difference is one is considered secondary. The most noticeable difference is
after you stop--or before you begin, for that matter--wielding after you stop---or before you begin, for that matter---wielding
two weapons at once. The primary is your wielded weapon and the two weapons at once. The primary is your wielded weapon and the
secondary is just an item in your inventory that's been designated secondary is just an item in your inventory that's been designated
as alternate weapon.) as alternate weapon.)
@@ -2558,7 +2558,7 @@ The commands to use rings are `{\tt P}' (put on) and `{\tt R}' (remove).
%.pg %.pg
Spellbooks are tomes of mighty magic. When studied with the `{\tt r}' (read) Spellbooks are tomes of mighty magic. When studied with the `{\tt r}' (read)
command, they transfer to the reader the knowledge of a spell (and command, they transfer to the reader the knowledge of a spell (and
therefore eventually become unreadable) --- unless the attempt backfires. therefore eventually become unreadable)---unless the attempt backfires.
Reading a cursed spellbook or one with mystic runes beyond Reading a cursed spellbook or one with mystic runes beyond
your ken can be harmful to your health! your ken can be harmful to your health!
@@ -2701,9 +2701,9 @@ you are carrying (shopkeepers aside).
Normally, if you have seen an object at a particular map location and Normally, if you have seen an object at a particular map location and
move to another location where you can't directly see that object any move to another location where you can't directly see that object any
more, if will continue to be displayed on your map. more, if will continue to be displayed on your map.
That remains the case even if it is not actually there any more-- That remains the case even if it is not actually there any
perhaps a monster has picked it up or it has rotted away-- more---perhaps a monster has picked it up or it has rotted
until you can see or feel that location again. away---until you can see or feel that location again.
One notable exception is that if the object gets covered by the One notable exception is that if the object gets covered by the
``remembered, unseen monster'' marker. ``remembered, unseen monster'' marker.
When that marker is later removed When that marker is later removed
@@ -3028,11 +3028,13 @@ See the ``Configuring User Sounds'' section.
Define the directory that contains the sound files. Define the directory that contains the sound files.
See the ``Configuring User Sounds'' section. See the ``Configuring User Sounds'' section.
%.lp %.lp
\item[\bb{SYMBOLS} \item[\bb{SYMBOLS}]
Override one or more symbols in the symbol set used for all dungeon Override one or more symbols in the symbol set used for all dungeon
levels except for the special rogue level. levels except for the special rogue level.
See the ``Modifying {\it NetHack\/} Symbols'' section. See the ``Modifying {\it NetHack\/} Symbols'' section.
%.pg %.pg
%.lp ""
Example: Example:
%.sd %.sd
\begin{verbatim} \begin{verbatim}
@@ -4378,158 +4380,158 @@ Below are the special commands you can rebind. Some of them can be bound to
same keys with no problems, others are in the same ``context'', and if bound same keys with no problems, others are in the same ``context'', and if bound
to same keys, only one of those commands will be available. Special command to same keys, only one of those commands will be available. Special command
can only be bound to a single key. can only be bound to a single key.
\elist
%.pg %.pg
\blist{} \blist{\itemindent 10mm \labelwidth 15mm \rightmargin 20mm}
%.lp %.lp
\item{\bb{count}} \item[{\bb{count}}]
Prefix key to start a count, to repeat a command this many times. Prefix key to start a count, to repeat a command this many times.
With {\it number\verb+_+pad\/} only. Default is `{\tt n}'. With {\it number\verb+_+pad\/} only. Default is `{\tt n}'.
%.lp %.lp
\item{\bb{doinv}} \item[{\bb{doinv}}]
Show inventory. With {\it number\verb+_+pad\/} only. Default is `{\tt 0}'. Show inventory. With {\it number\verb+_+pad\/} only. Default is `{\tt 0}'.
%.lp %.lp
\item{\bb{fight}} \item[{\bb{fight}}]
Prefix key to force fight a direction. Default is `{\tt F}'. Prefix key to force fight a direction. Default is `{\tt F}'.
%.lp %.lp
\item{\bb{fight.numpad}} \item[{\bb{fight.numpad}}]
Prefix key to force fight a direction. With {\it number\verb+_+pad\/} only. Prefix key to force fight a direction. With {\it number\verb+_+pad\/} only.
Default is `{\tt -}'. Default is `{\tt -}'.
%.lp %.lp
\item{\bb{getdir.help}} \item[{\bb{getdir.help}}]
When asked for a direction, the key to show the help. Default is `{\tt ?}'. When asked for a direction, the key to show the help. Default is `{\tt ?}'.
%.lp %.lp
\item{\bb{getdir.self}} \item[{\bb{getdir.self}}]
When asked for a direction, the key to target yourself. Default is `{\tt .}'. When asked for a direction, the key to target yourself. Default is `{\tt .}'.
%.lp %.lp
\item{\bb{getdir.self2}} \item[{\bb{getdir.self2}}]
When asked for a direction, the key to target yourself. Default is `{\tt s}'. When asked for a direction, the key to target yourself. Default is `{\tt s}'.
%.lp %.lp
\item{\bb{getpos.autodescribe}} \item[{\bb{getpos.autodescribe}}]
When asked for a location, the key to toggle {\it autodescribe\/}. When asked for a location, the key to toggle {\it autodescribe\/}.
Default is `{\tt \#}'. Default is `{\tt \#}'.
%.lp %.lp
\item{\bb{getpos.all.next}} \item[{\bb{getpos.all.next}}]
When asked for a location, the key to go to next closest interesting thing. When asked for a location, the key to go to next closest interesting thing.
Default is `{\tt a}'. Default is `{\tt a}'.
%.lp %.lp
\item{\bb{getpos.all.prev}} \item[{\bb{getpos.all.prev}}]
When asked for a location, the key to go to previous closest interesting thing. When asked for a location, the key to go to previous closest interesting thing.
Default is `{\tt A}'. Default is `{\tt A}'.
%.lp %.lp
\item{\bb{getpos.door.next}} \item[{\bb{getpos.door.next}}]
When asked for a location, the key to go to next closest door or doorway. When asked for a location, the key to go to next closest door or doorway.
Default is `{\tt d}'. Default is `{\tt d}'.
%.lp %.lp
\item{\bb{getpos.door.prev}} \item[{\bb{getpos.door.prev}}]
When asked for a location, the key to go to previous closest door or doorway. When asked for a location, the key to go to previous closest door or doorway.
Default is `{\tt D}'. Default is `{\tt D}'.
%.lp %.lp
\item{\bb{getpos.help}} \item[{\bb{getpos.help}}]
When asked for a location, the key to show help. Default is `{\tt ?}'. When asked for a location, the key to show help. Default is `{\tt ?}'.
%.lp %.lp
\item{\bb{getpos.mon.next}} \item[{\bb{getpos.mon.next}}]
When asked for a location, the key to go to next closest monster. When asked for a location, the key to go to next closest monster.
Default is `{\tt m}'. Default is `{\tt m}'.
%.lp %.lp
\item{\bb{getpos.mon.prev}} \item[{\bb{getpos.mon.prev}}]
When asked for a location, the key to go to previous closest monster. When asked for a location, the key to go to previous closest monster.
Default is `{\tt M}'. Default is `{\tt M}'.
%.lp %.lp
\item{\bb{getpos.obj.next}} \item[{\bb{getpos.obj.next}}]
When asked for a location, the key to go to next closest object. When asked for a location, the key to go to next closest object.
Default is `{\tt o}'. Default is `{\tt o}'.
%.lp %.lp
\item{\bb{getpos.obj.prev}} \item[{\bb{getpos.obj.prev}}]
When asked for a location, the key to go to previous closest object. When asked for a location, the key to go to previous closest object.
Default is `{\tt O}'. Default is `{\tt O}'.
%.lp %.lp
\item{\bb{getpos.menu}} \item[{\bb{getpos.menu}}]
When asked for a location, and using one of the next or previous keys to When asked for a location, and using one of the next or previous keys to
cycle through targets, toggle showing a menu instead. Default is `{\tt !}'. cycle through targets, toggle showing a menu instead. Default is `{\tt !}'.
%.lp %.lp
\item{\bb{getpos.moveskip}} \item[{\bb{getpos.moveskip}}]
When asked for a location, and using the shifted movement keys or When asked for a location, and using the shifted movement keys or
meta-digit keys to fast-move around, move by skipping the same glyphs meta-digit keys to fast-move around, move by skipping the same glyphs
instead of by 8 units. instead of by 8 units.
Default is `{\tt *}'. Default is `{\tt *}'.
%.lp %.lp
\item{\bb{getpos.filter}} \item[{\bb{getpos.filter}}]
When asked for a location, change the filtering mode when using one of When asked for a location, change the filtering mode when using one of
the next or previous keys to cycle through targets. Toggles between no the next or previous keys to cycle through targets. Toggles between no
filtering, in view only, and in the same area only. Default is `{\tt "}'. filtering, in view only, and in the same area only. Default is `{\tt "}'.
%.lp %.lp
\item{\bb{getpos.pick}} \item[{\bb{getpos.pick}}]
When asked for a location, the key to choose the location, and possibly When asked for a location, the key to choose the location, and possibly
ask for more info. Default is `{\tt .}'. ask for more info. Default is `{\tt .}'.
%.lp %.lp
\item{\bb{getpos.pick.once}} \item[{\bb{getpos.pick.once}}]
When asked for a location, the key to choose the location, and skip When asked for a location, the key to choose the location, and skip
asking for more info. Default is `{\tt ,}'. asking for more info. Default is `{\tt ,}'.
%.lp %.lp
\item{\bb{getpos.pick.quick}} \item[{\bb{getpos.pick.quick}}]
When asked for a location, the key to choose the location, skip asking When asked for a location, the key to choose the location, skip asking
for more info, and exit the location asking loop. Default is `{\tt ;}'. for more info, and exit the location asking loop. Default is `{\tt ;}'.
%.lp %.lp
\item{\bb{getpos.pick.verbose}} \item[{\bb{getpos.pick.verbose}}]
When asked for a location, the key to choose the location, and show more When asked for a location, the key to choose the location, and show more
info without asking. Default is `{\tt :}'. info without asking. Default is `{\tt :}'.
%.lp %.lp
\item{\bb{getpos.self}} \item[{\bb{getpos.self}}]
When asked for a location, the key to go to your location. When asked for a location, the key to go to your location.
Default is `{\tt @}'. Default is `{\tt @}'.
%.lp %.lp
\item{\bb{getpos.unexplored.next}} \item[{\bb{getpos.unexplored.next}}]
When asked for a location, the key to go to next closest unexplored location. When asked for a location, the key to go to next closest unexplored location.
Default is `{\tt x}'. Default is `{\tt x}'.
%.lp %.lp
\item{\bb{getpos.unexplored.prev}} \item[{\bb{getpos.unexplored.prev}}]
When asked for a location, the key to go to previous closest unexplored When asked for a location, the key to go to previous closest unexplored
location. Default is `{\tt X}'. location. Default is `{\tt X}'.
%.lp %.lp
\item{\bb{getpos.valid}} \item[{\bb{getpos.valid}}]
When asked for a location, the key to go to show valid target locations. When asked for a location, the key to go to show valid target locations.
Default is `{\tt \$}'. Default is `{\tt \$}'.
%.lp %.lp
\item{\bb{getpos.valid.next}} \item[{\bb{getpos.valid.next}}]
When asked for a location, the key to go to next closest valid location. When asked for a location, the key to go to next closest valid location.
Default is `{\tt z}'. Default is `{\tt z}'.
%.lp %.lp
\item{\bb{getpos.valid.prev}} \item[{\bb{getpos.valid.prev}}]
When asked for a location, the key to go to previous closest valid location. When asked for a location, the key to go to previous closest valid location.
Default is `{\tt Z}'. Default is `{\tt Z}'.
%.lp %.lp
\item{\bb{nopickup}} \item[{\bb{nopickup}}]
Prefix key to move without picking up items. Default is `{\tt m}'. Prefix key to move without picking up items. Default is `{\tt m}'.
%.lp %.lp
\item{\bb{redraw}} \item[{\bb{redraw}}]
Key to redraw the screen. Default is `{\tt \^{}R}'. Key to redraw the screen. Default is `{\tt \^{}R}'.
%.lp %.lp
\item{\bb{redraw.numpad}} \item[{\bb{redraw.numpad}}]
Key to redraw the screen. With {\it number\verb+_+pad\/} only. Key to redraw the screen. With {\it number\verb+_+pad\/} only.
Default is `{\tt \^{}L}'. Default is `{\tt \^{}L}'.
%.lp %.lp
\item{\bb{repeat}} \item[{\bb{repeat}}]
Key to repeat previous command. Default is `{\tt \^{}A}'. Key to repeat previous command. Default is `{\tt \^{}A}'.
%.lp %.lp
\item{\bb{reqmenu}} \item[{\bb{reqmenu}}]
Prefix key to request menu from some commands. Default is `{\tt m}'. Prefix key to request menu from some commands. Default is `{\tt m}'.
%.lp %.lp
\item{\bb{run}} \item[{\bb{run}}]
Prefix key to run towards a direction. Default is `{\tt G}'. Prefix key to run towards a direction. Default is `{\tt G}'.
%.lp %.lp
\item{\bb{run.nopickup}} \item[{\bb{run.nopickup}}]
Prefix key to run towards a direction without picking up items on the way. Prefix key to run towards a direction without picking up items on the way.
Default is `{\tt M}'. Default is `{\tt M}'.
%.lp %.lp
\item{\bb{run.numpad}} \item[{\bb{run.numpad}}]
Prefix key to run towards a direction. With {\it number\verb+_+pad\/} only. Prefix key to run towards a direction. With {\it number\verb+_+pad\/} only.
Default is `{\tt 5}'. Default is `{\tt 5}'.
%.lp %.lp
\item{\bb{rush}} \item[{\bb{rush}}]
Prefix key to rush towards a direction. Default is `{\tt g}'. Prefix key to rush towards a direction. Default is `{\tt g}'.
\elist \elist
\elist
%.hn 2 %.hn 2
@@ -4733,6 +4735,8 @@ combination with any of the other attributes.
To specify both a color and an attribute, use `\&' to combine them. To specify both a color and an attribute, use `\&' to combine them.
To specify multiple attributes, use `+' to combine those. To specify multiple attributes, use `+' to combine those.
%.lp ""
For example: {\tt magenta\&inverse+dim}. For example: {\tt magenta\&inverse+dim}.
Note that the display may substitute or ignore particular attributes Note that the display may substitute or ignore particular attributes
@@ -4785,23 +4789,19 @@ percentage or absolute number threshold, or text to match against.
\blist{} \blist{}
%.lp "*" %.lp "*"
\item{\bb{}} \item[{\tt always}] will set the default attributes for that field.
``{\tt always}'' will set the default attributes for that field.
%.lp "*" %.lp "*"
\item{\bb{}} \item[{\tt up} and ``{\tt down}''] set the field attributes for when the field
``{\tt up}'' and ``{\tt down}'' set the field attributes for when the field
value changes upwards or downwards. This attribute times out after value changes upwards or downwards. This attribute times out after
{\tt statushilites} turns. {\tt statushilites} turns.
%.lp "*" %.lp "*"
\item{\bb{}} \item[{\tt changed}] sets the field attribute for when the field value
``{\tt changed}'' sets the field attribute for when the field value
changes. This attribute times out after {\tt statushilites} turns. changes. This attribute times out after {\tt statushilites} turns.
(If a field has both a ``changed'' rule and an ``up'' or ``down'' (If a field has both a ``changed'' rule and an ``up'' or ``down''
rule which matches a change in the field's value, rule which matches a change in the field's value,
the ``up'' or ``down'' one takes precedence.) the ``up'' or ``down'' one takes precedence.)
%.lp "*" %.lp "*"
\item{\bb{}} \item[{\tt percentage}] sets the field attribute when the field value
percentage sets the field attribute when the field value
matches the percentage. matches the percentage.
It is specified as a number between 0 and 100, followed by `{\tt \%}' It is specified as a number between 0 and 100, followed by `{\tt \%}'
(percent sign). (percent sign).
@@ -4829,8 +4829,7 @@ exactly 1 experience point short of the next level.
% percentage will remain at 0\% no matter have many additional experience % percentage will remain at 0\% no matter have many additional experience
% points you earn.) % points you earn.)
%.lp "*" %.lp "*"
\item{\bb{}} \item[{\tt absolute}] value sets the attribute when the field value
absolute value sets the attribute when the field value
matches that number. matches that number.
The number must be 0 or higher, except for ``{\it armor-class\/} which The number must be 0 or higher, except for ``{\it armor-class\/} which
allows negative values, and may optionally be preceded by `{\tt =}'. allows negative values, and may optionally be preceded by `{\tt =}'.
@@ -4839,8 +4838,7 @@ it also matches when value is below or above.
If the prefix is `{\tt <}' or `{\tt >}', only match when strictly If the prefix is `{\tt <}' or `{\tt >}', only match when strictly
above or below. above or below.
%.lp "*" %.lp "*"
\item{\bb{}} \item[{\tt text}] match sets the attribute when the field value matches the text.
text match sets the attribute when the field value matches the text.
Text matches can only be used for ``{\it alignment\/}'', Text matches can only be used for ``{\it alignment\/}'',
``{\it carrying-capacity\/}'', ``{\it hunger\/}'', ``{\it dungeon-level\/}'', ``{\it carrying-capacity\/}'', ``{\it hunger\/}'', ``{\it dungeon-level\/}'',
and ``{\it title\/}''. and ``{\it title\/}''.
@@ -5469,7 +5467,7 @@ with help from {\it Ross Brown}, {\it Mike Engber}, {\it David Hairston},
{\it Michael Hamel}, {\it Jonathan Handler}, {\it Johnny Lee}, {\it Michael Hamel}, {\it Jonathan Handler}, {\it Johnny Lee},
{\it Tim Lennan}, {\it Rob Menke}, and {\it Andy Swanson}, {\it Tim Lennan}, {\it Rob Menke}, and {\it Andy Swanson},
developed {\it NetHack\/} 3.1 for the Macintosh, porting it for MPW. developed {\it NetHack\/} 3.1 for the Macintosh, porting it for MPW.
Building on their development, {\it Barton House} added a Think C port. Building on their development, {\it Bart House} added a Think C port.
%.pg %.pg
\medskip \medskip
@@ -5682,7 +5680,7 @@ maintained the port of {\it NetHack\/} 3.6 for Mac OSX.
%.pg %.pg
\medskip \medskip
{\it Michael Allison}, {\it David Cohrs}, {\it Barton House}, {\it Michael Allison}, {\it David Cohrs}, {\it Bart House},
{\it Pasi Kallinen}, {\it Alex Kompel}, {\it Dion Nicolaas}, {\it Pasi Kallinen}, {\it Alex Kompel}, {\it Dion Nicolaas},
{\it Derek S. Ray} and {\it Yitzhak Sapir} {\it Derek S. Ray} and {\it Yitzhak Sapir}
maintained the port of {\it NetHack\/} 3.6 for Microsoft Windows. maintained the port of {\it NetHack\/} 3.6 for Microsoft Windows.
@@ -5716,6 +5714,11 @@ time of release of 3.6.1 consisted of
In early May 2019, another 320 bug fixes along with some enhancements and In early May 2019, another 320 bug fixes along with some enhancements and
the adopted curses window port, were released as 3.6.2. the adopted curses window port, were released as 3.6.2.
%.pg
\medskip
{\it Bart House}, who had contributed to the game as a porting team participant
for decades, joined the {\it NetHack Development Team} in late May 2019.
%.pg %.pg
\medskip \medskip
\nd The official {\it NetHack\/} web site is maintained by {\it Ken Lorber} at \nd The official {\it NetHack\/} web site is maintained by {\it Ken Lorber} at
@@ -5757,7 +5760,7 @@ Andreas Dorn & Jeff Bailey & Pasi Kallinen\\
Andy Church & Jochen Erwied & Pat Rankin\\ Andy Church & Jochen Erwied & Pat Rankin\\
Andy Swanson & John Kallen & Patric Mueller\\ Andy Swanson & John Kallen & Patric Mueller\\
Ari Huttunen & John Rupley & Paul Winner\\ Ari Huttunen & John Rupley & Paul Winner\\
Barton House & John S. Bien & Pierre Martineau\\ Bart House & John S. Bien & Pierre Martineau\\
Benson I. Margulies & Johnny Lee & Ralf Brown\\ Benson I. Margulies & Johnny Lee & Ralf Brown\\
Bill Dyer & Jon W\{tte & Ray Chason\\ Bill Dyer & Jon W\{tte & Ray Chason\\
Boudewijn Waijers & Jonathan Handler & Richard Addison\\ Boudewijn Waijers & Jonathan Handler & Richard Addison\\
+4 -2
View File
@@ -21,15 +21,17 @@ extern LONG GetCurrentPackageFullName(UINT32 *packageFullNameLength,
PWSTR packageFullName); PWSTR packageFullName);
extern HRESULT SHGetKnownFolderPath(REFKNOWNFOLDERID rfid, extern HRESULT SHGetKnownFolderPath(REFKNOWNFOLDERID rfid,
DWORD dwFlags, HANDLE hToken, PWSTR *ppszPath); DWORD dwFlags, HANDLE hToken, PWSTR *ppszPath);
#ifndef DEFINE_KNOWN_FOLDER
#ifdef INITGUID #ifdef INITGUID
#define DEFINE_KNOWN_FOLDER(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) const GUID DECLSPEC_SELECTANY name = { l, w1, w2,{ b1, b2, b3, b4, b5, b6, b7, b8 } } #define DEFINE_KNOWN_FOLDER(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) const GUID DECLSPEC_SELECTANY name = { l, w1, w2,{ b1, b2, b3, b4, b5, b6, b7, b8 } }
#else #else
#define DEFINE_KNOWN_FOLDER(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) const GUID name #define DEFINE_KNOWN_FOLDER(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) const GUID name
#endif #endif /* INITGUID */
#endif /* DEFINE_KNOWN_FOLDER */
DEFINE_KNOWN_FOLDER (FOLDERID_ProgramData, 0x62ab5d82, 0xfdc1, 0x4dc3, 0xa9, 0xdd, 0x07, 0x0d, 0x1d, 0x49, 0x5d, 0x97); DEFINE_KNOWN_FOLDER (FOLDERID_ProgramData, 0x62ab5d82, 0xfdc1, 0x4dc3, 0xa9, 0xdd, 0x07, 0x0d, 0x1d, 0x49, 0x5d, 0x97);
DEFINE_KNOWN_FOLDER (FOLDERID_LocalAppData, 0xf1b32785, 0x6fba, 0x4fcf, 0x9d, 0x55, 0x7b, 0x8e, 0x7f, 0x15, 0x70, 0x91); DEFINE_KNOWN_FOLDER (FOLDERID_LocalAppData, 0xf1b32785, 0x6fba, 0x4fcf, 0x9d, 0x55, 0x7b, 0x8e, 0x7f, 0x15, 0x70, 0x91);
DEFINE_KNOWN_FOLDER (FOLDERID_Profile, 0x5e6c858f, 0x0e22, 0x4760, 0x9a, 0xfe, 0xea, 0x33, 0x17, 0xb6, 0x71, 0x73); DEFINE_KNOWN_FOLDER (FOLDERID_Profile, 0x5e6c858f, 0x0e22, 0x4760, 0x9a, 0xfe, 0xea, 0x33, 0x17, 0xb6, 0x71, 0x73);
#endif #endif /* __MINGW32__ */
#if 0 #if 0
#include "wintty.h" #include "wintty.h"
+5 -5
View File
@@ -172,12 +172,12 @@ BEGIN
CONTROL "Chaotic",IDC_PLSEL_ALIGN_CHAOTIC,"Button",BS_AUTORADIOBUTTON,168,72,38,10 CONTROL "Chaotic",IDC_PLSEL_ALIGN_CHAOTIC,"Button",BS_AUTORADIOBUTTON,168,72,38,10
CONTROL "Male",IDC_PLSEL_GENDER_MALE,"Button",BS_AUTORADIOBUTTON | WS_GROUP,168,108,30,10 CONTROL "Male",IDC_PLSEL_GENDER_MALE,"Button",BS_AUTORADIOBUTTON | WS_GROUP,168,108,30,10
CONTROL "Female",IDC_PLSEL_GENDER_FEMALE,"Button",BS_AUTORADIOBUTTON,168,120,38,10 CONTROL "Female",IDC_PLSEL_GENDER_FEMALE,"Button",BS_AUTORADIOBUTTON,168,120,38,10
GROUPBOX "Alignment",IDC_STATIC,162,36,48,54 GROUPBOX "Alignment",IDC_PLSEL_ALIGNMENT_GROUP,162,36,48,54
GROUPBOX "Gender",IDC_STATIC,162,96,48,42 GROUPBOX "Gender",IDC_PLSEL_GENDER_GROUP,162,96,48,42
GROUPBOX "Role",IDC_STATIC,6,36,72,150 GROUPBOX "Role",IDC_PLSEL_ROLE_GROUP,6,36,72,150
GROUPBOX "Race",IDC_STATIC,84,36,72,72 GROUPBOX "Race",IDC_PLSEL_RACE_GROUP,84,36,72,72
PUSHBUTTON "Random",IDC_PLSEL_RANDOM,90,192,54,14,WS_GROUP PUSHBUTTON "Random",IDC_PLSEL_RANDOM,90,192,54,14,WS_GROUP
GROUPBOX "Name",IDC_STATIC,6,0,120,30 GROUPBOX "Name",IDC_PLSEL_NAME_GROUP,6,0,120,30
CONTROL "",IDC_PLSEL_ROLE_LIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_OWNERDRAWFIXED | LVS_ALIGNLEFT | LVS_NOSCROLL | LVS_NOCOLUMNHEADER | WS_BORDER | WS_GROUP | WS_TABSTOP,12,48,60,130 CONTROL "",IDC_PLSEL_ROLE_LIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_OWNERDRAWFIXED | LVS_ALIGNLEFT | LVS_NOSCROLL | LVS_NOCOLUMNHEADER | WS_BORDER | WS_GROUP | WS_TABSTOP,12,48,60,130
CONTROL "",IDC_PLSEL_RACE_LIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_OWNERDRAWFIXED | LVS_ALIGNLEFT | LVS_NOSCROLL | LVS_NOCOLUMNHEADER | WS_BORDER | WS_GROUP | WS_TABSTOP,90,48,60,51 CONTROL "",IDC_PLSEL_RACE_LIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_OWNERDRAWFIXED | LVS_ALIGNLEFT | LVS_NOSCROLL | LVS_NOCOLUMNHEADER | WS_BORDER | WS_GROUP | WS_TABSTOP,90,48,60,51
END END
+395 -146
View File
@@ -4,6 +4,7 @@
/* various dialog boxes are defined here */ /* various dialog boxes are defined here */
#include "win10.h"
#include "winMS.h" #include "winMS.h"
#include "hack.h" #include "hack.h"
#include "func_tab.h" #include "func_tab.h"
@@ -12,6 +13,7 @@
#include <assert.h> #include <assert.h>
/*---------------------------------------------------------------*/ /*---------------------------------------------------------------*/
/* data for getlin dialog */ /* data for getlin dialog */
struct getlin_data { struct getlin_data {
@@ -276,22 +278,68 @@ ExtCmdDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
/*---------------------------------------------------------------*/ /*---------------------------------------------------------------*/
/* player selector dialog */ /* player selector dialog */
/* NOTE: this enumeration is in control tab order */
enum player_selector_control {
psc_name_group,
psc_role_group,
psc_race_group,
psc_alignment_group,
psc_gender_group,
psc_name_box,
psc_role_list,
psc_race_list,
psc_lawful_button,
psc_neutral_button,
psc_chaotic_button,
psc_male_button,
psc_female_button,
psc_play_button,
psc_random_button,
psc_quit_button,
psc_control_count
};
static const s_psc_id[psc_control_count] = {
IDC_PLSEL_NAME_GROUP,
IDC_PLSEL_ROLE_GROUP,
IDC_PLSEL_RACE_GROUP,
IDC_PLSEL_ALIGNMENT_GROUP,
IDC_PLSEL_GENDER_GROUP,
IDC_PLSEL_NAME,
IDC_PLSEL_ROLE_LIST,
IDC_PLSEL_RACE_LIST,
IDC_PLSEL_ALIGN_LAWFUL,
IDC_PLSEL_ALIGN_NEUTRAL,
IDC_PLSEL_ALIGN_CHAOTIC,
IDC_PLSEL_GENDER_MALE,
IDC_PLSEL_GENDER_FEMALE,
IDOK,
IDC_PLSEL_RANDOM,
IDCANCEL
};
typedef struct {
int id;
POINT pos;
SIZE size;
HWND hWnd;
} control_t;
typedef struct plsel_data { typedef struct plsel_data {
HWND dialog;
HWND focus;
control_t controls[psc_control_count];
SIZE client_size;
int config_race; int config_race;
int config_role; int config_role;
int config_gender; int config_gender;
int config_alignment; int config_alignment;
HWND control_role;
HWND control_race;
HWND control_genders[ROLE_GENDERS];
HWND control_aligns[ROLE_ALIGNS];
int role_count; int role_count;
int race_count; int race_count;
HWND focus;
} plsel_data_t; } plsel_data_t;
INT_PTR CALLBACK PlayerSelectorDlgProc(HWND, UINT, WPARAM, LPARAM); INT_PTR CALLBACK PlayerSelectorDlgProc(HWND, UINT, WPARAM, LPARAM);
static void plselInitDialog(HWND hWnd);
static void plselAdjustSelections(HWND hWnd); static void plselAdjustSelections(HWND hWnd);
static boolean plselRandomize(plsel_data_t * data); static boolean plselRandomize(plsel_data_t * data);
static BOOL plselDrawItem(HWND hWnd, WPARAM wParam, LPARAM lParam); static BOOL plselDrawItem(HWND hWnd, WPARAM wParam, LPARAM lParam);
@@ -322,38 +370,314 @@ mswin_player_selection_window()
return ok; return ok;
} }
int
list_view_height(HWND hWnd, int count)
{
return (ListView_ApproximateViewRect(hWnd, -1, -1, count)) >> 16;
}
/* calculate the size and position of the controls taking into account
the per-monitor DPI expressed as a scaling factor on sizes at 96 DPI */
void
calculate_player_selector_layout(plsel_data_t * data)
{
MonitorInfo monitorInfo;
win10_monitor_info(data->dialog, &monitorInfo);
double scale = monitorInfo.scale;
/* Note these hard coded sizes are in 96DPI pixels and must be
scaled by the per-monitor DPI scaling factor */
int list_width = (int) (120 * scale);
int group_border = (int) (16 * scale);
int client_border = (int) (16 * scale);
int group_spacing = (int) (16 * scale);
int button_width = (int) (80 * scale);
int button_height = (int) (28 * scale);
/* set control sizes */
control_t * name_box = &data->controls[psc_name_box];
name_box->size.cx = (int) (280 * scale);
name_box->size.cy = (int) (24 * scale);
control_t * role_list = &data->controls[psc_role_list];
/* NOTE: we dont' scale the list view reported height as it appears these
values are the actual size the control will be drawn at using the
existing DPI value */
role_list->size.cy = list_view_height(role_list->hWnd, data->role_count);
role_list->size.cx = list_width;
control_t * race_list = &data->controls[psc_race_list];
race_list->size.cy = list_view_height(race_list->hWnd, data->race_count);
race_list->size.cx = list_width;
for(int i = psc_lawful_button; i <= psc_quit_button; i++) {
data->controls[i].size.cx = button_width;
data->controls[i].size.cy = button_height;
}
for(int i = 0; i < 3; i++) {
control_t * group_control = &data->controls[psc_name_group + i];
control_t * inner_control = &data->controls[psc_name_box + i];
group_control->size.cx = inner_control->size.cx + (2 * group_border);
group_control->size.cy = inner_control->size.cy + (2 * group_border);
}
control_t * alignment_group = &data->controls[psc_alignment_group];
alignment_group->size.cx = button_width + (2 * group_border);
alignment_group->size.cy = (3 * button_height) + (2 * group_border);
control_t * gender_group = &data->controls[psc_gender_group];
gender_group->size.cx = button_width + (2 * group_border);
gender_group->size.cy = (2 * button_height) + (2 * group_border);
/* set control positions */
control_t * name_group = &data->controls[psc_name_group];
name_group->pos.x = client_border;
name_group->pos.y = client_border;
control_t * role_group = &data->controls[psc_role_group];
role_group->pos.x = client_border;
role_group->pos.y = name_group->pos.y + name_group->size.cy + group_spacing;
control_t * race_group = &data->controls[psc_race_group];
race_group->pos.x = role_group->pos.x + role_group->size.cx + group_spacing;
race_group->pos.y = role_group->pos.y;
for(int i = 0; i < 3; i++) {
control_t * group_control = &data->controls[psc_name_group + i];
control_t * inner_control = &data->controls[psc_name_box + i];
inner_control->pos.x = group_control->pos.x + group_border;
inner_control->pos.y = group_control->pos.y + group_border;
}
alignment_group->pos.x = race_group->pos.x + race_group->size.cx + group_spacing;
alignment_group->pos.y = race_group->pos.y;
for(int i = psc_lawful_button; i <= psc_chaotic_button; i++) {
data->controls[i].pos.x = alignment_group->pos.x + group_border;
data->controls[i].pos.y = alignment_group->pos.y + group_border +
((i -psc_lawful_button) * button_height);
}
gender_group->pos.x = alignment_group->pos.x;
gender_group->pos.y = alignment_group->pos.y + alignment_group->size.cy + group_spacing;
for(int i = psc_male_button; i <= psc_female_button; i++) {
data->controls[i].pos.x = gender_group->pos.x + group_border;
data->controls[i].pos.y = gender_group->pos.y + group_border +
((i - psc_male_button) * button_height);
}
int group_bottom = role_group->pos.y + role_group->size.cy;
if (group_bottom < race_group->pos.y + race_group->size.cy)
group_bottom = race_group->pos.y + race_group->size.cy;
if (group_bottom < gender_group->pos.y + gender_group->size.cy)
group_bottom = gender_group->pos.y + gender_group->size.cy;
control_t * play_button = &data->controls[psc_play_button];
play_button->pos.y = group_bottom + group_spacing;
play_button->pos.x = role_group->pos.x;
control_t * random_button = &data->controls[psc_random_button];
random_button->pos.y = play_button->pos.y;
random_button->pos.x = race_list->pos.x;
control_t * quit_button = &data->controls[psc_quit_button];
quit_button->pos.y = play_button->pos.y;
quit_button->pos.x = data->controls[psc_female_button].pos.x;
data->client_size.cx = alignment_group->pos.x + alignment_group->size.cx;
data->client_size.cy = quit_button->pos.y + quit_button->size.cy;
data->client_size.cx += client_border;
data->client_size.cy += client_border;
}
void
get_rect_size(RECT * rect, SIZE * size)
{
size->cx = rect->right - rect->left + 1;
size->cy = rect->bottom - rect->top + 1;
}
/* center given dialog in the main window */
void
center_dialog(HWND dialog)
{
RECT main_rect;
SIZE main_size;
RECT dialog_rect;
SIZE dialog_size;
POINT pos;
GetWindowRect(GetNHApp()->hMainWnd, &main_rect);
get_rect_size(&main_rect, &main_size);
GetWindowRect(dialog, &dialog_rect);
get_rect_size(&dialog_rect, &dialog_size);
pos.x = main_rect.left + (main_size.cx - dialog_size.cx) / 2;
pos.y = main_rect.top + (main_size.cy - dialog_size.cy) / 2;
MoveWindow(dialog, pos.x, pos.y, dialog_size.cx, dialog_size.cy,
TRUE);
}
/* size the dialog such that it has the given client rect size */
void
size_dialog(HWND dialog, SIZE new_client_size)
{
RECT dialog_rect;
SIZE dialog_size;
RECT client_rect;
SIZE client_size;
GetWindowRect(dialog, &dialog_rect);
get_rect_size(&dialog_rect, &dialog_size);
GetClientRect(dialog, &client_rect);
get_rect_size(&client_rect, &client_size);
dialog_size.cx += new_client_size.cx - client_size.cx;
dialog_size.cy += new_client_size.cy - client_size.cy;
MoveWindow(dialog, dialog_rect.left, dialog_rect.top,
dialog_size.cx, dialog_size.cy, TRUE);
}
/* helper routine to move all controls according to there position
and size information */
void
move_controls(control_t * controls, int count)
{
control_t * control = controls;
while(count-- > 0) {
MoveWindow(control->hWnd, control->pos.x, control->pos.y,
control->size.cx, control->size.cy, TRUE);
control++;
}
}
/* adjust the size and positions of all controls in the player
selection dialog taking into account the per-monitor DPI. */
void
do_player_selector_layout(plsel_data_t * data)
{
calculate_player_selector_layout(data);
move_controls(data->controls, psc_control_count);
size_dialog(data->dialog, data->client_size);
}
/* initialize player selector dialog */
void
plselInitDialog(struct plsel_data * data)
{
TCHAR wbuf[BUFSZ];
LVCOLUMN lvcol;
SetWindowLongPtr(data->dialog, GWLP_USERDATA, (LONG_PTR) data);
for(int i = 0; i < psc_control_count; i++) {
data->controls[i].id = s_psc_id[i];
data->controls[i].hWnd = GetDlgItem(data->dialog, s_psc_id[i]);
}
control_t * role_list = &data->controls[psc_role_list];
ZeroMemory(&lvcol, sizeof(lvcol));
lvcol.mask = LVCF_WIDTH;
lvcol.cx = 1024;
/* build role list */
ListView_InsertColumn(role_list->hWnd, 0, &lvcol);
data->role_count = 0;
for (int i = 0; roles[i].name.m; i++) {
LVITEM lvitem;
ZeroMemory(&lvitem, sizeof(lvitem));
lvitem.mask = LVIF_STATE | LVIF_TEXT;
lvitem.iItem = i;
lvitem.iSubItem = 0;
lvitem.state = 0;
lvitem.stateMask = LVIS_FOCUSED;
if (flags.female && roles[i].name.f)
lvitem.pszText = NH_A2W(roles[i].name.f, wbuf, BUFSZ);
else
lvitem.pszText = NH_A2W(roles[i].name.m, wbuf, BUFSZ);
if (ListView_InsertItem(role_list->hWnd, &lvitem) == -1) {
panic("cannot insert menu item");
}
data->role_count++;
}
/* build race list */
control_t * race_list = &data->controls[psc_race_list];
ListView_InsertColumn(race_list->hWnd, 0, &lvcol);
data->race_count = 0;
for (int i = 0; races[i].noun; i++) {
LVITEM lvitem;
ZeroMemory(&lvitem, sizeof(lvitem));
lvitem.mask = LVIF_STATE | LVIF_TEXT;
lvitem.iItem = i;
lvitem.iSubItem = 0;
lvitem.state = 0;
lvitem.stateMask = LVIS_FOCUSED;
lvitem.pszText = NH_A2W(races[i].noun, wbuf, BUFSZ);
if (ListView_InsertItem(race_list->hWnd, &lvitem) == -1) {
panic("cannot insert menu item");
}
data->race_count++;
}
/* set gender radio button state */
control_t * gender_buttons = &data->controls[psc_male_button];
for (int i = 0; i < ROLE_GENDERS; i++)
Button_Enable(gender_buttons[i].hWnd, TRUE);
Button_SetCheck(data->controls[psc_male_button].hWnd, BST_CHECKED);
/* set alignment radio button state */
control_t * alignment_buttons = &data->controls[psc_lawful_button];
for (int i = 0; i < ROLE_ALIGNS; i++)
Button_Enable(alignment_buttons[i].hWnd, TRUE);
Button_SetCheck(data->controls[psc_lawful_button].hWnd, BST_CHECKED);
/* set player name */
control_t * name_box = &data->controls[psc_name_box];
SetDlgItemText(data->dialog, name_box->id, NH_A2W(g.plname, wbuf, sizeof(wbuf)));
plselRandomize(data);
/* populate select boxes */
plselAdjustSelections(data->dialog);
/* set tab order */
control_t * control = &data->controls[psc_quit_button];
for(int i = psc_quit_button; i >= psc_name_box; i--, control++)
SetWindowPos(control->hWnd, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
do_player_selector_layout(data);
center_dialog(data->dialog);
}
INT_PTR CALLBACK INT_PTR CALLBACK
PlayerSelectorDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) PlayerSelectorDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{ {
struct plsel_data *data; plsel_data_t *data;
RECT main_rt, dlg_rt;
SIZE dlg_sz;
switch (message) { switch (message) {
case WM_INITDIALOG: case WM_INITDIALOG:
data = (struct plsel_data *) lParam;
SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) data);
/* center dialog in the main window */ data = (plsel_data_t *) lParam;
GetWindowRect(GetNHApp()->hMainWnd, &main_rt); data->dialog = hWnd;
GetWindowRect(hWnd, &dlg_rt);
dlg_sz.cx = dlg_rt.right - dlg_rt.left;
dlg_sz.cy = dlg_rt.bottom - dlg_rt.top;
dlg_rt.left = (main_rt.left + main_rt.right - dlg_sz.cx) / 2; plselInitDialog(data);
dlg_rt.right = dlg_rt.left + dlg_sz.cx;
dlg_rt.top = (main_rt.top + main_rt.bottom - dlg_sz.cy) / 2;
dlg_rt.bottom = dlg_rt.top + dlg_sz.cy;
MoveWindow(hWnd, (main_rt.left + main_rt.right - dlg_sz.cx) / 2,
(main_rt.top + main_rt.bottom - dlg_sz.cy) / 2, dlg_sz.cx,
dlg_sz.cy, TRUE);
/* init dialog */
plselInitDialog(hWnd);
/* tell windows to set the focus */ /* tell windows to set the focus */
return TRUE; return TRUE;
break;
case WM_DRAWITEM: case WM_DRAWITEM:
if (wParam == IDC_PLSEL_ROLE_LIST || wParam == IDC_PLSEL_RACE_LIST) if (wParam == IDC_PLSEL_ROLE_LIST || wParam == IDC_PLSEL_RACE_LIST)
@@ -367,20 +691,23 @@ PlayerSelectorDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
data = (struct plsel_data *) GetWindowLongPtr(hWnd, GWLP_USERDATA); data = (struct plsel_data *) GetWindowLongPtr(hWnd, GWLP_USERDATA);
control_t * role_control = &data->controls[psc_role_list];
control_t * race_control = &data->controls[psc_race_list];
switch (nmhdr->code) { switch (nmhdr->code) {
case LVN_KEYDOWN: case LVN_KEYDOWN:
{ {
LPNMLVKEYDOWN lpnmkeydown = (LPNMLVKEYDOWN) lParam; LPNMLVKEYDOWN lpnmkeydown = (LPNMLVKEYDOWN) lParam;
if (lpnmkeydown->wVKey == ' ') { if (lpnmkeydown->wVKey == ' ') {
if (control == data->control_role) { if (control == role_control->hWnd) {
int i = ListView_GetNextItem(data->control_role, -1, LVNI_FOCUSED); int i = ListView_GetNextItem(control, -1, LVNI_FOCUSED);
assert(i == -1 || ListView_GetNextItem(data->control_role, i, LVNI_FOCUSED) == -1); assert(i == -1 || ListView_GetNextItem(control, i, LVNI_FOCUSED) == -1);
flags.initrole = i; flags.initrole = i;
plselAdjustSelections(hWnd); plselAdjustSelections(hWnd);
} else if (control == data->control_race) { } else if (control == race_control->hWnd) {
int i = ListView_GetNextItem(data->control_race, -1, LVNI_FOCUSED); int i = ListView_GetNextItem(control, -1, LVNI_FOCUSED);
assert(i == -1 || ListView_GetNextItem(data->control_race, i, LVNI_FOCUSED) == -1); assert(i == -1 || ListView_GetNextItem(control, i, LVNI_FOCUSED) == -1);
if (ok_race(flags.initrole, i, ROLE_RANDOM, ROLE_RANDOM)) { if (ok_race(flags.initrole, i, ROLE_RANDOM, ROLE_RANDOM)) {
flags.initrace = i; flags.initrace = i;
plselAdjustSelections(hWnd); plselAdjustSelections(hWnd);
@@ -395,10 +722,10 @@ PlayerSelectorDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
int i = lpnmitem->iItem; int i = lpnmitem->iItem;
if (i == -1) if (i == -1)
return FALSE; return FALSE;
if (control == data->control_role) { if (control == role_control->hWnd) {
flags.initrole = i; flags.initrole = i;
plselAdjustSelections(hWnd); plselAdjustSelections(hWnd);
} else if(control == data->control_race) { } else if(control == race_control->hWnd) {
if (ok_race(flags.initrole, i, ROLE_RANDOM, ROLE_RANDOM)) { if (ok_race(flags.initrole, i, ROLE_RANDOM, ROLE_RANDOM)) {
flags.initrace = i; flags.initrace = i;
plselAdjustSelections(hWnd); plselAdjustSelections(hWnd);
@@ -408,12 +735,12 @@ PlayerSelectorDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
break; break;
case NM_KILLFOCUS: case NM_KILLFOCUS:
{ {
if (data->focus == data->control_race) { if (data->focus == race_control->hWnd) {
data->focus = NULL; data->focus = NULL;
ListView_RedrawItems(data->control_race, 0, data->race_count - 1); ListView_RedrawItems(race_control->hWnd, 0, data->race_count - 1);
} else if (data->focus == data->control_role) { } else if (data->focus == role_control->hWnd) {
data->focus = NULL; data->focus = NULL;
ListView_RedrawItems(data->control_role, 0, data->role_count - 1); ListView_RedrawItems(role_control->hWnd, 0, data->role_count - 1);
} }
} }
break; break;
@@ -421,11 +748,11 @@ PlayerSelectorDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{ {
data->focus = control; data->focus = control;
if (control == data->control_race) { if (control == race_control->hWnd) {
data->focus = data->control_race; data->focus = control;
plselAdjustSelections(hWnd); plselAdjustSelections(hWnd);
} else if (control == data->control_role) { } else if (control == role_control->hWnd) {
data->focus = data->control_role; data->focus = control;
plselAdjustSelections(hWnd); plselAdjustSelections(hWnd);
} }
} }
@@ -478,109 +805,29 @@ PlayerSelectorDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
} }
break; break;
case WM_DPICHANGED:
{
data = (struct plsel_data *) GetWindowLongPtr(hWnd, GWLP_USERDATA);
do_player_selector_layout(data);
InvalidateRect(hWnd, NULL, TRUE);
} break;
} }
return FALSE; return FALSE;
} }
/* initialize player selector dialog */
void
plselInitDialog(HWND hWnd)
{
struct plsel_data * data = (plsel_data_t *) GetWindowLongPtr(hWnd, GWLP_USERDATA);
TCHAR wbuf[BUFSZ];
LVCOLUMN lvcol;
data->control_role = GetDlgItem(hWnd, IDC_PLSEL_ROLE_LIST);
data->control_race = GetDlgItem(hWnd, IDC_PLSEL_RACE_LIST);
ZeroMemory(&lvcol, sizeof(lvcol));
lvcol.mask = LVCF_WIDTH;
lvcol.cx = GetSystemMetrics(SM_CXFULLSCREEN);
/* build role list */
ListView_InsertColumn(data->control_role, 0, &lvcol);
data->role_count = 0;
for (int i = 0; roles[i].name.m; i++) {
LVITEM lvitem;
ZeroMemory(&lvitem, sizeof(lvitem));
lvitem.mask = LVIF_STATE | LVIF_TEXT;
lvitem.iItem = i;
lvitem.iSubItem = 0;
lvitem.state = 0;
lvitem.stateMask = LVIS_FOCUSED;
if (flags.female && roles[i].name.f)
lvitem.pszText = NH_A2W(roles[i].name.f, wbuf, BUFSZ);
else
lvitem.pszText = NH_A2W(roles[i].name.m, wbuf, BUFSZ);
if (ListView_InsertItem(data->control_role, &lvitem) == -1) {
panic("cannot insert menu item");
}
data->role_count++;
}
/* build race list */
ListView_InsertColumn(data->control_race, 0, &lvcol);
data->race_count = 0;
for (int i = 0; races[i].noun; i++) {
LVITEM lvitem;
ZeroMemory(&lvitem, sizeof(lvitem));
lvitem.mask = LVIF_STATE | LVIF_TEXT;
lvitem.iItem = i;
lvitem.iSubItem = 0;
lvitem.state = 0;
lvitem.stateMask = LVIS_FOCUSED;
lvitem.pszText = NH_A2W(races[i].noun, wbuf, BUFSZ);
if (ListView_InsertItem(data->control_race, &lvitem) == -1) {
panic("cannot insert menu item");
}
data->race_count++;
}
for(int i = 0; i < ROLE_GENDERS; i++)
data->control_genders[i] = GetDlgItem(hWnd, IDC_PLSEL_GENDER_MALE + i);
for(int i = 0; i < ROLE_ALIGNS; i++)
data->control_aligns[i] = GetDlgItem(hWnd, IDC_PLSEL_ALIGN_LAWFUL + i);
/* set gender radio button state */
for (int i = 0; i < ROLE_GENDERS; i++)
Button_Enable(data->control_genders[i], TRUE);
Button_SetCheck(data->control_genders[0], BST_CHECKED);
/* set alignment radio button state */
for (int i = 0; i < ROLE_ALIGNS; i++)
Button_Enable(data->control_aligns[i], TRUE);
Button_SetCheck(data->control_aligns[0], BST_CHECKED);
/* set player name */
SetDlgItemText(hWnd, IDC_PLSEL_NAME, NH_A2W(g.plname, wbuf, sizeof(wbuf)));
plselRandomize(data);
/* populate select boxes */
plselAdjustSelections(hWnd);
/* set tab order */
SetWindowPos(GetDlgItem(hWnd, IDCANCEL), NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
SetWindowPos(GetDlgItem(hWnd, IDC_PLSEL_RANDOM), NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
SetWindowPos(GetDlgItem(hWnd, IDOK), NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
for(int i = ROLE_GENDERS - 1; i >= 0; i--)
SetWindowPos(data->control_genders[i], NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
for(int i = ROLE_ALIGNS - 1; i >= 0; i--)
SetWindowPos(data->control_aligns[i], NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
SetWindowPos(data->control_race, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
SetWindowPos(data->control_role, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
}
void void
plselAdjustSelections(HWND hWnd) plselAdjustSelections(HWND hWnd)
{ {
struct plsel_data * data = (plsel_data_t *) GetWindowLongPtr(hWnd, GWLP_USERDATA); struct plsel_data * data = (plsel_data_t *) GetWindowLongPtr(hWnd, GWLP_USERDATA);
control_t * role_control = &data->controls[psc_role_list];
control_t * race_control = &data->controls[psc_race_list];
if (!ok_race(flags.initrole, flags.initrace, ROLE_RANDOM, ROLE_RANDOM)) if (!ok_race(flags.initrole, flags.initrace, ROLE_RANDOM, ROLE_RANDOM))
flags.initrace = pick_race(flags.initrole, ROLE_RANDOM, ROLE_RANDOM, ROLE_RANDOM); flags.initrace = pick_race(flags.initrole, ROLE_RANDOM, ROLE_RANDOM, ROLE_RANDOM);
@@ -590,29 +837,31 @@ plselAdjustSelections(HWND hWnd)
if (!ok_align(flags.initrole, flags.initrace, flags.initgend, flags.initalign)) if (!ok_align(flags.initrole, flags.initrace, flags.initgend, flags.initalign))
flags.initalign = pick_align(flags.initrole, flags.initrace, flags.initgend , ROLE_RANDOM); flags.initalign = pick_align(flags.initrole, flags.initrace, flags.initgend , ROLE_RANDOM);
ListView_RedrawItems(data->control_role, 0, data->role_count - 1); ListView_RedrawItems(role_control->hWnd, 0, data->role_count - 1);
ListView_RedrawItems(data->control_race, 0, data->race_count - 1); ListView_RedrawItems(race_control->hWnd, 0, data->race_count - 1);
/* set gender radio button state */ /* set gender radio button state */
for (int i = 0; i < ROLE_GENDERS; i++) { for (int i = 0; i < ROLE_GENDERS; i++) {
HWND button = data->controls[psc_male_button+i].hWnd;
BOOL enable = ok_gend(flags.initrole, flags.initrace, i, flags.initalign); BOOL enable = ok_gend(flags.initrole, flags.initrace, i, flags.initalign);
Button_Enable(data->control_genders[i], enable); Button_Enable(button, enable);
LRESULT state = Button_GetCheck(data->control_genders[i]); LRESULT state = Button_GetCheck(button);
if (state == BST_CHECKED && flags.initgend != i) if (state == BST_CHECKED && flags.initgend != i)
Button_SetCheck(data->control_genders[i], BST_UNCHECKED); Button_SetCheck(button, BST_UNCHECKED);
if (state == BST_UNCHECKED && flags.initgend == i) if (state == BST_UNCHECKED && flags.initgend == i)
Button_SetCheck(data->control_genders[i], BST_CHECKED); Button_SetCheck(button, BST_CHECKED);
} }
/* set alignment radio button state */ /* set alignment radio button state */
for (int i = 0; i < ROLE_ALIGNS; i++) { for (int i = 0; i < ROLE_ALIGNS; i++) {
HWND button = data->controls[psc_lawful_button+i].hWnd;
BOOL enable = ok_align(flags.initrole, flags.initrace, flags.initgend, i); BOOL enable = ok_align(flags.initrole, flags.initrace, flags.initgend, i);
Button_Enable(data->control_aligns[i], enable); Button_Enable(button, enable);
LRESULT state = Button_GetCheck(data->control_aligns[i]); LRESULT state = Button_GetCheck(button);
if (state == BST_CHECKED && flags.initalign != i) if (state == BST_CHECKED && flags.initalign != i)
Button_SetCheck(data->control_aligns[i], BST_UNCHECKED); Button_SetCheck(button, BST_UNCHECKED);
if (state == BST_UNCHECKED && flags.initalign == i) if (state == BST_UNCHECKED && flags.initalign == i)
Button_SetCheck(data->control_aligns[i], BST_CHECKED); Button_SetCheck(button, BST_CHECKED);
} }
} }
+6 -1
View File
@@ -1,6 +1,6 @@
//{{NO_DEPENDENCIES}} //{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file. // Microsoft Visual C++ generated include file.
// Used by winhack.rc // Used by NetHackW.rc
// //
#define IDC_MYICON 2 #define IDC_MYICON 2
#define IDD_WINHACK_DIALOG 102 #define IDD_WINHACK_DIALOG 102
@@ -114,6 +114,11 @@
#define IDC_PLSEL_ALIGN_CHAOTIC 1336 #define IDC_PLSEL_ALIGN_CHAOTIC 1336
#define IDC_PLSEL_GENDER_MALE 1337 #define IDC_PLSEL_GENDER_MALE 1337
#define IDC_PLSEL_GENDER_FEMALE 1338 #define IDC_PLSEL_GENDER_FEMALE 1338
#define IDC_PLSEL_NAME_GROUP 1339
#define IDC_PLSEL_ROLE_GROUP 1340
#define IDC_PLSEL_RACE_GROUP 1341
#define IDC_PLSEL_ALIGNMENT_GROUP 1342
#define IDC_PLSEL_GENDER_GROUP 1343
#define IDM_SAVE 32771 #define IDM_SAVE 32771
#define IDM_HELP_LONG 32772 #define IDM_HELP_LONG 32772
#define IDM_HELP_COMMANDS 32773 #define IDM_HELP_COMMANDS 32773
+1 -1
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Package xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10" xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest" xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10" xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities" IgnorableNamespaces="uap mp rescap"> <Package xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10" xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest" xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10" xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities" IgnorableNamespaces="uap mp rescap">
<Identity Name="30485NetHackDevTeam.NetHack3.6" Publisher="CN=8BDC628A-FAAA-4EBA-8B5B-EB61BA93BA1F" Version="363.0.19.0" /> <Identity Name="30485NetHackDevTeam.NetHack3.6" Publisher="CN=8BDC628A-FAAA-4EBA-8B5B-EB61BA93BA1F" Version="363.0.20.0" />
<Properties> <Properties>
<DisplayName>NetHack 3.6</DisplayName> <DisplayName>NetHack 3.6</DisplayName>
<PublisherDisplayName>NetHack DevTeam</PublisherDisplayName> <PublisherDisplayName>NetHack DevTeam</PublisherDisplayName>
+12
View File
@@ -206,6 +206,18 @@
<ClInclude Include="$(WinWin32Dir)mhstatus.h" /> <ClInclude Include="$(WinWin32Dir)mhstatus.h" />
<ClInclude Include="$(WinWin32Dir)mhtext.h" /> <ClInclude Include="$(WinWin32Dir)mhtext.h" />
<ClInclude Include="$(WinWin32Dir)winMS.h" /> <ClInclude Include="$(WinWin32Dir)winMS.h" />
<ClInclude Include="..\resource.h" />
</ItemGroup>
<ItemGroup>
<Image Include="..\mnsel.bmp" />
<Image Include="..\mnselcnt.bmp" />
<Image Include="..\mnunsel.bmp" />
<Image Include="..\NETHACK.ICO" />
<Image Include="..\petmark.bmp" />
<Image Include="..\pilemark.bmp" />
<Image Include="..\rip.bmp" />
<Image Include="..\splash.bmp" />
<Image Include="..\tiles.bmp" />
</ItemGroup> </ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<Target Name="AfterBuild"> <Target Name="AfterBuild">