Merge branch 'NetHack-3.6.0'

This commit is contained in:
keni
2016-06-21 10:29:14 -04:00
84 changed files with 3167 additions and 1281 deletions
+7 -7
View File
@@ -12,13 +12,13 @@ dat:
(files for all versions)
Arch.des Barb.des Caveman.des Healer.des Knight.des
Monk.des Priest.des Ranger.des Rogue.des Samurai.des
Tourist.des Valkyrie.des Wizard.des bigroom.des castle.des
cmdhelp data.base dungeon.def endgame.des gehennom.des
help hh history knox.des license
medusa.des mines.des opthelp oracle.des oracles.txt
quest.txt rumors.fal rumors.tru sokoban.des symbols
tower.des wizhelp yendor.des tribute bogusmon.txt
engrave.txt epitaph.txt
Tourist.des Valkyrie.des Wizard.des bigroom.des bogusmon.txt
castle.des cmdhelp data.base dungeon.def endgame.des
engrave.txt epitaph.txt gehennom.des help hh
history keyhelp knox.des license medusa.des
mines.des opthelp oracle.des oracles.txt quest.txt
rumors.fal rumors.tru sokoban.des symbols tower.des
tribute wizhelp yendor.des
doc:
(files for all versions)
+224 -127
View File
@@ -1,127 +1,224 @@
^ Show the type of a trap
^[ Cancel command
^A Redo the previous command
^C Quit the game
^D Kick something (usually a door, chest, or box)
^E Search a room (available in debug mode only)
^F Map the level (available in debug mode only)
^G Create a monster (available in debug mode only)
^I Identify all items (available in debug mode only)
^O Show location of special levels (available in debug mode only)
^P Toggle through previously displayed game messages
^R Redraw screen
^T Teleport around level
^V Teleport between levels (available in debug mode only)
^W Wish (available in debug mode only)
^X Show your attributes (shows more in debug or explore mode)
^Z Suspend game (only if defined)
a Apply (use) a tool
A Remove all armor
b Go southwest 1 space
B Go southwest until you are on top of something
^B Go southwest until you are near something
c Close a door
C Call (name) a monster, an individual object, or a type of object
d Drop an item
D Drop specific item types
e Eat something
E Engrave writing on the floor
f Fire ammunition from quiver
F Followed by direction, fight a monster (even if you don't sense it)
g Followed by direction, move until you are near something
G Followed by direction, same as control-direction
h Go west 1 space (if number_pad is on, display help message)
H Go west until you are on top of something
^H Go west until you are near something
i Show your inventory
I Inventory specific item types
j Go south 1 space (or if number_pad is on, jump to another location)
J Go south until you are on top of something
^J Go south until you are near something
k Go north 1 space (or if number_pad is on, kick something)
K Go north until you are on top of something
^K Go north until you are near something
l Go east 1 space (or if number_pad is on, loot a box on the floor)
L Go east until you are on top of something
^L Go east until you are near something
m Followed by direction, move without picking anything up or fighting
M Followed by direction, move a distance without picking anything up
n Go southeast 1 space
N Go southeast until you are on something (if number_pad is on, name)
^N Go southeast until you are near something
o Open a door
O Show option settings, possibly change them
p Pay your shopping bill
P Put on an accessory (ring, amulet, etc)
q Quaff (drink) something (potion, water, etc)
Q Select ammunition for quiver
r Read a scroll or spellbook
R Remove an accessory (ring, amulet, etc)
s Search for traps and secret doors
S Save the game
t Throw something
T Take off one piece of armor
u Go northeast 1 space (or if number_pad is on, untrap something)
U Go northeast until you are on top of something
^U Go northeast until you are near something
v Show version
V Show long version and game history
w Wield (put in use) a weapon
W Wear a piece of armor
x Swap wielded and secondary weapons
X Toggle two-weapon combat
y Go northwest 1 space
Y Go northwest until you are on top of something
^Y Go northwest until you are near something
z Zap a wand
Z Zap (cast) a spell
< Go up a staircase
> Go down a staircase
/ Show what type of thing a symbol corresponds to
? Give a help message
& Tell what a command does
! Do a shell escape (only if defined)
\ Show what object types have been discovered
` Show discovered types for one class of objects
_ Travel via a shortest-path algorithm to a point on the map
. Rest one move while doing nothing
Rest one move while doing nothing (if rest_on_space option is on)
: Look at what is on the floor
; Show what type of thing a map symbol on the level corresponds to
, Pick up things at the current location
@ Toggle the pickup option on/off
) Show the weapon currently wielded
[ Show the armor currently worn
= Show the ring(s) currently worn
" Show the amulet currently worn
( Show the tools currently in use
* Show all equipment in use (combination of the ),[,=,",( commands)
$ Count your gold
+ List known spells
# Perform an extended command
M-? Display extended command help (if the platform allows this)
M-2 Toggle two-weapon combat (unless number_pad is enabled)
M-a Adjust inventory letters
M-A Annotate: supply a name for the current dungeon level
M-c Talk to someone
M-C Conduct: list voluntary challenges you have maintained
M-d Dip an object into something
M-e Advance or check weapons skills
M-f Force a lock
M-i Invoke an object's special powers
M-j Jump to another location
M-l Loot a box on the floor
M-m Use a monster's special ability
M-n Name a monster, an individual object, or a type of object
M-o Offer a sacrifice to the gods
M-O Overview: show a summary of the explored dungeon
M-p Pray to the gods for help
M-q Quit
M-r Rub a lamp
M-R Ride: mount or dismount a saddled steed
M-s Sit down
M-t Turn undead
M-T Tip: empty a container
M-u Untrap something (trap, door, or chest)
M-v Print compile time options for this version of NetHack
M-w Wipe off your face
&# cmdhelp
& Tell what command a keystroke invokes
^ Show the type of an adjacent trap
^[ Cancel command (same as ESCape key)
&? debug
^E Search for nearby traps, secret doors, and unseen monsters
^F Map level; reveals traps and secret corridors but not secret doors
^G Create a monster by name or class
^I View inventory with all items identified
^O List special level locations
^V Teleport between levels
^W Wish for something
&: #!debug
^E unavailable debugging command
^F unavailable debugging command
^G unavailable debugging command
^I unavailable debugging command
^O Shortcut for '#overview': list interesting levels you have visited
^V unavailable debugging command
^W unavailable debugging command
&. #?debug
&? number_pad=0,-1
b Go southwest 1 space
B Go southwest until you are on top of something
h Go west 1 space
H Go west until you are on top of something
j Go south 1 space
J Go south until you are on top of something
k Go north 1 space
K Go north until you are on top of something
l Go east 1 space
L Go east until you are on top of something
n Go southeast 1 space
N Go southeast until you are on something
u Go northeast 1 space
U Go northeast until you are on top of something
&# y,Y handled below
&: #number_pad=1,2,3,4
h Help: synonym for '?'
j Jump: shortcut for '#jump'
k Kick: synonym for '^D'
l Loot: shortcut for '#loot'
n Start a count; continue with digit(s)
N Name: shortcut for '#name'
u Untrap: shortcut for '#untrap'
&. #0,-1 vs 1,2,3,4
a Apply (use) a tool or break a wand
A Remove all armor and/or all accessories and/or unwield weapons
^A Redo the previous command
^B Go southwest until you are near something
c Close a door
C Call (name) a monster, an individual object, or a type of object
^C Interrupt: quit the game
d Drop an item
D Drop specific item types
^D Kick something (usually a door, chest, or box)
e Eat something
E Engrave writing on the floor
f Fire ammunition from quiver
F Followed by direction, fight a monster (even if you don't sense it)
g Followed by direction, move until you are near something
G Followed by direction, same as control-direction
^H Go west until you are near something
i Show your inventory
I Inventory specific item types
^J Go south until you are near something
^K Go north until you are near something
^L Go east until you are near something
m Followed by direction, move without picking anything up or fighting
M Followed by direction, move a distance without picking anything up
^N Go southeast until you are near something
o Open a door
O Show option settings, possibly change them
p Pay your shopping bill
P Put on an accessory (ring, amulet, etc; will work for armor too)
^P Toggle through previously displayed game messages
q Quaff (drink) something (potion, water, etc)
Q Select ammunition for quiver (use '#quit' to quit)
r Read a scroll or spellbook
R Remove an accessory (ring, amulet, etc; will work for armor too)
^R Redraw screen
s Search all immediately adjacent locations for traps and secret doors
S Save the game (and exit; there is no "save and keep going")
t Throw something (choose an item, then a direction--not a target)
T Take off one piece of armor (will work for accessories too)
^T Teleport around level
^U Go northeast until you are near something
v Show version ('#version' shows more information)
V Show history of game's development
w Wield a weapon (for dual weapons: 'w' secondary, 'x', 'w' primary, 'X')
W Wear a piece of armor (will work for accessories too)
x Swap wielded and secondary weapons
X Toggle two-weapon combat
^X Show your attributes (shows more in debug or explore mode)
&? number_pad=0,1,2,3,4
&? number_pad=0
y Go northwest 1 space
Y Go northwest until you are on top of something
&.
^Y Go northwest until you are near something
z Zap a wand
Z Zap (cast) a spell
&? suspend
^Z Suspend game; 'fg' (foreground) to resume
&:
^Z unavailable command: suspend
&.
&: number_pad=-1
y Zap a wand
Y Zap (cast) a spell
&? suspend
^Y Suspend game; 'fg' (foreground) to resume
&:
^Y unavailable command: suspend
&.
z Go northwest 1 space
Z Go northwest until you are on top of something
^Z Go northwest until you are near something
&. #0,1..4 vs -1
< Go up a staircase
> Go down a staircase
/ Show what type of thing a symbol corresponds to
? Give a help message
&? shell
! Do a shell escape; 'exit' shell to come back
&:
! unavailable command: shell
&.
\ Show what object types have been discovered
` Show discovered types for one class of objects
_ Travel via a shortest-path algorithm to a point on the map
. Rest one move while doing nothing
&? rest_on_space
Rest one move while doing nothing
&.
: Look at what is on the floor
; Show what type of thing a map symbol on the level corresponds to
, Pick up things at the current location
@ Toggle the pickup option on/off
) Show the weapon(s) currently wielded or readied
[ Show the armor currently worn
= Show the ring(s) currently worn
" Show the amulet currently worn
( Show the tools currently in use
* Show all equipment in use (combination of the ),[,=,",( commands)
$ Count your gold
+ List known spells
# Perform an extended command (use '#?' to list choices)
&# number_pad:
&# -1 = numpad off, swap y with z (including Y with Z, ^Y with ^Z, M-y &c)
&# 0 = numpad off (default)
&# 1 = numpad on, normal keypad layout, '5'->'g'
&# 2 = numpad on, normal keypad layout, '5'->'G'
&# 3 = numpad on, phone keypad layout, '5'->'g'
&# 4 = numpad on, phone keypad layout, '5'->'G'
&? number_pad = 1,2,3,4
0 Show inventory
4 Move west
6 Move east
- 'F' prefix; force fight
&: #-1,0
0 Continue a count
4 Start or continue a count
6 Start or continue a count
&. #1,2,3,4 vs -1,0
&? number_pad=1,2
7 Move northwest
8 Move north
9 Move northeast
1 Move southwest
2 Move south
3 Move southeast
&: number_pad=3,4
1 Move northwest
2 Move north
3 Move northeast
7 Move southwest
8 Move south
9 Move southeast
&: #-1,0
1 Start or continue a count
2 Start or continue a count
3 Start or continue a count
7 Start or continue a count
8 Start or continue a count
9 Start or continue a count
&. #1,2 vs 3,4 vs -1,0
&? number_pad=1,3
5 'g' movement prefix
M-5 'G' movement prefix
&: number_pad=2,4
5 'G' movement prefix
M-5 'g' movement prefix
M-0 Inventory specific item types
&: #-1,0
5 Start or continue a count
M-2 Toggle two-weapon combat
&. #1,3 vs 2,4 vs -1,0
M-? Display extended command help (if the platform allows this)
M-a Adjust inventory letters
M-A Annotate: supply a name for the current dungeon level
M-c Chat: talk to an adjacent creature
M-C Conduct: list voluntary challenges you have maintained
M-d Dip an object into something
M-e Enhance: check weapons skills, advance them if eligible
M-f Force a lock
M-i Invoke an object's special powers
M-j Jump to a nearby location
M-l Loot a box on the floor
M-m When polymorphed, use a monster's special ability
M-n Name a monster, an individual object, or a type of object
M-N Name a monster, an individual object, or a type of object
M-o Offer a sacrifice to the gods
M-O Overview: show a summary of the explored dungeon
M-p Pray to the gods for help
M-q Quit (exit without saving)
M-r Rub a lamp or a touchstone
M-R Ride: mount or dismount a saddled steed
M-s Sit down
M-t Turn undead
M-T Tip: empty a container
M-u Untrap something (trap, door, or chest)
M-v Print compile time options for this version of NetHack
M-w Wipe off your face
+3 -2
View File
@@ -36,6 +36,7 @@ V history display game history
^R redraw redraw the screen
^P prevmsg repeat previous message (subsequent ^P's repeat earlier ones)
# introduces an extended command (#? for a list of them)
& what-does describe the command a keystroke invokes
Game commands:
^D kick kick (a door, or something else)
@@ -60,7 +61,7 @@ o open open a door
p pay pay your bill (in a shop)
P puton put on an accessory (ring, amulet, etc)
q quaff drink something (potion, water, etc)
Q quiver select ammunition for quiver
Q quiver select ammunition for quiver (use '#quit' to quit)
r read read a scroll or spellbook
R remove remove an accessory (ring, amulet, etc)
s search search for secret doors, hidden traps and monsters
@@ -69,7 +70,7 @@ T takeoff take off some armor
w wield wield a weapon (w- wield nothing)
W wear put on some armor
x xchange swap wielded and secondary weapons
X twoweapon toggle two-weapon combat
X twoweapon toggle two-weapon combat (use '#explore' for explore mode)
z zap zap a wand (use y instead of z if number_pad is -1)
Z Zap cast a spell (use Y instead of Z if number_pad is -1)
< up go up the stairs
+58
View File
@@ -0,0 +1,58 @@
Depending upon hardware or operating system or NetHack's interface,
some keystrokes may be off-limits.
For example, ^S and ^Q are often used for XON/XOFF flow-control,
meaning that ^S suspends output and subsequent ^Q resumes suspended
output. When that it the case, neither of those characters will
reach NetHack when it is waiting for a command keystroke. So they
aren't used as commands, but 'whatdoes' might not be able to tell
you that if they don't get passed through to NetHack.
^M or <return> or <enter> is likely to be transformed into ^J or
<linefeed> or 'newline' before being passed to NetHack for handling.
So it isn't used as a command, and 'whatdoes' might seem as if it
is reporting the wrong character but will be operating correctly if
it describes ^J when you type ^M.
A NUL character, typed as ^<space> on some keyboards, ^@ on others,
and maybe not typeable at all on yet others. It is not used as a
command, and will be converted into ESC before reaching 'whatdoes'.
Unlike ^M, this transformation is performed by NetHack itself.
But like ^M, if you type NUL and get feedback about ESC, the
situation is expected.
ESC itself is a synonym for ^[, and is another source of oddity.
Various function keys, including cursor arrow keys, may transmit
an "escape sequence" of ESC + [ + other stuff, confusing NetHack
as to what command was intended since the ESC will be processed
and then whatever follows will seem to NetHack like--and be used
as--something typed by the user. (If you press a function key and
a menu of the armor your hero is wearing appears, what happened
was that an escape sequence was sent to NetHack, its ESC aborted
any pending key operation, its '[' was then treated as a command
to show worn armor, and the "other stuff" probably got silently
discarded as invalid choices while you dismissed the menu.)
If you have NetHack's 'altmeta' option enabled, meaning that the
<alt> or <option> key, when used as shift while typing some other
character, transmits ESC and then the other character so NetHack
should treat that other character as a meta-character, then ESC
takes on added potential for confusion. Implicit in the handling
of a two character sequence ESC + something is the fact that when
NetHack sees ESC, it needs to wait for another character before
it can decide what to do. So if you type ESC manually, you'll
need to type it a second time or NetHack will sit there waiting.
(It will then be treated as if you typed ESC rather than M-ESC.)
On some systems, typing ^\ will send a QUIT signal to the current
process, probably killing it and possibly causing it to save a
core dump. It is not used for any NetHack command, so don't type
that character.
One last note: characters shown as ^x mean that you should hold
down the <control> or <ctrl> key as a shift and then type 'x'.
Control characters are all implicitly uppercase, but you don't
need to press the shift key while typing them. The opposite is
true for meta-characters: they can be either case, so you need
to use shift as well as <meta> or <alt> to generate an uppercase
letter meta-character.
+13 -9
View File
@@ -12,13 +12,13 @@ MAP
----------------------------------------------------------------------------
| |........|...............................................................|
| |........|.................................................------------..|
| -------+--.................................................|..........|..|
| |........}}}}}}}....................}}}}}}}..........|..........|..|
| |........}-----}....................}-----}..........--+--+--...|..|
| ---........}|...|}}}}}}}}}}}}}}}}}}}}}}|...|}.................|...|..|
| |..........}---S------------------------S---}.................|...|..|
| |..........}}}|...............|..........|}}}.................+...|..|
| -------..........}|...............S..........|}...................|...|..|
| --S----S--.................................................|..........|..|
| # |........}}}}}}}....................}}}}}}}..........|..........|..|
| # |........}-----}....................}-----}..........--+--+--...|..|
| # ---........}|...|}}}}}}}}}}}}}}}}}}}}}}|...|}.................|...|..|
| # |..........}---S------------------------S---}.................|...|..|
| # |..........}}}|...............|..........|}}}.................+...|..|
| --S----..........}|...............S..........|}...................|...|..|
| |.....|..........}|...............|......\...S}...................|...|..|
| |.....+........}}}|...............|..........|}}}.................+...|..|
| |.....|........}---S------------------------S---}.................|...|..|
@@ -35,8 +35,8 @@ NON_DIGGABLE:(00,00,75,19)
# Portal arrival point
BRANCH:(08,16,08,16),(0,0,0,0)
# accessible via ^V in wizard mode; arrive near the portal
TELEPORT_REGION:(06,16,09,17),(0,0,0,0),up
TELEPORT_REGION:(06,16,09,17),(0,0,0,0),down
TELEPORT_REGION:(06,15,09,16),(0,0,0,0),up
TELEPORT_REGION:(06,15,09,16),(0,0,0,0),down
# Throne room, with Croesus on the throne
REGION:(37,08,46,11),lit,"throne"
# 50% chance each to move throne and/or fort's entry secret door up one row
@@ -82,6 +82,8 @@ DOOR:locked,(08,11)
DOOR:open,(68,11)
DOOR:closed,(63,14)
DOOR:closed,(66,14)
DOOR:closed,(04,03)
DOOR:closed,(04,09)
# Soldiers guarding the fort
MONSTER:('@',"soldier"),(12,14)
MONSTER:('@',"soldier"),(12,13)
@@ -100,6 +102,8 @@ MONSTER:('@',"soldier"),(54,13)
MONSTER:('@',"soldier"),(57,10)
MONSTER:('@',"soldier"),(57,09)
MONSTER:('@',"lieutenant"),(15,08)
# Possible source of a boulder
MONSTER:('H',"stone giant"),(03,01)
# Four dragons guarding each side
MONSTER:'D',(18,09)
MONSTER:'D',(49,10)
+18 -26
View File
@@ -194,20 +194,6 @@ start: RogueEpyx
Restrictions: rogue
Handling: IBM
Color: Yes
S_weapon: \x18 # up arrow
S_armor: \x0a # Vert rect with o
S_ring: \x09 # circle with arrow
S_amulet: \x0c # "female" symbol
S_food: \x05 # club (as in cards)
S_potion: \xad # upside down '!'
S_scroll: \x0e # musical note
S_wand: \xe7 # greek tau
S_coin: \x0f # yes it's the same as gems
S_gem: \x0f # fancy '*'
S_rock: \x60
S_ball: \x30
S_chain: \x5f
S_venom: \x2e
S_vwall: \xba # all walls now use
S_hwall: \xcd # double line graphics
S_tlcorn: \xc9
@@ -249,18 +235,24 @@ start: RogueEpyx
S_magic_trap: \x04
S_anti_magic_trap: \x04
S_polymorph_trap: \x04
S_weapon: \x18
S_armor: \x5b
S_ring: \x3d
S_amulet: \xc
S_tool: \x28
S_food: \x5
S_potion: \xad
S_scroll: \xe
S_book: \x2b
S_wand: \xe7
S_coin: \xf
S_gem: \xf
S_weapon: \x18 # up arrow
# ^J S_armor: \x0a # Vert rect with o
S_armor: \x5b # default: '['
# ^I S_ring: \x09 # circle with arrow
S_ring: \x3d # default: '='
S_amulet: \x0c # "female" symbol
S_tool: \x28 # default: '('
S_food: \x05 # club (as in cards)
S_potion: \xad # upside down '!'
S_scroll: \x0e # musical note
S_book: \x2b # default: '+'
S_wand: \xe7 # greek tau
S_coin: \x0f # yes it's the same as gems
S_gem: \x0f # fancy '*'
S_rock: \x60
S_ball: \x30
S_chain: \x5f
S_venom: \x2e
S_rock: \x60
S_ball: \x30
S_chain: \x5f
+7 -3
View File
@@ -1,13 +1,13 @@
Debug-Mode Quick Reference:
^E == detect secret doors and traps.
^F == do magic mapping.
^G == create monster.
^F == map level; reveals traps and secret corridors but not secret doors.
^G == create monster by name or class.
^I == identify items in pack.
^O == tell locations of special levels.
^T == do intra-level teleport.
^V == do trans-level teleport.
^W == make wish.
^W == make a wish for an item or a trap or a limited subset of terrain.
^X == show attributes including intrinsic attributes.
#levelchange == change experience level
@@ -19,5 +19,9 @@ Debug-Mode Quick Reference:
#stats == show memory statistics
#timeout == look at timeout queue
#vision == show vision array
#vanquished == disclose counts of dead monsters
#wizsmell == smell a monster
#wizintrinsic == set selected intrinsic timeouts
#wizrumorcheck == validate first and last rumor for true and false set
#wmode == show wall modes
+111 -43
View File
@@ -691,6 +691,14 @@ a further menu or prompt will appear once you've closed this menu.
The available options
are listed later in this Guidebook. Options are usually set before the
game rather than with the `O' command; see the section on options below.
.lp ^O
Show overview or show dungeon layout
.lp ""
In normal play and in explore mode, a shortcut for the ``#overview''
extended command to list interesting dungeon levels visited.
.lp ""
In debug mode, an extra command which lists the placement of all special
levels.
.lp p
Pay your shopping bill.
.lp P
@@ -1961,12 +1969,111 @@ Setting the options
.pg
Options may be set in a number of ways. Within the game, the `O'
command allows you to view all options and change most of them.
You can also set options automatically by placing them in the
NETHACKOPTIONS environment variable or in a configuration file.
You can also set options automatically by placing them in a configuration
file, or in the NETHACKOPTIONS environment variable.
Some versions of NetHack also have front-end programs that allow
you to set options before starting the game or a global configuration
for system administrators.
.hn 2
Using a configuration file
.pg
The default name of the configuration file varies on different
operating systems. On DOS and Windows, it is ``defaults.nh''
in the same folder as nethack.exe or nethackW.exe. On Unix, Linux
and Mac OS X it is ``.nethackrc'' in the user's home directory.
The file may not exist, but it is a normal ASCII text file and
can be created with any text editor.
.pg
Any line in the configuration file starting with `#' is treated as a comment.
Empty lines are ignored.
.pg
You can use different configuration statements in the file, some
of which can be used multiple times. In general, the statements are
written in capital letters, followed by an equals sign, followed by
settings particular to that statement. Here is a list of allowed statements:
.lp OPTIONS
There are two types of options, boolean and compound options.
Boolean options toggle a setting on or off, while compound options
take more diverse values.
Prefix a boolean option with `no' or `!' to turn it off.
For compound options, the option name and value are separated by a colon.
Some options are persistent, and apply only to new games.
You can specify multiple OPTIONS statements, and multiple options
in a single OPTIONS statement.
.pg
Example:
.sd
\fBOPTIONS=dogname:Fido\fP
\fBOPTIONS=!legacy,autopickup,pickup_types:$"=/!?+\fP
.ed
.lp HACKDIR
Default location of files NetHack needs. On Windows HACKDIR
defaults to the location of the NetHack.exe or NetHackw.exe file
so setting HACKDIR to override that is not usually necessary or recommended.
.lp LEVELDIR
The location that in-progress level files are stored. Defaults to HACKDIR,
must be writeable.
.lp SAVEDIR
The location where saved games are kept. Defaults to HACKDIR, must be
writeable.
.lp BONESDIR
The location that bones files are kept. Defaults to HACKDIR, must be
writeable.
.lp LOCKDIR
The location that file synchronization locks are stored. Defaults to
HACKDIR, must be writeable.
.lp TROUBLEDIR
The location that a record of game aborts and self-diagnosed game problems
is kept. Defaults to HACKDIR, must be writeable.
.lp AUTOPICKUP_EXCEPTION
Set exceptions to the
.op pickup_types
option. See the ``Configuring Autopickup Exceptions'' section.
.lp MSGTYPE
Change the way messages are shown in the top status line.
See the ``Configuring Message Types`` section.
.lp MENUCOLOR
Highlight menu lines with different colors.
See the ``Configuring Menu Colors`` section.
.lp SYMBOLS
Override one or more symbols in the symbols files.
See the ``Modifying NetHack Symbols'' section.
.pg
Example:
.sd
\fBSYMBOLS=S_boulder:0\fP
.ed
.lp WIZKIT
Wizard-mode extra items, in a text file containing item names,
one per line, up to a maximum of 128 lines. Each line is processed
by the function that handles wishing.
.pg
Example:
.sd
\fBWIZKIT=~/wizkit.txt\fP
.ed
.lp SOUNDDIR
Define the directory that contains the sound files.
See the ``Configuring User Sounds'' section.
.lp SOUND
Define a sound mapping. See the ``Configuring User Sounds'' section.
.pg
Here is a short example of config file contents:
.sd
\fB# Set your character's role, race, gender, and alignment.\fP
\fBOPTIONS=role:Valkyrie, race:Human, gender:female, align:lawful\fP
\fB# Turn on autopickup, and set automatically picked up object types\fP
\fBOPTIONS=autopickup,pickup_types:$"=/!?+\fP
\fB# Show colored text if possible\fP
\fBOPTIONS=color\fP
\fB# Show lit corridors differently\fP
\fBOPTIONS=lit_corridor\fP
\fB# No startup splash screen. Windows GUI only.\fP
\fBOPTIONS=!splash_screen\fP
.ed
.hn 2
Using the NETHACKOPTIONS environment variable
.pg
The NETHACKOPTIONS variable is a comma-separated list of initial
@@ -1989,48 +2096,9 @@ $ \fBNETHACKOPTIONS="autoquiver,!autopickup,name:Blue Meanie,fruit:papaya"\fP
$ \fBexport NETHACKOPTIONS\fP
.ed
in \fIsh\fP or \fIksh\fP.
.hn 2
Using a configuration file
.pg
Any line in the configuration file starting with `#' is treated as a comment.
Any line in the configuration file starting with ``OPTIONS='' may be
filled out with options in the same syntax as in NETHACKOPTIONS.
Any line starting with ``SYMBOLS=''
is taken as defining the corresponding symbol
in a different syntax, a sequence of decimal numbers giving
the character position in the current font to be used in displaying
each entry. Such a sequence can be continued to multiple lines by
putting a `\e'
at the end of each line to be continued.
.pg
Any line starting with ``AUTOPICKUP_EXCEPTION='' is taken
as defining an exception to the
.op pickup_types
option.
There is a section of this Guidebook that discusses that.
.pg
The default name of the configuration file varies on different
operating systems. On DOS and Windows, it is ``defaults.nh''
in the same folder as nethack.exe or nethackW.exe. On Unix, Linux
and Mac OS X it is ``.nethackrc'' in the user's home directory.
NETHACKOPTIONS can also be set to the full name of a file you
NETHACKOPTIONS can also be set to the full name of a configuration file you
want to use (possibly preceded by an `@').
.pg
Here is a short example of config file contents:
.sd
\fB# Set your character's role, race, gender, and alignment.\fP
\fBOPTIONS=role:Valkyrie, race:Human, gender:female, align:lawful\fP
\fB# Turn on autopickup, and set automatically picked up object types\fP
\fBOPTIONS=autopickup,pickup_types:$"=/!?+\fP
\fB# Show colored text if possible\fP
\fBOPTIONS=color\fP
\fB# Show lit corridors differently\fP
\fBOPTIONS=lit_corridor\fP
\fB# No startup splash screen. Windows GUI only.\fP
\fBOPTIONS=!splash_screen\fP
.ed
.hn 2
Customization options
.pg
@@ -2380,7 +2448,7 @@ is the same as specifying 0.
(Settings 2 and 4 are for compatibility with MSDOS or old PC Hack;
in addition to the different behavior for `5', `Alt-5' acts as `G'
and `Alt-0' acts as `I'.
Setting -1 is to accommodate some German keyboards which have the
Setting -1 is to accommodate some QWERTZ keyboards which have the
location of the `y' and `z' keys swapped.)
When moving by numbers, to enter a count prefix for those commands
which accept one (such as ``12s'' to search twelve times), precede it
+144 -46
View File
@@ -835,6 +835,15 @@ The available options
are listed later in this Guidebook. Options are usually set before the
game rather than with the `{\tt O}' command; see the section on options below.
%.lp
\item[\tb{\^{}O}]
Show overview or show dungeon layout\\
%.lp ""
In normal play and in explore mode, a shortcut for the ``{\tt \#overview}''
extended command to list interesting dungeon levels visited.\\
%.lp ""
In debug mode, an extra command which lists the placement of all special
levels.
%.lp
\item[\tb{p}]
Pay your shopping bill.
%.lp
@@ -2351,12 +2360,143 @@ behaves.
%.pg
Options may be set in a number of ways. Within the game, the `{\tt O}'
command allows you to view all options and change most of them.
You can also set options automatically by placing them in the
``NETHACKOPTIONS'' environment variable or in a configuration file.
You can also set options automatically by placing them in a configuration
file, or in the ``NETHACKOPTIONS'' environment variable.
Some versions of {\it NetHack\/} also have front-end programs that allow
you to set options before starting the game or a global configuration
for system administrators.
%.hn 2
\subsection*{Using a configuration file}
%.pg
The default name of the configuration file varies on different
operating systems. On DOS and Windows, it is ``defaults.nh''
in the same folder as nethack.exe or nethackW.exe. On Unix, Linux
and Mac OS X it is ``.nethackrc'' in the user's home directory.
The file may not exist, but it is a normal ASCII text file and
can be created with any text editor.
%.pg
Any line in the configuration file starting with `{\tt \#}' is treated as a comment.
Empty lines are ignore.
%.pg
You can use different configuration statements in the file, some
of which can be used multiple times. In general, the statements are
written in capital letters, followed by an equals sign, followed by
settings particular to that statement. Here is a list of allowed statements:
%.lp
\blist{}
\item[\bb{OPTIONS}]
There are two types of options, boolean and compound options.
Boolean options toggle a setting on or off, while compound options
take more diverse values.
Prefix a boolean option with `no' or `!' to turn it off.
For compound options, the option name and value are separated by a colon.
Some options are persistent, and apply only to new games.
You can specify multiple OPTIONS statements, and multiple options
in a single OPTIONS statement.
%.pg
Example:
%.sd
\begin{verbatim}
OPTIONS=dogname:Fido
OPTIONS=!legacy,autopickup,pickup_types:$"=/!?+
\end{verbatim}
%.ed
%.lp
\item[\bb{HACKDIR}]
Default location of files NetHack needs. On Windows HACKDIR
defaults to the location of the NetHack.exe or NetHackw.exe file
so setting HACKDIR to override that is not usually necessary or recommended.
%.lp
\item[\bb{LEVELDIR}]
The location that in-progress level files are stored. Defaults to HACKDIR,
must be writeable.
%.lp
\item[\bb{SAVEDIR}]
The location where saved games are kept. Defaults to HACKDIR, must be
writeable.
%.lp
\item[\bb{BONESDIR}]
The location that bones files are kept. Defaults to HACKDIR, must be
writeable.
%.lp
\item[\bb{LOCKDIR}]
The location that file synchronization locks are stored. Defaults to
HACKDIR, must be writeable.
%.lp
\item[\bb{TROUBLEDIR}]
The location that a record of game aborts and self-diagnosed game problems
is kept. Defaults to HACKDIR, must be writeable.
%.lp
\item[\bb{AUTOPICKUP\_EXCEPTION}]
Set exceptions to the {{\it pickup\_types\/}}
option. See the ``Configuring Autopickup Exceptions'' section.
%.lp
\item[\bb{MSGTYPE}]
Change the way messages are shown in the top status line.
See the ``Configuring Message Types`` section.
%.lp
\item[\bb{MENUCOLOR}]
Highlight menu lines with different colors.
See the ``Configuring Menu Colors`` section.
%.lp
\item[\bb{SYMBOLS}]
Override one or more symbols in the symbols files.
See the ``Modifying NetHack Symbols'' section.
%.pg
Example:
%.sd
\begin{verbatim}
SYMBOLS=S_boulder:0
\end{verbatim}
%.ed
%.lp
\item[\bb{WIZKIT}]
Wizard-mode extra items, in a text file containing item names,
one per line, up to a maximum of 128 lines. Each line is processed
by the function that handles wishing.
%.pg
Example:
%.sd
\begin{verbatim}
WIZKIT=~/wizkit.txt
\end{verbatim}
%.ed
%.lp
\item[\bb{SOUNDDIR}]
Define the directory that contains the sound files.
See the ``Configuring User Sounds'' section.
%.lp
\item[\bb{SOUND}]
Define a sound mapping. See the ``Configuring User Sounds'' section.
\elist
%.pg
Here is a short example of config file contents:
%.sd
\begin{verbatim}
# Set your character's role, race, gender, and alignment.
OPTIONS=role:Valkyrie, race:Human, gender:female, align:lawful
# Turn on autopickup, and set automatically picked up object types
OPTIONS=autopickup,pickup_types:$"=/!?+
# Show colored text if possible
OPTIONS=color
# Show lit corridors differently
OPTIONS=lit_corridor
# No startup splash screen. Windows GUI only.
OPTIONS=!splash_screen
\end{verbatim}
%.ed
%.hn 2
\subsection*{Using the NETHACKOPTIONS environment variable}
@@ -2391,52 +2531,10 @@ and the {\it fruit\/} is set to ``papaya'', you would enter the command
\nd in {\it sh\/} or {\it ksh}.
%.hn 2
\subsection*{Using a configuration file}
%.pg
Any line in the configuration file starting with `{\tt \#}' is treated as a comment.
Any line in the configuration file starting with ``{\tt OPTIONS=}'' may be
filled out with options in the same syntax as in NETHACKOPTIONS.
Any line starting with ``{\tt SYMBOLS=}''
is taken as defining the corresponding {\it symbol}
in a different syntax, a sequence of decimal numbers giving
the character position in the current font to be used in displaying
each entry. Such a sequence can be continued to multiple lines by putting a
`{\tt \verb+\+}' at the end of each line to be continued.
%.pg
Any line starting with ``{\tt AUTOPICKUP\verb+_+EXCEPTION=}''
is taken as defining an exception to the ``{\tt pickup\verb+_+types}'' option.
There is a section of this Guidebook that discusses that.
%.pg
The default name of the configuration file varies on different
operating systems. On DOS and Windows, it is ``{\tt defaults.nh}''
in the same folder as nethack.exe or nethackW.exe. On Unix, Linux
and Mac OS X it is ``{\tt.nethackrc}'' in the user's home directory.
NETHACKOPTIONS can also be set to the full name of a file you
NETHACKOPTIONS can also be set to the full name of a configuration file you
want to use (possibly preceded by an `{\tt @}').
%.pg
Here is a short example of config file contents:
%.sd
\begin{verbatim}
# Set your character's role, race, gender, and alignment.
OPTIONS=role:Valkyrie, race:Human, gender:female, align:lawful
# Turn on autopickup, and set automatically picked up object types
OPTIONS=autopickup,pickup_types:$"=/!?+
# Show colored text if possible
OPTIONS=color
# Show lit corridors differently
OPTIONS=lit_corridor
# No startup splash screen. Windows GUI only.
OPTIONS=!splash_screen
\end{verbatim}
%.ed
%.hn 2
\subsection*{Customization options}
@@ -2836,7 +2934,7 @@ is the same as specifying {\tt 0}.
(Settings {\tt 2} and {\tt 4} are for compatibility with MSDOS or old PC Hack;
in addition to the different behavior for `{\tt 5}', `{\tt Alt-5}' acts as `{\tt G}'
and `{\tt Alt-0}' acts as `{\tt I}'.
Setting {\tt -1} is to accommodate some German keyboards which have the
Setting {\tt -1} is to accommodate some QWERTZ keyboards which have the
location of the `{\tt y}' and `{\tt z}' keys swapped.)
When moving by numbers, to enter a count prefix for those commands
which accept one (such as ``{\tt 12s}'' to search twelve times), precede it
+56 -6
View File
@@ -53,6 +53,7 @@ dipping fruit juice into enlightenment gave different result than the inverse
make travel walk up to a trap and stop when the trap blocks the only
way forward, instead of trying to go straight line
travel will displace pets rather than stop
discard travel cache when moving to a different dungeon level
do not autopickup unpaid items in shops
death due an unseen gas spore's explosion resulted in "killed by a died"
allow optional parameter "true", "yes", "false", or "no" for boolean options
@@ -185,6 +186,7 @@ wand/spell/breath zaps that reached the edge of the level on the Plane of Air
stop amulets and other items which aren't affected by erosion damage from
being subjected to erosion damage
grammar bit: polyself w/ gender change yielded "you turn into a Elvenking"
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
@@ -269,9 +271,40 @@ while in shop, stone-to-flesh at self causing carried, hero owned figurine
or statue to animate claimed it belonged to shopkeeper
reviving one of a stack of N corpses in a shop charged a usage fee for all N;
remaining N-1 were owned by hero if carried but by shop if on floor
gremlin wailing in agony should wake up nearby monsters
add more lighting variance to the second bigroom variant
when getpos was picking a location, typing '^' to move to the next known trap
skipped some detected traps if their location was unseen
describe detected door traps and chest traps as trapped door and trapped chest
instead of bear trap; bear trap tile is still used on map though
thrown potion that killed peaceful monster would cause "the <mon> gets argry"
after the message about it being killed
when poly'd into a hider and engulfed, attempt to hide via #monster was blocked
but feedback said "can't hide while held" rather than "while engulfed"
various monster/object/food/gold/trap detections were inconsistent in how they
behaved if performed while engulfed or underwater
show in inventory which monster a leash is attached to
using /? to look up something by name, supplying multiple spaces (with no
other characters) as the name triggered impossible "singular of null?"
add support for the 'altmeta' option to the 'what-does' command ('&' or '?f')
when wielded weapon becomes untouchable (after alignment change or polymorph)
hero could be 'blasted by its power' twice in succession
at startup, if sysconf had been read but user's own config file couldn't be
read, sysconf got processed again as if it contained user's options
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<dir>' 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<foo> to eat a <foo> 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
avoid ring of poison resistance as starting equipment for orcish wizard
gelatinous cube shouldn't be able to eat a scroll of scare monster
make fireballs or cones of cold cast a skilled or higher not go through walls
Fixes to Post-3.6.0 Problems that Were Exposed Via git Respository
Fixes to Post-3.6.0 Problems that Were Exposed Via git Repository
------------------------------------------------------------------
fix "object lost" panic during pickup caused by sortloot revamp
more sortloot revisions
@@ -284,6 +317,7 @@ catch up win/Qt/qt_win.cpp on 18-Dec-2015 change to formatkiller()
fix for long lines in config file (28-Jan-2016) made 'O' command's 'list' and
'remove' menu choices in interactive handling for menu colorings,
message types, and autopickup exceptions subject to buffer overflow
when picking a destination for #jump, '$' to show valid dest. is more accurate
Platform- and/or Interface-Specific Fixes
@@ -366,7 +400,8 @@ feedback from probing of long worm now includes number of segments it has
monk starts with 'shuriken' pre-discovered (despite language issue...)
item-using monster on or next to a fire trap can use it to be cured of
turning into slime
wizard mode ^G can now specify "male" or "female" when creating a monster
wizard mode ^G can now specify "sleeping", "male" or "female" when
creating a monster
REPRODUCIBLE_BUILD is new config.h setting to fetch build date+time from
environment instead of using current date+time, so that later rebuild
could duplicate the original (disabled by default; tested for Unix)
@@ -383,8 +418,22 @@ during end of game disclosure, the vanquished monsters list can be sorted in
one of several ways by answering 'a' to "disclose vanquished monsters?"
when #terrain is displaying a censored version of the map (no monsters, &c),
moving the cursor will display farlook's brief autodescribe feedback
when monster/object/trap detection temporarily clears the map to highlight the
results of such detection, farlook autodescibe can be used to view it
interrupt a multi turn action if hp or pw is restored to maximum
pressing d or D when cursor positioning targets doors and doorways
pressing x or X when cursor positioning targets possibly unexplored location
(potentially useful when using '_' [not mouse] to invoke travel)
swallowers can't re-engulf hero immediately after spitting him/her out
werejackals can summon foxes and coyotes; werewolves can summon wargs
allow taming monkeys and apes with bananas
GENERICUSERS is now a sysconf statement instead of compile-time option
fountains are bright blue
ray bounceback chance depends on the wall type
undead #turning takes less time at higher experience level
peacefuls may react when you attack other peacefuls
prevent diagonal jumping through open doorways
different liquids when hallucinating
Platform- and/or Interface-Specific New Features
@@ -407,16 +456,17 @@ X11: status display split into three columns to accomodate Stone/Deaf/Lev/&c;
NetHack Community Patches (or Variation) Included
-------------------------------------------------
Malcolm Ryan's improved tin opener
Ray Chason's keyboard may stop responding after locking or unlocking a door when
using altkeyhandler=nhraykey.dll
Ray Chason's fix: window interfaces that support transparency may give away unseen
parts of the map
Ray Chason's keyboard may stop responding after locking or unlocking a door
when using altkeyhandler=nhraykey.dll
Ray Chason's fix: window interfaces that support transparency may give away
unseen parts of the map
Ray Chason's xprname should honor iflags.menu_tab_sep
Ray Chason's punctuation for "That foo is really a mimic."
Ray Chason's proper background tiles for lava and water
Ray Chason's MS-DOS port restored to functionality with credit to Reddit user
b_helyer for the fix to sys/share/pcmain.c
Ray Chason's MSDOS port support for some VESA modes
Darshan Shaligram's pet ranged attack
Code Cleanup and Reorganization
-5
View File
@@ -364,11 +364,6 @@
*/
#endif /* CHDIR */
/* If GENERIC_USERNAMES is defined, and the player's username is found
* in the list, prompt for character name instead of using username.
* A public server should probably disable this. */
#define GENERIC_USERNAMES "play player game games nethack nethacker"
/*
* Section 3: Definitions that may vary with system type.
* For example, both schar and uchar should be short ints on
-2
View File
@@ -185,8 +185,6 @@ E NEARDATA struct kinfo {
} killer;
E long done_money;
E const char *configfile;
E char lastconfigfile[BUFSZ]; /* used for messaging */
E NEARDATA char plname[PL_NSIZ];
E NEARDATA char dogname[];
E NEARDATA char catname[];
+10 -1
View File
@@ -236,6 +236,8 @@ E void NDECL(decl_init);
/* ### detect.c ### */
E boolean FDECL(trapped_chest_at, (int, int, int));
E boolean FDECL(trapped_door_at, (int, int, int));
E struct obj *FDECL(o_in, (struct obj *, CHAR_P));
E struct obj *FDECL(o_material, (struct obj *, unsigned));
E int FDECL(gold_detect, (struct obj *));
@@ -246,7 +248,7 @@ E int FDECL(trap_detect, (struct obj *));
E const char *FDECL(level_distance, (d_level *));
E void FDECL(use_crystal_ball, (struct obj **));
E void NDECL(do_mapping);
E void NDECL(do_vicinity_map);
E void FDECL(do_vicinity_map, (struct obj *));
E void FDECL(cvt_sdoor_to_door, (struct rm *));
#ifdef USE_TRAMPOLI
E void FDECL(findone, (int, int, genericptr_t));
@@ -399,6 +401,7 @@ E char *FDECL(distant_monnam, (struct monst *, int, char *));
E char *FDECL(rndmonnam, (char *));
E const char *FDECL(hcolor, (const char *));
E const char *NDECL(rndcolor);
E const char *FDECL(hliquid, (const char *));
E const char *NDECL(roguename);
E struct obj *FDECL(realloc_obj,
(struct obj *, int, genericptr_t, int, const char *));
@@ -1013,6 +1016,7 @@ E boolean FDECL(picking_lock, (int *, int *));
E boolean FDECL(picking_at, (int, int));
E void FDECL(breakchestlock, (struct obj *, BOOLEAN_P));
E void NDECL(reset_pick);
E void NDECL(maybe_reset_pick);
E int FDECL(pick_lock, (struct obj *));
E int NDECL(doforce);
E boolean FDECL(boxlock, (struct obj *, struct obj *));
@@ -1512,6 +1516,9 @@ E int FDECL(breamu, (struct monst *, struct attack *));
E boolean FDECL(linedup, (XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P, int));
E boolean FDECL(lined_up, (struct monst *));
E struct obj *FDECL(m_carrying, (struct monst *, int));
E int FDECL(thrwmm, (struct monst *, struct monst *));
E int FDECL(spitmm, (struct monst *, struct attack *, struct monst *));
E int FDECL(breamm, (struct monst *, struct attack *, struct monst *));
E void FDECL(m_useupall, (struct monst *, struct obj *));
E void FDECL(m_useup, (struct monst *, struct obj *));
E void FDECL(m_throw, (struct monst *, int, int, int, int, int, struct obj *));
@@ -1769,6 +1776,7 @@ E int FDECL(query_objlist, (const char *, struct obj **, int,
menu_item **, int, boolean (*)(OBJ_P)));
E struct obj *FDECL(pick_obj, (struct obj *));
E int NDECL(encumber_msg);
E int FDECL(container_at, (int, int, BOOLEAN_P));
E int NDECL(doloot);
E boolean FDECL(container_gone, (int (*)(OBJ_P)));
E boolean NDECL(u_handsy);
@@ -2796,6 +2804,7 @@ E struct monst *FDECL(boomhit, (struct obj *, int, int));
E int FDECL(zhitm, (struct monst *, int, int, struct obj **));
E int FDECL(burn_floor_objects, (int, int, BOOLEAN_P, BOOLEAN_P));
E void FDECL(buzz, (int, int, XCHAR_P, XCHAR_P, int, int));
E void FDECL(dobuzz, (int, int, XCHAR_P, XCHAR_P, int, int, BOOLEAN_P));
E void FDECL(melt_ice, (XCHAR_P, XCHAR_P, const char *));
E void FDECL(start_melt_ice_timeout, (XCHAR_P, XCHAR_P, long));
E void FDECL(melt_ice_away, (ANY_P *, long));
+7 -5
View File
@@ -187,10 +187,11 @@ struct instance_flags {
int override_ID; /* true to force full identification of objects */
int suppress_price; /* controls doname() for unpaid objects */
int terrainmode; /* for getpos()'s autodescribe when #terrain is active */
#define TER_MAP 0x01
#define TER_TRP 0x02
#define TER_OBJ 0x04
#define TER_MON 0x08
#define TER_MAP 0x01
#define TER_TRP 0x02
#define TER_OBJ 0x04
#define TER_MON 0x08
#define TER_DETECT 0x10 /* detect_foo magic rather than #terrain */
coord travelcc; /* coordinates for travel_cache */
boolean window_inited; /* true if init_nhwindows() completed */
boolean vision_inited; /* true if vision is ready */
@@ -347,6 +348,7 @@ struct instance_flags {
/* copies of values in struct u, used during detection when the
originals are temporarily cleared; kept here rather than
locally so that they can be restored during a hangup save */
Bitfield(save_uswallow, 1);
Bitfield(save_uinwater, 1);
Bitfield(save_uburied, 1);
};
@@ -434,7 +436,7 @@ struct cmd {
boolean num_pad; /* same as iflags.num_pad except during updates */
boolean pcHack_compat; /* for numpad: affects 5, M-5, and M-0 */
boolean phone_layout; /* inverted keypad: 1,2,3 above, 7,8,9 below */
boolean swap_yz; /* German keyboards; use z to move NW, y to zap */
boolean swap_yz; /* QWERTZ keyboards; use z to move NW, y to zap */
char move_W, move_NW, move_N, move_NE, move_E, move_SE, move_S, move_SW;
const char *dirchars; /* current movement/direction characters */
const char *alphadirchars; /* same as dirchars if !numpad */
+2 -1
View File
@@ -1,4 +1,4 @@
/* NetHack 3.6 global.h $NHDT-Date: 1450306170 2015/12/16 22:49:30 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.47 $ */
/* NetHack 3.6 global.h $NHDT-Date: 1465114189 2016/06/05 08:09:49 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.49 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
@@ -18,6 +18,7 @@
#define RECORD "record" /* file containing list of topscorers */
#define HELP "help" /* file containing command descriptions */
#define SHELP "hh" /* abbreviated form of the same */
#define KEYHELP "keyhelp" /* explanatory text for 'whatdoes' command */
#define DEBUGHELP "wizhelp" /* file containing debug mode cmds */
#define RUMORFILE "rumors" /* file with fortune cookies */
#define ORACLEFILE "oracles" /* file with oracular information */
+8 -6
View File
@@ -57,13 +57,15 @@
#define DISMOUNT_BYCHOICE 6
/* Special returns from mapglyph() */
#define MG_CORPSE 0x01
#define MG_INVIS 0x02
#define MG_DETECT 0x04
#define MG_PET 0x08
#define MG_RIDDEN 0x10
#define MG_STATUE 0x20
#define MG_CORPSE 0x01
#define MG_INVIS 0x02
#define MG_DETECT 0x04
#define MG_PET 0x08
#define MG_RIDDEN 0x10
#define MG_STATUE 0x20
#define MG_OBJPILE 0x40 /* more than one stack of objects */
#define MG_BW_LAVA 0x80 /* 'black & white lava': highlight lava if it
can't be distringuished from water by color */
/* sellobj_state() states */
#define SELL_NORMAL (0)
+4 -1
View File
@@ -194,6 +194,9 @@
|| ((ptr)->mlet == S_PUDDING && (ptr) != &mons[PM_BLACK_PUDDING]))
#define befriend_with_obj(ptr, obj) \
((obj)->oclass == FOOD_CLASS && is_domestic(ptr))
(((obj)->oclass == FOOD_CLASS && is_domestic(ptr)) \
|| ((obj)->otyp == BANANA && \
((ptr) == &mons[PM_MONKEY] \
|| (ptr) == &mons[PM_APE])))
#endif /* MONDATA_H */
+4
View File
@@ -227,6 +227,10 @@
#define DARKROOMSYM (Is_rogue_level(&u.uz) ? S_stone : S_darkroom)
#define is_cmap_trap(i) ((i) >= S_arrow_trap && (i) <= S_polymorph_trap)
#define is_cmap_drawbridge(i) ((i) >= S_vodbridge && (i) <= S_hcdbridge)
#define is_cmap_door(i) ((i) >= S_vodoor && (i) <= S_hcdoor)
struct symdef {
uchar sym;
const char *explanation;
+1
View File
@@ -13,6 +13,7 @@ struct sysopt {
or "one or two" or "one, two, or three", &c */
char *explorers; /* like wizards, but for access to explore mode */
char *shellers; /* like wizards, for ! command (-DSHELL); also ^Z */
char *genericusers; /* usernames that prompt for user name */
char *debugfiles; /* files to show debugplines in. '*' is all. */
int env_dbgfl; /* 1: debugfiles comes from getenv("DEBUGFILES")
* so sysconf's DEBUGFILES shouldn't override it;
+86 -84
View File
@@ -27,9 +27,9 @@ struct RoleAdvance {
};
struct u_have {
Bitfield(amulet, 1); /* carrying Amulet */
Bitfield(bell, 1); /* carrying Bell */
Bitfield(book, 1); /* carrying Book */
Bitfield(amulet, 1); /* carrying Amulet */
Bitfield(bell, 1); /* carrying Bell */
Bitfield(book, 1); /* carrying Book */
Bitfield(menorah, 1); /* carrying Candelabrum */
Bitfield(questart, 1); /* carrying the Quest Artifact */
Bitfield(unused, 3);
@@ -124,16 +124,16 @@ struct Role {
short questarti; /* index (ART_) of quest artifact (questpgr.c) */
/*** Bitmasks ***/
short allow; /* bit mask of allowed variations */
#define ROLE_RACEMASK 0x0ff8 /* allowable races */
#define ROLE_GENDMASK 0xf000 /* allowable genders */
#define ROLE_MALE 0x1000
#define ROLE_FEMALE 0x2000
#define ROLE_NEUTER 0x4000
#define ROLE_ALIGNMASK AM_MASK /* allowable alignments */
#define ROLE_LAWFUL AM_LAWFUL
#define ROLE_NEUTRAL AM_NEUTRAL
#define ROLE_CHAOTIC AM_CHAOTIC
short allow; /* bit mask of allowed variations */
#define ROLE_RACEMASK 0x0ff8 /* allowable races */
#define ROLE_GENDMASK 0xf000 /* allowable genders */
#define ROLE_MALE 0x1000
#define ROLE_FEMALE 0x2000
#define ROLE_NEUTER 0x4000
#define ROLE_ALIGNMASK AM_MASK /* allowable alignments */
#define ROLE_LAWFUL AM_LAWFUL
#define ROLE_NEUTRAL AM_NEUTRAL
#define ROLE_CHAOTIC AM_CHAOTIC
/*** Attributes (from attrib.c and exper.c) ***/
xchar attrbase[A_MAX]; /* lowest initial attributes */
@@ -202,9 +202,9 @@ struct Race {
xchar attrmax[A_MAX]; /* maximum allowable attribute */
struct RoleAdvance hpadv; /* hit point advancement */
struct RoleAdvance enadv; /* energy advancement */
#if 0 /* DEFERRED */
int nv_range; /* night vision range */
int xray_range; /* X-ray vision range */
#if 0 /* DEFERRED */
int nv_range; /* night vision range */
int xray_range; /* X-ray vision range */
#endif
/*** Properties in variable-length arrays ***/
@@ -231,14 +231,14 @@ struct Gender {
const char *filecode; /* file code */
short allow; /* equivalent ROLE_ mask */
};
#define ROLE_GENDERS 2 /* number of permitted player genders */
/* increment to 3 if you allow neuter roles */
#define ROLE_GENDERS 2 /* number of permitted player genders
increment to 3 if you allow neuter roles */
extern const struct Gender genders[]; /* table of available genders */
#define uhe() (genders[flags.female ? 1 : 0].he)
#define uhim() (genders[flags.female ? 1 : 0].him)
#define uhis() (genders[flags.female ? 1 : 0].his)
#define mhe(mtmp) (genders[pronoun_gender(mtmp)].he)
#define uhe() (genders[flags.female ? 1 : 0].he)
#define uhim() (genders[flags.female ? 1 : 0].him)
#define uhis() (genders[flags.female ? 1 : 0].his)
#define mhe(mtmp) (genders[pronoun_gender(mtmp)].he)
#define mhim(mtmp) (genders[pronoun_gender(mtmp)].him)
#define mhis(mtmp) (genders[pronoun_gender(mtmp)].his)
@@ -250,32 +250,32 @@ struct Align {
short allow; /* equivalent ROLE_ mask */
aligntyp value; /* equivalent A_ value */
};
#define ROLE_ALIGNS 3 /* number of permitted player alignments */
#define ROLE_ALIGNS 3 /* number of permitted player alignments */
extern const struct Align aligns[]; /* table of available alignments */
/*** Information about the player ***/
struct you {
xchar ux, uy;
schar dx, dy, dz; /* direction of move (or zap or ... ) */
schar di; /* direction of FF */
xchar tx, ty; /* destination of travel */
xchar ux0, uy0; /* initial position FF */
d_level uz, uz0; /* your level on this and the previous turn */
d_level utolev; /* level monster teleported you to, or uz */
uchar utotype; /* bitmask of goto_level() flags for utolev */
boolean umoved; /* changed map location (post-move) */
int last_str_turn; /* 0: none, 1: half turn, 2: full turn */
/* +: turn right, -: turn left */
int ulevel; /* 1 to MAXULEV */
xchar ux, uy; /* current map coordinates */
schar dx, dy, dz; /* direction of move (or zap or ... ) */
schar di; /* direction of FF */
xchar tx, ty; /* destination of travel */
xchar ux0, uy0; /* initial position FF */
d_level uz, uz0; /* your level on this and the previous turn */
d_level utolev; /* level monster teleported you to, or uz */
uchar utotype; /* bitmask of goto_level() flags for utolev */
boolean umoved; /* changed map location (post-move) */
int last_str_turn; /* 0: none, 1: half turn, 2: full turn
+: turn right, -: turn left */
int ulevel; /* 1 to MAXULEV */
int ulevelmax;
unsigned utrap; /* trap timeout */
unsigned utraptype; /* defined if utrap nonzero */
#define TT_BEARTRAP 0
#define TT_PIT 1
#define TT_WEB 2
#define TT_LAVA 3
#define TT_INFLOOR 4
#define TT_BEARTRAP 0
#define TT_PIT 1
#define TT_WEB 2
#define TT_LAVA 3
#define TT_INFLOOR 4
#define TT_BURIEDBALL 5
char urooms[5]; /* rooms (roomno + 3) occupied now */
char urooms0[5]; /* ditto, for previous position */
@@ -310,16 +310,16 @@ struct you {
int bc_order; /* ball & chain order [see bc_order() in ball.c] */
int bc_felt; /* mask for ball/chain being felt */
int umonster; /* hero's "real" monster num */
int umonnum; /* current monster number */
int umonster; /* hero's "real" monster num */
int umonnum; /* current monster number */
int mh, mhmax, mtimedone; /* for polymorph-self */
struct attribs macurr, /* for monster attribs */
mamax; /* for monster attribs */
int ulycn; /* lycanthrope type */
int mh, mhmax, mtimedone; /* for polymorph-self */
struct attribs macurr, /* for monster attribs */
mamax; /* for monster attribs */
int ulycn; /* lycanthrope type */
unsigned ucreamed;
unsigned uswldtim; /* time you have been swallowed */
unsigned uswldtim; /* time you have been swallowed */
Bitfield(uswallow, 1); /* true if swallowed */
Bitfield(uinwater, 1); /* if you're currently in water (only
@@ -328,60 +328,62 @@ struct you {
Bitfield(mfemale, 1); /* saved human value of flags.female */
Bitfield(uinvulnerable, 1); /* you're invulnerable (praying) */
Bitfield(uburied, 1); /* you're buried */
Bitfield(uedibility, 1); /* blessed food detection; sense unsafe food */
Bitfield(uedibility, 1); /* blessed food detect; sense unsafe food */
/* 1 free bit! */
unsigned udg_cnt; /* how long you have been demigod */
struct u_achieve uachieve; /* achievements */
struct u_event uevent; /* certain events have happened */
struct u_have uhave; /* you're carrying special objects */
struct u_conduct uconduct; /* KMH, conduct */
unsigned udg_cnt; /* how long you have been demigod */
struct u_achieve uachieve; /* achievements */
struct u_event uevent; /* certain events have happened */
struct u_have uhave; /* you're carrying special objects */
struct u_conduct uconduct; /* KMH, conduct */
struct u_roleplay uroleplay;
struct attribs acurr, /* your current attributes (eg. str)*/
aexe, /* for gain/loss via "exercise" */
abon, /* your bonus attributes (eg. str) */
amax, /* your max attributes (eg. str) */
atemp, /* used for temporary loss/gain */
atime; /* used for loss/gain countdown */
align ualign; /* character alignment */
#define CONVERT 2
struct attribs acurr, /* your current attributes (eg. str)*/
aexe, /* for gain/loss via "exercise" */
abon, /* your bonus attributes (eg. str) */
amax, /* your max attributes (eg. str) */
atemp, /* used for temporary loss/gain */
atime; /* used for loss/gain countdown */
align ualign; /* character alignment */
#define CONVERT 2
#define A_ORIGINAL 1
#define A_CURRENT 0
#define A_CURRENT 0
aligntyp ualignbase[CONVERT]; /* for ualign conversion record */
schar uluck, moreluck; /* luck and luck bonus */
#define Luck (u.uluck + u.moreluck)
#define LUCKADD 3 /* added value when carrying luck stone */
#define LUCKMAX 10
#define LUCKMIN (-10)
#define LUCKADD 3 /* value of u.moreluck when carrying luck stone;
+ when blessed or uncursed, - when cursed */
#define LUCKMAX 10 /* maximum value of u.ulUck */
#define LUCKMIN (-10) /* minimum value of u.uluck */
schar uhitinc;
schar udaminc;
schar uac;
uchar uspellprot; /* protection by SPE_PROTECTION */
uchar usptime; /* #moves until uspellprot-- */
uchar uspmtime; /* #moves between uspellprot-- */
int uhp, uhpmax;
int uen, uenmax; /* magical energy - M. Stephenson */
xchar uhpinc[MAXULEV], ueninc[MAXULEV]; /* increases from level gain */
int ugangr; /* if the gods are angry at you */
int ugifts; /* number of artifacts bestowed */
int ublessed, ublesscnt; /* blessing/duration from #pray */
uchar uspellprot; /* protection by SPE_PROTECTION */
uchar usptime; /* #moves until uspellprot-- */
uchar uspmtime; /* #moves between uspellprot-- */
int uhp, uhpmax; /* hit points, aka health */
int uen, uenmax; /* magical energy - M. Stephenson */
xchar uhpinc[MAXULEV], /* increases to uhpmax for each level gain */
ueninc[MAXULEV]; /* increases to uenmax for each level gain */
int ugangr; /* if the gods are angry at you */
int ugifts; /* number of artifacts bestowed */
int ublessed, ublesscnt; /* blessing/duration from #pray */
long umoney0;
long uspare1;
long uexp, urexp;
long ucleansed; /* to record moves when player was cleansed */
long usleep; /* sleeping; monstermove you last started */
long ucleansed; /* to record moves when player was cleansed */
long usleep; /* sleeping; monstermove you last started */
int uinvault;
struct monst *ustuck;
struct monst *usteed;
long ugallop;
int urideturns;
int umortality; /* how many times you died */
struct monst *ustuck; /* engulfer or grabber, maybe grabbee if Upolyd */
struct monst *usteed; /* mount when riding */
long ugallop; /* turns steed will run after being kicked */
int urideturns; /* time spent riding, for skill advancement */
int umortality; /* how many times you died */
int ugrave_arise; /* you die and become something aside from a ghost */
int weapon_slots; /* unused skill slots */
int skills_advanced; /* # of advances made so far */
int weapon_slots; /* unused skill slots */
int skills_advanced; /* # of advances made so far */
xchar skill_record[P_SKILL_LIMIT]; /* skill advancements */
struct skills weapon_skills[P_NUM_SKILLS];
boolean twoweap; /* KMH -- Using two-weapon combat */
boolean twoweap; /* KMH -- Using two-weapon combat */
}; /* end of `struct you' */
+1 -1
View File
@@ -378,7 +378,7 @@ boolean resuming;
clear_bypasses();
if ((u.uhave.amulet || Clairvoyant) && !In_endgame(&u.uz)
&& !BClairvoyant && !(moves % 15) && !rn2(2))
do_vicinity_map();
do_vicinity_map((struct obj *) 0);
if (u.utrap && u.utraptype == TT_LAVA)
sink_into_lava();
/* when/if hero escapes from lava, he can't just stay there */
+104 -21
View File
@@ -36,6 +36,7 @@ STATIC_DCL boolean FDECL(figurine_location_checks, (struct obj *,
coord *, BOOLEAN_P));
STATIC_DCL void FDECL(add_class, (char *, CHAR_P));
STATIC_DCL void FDECL(setapplyclasses, (char *));
STATIC_PTR boolean FDECL(check_jump, (genericptr_t, int, int));
STATIC_DCL boolean FDECL(is_valid_jump_pos, (int, int, int, BOOLEAN_P));
STATIC_DCL boolean FDECL(find_poleable_mon, (coord *, int, int));
@@ -1450,7 +1451,48 @@ dojump()
return jump(0);
}
boolean
enum jump_trajectory {
jAny = 0, /* any direction => magical jump */
jHorz = 1,
jVert = 2,
jDiag = 3 /* jHorz|jVert */
};
/* callback routine for walk_path() */
STATIC_PTR boolean
check_jump(arg, x, y)
genericptr arg;
int x, y;
{
int traj = *(int *) arg;
struct rm *lev = &levl[x][y];
if (Passes_walls)
return TRUE;
if (IS_STWALL(lev->typ))
return FALSE;
if (IS_DOOR(lev->typ)) {
if (closed_door(x, y))
return FALSE;
if ((lev->doormask & D_ISOPEN) != 0 && traj != jAny
/* reject diagonal jump into or out-of or through open door */
&& (traj == jDiag
/* reject horizontal jump through horizontal open door
and non-horizontal (ie, vertical) jump through
non-horizontal (vertical) open door */
|| ((traj & jHorz) != 0) == (lev->horizontal != 0)))
return FALSE;
/* empty doorways aren't restricted */
}
/* let giants jump over boulders (what about Flying?
and is there really enough head room for giants to jump
at all, let alone over something tall?) */
if (sobj_at(BOULDER, x, y) && !throws_rocks(youmonst.data))
return FALSE;
return TRUE;
}
STATIC_OVL boolean
is_valid_jump_pos(x, y, magic, showmsg)
int x, y, magic;
boolean showmsg;
@@ -1466,14 +1508,54 @@ boolean showmsg;
if (showmsg)
pline("Too far!");
return FALSE;
} else if (!cansee(x, y)) {
if (showmsg)
You("cannot see where to land!");
return FALSE;
} else if (!isok(x, y)) {
if (showmsg)
You("cannot jump there!");
return FALSE;
} else if (!cansee(x, y)) {
if (showmsg)
You("cannot see where to land!");
return FALSE;
} else {
coord uc, tc;
struct rm *lev = &levl[u.ux][u.uy];
/* we want to categorize trajectory for use in determining
passage through doorways: horizonal, vertical, or diagonal;
since knight's jump and other irregular directions are
possible, we flatten those out to simplify door checks */
int diag, traj,
dx = x - u.ux, dy = y - u.uy,
ax = abs(dx), ay = abs(dy);
/* diag: any non-orthogonal destination classifed as diagonal */
diag = (magic || Passes_walls || (!dx && !dy)) ? jAny
: !dy ? jHorz : !dx ? jVert : jDiag;
/* traj: flatten out the trajectory => some diagonals re-classified */
if (ax >= 2 * ay)
ay = 0;
else if (ay >= 2 * ax)
ax = 0;
traj = (magic || Passes_walls || (!ax && !ay)) ? jAny
: !ay ? jHorz : !ax ? jVert : jDiag;
/* walk_path doesn't process the starting spot;
this is iffy: if you're starting on a closed door spot,
you _can_ jump diagonally from doorway (without needing
Passes_walls); that's intentional but is it correct? */
if (diag == jDiag && IS_DOOR(lev->typ)
&& (lev->doormask & D_ISOPEN) != 0
&& (traj == jDiag
|| ((traj & jHorz) != 0) == (lev->horizontal != 0))) {
if (showmsg)
You_cant("jump diagonally out of a doorway.");
return FALSE;
}
uc.x = u.ux, uc.y = u.uy;
tc.x = x, tc.y = y; /* target */
if (!walk_path(&uc, &tc, check_jump, (genericptr_t) &traj)) {
if (showmsg)
There("is an obstacle preventing that jump.");
return FALSE;
}
}
return TRUE;
}
@@ -1493,7 +1575,8 @@ int state;
for (dy = -4; dy <= 4; dy++) {
x = dx + (int) u.ux;
y = dy + (int) u.uy;
if (isok(x, y) && ACCESSIBLE(levl[x][y].typ)
if (isok(x, y)
&& (ACCESSIBLE(levl[x][y].typ) || Passes_walls)
&& is_valid_jump_pos(x, y, jumping_is_magic, FALSE))
tmp_at(x, y);
}
@@ -1621,7 +1704,7 @@ int magic; /* 0=Physical, otherwise skill level */
deltrap(t_at(u.ux, u.uy));
break;
case TT_LAVA:
You("pull yourself above the lava!");
You("pull yourself above the %s!", hliquid("lava"));
u.utrap = 0;
return 1;
case TT_BURIEDBALL:
@@ -2179,20 +2262,6 @@ struct obj *obj;
update_inventory();
}
static struct trapinfo {
struct obj *tobj;
xchar tx, ty;
int time_needed;
boolean force_bungle;
} trapinfo;
void
reset_trapset()
{
trapinfo.tobj = 0;
trapinfo.force_bungle = 0;
}
/* touchstones - by Ken Arnold */
STATIC_OVL void
use_stone(tstone)
@@ -2322,6 +2391,20 @@ struct obj *tstone;
return;
}
static struct trapinfo {
struct obj *tobj;
xchar tx, ty;
int time_needed;
boolean force_bungle;
} trapinfo;
void
reset_trapset()
{
trapinfo.tobj = 0;
trapinfo.force_bungle = 0;
}
/* Place a landmine/bear trap. Helge Hafting */
STATIC_OVL void
use_trap(otmp)
+1 -1
View File
@@ -1888,7 +1888,7 @@ boolean loseit; /* whether to drop it if hero can longer touch it */
bane = bane_applies(get_artifact(obj), &youmonst);
/* nothing else to do if hero can successfully handle this object */
if (!ag && !bane)
if (!ag && !bane && !touch_blasted)
return 1;
/* hero can't handle this object, but didn't get touch_artifact()'s
+1 -1
View File
@@ -716,7 +716,7 @@ xchar x, y;
deltrap(t_at(u.ux, u.uy));
break;
case TT_LAVA:
pline(pullmsg, "lava");
pline(pullmsg, hliquid("lava"));
break;
case TT_BEARTRAP: {
register long side = rn2(3) ? LEFT_SIDE : RIGHT_SIDE;
+94 -48
View File
@@ -183,6 +183,7 @@ static const char *readchar_queue = "";
static coord clicklook_cc;
STATIC_DCL char *NDECL(parse);
STATIC_DCL void FDECL(show_direction_keys, (winid, BOOLEAN_P));
STATIC_DCL boolean FDECL(help_dir, (CHAR_P, const char *));
STATIC_PTR int
@@ -356,7 +357,7 @@ doextlist(VOID_ARGS)
return 0;
}
#if defined(TTY_GRAPHICS) || defined(CURSES_GRAPHICS)
#ifdef TTY_GRAPHICS
#define MAX_EXT_CMD 50 /* Change if we ever have > 50 ext cmds */
/*
@@ -1491,16 +1492,26 @@ int final;
}
you_are(buf, "");
/* report alignment (bypass you_are() in order to omit ending period) */
/* report alignment (bypass you_are() in order to omit ending period);
adverb is used to distinguish between temporary change (helm of opp.
alignment), permanent change (one-time conversion), and original */
Sprintf(buf, " %s%s%s, %son a mission for %s",
You_, !final ? are : were,
align_str(u.ualign.type),
/* helm of opposite alignment (might hide conversion) */
(u.ualign.type != u.ualignbase[A_CURRENT]) ? "temporarily "
(u.ualign.type != u.ualignbase[A_CURRENT])
/* what's the past tense of "currently"? if we used "formerly"
it would sound like a reference to the original alignment */
? (!final ? "currently " : "temporarily ")
/* permanent conversion */
: (u.ualign.type != u.ualignbase[A_ORIGINAL]) ? "now "
: (u.ualign.type != u.ualignbase[A_ORIGINAL])
/* and what's the past tense of "now"? certainly not "then"
in a context like this...; "belatedly" == weren't that
way sooner (in other words, didn't start that way) */
? (!final ? "now " : "belatedly ")
/* atheist (ignored in very early game) */
: (!u.uconduct.gnostic && moves > 1000L) ? "nominally "
: (!u.uconduct.gnostic && moves > 1000L)
? "nominally "
/* lastly, normal case */
: "",
u_gname());
@@ -2623,6 +2634,26 @@ int final;
} else {
Sprintf(buf, "used %ld wish%s", u.uconduct.wishes,
(u.uconduct.wishes > 1L) ? "es" : "");
if (u.uconduct.wisharti) {
/* if wisharti == wishes
* 1 wish (for an artifact)
* 2 wishes (both for artifacts)
* N wishes (all for artifacts)
* else (N is at least 2 in order to get here; M < N)
* N wishes (1 for an artifact)
* N wishes (M for artifacts)
*/
if (u.uconduct.wisharti == u.uconduct.wishes)
Sprintf(eos(buf), " (%s",
(u.uconduct.wisharti > 2L) ? "all "
: (u.uconduct.wisharti == 2L) ? "both " : "");
else
Sprintf(eos(buf), " (%ld ", u.uconduct.wisharti);
Sprintf(eos(buf), "for %s)",
(u.uconduct.wisharti == 1L) ? "an artifact"
: "artifacts");
}
you_have_X(buf);
if (!u.uconduct.wisharti)
@@ -3350,7 +3381,8 @@ boolean initial;
Cmd.num_pad = flagtemp;
++updated;
}
/* swap_yz mode (only applicable for !num_pad) */
/* swap_yz mode (only applicable for !num_pad); intended for
QWERTZ keyboard used in Central Europe, particularly Germany */
flagtemp = (iflags.num_pad_mode & 1) ? !Cmd.num_pad : FALSE;
if (flagtemp != Cmd.swap_yz) {
Cmd.swap_yz = flagtemp;
@@ -3384,12 +3416,12 @@ boolean initial;
++updated;
/* phone_layout has been toggled */
for (i = 0; i < 3; i++) {
c = '1' + i; /* 1,2,3 <-> 7,8,9 */
c = '1' + i; /* 1,2,3 <-> 7,8,9 */
cmdtmp = Cmd.commands[c]; /* tmp = [1] */
Cmd.commands[c] = Cmd.commands[c + 6]; /* [1] = [7] */
Cmd.commands[c + 6] = cmdtmp; /* [7] = tmp */
c = (M('1') & 0xff) + i; /* M-1,M-2,M-3 <-> M-7,M-8,M-9 */
cmdtmp = Cmd.commands[c]; /* tmp = [M-1] */
c = (M('1') & 0xff) + i; /* M-1,M-2,M-3 <-> M-7,M-8,M-9 */
cmdtmp = Cmd.commands[c]; /* tmp = [M-1] */
Cmd.commands[c] = Cmd.commands[c + 6]; /* [M-1] = [M-7] */
Cmd.commands[c + 6] = cmdtmp; /* [M-7] = tmp */
}
@@ -3789,46 +3821,14 @@ retry:
return 1;
}
STATIC_OVL boolean
help_dir(sym, msg)
char sym;
const char *msg;
STATIC_OVL void
show_direction_keys(win, nodiag)
winid win;
boolean nodiag;
{
char ctrl;
winid win;
static const char wiz_only_list[] = "EFGIOVW";
char buf[BUFSZ], buf2[BUFSZ], *explain;
char buf[BUFSZ];
win = create_nhwindow(NHW_TEXT);
if (!win)
return FALSE;
if (msg) {
Sprintf(buf, "cmdassist: %s", msg);
putstr(win, 0, buf);
putstr(win, 0, "");
}
if (letter(sym)) {
sym = highc(sym);
ctrl = (sym - 'A') + 1;
if ((explain = dowhatdoes_core(ctrl, buf2))
&& (!index(wiz_only_list, sym) || wizard)) {
Sprintf(buf, "Are you trying to use ^%c%s?", sym,
index(wiz_only_list, sym)
? ""
: " as specified in the Guidebook");
putstr(win, 0, buf);
putstr(win, 0, "");
putstr(win, 0, explain);
putstr(win, 0, "");
putstr(win, 0, "To use that command, you press");
Sprintf(buf, "the <Ctrl> key, and the <%c> key at the same time.",
sym);
putstr(win, 0, buf);
putstr(win, 0, "");
}
}
if (NODIAG(u.umonnum)) {
putstr(win, 0, "Valid direction keys in your current form are:");
if (nodiag) {
Sprintf(buf, " %c ", Cmd.move_N);
putstr(win, 0, buf);
putstr(win, 0, " | ");
@@ -3838,7 +3838,6 @@ const char *msg;
Sprintf(buf, " %c ", Cmd.move_S);
putstr(win, 0, buf);
} else {
putstr(win, 0, "Valid direction keys are:");
Sprintf(buf, " %c %c %c", Cmd.move_NW, Cmd.move_N,
Cmd.move_NE);
putstr(win, 0, buf);
@@ -3850,6 +3849,53 @@ const char *msg;
Cmd.move_SE);
putstr(win, 0, buf);
};
}
STATIC_OVL boolean
help_dir(sym, msg)
char sym;
const char *msg;
{
static const char wiz_only_list[] = "EFGIVW";
char ctrl;
winid win;
char buf[BUFSZ], buf2[BUFSZ], *explain;
win = create_nhwindow(NHW_TEXT);
if (!win)
return FALSE;
if (msg) {
Sprintf(buf, "cmdassist: %s", msg);
putstr(win, 0, buf);
putstr(win, 0, "");
}
if (letter(sym) || sym == '[') { /* 'dat/cmdhelp' shows ESC as ^[ */
sym = highc(sym); /* @A-Z[ (note: letter() accepts '@') */
ctrl = (sym - 'A') + 1; /* 0-27 (note: 28-31 aren't applicable) */
if ((explain = dowhatdoes_core(ctrl, buf2)) != 0
&& (!index(wiz_only_list, sym) || wizard)) {
Sprintf(buf, "Are you trying to use ^%c%s?", sym,
index(wiz_only_list, sym)
? ""
: " as specified in the Guidebook");
putstr(win, 0, buf);
putstr(win, 0, "");
putstr(win, 0, explain);
putstr(win, 0, "");
putstr(win, 0,
"To use that command, hold down the <Ctrl> key as a shift");
Sprintf(buf, "and press the <%c> key.", sym);
putstr(win, 0, buf);
putstr(win, 0, "");
}
}
Sprintf(buf, "Valid direction keys %sare:",
NODIAG(u.umonnum) ? "in your current form " : "");
putstr(win, 0, buf);
show_direction_keys(win, NODIAG(u.umonnum));
putstr(win, 0, "");
putstr(win, 0, " < up");
putstr(win, 0, " > down");
+3 -3
View File
@@ -750,7 +750,7 @@ struct entity *etmp;
E_phrase(etmp, "drink"), lava ? "lava" : "moat");
else
pline("%s into the %s.", E_phrase(etmp, "fall"),
lava ? "lava" : "moat");
lava ? hliquid("lava") : "moat");
}
killer.format = NO_KILLER_PREFIX;
Strcpy(killer.name, "fell from a drawbridge");
@@ -901,13 +901,13 @@ int x, y;
if (lev1->typ == DRAWBRIDGE_UP) {
if (cansee(x2, y2))
pline_The("portcullis of the drawbridge falls into the %s!",
lava ? "lava" : "moat");
lava ? hliquid("lava") : "moat");
else if (!Deaf)
You_hear("a loud *SPLASH*!");
} else {
if (cansee(x, y))
pline_The("drawbridge collapses into the %s!",
lava ? "lava" : "moat");
lava ? hliquid("lava") : "moat");
else if (!Deaf)
You_hear("a loud *SPLASH*!");
}
+346 -152
View File
@@ -12,6 +12,10 @@
extern boolean known; /* from read.c */
STATIC_DCL boolean NDECL(unconstrain_map);
STATIC_DCL void NDECL(reconstrain_map);
STATIC_DCL void FDECL(browse_map, (int, const char *));
STATIC_DCL void FDECL(map_monst, (struct monst *, BOOLEAN_P));
STATIC_DCL void FDECL(do_dknown_of, (struct obj *));
STATIC_DCL boolean FDECL(check_map_spot, (int, int, CHAR_P, unsigned));
STATIC_DCL boolean FDECL(clear_stale_map, (CHAR_P, unsigned));
@@ -22,8 +26,130 @@ STATIC_PTR void FDECL(findone, (int, int, genericptr_t));
STATIC_PTR void FDECL(openone, (int, int, genericptr_t));
STATIC_DCL int FDECL(mfind0, (struct monst *, BOOLEAN_P));
/* Recursively search obj for an object in class oclass and return 1st found
*/
/* bring hero out from underwater or underground or being engulfed;
return True iff any change occurred */
STATIC_OVL boolean
unconstrain_map()
{
boolean res = u.uinwater || u.uburied || u.uswallow;
/* bring Underwater, buried, or swallowed hero to normal map */
iflags.save_uinwater = u.uinwater, u.uinwater = 0;
iflags.save_uburied = u.uburied, u.uburied = 0;
iflags.save_uswallow = u.uswallow, u.uswallow = 0;
return res;
}
/* put hero back underwater or underground or engulfed */
STATIC_OVL void
reconstrain_map()
{
u.uinwater = iflags.save_uinwater, iflags.save_uinwater = 0;
u.uburied = iflags.save_uburied, iflags.save_uburied = 0;
u.uswallow = iflags.save_uswallow, iflags.save_uswallow = 0;
}
/* use getpos()'s 'autodescribe' to view whatever is currently shown on map */
STATIC_DCL void
browse_map(ter_typ, ter_explain)
int ter_typ;
const char *ter_explain;
{
coord dummy_pos; /* don't care whether player actually picks a spot */
dummy_pos.x = u.ux, dummy_pos.y = u.uy; /* starting spot for getpos() */
iflags.autodescribe = TRUE;
iflags.terrainmode = ter_typ;
getpos(&dummy_pos, FALSE, ter_explain);
iflags.terrainmode = 0;
/* leave iflags.autodescribe 'on' even if previously 'off' */
}
/* extracted from monster_detection() so can be shared by do_vicinity_map() */
STATIC_DCL void
map_monst(mtmp, showtail)
struct monst *mtmp;
boolean showtail;
{
if (def_monsyms[(int) mtmp->data->mlet].sym == ' ')
show_glyph(mtmp->mx, mtmp->my, detected_mon_to_glyph(mtmp));
else
show_glyph(mtmp->mx, mtmp->my,
mtmp->mtame ? pet_to_glyph(mtmp) : mon_to_glyph(mtmp));
if (showtail && mtmp->data == &mons[PM_LONG_WORM])
detect_wsegs(mtmp, 0);
}
/* this is checking whether a trap symbol represents a trapped chest,
not whether a trapped chest is actually present */
boolean
trapped_chest_at(ttyp, x, y)
int ttyp;
int x, y;
{
struct monst *mtmp;
struct obj *otmp;
if (!glyph_is_trap(glyph_at(x, y)))
return FALSE;
if (ttyp != BEAR_TRAP || (Hallucination && rn2(20)))
return FALSE;
/*
* TODO? We should check containers recursively like the trap
* detecting routine does. Chests and large boxes do not nest in
* themselves or each other, but could be contained inside statues.
*
* For farlook, we should also check for buried containers, but
* for '^' command to examine adjacent trap glyph, we shouldn't.
*/
/* on map, presence of any trappable container will do */
if (sobj_at(CHEST, x, y) || sobj_at(LARGE_BOX, x, y))
return TRUE;
/* in inventory, we need to find one which is actually trapped */
if (x == u.ux && y == u.uy) {
for (otmp = invent; otmp; otmp = otmp->nobj)
if (Is_box(otmp) && otmp->otrapped)
return TRUE;
if (u.usteed) { /* steed isn't on map so won't be found by m_at() */
for (otmp = u.usteed->minvent; otmp; otmp = otmp->nobj)
if (Is_box(otmp) && otmp->otrapped)
return TRUE;
}
}
if ((mtmp = m_at(x, y)) != 0)
for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj)
if (Is_box(otmp) && otmp->otrapped)
return TRUE;
return FALSE;
}
/* this is checking whether a trap symbol represents a trapped door,
not whether the door here is actually trapped */
boolean
trapped_door_at(ttyp, x, y)
int ttyp;
int x, y;
{
struct rm *lev;
if (!glyph_is_trap(glyph_at(x, y)))
return FALSE;
if (ttyp != BEAR_TRAP || (Hallucination && rn2(20)))
return FALSE;
lev = &levl[x][y];
if (!IS_DOOR(lev->typ))
return FALSE;
if ((lev->doormask & (D_NODOOR | D_BROKEN | D_ISOPEN)) != 0
&& trapped_chest_at(ttyp, x, y))
return FALSE;
return TRUE;
}
/* recursively search obj for an object in class oclass, return 1st found */
struct obj *
o_in(obj, oclass)
struct obj *obj;
@@ -39,7 +165,7 @@ char oclass;
for (otmp = obj->cobj; otmp; otmp = otmp->nobj)
if (otmp->oclass == oclass)
return otmp;
else if (Has_contents(otmp) && (temp = o_in(otmp, oclass)))
else if (Has_contents(otmp) && (temp = o_in(otmp, oclass)) != 0)
return temp;
}
return (struct obj *) 0;
@@ -64,7 +190,7 @@ unsigned material;
if (objects[otmp->otyp].oc_material == material)
return otmp;
else if (Has_contents(otmp)
&& (temp = o_material(otmp, material)))
&& (temp = o_material(otmp, material)) != 0)
return temp;
}
return (struct obj *) 0;
@@ -166,28 +292,36 @@ register struct obj *sobj;
{
register struct obj *obj;
register struct monst *mtmp;
struct obj *temp;
boolean stale;
struct obj gold, *temp = 0;
boolean stale, ugold = FALSE, steedgold = FALSE;
int ter_typ = TER_DETECT | TER_OBJ;
known = stale =
clear_stale_map(COIN_CLASS, (unsigned) (sobj->blessed ? GOLD : 0));
known = stale = clear_stale_map(COIN_CLASS,
(unsigned) (sobj->blessed ? GOLD : 0));
/* look for gold carried by monsters (might be in a container) */
for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
if (DEADMONSTER(mtmp))
continue; /* probably not needed in this case but... */
if (findgold(mtmp->minvent) || monsndx(mtmp->data) == PM_GOLD_GOLEM) {
known = TRUE;
goto outgoldmap; /* skip further searching */
} else
if (mtmp == u.usteed) {
steedgold = TRUE;
} else {
known = TRUE;
goto outgoldmap; /* skip further searching */
}
} else {
for (obj = mtmp->minvent; obj; obj = obj->nobj)
if (sobj->blessed && o_material(obj, GOLD)) {
known = TRUE;
goto outgoldmap;
} else if (o_in(obj, COIN_CLASS)) {
known = TRUE;
goto outgoldmap; /* skip further searching */
if ((sobj->blessed && o_material(obj, GOLD))
|| o_in(obj, COIN_CLASS)) {
if (mtmp == u.usteed) {
steedgold = TRUE;
} else {
known = TRUE;
goto outgoldmap; /* skip further searching */
}
}
}
}
/* look for gold objects */
@@ -208,13 +342,22 @@ register struct obj *sobj;
adjust message if you have gold in your inventory */
if (sobj) {
char buf[BUFSZ];
if (youmonst.data == &mons[PM_GOLD_GOLEM]) {
if (youmonst.data == &mons[PM_GOLD_GOLEM])
Sprintf(buf, "You feel like a million %s!", currency(2L));
} else if (hidden_gold() || money_cnt(invent))
else if (money_cnt(invent) || hidden_gold())
Strcpy(buf,
"You feel worried about your future financial situation.");
else if (steedgold)
Sprintf(buf, "You feel interested in %s financial situation.",
s_suffix(x_monnam(u.usteed,
u.usteed->mtame ? ARTICLE_YOUR
: ARTICLE_THE,
(char *) 0,
SUPPRESS_SADDLE, FALSE)));
else
Strcpy(buf, "You feel materially poor.");
strange_feeling(sobj, buf);
}
return 1;
@@ -228,54 +371,64 @@ register struct obj *sobj;
outgoldmap:
cls();
iflags.save_uinwater = u.uinwater, iflags.save_uburied = u.uburied;
u.uinwater = u.uburied = 0;
(void) unconstrain_map();
/* Discover gold locations. */
for (obj = fobj; obj; obj = obj->nobj) {
if (sobj->blessed && (temp = o_material(obj, GOLD))) {
if (sobj->blessed && (temp = o_material(obj, GOLD)) != 0) {
if (temp != obj) {
temp->ox = obj->ox;
temp->oy = obj->oy;
}
map_object(temp, 1);
} else if ((temp = o_in(obj, COIN_CLASS))) {
} else if ((temp = o_in(obj, COIN_CLASS)) != 0) {
if (temp != obj) {
temp->ox = obj->ox;
temp->oy = obj->oy;
}
map_object(temp, 1);
}
if (temp && temp->ox == u.ux && temp->oy == u.uy)
ugold = TRUE;
}
for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
if (DEADMONSTER(mtmp))
continue; /* probably overkill here */
temp = 0;
if (findgold(mtmp->minvent) || monsndx(mtmp->data) == PM_GOLD_GOLEM) {
struct obj gold;
gold = zeroobj; /* ensure oextra is cleared too */
gold.otyp = GOLD_PIECE;
gold.quan = (long) rnd(10); /* usually more than 1 */
gold.ox = mtmp->mx;
gold.oy = mtmp->my;
map_object(&gold, 1);
} else
temp = &gold;
} else {
for (obj = mtmp->minvent; obj; obj = obj->nobj)
if (sobj->blessed && (temp = o_material(obj, GOLD))) {
if (sobj->blessed && (temp = o_material(obj, GOLD)) != 0) {
temp->ox = mtmp->mx;
temp->oy = mtmp->my;
map_object(temp, 1);
break;
} else if ((temp = o_in(obj, COIN_CLASS))) {
} else if ((temp = o_in(obj, COIN_CLASS)) != 0) {
temp->ox = mtmp->mx;
temp->oy = mtmp->my;
map_object(temp, 1);
break;
}
}
if (temp && temp->ox == u.ux && temp->oy == u.uy)
ugold = TRUE;
}
if (!ugold) {
newsym(u.ux, u.uy);
ter_typ |= TER_MON; /* so autodescribe will recognize hero */
}
newsym(u.ux, u.uy);
u.uinwater = iflags.save_uinwater, u.uburied = iflags.save_uburied;
iflags.save_uinwater = iflags.save_uburied = 0;
You_feel("very greedy, and sense gold!");
exercise(A_WIS, TRUE);
display_nhwindow(WIN_MAP, TRUE);
browse_map(ter_typ, "gold");
reconstrain_map();
docrt();
if (Underwater)
under_water(2);
@@ -298,6 +451,8 @@ register struct obj *sobj;
const char *what = confused ? something : "food";
stale = clear_stale_map(oclass, 0);
if (u.usteed) /* some situations leave steed with stale coordinates */
u.usteed->mx = u.ux, u.usteed->my = u.uy;
for (obj = fobj; obj; obj = obj->nobj)
if (o_in(obj, oclass)) {
@@ -306,12 +461,14 @@ register struct obj *sobj;
else
ct++;
}
for (mtmp = fmon; mtmp && !ct; mtmp = mtmp->nmon) {
/* no DEADMONSTER(mtmp) check needed since dmons never have inventory
*/
for (mtmp = fmon; mtmp && (!ct || !ctu); mtmp = mtmp->nmon) {
/* no DEADMONSTER(mtmp) check needed -- dmons never have inventory */
for (obj = mtmp->minvent; obj; obj = obj->nobj)
if (o_in(obj, oclass)) {
ct++;
if (mtmp->mx == u.ux && mtmp->my == u.uy)
ctu++; /* steed or an engulfer with inventory */
else
ct++;
break;
}
}
@@ -328,6 +485,7 @@ register struct obj *sobj;
}
} else if (sobj) {
char buf[BUFSZ];
Sprintf(buf, "Your %s twitches%s.", body_part(NOSE),
(sobj->blessed && !u.uedibility)
? " then starts to tingle"
@@ -353,10 +511,11 @@ register struct obj *sobj;
}
} else {
struct obj *temp;
int ter_typ = TER_DETECT | TER_OBJ;
known = TRUE;
cls();
iflags.save_uinwater = u.uinwater, iflags.save_uburied = u.uburied;
u.uinwater = u.uburied = 0;
(void) unconstrain_map();
for (obj = fobj; obj; obj = obj->nobj)
if ((temp = o_in(obj, oclass)) != 0) {
if (temp != obj) {
@@ -366,8 +525,7 @@ register struct obj *sobj;
map_object(temp, 1);
}
for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
/* no DEADMONSTER(mtmp) check needed since dmons never have
* inventory */
/* no DEADMONSTER() check needed -- dmons never have inventory */
for (obj = mtmp->minvent; obj; obj = obj->nobj)
if ((temp = o_in(obj, oclass)) != 0) {
temp->ox = mtmp->mx;
@@ -375,9 +533,10 @@ register struct obj *sobj;
map_object(temp, 1);
break; /* skip rest of this monster's inventory */
}
newsym(u.ux, u.uy);
u.uinwater = iflags.save_uinwater, u.uburied = iflags.save_uburied;
iflags.save_uinwater = iflags.save_uburied = 0;
if (!ctu) {
newsym(u.ux, u.uy);
ter_typ |= TER_MON; /* for autodescribe of self */
}
if (sobj) {
if (sobj->blessed) {
Your("%s %s to tingle and you smell %s.", body_part(NOSE),
@@ -387,8 +546,11 @@ register struct obj *sobj;
Your("%s tingles and you smell %s.", body_part(NOSE), what);
} else
You("sense %s.", what);
display_nhwindow(WIN_MAP, TRUE);
exercise(A_WIS, TRUE);
browse_map(ter_typ, "food");
reconstrain_map();
docrt();
if (Underwater)
under_water(2);
@@ -418,7 +580,7 @@ int class; /* an object class, 0 for all */
int ct = 0, ctu = 0;
register struct obj *obj, *otmp = (struct obj *) 0;
register struct monst *mtmp;
int sym, boulder = 0;
int sym, boulder = 0, ter_typ = TER_DETECT | TER_OBJ;
if (class < 0 || class >= MAXOCLASSES) {
impossible("object_detect: illegal class %d", class);
@@ -468,6 +630,9 @@ int class; /* an object class, 0 for all */
do_dknown_of(obj);
}
if (u.usteed)
u.usteed->mx = u.ux, u.usteed->my = u.uy;
for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
if (DEADMONSTER(mtmp))
continue;
@@ -499,13 +664,12 @@ int class; /* an object class, 0 for all */
cls();
iflags.save_uinwater = u.uinwater, iflags.save_uburied = u.uburied;
u.uinwater = u.uburied = 0;
(void) unconstrain_map();
/*
* Map all buried objects first.
*/
for (obj = level.buriedobjlist; obj; obj = obj->nobj)
if (!class || (otmp = o_in(obj, class))) {
if (!class || (otmp = o_in(obj, class)) != 0) {
if (class) {
if (otmp != obj) {
otmp->ox = obj->ox;
@@ -526,8 +690,8 @@ int class; /* an object class, 0 for all */
for (x = 1; x < COLNO; x++)
for (y = 0; y < ROWNO; y++)
for (obj = level.objects[x][y]; obj; obj = obj->nexthere)
if ((!class && !boulder) || (otmp = o_in(obj, class))
|| (otmp = o_in(obj, boulder))) {
if ((!class && !boulder) || (otmp = o_in(obj, class)) != 0
|| (otmp = o_in(obj, boulder)) != 0) {
if (class || boulder) {
if (otmp != obj) {
otmp->ox = obj->ox;
@@ -544,8 +708,8 @@ int class; /* an object class, 0 for all */
if (DEADMONSTER(mtmp))
continue;
for (obj = mtmp->minvent; obj; obj = obj->nobj)
if ((!class && !boulder) || (otmp = o_in(obj, class))
|| (otmp = o_in(obj, boulder))) {
if ((!class && !boulder) || (otmp = o_in(obj, class)) != 0
|| (otmp = o_in(obj, boulder)) != 0) {
if (!class && !boulder)
otmp = obj;
otmp->ox = mtmp->mx; /* at monster location */
@@ -558,8 +722,9 @@ int class; /* an object class, 0 for all */
&& (!class || class == objects[mtmp->mappearance].oc_class)) {
struct obj temp;
temp.oextra = (struct oextra *) 0;
temp = zeroobj;
temp.otyp = mtmp->mappearance; /* needed for obj_to_glyph() */
temp.quan = 1L;
temp.ox = mtmp->mx;
temp.oy = mtmp->my;
temp.corpsenm = PM_TENGU; /* if mimicing a corpse */
@@ -567,25 +732,28 @@ int class; /* an object class, 0 for all */
} else if (findgold(mtmp->minvent)
&& (!class || class == COIN_CLASS)) {
struct obj gold;
gold = zeroobj; /* ensure oextra is cleared too */
gold.otyp = GOLD_PIECE;
gold.quan = (long) rnd(10); /* usually more than 1 */
gold.ox = mtmp->mx;
gold.oy = mtmp->my;
map_object(&gold, 1);
}
}
newsym(u.ux, u.uy);
u.uinwater = iflags.save_uinwater, u.uburied = iflags.save_uburied;
iflags.save_uinwater = iflags.save_uburied = 0;
if (!glyph_is_object(glyph_at(u.ux, u.uy))) {
newsym(u.ux, u.uy);
ter_typ |= TER_MON;
}
You("detect the %s of %s.", ct ? "presence" : "absence", stuff);
display_nhwindow(WIN_MAP, TRUE);
/*
* What are we going to do when the hero does an object detect while blind
* and the detected object covers a known pool?
*/
docrt(); /* this will correctly reset vision */
if (!ct)
display_nhwindow(WIN_MAP, TRUE);
else
browse_map(ter_typ, "object");
reconstrain_map();
docrt(); /* this will correctly reset vision */
if (Underwater)
under_water(2);
if (u.uburied)
@@ -625,26 +793,19 @@ int mclass; /* monster class, 0 for all */
: "You feel threatened.");
return 1;
} else {
boolean woken = FALSE;
boolean unconstrained, woken = FALSE;
unsigned swallowed = u.uswallow; /* before unconstrain_map() */
cls();
unconstrained = unconstrain_map();
for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
if (DEADMONSTER(mtmp))
continue;
if (!mclass || mtmp->data->mlet == mclass
|| (mtmp->data == &mons[PM_LONG_WORM]
&& mclass == S_WORM_TAIL))
if (mtmp->mx > 0) {
if (mclass && def_monsyms[mclass].sym == ' ')
show_glyph(mtmp->mx, mtmp->my,
detected_mon_to_glyph(mtmp));
else
show_glyph(mtmp->mx, mtmp->my,
mtmp->mtame ? pet_to_glyph(mtmp) : mon_to_glyph(mtmp));
/* don't be stingy - display entire worm */
if (mtmp->data == &mons[PM_LONG_WORM])
detect_wsegs(mtmp, 0);
}
map_monst(mtmp, TRUE);
if (otmp && otmp->cursed
&& (mtmp->msleeping || !mtmp->mcanmove)) {
mtmp->msleeping = mtmp->mfrozen = 0;
@@ -652,12 +813,25 @@ int mclass; /* monster class, 0 for all */
woken = TRUE;
}
}
display_self();
if (!swallowed)
display_self();
You("sense the presence of monsters.");
if (woken)
pline("Monsters sense the presence of you.");
display_nhwindow(WIN_MAP, TRUE);
docrt();
if ((otmp && otmp->blessed) && !unconstrained) {
/* persistent detection--just show updated map */
display_nhwindow(WIN_MAP, TRUE);
} else {
/* one-shot detection--allow player to move cursor around and
get autodescribe feedback */
EDetect_monsters |= I_SPECIAL;
browse_map(TER_DETECT | TER_MON, "monster of interest");
EDetect_monsters &= ~I_SPECIAL;
}
reconstrain_map();
docrt(); /* redraw the screen to remove unseen monsters from map */
if (Underwater)
under_water(2);
if (u.uburied)
@@ -675,7 +849,7 @@ int src_cursed;
if (Hallucination || src_cursed) {
struct obj obj; /* fake object */
obj.oextra = (struct oextra *) 0;
obj = zeroobj;
if (trap) {
obj.ox = trap->tx;
obj.oy = trap->ty;
@@ -683,14 +857,18 @@ int src_cursed;
obj.ox = x;
obj.oy = y;
}
obj.otyp = (src_cursed) ? GOLD_PIECE : random_object();
obj.otyp = !Hallucination ? GOLD_PIECE : random_object();
obj.quan = (long) ((obj.otyp == GOLD_PIECE) ? rnd(10)
: objects[obj.otyp].oc_merge ? rnd(2) : 1);
obj.corpsenm = random_monster(); /* if otyp == CORPSE */
map_object(&obj, 1);
} else if (trap) {
map_trap(trap, 1);
trap->tseen = 1;
} else {
} else { /* trapped door or trapped chest */
struct trap temp_trap; /* fake trap */
(void) memset((genericptr_t) &temp_trap, 0, sizeof temp_trap);
temp_trap.tx = x;
temp_trap.ty = y;
temp_trap.ttyp = BEAR_TRAP; /* some kind of trap */
@@ -715,6 +893,11 @@ int how; /* 1 for misleading map feedback */
xchar x, y;
int result = OTRAP_NONE;
/*
* TODO? Display locations of unarmed land mine and beartrap objects.
* If so, should they be displayed as objects or as traps?
*/
for (otmp = objlist; otmp; otmp = otmp->nobj) {
if (Is_box(otmp) && otmp->otrapped
&& get_obj_location(otmp, &x, &y, BURIED_TOO | CONTAINED_TOO)) {
@@ -735,16 +918,18 @@ int how; /* 1 for misleading map feedback */
*/
int
trap_detect(sobj)
register struct obj *sobj;
/* sobj is null if crystal ball, *scroll if gold detection scroll */
struct obj *sobj; /* null if crystal ball, *scroll if gold detection scroll */
{
register struct trap *ttmp;
struct monst *mon;
int door, glyph, tr;
int door, glyph, tr, ter_typ = TER_DETECT | TER_TRP;
int cursed_src = sobj && sobj->cursed;
boolean found = FALSE;
coord cc;
if (u.usteed)
u.usteed->mx = u.ux, u.usteed->my = u.uy;
/* floor/ceiling traps */
for (ttmp = ftrap; ttmp; ttmp = ttmp->ntrap) {
if (ttmp->tx != u.ux || ttmp->ty != u.uy)
@@ -759,8 +944,7 @@ register struct obj *sobj;
else
found = TRUE;
}
if ((tr = detect_obj_traps(level.buriedobjlist, FALSE, 0))
!= OTRAP_NONE) {
if ((tr = detect_obj_traps(level.buriedobjlist, FALSE, 0)) != OTRAP_NONE) {
if (tr & OTRAP_THERE)
goto outtrapmap;
else
@@ -798,12 +982,11 @@ register struct obj *sobj;
/* traps exist, but only under me - no separate display required */
Your("%s itch.", makeplural(body_part(TOE)));
return 0;
outtrapmap:
cls();
iflags.save_uinwater = u.uinwater, iflags.save_uburied = u.uburied;
u.uinwater = u.uburied = 0;
(void) unconstrain_map();
/* show chest traps first, so that subsequent floor trap display
will override if both types are present at the same location */
(void) detect_obj_traps(fobj, TRUE, cursed_src);
@@ -826,15 +1009,16 @@ outtrapmap:
/* redisplay hero unless sense_trap() revealed something at <ux,uy> */
glyph = glyph_at(u.ux, u.uy);
if (!(glyph_is_trap(glyph) || glyph_is_object(glyph)))
if (!(glyph_is_trap(glyph) || glyph_is_object(glyph))) {
newsym(u.ux, u.uy);
u.uinwater = iflags.save_uinwater, u.uburied = iflags.save_uburied;
iflags.save_uinwater = iflags.save_uburied = 0;
ter_typ |= TER_MON; /* for autodescribe at <u.ux,u.uy> */
}
You_feel("%s.", cursed_src ? "very greedy" : "entrapped");
/* wait for user to respond, then reset map display to normal */
display_nhwindow(WIN_MAP, TRUE);
docrt();
browse_map(ter_typ, "trap of interest");
reconstrain_map();
docrt(); /* redraw the screen to remove unseen traps from the map */
if (Underwater)
under_water(2);
if (u.uburied)
@@ -993,10 +1177,10 @@ struct obj **optr;
nomul(-rnd(10));
multi_reason = "gazing into a crystal ball";
nomovemsg = "";
if (obj->spe <= 0)
if (obj->spe <= 0) {
pline_The("vision is unclear.");
else {
int class;
} else {
int class, i;
int ret = 0;
makeknown(CRYSTAL_BALL);
@@ -1019,11 +1203,10 @@ struct obj **optr;
case '^':
ret = trap_detect((struct obj *) 0);
break;
default: {
int i = rn2(SIZE(level_detects));
default:
i = rn2(SIZE(level_detects));
You_see("%s, %s.", level_detects[i].what,
level_distance(level_detects[i].where));
}
ret = 0;
break;
}
@@ -1087,40 +1270,67 @@ void
do_mapping()
{
register int zx, zy;
boolean unconstrained;
iflags.save_uinwater = u.uinwater, iflags.save_uburied = u.uburied;
u.uinwater = u.uburied = 0;
unconstrained = unconstrain_map();
for (zx = 1; zx < COLNO; zx++)
for (zy = 0; zy < ROWNO; zy++)
show_map_spot(zx, zy);
u.uinwater = iflags.save_uinwater, u.uburied = iflags.save_uburied;
iflags.save_uinwater = iflags.save_uburied = 0;
if (!level.flags.hero_memory || Underwater) {
if (!level.flags.hero_memory || unconstrained) {
flush_screen(1); /* flush temp screen */
display_nhwindow(WIN_MAP, TRUE); /* wait */
/* browse_map() instead of display_nhwindow(WIN_MAP, TRUE) */
browse_map(TER_DETECT | TER_MAP | TER_TRP | TER_OBJ,
"anything of interest");
docrt();
}
reconstrain_map();
exercise(A_WIS, TRUE);
}
/* clairvoyance */
void
do_vicinity_map()
do_vicinity_map(sobj)
struct obj *sobj; /* scroll--actually fake spellbook--object */
{
register int zx, zy;
int lo_y = (u.uy - 5 < 0 ? 0 : u.uy - 5),
hi_y = (u.uy + 6 > ROWNO ? ROWNO : u.uy + 6),
lo_x = (u.ux - 9 < 1 ? 1 : u.ux - 9), /* avoid column 0 */
hi_x = (u.ux + 10 > COLNO ? COLNO : u.ux + 10);
struct monst *mtmp;
boolean unconstrained, refresh = FALSE, mdetected = FALSE,
extended = (sobj && sobj->blessed);
int lo_y = ((u.uy - 5 < 0) ? 0 : u.uy - 5),
hi_y = ((u.uy + 6 >= ROWNO) ? ROWNO - 1 : u.uy + 6),
lo_x = ((u.ux - 9 < 1) ? 1 : u.ux - 9), /* avoid column 0 */
hi_x = ((u.ux + 10 >= COLNO) ? COLNO - 1 : u.ux + 10),
ter_typ = TER_DETECT | TER_MAP | TER_TRP | TER_OBJ;
for (zx = lo_x; zx < hi_x; zx++)
for (zy = lo_y; zy < hi_y; zy++)
unconstrained = unconstrain_map();
for (zx = lo_x; zx <= hi_x; zx++)
for (zy = lo_y; zy <= hi_y; zy++) {
show_map_spot(zx, zy);
if (!level.flags.hero_memory || Underwater) {
if (extended && (mtmp = m_at(zx, zy)) != 0
&& mtmp->mx == zx && mtmp->my == zy) { /* skip worm tails */
int oldglyph = glyph_at(zx, zy);
map_monst(mtmp, FALSE);
if (glyph_at(zx, zy) != oldglyph)
mdetected = TRUE;
}
}
if (!level.flags.hero_memory || unconstrained || mdetected) {
flush_screen(1); /* flush temp screen */
display_nhwindow(WIN_MAP, TRUE); /* wait */
docrt();
if (extended || glyph_is_monster(glyph_at(u.ux, u.uy)))
ter_typ |= TER_MON;
if (extended)
EDetect_monsters |= I_SPECIAL;
browse_map(ter_typ, "anything of interest");
EDetect_monsters &= ~I_SPECIAL;
refresh = TRUE;
}
reconstrain_map();
if (refresh)
docrt();
}
/* convert a secret door into a normal door */
@@ -1334,12 +1544,10 @@ boolean via_warning;
exercise(A_WIS, TRUE);
if (!canspotmon(mtmp)) {
if (glyph_is_invisible(levl[x][y].glyph)) {
/* found invisible monster in a square
* which already has an 'I' in it.
* Logically, this should still take
* time and lead to a return(1), but
* if we did that the player would keep
* finding the same monster every turn.
/* Found invisible monster in a square which already has
* an 'I' in it. Logically, this should still take time
* and lead to a return 1, but if we did that the player
* would keep finding the same monster every turn.
*/
return -1;
} else {
@@ -1347,18 +1555,16 @@ boolean via_warning;
map_invisible(x, y);
}
} else if (!sensemon(mtmp))
You("find %s.", mtmp->mtame
? y_monnam(mtmp)
: a_monnam(mtmp));
You("find %s.",
mtmp->mtame ? y_monnam(mtmp) : a_monnam(mtmp));
return 1;
}
if (!canspotmon(mtmp)) {
if (mtmp->mundetected
&& (is_hider(mtmp->data)
|| mtmp->data->mlet == S_EEL))
&& (is_hider(mtmp->data) || mtmp->data->mlet == S_EEL))
if (via_warning) {
Your("warning senses cause you to take a second %s.",
Blind ? "to check nearby" : "look close by");
Blind ? "to check nearby" : "look close by");
display_nhwindow(WIN_MESSAGE, FALSE); /* flush messages */
}
mtmp->mundetected = 0;
@@ -1373,10 +1579,10 @@ dosearch0(aflag)
register int aflag; /* intrinsic autosearch vs explicit searching */
{
#ifdef GCC_BUG
/* some versions of gcc seriously muck up nested loops. if you get strange
crashes while searching in a version compiled with gcc, try putting
#define GCC_BUG in *conf.h (or adding -DGCC_BUG to CFLAGS in the
makefile).
/* Some old versions of gcc seriously muck up nested loops. If you get
* strange crashes while searching in a version compiled with gcc, try
* putting #define GCC_BUG in *conf.h (or adding -DGCC_BUG to CFLAGS in
* the makefile).
*/
volatile xchar x, y;
#else
@@ -1521,21 +1727,16 @@ int which_subset; /* when not full, whether to suppress objs and/or traps */
} else {
int x, y, glyph, levl_glyph, default_glyph;
uchar seenv;
unsigned save_swallowed;
struct monst *mtmp;
struct trap *t;
coord pos;
char buf[BUFSZ];
/* there is a TER_MAP bit too; we always show map regardless of it */
boolean keep_traps = (which_subset & TER_TRP) !=0,
keep_objs = (which_subset & TER_OBJ) != 0,
keep_mons = (which_subset & TER_MON) != 0; /* not used */
unsigned swallowed = u.uswallow; /* before unconstrain_map() */
save_swallowed = u.uswallow;
iflags.save_uinwater = u.uinwater, iflags.save_uburied = u.uburied;
u.uinwater = u.uburied = 0;
u.uswallow = 0;
if (iflags.save_uinwater || iflags.save_uburied)
if (unconstrain_map())
docrt();
default_glyph = cmap_to_glyph(level.flags.arboreal ? S_tree : S_stone);
/* for 'full', show the actual terrain for the entire level,
@@ -1560,8 +1761,8 @@ int which_subset; /* when not full, whether to suppress objs and/or traps */
glyph, which will never be a monster (unless it is
the invisible monster glyph, which is handled like
an object, replacing any object or trap at its spot) */
glyph = !save_swallowed ? glyph_at(x, y) : levl_glyph;
if (keep_mons && x == u.ux && y == u.uy && save_swallowed)
glyph = !swallowed ? glyph_at(x, y) : levl_glyph;
if (keep_mons && x == u.ux && y == u.uy && swallowed)
glyph = mon_to_glyph(u.ustuck);
else if (((glyph_is_monster(glyph)
|| glyph_is_warning(glyph)) && !keep_mons)
@@ -1631,17 +1832,10 @@ int which_subset; /* when not full, whether to suppress objs and/or traps */
/* allow player to move cursor around and get autodescribe feedback
based on what is visible now rather than what is on 'real' map */
pos.x = u.ux, pos.y = u.uy;
iflags.autodescribe = TRUE;
iflags.terrainmode = which_subset | TER_MAP; /* guaranteed non-zero */
getpos(&pos, FALSE, "anything of interest");
iflags.terrainmode = 0;
/* leave iflags.autodescribe 'on' even if it was previously 'off' */
which_subset |= TER_MAP; /* guarantee non-zero */
browse_map(which_subset, "anything of interest");
u.uinwater = iflags.save_uinwater, u.uburied = iflags.save_uburied;
iflags.save_uinwater = iflags.save_uburied = 0;
if (save_swallowed)
u.uswallow = 1;
reconstrain_map();
docrt(); /* redraw the screen, restoring regular map */
if (Underwater)
under_water(2);
+3 -3
View File
@@ -209,7 +209,7 @@ int x, y;
return FALSE;
} else if (Is_waterlevel(&u.uz)) {
if (verbose)
pline_The("water splashes and subsides.");
pline_The("%s splashes and subsides.", hliquid("water"));
return FALSE;
} else if ((IS_ROCK(levl[x][y].typ) && levl[x][y].typ != SDOOR
&& (levl[x][y].wall_info & W_NONDIGGABLE) != 0)
@@ -735,7 +735,7 @@ const char *fillmsg;
unearth_objs(x, y);
if (fillmsg)
pline(fillmsg, typ == LAVAPOOL ? "lava" : "water");
pline(fillmsg, hliquid(typ == LAVAPOOL ? "lava" : "water"));
if (u_spot && !(Levitation || Flying)) {
if (typ == LAVAPOOL)
(void) lava_effects();
@@ -780,7 +780,7 @@ coord *cc;
} else if (is_pool_or_lava(dig_x, dig_y)) {
pline_The("%s sloshes furiously for a moment, then subsides.",
is_lava(dig_x, dig_y) ? "lava" : "water");
hliquid(is_lava(dig_x, dig_y) ? "lava" : "water"));
wake_nearby(); /* splashing */
} else if (lev->typ == DRAWBRIDGE_DOWN
+23 -10
View File
@@ -1,4 +1,4 @@
/* NetHack 3.6 do.c $NHDT-Date: 1454033599 2016/01/29 02:13:19 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.153 $ */
/* NetHack 3.6 do.c $NHDT-Date: 1464487100 2016/05/29 01:58:20 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.156 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
@@ -103,7 +103,8 @@ boolean pushing;
You("find yourself on dry land again!");
} else if (lava && distu(rx, ry) <= 2) {
int dmg;
You("are hit by molten lava%c", Fire_resistance ? '.' : '!');
You("are hit by molten %s%c",
hliquid("lava"), Fire_resistance ? '.' : '!');
burn_away_slime();
dmg = d((Fire_resistance ? 1 : 3), 6);
losehp(Maybe_Half_Phys(dmg), /* lava damage */
@@ -379,18 +380,21 @@ register struct obj *obj;
You_hear("loud noises coming from the drain.");
break;
case RIN_SUSTAIN_ABILITY: /* KMH */
pline_The("water flow seems fixed.");
pline_The("%s flow seems fixed.", hliquid("water"));
break;
case RIN_GAIN_STRENGTH:
pline_The("water flow seems %ser now.",
pline_The("%s flow seems %ser now.",
hliquid("water"),
(obj->spe < 0) ? "weak" : "strong");
break;
case RIN_GAIN_CONSTITUTION:
pline_The("water flow seems %ser now.",
pline_The("%s flow seems %ser now.",
hliquid("water"),
(obj->spe < 0) ? "less" : "great");
break;
case RIN_INCREASE_ACCURACY: /* KMH */
pline_The("water flow %s the drain.",
pline_The("%s flow %s the drain.",
hliquid("water"),
(obj->spe < 0) ? "misses" : "hits");
break;
case RIN_INCREASE_DAMAGE:
@@ -456,10 +460,12 @@ register struct obj *obj;
pline_The("sink seems to blend into the floor for a moment.");
break;
case RIN_FIRE_RESISTANCE:
pline_The("hot water faucet flashes brightly for a moment.");
pline_The("hot %s faucet flashes brightly for a moment.",
hliquid("water"));
break;
case RIN_COLD_RESISTANCE:
pline_The("cold water faucet flashes brightly for a moment.");
pline_The("cold %s faucet flashes brightly for a moment.",
hliquid("water"));
break;
case RIN_PROTECTION_FROM_SHAPE_CHAN:
pline_The("sink looks nothing like a fountain.");
@@ -1532,13 +1538,20 @@ boolean at_stairs, falling, portal;
save_currentstate();
#endif
if ((annotation = get_annotation(&u.uz)))
if ((annotation = get_annotation(&u.uz)) != 0)
You("remember this level as %s.", annotation);
/* assume this will always return TRUE when changing level */
(void) in_out_region(u.ux, u.uy);
(void) pickup(1);
context.polearm.hitmon = NULL;
/* discard context which applied to previous level */
maybe_reset_pick(); /* for door or for box not accompanying hero */
reset_trapset(); /* even if to-be-armed trap obj is accompanying hero */
iflags.travelcc.x = iflags.travelcc.y = -1; /* travel destination cache */
context.polearm.hitmon = (struct monst *) 0; /* polearm target */
/* digging context is level-aware and can actually be resumed if
hero returns to the previous level without any intervening dig */
}
STATIC_OVL void
+154 -109
View File
@@ -8,6 +8,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 boolean FDECL(gather_locs_interesting, (int, int, int));
STATIC_DCL void FDECL(gather_locs, (coord **, int *, int));
STATIC_DCL void FDECL(auto_describe, (int, int));
STATIC_DCL void NDECL(do_mname);
@@ -63,8 +64,15 @@ const char *goal;
putstr(tmpwin, 0, "Use m or M to move the cursor to next monster.");
if (!iflags.terrainmode || (iflags.terrainmode & TER_OBJ) != 0)
putstr(tmpwin, 0, "Use o or O to move the cursor to next object.");
if (!iflags.terrainmode || (iflags.terrainmode & TER_MAP) != 0) {
/* both of these are primarily useful when choosing a travel
destination for the '_' command */
putstr(tmpwin, 0,
"Use d or D to move the cursor to next door or doorway.");
putstr(tmpwin, 0,
"Use x or X to move the cursor to unexplored location.");
}
if (!iflags.terrainmode) {
putstr(tmpwin, 0, "Use d or D to move the cursor to next door or doorway.");
if (getpos_hilitefunc)
putstr(tmpwin, 0, "Use $ to display valid locations.");
putstr(tmpwin, 0, "Use # to toggle automatic description.");
@@ -121,28 +129,63 @@ const void *b;
return dist_1 - dist_2;
}
#define GLOC_MONS 0
#define GLOC_OBJS 1
#define GLOC_DOOR 2
enum gloctypes {
GLOC_MONS = 0,
GLOC_OBJS,
GLOC_DOOR,
GLOC_EXPLORE,
boolean
gather_locs_glyphmatch(glyph, gloc)
int glyph, gloc;
NUM_GLOCS
};
#define IS_UNEXPLORED_LOC(x,y) \
(isok((x), (y)) \
&& glyph_is_cmap(levl[(x)][(y)].glyph) \
&& glyph_to_cmap(levl[(x)][(y)].glyph) == S_stone \
&& !levl[(x)][(y)].seenv)
STATIC_OVL boolean
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);
switch (gloc) {
default:
case GLOC_MONS: return (glyph_is_monster(glyph)
&& glyph != monnum_to_glyph(PM_LONG_WORM_TAIL));
case GLOC_OBJS: return (glyph_is_object(glyph)
&& glyph != objnum_to_glyph(BOULDER)
&& glyph != objnum_to_glyph(ROCK));
case GLOC_DOOR: return (glyph_is_cmap(glyph)
&& ((glyph_to_cmap(glyph) == S_hcdoor)
|| (glyph_to_cmap(glyph) == S_vcdoor)
|| (glyph_to_cmap(glyph) == S_hodoor)
|| (glyph_to_cmap(glyph) == S_vodoor)
|| (glyph_to_cmap(glyph) == S_ndoor)));
case GLOC_MONS:
/* unlike '/M', this skips monsters revealed by
warning glyphs and remembered unseen ones */
return (glyph_is_monster(glyph)
&& glyph != monnum_to_glyph(PM_LONG_WORM_TAIL));
case GLOC_OBJS:
return (glyph_is_object(glyph)
&& glyph != objnum_to_glyph(BOULDER)
&& glyph != objnum_to_glyph(ROCK));
case GLOC_DOOR:
return (glyph_is_cmap(glyph)
&& (is_cmap_door(glyph_to_cmap(glyph))
|| is_cmap_drawbridge(glyph_to_cmap(glyph))
|| glyph_to_cmap(glyph) == S_ndoor));
case GLOC_EXPLORE:
return (glyph_is_cmap(glyph)
&& (is_cmap_door(glyph_to_cmap(glyph))
|| is_cmap_drawbridge(glyph_to_cmap(glyph))
|| glyph_to_cmap(glyph) == S_ndoor
|| glyph_to_cmap(glyph) == S_room
|| glyph_to_cmap(glyph) == S_darkroom
|| glyph_to_cmap(glyph) == S_corr
|| glyph_to_cmap(glyph) == S_litcorr)
&& (IS_UNEXPLORED_LOC(x + 1, y)
|| IS_UNEXPLORED_LOC(x - 1, y)
|| IS_UNEXPLORED_LOC(x, y + 1)
|| IS_UNEXPLORED_LOC(x, y - 1)));
}
/*NOTREACHED*/
return FALSE;
}
/* gather locations for monsters or objects shown on the map */
@@ -152,7 +195,7 @@ coord **arr_p;
int *cnt_p;
int gloc;
{
int x, y, pass, glyph, idx;
int x, y, pass, idx;
/*
* We always include the hero's location even if there is no monster
@@ -169,14 +212,8 @@ int gloc;
for (pass = 0; pass < 2; pass++) {
for (x = 1; x < COLNO; x++)
for (y = 0; y < ROWNO; y++) {
/* TODO: if glyph is a pile glyph, convert to ordinary one
* in order to keep tail/boulder/rock check simple.
*/
glyph = glyph_at(x, y);
/* unlike '/M', this skips monsters revealed by
warning glyphs and remembered invisible ones */
if ((x == u.ux && y == u.uy)
|| gather_locs_glyphmatch(glyph, gloc)) {
|| gather_locs_interesting(x, y, gloc)) {
if (!pass) {
++*cnt_p;
} else {
@@ -291,18 +328,18 @@ coord *ccp;
boolean force;
const char *goal;
{
static const char pick_chars[] = ".,;:",
mMoOdDxX[] = "mMoOdDxX";
const char *cp;
int result = 0;
int cx, cy, i, c;
int sidx, tx, ty;
boolean msg_given = TRUE; /* clear message window by default */
boolean show_goal_msg = FALSE;
static const char pick_chars[] = ".,;:";
const char *cp;
boolean hilite_state = FALSE;
coord *monarr = (coord *) 0, *objarr = (coord *) 0,
*doorarr = (coord *) 0;
int moncount = 0, monidx = 0, objcount = 0, objidx = 0,
doorcount = 0, dooridx = 0;
coord *garr[NUM_GLOCS] = DUMMY;
int gcount[NUM_GLOCS] = DUMMY;
int gidx[NUM_GLOCS] = DUMMY;
if (!goal)
goal = "desired location";
@@ -412,6 +449,10 @@ const char *goal;
}
goto nxtc;
} else if (c == '#') {
/* unfortunately, using '#' as a command means we can't move
cursor to sinks, iron bars, and poison clouds; perhaps
when autodescribe is already on, next '#' should try to
move to '#' rather than to toggle off? (or ask; ick...) */
iflags.autodescribe = !iflags.autodescribe;
pline("Automatic description %sis %s.",
flags.verbose ? "of features under cursor " : "",
@@ -421,53 +462,30 @@ const char *goal;
msg_given = TRUE;
goto nxtc;
} else if (c == '@') { /* return to hero's spot */
/* reset 'm','M' and 'o','O'; otherwise, there's no way for player
/* reset 'm&M', 'o&O', &c; otherwise, there's no way for player
to achieve that except by manually cycling through all spots */
monidx = objidx = dooridx = 0;
for (i = 0; i < NUM_GLOCS; i++)
gidx[i] = 0;
cx = u.ux;
cy = u.uy;
goto nxtc;
} else if (c == 'm' || c == 'M') { /* nearest or farthest monster */
if (!monarr) {
gather_locs(&monarr, &moncount, GLOC_MONS);
monidx = 0; /* monarr[0] is hero's spot */
} else if ((cp = index(mMoOdDxX, c)) != 0) { /* 'm|M', 'o|O', &c */
/* nearest or farthest monster or object or door or unexplored */
int gtmp = (int) (cp - mMoOdDxX), /* 0..7 */
gloc = gtmp >> 1; /* 0..3 */
if (!garr[gloc]) {
gather_locs(&garr[gloc], &gcount[gloc], gloc);
gidx[gloc] = 0; /* garr[][0] is hero's spot */
}
if (c == 'm') {
monidx = (monidx + 1) % moncount;
} else {
if (--monidx < 0)
monidx = moncount - 1;
if (!(gtmp & 1)) { /* c=='m' || c=='o' || c=='d' || c=='x') */
gidx[gloc] = (gidx[gloc] + 1) % gcount[gloc];
} else { /* c=='M' || c=='O' || c=='D' || c=='X') */
if (--gidx[gloc] < 0)
gidx[gloc] = gcount[gloc] - 1;
}
cx = monarr[monidx].x;
cy = monarr[monidx].y;
goto nxtc;
} else if (c == 'o' || c == 'O') { /* nearest or farthest object */
if (!objarr) {
gather_locs(&objarr, &objcount, GLOC_OBJS);
objidx = 0; /* objarr[0] is hero's spot */
}
if (c == 'o') {
objidx = (objidx + 1) % objcount;
} else {
if (--objidx < 0)
objidx = objcount - 1;
}
cx = objarr[objidx].x;
cy = objarr[objidx].y;
goto nxtc;
} else if (c == 'd' || c == 'D') { /* door/doorway */
if (!doorarr) {
gather_locs(&doorarr, &doorcount, GLOC_DOOR);
dooridx = 0; /* objarr[0] is hero's spot */
}
if (c == 'd') {
dooridx = (dooridx + 1) % doorcount;
} else {
if (--dooridx < 0)
dooridx = doorcount - 1;
}
cx = doorarr[dooridx].x;
cy = doorarr[dooridx].y;
cx = garr[gloc][gidx[gloc]].x;
cy = garr[gloc][gidx[gloc]].y;
goto nxtc;
} else {
if (!index(quitchars, c)) {
@@ -475,9 +493,17 @@ const char *goal;
int pass, lo_x, lo_y, hi_x, hi_y, k = 0;
(void) memset((genericptr_t) matching, 0, sizeof matching);
for (sidx = 1; sidx < MAXPCHARS; sidx++)
for (sidx = 1; sidx < MAXPCHARS; sidx++) { /* [0] left as 0 */
if (IS_DOOR(sidx) || IS_WALL(sidx)
|| sidx == SDOOR || sidx == SCORR
|| glyph_to_cmap(k) == S_room
|| glyph_to_cmap(k) == S_darkroom
|| glyph_to_cmap(k) == S_corr
|| glyph_to_cmap(k) == S_litcorr)
continue;
if (c == defsyms[sidx].sym || c == (int) showsyms[sidx])
matching[sidx] = (char) ++k;
}
if (k) {
for (pass = 0; pass <= 1; pass++) {
/* pass 0: just past current pos to lower right;
@@ -488,35 +514,39 @@ const char *goal;
lo_x = (pass == 0 && ty == lo_y) ? cx + 1 : 1;
hi_x = (pass == 1 && ty == hi_y) ? cx : COLNO - 1;
for (tx = lo_x; tx <= hi_x; tx++) {
/* look at dungeon feature, not at
user-visible glyph */
k = back_to_glyph(tx, ty);
/* uninteresting background glyph */
/* first, look at what is currently visible
(might be monster) */
k = glyph_at(tx, ty);
if (glyph_is_cmap(k)
&& (IS_DOOR(levl[tx][ty].typ)
|| glyph_to_cmap(k) == S_room
|| glyph_to_cmap(k) == S_darkroom
|| glyph_to_cmap(k) == S_corr
|| glyph_to_cmap(k) == S_litcorr)) {
/* what hero remembers to be at tx,ty */
k = glyph_at(tx, ty);
&& matching[glyph_to_cmap(k)])
goto foundc;
/* next, try glyph that's remembered here
(might be trap or object) */
if (level.flags.hero_memory
/* !terrainmode: don't move to remembered
trap or object if not currently shown */
&& !iflags.terrainmode) {
k = levl[tx][ty].glyph;
if (glyph_is_cmap(k)
&& matching[glyph_to_cmap(k)])
goto foundc;
}
if (glyph_is_cmap(k)
&& matching[glyph_to_cmap(k)]
&& (levl[tx][ty].seenv
|| iflags.terrainmode)
&& !IS_WALL(levl[tx][ty].typ)
&& levl[tx][ty].typ != SDOOR
&& glyph_to_cmap(k) != S_room
&& glyph_to_cmap(k) != S_corr
&& glyph_to_cmap(k) != S_litcorr) {
cx = tx, cy = ty;
if (msg_given) {
clear_nhwindow(WIN_MESSAGE);
msg_given = FALSE;
}
goto nxtc;
/* last, try actual terrain here (shouldn't
we be using lastseentyp[][] instead?) */
if (levl[tx][ty].seenv) {
k = back_to_glyph(tx, ty);
if (glyph_is_cmap(k)
&& matching[glyph_to_cmap(k)])
goto foundc;
}
continue;
foundc:
cx = tx, cy = ty;
if (msg_given) {
clear_nhwindow(WIN_MESSAGE);
msg_given = FALSE;
}
goto nxtc;
} /* column */
} /* row */
} /* pass */
@@ -539,10 +569,8 @@ const char *goal;
} /* !quitchars */
if (force)
goto nxtc;
if (!iflags.terrainmode) {
pline("Done.");
msg_given = FALSE; /* suppress clear */
}
pline("Done.");
msg_given = FALSE; /* suppress clear */
cx = -1;
cy = 0;
result = 0; /* not -1 */
@@ -563,10 +591,9 @@ const char *goal;
clear_nhwindow(WIN_MESSAGE);
ccp->x = cx;
ccp->y = cy;
if (monarr)
free((genericptr_t) monarr);
if (objarr)
free((genericptr_t) objarr);
for (i = 0; i < NUM_GLOCS; i++)
if (garr[i])
free((genericptr_t) garr[i]);
getpos_hilitefunc = (void FDECL((*), (int))) 0;
return result;
}
@@ -1564,6 +1591,24 @@ rndcolor()
: c_obj_colors[k];
}
static NEARDATA const char *const hliquids[] = {
"yoghurt", "oobleck", "clotted blood", "diluted water", "purified water",
"instant coffee", "tea", "herbal infusion", "liquid rainbow",
"creamy foam", "mulled wine", "bouillon", "nectar", "grog", "flubber",
"ketchup", "slow light", "oil", "vinaigrette", "liquid crystal", "honey",
"caramel sauce", "ink", "aqueous humour", "milk substitute", "fruit juice",
"glowing lava", "gastric acid", "mineral water", "cough syrup", "quicksilver",
"sweet vitriol", "grey goo", "pink slime",
};
const char *
hliquid(liquidpref)
const char *liquidpref;
{
return (Hallucination || !liquidpref) ? hliquids[rn2(SIZE(hliquids))]
: liquidpref;
}
/* Aliases for road-runner nemesis
*/
static const char *const coynames[] = {
@@ -1586,7 +1631,7 @@ char *buf;
Sprintf(buf, "%s - %s",
x_monnam(mtmp, ARTICLE_NONE, (char *) 0, 0, TRUE),
mtmp->mcan ? coynames[SIZE(coynames) - 1]
: coynames[rn2(SIZE(coynames) - 1)]);
: coynames[mtmp->m_id % (SIZE(coynames) - 1)]);
}
return buf;
}
+2 -1
View File
@@ -773,7 +773,8 @@ Amulet_off()
setworn((struct obj *) 0, W_AMUL);
if (!breathless(youmonst.data) && !amphibious(youmonst.data)
&& !Swimming) {
You("suddenly inhale an unhealthy amount of water!");
You("suddenly inhale an unhealthy amount of %s!",
hliquid("water"));
(void) drown();
}
return;
+304 -16
View File
@@ -11,6 +11,10 @@ extern boolean notonhead;
STATIC_DCL boolean FDECL(dog_hunger, (struct monst *, struct edog *));
STATIC_DCL int FDECL(dog_invent, (struct monst *, struct edog *, int));
STATIC_DCL int FDECL(dog_goal, (struct monst *, struct edog *, int, int, int));
STATIC_DCL struct monst *FDECL(find_targ, (struct monst *, int, int, int));
STATIC_OVL int FDECL(find_friends, (struct monst *, struct monst *, int));
STATIC_DCL struct monst *FDECL(best_target, (struct monst *));
STATIC_DCL long FDECL(score_targ, (struct monst *, struct monst *));
STATIC_DCL boolean FDECL(can_reach_location, (struct monst *, XCHAR_P,
XCHAR_P, XCHAR_P, XCHAR_P));
STATIC_DCL boolean FDECL(could_reach_item, (struct monst *, XCHAR_P, XCHAR_P));
@@ -280,8 +284,8 @@ boolean devour;
Strcpy(objnambuf, xname(obj));
iflags.suppress_price--;
}
/* It's a reward if it's DOGFOOD and the player dropped/threw it. */
/* We know the player had it if invlet is set -dlc */
/* It's a reward if it's DOGFOOD and the player dropped/threw it.
We know the player had it if invlet is set. -dlc */
if (dogfood(mtmp, obj) == DOGFOOD && obj->invlet)
#ifdef LINT
edog->apport = 0;
@@ -347,8 +351,8 @@ boolean devour;
/* hunger effects -- returns TRUE on starvation */
STATIC_OVL boolean
dog_hunger(mtmp, edog)
register struct monst *mtmp;
register struct edog *edog;
struct monst *mtmp;
struct edog *edog;
{
if (monstermoves > edog->hungrytime + 500) {
if (!carnivorous(mtmp->data) && !herbivorous(mtmp->data)) {
@@ -419,7 +423,8 @@ int udist;
edog->droptime = monstermoves;
}
} else {
if ((obj = level.objects[omx][omy]) && !index(nofetch, obj->oclass)
if ((obj = level.objects[omx][omy]) != 0
&& !index(nofetch, obj->oclass)
#ifdef MAIL
&& obj->otyp != SCR_MAIL
#endif
@@ -557,16 +562,12 @@ int after, udist, whappr;
appr = 1;
}
/* if you have dog food it'll follow you more closely */
if (appr == 0) {
obj = invent;
while (obj) {
if (appr == 0)
for (obj = invent; obj; obj = obj->nobj)
if (dogfood(mtmp, obj) == DOGFOOD) {
appr = 1;
break;
}
obj = obj->nobj;
}
}
} else
appr = 1; /* gtyp != UNDEF */
if (mtmp->mconf)
@@ -585,7 +586,7 @@ int after, udist, whappr;
} else {
/* assume master hasn't moved far, and reuse previous goal */
if (edog && edog->ogoal.x
&& ((edog->ogoal.x != omx) || (edog->ogoal.y != omy))) {
&& (edog->ogoal.x != omx || edog->ogoal.y != omy)) {
gx = edog->ogoal.x;
gy = edog->ogoal.y;
edog->ogoal.x = 0;
@@ -610,6 +611,236 @@ int after, udist, whappr;
return appr;
}
STATIC_OVL struct monst *
find_targ(mtmp, dx, dy, maxdist)
register struct monst *mtmp;
int dx, dy;
int maxdist;
{
struct monst *targ = 0;
int curx = mtmp->mx, cury = mtmp->my;
int dist = 0;
/* Walk outwards */
for ( ; dist < maxdist; ++dist) {
curx += dx;
cury += dy;
if (!isok(curx, cury))
break;
/* FIXME: Check if we hit a wall/door/boulder to
* short-circuit unnecessary subsequent checks
*/
/* If we can't see up to here, forget it - will this
* mean pets in corridors don't breathe at monsters
* in rooms? If so, is that necessarily bad?
*/
if (!m_cansee(mtmp, curx, cury))
break;
targ = m_at(curx, cury);
if (curx == mtmp->mux && cury == mtmp->muy)
return &youmonst;
if (targ) {
/* Is the monster visible to the pet? */
if ((!targ->minvis || perceives(mtmp->data)) &&
!targ->mundetected)
break;
/* If the pet can't see it, it assumes it aint there */
targ = 0;
}
}
return targ;
}
STATIC_OVL int
find_friends(mtmp, mtarg, maxdist)
struct monst *mtmp, *mtarg;
int maxdist;
{
struct monst *pal;
int dx = sgn(mtarg->mx - mtmp->mx),
dy = sgn(mtarg->my - mtmp->my);
int curx = mtarg->mx, cury = mtarg->my;
int dist = distmin(mtarg->mx, mtarg->my, mtmp->mx, mtmp->my);
for ( ; dist <= maxdist; ++dist) {
curx += dx;
cury += dy;
if (!isok(curx, cury))
return 0;
/* If the pet can't see beyond this point, don't
* check any farther
*/
if (!m_cansee(mtmp, curx, cury))
return 0;
/* Does pet think you're here? */
if (mtmp->mux == curx && mtmp->muy == cury)
return 1;
pal = m_at(curx, cury);
if (pal) {
if (pal->mtame) {
/* Pet won't notice invisible pets */
if (!pal->minvis || perceives(mtmp->data))
return 1;
} else {
/* Quest leaders and guardians are always seen */
if (pal->data->msound == MS_LEADER
|| pal->data->msound == MS_GUARDIAN)
return 1;
}
}
}
return 0;
}
STATIC_OVL long
score_targ(mtmp, mtarg)
struct monst *mtmp, *mtarg;
{
long score = 0L;
/* If the monster is confused, normal scoring is disrupted -
* anything may happen
*/
/* Give 1 in 3 chance of safe breathing even if pet is confused or
* if you're on the quest start level */
if (!mtmp->mconf || !rn2(3) || Is_qstart(&u.uz)) {
aligntyp align1 = A_NONE, align2 = A_NONE; /* For priests, minions */
boolean faith1 = TRUE, faith2 = TRUE;
if (mtmp->isminion)
align1 = EMIN(mtmp)->min_align;
else if (mtmp->ispriest)
align1 = EPRI(mtmp)->shralign;
else
faith1 = FALSE;
if (mtarg->isminion)
align2 = EMIN(mtarg)->min_align; /* MAR */
else if (mtarg->ispriest)
align2 = EPRI(mtarg)->shralign; /* MAR */
else
faith2 = FALSE;
/* Never target quest friendlies */
if (mtarg->data->msound == MS_LEADER
|| mtarg->data->msound == MS_GUARDIAN)
return -5000L;
/* D: Fixed angelic beings using gaze attacks on coaligned priests */
if (faith1 && faith2 && align1 == align2 && mtarg->mpeaceful) {
score -= 5000L;
return score;
}
/* Is monster adjacent? */
if (distmin(mtmp->mx, mtmp->my, mtarg->mx, mtarg->my) <= 1) {
score -= 3000L;
return score;
}
/* Is the monster peaceful or tame? */
if (/*mtarg->mpeaceful ||*/ mtarg->mtame || mtarg == &youmonst) {
/* Pets will never be targeted */
score -= 3000L;
return score;
}
/* Is master/pet behind monster? Check up to 15 squares beyond pet. */
if (find_friends(mtmp, mtarg, 15)) {
score -= 3000L;
return score;
}
/* Target hostile monsters in preference to peaceful ones */
if (!mtarg->mpeaceful)
score += 10;
/* Is the monster passive? Don't waste energy on it, if so */
if (mtarg->data->mattk[0].aatyp == AT_NONE)
score -= 1000;
/* Even weak pets with breath attacks shouldn't take on very
low-level monsters. Wasting breath on lichens is ridiculous. */
if ((mtarg->m_lev < 2 && mtmp->m_lev > 5)
|| (mtmp->m_lev > 12 && mtarg->m_lev < mtmp->m_lev - 9
&& u.ulevel > 8 && mtarg->m_lev < u.ulevel - 7))
score -= 25;
/* And pets will hesitate to attack vastly stronger foes.
This penalty will be discarded if master's in trouble. */
if (mtarg->m_lev > mtmp->m_lev + 4L)
score -= (mtarg->m_lev - mtmp->m_lev) * 20L;
/* All things being the same, go for the beefiest monster. This
bonus should not be large enough to override the pet's aversion
to attacking much stronger monsters. */
score += mtarg->m_lev * 2 + mtarg->mhp / 3;
}
/* Fuzz factor to make things less predictable when very
similar targets are abundant. */
score += rnd(5);
/* Pet may decide not to use ranged attack when confused */
if (mtmp->mconf && !rn2(3))
score -= 1000;
return score;
}
STATIC_OVL struct monst *
best_target(mtmp)
struct monst *mtmp; /* Pet */
{
int dx, dy;
long bestscore = -40000L, currscore;
struct monst *best_targ = 0, *temp_targ = 0;
/* Help! */
if (!mtmp)
return 0;
/* If the pet is blind, it's not going to see any target */
if (!mtmp->mcansee)
return 0;
/* Search for any monsters lined up with the pet, within an arbitrary
* distance from the pet (7 squares, even along diagonals). Monsters
* are assigned scores and the best score is chosen.
*/
for (dy = -1; dy < 2; ++dy) {
for (dx = -1; dx < 2; ++dx) {
if (!dx && !dy)
continue;
/* Traverse the line to find the first monster within 7
* squares. Invisible monsters are skipped (if the
* pet doesn't have see invisible).
*/
temp_targ = find_targ(mtmp, dx, dy, 7);
/* Nothing in this line? */
if (!temp_targ)
continue;
/* Decide how attractive the target is */
currscore = score_targ(mtmp, temp_targ);
if (currscore > bestscore) {
bestscore = currscore;
best_targ = temp_targ;
}
}
}
/* Filter out targets the pet doesn't like */
if (bestscore < 0L)
best_targ = 0;
return best_targ;
}
/* return 0 (no move), 1 (move) or 2 (dead) */
int
dog_move(mtmp, after)
@@ -872,6 +1103,63 @@ int after; /* this is extra fast monster movement */
nxti:
;
}
/* Pet hasn't attacked anything but is considering moving -
* now's the time for ranged attacks. Note that the pet can move
* after it performs its ranged attack. Should this be changed?
*/
{
struct monst *mtarg;
int hungry = 0;
/* How hungry is the pet? */
if (!mtmp->isminion) {
struct edog *dog = EDOG(mtmp);
hungry = (monstermoves > (dog->hungrytime + 300));
}
/* Identify the best target in a straight line from the pet;
* if there is such a target, we'll let the pet attempt an
* attack.
*/
mtarg = best_target(mtmp);
/* Hungry pets are unlikely to use breath/spit attacks */
if (mtarg && (!hungry || !rn2(5))) {
int mstatus;
if (mtarg == &youmonst) {
if (mattacku(mtmp))
return 2;
} else {
mstatus = mattackm(mtmp, mtarg);
/* Shouldn't happen, really */
if (mstatus & MM_AGR_DIED)
return 2;
/* Allow the targeted nasty to strike back - if
* the targeted beast doesn't have a ranged attack,
* nothing will happen.
*/
if ((mstatus & MM_HIT) && !(mstatus & MM_DEF_DIED)
&& rn2(4) && mtarg != &youmonst) {
/* Can monster see? If it can, it can retaliate
* even if the pet is invisible, since it'll see
* the direction from which the ranged attack came;
* if it's blind or unseeing, it can't retaliate
*/
if (mtarg->mcansee && haseyes(mtarg->data)) {
mstatus = mattackm(mtarg, mtmp);
if (mstatus & MM_DEF_DIED)
return 2;
}
}
}
}
}
newdogpos:
if (nix != omx || niy != omy) {
boolean wasseen;
@@ -898,7 +1186,7 @@ newdogpos:
/* describe top item of pile, not necessarily cursed item itself;
don't use glyph_at() here--it would return the pet but we want
to know whether an object is remembered at this map location */
struct obj *o = (!Hallucination
struct obj *o = (!Hallucination && level.flags.hero_memory
&& glyph_is_object(levl[nix][niy].glyph))
? vobj_at(nix, niy) : 0;
const char *what = o ? distant_name(o, doname) : something;
@@ -1016,12 +1304,12 @@ wantdoor(x, y, distance)
int x, y;
genericptr_t distance;
{
int ndist;
int ndist, *dist_ptr = (int *) distance;
if (*(int *) distance > (ndist = distu(x, y))) {
if (*dist_ptr > (ndist = distu(x, y))) {
gx = x;
gy = y;
*(int *) distance = ndist;
*dist_ptr = ndist;
}
}
+1 -1
View File
@@ -947,7 +947,7 @@ dokick()
}
if (is_pool(x, y) ^ !!u.uinwater) {
/* objects normally can't be removed from water by kicking */
You("splash some water around.");
You("splash some %s around.", hliquid("water"));
return 1;
}
+8 -2
View File
@@ -544,9 +544,15 @@ int x, y;
}
if (!Passes_walls || !(may_pass = may_passwall(x, y))) {
if (IS_ROCK(levl[x][y].typ) || closed_door(x, y)) {
boolean odoor_diag = (IS_DOOR(levl[x][y].typ)
&& (levl[x][y].doormask & D_ISOPEN)
&& (u.ux - x) && (u.uy - y));
if (IS_ROCK(levl[x][y].typ) || closed_door(x, y) || odoor_diag) {
const char *s;
if (odoor_diag)
You("hit the door edge!");
pline("Ouch!");
if (IS_TREE(levl[x][y].typ))
s = "bumping into a tree";
@@ -729,7 +735,7 @@ boolean verbose;
u.utraptype == TT_WEB
? "web"
: u.utraptype == TT_LAVA
? "lava"
? hliquid("lava")
: u.utraptype == TT_INFLOOR
? surface(u.ux, u.uy)
: u.utraptype == TT_BURIEDBALL ? "buried ball"
+1 -1
View File
@@ -169,7 +169,7 @@ const struct symdef defsyms[MAXPCHARS] = {
{ '|', "grave", C(CLR_GRAY) }, /* grave */
{ '\\', "opulent throne", C(HI_GOLD) }, /* throne */
/*30*/ { '#', "sink", C(CLR_GRAY) }, /* sink */
{ '{', "fountain", C(CLR_BLUE) }, /* fountain */
{ '{', "fountain", C(CLR_BRIGHT_BLUE) }, /* fountain */
{ '}', "water", C(CLR_BLUE) }, /* pool */
{ '.', "ice", C(CLR_CYAN) }, /* ice */
{ '}', "molten lava", C(CLR_RED) }, /* lava */
+36 -10
View File
@@ -1,4 +1,4 @@
/* NetHack 3.6 eat.c $NHDT-Date: 1454715969 2016/02/05 23:46:09 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.163 $ */
/* NetHack 3.6 eat.c $NHDT-Date: 1466289475 2016/06/18 22:37:55 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.169 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
@@ -619,7 +619,9 @@ boolean allowmsg;
and also shouldn't eat current species when polymorphed
(even if having the form of something which doesn't care
about cannibalism--hero's innate traits aren't altered) */
&& (your_race(fptr) || (Upolyd && same_race(youmonst.data, fptr)))) {
&& (your_race(fptr)
|| (Upolyd && same_race(youmonst.data, fptr))
|| (u.ulycn >= LOW_PM && were_beastie(pm) == u.ulycn))) {
if (allowmsg) {
if (Upolyd && your_race(fptr))
You("have a bad feeling deep inside.");
@@ -2012,12 +2014,23 @@ eatspecial()
vault_gd_watching(GD_EATGOLD);
return;
}
if (objects[otmp->otyp].oc_material == PAPER) {
#ifdef MAIL
if (otmp->otyp == SCR_MAIL) {
/* no nutrition */
pline("This junk mail is less than satisfying.");
}
if (otmp->otyp == SCR_MAIL)
/* no nutrition */
pline("This junk mail is less than satisfying.");
else
#endif
if (otmp->otyp == SCR_SCARE_MONSTER)
/* to eat scroll, hero is currently polymorphed into a monster */
pline("Yuck%c", otmp->blessed ? '!' : '.');
else if (otmp->oclass == SCROLL_CLASS
/* check description after checking for specific scrolls */
&& !strcmpi(OBJ_DESCR(objects[otmp->otyp]), "YUM YUM"))
pline("Yum%c", otmp->blessed ? '!' : '.');
else
pline("Needs salt...");
}
if (otmp->oclass == POTION_CLASS) {
otmp->quan++; /* dopotion() does a useup() */
(void) dopotion(otmp);
@@ -2451,8 +2464,11 @@ doeat()
u.uconduct.unvegan++;
u.uconduct.food++;
if (otmp->cursed)
if (otmp->cursed) {
(void) rottenfood(otmp);
nodelicious = TRUE;
} else if (objects[otmp->otyp].oc_material == PAPER)
nodelicious = TRUE;
if (otmp->oclass == WEAPON_CLASS && otmp->opoisoned) {
pline("Ecch - that must have been poisonous!");
@@ -2461,7 +2477,7 @@ doeat()
losehp(rnd(15), xname(otmp), KILLED_BY_AN);
} else
You("seem unaffected by the poison.");
} else if (!otmp->cursed && !nodelicious) {
} else if (!nodelicious) {
pline("%s%s is delicious!",
(obj_is_pname(otmp)
&& otmp->oartifact < ART_ORB_OF_DETECTION)
@@ -3009,6 +3025,16 @@ int corpsecheck; /* 0, no check, 1, corpses, 2, tinnable corpses */
char qsfx[QBUFSZ];
boolean one = (otmp->quan == 1L);
/* if blind and without gloves, attempting to eat (or tin or
offer) a cockatrice corpse is fatal before asking whether
or not to use it; otherwise, 'm<dir>' followed by 'e' could
be used to locate cockatrice corpses without touching them */
if (otmp->otyp == CORPSE && will_feel_cockatrice(otmp, FALSE)) {
feel_cockatrice(otmp, FALSE);
/* if life-saved (or poly'd into stone golem), terminate
attempt to eat off floor */
return (struct obj *) 0;
}
/* "There is <an object> here; <verb> it?" or
"There are <N objects> here; <verb> one?" */
Sprintf(qbuf, "There %s ", otense(otmp, "are"));
@@ -3026,8 +3052,8 @@ skipfloor:
/* We cannot use ALL_CLASSES since that causes getobj() to skip its
* "ugly checks" and we need to check for inedible items.
*/
otmp =
getobj(feeding ? allobj : offering ? offerfodder : comestibles, verb);
otmp = getobj(feeding ? allobj : offering ? offerfodder : comestibles,
verb);
if (corpsecheck && otmp && !(offering && otmp->oclass == AMULET_CLASS))
if (otmp->otyp != CORPSE || (corpsecheck == 2 && !tinnable(otmp))) {
You_cant("%s that!", verb);
+3 -1
View File
@@ -781,6 +781,8 @@ int how;
u.ugrave_arise = NON_PM;
HUnchanging = 0L;
curs_on_u();
if (!context.mon_moving)
endmultishot(FALSE);
}
/*
@@ -1678,7 +1680,7 @@ boolean ask;
pfx = !strncmpi(buf, "the ", 3) ? 0
: !strncmpi(buf, "an ", 3) ? 1
: !strncmpi(buf, "a ", 2) ? 2
: !isdigit(buf[2]) ? 4 : 0;
: !digit(buf[2]) ? 4 : 0;
if (class_header)
++pfx;
Sprintf(buftoo, "%*s%s", pfx, "", buf);
+3 -2
View File
@@ -185,11 +185,12 @@ register int x, y;
else if (IS_AIR(lev->typ) && Is_airlevel(&u.uz))
return "air";
else if (is_pool(x, y))
return (Underwater && !Is_waterlevel(&u.uz)) ? "bottom" : "water";
return (Underwater && !Is_waterlevel(&u.uz))
? "bottom" : hliquid("water");
else if (is_ice(x, y))
return "ice";
else if (is_lava(x, y))
return "lava";
return hliquid("lava");
else if (lev->typ == DRAWBRIDGE_DOWN)
return "bridge";
else if (IS_ALTAR(levl[x][y].typ))
+74 -60
View File
@@ -188,6 +188,7 @@ STATIC_DCL boolean FDECL(make_compressed_name, (const char *, char *));
#ifndef USE_FCNTL
STATIC_DCL char *FDECL(make_lockname, (const char *, char *));
#endif
STATIC_DCL void FDECL(set_configfile_name, (const char *));
STATIC_DCL FILE *FDECL(fopen_config_file, (const char *, int));
STATIC_DCL int FDECL(get_uchars, (FILE *, char *, char *, uchar *, BOOLEAN_P,
int, const char *));
@@ -1821,7 +1822,7 @@ const char *filename;
/* ---------- BEGIN CONFIG FILE HANDLING ----------- */
const char *configfile =
const char *default_configfile =
#ifdef UNIX
".nethackrc";
#else
@@ -1837,7 +1838,7 @@ const char *configfile =
#endif
/* used for messaging */
char lastconfigfile[BUFSZ];
char configfile[BUFSZ];
#ifdef MSDOS
/* conflict with speed-dial under windows
@@ -1850,6 +1851,16 @@ char lastconfigfile[BUFSZ];
const char *backward_compat_configfile = "nethack.cnf";
#endif
/* remember the name of the file we're accessing;
if may be used in option reject messages */
STATIC_OVL void
set_configfile_name(fname)
const char *fname;
{
(void) strncpy(configfile, fname, sizeof configfile - 1);
configfile[sizeof configfile - 1] = '\0';
}
#ifndef MFLOPPY
#define fopenp fopen
#endif
@@ -1865,84 +1876,86 @@ int src;
char *envp;
#endif
if (src == SET_IN_SYS) {
/* SYSCF_FILE; if we can't open it, caller will bail */
if (filename && *filename) {
set_configfile_name(fqname(filename, SYSCONFPREFIX, 0));
fp = fopenp(configfile, "r");
} else
fp = (FILE *) 0;
return fp;
}
/* If src != SET_IN_SYS, "filename" is an environment variable, so it
* should hang around. If set, it is expected to be a full path name
* (if relevant) */
if (filename) {
* (if relevant)
*/
if (filename && *filename) {
set_configfile_name(filename);
#ifdef UNIX
if ((src != SET_IN_SYS) && access(filename, 4) == -1) {
/* 4 is R_OK on newer systems */
if (access(configfile, 4) == -1) { /* 4 is R_OK on newer systems */
/* nasty sneaky attempt to read file through
* NetHack's setuid permissions -- this is the only
* place a file name may be wholly under the player's
* control (but SYSCF_FILE is not under the player's
* control so it's OK).
*/
raw_printf("Access to %s denied (%d).", filename, errno);
raw_printf("Access to %s denied (%d).", configfile, errno);
wait_synch();
/* fall through to standard names */
} else
#endif
#ifdef PREFIXES_IN_USE
if (src == SET_IN_SYS) {
(void) strncpy(lastconfigfile, fqname(filename, SYSCONFPREFIX, 0),
BUFSZ - 1);
} else
#endif
/* always honor sysconf first before anything else */
(void) strncpy(lastconfigfile, filename, BUFSZ - 1);
lastconfigfile[BUFSZ - 1] = '\0';
if ((fp = fopenp(lastconfigfile, "r")) != (FILE *) 0)
return fp;
if ((fp = fopenp(filename, "r")) != (FILE *) 0) {
if ((fp = fopenp(configfile, "r")) != (FILE *) 0) {
return fp;
#if defined(UNIX) || defined(VMS)
} else {
/* access() above probably caught most problems for UNIX */
raw_printf("Couldn't open requested config file %s (%d).",
filename, errno);
configfile, errno);
wait_synch();
/* fall through to standard names */
#endif
}
}
/* fall through to standard names */
#if defined(MICRO) || defined(MAC) || defined(__BEOS__) || defined(WIN32)
if ((fp = fopenp(fqname(configfile, CONFIGPREFIX, 0), "r")) != (FILE *) 0)
return fp;
if ((fp = fopenp(configfile, "r")) != (FILE *) 0)
set_configfile_name(fqname(default_configfile, CONFIGPREFIX, 0));
if ((fp = fopenp(configfile, "r")) != (FILE *) 0) {
return fp;
} else if (strcmp(default_configfile, configfile)) {
set_configfile_name(default_configfile);
if ((fp = fopenp(configfile, "r")) != (FILE *) 0)
return fp;
}
#ifdef MSDOS
if ((fp = fopenp(fqname(backward_compat_configfile, CONFIGPREFIX, 0),
"r")) != (FILE *) 0)
return fp;
if ((fp = fopenp(backward_compat_configfile, "r")) != (FILE *) 0)
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)) {
set_configfile_name(backward_compat_configfile);
if ((fp = fopenp(configfile, "r")) != (FILE *) 0)
return fp;
}
#endif
#else
/* constructed full path names don't need fqname() */
#ifdef VMS
(void) strncpy(lastconfigfile, fqname("nethackini", CONFIGPREFIX, 0),
BUFSZ - 1);
lastconfigfile[BUFSZ - 1] = '\0';
if ((fp = fopenp(lastconfigfile, "r")) != (FILE *) 0) {
/* no punctuation, so might be a logical name */
set_configfile_name(fqname("nethackini", CONFIGPREFIX, 0));
if ((fp = fopenp(configfile, "r")) != (FILE *) 0)
return fp;
}
(void) strncpy(lastconfigfile, "sys$login:nethack.ini", BUFSZ - 1);
lastconfigfile[BUFSZ - 1] = '\0';
if ((fp = fopenp(lastconfigfile, "r")) != (FILE *) 0) {
set_configfile_name("sys$login:nethack.ini");
if ((fp = fopenp(configfile, "r")) != (FILE *) 0)
return fp;
}
envp = nh_getenv("HOME");
if (!envp)
if (!envp || !*envp)
Strcpy(tmp_config, "NetHack.cnf");
else
Sprintf(tmp_config, "%s%s", envp, "NetHack.cnf");
(void) strncpy(lastconfigfile, tmp_config, BUFSZ - 1);
lastconfigfile[BUFSZ - 1] = '\0';
if ((fp = fopenp(tmp_config, "r")) != (FILE *) 0)
Sprintf(tmp_config, "%s%s%s", envp,
!index(":]>/", envp[strlen(envp) - 1]) ? "/" : "",
"NetHack.cnf");
set_configfile_name(tmp_config);
if ((fp = fopenp(configfile, "r")) != (FILE *) 0)
return fp;
#else /* should be only UNIX left */
envp = nh_getenv("HOME");
@@ -1951,43 +1964,41 @@ int src;
else
Sprintf(tmp_config, "%s/%s", envp, ".nethackrc");
(void) strncpy(lastconfigfile, tmp_config, BUFSZ - 1);
lastconfigfile[BUFSZ - 1] = '\0';
if ((fp = fopenp(lastconfigfile, "r")) != (FILE *) 0)
set_configfile_name(tmp_config);
if ((fp = fopenp(configfile, "r")) != (FILE *) 0)
return fp;
#if defined(__APPLE__)
#if defined(__APPLE__) /* UNIX+__APPLE__ => MacOSX */
/* try an alternative */
if (envp) {
/* OSX-style configuration settings */
Sprintf(tmp_config, "%s/%s", envp,
"Library/Preferences/NetHack Defaults");
(void) strncpy(lastconfigfile, tmp_config, BUFSZ - 1);
lastconfigfile[BUFSZ - 1] = '\0';
if ((fp = fopenp(lastconfigfile, "r")) != (FILE *) 0)
set_configfile_name(tmp_config);
if ((fp = fopenp(configfile, "r")) != (FILE *) 0)
return fp;
/* may be easier for user to edit if filename as '.txt' suffix */
Sprintf(tmp_config, "%s/%s", envp,
"Library/Preferences/NetHack Defaults.txt");
(void) strncpy(lastconfigfile, tmp_config, BUFSZ - 1);
lastconfigfile[BUFSZ - 1] = '\0';
if ((fp = fopenp(lastconfigfile, "r")) != (FILE *) 0)
set_configfile_name(tmp_config);
if ((fp = fopenp(configfile, "r")) != (FILE *) 0)
return fp;
}
#endif
#endif /*__APPLE__*/
if (errno != ENOENT) {
const char *details;
/* e.g., problems when setuid NetHack can't search home
* directory restricted to user */
/* e.g., problems when setuid NetHack can't search home
directory restricted to user */
#if defined(NHSTDC) && !defined(NOTSTDC)
if ((details = strerror(errno)) == 0)
#endif
details = "";
raw_printf("Couldn't open default config file %s %s(%d).",
lastconfigfile, details, errno);
configfile, details, errno);
wait_synch();
}
#endif /* Unix */
#endif
#endif /* !VMS => Unix */
#endif /* !(MICRO || MAC || __BEOS__ || WIN32) */
return (FILE *) 0;
}
@@ -2252,6 +2263,9 @@ int src;
free((genericptr_t) sysopt.debugfiles);
sysopt.debugfiles = dupstr(bufp);
}
} else if (src == SET_IN_SYS && match_varname(buf, "GENERICUSERS", 12)) {
if (sysopt.genericusers) free(sysopt.genericusers);
sysopt.genericusers = dupstr(bufp);
} else if (src == SET_IN_SYS && match_varname(buf, "SUPPORT", 7)) {
if (sysopt.support)
free((genericptr_t) sysopt.support);
+19 -15
View File
@@ -337,7 +337,8 @@ drinkfountain()
{
register struct monst *mtmp;
pline("This water gives you bad breath!");
pline("This %s gives you bad breath!",
hliquid("water"));
for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
if (DEADMONSTER(mtmp))
continue;
@@ -349,7 +350,8 @@ drinkfountain()
dogushforth(TRUE);
break;
default:
pline("This tepid water is tasteless.");
pline("This tepid %s is tasteless.",
hliquid("water"));
break;
}
}
@@ -372,8 +374,8 @@ register struct obj *obj;
&& !exist_artifact(LONG_SWORD, artiname(ART_EXCALIBUR))) {
if (u.ualign.type != A_LAWFUL) {
/* Ha! Trying to cheat her. */
pline(
"A freezing mist rises from the water and envelopes the sword.");
pline("A freezing mist rises from the %s and envelopes the sword.",
hliquid("water"));
pline_The("fountain disappears!");
curse(obj);
if (obj->spe > -6 && !rn2(3))
@@ -423,7 +425,7 @@ register struct obj *obj;
case 20: /* Uncurse the item */
if (obj->cursed) {
if (!Blind)
pline_The("water glows for a moment.");
pline_The("%s glows for a moment.", hliquid("water"));
uncurse(obj);
} else {
pline("A feeling of loss comes over you.");
@@ -490,7 +492,8 @@ register struct obj *obj;
+ 1) * 2) + 5),
u.ux, u.uy);
if (!Blind)
pline("Far below you, you see coins glistening in the water.");
pline("Far below you, you see coins glistening in the %s.",
hliquid("water"));
exercise(A_WIS, TRUE);
newsym(u.ux, u.uy);
break;
@@ -524,13 +527,13 @@ drinksink()
}
switch (rn2(20)) {
case 0:
You("take a sip of very cold water.");
You("take a sip of very cold %s.", hliquid("water"));
break;
case 1:
You("take a sip of very warm water.");
You("take a sip of very warm %s.", hliquid("water"));
break;
case 2:
You("take a sip of scalding hot water.");
You("take a sip of scalding hot %s.", hliquid("water"));
if (Fire_resistance)
pline("It seems quite tasty.");
else
@@ -573,19 +576,19 @@ drinksink()
exercise(A_WIS, TRUE);
newsym(u.ux, u.uy);
} else
pline("Some dirty water backs up in the drain.");
pline("Some dirty %s backs up in the drain.", hliquid("water"));
break;
case 6:
breaksink(u.ux, u.uy);
break;
case 7:
pline_The("water moves as though of its own will!");
pline_The("%s moves as though of its own will!", hliquid("water"));
if ((mvitals[PM_WATER_ELEMENTAL].mvflags & G_GONE)
|| !makemon(&mons[PM_WATER_ELEMENTAL], u.ux, u.uy, NO_MM_FLAGS))
pline("But it quiets down.");
break;
case 8:
pline("Yuk, this water tastes awful.");
pline("Yuk, this %s tastes awful.", hliquid("water"));
more_experienced(1, 0);
newexplevel();
break;
@@ -595,7 +598,7 @@ drinksink()
vomit();
break;
case 10:
pline("This water contains toxic wastes!");
pline("This %s contains toxic wastes!", hliquid("water"));
if (!Unchanging) {
You("undergo a freakish metamorphosis!");
polyself(0);
@@ -614,8 +617,9 @@ drinksink()
break;
}
default:
You("take a sip of %s water.",
rn2(3) ? (rn2(2) ? "cold" : "warm") : "hot");
You("take a sip of %s %s.",
rn2(3) ? (rn2(2) ? "cold" : "warm") : "hot",
hliquid("water"));
}
}
+77 -19
View File
@@ -1,4 +1,4 @@
/* NetHack 3.6 hack.c $NHDT-Date: 1462663937 2016/05/07 23:32:17 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.165 $ */
/* NetHack 3.6 hack.c $NHDT-Date: 1464485934 2016/05/29 01:38:54 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.168 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
@@ -679,6 +679,14 @@ int mode;
feel_location(x, y);
if (Passes_walls && may_passwall(x, y)) {
; /* do nothing */
} else if (Underwater) {
/* note: if water_friction() changes direction due to
turbulence, new target destination will always be water,
so we won't get here, hence don't need to worry about
"there" being somewhere the player isn't sure of */
if (mode == DO_MOVE)
pline("There is an obstacle there.");
return FALSE;
} else if (tmpr->typ == IRONBARS) {
if ((dmgtype(youmonst.data, AD_RUST)
|| dmgtype(youmonst.data, AD_CORR)) && mode == DO_MOVE
@@ -686,7 +694,7 @@ int mode;
return FALSE;
}
if (!(Passes_walls || passes_bars(youmonst.data))) {
if (iflags.mention_walls)
if (mode == DO_MOVE && iflags.mention_walls)
You("cannot pass through the bars.");
return FALSE;
}
@@ -702,14 +710,16 @@ int mode;
return FALSE;
} else {
if (mode == DO_MOVE) {
if (Is_stronghold(&u.uz) && is_db_wall(x, y))
pline_The("drawbridge is up!");
if (is_db_wall(x, y))
pline("That drawbridge is up!");
/* sokoban restriction stays even after puzzle is solved */
else if (Passes_walls && !may_passwall(x, y)
&& In_sokoban(&u.uz))
pline_The("Sokoban walls resist your ability.");
else if (iflags.mention_walls)
pline("It's a wall.");
pline("It's %s.", IS_WALL(tmpr->typ) ? "a wall"
: IS_TREE(tmpr->typ) ? "a tree"
: "solid stone");
}
return FALSE;
}
@@ -722,6 +732,10 @@ int mode;
} else if (can_ooze(&youmonst)) {
if (mode == DO_MOVE)
You("ooze under the door.");
} else if (Underwater) {
if (mode == DO_MOVE)
pline("There is an obstacle there.");
return FALSE;
} else if (tunnels(youmonst.data) && !needspick(youmonst.data)) {
/* Eat the door. */
if (mode == DO_MOVE && still_chewing(x, y))
@@ -757,8 +771,12 @@ int mode;
if (dx && dy && !Passes_walls
&& (!doorless_door(x, y) || block_door(x, y))) {
/* Diagonal moves into a door are not allowed. */
if (Blind && mode == DO_MOVE)
feel_location(x, y);
if (mode == DO_MOVE) {
if (Blind)
feel_location(x, y);
if (Underwater || iflags.mention_walls)
You_cant("move diagonally into an intact doorway.");
}
return FALSE;
}
}
@@ -791,8 +809,7 @@ int mode;
/* Pick travel path that does not require crossing a trap.
* Avoid water and lava using the usual running rules.
* (but not u.ux/u.uy because findtravelpath walks toward u.ux/u.uy) */
if (context.run == 8
&& (mode == TEST_MOVE || mode == TEST_TRAP)
if (context.run == 8 && (mode != DO_MOVE)
&& (x != u.ux || y != u.uy)) {
struct trap *t = t_at(x, y);
@@ -811,6 +828,8 @@ int mode;
if (dx && dy && !Passes_walls && IS_DOOR(ust->typ)
&& (!doorless_door(ux, uy) || block_entry(x, y))) {
/* Can't move at a diagonal out of a doorway with door. */
if (mode == DO_MOVE && iflags.mention_walls)
You_cant("move diagonally out of an intact doorway.");
return FALSE;
}
@@ -931,7 +950,44 @@ boolean guess;
int nx = x + xdir[ordered[dir]];
int ny = y + ydir[ordered[dir]];
if (!isok(nx, ny))
/*
* When guessing and trying to travel as close as possible
* to an unreachable target space, don't include spaces
* that would never be picked as a guessed target in the
* travel matrix describing hero-reachable spaces.
* This stops travel from getting confused and moving
* the hero back and forth in certain degenerate
* configurations of sight-blocking obstacles, e.g.
*
* T 1. Dig this out and carry enough to not be
* #### able to squeeze through diagonal gaps.
* #--.--- Stand at @ and target travel at space T.
* @.....
* |.....
*
* T 2. couldsee() marks spaces marked a and x
* #### as eligible guess spaces to move the hero
* a--.--- towards. Space a is closest to T, so it
* @xxxxx gets chosen. Travel system moves @ right
* |xxxxx to travel to space a.
*
* T 3. couldsee() marks spaces marked b, c and x
* #### as eligible guess spaces to move the hero
* a--c--- towards. Since findtravelpath() is called
* b@xxxx repeatedly during travel, it doesn't
* |xxxxx remember that it wanted to go to space a,
* so in comparing spaces b and c, b is
* chosen, since it seems like the closest
* eligible space to T. Travel system moves @
* left to go to space b.
*
* 4. Go to 2.
*
* By limiting the travel matrix here, space a in the
* example above is never included in it, preventing
* the cycle.
*/
if (!isok(nx, ny) || (guess && !couldsee(nx, ny)))
continue;
if ((!Passes_walls && !can_ooze(&youmonst)
&& closed_door(x, y)) || sobj_at(BOULDER, x, y)
@@ -960,8 +1016,7 @@ boolean guess;
nomul(0);
/* reset run so domove run checks work */
context.run = 8;
iflags.travelcc.x = iflags.travelcc.y =
-1;
iflags.travelcc.x = iflags.travelcc.y = -1;
}
return TRUE;
}
@@ -1134,9 +1189,11 @@ struct trap *desttrap; /* nonnull if another trap at <x,y> */
if ((u.utrap & 0xff) == 0) {
u.utrap = 0;
if (u.usteed)
You("lead %s to the edge of the lava.", steedname);
You("lead %s to the edge of the %s.", steedname,
hliquid("lava"));
else
You("pull yourself to the edge of the lava.");
You("pull yourself to the edge of the %s.",
hliquid("lava"));
}
}
u.umoved = TRUE;
@@ -1843,16 +1900,16 @@ boolean newspot; /* true if called by spoteffects */
if (Is_waterlevel(&u.uz))
You("pop into an air bubble.");
else if (is_lava(u.ux, u.uy))
You("leave the water..."); /* oops! */
You("leave the %s...", hliquid("water")); /* oops! */
else
You("are on solid %s again.",
is_ice(u.ux, u.uy) ? "ice" : "land");
} else if (Is_waterlevel(&u.uz)) {
still_inwater = TRUE;
} else if (Levitation) {
You("pop out of the water like a cork!");
You("pop out of the %s like a cork!", hliquid("water"));
} else if (Flying) {
You("fly out of the water.");
You("fly out of the %s.", hliquid("water"));
} else if (Wwalking) {
You("slowly rise above the surface.");
} else {
@@ -2363,7 +2420,8 @@ dopickup()
if (is_pool(u.ux, u.uy)) {
if (Wwalking || is_floater(youmonst.data) || is_clinger(youmonst.data)
|| (Flying && !Breathless)) {
You("cannot dive into the water to pick things up.");
You("cannot dive into the %s to pick things up.",
hliquid("water"));
return 0;
} else if (!Underwater) {
You_cant("even see the bottom, let alone pick up %s.", something);
@@ -2390,7 +2448,7 @@ dopickup()
else if (IS_GRAVE(lev->typ))
You("don't need a gravestone. Yet.");
else if (IS_FOUNTAIN(lev->typ))
You("could drink the water...");
You("could drink the %s...", hliquid("water"));
else if (IS_DOOR(lev->typ) && (lev->doormask & D_ISOPEN))
pline("It won't come off the hinges.");
else
+14 -2
View File
@@ -75,7 +75,8 @@ STATIC_PTR int
picklock(VOID_ARGS)
{
if (xlock.box) {
if ((xlock.box->ox != u.ux) || (xlock.box->oy != u.uy)) {
if (xlock.box->where != OBJ_FLOOR
|| xlock.box->ox != u.ux || xlock.box->oy != u.uy) {
return ((xlock.usedtime = 0)); /* you or it moved */
}
} else { /* door */
@@ -228,6 +229,14 @@ reset_pick()
xlock.box = 0;
}
/* level change; don't reset if hero is carrying xlock.box with him/her */
void
maybe_reset_pick()
{
if (!xlock.box || !carried(xlock.box))
reset_pick();
}
/* for doapply(); if player gives a direction or resumes an interrupted
previous attempt then it costs hero a move even if nothing ultimately
happens; when told "can't do that" before being asked for direction
@@ -306,7 +315,7 @@ struct obj *pick;
pline("Doing that would probably melt %s.", yname(pick));
return PICKLOCK_LEARNED_SOMETHING;
} else if (is_pool(u.ux, u.uy) && !Underwater) {
pline_The("water has no lock.");
pline_The("%s has no lock.", hliquid("water"));
return PICKLOCK_LEARNED_SOMETHING;
}
@@ -609,6 +618,9 @@ int x, y;
There("is no obvious way to open the drawbridge.");
else if (portcullis || door->typ == DRAWBRIDGE_DOWN)
pline_The("drawbridge is already open.");
else if (container_at(cc.x, cc.y, TRUE))
pline("%s like something lootable over there.",
Blind ? "Feels" : "Seems");
else
You("%s no door there.", Blind ? "feel" : "see");
return res;
+6 -1
View File
@@ -90,7 +90,12 @@ free_maildata()
void
getmailstatus()
{
if (!mailbox && !(mailbox = nh_getenv("MAIL"))) {
char *emailbox;
if ((emailbox = nh_getenv("MAIL")) != 0) {
mailbox = (char *) alloc((unsigned) strlen(emailbox));
Strcpy(mailbox, emailbox);
}
if (!mailbox) {
#ifdef MAILPATH
#ifdef AMS
struct passwd ppasswd;
+7 -7
View File
@@ -54,6 +54,9 @@ static int explcolors[] = {
(currentgraphics == ROGUESET && SYMHANDLING(H_IBM))
#endif
#define is_objpile(x,y) (!Hallucination && level.objects[(x)][(y)] \
&& level.objects[(x)][(y)]->nexthere)
/*ARGSUSED*/
int
mapglyph(glyph, ochar, ocolor, ospecial, x, y)
@@ -83,7 +86,7 @@ unsigned *ospecial;
else
obj_color(STATUE);
special |= MG_STATUE;
if (level.objects[x][y] && level.objects[x][y]->nexthere)
if (is_objpile(x,y))
special |= MG_OBJPILE;
} else if ((offset = (glyph - GLYPH_WARNING_OFF)) >= 0) { /* warn flash */
idx = offset + SYM_OFF_W;
@@ -134,9 +137,7 @@ unsigned *ospecial;
} else if (!iflags.use_color && offset == S_lava
&& (showsyms[idx] == showsyms[S_pool + SYM_OFF_P]
|| showsyms[idx] == showsyms[S_water + SYM_OFF_P])) {
/* temporary? hack; makes tty use inverse video if the
corresponding boolean option is enabled */
special |= MG_DETECT;
special |= MG_BW_LAVA;
} else {
cmap_color(offset);
}
@@ -158,8 +159,7 @@ unsigned *ospecial;
}
} else
obj_color(offset);
if (offset != BOULDER && level.objects[x][y]
&& level.objects[x][y]->nexthere)
if (offset != BOULDER && is_objpile(x,y))
special |= MG_OBJPILE;
} else if ((offset = (glyph - GLYPH_RIDDEN_OFF)) >= 0) { /* mon ridden */
idx = mons[offset].mlet + SYM_OFF_M;
@@ -178,7 +178,7 @@ unsigned *ospecial;
else
mon_color(offset);
special |= MG_CORPSE;
if (level.objects[x][y] && level.objects[x][y]->nexthere)
if (is_objpile(x,y))
special |= MG_OBJPILE;
} else if ((offset = (glyph - GLYPH_DETECT_OFF)) >= 0) { /* mon detect */
idx = mons[offset].mlet + SYM_OFF_M;
+67 -22
View File
@@ -291,7 +291,7 @@ register struct monst *magr, *mdef;
{
int i, /* loop counter */
tmp, /* amour class difference */
strike, /* hit this attack */
strike = 0, /* hit this attack */
attk, /* attack attempted this time */
struck = 0, /* hit at least once */
res[NATTK]; /* results of all attacks */
@@ -354,6 +354,15 @@ register struct monst *magr, *mdef;
attk = 1;
switch (mattk->aatyp) {
case AT_WEAP: /* "hand to hand" attacks */
if (distmin(magr->mx, magr->my, mdef->mx, mdef->my) > 1) {
/* D: Do a ranged attack here! */
strike = thrwmm(magr, mdef);
if (DEADMONSTER(mdef))
res[i] = MM_DEF_DIED;
if (DEADMONSTER(magr))
res[i] |= MM_AGR_DIED;
break;
}
if (magr->weapon_check == NEED_WEAPON || !MON_WEP(magr)) {
magr->weapon_check = NEED_HTH_WEAPON;
if (mon_wield_item(magr) != 0)
@@ -377,7 +386,8 @@ register struct monst *magr, *mdef;
case AT_TENT:
/* Nymph that teleported away on first attack? */
if (distmin(magr->mx, magr->my, mdef->mx, mdef->my) > 1)
return MM_MISS;
/* Continue because the monster may have a ranged attack. */
continue;
/* Monsters won't attack cockatrices physically if they
* have a weapon instead. This instinct doesn't work for
* players, or under conflict or confusion.
@@ -426,6 +436,10 @@ register struct monst *magr, *mdef;
break;
case AT_EXPL:
/* D: Prevent explosions from a distance */
if (distmin(magr->mx,magr->my,mdef->mx,mdef->my) > 1)
continue;
res[i] = explmm(magr, mdef, mattk);
if (res[i] == MM_MISS) { /* cancelled--no attack */
strike = 0;
@@ -435,20 +449,49 @@ register struct monst *magr, *mdef;
break;
case AT_ENGL:
if (u.usteed && (mdef == u.usteed)) {
if (u.usteed && mdef == u.usteed) {
strike = 0;
break;
}
/* Engulfing attacks are directed at the hero if
* possible. -dlc
*/
/* D: Prevent engulf from a distance */
if (distmin(magr->mx, magr->my, mdef->mx, mdef->my) > 1)
continue;
/* Engulfing attacks are directed at the hero if possible. -dlc */
if (u.uswallow && magr == u.ustuck)
strike = 0;
else {
if ((strike = (tmp > rnd(20 + i))))
res[i] = gulpmm(magr, mdef, mattk);
else
missmm(magr, mdef, mattk);
else if ((strike = (tmp > rnd(20 + i))) != 0)
res[i] = gulpmm(magr, mdef, mattk);
else
missmm(magr, mdef, mattk);
break;
case AT_BREA:
if (!monnear(magr, mdef->mx, mdef->my)) {
strike = breamm(magr, mattk, mdef);
/* We don't really know if we hit or not; pretend we did. */
if (strike)
res[i] |= MM_HIT;
if (DEADMONSTER(mdef))
res[i] = MM_DEF_DIED;
if (DEADMONSTER(magr))
res[i] |= MM_AGR_DIED;
}
else
strike = 0;
break;
case AT_SPIT:
if (!monnear(magr, mdef->mx, mdef->my)) {
strike = spitmm(magr, mattk, mdef);
/* We don't really know if we hit or not; pretend we did. */
if (strike)
res[i] |= MM_HIT;
if (DEADMONSTER(mdef))
res[i] = MM_DEF_DIED;
if (DEADMONSTER(magr))
res[i] |= MM_AGR_DIED;
}
break;
@@ -458,12 +501,12 @@ register struct monst *magr, *mdef;
break;
}
if (attk && !(res[i] & MM_AGR_DIED))
if (attk && !(res[i] & MM_AGR_DIED)
&& distmin(magr->mx, magr->my, mdef->mx, mdef->my) <= 1)
res[i] = passivemm(magr, mdef, strike, res[i] & MM_DEF_DIED);
if (res[i] & MM_DEF_DIED)
return res[i];
if (res[i] & MM_AGR_DIED)
return res[i];
/* return if aggressor can no longer attack */
@@ -548,9 +591,8 @@ struct attack *mattk;
pline("%s %s...", buf, mon_nam(mdef));
}
if (magr->mcan || !magr->mcansee
|| (magr->minvis && !perceives(mdef->data)) || !mdef->mcansee
|| mdef->msleeping) {
if (magr->mcan || !magr->mcansee || !mdef->mcansee
|| (magr->minvis && !perceives(mdef->data)) || mdef->msleeping) {
if (vis)
pline("but nothing happens.");
return MM_MISS;
@@ -562,8 +604,8 @@ struct attack *mattk;
if (mdef->mcansee) {
if (mon_reflects(magr, (char *) 0)) {
if (canseemon(magr))
(void) mon_reflects(
magr, "The gaze is reflected away by %s %s.");
(void) mon_reflects(magr,
"The gaze is reflected away by %s %s.");
return MM_MISS;
}
if (mdef->minvis && !perceives(magr->data)) {
@@ -676,7 +718,7 @@ register struct attack *mattk;
} else if (status & MM_AGR_DIED) { /* aggressor died */
place_monster(mdef, dx, dy);
newsym(dx, dy);
} else { /* both alive, put them back */
} else { /* both alive, put them back */
if (cansee(dx, dy))
pline("%s is regurgitated!", Monnam(mdef));
@@ -930,11 +972,12 @@ register struct attack *mattk;
}
if (resists_acid(mdef)) {
if (vis)
pline("%s is covered in acid, but it seems harmless.",
pline("%s is covered in %s, but it seems harmless.",
hliquid("acid"),
Monnam(mdef));
tmp = 0;
} else if (vis) {
pline("%s is covered in acid!", Monnam(mdef));
pline("%s is covered in %s!", hliquid("acid"), Monnam(mdef));
pline("It burns %s!", mon_nam(mdef));
}
if (!rn2(30))
@@ -1127,6 +1170,7 @@ register struct attack *mattk;
*/
{
struct obj *gold = findgold(mdef->minvent);
if (!gold)
break;
obj_extract_self(gold);
@@ -1447,7 +1491,8 @@ int mdead;
if (mhit && !rn2(2)) {
Strcpy(buf, Monnam(magr));
if (canseemon(magr))
pline("%s is splashed by %s acid!", buf,
pline("%s is splashed by %s %s!", buf,
hliquid("acid"),
s_suffix(mon_nam(mdef)));
if (resists_acid(magr)) {
if (canseemon(magr))
+90 -72
View File
@@ -8,11 +8,9 @@
STATIC_VAR NEARDATA struct obj *otmp;
STATIC_DCL boolean FDECL(u_slip_free, (struct monst *, struct attack *));
STATIC_DCL int FDECL(passiveum,
(struct permonst *, struct monst *, struct attack *));
STATIC_DCL int FDECL(passiveum, (struct permonst *, struct monst *,
struct attack *));
STATIC_DCL void FDECL(mayberem, (struct obj *, const char *));
STATIC_DCL boolean FDECL(diseasemu, (struct permonst *));
STATIC_DCL int FDECL(hitmu, (struct monst *, struct attack *));
STATIC_DCL int FDECL(gulpmu, (struct monst *, struct attack *));
@@ -20,7 +18,6 @@ STATIC_DCL int FDECL(explmu, (struct monst *, struct attack *, BOOLEAN_P));
STATIC_DCL void FDECL(missmu, (struct monst *, BOOLEAN_P, struct attack *));
STATIC_DCL void FDECL(mswings, (struct monst *, struct obj *));
STATIC_DCL void FDECL(wildmiss, (struct monst *, struct attack *));
STATIC_DCL void FDECL(hitmsg, (struct monst *, struct attack *));
/* See comment in mhitm.c. If we use this a lot it probably should be */
@@ -33,41 +30,48 @@ register struct monst *mtmp;
register struct attack *mattk;
{
int compat;
const char *pfmt = 0;
char *Monst_name = Monnam(mtmp);
/* Note: if opposite gender, "seductively" */
/* If same gender, "engagingly" for nymph, normal msg for others */
if ((compat = could_seduce(mtmp, &youmonst, mattk)) && !mtmp->mcan
&& !mtmp->mspec_used) {
pline("%s %s you %s.", Monnam(mtmp), Blind ? "talks to" : "smiles at",
compat == 2 ? "engagingly" : "seductively");
} else
if ((compat = could_seduce(mtmp, &youmonst, mattk)) != 0
&& !mtmp->mcan && !mtmp->mspec_used) {
pline("%s %s you %s.", Monst_name,
Blind ? "talks to" : "smiles at",
(compat == 2) ? "engagingly" : "seductively");
} else {
switch (mattk->aatyp) {
case AT_BITE:
pline("%s bites!", Monnam(mtmp));
pfmt = "%s bites!";
break;
case AT_KICK:
pline("%s kicks%c", Monnam(mtmp),
pline("%s kicks%c", Monst_name,
thick_skinned(youmonst.data) ? '.' : '!');
break;
case AT_STNG:
pline("%s stings!", Monnam(mtmp));
pfmt = "%s stings!";
break;
case AT_BUTT:
pline("%s butts!", Monnam(mtmp));
pfmt = "%s butts!";
break;
case AT_TUCH:
pline("%s touches you!", Monnam(mtmp));
pfmt = "%s touches you!";
break;
case AT_TENT:
pline("%s tentacles suck you!", s_suffix(Monnam(mtmp)));
pfmt = "%s tentacles suck you!";
Monst_name = s_suffix(Monst_name);
break;
case AT_EXPL:
case AT_BOOM:
pline("%s explodes!", Monnam(mtmp));
pfmt = "%s explodes!";
break;
default:
pline("%s hits!", Monnam(mtmp));
pfmt = "%s hits!";
}
if (pfmt)
pline(pfmt, Monst_name);
}
}
/* monster missed you */
@@ -139,6 +143,7 @@ register struct monst *mtmp;
register struct attack *mattk;
{
int compat;
const char *Monst_name; /* Monnam(mtmp) */
/* no map_invisible() -- no way to tell where _this_ is coming from */
@@ -150,42 +155,41 @@ register struct attack *mattk;
compat = ((mattk->adtyp == AD_SEDU || mattk->adtyp == AD_SSEX)
&& could_seduce(mtmp, &youmonst, (struct attack *) 0));
Monst_name = Monnam(mtmp);
if (!mtmp->mcansee || (Invis && !perceives(mtmp->data))) {
const char *swings =
mattk->aatyp == AT_BITE
? "snaps"
: mattk->aatyp == AT_KICK
? "kicks"
: (mattk->aatyp == AT_STNG || mattk->aatyp == AT_BUTT
|| nolimbs(mtmp->data))
? "lunges"
: "swings";
const char *swings = (mattk->aatyp == AT_BITE) ? "snaps"
: (mattk->aatyp == AT_KICK) ? "kicks"
: (mattk->aatyp == AT_STNG
|| mattk->aatyp == AT_BUTT
|| nolimbs(mtmp->data)) ? "lunges"
: "swings";
if (compat)
pline("%s tries to touch you and misses!", Monnam(mtmp));
pline("%s tries to touch you and misses!", Monst_name);
else
switch (rn2(3)) {
case 0:
pline("%s %s wildly and misses!", Monnam(mtmp), swings);
pline("%s %s wildly and misses!", Monst_name, swings);
break;
case 1:
pline("%s attacks a spot beside you.", Monnam(mtmp));
pline("%s attacks a spot beside you.", Monst_name);
break;
case 2:
pline("%s strikes at %s!", Monnam(mtmp),
levl[mtmp->mux][mtmp->muy].typ == WATER ? "empty water"
: "thin air");
pline("%s strikes at %s!", Monst_name,
(levl[mtmp->mux][mtmp->muy].typ == WATER)
? "empty water"
: "thin air");
break;
default:
pline("%s %s wildly!", Monnam(mtmp), swings);
pline("%s %s wildly!", Monst_name, swings);
break;
}
} else if (Displaced) {
if (compat)
pline("%s smiles %s at your %sdisplaced image...", Monnam(mtmp),
compat == 2 ? "engagingly" : "seductively",
pline("%s smiles %s at your %sdisplaced image...", Monst_name,
(compat == 2) ? "engagingly" : "seductively",
Invis ? "invisible " : "");
else
pline("%s strikes at your %sdisplaced image and misses you!",
@@ -194,20 +198,20 @@ register struct attack *mattk;
* displaced image, since the displaced image is also
* invisible.
*/
Monnam(mtmp), Invis ? "invisible " : "");
Monst_name, Invis ? "invisible " : "");
} else if (Underwater) {
/* monsters may miss especially on water level where
bubbles shake the player here and there */
if (compat)
pline("%s reaches towards your distorted image.", Monnam(mtmp));
pline("%s reaches towards your distorted image.", Monst_name);
else
pline("%s is fooled by water reflections and misses!",
Monnam(mtmp));
Monst_name);
} else
impossible("%s attacks you without knowing your location?",
Monnam(mtmp));
Monst_name);
}
void
@@ -217,9 +221,9 @@ struct permonst *mdat; /* if mtmp is polymorphed, mdat != mtmp->data */
boolean message;
{
if (message) {
if (is_animal(mdat))
if (is_animal(mdat)) {
You("get regurgitated!");
else {
} else {
char blast[40];
register int i;
@@ -227,9 +231,9 @@ boolean message;
for (i = 0; i < NATTK; i++)
if (mdat->mattk[i].aatyp == AT_ENGL)
break;
if (mdat->mattk[i].aatyp != AT_ENGL)
if (mdat->mattk[i].aatyp != AT_ENGL) {
impossible("Swallower has no engulfing attack?");
else {
} else {
if (is_whirly(mdat)) {
switch (mdat->mattk[i].adtyp) {
case AD_ELEC:
@@ -296,6 +300,20 @@ struct attack *alt_attk_buf;
/* note: 3d9 is slightly higher than previous 4d6 */
}
} else if (attk->aatyp == AT_ENGL && magr->mspec_used) {
/* can't re-engulf yet; switch to simpler attack */
*alt_attk_buf = *attk;
attk = alt_attk_buf;
if (attk->adtyp == AD_ACID || attk->adtyp == AD_ELEC
|| attk->adtyp == AD_COLD || attk->adtyp == AD_FIRE) {
attk->aatyp = AT_TUCH;
} else {
attk->aatyp = AT_CLAW; /* attack message will be "<foo> hits" */
attk->adtyp = AD_PHYS;
}
attk->damn = 1; /* relatively weak: 1d6 */
attk->damd = 6;
/* barrow wight, Nazgul, erinys have weapon attack for non-physical
damage; force physical damage if attacker has been cancelled or
if weapon is sufficiently interesting; a few unique creatures
@@ -306,11 +324,10 @@ struct attack *alt_attk_buf;
&& !(mptr->mattk[1].aatyp == AT_WEAP
&& mptr->mattk[1].adtyp == AD_PHYS)
&& (magr->mcan
|| (weap
&& ((weap->otyp == CORPSE
&& touch_petrifies(&mons[weap->corpsenm]))
|| weap->oartifact == ART_STORMBRINGER
|| weap->oartifact == ART_VORPAL_BLADE)))) {
|| (weap && ((weap->otyp == CORPSE
&& touch_petrifies(&mons[weap->corpsenm]))
|| weap->oartifact == ART_STORMBRINGER
|| weap->oartifact == ART_VORPAL_BLADE)))) {
*alt_attk_buf = *attk;
attk = alt_attk_buf;
attk->adtyp = AD_PHYS;
@@ -332,7 +349,7 @@ mattacku(mtmp)
register struct monst *mtmp;
{
struct attack *mattk, alt_attk;
int i, j, tmp, sum[NATTK];
int i, j = 0, tmp, sum[NATTK];
struct permonst *mdat = mtmp->data;
boolean ranged = (distu(mtmp->mx, mtmp->my) > 3);
/* Is it near you? Affects your actions */
@@ -681,10 +698,10 @@ register struct monst *mtmp;
case AT_ENGL:
if (!range2) {
if (foundyou) {
if (u.uswallow || tmp > (j = rnd(20 + i))) {
/* Force swallowing monster to be
* displayed even when player is
* moving away */
if (u.uswallow
|| (!mtmp->mspec_used && tmp > (j = rnd(20 + i)))) {
/* force swallowing monster to be displayed
even when hero is moving away */
flush_screen(1);
sum[i] = gulpmu(mtmp, mattk);
} else {
@@ -1157,7 +1174,8 @@ register struct attack *mattk;
break;
case AD_LEGS: {
register long side = rn2(2) ? RIGHT_SIDE : LEFT_SIDE;
const char *sidestr = (side == RIGHT_SIDE) ? "right" : "left";
const char *sidestr = (side == RIGHT_SIDE) ? "right" : "left",
*Monst_name = Monnam(mtmp), *leg = body_part(LEG);
/* This case is too obvious to ignore, but Nethack is not in
* general very good at considering height--most short monsters
@@ -1165,31 +1183,30 @@ register struct attack *mattk;
* [FIXME: why can't a flying attacker overcome this?]
*/
if (u.usteed || Levitation || Flying) {
pline("%s tries to reach your %s %s!", Monnam(mtmp), sidestr,
body_part(LEG));
pline("%s tries to reach your %s %s!", Monst_name, sidestr, leg);
dmg = 0;
} else if (mtmp->mcan) {
pline("%s nuzzles against your %s %s!", Monnam(mtmp), sidestr,
body_part(LEG));
pline("%s nuzzles against your %s %s!", Monnam(mtmp),
sidestr, leg);
dmg = 0;
} else {
if (uarmf) {
if (rn2(2) && (uarmf->otyp == LOW_BOOTS
|| uarmf->otyp == IRON_SHOES))
|| uarmf->otyp == IRON_SHOES)) {
pline("%s pricks the exposed part of your %s %s!",
Monnam(mtmp), sidestr, body_part(LEG));
else if (!rn2(5))
pline("%s pricks through your %s boot!", Monnam(mtmp),
Monst_name, sidestr, leg);
} else if (!rn2(5)) {
pline("%s pricks through your %s boot!", Monst_name,
sidestr);
else {
pline("%s scratches your %s boot!", Monnam(mtmp),
} else {
pline("%s scratches your %s boot!", Monst_name,
sidestr);
dmg = 0;
break;
}
} else
pline("%s pricks your %s %s!", Monnam(mtmp), sidestr,
body_part(LEG));
pline("%s pricks your %s %s!", Monst_name, sidestr, leg);
set_wounded_legs(side, rnd(60 - ACURR(A_DEX)));
exercise(A_STR, FALSE);
exercise(A_DEX, FALSE);
@@ -1308,12 +1325,11 @@ register struct attack *mattk;
(void) rloc(mtmp, TRUE);
return 3;
} else if (mtmp->mcan) {
if (!Blind) {
if (!Blind)
pline("%s tries to %s you, but you seem %s.",
Adjmonnam(mtmp, "plain"),
flags.female ? "charm" : "seduce",
flags.female ? "unaffected" : "uninterested");
}
if (rn2(3)) {
if (!tele_restrict(mtmp))
(void) rloc(mtmp, TRUE);
@@ -1478,10 +1494,11 @@ register struct attack *mattk;
hitmsg(mtmp, mattk);
if (!mtmp->mcan && !rn2(3))
if (Acid_resistance) {
pline("You're covered in acid, but it seems harmless.");
pline("You're covered in %s, but it seems harmless.",
hliquid("acid"));
dmg = 0;
} else {
pline("You're covered in acid! It burns!");
pline("You're covered in %s! It burns!", hliquid("acid"));
exercise(A_STR, FALSE);
}
else
@@ -1705,6 +1722,7 @@ register struct attack *mattk;
newsym(mtmp->mx, mtmp->my);
if (is_animal(mtmp->data) && u.usteed) {
char buf[BUFSZ];
/* Too many quirks presently if hero and steed
* are swallowed. Pretend purple worms don't
* like horses for now :-)
@@ -2633,7 +2651,7 @@ register struct attack *mattk;
switch (olduasmon->mattk[i].adtyp) {
case AD_ACID:
if (!rn2(2)) {
pline("%s is splashed by your acid!", Monnam(mtmp));
pline("%s is splashed by your %s!", Monnam(mtmp), hliquid("acid"));
if (resists_acid(mtmp)) {
pline("%s is not affected.", Monnam(mtmp));
tmp = 0;
+2 -2
View File
@@ -1327,7 +1327,7 @@ xchar x, y;
ltyp = db_under_typ(lev->drawbridgemask);
if (ltyp == LAVAPOOL)
return "lava";
return hliquid("lava");
else if (ltyp == ICE)
return "ice";
else if (ltyp == POOL)
@@ -1339,7 +1339,7 @@ xchar x, y;
else if (ltyp == MOAT && !Is_medusa_level(&u.uz))
return "moat";
return "water";
return hliquid("water");
}
STATIC_OVL void
+3 -3
View File
@@ -872,9 +872,6 @@ boolean artif;
case BAG_OF_HOLDING:
mkbox_cnts(otmp);
break;
case LEASH:
otmp->leashmon = 0;
break;
case EXPENSIVE_CAMERA:
case TINNING_KIT:
case MAGIC_MARKER:
@@ -1034,6 +1031,9 @@ boolean artif;
/* case TIN: */
set_corpsenm(otmp, otmp->corpsenm);
break;
case LEASH:
otmp->leashmon = 0;
break;
case SPE_NOVEL:
otmp->novelidx = -1; /* "none of the above"; will be changed */
otmp = oname(otmp, noveltitle(&otmp->novelidx));
+80 -12
View File
@@ -1,4 +1,4 @@
/* NetHack 3.6 mon.c $NHDT-Date: 1463534459 2016/05/18 01:20:59 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.221 $ */
/* NetHack 3.6 mon.c $NHDT-Date: 1466289475 2016/06/18 22:37:55 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.227 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
@@ -554,7 +554,8 @@ register struct monst *mtmp;
if (u.ustuck && u.uswallow && u.ustuck == mtmp) {
/* This can happen after a purple worm plucks you off a
flying steed while you are over water. */
pline("%s sinks as water rushes in and flushes you out.",
pline("%s sinks as %s rushes in and flushes you out.",
hliquid("water"),
Monnam(mtmp));
}
mondead(mtmp);
@@ -907,7 +908,12 @@ struct monst *mtmp;
&& !resists_ston(mtmp))
/* don't engulf boulders and statues or ball&chain */
|| otmp->oclass == ROCK_CLASS
|| otmp == uball || otmp == uchain) {
|| otmp == uball || otmp == uchain
/* normally mtmp won't have stepped onto scare monster
scroll, but if it does, don't eat or engulf that
(note: scrolls inside eaten containers will still
become engulfed) */
|| otmp->otyp == SCR_SCARE_MONSTER) {
/* do nothing--neither eaten nor engulfed */
continue;
@@ -939,11 +945,18 @@ struct monst *mtmp;
} else {
/* devour */
++count;
if (cansee(mtmp->mx, mtmp->my) && flags.verbose)
pline("%s eats %s!", Monnam(mtmp),
distant_name(otmp, doname));
else if (flags.verbose)
You_hear("a slurping sound.");
if (cansee(mtmp->mx, mtmp->my)) {
if (flags.verbose)
pline("%s eats %s!", Monnam(mtmp),
distant_name(otmp, doname));
/* give this one even if !verbose */
if (otmp->oclass == SCROLL_CLASS
&& !strcmpi(OBJ_DESCR(objects[otmp->otyp]), "YUM YUM"))
pline("Yum%c", otmp->blessed ? '!' : '.');
} else {
if (flags.verbose)
You_hear("a slurping sound.");
}
/* Heal up to the object's weight in hp */
if (mtmp->mhp < mtmp->mhpmax) {
mtmp->mhp += objects[otmp->otyp].oc_weight;
@@ -2146,6 +2159,10 @@ struct monst *mtmp;
placebc();
vision_full_recalc = 1;
docrt();
/* prevent swallower (mtmp might have just poly'd into something
without an engulf attack) from immediately re-engulfing */
if (attacktype(mtmp->data, AT_ENGL) && !mtmp->mspec_used)
mtmp->mspec_used = rnd(2);
}
u.ustuck = 0;
}
@@ -2178,14 +2195,16 @@ int xkill_flags; /* 1: suppress message, 2: suppress corpse, 4: pacifist */
if (!noconduct) /* KMH, conduct */
u.uconduct.killer++;
if (!nomsg)
if (!nomsg) {
boolean namedpet = has_mname(mtmp) && !Hallucination;
You("%s %s!",
nonliving(mtmp->data) ? "destroy" : "kill",
!(wasinside || canspotmon(mtmp)) ? "it"
: !mtmp->mtame ? mon_nam(mtmp)
: x_monnam(mtmp, has_mname(mtmp) ? ARTICLE_NONE : ARTICLE_THE,
"poor", has_mname(mtmp) ? SUPPRESS_SADDLE : 0,
FALSE));
: x_monnam(mtmp, namedpet ? ARTICLE_NONE : ARTICLE_THE,
"poor", namedpet ? SUPPRESS_SADDLE : 0, FALSE));
}
if (mtmp->mtrapped && (t = t_at(x, y)) != 0
&& (t->ttyp == PIT || t->ttyp == SPIKED_PIT)) {
@@ -2610,6 +2629,55 @@ struct monst *mtmp;
: makeplural(q_guardian->mname),
got_mad == 1 ? "s" : "");
}
/* make other peaceful monsters react */
if (!context.mon_moving) {
struct monst *mon;
for (mon = fmon; mon; mon = mon->nmon) {
if (DEADMONSTER(mon))
continue;
if (!mindless(mon->data) && mon->mpeaceful
&& couldsee(mon->mx, mon->my) && !mon->msleeping
&& mon->mcansee && m_canseeu(mon)) {
boolean exclaimed = FALSE;
if (humanoid(mon->data) || mon->isshk || mon->ispriest) {
if (is_watch(mon->data)) {
verbalize("Halt! You're under arrest!");
(void) angry_guards(!!Deaf);
} else {
const char *exclam[] = {
"Gasp!", "Uh-oh.", "Oh my!", "What?", "Why?"
};
if (!rn2(5)) {
verbalize("%s", exclam[mon->m_id % SIZE(exclam)]);
exclaimed = TRUE;
}
if (!mon->isshk && !mon->ispriest
&& (mon->data->mlevel < rn2(10))) {
monflee(mon, rn2(50)+25, TRUE, !exclaimed);
exclaimed = TRUE;
}
if (!mon->isshk && !mon->ispriest) {
mon->mpeaceful = 0;
adjalign(-1);
if (!exclaimed)
pline("%s gets angry!", Monnam(mon));
}
}
} else if ((mtmp->data == mon->data) && !rn2(3)) {
if (!rn2(4)) {
growl(mon);
exclaimed = TRUE;
}
if (rn2(6))
monflee(mon, rn2(25)+15, TRUE, !exclaimed);
}
}
}
}
}
/* wake up a monster, usually making it angry in the process */
+350 -122
View File
@@ -4,13 +4,18 @@
#include "hack.h"
STATIC_DCL int FDECL(monmulti, (struct monst *, struct obj *, struct obj *));
STATIC_DCL void FDECL(monshoot, (struct monst *, struct obj *, struct obj *));
STATIC_DCL int FDECL(drop_throw, (struct obj *, BOOLEAN_P, int, int));
STATIC_DCL boolean FDECL(m_lined_up, (struct monst *, struct monst *));
#define URETREATING(x, y) \
(distmin(u.ux, u.uy, x, y) > distmin(u.ux0, u.uy0, x, y))
#define POLE_LIM 5 /* How far monsters can use pole-weapons */
#define PET_MISSILE_RANGE2 36 /* Square of distance within which pets shoot */
/*
* Keep consistent with breath weapons in zap.c, and AD_* in monattk.h.
*/
@@ -48,9 +53,9 @@ const char *name; /* if null, then format `obj' */
|| !strncmpi(name, "a ", 2))
kprefix = KILLED_BY;
}
onm = (obj && obj_is_pname(obj)) ? the(name) : (obj && obj->quan > 1L)
? name
: an(name);
onm = (obj && obj_is_pname(obj)) ? the(name)
: (obj && obj->quan > 1L) ? name
: an(name);
is_acid = (obj && obj->otyp == ACID_VENOM);
if (u.uac + tlev <= rnd(20)) {
@@ -70,9 +75,9 @@ const char *name; /* if null, then format `obj' */
pline_The("silver sears your flesh!");
exercise(A_CON, FALSE);
}
if (is_acid && Acid_resistance)
if (is_acid && Acid_resistance) {
pline("It doesn't seem to hurt you.");
else {
} else {
if (is_acid)
pline("It burns!");
losehp(dam, knm, kprefix); /* acid damage */
@@ -113,8 +118,7 @@ int x, y;
if (down_gate(x, y) != -1)
objgone = ship_object(obj, x, y, FALSE);
if (!objgone) {
if (!flooreffects(obj, x, y,
"fall")) { /* don't double-dip on damage */
if (!flooreffects(obj, x, y, "fall")) {
place_object(obj, x, y);
if (!mtmp && x == u.ux && y == u.uy)
mtmp = &youmonst;
@@ -129,6 +133,155 @@ int x, y;
return retvalu;
}
/* The monster that's being shot at when one monster shoots at another */
STATIC_OVL struct monst *target = 0;
/* The monster that's doing the shooting/throwing */
STATIC_OVL struct monst *archer = 0;
/* calculate multishot volley count for mtmp throwing otmp (if not ammo) or
shooting otmp with mwep (if otmp is ammo and mwep appropriate launcher) */
STATIC_OVL int
monmulti(mtmp, otmp, mwep)
struct monst *mtmp;
struct obj *otmp, *mwep;
{
int skill = (int) objects[otmp->otyp].oc_skill;
int multishot = 1;
if (otmp->quan > 1L /* no point checking if there's only 1 */
/* ammo requires corresponding launcher be wielded */
&& (is_ammo(otmp)
? matching_launcher(otmp, mwep)
/* otherwise any stackable (non-ammo) weapon */
: otmp->oclass == WEAPON_CLASS)
&& !mtmp->mconf) {
/* Assumes lords are skilled, princes are expert */
if (is_prince(mtmp->data))
multishot += 2;
else if (is_lord(mtmp->data))
multishot++;
/* fake players treated as skilled (regardless of role limits) */
else if (is_mplayer(mtmp->data))
multishot++;
/* this portion is different from hero multishot; from slash'em?
*/
/* Elven Craftsmanship makes for light, quick bows */
if (otmp->otyp == ELVEN_ARROW && !otmp->cursed)
multishot++;
if (ammo_and_launcher(otmp, uwep) && mwep->otyp == ELVEN_BOW
&& !mwep->cursed)
multishot++;
/* 1/3 of launcher enchantment */
if (ammo_and_launcher(otmp, mwep) && mwep->spe > 1)
multishot += (long) rounddiv(mwep->spe, 3);
/* Some randomness */
multishot = (long) rnd((int) multishot);
/* class bonus */
switch (monsndx(mtmp->data)) {
case PM_CAVEMAN: /* give bonus for low-tech gear */
if (skill == -P_SLING || skill == P_SPEAR)
multishot++;
break;
case PM_MONK: /* allow higher volley count */
if (skill == -P_SHURIKEN)
multishot++;
break;
case PM_RANGER:
if (skill != P_DAGGER)
multishot++;
break;
case PM_ROGUE:
if (skill == P_DAGGER)
multishot++;
break;
case PM_NINJA:
if (skill == -P_SHURIKEN || skill == -P_DART)
multishot++;
/*FALLTHRU*/
case PM_SAMURAI:
if (otmp->otyp == YA && mwep->otyp == YUMI)
multishot++;
break;
default:
break;
}
/* racial bonus */
if ((is_elf(mtmp->data) && otmp->otyp == ELVEN_ARROW
&& mwep->otyp == ELVEN_BOW)
|| (is_orc(mtmp->data) && otmp->otyp == ORCISH_ARROW
&& mwep->otyp == ORCISH_BOW)
|| (is_gnome(mtmp->data) && otmp->otyp == CROSSBOW_BOLT
&& mwep->otyp == CROSSBOW))
multishot++;
}
if (otmp->quan < multishot)
multishot = (int) otmp->quan;
if (multishot < 1)
multishot = 1;
return multishot;
}
/* mtmp throws otmp, or shoots otmp with mwep, at hero or at monster mtarg */
STATIC_OVL void
monshoot(mtmp, otmp, mwep)
struct monst *mtmp;
struct obj *otmp, *mwep;
{
struct monst *mtarg = target;
int dm = distmin(mtmp->mx, mtmp->my,
mtarg ? mtarg->mx : mtmp->mux,
mtarg ? mtarg->my : mtmp->muy),
multishot = monmulti(mtmp, otmp, mwep);
/*
* Caller must have called linedup() to set up tbx, tby.
*/
if (canseemon(mtmp)) {
const char *onm;
char onmbuf[BUFSZ], trgbuf[BUFSZ];
if (multishot > 1) {
/* "N arrows"; multishot > 1 implies otmp->quan > 1, so
xname()'s result will already be pluralized */
Sprintf(onmbuf, "%d %s", multishot, xname(otmp));
onm = onmbuf;
} else {
/* "an arrow" */
onm = singular(otmp, xname);
onm = obj_is_pname(otmp) ? the(onm) : an(onm);
}
m_shot.s = ammo_and_launcher(otmp, mwep) ? TRUE : FALSE;
Strcpy(trgbuf, mtarg ? mon_nam(mtarg) : "");
if (!strcmp(trgbuf, "it"))
Strcpy(trgbuf, humanoid(mtmp->data) ? "someone" : something);
pline("%s %s %s%s%s!", Monnam(mtmp),
m_shot.s ? "shoots" : "throws", onm,
mtarg ? " at " : "", trgbuf);
m_shot.o = otmp->otyp;
} else {
m_shot.o = STRANGE_OBJECT; /* don't give multishot feedback */
}
m_shot.n = multishot;
for (m_shot.i = 1; m_shot.i <= m_shot.n; m_shot.i++) {
m_throw(mtmp, mtmp->mx, mtmp->my, sgn(tbx), sgn(tby), dm, otmp);
/* conceptually all N missiles are in flight at once, but
if mtmp gets killed (shot kills adjacent gas spore and
triggers explosion, perhaps), inventory will be dropped
and otmp might go away via merging into another stack */
if (mtmp->mhp <= 0 && m_shot.i < m_shot.n)
/* cancel pending shots (perhaps ought to give a message here
since we gave one above about throwing/shooting N missiles) */
break; /* endmultishot(FALSE); */
}
/* reset 'm_shot' */
m_shot.n = m_shot.i = 0;
m_shot.o = STRANGE_OBJECT;
m_shot.s = FALSE;
}
/* an object launched by someone/thing other than player attacks a monster;
return 1 if the object has stopped moving (hit or its range used up) */
int
@@ -143,17 +296,27 @@ boolean verbose; /* give message(s) even when you can't see what happened */
int damage, tmp;
boolean vis, ismimic;
int objgone = 1;
struct obj *mon_launcher = archer ? MON_WEP(archer) : NULL;
notonhead = (bhitpos.x != mtmp->mx || bhitpos.y != mtmp->my);
ismimic = mtmp->m_ap_type && mtmp->m_ap_type != M_AP_MONSTER;
vis = cansee(bhitpos.x, bhitpos.y);
tmp = 5 + find_mac(mtmp) + omon_adj(mtmp, otmp, FALSE);
/* High level monsters will be more likely to hit */
/* This check applies only if this monster is the target
* the archer was aiming at. */
if (archer && target == mtmp) {
if (archer->m_lev > 5)
tmp += archer->m_lev - 5;
if (mon_launcher && mon_launcher->oartifact)
tmp += spec_abon(mon_launcher, mtmp);
}
if (tmp < rnd(20)) {
if (!ismimic) {
if (vis)
miss(distant_name(otmp, mshot_xname), mtmp);
else if (verbose)
else if (verbose && !target)
pline("It is missed.");
}
if (!range) { /* Last position; object drops */
@@ -177,7 +340,7 @@ boolean verbose; /* give message(s) even when you can't see what happened */
mtmp->msleeping = 0;
if (vis)
hit(distant_name(otmp, mshot_xname), mtmp, exclam(damage));
else if (verbose)
else if (verbose && !target)
pline("%s is hit%s", Monnam(mtmp), exclam(damage));
if (otmp->opoisoned && is_poisonable(otmp)) {
@@ -199,29 +362,27 @@ boolean verbose; /* give message(s) even when you can't see what happened */
&& mon_hates_silver(mtmp)) {
if (vis)
pline_The("silver sears %s flesh!", s_suffix(mon_nam(mtmp)));
else if (verbose)
else if (verbose && !target)
pline("Its flesh is seared!");
}
if (otmp->otyp == ACID_VENOM && cansee(mtmp->mx, mtmp->my)) {
if (resists_acid(mtmp)) {
if (vis || verbose)
if (vis || (verbose && !target))
pline("%s is unaffected.", Monnam(mtmp));
damage = 0;
} else {
if (vis)
pline_The("acid burns %s!", mon_nam(mtmp));
else if (verbose)
pline_The("%s burns %s!", hliquid("acid"), mon_nam(mtmp));
else if (verbose && !target)
pline("It is burned!");
}
}
mtmp->mhp -= damage;
if (mtmp->mhp < 1) {
if (vis || verbose)
if (vis || (verbose && !target))
pline("%s is %s!", Monnam(mtmp),
(nonliving(mtmp->data) || is_vampshifter(mtmp)
|| !canspotmon(mtmp))
? "destroyed"
: "killed");
|| !canspotmon(mtmp)) ? "destroyed" : "killed");
/* don't blame hero for unknown rolling boulder trap */
if (!context.mon_moving
&& (otmp->otyp != BOULDER || range >= 0 || otmp->otrapped))
@@ -231,8 +392,8 @@ boolean verbose; /* give message(s) even when you can't see what happened */
}
if (can_blnd((struct monst *) 0, mtmp,
(uchar) (otmp->otyp == BLINDING_VENOM ? AT_SPIT
: AT_WEAP),
(uchar) ((otmp->otyp == BLINDING_VENOM) ? AT_SPIT
: AT_WEAP),
otmp)) {
if (vis && mtmp->mcansee)
pline("%s is blinded by %s.", Monnam(mtmp), the(xname(otmp)));
@@ -262,7 +423,7 @@ struct obj *obj; /* missile (or stack providing it) */
struct monst *mtmp;
struct obj *singleobj;
char sym = obj->oclass;
int hitu, oldumort, blindinc = 0;
int hitu = 0, oldumort, blindinc = 0;
bhitpos.x = x;
bhitpos.y = y;
@@ -354,9 +515,10 @@ struct obj *obj; /* missile (or stack providing it) */
You(
"accept %s gift in the spirit in which it was intended.",
s_suffix(mon_nam(mon)));
(void) hold_another_object(
singleobj, "You catch, but drop, %s.",
xname(singleobj), "You catch:");
(void) hold_another_object(singleobj,
"You catch, but drop, %s.",
xname(singleobj),
"You catch:");
}
break;
}
@@ -412,7 +574,7 @@ struct obj *obj; /* missile (or stack providing it) */
(u.umortality > oldumort) ? 0 : 10, TRUE);
}
if (hitu && can_blnd((struct monst *) 0, &youmonst,
(uchar) (singleobj->otyp == BLINDING_VENOM
(uchar) ((singleobj->otyp == BLINDING_VENOM)
? AT_SPIT
: AT_WEAP),
singleobj)) {
@@ -443,7 +605,7 @@ struct obj *obj; /* missile (or stack providing it) */
}
}
stop_occupation();
if (hitu || !range) {
if (hitu) {
(void) drop_throw(singleobj, hitu, u.ux, u.uy);
break;
}
@@ -463,8 +625,12 @@ struct obj *obj; /* missile (or stack providing it) */
!rn2(5), 0))
/* Thrown objects "sink" */
|| IS_SINK(levl[bhitpos.x][bhitpos.y].typ)) {
if (singleobj) /* hits_bars might have destroyed it */
if (singleobj) { /* hits_bars might have destroyed it */
if (m_shot.n > 1 && (cansee(bhitpos.x, bhitpos.y)
|| (archer && canseemon(archer))))
pline("%s misses.", The(mshot_xname(singleobj)));
(void) drop_throw(singleobj, 0, bhitpos.x, bhitpos.y);
}
break;
}
tmp_at(bhitpos.x, bhitpos.y);
@@ -482,6 +648,155 @@ struct obj *obj; /* missile (or stack providing it) */
}
}
/* Monster throws item at another monster */
int
thrwmm(mtmp, mtarg)
struct monst *mtmp, *mtarg;
{
struct obj *otmp, *mwep;
register xchar x, y;
boolean ispole;
/* Polearms won't be applied by monsters against other monsters */
if (mtmp->weapon_check == NEED_WEAPON || !MON_WEP(mtmp)) {
mtmp->weapon_check = NEED_RANGED_WEAPON;
/* mon_wield_item resets weapon_check as appropriate */
if (mon_wield_item(mtmp) != 0)
return 0;
}
/* Pick a weapon */
otmp = select_rwep(mtmp);
if (!otmp)
return 0;
ispole = is_pole(otmp);
x = mtmp->mx;
y = mtmp->my;
mwep = MON_WEP(mtmp); /* wielded weapon */
if (!ispole && m_lined_up(mtarg, mtmp)) {
int chance = max(BOLT_LIM - distmin(x, y, mtarg->mx, mtarg->my), 1);
if (!mtarg->mflee || !rn2(chance)) {
if (ammo_and_launcher(otmp, mwep)
&& dist2(mtmp->mx, mtmp->my, mtarg->mx, mtarg->my)
> PET_MISSILE_RANGE2)
return 0; /* Out of range */
/* Set target monster */
target = mtarg;
archer = mtmp;
monshoot(mtmp, otmp, mwep); /* multishot shooting or throwing */
archer = target = (struct monst *) 0;
nomul(0);
return 1;
}
}
return 0;
}
/* monster spits substance at monster */
int
spitmm(mtmp, mattk, mtarg)
struct monst *mtmp, *mtarg;
struct attack *mattk;
{
struct obj *otmp;
if (mtmp->mcan) {
if (!Deaf)
pline("A dry rattle comes from %s throat.",
s_suffix(mon_nam(mtmp)));
return 0;
}
if (m_lined_up(mtarg, mtmp)) {
switch (mattk->adtyp) {
case AD_BLND:
case AD_DRST:
otmp = mksobj(BLINDING_VENOM, TRUE, FALSE);
break;
default:
impossible("bad attack type in spitmu");
/* fall through */
case AD_ACID:
otmp = mksobj(ACID_VENOM, TRUE, FALSE);
break;
}
if (!rn2(BOLT_LIM-distmin(mtmp->mx,mtmp->my,mtarg->mx,mtarg->my))) {
if (canseemon(mtmp))
pline("%s spits venom!", Monnam(mtmp));
target = mtarg;
m_throw(mtmp, mtmp->mx, mtmp->my, sgn(tbx), sgn(tby),
distmin(mtmp->mx,mtmp->my,mtarg->mx,mtarg->my), otmp);
target = (struct monst *)0;
nomul(0);
/* If this is a pet, it'll get hungry. Minions and
* spell beings won't hunger */
if (mtmp->mtame && !mtmp->isminion) {
struct edog *dog = EDOG(mtmp);
/* Hunger effects will catch up next move */
if (dog->hungrytime > 1)
dog->hungrytime -= 5;
}
return 1;
}
}
return 0;
}
/* monster breathes at monster (ranged) */
int
breamm(mtmp, mattk, mtarg)
struct monst *mtmp, *mtarg;
struct attack *mattk;
{
/* if new breath types are added, change AD_ACID to max type */
int typ = (mattk->adtyp == AD_RBRE) ? rnd(AD_ACID) : mattk->adtyp ;
if (m_lined_up(mtarg, mtmp)) {
if (mtmp->mcan) {
if (!Deaf) {
if (canseemon(mtmp))
pline("%s coughs.", Monnam(mtmp));
else
You_hear("a cough.");
}
return 0;
}
if (!mtmp->mspec_used && rn2(3)) {
if ((typ >= AD_MAGM) && (typ <= AD_ACID)) {
if (canseemon(mtmp))
pline("%s breathes %s!", Monnam(mtmp), breathwep[typ - 1]);
dobuzz((int) (-20 - (typ - 1)), (int)mattk->damn,
mtmp->mx, mtmp->my, sgn(tbx), sgn(tby), FALSE);
nomul(0);
/* breath runs out sometimes. Also, give monster some
* cunning; don't breath if the target fell asleep.
*/
mtmp->mspec_used = 6 + rn2(18);
/* If this is a pet, it'll get hungry. Minions and
* spell beings won't hunger */
if (mtmp->mtame && !mtmp->isminion) {
struct edog *dog = EDOG(mtmp);
/* Hunger effects will catch up next move */
if (dog->hungrytime >= 10)
dog->hungrytime -= 10;
}
} else impossible("Breath weapon %d used", typ-1);
} else
return 0;
}
return 1;
}
/* remove an entire item from a monster's inventory; destroy that item */
void
m_useupall(mon, obj)
@@ -520,7 +835,6 @@ struct monst *mtmp;
{
struct obj *otmp, *mwep;
xchar x, y;
int multishot;
const char *onm;
/* Rearranged beginning so monsters can use polearms not in a line */
@@ -579,101 +893,7 @@ struct monst *mtmp;
return;
mwep = MON_WEP(mtmp); /* wielded weapon */
/* Multishot calculations */
multishot = 1;
if (otmp->quan > 1L /* no point checking if there's only 1 */
/* ammo requires corresponding launcher be wielded */
&& (is_ammo(otmp)
? matching_launcher(otmp, mwep)
/* otherwise any stackable (non-ammo) weapon */
: otmp->oclass == WEAPON_CLASS)
&& !mtmp->mconf) {
int skill = (int) objects[otmp->otyp].oc_skill;
/* Assumes lords are skilled, princes are expert */
if (is_prince(mtmp->data))
multishot += 2;
else if (is_lord(mtmp->data))
multishot++;
/* fake players treated as skilled (regardless of role limits) */
else if (is_mplayer(mtmp->data))
multishot++;
/* class bonus */
switch (monsndx(mtmp->data)) {
case PM_MONK:
if (skill == -P_SHURIKEN)
multishot++;
break;
case PM_RANGER:
multishot++;
break;
case PM_ROGUE:
if (skill == P_DAGGER)
multishot++;
break;
case PM_NINJA:
if (skill == -P_SHURIKEN || skill == -P_DART)
multishot++;
/*FALLTHRU*/
case PM_SAMURAI:
if (otmp->otyp == YA && mwep && mwep->otyp == YUMI)
multishot++;
break;
default:
break;
}
/* racial bonus */
if ((is_elf(mtmp->data) && otmp->otyp == ELVEN_ARROW && mwep
&& mwep->otyp == ELVEN_BOW)
|| (is_orc(mtmp->data) && otmp->otyp == ORCISH_ARROW && mwep
&& mwep->otyp == ORCISH_BOW))
multishot++;
multishot = rnd(multishot);
if ((long) multishot > otmp->quan)
multishot = (int) otmp->quan;
}
if (canseemon(mtmp)) {
char onmbuf[BUFSZ];
if (multishot > 1) {
/* "N arrows"; multishot > 1 implies otmp->quan > 1, so
xname()'s result will already be pluralized */
Sprintf(onmbuf, "%d %s", multishot, xname(otmp));
onm = onmbuf;
} else {
/* "an arrow" */
onm = singular(otmp, xname);
onm = obj_is_pname(otmp) ? the(onm) : an(onm);
}
m_shot.s = ammo_and_launcher(otmp, mwep) ? TRUE : FALSE;
pline("%s %s %s!", Monnam(mtmp), m_shot.s ? "shoots" : "throws", onm);
m_shot.o = otmp->otyp;
} else {
m_shot.o = STRANGE_OBJECT; /* don't give multishot feedback */
}
m_shot.n = multishot;
for (m_shot.i = 1; m_shot.i <= m_shot.n; m_shot.i++) {
m_throw(mtmp, mtmp->mx, mtmp->my, sgn(tbx), sgn(tby),
distmin(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy), otmp);
/* conceptually all N missiles are in flight at once, but
if mtmp gets killed (shot kills adjacent gas spore and
triggers explosion, perhaps), inventory will be dropped
and otmp might go away via merging into another stack */
if (mtmp->mhp <= 0 && m_shot.i < m_shot.n) {
/* cancel pending shots (ought to give a message here since
we gave one above about throwing/shooting N missiles) */
break; /* endmultishot(FALSE); */
}
}
m_shot.n = m_shot.i = 0;
m_shot.o = STRANGE_OBJECT;
m_shot.s = FALSE;
monshoot(mtmp, otmp, mwep); /* multishot shooting or throwing */
nomul(0);
}
@@ -803,6 +1023,14 @@ int boulderhandling; /* 0=block, 1=ignore, 2=conditionally block */
return FALSE;
}
STATIC_OVL boolean
m_lined_up(mtarg, mtmp)
struct monst *mtarg, *mtmp;
{
return (linedup(mtarg->mx, mtarg->my, mtmp->mx, mtmp->my, 0));
}
/* is mtmp in position to use ranged attack? */
boolean
lined_up(mtmp)
+6 -3
View File
@@ -908,7 +908,8 @@ boolean with_price;
break;
}
if (obj->otyp == LEASH && obj->leashmon != 0) {
Strcat(bp, " (in use)");
Sprintf(eos(bp), " (attached to %s)",
a_monnam(find_mid(obj->leashmon, FM_FMON)));
break;
}
if (obj->otyp == CANDELABRUM_OF_INVOCATION) {
@@ -2488,7 +2489,8 @@ char oclass;
long prob = rn2(maxprob);
i = 0;
while (i < n - 1 && (prob -= (objects[validobjs[i]].oc_prob + 1)) > 0)
while (i < n - 1
&& (prob -= (objects[validobjs[i]].oc_prob + 1)) >= 0)
i++;
return validobjs[i];
}
@@ -3568,7 +3570,8 @@ typfnd:
}
otmp = oname(otmp, name);
if (otmp->oartifact) {
/* name==aname => wished for artifact (otmp->oartifact => got it) */
if (otmp->oartifact || name == aname) {
otmp->quan = 1L;
u.uconduct.wisharti++; /* KMH, conduct */
}
+13 -12
View File
@@ -420,6 +420,8 @@ static struct Comp_Opt {
#else /* use rest of file */
extern char configfile[]; /* for messages */
extern struct symparse loadsyms[];
static boolean need_redraw; /* for doset() */
@@ -917,10 +919,10 @@ rejectoption(optname)
const char *optname;
{
#ifdef MICRO
pline("\"%s\" settable only from %s.", optname, lastconfigfile);
pline("\"%s\" settable only from %s.", optname, configfile);
#else
pline("%s can be set only from NETHACKOPTIONS or %s.", optname,
lastconfigfile);
configfile);
#endif
}
@@ -941,7 +943,7 @@ const char *opts;
#endif
if (from_file)
raw_printf("Bad syntax in OPTIONS in %s: %s%s.\n", lastconfigfile,
raw_printf("Bad syntax in OPTIONS in %s: %s%s.\n", configfile,
#ifdef WIN32
"\n",
#else
@@ -2207,12 +2209,13 @@ boolean tinitial, tfrom_file;
bad_negation(fullname, TRUE);
return;
}
#ifdef CHANGE_COLOR
if (match_optname(opts, "palette", 3, TRUE)
#ifdef MAC
|| match_optname(opts, "hicolor", 3, TRUE)
#endif
) {
) {
int color_number, color_incr;
#ifndef WIN32
@@ -2227,17 +2230,16 @@ boolean tinitial, tfrom_file;
}
color_number = CLR_MAX + 4; /* HARDCODED inverse number */
color_incr = -1;
} else {
} else
#endif
{
if (negated) {
bad_negation("palette", FALSE);
return;
}
color_number = 0;
color_incr = 1;
#ifdef MAC
}
#endif
#ifdef WIN32
op = string_for_opt(opts, TRUE);
if (!alternative_palette(op))
@@ -2264,8 +2266,8 @@ boolean tinitial, tfrom_file;
#else
rgb <<= 8;
#endif
tmp = *(pt++);
if (isalpha(tmp)) {
tmp = *pt++;
if (isalpha((uchar) tmp)) {
tmp = (tmp + 9) & 0xf; /* Assumes ASCII... */
} else {
tmp &= 0xf; /* Digits in ASCII too... */
@@ -2277,9 +2279,8 @@ boolean tinitial, tfrom_file;
rgb += tmp;
}
}
if (*pt == '/') {
if (*pt == '/')
pt++;
}
change_color(color_number, rgb, reverse);
color_number += color_incr;
}
@@ -5319,7 +5320,7 @@ option_help()
winid datawin;
datawin = create_nhwindow(NHW_TEXT);
Sprintf(buf, "Set options as OPTIONS=<options> in %s", lastconfigfile);
Sprintf(buf, "Set options as OPTIONS=<options> in %s", configfile);
opt_intro[CONFIG_SLOT] = (const char *) buf;
for (i = 0; opt_intro[i]; i++)
putstr(datawin, 0, opt_intro[i]);
+303 -47
View File
@@ -1,4 +1,4 @@
/* NetHack 3.6 pager.c $NHDT-Date: 1463790247 2016/05/21 00:24:07 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.98 $ */
/* NetHack 3.6 pager.c $NHDT-Date: 1465114189 2016/06/05 08:09:49 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.107 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
@@ -17,6 +17,7 @@ STATIC_DCL struct permonst *FDECL(lookat, (int, int, char *, char *));
STATIC_DCL void FDECL(checkfile, (char *, struct permonst *,
BOOLEAN_P, BOOLEAN_P));
STATIC_DCL void FDECL(look_all, (BOOLEAN_P,BOOLEAN_P));
STATIC_DCL void NDECL(whatdoes_help);
STATIC_DCL boolean FDECL(help_menu, (int *));
STATIC_DCL void NDECL(docontact);
#ifdef PORT_HELP
@@ -74,11 +75,13 @@ char *outbuf;
mons[u.umonnum].mname, plname);
if (u.usteed)
Sprintf(eos(outbuf), ", mounted on %s", y_monnam(u.usteed));
if (u.uundetected || (Upolyd && youmonst.m_ap_type))
mhidden_description(&youmonst, FALSE, eos(outbuf));
return outbuf;
}
/* describe a hidden monster; used for look_at during extended monster
detection and for probing */
detection and for probing; also when looking at self */
void
mhidden_description(mon, altmon, outbuf)
struct monst *mon;
@@ -86,8 +89,10 @@ boolean altmon; /* for probing: if mimicking a monster, say so */
char *outbuf;
{
struct obj *otmp;
boolean fakeobj;
int x = mon->mx, y = mon->my, glyph = levl[x][y].glyph;
boolean fakeobj, isyou = (mon == &youmonst);
int x = isyou ? u.ux : mon->mx, y = isyou ? u.uy : mon->my,
glyph = (level.flags.hero_memory && !isyou) ? levl[x][y].glyph
: glyph_at(x, y);
*outbuf = '\0';
if (mon->m_ap_type == M_AP_FURNITURE
@@ -113,7 +118,7 @@ char *outbuf;
if (altmon)
Sprintf(outbuf, ", masquerading as %s",
an(mons[mon->mappearance].mname));
} else if (mon->mundetected) {
} else if (isyou ? u.uundetected : mon->mundetected) {
Strcpy(outbuf, ", hiding");
if (hides_under(mon->data)) {
Strcat(outbuf, " under ");
@@ -141,10 +146,16 @@ struct obj **obj_p;
{
boolean fakeobj = FALSE;
struct monst *mtmp;
struct obj *otmp = vobj_at(x, y);
struct obj *otmp;
int glyphotyp = glyph_to_obj(glyph);
*obj_p = (struct obj *) 0;
/* TODO: check inside containers in case glyph came from detection */
if ((otmp = sobj_at(glyphotyp, x, y)) == 0)
for (otmp = level.buriedobjlist; otmp; otmp = otmp->nobj)
if (otmp->ox == x && otmp->oy == y && otmp->otyp == glyphotyp)
break;
/* there might be a mimic here posing as an object */
mtmp = m_at(x, y);
if (mtmp && is_obj_mappear(mtmp, (unsigned) glyphotyp))
@@ -169,6 +180,11 @@ struct obj **obj_p;
(corpse type will be known even if dknown is 0, so we don't need a
touch check for cockatrice corpse--we're looking without touching) */
if (otmp && distu(x, y) <= 2 && !Blind && !Hallucination
/* redundant: we only look for an object which matches current
glyph among floor and buried objects; when !Blind, any buried
object's glyph will have been replaced by whatever is present
on the surface as soon as we moved next to its spot */
&& otmp->where == OBJ_FLOOR /* not buried */
/* terrain mode views what's already known, doesn't learn new stuff */
&& !iflags.terrainmode) /* so don't set dknown when in terrain mode */
otmp->dknown = 1; /* if a pile, clearly see the top item only */
@@ -194,7 +210,9 @@ int x, y, glyph;
} else
Strcpy(buf, something); /* sanity precaution */
if (levl[x][y].typ == STONE || levl[x][y].typ == SCORR)
if (otmp && otmp->where == OBJ_BURIED)
Strcat(buf, " (buried)");
else if (levl[x][y].typ == STONE || levl[x][y].typ == SCORR)
Strcat(buf, " embedded in stone");
else if (IS_WALL(levl[x][y].typ) || levl[x][y].typ == SDOOR)
Strcat(buf, " embedded in a wall");
@@ -229,9 +247,14 @@ int x, y;
? "peaceful "
: "",
name);
if (u.ustuck == mtmp)
Strcat(buf, (Upolyd && sticks(youmonst.data))
? ", being held" : ", holding you");
if (u.ustuck == mtmp) {
if (u.uswallow || iflags.save_uswallow) /* monster detection */
Strcat(buf, is_animal(mtmp->data)
? ", swallowing you" : ", engulfing you");
else
Strcat(buf, (Upolyd && sticks(youmonst.data))
? ", being held" : ", holding you");
}
if (mtmp->mleashed)
Strcat(buf, ", leashed to you");
@@ -328,6 +351,7 @@ char *buf, *monbuf;
buf[0] = monbuf[0] = '\0';
glyph = glyph_at(x, y);
if (u.ux == x && u.uy == y && canspotself()
&& !(iflags.save_uswallow && glyph == mon_to_glyph(u.ustuck))
&& (!iflags.terrainmode || (iflags.terrainmode & TER_MON) != 0)) {
/* fill in buf[] */
(void) self_lookat(buf);
@@ -342,7 +366,8 @@ char *buf, *monbuf;
(even if you could also see yourself via other means).
Sensing self while blind or swallowed is treated as if it
were by normal vision (cf canseeself()). */
if ((Invisible || u.uundetected) && !Blind && !u.uswallow) {
if ((Invisible || u.uundetected) && !Blind
&& !(u.uswallow || iflags.save_uswallow)) {
unsigned how = 0;
if (Infravision)
@@ -379,7 +404,17 @@ char *buf, *monbuf;
} else if (glyph_is_trap(glyph)) {
int tnum = what_trap(glyph_to_trap(glyph));
Strcpy(buf, defsyms[trap_to_defsym(tnum)].explanation);
/* Trap detection displays a bear trap at locations having
* a trapped door or trapped container or both.
* TODO: we should create actual trap types for doors and
* chests so that they can have their own glyphs and tiles.
*/
if (trapped_chest_at(tnum, x, y))
Strcpy(buf, "trapped chest"); /* might actually be a large box */
else if (trapped_door_at(tnum, x, y))
Strcpy(buf, "trapped door"); /* not "trap door"... */
else
Strcpy(buf, defsyms[trap_to_defsym(tnum)].explanation);
} else if (glyph_is_warning(glyph)) {
int warnindx = glyph_to_warning(glyph);
@@ -692,10 +727,15 @@ const char **firstmatch;
* submerged will always both be False and skip this code.)
*/
x_str = 0;
if (looked && (u.uswallow || submerged) && distu(cc.x, cc.y) > 2) {
if (!looked) {
; /* skip special handling */
} else if (((u.uswallow || submerged) && distu(cc.x, cc.y) > 2)
/* detection showing some category, so mostly background */
|| ((iflags.terrainmode & (TER_DETECT | TER_MAP)) == TER_DETECT
&& glyph == cmap_to_glyph(S_stone))) {
x_str = unreconnoitered;
need_to_look = FALSE;
} else if (looked && u.uswallow && is_swallow_sym(sym)) {
} else if (is_swallow_sym(sym)) {
x_str = mon_interior;
need_to_look = TRUE; /* for specific monster type */
}
@@ -775,9 +815,6 @@ const char **firstmatch;
}
}
#define is_cmap_trap(i) ((i) >= S_arrow_trap && (i) <= S_polymorph_trap)
#define is_cmap_drawbridge(i) ((i) >= S_vodbridge && (i) <= S_hcdbridge)
/* Now check for graphics symbols */
alt_i = (sym == (looked ? showsyms[0] : defsyms[0].sym)) ? 0 : (2 + 1);
for (hit_trap = FALSE, i = 0; i < MAXPCHARS; i++) {
@@ -936,9 +973,7 @@ coord *click_cc;
if (quick) {
from_screen = TRUE; /* yes, we want to use the cursor */
i = 'y';
}
if (i != 'y') {
} else {
menu_item *pick_list = (menu_item *) 0;
winid win;
anything any;
@@ -1026,6 +1061,10 @@ coord *click_cc;
case '?':
from_screen = FALSE;
getlin("Specify what? (type the word)", out_str);
if (strcmp(out_str, " ")) /* keep single space as-is */
/* remove leading and trailing whitespace and
condense consecutive internal whitespace */
mungspaces(out_str);
if (out_str[0] == '\0' || out_str[0] == '\033')
return 0;
@@ -1220,12 +1259,24 @@ int
doidtrap()
{
register struct trap *trap;
int x, y, tt;
int x, y, tt, glyph;
if (!getdir("^"))
return 0;
x = u.ux + u.dx;
y = u.uy + u.dy;
/* check fake bear trap from confused gold detection */
glyph = glyph_at(x, y);
if (glyph_is_trap(glyph) && (tt = glyph_to_trap(glyph)) == BEAR_TRAP) {
boolean chesttrap = trapped_chest_at(tt, x, y);
if (chesttrap || trapped_door_at(tt, x, y)) {
pline("That is a trapped %s.", chesttrap ? "chest" : "door");
return 0; /* trap ID'd, but no time elapses */
}
}
for (trap = ftrap; trap; trap = trap->ntrap)
if (trap->tx == x && trap->ty == y) {
if (!trap->tseen)
@@ -1256,40 +1307,219 @@ doidtrap()
return 0;
}
STATIC_DCL void
whatdoes_help()
{
dlb *fp;
char *p, buf[BUFSZ];
winid tmpwin = create_nhwindow(NHW_TEXT);
fp = dlb_fopen(KEYHELP, "r");
if (!fp) {
pline("Cannot open \"%s\" data file!", KEYHELP);
display_nhwindow(WIN_MESSAGE, TRUE);
return;
}
while (dlb_fgets(buf, (int) sizeof buf, fp)) {
if (*buf == '#')
continue;
for (p = buf; *p; p++)
if (*p != ' ' && *p != '\t')
break;
putstr(tmpwin, 0, p);
}
(void) dlb_fclose(fp);
display_nhwindow(tmpwin, TRUE);
destroy_nhwindow(tmpwin);
}
#define WD_STACKLIMIT 5
struct wd_stack_frame {
Bitfield(active, 1);
Bitfield(been_true, 1);
Bitfield(else_seen, 1);
};
STATIC_DCL boolean FDECL(whatdoes_cond, (char *, struct wd_stack_frame *,
int *, int));
STATIC_OVL boolean
whatdoes_cond(buf, stack, depth, lnum)
char *buf;
struct wd_stack_frame *stack;
int *depth, lnum;
{
const char badstackfmt[] = "cmdhlp: too many &%c directives at line %d.";
boolean newcond, neg, gotopt;
char *p, *q, act = buf[1];
int np = 0;
newcond = (act == '?' || !stack[*depth].been_true);
buf += 2;
mungspaces(buf);
if (act == '#' || *buf == '#' || !*buf || !newcond) {
gotopt = (*buf && *buf != '#');
*buf = '\0';
neg = FALSE; /* lint suppression */
p = q = (char *) 0;
} else {
gotopt = TRUE;
if ((neg = (*buf == '!')) != 0)
if (*++buf == ' ')
++buf;
p = index(buf, '='), q = index(buf, ':');
if (!p || (q && q < p))
p = q;
if (p) { /* we have a value specified */
/* handle a space before or after (or both) '=' (or ':') */
if (p > buf && p[-1] == ' ')
p[-1] = '\0'; /* end of keyword in buf[] */
*p++ = '\0'; /* terminate keyword, advance to start of value */
if (*p == ' ')
p++;
}
}
if (*buf && (act == '?' || act == ':')) {
if (!strcmpi(buf, "number_pad")) {
if (!p) {
newcond = iflags.num_pad;
} else {
/* convert internal encoding (separate yes/no and 0..3)
back to user-visible one (-1..4) */
np = iflags.num_pad ? (1 + iflags.num_pad_mode) /* 1..4 */
: (-1 * iflags.num_pad_mode); /* -1..0 */
newcond = FALSE;
for (; p; p = q) {
q = index(p, ',');
if (q)
*q++ = '\0';
if (atoi(p) == np) {
newcond = TRUE;
break;
}
}
}
} else if (!strcmpi(buf, "rest_on_space")) {
newcond = flags.rest_on_space;
} else if (!strcmpi(buf, "debug") || !strcmpi(buf, "wizard")) {
newcond = flags.debug; /* == wizard */
} else if (!strcmpi(buf, "shell")) {
#ifdef SHELL
/* should we also check sysopt.shellers? */
newcond = TRUE;
#else
newcond = FALSE;
#endif
} else if (!strcmpi(buf, "suspend")) {
#ifdef SUSPEND
/* sysopt.shellers is also used for dosuspend()... */
newcond = TRUE;
#else
newcond = FALSE;
#endif
} else {
impossible(
"cmdhelp: unrecognized &%c conditional at line %d: \"%.20s\"",
act, lnum, buf);
neg = FALSE;
}
/* this works for number_pad too: &? !number_pad:-1,0
would be true for 1..4 after negation */
if (neg)
newcond = !newcond;
}
switch (act) {
default:
case '#': /* comment */
break;
case '.': /* endif */
if (--*depth < 0) {
impossible(badstackfmt, '.', lnum);
*depth = 0;
}
break;
case ':': /* else or elif */
if (*depth == 0 || stack[*depth].else_seen) {
impossible(badstackfmt, ':', lnum);
*depth = 1; /* so that stack[*depth - 1] is a valid access */
}
if (stack[*depth].active || stack[*depth].been_true
|| !stack[*depth - 1].active)
stack[*depth].active = 0;
else if (newcond)
stack[*depth].active = stack[*depth].been_true = 1;
if (!gotopt)
stack[*depth].else_seen = 1;
break;
case '?': /* if */
if (++*depth >= WD_STACKLIMIT) {
impossible(badstackfmt, '?', lnum);
*depth = WD_STACKLIMIT - 1;
}
stack[*depth].active = (newcond && stack[*depth - 1].active) ? 1 : 0;
stack[*depth].been_true = stack[*depth].active;
stack[*depth].else_seen = 0;
break;
}
return stack[*depth].active ? TRUE : FALSE;
}
char *
dowhatdoes_core(q, cbuf)
char q;
char *cbuf;
{
dlb *fp;
char bufr[BUFSZ];
register char *buf = &bufr[6], ctrl, meta;
char buf[BUFSZ];
struct wd_stack_frame stack[WD_STACKLIMIT];
boolean cond;
int ctrl, meta, depth = 0, lnum = 0;
fp = dlb_fopen(CMDHELPFILE, "r");
if (!fp) {
pline("Cannot open data file!");
pline("Cannot open \"%s\" data file!", CMDHELPFILE);
return 0;
}
ctrl = ((q <= '\033') ? (q - 1 + 'A') : 0);
meta = ((0x80 & q) ? (0x7f & q) : 0);
while (dlb_fgets(buf, BUFSZ - 6, fp)) {
if ((ctrl && *buf == '^' && *(buf + 1) == ctrl)
|| (meta && *buf == 'M' && *(buf + 1) == '-'
&& *(buf + 2) == meta) || *buf == q) {
meta = (0x80 & (uchar) q) != 0;
if (meta)
q &= 0x7f;
ctrl = (0x1f & (uchar) q) == (uchar) q;
if (ctrl)
q |= 0x40; /* NUL -> '@', ^A -> 'A', ... ^Z -> 'Z', ^[ -> '[', ... */
else if (q == 0x7f)
ctrl = 1, q = '?';
(void) memset((genericptr_t) stack, 0, sizeof stack);
cond = stack[0].active = 1;
while (dlb_fgets(buf, sizeof buf, fp)) {
++lnum;
if (buf[0] == '&' && buf[1] && index("?:.#", buf[1])) {
cond = whatdoes_cond(buf, stack, &depth, lnum);
continue;
}
if (!cond)
continue;
if (meta ? (buf[0] == 'M' && buf[1] == '-'
&& (ctrl ? buf[2] == '^' && highc(buf[3]) == q
: buf[2] == q))
: (ctrl ? buf[0] == '^' && highc(buf[1]) == q
: buf[0] == q)) {
(void) strip_newline(buf);
if (ctrl && buf[2] == '\t') {
buf = bufr + 1;
(void) strncpy(buf, "^? ", 8);
buf[1] = ctrl;
} else if (meta && buf[3] == '\t') {
buf = bufr + 2;
if (index(buf, '\t'))
(void) tabexpand(buf);
if (meta && ctrl && buf[4] == ' ') {
(void) strncpy(buf, "M-^? ", 8);
buf[3] = q;
} else if (meta && buf[3] == ' ') {
(void) strncpy(buf, "M-? ", 8);
buf[2] = meta;
} else if (buf[1] == '\t') {
buf = bufr;
buf[2] = q;
} else if (ctrl && buf[2] == ' ') {
(void) strncpy(buf, "^? ", 8);
buf[1] = q;
} else if (buf[1] == ' ') {
(void) strncpy(buf, "? ", 8);
buf[0] = q;
(void) strncpy(buf + 1, " ", 7);
}
(void) dlb_fclose(fp);
Strcpy(cbuf, buf);
@@ -1297,31 +1527,57 @@ char *cbuf;
}
}
(void) dlb_fclose(fp);
if (depth != 0)
impossible("cmdhelp: mismatched &? &: &. conditionals.");
return (char *) 0;
}
int
dowhatdoes()
{
static boolean once = FALSE;
char bufr[BUFSZ];
char q, *reslt;
if (!once) {
pline("Ask about '&' or '?' to get more info.%s",
#ifdef ALTMETA
iflags.altmeta ? " (For ESC, type it twice.)" :
#endif
"");
once = TRUE;
}
#if defined(UNIX) || defined(VMS)
introff();
introff(); /* disables ^C but not ^\ */
#endif
q = yn_function("What command?", (char *) 0, '\0');
#ifdef ALTMETA
if (q == '\033' && iflags.altmeta) {
/* in an ideal world, we would know whether another keystroke
was already pending, but this is not an ideal world...
if user typed ESC, we'll essentially hang until another
character is typed */
q = yn_function("]", (char *) 0, '\0');
if (q != '\033')
q = (char) ((uchar) q | 0200);
}
#endif /*ALTMETA*/
#if defined(UNIX) || defined(VMS)
intron();
intron(); /* reenables ^C */
#endif
reslt = dowhatdoes_core(q, bufr);
if (reslt)
pline1(reslt);
else
pline("I've never heard of such commands.");
if (reslt) {
if (q == '&' || q == '?')
whatdoes_help();
pline("%s", reslt);
} else {
pline("No such command '%s', char code %d (0%03o or 0x%02x).",
visctrl(q), (uchar) q, (uchar) q, (uchar) q);
}
return 0;
}
void
STATIC_OVL void
docontact()
{
winid cwin = create_nhwindow(NHW_TEXT);
+2 -3
View File
@@ -39,7 +39,6 @@ STATIC_DCL int FDECL(traditional_loot, (BOOLEAN_P));
STATIC_DCL int FDECL(menu_loot, (int, BOOLEAN_P));
STATIC_DCL char FDECL(in_or_out_menu, (const char *, struct obj *, BOOLEAN_P,
BOOLEAN_P, BOOLEAN_P, BOOLEAN_P));
STATIC_DCL int FDECL(container_at, (int, int, BOOLEAN_P));
STATIC_DCL boolean FDECL(able_to_loot, (int, int, BOOLEAN_P));
STATIC_DCL boolean NDECL(reverse_loot);
STATIC_DCL boolean FDECL(mon_beside, (int, int));
@@ -1513,7 +1512,7 @@ encumber_msg()
}
/* Is there a container at x,y. Optional: return count of containers at x,y */
STATIC_OVL int
int
container_at(x, y, countem)
int x, y;
boolean countem;
@@ -1549,7 +1548,7 @@ boolean looting; /* loot vs tip */
/* at present, can't loot in water even when Underwater;
can tip underwater, but not when over--or stuck in--lava */
You("cannot %s things that are deep in the %s.", verb,
is_lava(x, y) ? "lava" : "water");
hliquid(is_lava(x, y) ? "lava" : "water"));
return FALSE;
} else if (nolimbs(youmonst.data)) {
pline("Without limbs, you cannot %s anything.", verb);
+8 -7
View File
@@ -807,7 +807,7 @@ int mntmp;
} else if (likes_lava(youmonst.data) && u.utrap
&& u.utraptype == TT_LAVA) {
u.utrap = 0;
pline_The("lava now feels soothing.");
pline_The("%s now feels soothing.", hliquid("lava"));
}
if (amorphous(youmonst.data) || is_whirly(youmonst.data)
|| unsolid(youmonst.data)) {
@@ -1399,11 +1399,12 @@ dohide()
(except for floor hiders [trapper or mimic] in pits) */
if (u.ustuck || (u.utrap && (u.utraptype != TT_PIT || on_ceiling))) {
You_cant("hide while you're %s.",
!u.ustuck ? "trapped" : !sticks(youmonst.data)
? "being held"
: humanoid(u.ustuck->data)
? "holding someone"
: "holding that creature");
!u.ustuck ? "trapped"
: u.uswallow ? (is_animal(u.ustuck->data) ? "swallowed"
: "engulfed")
: !sticks(youmonst.data) ? "being held"
: (humanoid(u.ustuck->data) ? "holding someone"
: "holding that creature"));
if (u.uundetected
|| (ismimic && youmonst.m_ap_type != M_AP_NOTHING)) {
u.uundetected = 0;
@@ -1418,7 +1419,7 @@ dohide()
if (IS_FOUNTAIN(levl[u.ux][u.uy].typ))
The("fountain is not deep enough to hide in.");
else
There("is no water to hide in here.");
There("is no %s to hide in here.", hliquid("water"));
u.uundetected = 0;
return 0;
}
+33 -24
View File
@@ -578,7 +578,7 @@ register struct obj *otmp;
break;
case POT_WATER:
if (!otmp->blessed && !otmp->cursed) {
pline("This tastes like water.");
pline("This tastes like %s.", hliquid("water"));
u.uhunger += rnd(10);
newuhs(FALSE);
break;
@@ -587,7 +587,7 @@ register struct obj *otmp;
if (is_undead(youmonst.data) || is_demon(youmonst.data)
|| u.ualign.type == A_CHAOTIC) {
if (otmp->blessed) {
pline("This burns like acid!");
pline("This burns like %s!", hliquid("acid"));
exercise(A_CON, FALSE);
if (u.ulycn >= LOW_PM) {
Your("affinity to %s disappears!",
@@ -616,7 +616,7 @@ register struct obj *otmp;
/* make_confused(0L, TRUE); */
} else {
if (u.ualign.type == A_LAWFUL) {
pline("This burns like acid!");
pline("This burns like %s!", hliquid("acid"));
losehp(Maybe_Half_Phys(d(2, 6)), "potion of unholy water",
KILLED_BY_AN);
} else
@@ -1241,16 +1241,18 @@ boolean your_fault;
{
const char *botlnam = bottlename();
boolean isyou = (mon == &youmonst);
int distance;
int distance, tx, ty;
struct obj *saddle = (struct obj *) 0;
boolean hit_saddle = FALSE;
if (isyou) {
tx = u.ux, ty = u.uy;
distance = 0;
pline_The("%s crashes on your %s and breaks into shards.", botlnam,
body_part(HEAD));
losehp(Maybe_Half_Phys(rnd(2)), "thrown potion", KILLED_BY_AN);
} else {
tx = mon->mx, ty = mon->my;
/* sometimes it hits the saddle */
if (((mon->misc_worn_check & W_SADDLE)
&& (saddle = which_armor(mon, W_SADDLE)))
@@ -1259,10 +1261,10 @@ boolean your_fault;
&& ((rnl(10) > 7 && obj->cursed)
|| (rnl(10) < 4 && obj->blessed) || !rn2(3)))))
hit_saddle = TRUE;
distance = distu(mon->mx, mon->my);
if (!cansee(mon->mx, mon->my))
distance = distu(tx, ty);
if (!cansee(tx, ty)) {
pline("Crash!");
else {
} else {
char *mnam = mon_nam(mon);
char buf[BUFSZ];
@@ -1285,7 +1287,7 @@ boolean your_fault;
}
/* oil doesn't instantly evaporate; Neither does a saddle hit */
if (obj->otyp != POT_OIL && !hit_saddle && cansee(mon->mx, mon->my))
if (obj->otyp != POT_OIL && !hit_saddle && cansee(tx, ty))
pline("%s.", Tobjnam(obj, "evaporate"));
if (isyou) {
@@ -1313,7 +1315,7 @@ boolean your_fault;
} else if (hit_saddle && saddle) {
char *mnam, buf[BUFSZ], saddle_glows[BUFSZ];
boolean affected = FALSE;
boolean useeit = !Blind && canseemon(mon) && cansee(mon->mx, mon->my);
boolean useeit = !Blind && canseemon(mon) && cansee(tx, ty);
mnam = x_monnam(mon, ARTICLE_THE, (char *) 0,
(SUPPRESS_IT | SUPPRESS_SADDLE), FALSE);
@@ -1331,10 +1333,8 @@ boolean your_fault;
if (useeit && !affected)
pline("%s %s wet.", buf, aobjnam(saddle, "get"));
} else {
boolean angermon = TRUE;
boolean angermon = your_fault;
if (!your_fault)
angermon = FALSE;
switch (obj->otyp) {
case POT_HEALING:
case POT_EXTRA_HEALING:
@@ -1419,7 +1419,7 @@ boolean your_fault;
pline("%s %s in pain!", Monnam(mon),
is_silent(mon->data) ? "writhes" : "shrieks");
if (!is_silent(mon->data))
wake_nearto(mon->mx, mon->my, mon->data->mlevel * 10);
wake_nearto(tx, ty, mon->data->mlevel * 10);
mon->mhp -= d(2, 6);
/* should only be by you */
if (mon->mhp < 1)
@@ -1451,14 +1451,14 @@ boolean your_fault;
break;
case POT_OIL:
if (obj->lamplit)
explode_oil(obj, mon->mx, mon->my);
explode_oil(obj, tx, ty);
break;
case POT_ACID:
if (!resists_acid(mon) && !resist(mon, POTION_CLASS, 0, NOTELL)) {
pline("%s %s in pain!", Monnam(mon),
is_silent(mon->data) ? "writhes" : "shrieks");
if (!is_silent(mon->data))
wake_nearto(mon->mx, mon->my, mon->data->mlevel * 10);
wake_nearto(tx, ty, mon->data->mlevel * 10);
mon->mhp -= d(obj->cursed ? 2 : 1, obj->blessed ? 4 : 8);
if (mon->mhp < 1) {
if (your_fault)
@@ -1480,27 +1480,36 @@ boolean your_fault;
break;
*/
}
if (angermon)
wakeup(mon);
else
mon->msleeping = 0;
/* target might have been killed */
if (mon->mhp > 0) {
if (angermon)
wakeup(mon);
else
mon->msleeping = 0;
}
}
/* Note: potionbreathe() does its own docall() */
if ((distance == 0 || ((distance < 3) && rn2(5)))
if ((distance == 0 || (distance < 3 && rn2(5)))
&& (!breathless(youmonst.data) || haseyes(youmonst.data)))
potionbreathe(obj);
else if (obj->dknown && !objects[obj->otyp].oc_name_known
&& !objects[obj->otyp].oc_uname && cansee(mon->mx, mon->my))
&& !objects[obj->otyp].oc_uname && cansee(tx, ty))
docall(obj);
if (*u.ushops && obj->unpaid) {
struct monst *shkp = shop_keeper(*in_rooms(u.ux, u.uy, SHOPBASE));
if (shkp)
/* neither of the first two cases should be able to happen;
only the hero should ever have an unpaid item, and only
when inside a tended shop */
if (!shkp) /* if shkp was killed, unpaid ought to cleared already */
obj->unpaid = 0;
else if (context.mon_moving) /* obj thrown by monster */
subfrombill(obj, shkp);
else /* obj thrown by hero */
(void) stolen_value(obj, u.ux, u.uy, (boolean) shkp->mpeaceful,
FALSE);
else
obj->unpaid = 0;
}
obfree(obj, (struct obj *) 0);
}
+1 -1
View File
@@ -1973,7 +1973,7 @@ doturn()
}
}
}
nomul(-5);
nomul(-(5 - ((u.ulevel - 1) / 6))); /* -5 .. -1 */
multi_reason = "trying to turn the monsters";
nomovemsg = You_can_move_again;
return 1;
+5 -5
View File
@@ -491,11 +491,11 @@ int roomno;
if (!rn2(5)
&& (mtmp = makemon(&mons[PM_GHOST], u.ux, u.uy, NO_MM_FLAGS))
!= 0) {
/* [TODO: alter this (at a minimum, by switching from
an exclamation to a simple declaration) if hero has
already killed enough ghosts.] */
int ngen = mvitals[PM_GHOST].born;
if (canspotmon(mtmp))
pline("An enormous ghost appears next to you!");
pline("A%s ghost appears next to you%c",
ngen < 5 ? "n enormous" : "",
ngen < 10 ? '!' : '.');
else
You("sense a presence close by!");
mtmp->mpeaceful = 0;
@@ -503,7 +503,7 @@ int roomno;
if (flags.verbose)
You("are frightened to death, and unable to move.");
nomul(-3);
multi_reason = "being terrified of a demon";
multi_reason = "being terrified of a ghost";
nomovemsg = "You regain your composure.";
}
}
+10 -3
View File
@@ -1571,7 +1571,7 @@ struct obj *sobj; /* scroll, or fake spellbook object for scroll-like spell */
break;
}
if (Underwater) {
pline_The("water around you vaporizes violently!");
pline_The("%s around you vaporizes violently!", hliquid("water"));
} else {
pline_The("scroll erupts in a tower of flame!");
iflags.last_msg = PLNMSG_TOWER_OF_FLAME; /* for explode() */
@@ -2371,7 +2371,8 @@ create_particular()
struct permonst *whichpm = NULL;
struct monst *mtmp;
boolean madeany = FALSE, randmonst = FALSE,
maketame, makepeaceful, makehostile, saddled, invisible;
maketame, makepeaceful, makehostile, saddled, invisible,
sleeping;
int fem;
tryct = 5;
@@ -2379,7 +2380,7 @@ create_particular()
monclass = MAXMCLASSES;
which = urole.malenum; /* an arbitrary index into mons[] */
maketame = makepeaceful = makehostile = FALSE;
saddled = invisible = FALSE;
sleeping = saddled = invisible = FALSE;
fem = -1; /* gender not specified */
getlin("Create what kind of monster? [type the name or symbol]", buf);
bufp = mungspaces(buf);
@@ -2389,6 +2390,10 @@ create_particular()
saddled = TRUE;
(void) memset(tmpp, ' ', sizeof "saddled " - 1);
}
if ((tmpp = strstri(bufp, "sleeping ")) != 0) {
sleeping = TRUE;
(void) memset(tmpp, ' ', sizeof "sleeping " - 1);
}
if ((tmpp = strstri(bufp, "invisible ")) != 0) {
invisible = TRUE;
(void) memset(tmpp, ' ', sizeof "invisible " - 1);
@@ -2478,6 +2483,8 @@ create_particular()
}
if (invisible)
mon_set_minvis(mtmp);
if (sleeping)
mtmp->msleeping = 1;
madeany = TRUE;
/* in case we got a doppelganger instead of what was asked
for, make it start out looking like what was asked for */
+10 -11
View File
@@ -1700,18 +1700,17 @@ plnamesuffix()
char *sptr, *eptr;
int i;
#ifdef GENERIC_USERNAMES
{
/* some generic user names will be ignored in favor of prompting */
const char *uptr = GENERIC_USERNAMES;
i = (int) strlen(plname);
if ((sptr = strstri(uptr, plname)) != 0
&& (sptr == uptr || sptr[-1] == ' ')
&& (sptr[i] == ' ' || sptr[i] == '\0'))
*plname = '\0'; /* call askname() */
/* some generic user names will be ignored in favor of prompting */
if (sysopt.genericusers) {
if (*sysopt.genericusers == '*') *plname = '\0';
else {
i = (int)strlen(plname);
if ((sptr = strstri(sysopt.genericusers, plname)) != 0
&& (sptr == sysopt.genericusers || sptr[-1] == ' ')
&& (sptr[i] == ' ' || sptr[i] == '\0'))
*plname = '\0'; /* call askname() */
}
}
#endif
do {
if (!*plname)
+2
View File
@@ -115,6 +115,8 @@ dosave0()
a few of things before saving so that they won't be restored in
an improper state; these will be no-ops for normal save sequence */
u.uinvulnerable = 0;
if (iflags.save_uswallow)
u.uswallow = 1, iflags.save_uswallow = 0;
if (iflags.save_uinwater)
u.uinwater = 1, iflags.save_uinwater = 0;
if (iflags.save_uburied)
+5 -5
View File
@@ -100,7 +100,7 @@ dosit()
u.utrap += rn1(10, 5);
} else if (u.utraptype == TT_LAVA) {
/* Must have fire resistance or they'd be dead already */
You("sit in the lava!");
You("sit in the %s!", hliquid("lava"));
if (Slimed)
burn_away_slime();
u.utrap += rnd(4);
@@ -122,7 +122,7 @@ dosit()
You("sit down on the muddy bottom.");
} else if (is_pool(u.ux, u.uy)) {
in_water:
You("sit in the water.");
You("sit in the %s.", hliquid("water"));
if (!rn2(10) && uarm)
(void) water_damage(uarm, "armor", TRUE);
if (!rn2(10) && uarmf && uarmf->otyp != WATER_WALKING_BOOTS)
@@ -141,13 +141,13 @@ dosit()
You(sit_message, "ladder");
} else if (is_lava(u.ux, u.uy)) {
/* must be WWalking */
You(sit_message, "lava");
You(sit_message, hliquid("lava"));
burn_away_slime();
if (likes_lava(youmonst.data)) {
pline_The("lava feels warm.");
pline_The("%s feels warm.", hliquid("lava"));
return 1;
}
pline_The("lava burns you!");
pline_The("%s burns you!", hliquid("lava"));
losehp(d((Fire_resistance ? 2 : 10), 10), /* lava damage */
"sitting on lava", KILLED_BY);
} else if (is_ice(u.ux, u.uy)) {
+27 -6
View File
@@ -43,6 +43,7 @@ STATIC_DCL int NDECL(throwspell);
STATIC_DCL void NDECL(cast_protection);
STATIC_DCL void FDECL(spell_backfire, (int));
STATIC_DCL const char *FDECL(spelltypemnemonic, (int));
STATIC_DCL boolean FDECL(spell_hurtle_step, (genericptr_t, int, int));
/* The roles[] table lists the role-specific values for tuning
* percent_success().
@@ -812,11 +813,11 @@ cast_protection()
? "maw"
: "ooze")
: (u.uinwater
? "water"
? hliquid("water")
: (rmtyp == CLOUD)
? "cloud"
: IS_TREE(rmtyp)
? "vegitation"
? "vegetation"
: IS_STWALL(rmtyp)
? "stone"
: "air");
@@ -1136,6 +1137,7 @@ boolean atme;
case SPE_INVISIBILITY:
(void) peffects(pseudo);
break;
/* end of potion-like spells */
case SPE_CURE_BLINDNESS:
healup(0, 0, FALSE, TRUE);
@@ -1151,10 +1153,12 @@ boolean atme;
(void) make_familiar((struct obj *) 0, u.ux, u.uy, FALSE);
break;
case SPE_CLAIRVOYANCE:
if (!BClairvoyant)
do_vicinity_map();
if (!BClairvoyant) {
if (role_skill >= P_SKILLED)
pseudo->blessed = 1; /* detect monsters as well as map */
do_vicinity_map(pseudo);
/* at present, only one thing blocks clairvoyance */
else if (uarmh && uarmh->otyp == CORNUTHAUM)
} else if (uarmh && uarmh->otyp == CORNUTHAUM)
You("sense a pointy hat on top of your %s.", body_part(HEAD));
break;
case SPE_PROTECTION:
@@ -1177,11 +1181,23 @@ boolean atme;
return 1;
}
STATIC_OVL boolean
spell_hurtle_step(arg, x, y)
genericptr_t arg;
int x, y;
{
if (!isok(x,y)) return FALSE;
if (!ZAP_POS(levl[x][y].typ)
&& !(IS_DOOR(levl[x][y].typ) && (levl[x][y].doormask & D_ISOPEN)))
return FALSE;
return TRUE;
}
/* Choose location where spell takes effect. */
STATIC_OVL int
throwspell()
{
coord cc;
coord cc, uc;
struct monst *mtmp;
if (u.uinwater) {
@@ -1214,6 +1230,11 @@ throwspell()
return 0;
}
uc.x = u.ux;
uc.y = u.uy;
walk_path(&uc, &cc, spell_hurtle_step, NULL);
u.dx = cc.x;
u.dy = cc.y;
return 1;
+4 -2
View File
@@ -289,7 +289,8 @@ boolean force; /* Quietly force this animal */
return (FALSE);
}
if (!force && Underwater && !is_swimmer(ptr)) {
You_cant("ride that creature while under water.");
You_cant("ride that creature while under %s.",
hliquid("water"));
return (FALSE);
}
if (!can_saddle(mtmp) || !can_ride(mtmp)) {
@@ -565,7 +566,8 @@ int reason; /* Player was thrown off etc. */
adjalign(-1);
}
} else if (is_lava(u.ux, u.uy)) {
pline("%s is pulled into the lava!", Monnam(mtmp));
pline("%s is pulled into the %s!", Monnam(mtmp),
hliquid("lava"));
if (!likes_lava(mdat)) {
killed(mtmp);
adjalign(-1);
+4
View File
@@ -35,6 +35,7 @@ sys_early_init()
sysopt.env_dbgfl = 0; /* haven't checked getenv("DEBUGFILES") yet */
sysopt.shellers = (char *) 0;
sysopt.explorers = (char *) 0;
sysopt.genericusers = (char *) 0;
sysopt.maxplayers = 0; /* XXX eventually replace MAX_NR_OF_PLAYERS */
/* record file */
@@ -94,6 +95,9 @@ sysopt_release()
if (sysopt.debugfiles)
free((genericptr_t) sysopt.debugfiles),
sysopt.debugfiles = (char *) 0;
if (sysopt.genericusers)
free((genericptr_t) sysopt.genericusers),
sysopt.genericusers = (char *) 0;
#ifdef PANICTRACE
if (sysopt.gdbpath)
free((genericptr_t) sysopt.gdbpath), sysopt.gdbpath = (char *) 0;
+9 -7
View File
@@ -3560,7 +3560,8 @@ drown()
}
if (!u.uinwater) {
You("%s into the water%c", Is_waterlevel(&u.uz) ? "plunge" : "fall",
You("%s into the %s%c", Is_waterlevel(&u.uz) ? "plunge" : "fall",
hliquid("water"),
Amphibious || Swimming ? '.' : '!');
if (!Swimming && !Is_waterlevel(&u.uz))
You("sink like %s.", Hallucination ? "the Titanic" : "a rock");
@@ -3657,7 +3658,7 @@ crawl:
/* time to do some strip-tease... */
boolean succ = Is_waterlevel(&u.uz) ? TRUE : emergency_disrobe(&lost);
You("try to crawl out of the water.");
You("try to crawl out of the %s.", hliquid("water"));
if (lost)
You("dump some of your gear to lose weight...");
if (succ) {
@@ -5026,13 +5027,13 @@ lava_effects()
if (!Fire_resistance) {
if (Wwalking) {
pline_The("lava here burns you!");
pline_The("%s here burns you!", hliquid("lava"));
if (usurvive) {
losehp(dmg, lava_killer, KILLED_BY); /* lava damage */
goto burn_stuff;
}
} else
You("fall into the lava!");
You("fall into the %s!", hliquid("lava"));
usurvive = Lifesaved || discover;
if (wizard)
@@ -5089,9 +5090,10 @@ lava_effects()
hero needs to escape immediately */
u.utrap = rn1(4, 4) + ((boil_away ? 2 : rn1(4, 12)) << 8);
u.utraptype = TT_LAVA;
You("sink into the lava%s!", !boil_away
? ", but it only burns slightly"
: " and are about to be immolated");
You("sink into the %s%s!", hliquid("lava"),
!boil_away
? ", but it only burns slightly"
: " and are about to be immolated");
if (u.uhp > 1)
losehp(!boil_away ? 1 : (u.uhp / 2), lava_killer,
KILLED_BY); /* lava damage */
+2
View File
@@ -1013,6 +1013,8 @@ register struct trobj *trop;
|| otyp == RIN_AGGRAVATE_MONSTER
|| otyp == RIN_HUNGER
|| otyp == WAN_NOTHING
/* orcs start with poison resistance */
|| (otyp == RIN_POISON_RESISTANCE && Race_if(PM_ORC))
/* Monks don't use weapons */
|| (otyp == SCR_ENCHANT_WEAPON && Role_if(PM_MONK))
/* wizard patch -- they already have one */
+3 -1
View File
@@ -2325,7 +2325,8 @@ boolean wep_was_destroyed;
if (Blind || !flags.verbose)
You("are splashed!");
else
You("are splashed by %s acid!", s_suffix(mon_nam(mon)));
You("are splashed by %s %s!", s_suffix(mon_nam(mon)),
hliquid("acid"));
if (!Acid_resistance)
mdamageu(mon, tmp);
@@ -2695,6 +2696,7 @@ int dmg;
pline("%s %s!", Monnam(mon),
(dmg > mon->mhp / 2) ? "wails in agony" : "cries out in pain");
mon->mhp -= dmg;
wake_nearto(mon->mx, mon->my, 30);
if (mon->mhp <= 0) {
if (context.mon_moving)
monkilled(mon, (char *) 0, AD_BLND);
+13 -12
View File
@@ -47,17 +47,17 @@ int pm;
{
switch (pm) {
case PM_WEREWOLF:
return (PM_HUMAN_WEREWOLF);
return PM_HUMAN_WEREWOLF;
case PM_HUMAN_WEREWOLF:
return (PM_WEREWOLF);
return PM_WEREWOLF;
case PM_WEREJACKAL:
return (PM_HUMAN_WEREJACKAL);
return PM_HUMAN_WEREJACKAL;
case PM_HUMAN_WEREJACKAL:
return (PM_WEREJACKAL);
return PM_WEREJACKAL;
case PM_WERERAT:
return (PM_HUMAN_WERERAT);
return PM_HUMAN_WERERAT;
case PM_HUMAN_WERERAT:
return (PM_WERERAT);
return PM_WERERAT;
default:
return NON_PM;
}
@@ -121,7 +121,8 @@ register struct monst *mon;
}
/* were-creature (even you) summons a horde */
int were_summon(ptr, yours, visible, genbuf)
int
were_summon(ptr, yours, visible, genbuf)
struct permonst *ptr;
boolean yours;
int *visible; /* number of visible helpers created */
@@ -138,20 +139,20 @@ char *genbuf;
switch (pm) {
case PM_WERERAT:
case PM_HUMAN_WERERAT:
typ =
rn2(3) ? PM_SEWER_RAT : rn2(3) ? PM_GIANT_RAT : PM_RABID_RAT;
typ = rn2(3) ? PM_SEWER_RAT
: rn2(3) ? PM_GIANT_RAT : PM_RABID_RAT;
if (genbuf)
Strcpy(genbuf, "rat");
break;
case PM_WEREJACKAL:
case PM_HUMAN_WEREJACKAL:
typ = PM_JACKAL;
typ = rn2(7) ? PM_JACKAL : rn2(3) ? PM_COYOTE : PM_FOX;
if (genbuf)
Strcpy(genbuf, "jackal");
break;
case PM_WEREWOLF:
case PM_HUMAN_WEREWOLF:
typ = rn2(5) ? PM_WOLF : PM_WINTER_WOLF;
typ = rn2(5) ? PM_WOLF : rn2(2) ? PM_WARG : PM_WINTER_WOLF;
if (genbuf)
Strcpy(genbuf, "wolf");
break;
@@ -176,7 +177,7 @@ you_were()
char qbuf[QBUFSZ];
boolean controllable_poly = Polymorph_control && !(Stunned || Unaware);
if (Unchanging || (u.umonnum == u.ulycn))
if (Unchanging || u.umonnum == u.ulycn)
return;
if (controllable_poly) {
/* `+4' => skip "were" prefix to get name of beast */
+25 -10
View File
@@ -3719,10 +3719,10 @@ xchar sx, sy;
break;
case ZT_ACID:
if (Acid_resistance) {
pline_The("acid doesn't hurt.");
pline_The("%s doesn't hurt.", hliquid("acid"));
dam = 0;
} else {
pline_The("acid burns!");
pline_The("%s burns!", hliquid("acid"));
dam = d(nd, 6);
exercise(A_STR, FALSE);
}
@@ -3869,6 +3869,15 @@ const char *fltxt;
xkilled(mon, XKILL_NOMSG | XKILL_NOCORPSE);
}
void
buzz(type,nd,sx,sy,dx,dy)
int type, nd;
xchar sx,sy;
int dx,dy;
{
dobuzz(type, nd, sx, sy, dx, dy, TRUE);
}
/*
* type == 0 to 9 : you shooting a wand
* type == 10 to 19 : you casting a spell
@@ -3879,10 +3888,11 @@ const char *fltxt;
* called with dx = dy = 0 with vertical bolts
*/
void
buzz(type, nd, sx, sy, dx, dy)
dobuzz(type, nd, sx, sy, dx, dy,say)
register int type, nd;
register xchar sx, sy;
register int dx, dy;
boolean say; /* Announce out of sight hit/miss events if true */
{
int range, abstype = abs(type) % 10;
register xchar lsx, lsy;
@@ -4009,7 +4019,8 @@ register int dx, dy;
} else {
if (!otmp) {
/* normal non-fatal hit */
hit(fltxt, mon, exclam(tmp));
if (say || canseemon(mon))
hit(fltxt, mon, exclam(tmp));
} else {
/* some armor was destroyed; no damage done */
if (canseemon(mon))
@@ -4024,7 +4035,8 @@ register int dx, dy;
}
range -= 2;
} else {
miss(fltxt, mon);
if (say || canseemon(mon))
miss(fltxt, mon);
}
} else if (sx == u.ux && sy == u.uy && range >= 0) {
nomul(0);
@@ -4059,11 +4071,14 @@ register int dx, dy;
if (!ZAP_POS(levl[sx][sy].typ)
|| (closed_door(sx, sy) && range >= 0)) {
int bounce;
int bounce, bchance;
uchar rmn;
boolean fireball;
make_bounce:
bchance = (levl[sx][sy].typ == STONE) ? 10
: (In_mines(&u.uz) && IS_WALL(levl[sx][sy].typ)) ? 20
: 75;
bounce = 0;
fireball = (type == ZT_SPELL(ZT_FIRE));
if ((--range > 0 && isok(lsx, lsy) && cansee(lsx, lsy))
@@ -4080,7 +4095,7 @@ register int dx, dy;
} else
pline_The("%s bounces!", fltxt);
}
if (!dx || !dy || !rn2(20)) {
if (!dx || !dy || !rn2(bchance)) {
dx = -dx;
dy = -dy;
} else {
@@ -4291,7 +4306,7 @@ short exploding_wand_typ;
if (lev->typ == WATER) {
/* For now, don't let WATER freeze. */
if (see_it)
pline_The("water freezes for a moment.");
pline_The("%s freezes for a moment.", hliquid("water"));
else
You_hear("a soft crackling.");
rangemod -= 1000; /* stop */
@@ -4312,11 +4327,11 @@ short exploding_wand_typ;
bury_objs(x, y);
if (see_it) {
if (lava)
Norep("The lava cools and solidifies.");
Norep("The %s cools and solidifies.", hliquid("lava"));
else if (moat)
Norep("The %s is bridged with ice!", buf);
else
Norep("The water freezes.");
Norep("The %s freezes.", hliquid("water"));
newsym(x, y);
} else if (!lava)
You_hear("a crackling sound.");
+1 -1
View File
@@ -55,7 +55,7 @@ void ClearCol(struct Window *w);
void
EditColor()
{
extern const char *configfile;
extern char configfile[];
int i, done = 0, okay = 0;
long code, qual, class;
register struct Gadget *gd, *dgad;
+2 -2
View File
@@ -1,5 +1,5 @@
# NetHack Makefile.
# NetHack 3.6 Makefile.top $NHDT-Date: 1449621572 2015/12/09 00:39:32 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.33 $
# NetHack 3.6 Makefile.top $NHDT-Date: 1465114189 2016/06/05 08:09:49 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.35 $
# Root of source tree:
NHSROOT=.
@@ -76,7 +76,7 @@ VARDAT = $(VARDATD) $(VARDATND)
# end of configuration
#
DATHELP = help hh cmdhelp history opthelp wizhelp
DATHELP = help hh cmdhelp keyhelp history opthelp wizhelp
SPEC_LEVS = asmodeus.lev baalz.lev bigrm-*.lev castle.lev fakewiz?.lev \
juiblex.lev knox.lev medusa-?.lev minend-?.lev minefill.lev \
+5
View File
@@ -30,6 +30,11 @@ EXPLORERS=*
# Uses the same syntax as the WIZARDS and EXPLORERS options above.
#SHELLERS=
# If the user name is found in this list, prompt for username instead.
# Uses the same syntax as the WIZARDS option above.
# A public server should probably disable this.
GENERICUSERS=play player game games nethack nethacker
# Use the player name for matching WIZARDS, EXPLORERS and SHELLERS,
# instead of the user's login name.
#CHECK_PLNAME=1
+1
View File
@@ -1 +1,2 @@
Makefile.* NHSUBST
*.com NHSUBST
+2 -2
View File
@@ -1,5 +1,5 @@
# NetHack Makefile (VMS) - for building nethack itself.
# NetHack 3.6 Makefile.src $NHDT-Date: 1447314365 2015/11/12 07:46:05 $ $NHDT-Branch: master $:$NHDT-Revision: 1.27 $
# NetHack 3.6 Makefile.src $NHDT-Date: 1465133388 2016/06/05 13:29:48 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.28 $
# Copy this file to [.src]Makefile. and then edit it as needed.
# The default configuration is for building with DEC C (aka Compaq C).
@@ -97,7 +97,7 @@ RANDOBJ = random.obj
# Other things that have to be reconfigured are in vmsconf.h,
# and config.h
VERSION = 3.5.0
VERSION = 3.6.1
MAKEDEFS = $(UTL)makedefs.exe;
Regular → Executable
+3 -2
View File
@@ -1,6 +1,6 @@
$ ! vms/install.com -- set up nethack 'playground'
$ !
$ ! $NHDT-Date$ $NHDT-Branch$:$NHDT-Revision$
$ ! $NHDT-Date: 1465133391 2016/06/05 13:29:51 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.9 $
$ !
$ ! Use vmsbuild.com to create nethack.exe, makedefs, and lev_comp *first*.
$ !
@@ -24,7 +24,8 @@ $
$ ! note: all filespecs contain some punctuation,
$ ! to avoid inadvertent logical name interaction
$ play_files = "PERM.,RECORD.,LOGFILE.,PANICLOG."
$ help_files = "HELP.,HH.,CMDHELP.,WIZHELP.,OPTHELP.,HISTORY.,LICENSE."
$ help_files = "HELP.,HH.,CMDHELP.,KEYHELP.,WIZHELP.,OPTHELP.," -
+ "HISTORY.,LICENSE."
$ data_files = "DATA.,RUMORS.,ORACLES.,OPTIONS.,QUEST.DAT,TRIBUTE."
$ sysconf_file = "[.sys.vms]sysconf"
$ guidebook = "[.doc]Guidebook.txt"
+1 -1
View File
@@ -1,7 +1,7 @@
$! NetHack.Com -- sample command procedure for invoking NetHack 9-JAN-1993
$ v = 'f$verify(0)'
$!
$! $NHDT-Date$ $NHDT-Branch$:$NHDT-Revision$
$! $NHDT-Date: 1465133392 2016/06/05 13:29:52 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.4 $
$!
$! Possible command line arguments include
$! "-uConan-B" !play a barbarian named Conan
+1 -1
View File
@@ -1,6 +1,6 @@
$ ! sys/vms/spec_lev.com -- preprocess nethack's special level compiler code
$ !
$ ! $NHDT-Date$ $NHDT-Branch$:$NHDT-Revision$
$ ! $NHDT-Date: 1465133393 2016/06/05 13:29:53 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.4 $
$ !
$ ! This operation needs to be performed prior to executing vmsbuild.com.
$ ! Process the scanning and parsing code for NetHack's special level
+2 -2
View File
@@ -1,6 +1,6 @@
$ ! vms/vmsbuild.com -- compile and link NetHack 3.6.* [pr]
$ version_number = "3.5.0"
$ ! $NHDT-Date$ $NHDT-Branch$:$NHDT-Revision$
$ version_number = "3.6.1"
$ ! $NHDT-Date: 1465133393 2016/06/05 13:29:53 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.15 $
$ !
$ ! usage:
$ ! $ set default [.src] !or [-.-.src] if starting from [.sys.vms]
+15 -8
View File
@@ -124,8 +124,9 @@ int bkglyph UNUSED;
}
#ifdef TEXTCOLOR
co_ptr = &map_info->text_map.colors[y][x];
colordif = (((special & MG_PET) && iflags.hilite_pet)
|| ((special & MG_OBJPILE) && iflags.hilite_pile))
colordif = (((special & MG_PET) != 0 && iflags.hilite_pet)
|| ((special & MG_OBJPILE) != 0 && iflags.hilite_pile)
|| ((special & (MG_DETECT | MG_BW_LAVA)) != 0))
? CLR_MAX : 0;
if (*co_ptr != (uchar) (color + colordif)) {
*co_ptr = (uchar) (color + colordif);
@@ -1223,7 +1224,7 @@ XtPointer widget_data; /* expose event from Window widget */
/*
* Do the actual work of the putting characters onto our X window. This
* is called from the expose event routine, the display window (flush)
* routine, and the display cursor routine. The later involves inverting
* routine, and the display cursor routine. The last involves inverting
* the foreground and background colors, which are also inverted when the
* position's color is above CLR_MAX.
*
@@ -1332,7 +1333,7 @@ boolean inverted;
struct text_map_info_t *text_map = &map_info->text_map;
#ifdef TEXTCOLOR
if (iflags.use_color) {
{
register char *c_ptr;
char *t_ptr;
int cur_col, color, win_ystart;
@@ -1359,8 +1360,13 @@ boolean inverted;
}
XDrawImageString(XtDisplay(wp->w), XtWindow(wp->w),
cur_inv ? text_map->inv_color_gcs[color]
: text_map->color_gcs[color],
iflags.use_color
? (cur_inv
? text_map->inv_color_gcs[color]
: text_map->color_gcs[color])
: (cur_inv
? text_map->inv_copy_gc
: text_map->copy_gc),
text_map->square_lbearing
+ (text_map->square_width * cur_col),
win_ystart, t_ptr, count);
@@ -1370,8 +1376,8 @@ boolean inverted;
cur_col += count;
} /* col loop */
} /* row loop */
} else
#endif /* TEXTCOLOR */
}
#else /* !TEXTCOLOR */
{
int win_row, win_xstart;
@@ -1393,6 +1399,7 @@ boolean inverted;
count);
}
}
#endif /* ?TEXTCOLOR */
}
}
+1 -2
View File
@@ -38,7 +38,6 @@
#include "hack.h"
#include "winX.h"
#include <ctype.h>
static void FDECL(menu_select, (Widget, XtPointer, XtPointer));
static void FDECL(invert_line, (struct xwindow *, x11_menu_item *, int, long));
@@ -251,7 +250,7 @@ Cardinal *num_params;
select_none(wp);
} else if (ch == '\n' || ch == '\r') {
; /* accept */
} else if (isdigit(ch)) {
} else if (digit(ch)) {
/* special case: '0' is also the default ball class */
if (ch == '0' && !menu_info->counting
&& index(menu_info->curr_menu.gacc, ch))
+5 -5
View File
@@ -1,4 +1,4 @@
/* NetHack 3.6 tilemap.c $NHDT-Date: 1457207051 2016/03/05 19:44:11 $ $NHDT-Branch: chasonr $:$NHDT-Revision: 1.29 $ */
/* NetHack 3.6 tilemap.c $NHDT-Date: 1465163425 2016/06/05 21:50:25 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.30 $ */
/* NetHack may be freely redistributed. See license for details. */
/*
@@ -581,10 +581,10 @@ struct {
{S_anti_magic_trap, "anti magic trap", "anti-magic field"},
{S_polymorph_trap, "polymorph trap", "polymorph trap"},
{S_vibrating_square, "vibrating square", "vibrating square"},
{S_vbeam, "vertical beam", "wall"},
{S_hbeam, "horizontal beam", "wall"},
{S_lslant, "left slant beam", "wall"},
{S_rslant, "right slant beam", "wall"},
{S_vbeam, "vertical beam", "cmap 65"},
{S_hbeam, "horizontal beam", "cmap 66"},
{S_lslant, "left slant beam", "cmap 67"},
{S_rslant, "right slant beam", "cmap 68"},
{S_digbeam, "dig beam", "cmap 69"},
{S_flashbeam, "flash beam", "cmap 70"},
{S_boomleft, "boom left", "cmap 71"},
+2 -1
View File
@@ -3220,7 +3220,8 @@ int bkglyph UNUSED;
/* must be after color check; term_end_color may turn off inverse too */
if (((special & MG_PET) && iflags.hilite_pet)
|| ((special & MG_OBJPILE) && iflags.hilite_pile)
|| ((special & MG_DETECT) && iflags.use_inverse)) {
|| ((special & MG_DETECT) && iflags.use_inverse)
|| ((special & MG_BW_LAVA) && iflags.use_inverse)) {
term_start_attr(ATR_INVERSE);
reverse_on = TRUE;
}
+1 -1
View File
@@ -682,7 +682,7 @@ onPaint(HWND hWnd)
&special, i, j);
ch = (char) mgch;
if (((special & MG_PET) && iflags.hilite_pet)
|| ((special & MG_DETECT)
|| ((special & (MG_DETECT | MG_BW_LAVA))
&& iflags.use_inverse)) {
back_brush =
CreateSolidBrush(nhcolor_to_RGB(CLR_GRAY));