Merge branch 'NetHack-3.6.0'

This commit is contained in:
keni
2016-06-04 09:30:59 -04:00
102 changed files with 6928 additions and 2299 deletions
+12 -11
View File
@@ -22,13 +22,14 @@ engrave.txt epitaph.txt
doc:
(files for all versions)
Guidebook.mn Guidebook.tex Guidebook.txt dgn_comp.6 dgn_comp.txt
dlb.6 dlb.txt fixes22.0 fixes30.0 fixes31.1
fixes31.2 fixes31.3 fixes32.0 fixes32.1 fixes32.2
fixes32.3 fixes33.0 fixes33.1 fixes34.0 fixes34.1
fixes34.2 fixes34.3 fixes35.0 fixes36.0 lev_comp.6
lev_comp.txt makedefs.6 makedefs.txt nethack.6 nethack.txt
recover.6 recover.txt tmac.n window.doc
config.nh Guidebook.mn Guidebook.tex Guidebook.txt dgn_comp.6
dgn_comp.txt dlb.6 dlb.txt fixes22.0 fixes30.0
fixes31.1 fixes31.2 fixes31.3 fixes32.0 fixes32.1
fixes32.2 fixes32.3 fixes33.0 fixes33.1 fixes34.0
fixes34.1 fixes34.2 fixes34.3 fixes35.0 fixes36.0
fixes36.1 lev_comp.6 lev_comp.txt makedefs.6 makedefs.txt
nethack.6 nethack.txt recover.6 recover.txt tmac.n
window.doc
include:
(files for all versions)
@@ -120,7 +121,7 @@ Install.dos Makefile.BC Makefile.GCC Makefile.MSC moveinit.pat
msdos.c msdoshlp.txt ovlinit.c pckeys.c pctiles.c
pctiles.h pcvideo.h portio.h schema1.BC schema2.BC
schema3.MSC SCHEMA35.MSC setup.bat sound.c tile2bin.c
video.c vidtxt.c vidvga.c
video.c vidtxt.c vidvesa.c vidvga.c
(files for running MSDOS binary under Windows)
nhico.uu nhpif.uu
@@ -264,9 +265,9 @@ NetHackTerm.applescript recover.pl
win/share:
(files for versions using optional tiles)
gifread.c monsters.txt objects.txt other.txt ppmwrite.c
renumtiles.pl thintile.c tile.doc tile.h tile2bmp.c
tilemap.c tiletext.c
gifread.c giftiles.c monsters.txt objects.txt other.txt
ppmwrite.c renumtiles.pl thintile.c tile.doc tile.h
tile2bmp.c tilemap.c tiletext.c
win/tty:
(files for tty versions)
+16 -9
View File
@@ -139,15 +139,22 @@ MAP
---------------------------------------------------------------------------
ENDMAP
# Dungeon Description
REGION:(01,01,23,06),lit,"ordinary"
REGION:(01,07,23,10),unlit,"ordinary"
REGION:(01,11,23,16),lit,"ordinary"
REGION:(24,01,50,06),unlit,"ordinary"
REGION:(24,07,50,10),lit,"ordinary"
REGION:(24,11,50,16),unlit,"ordinary"
REGION:(51,01,73,06),lit,"ordinary"
REGION:(51,07,73,10),unlit,"ordinary"
REGION:(51,11,73,16),lit,"ordinary"
REGION:(01,01,73,16),lit,"ordinary"
SWITCH [ 3 ] {
CASE 0:
REGION:(01,07,22,09),unlit,"ordinary"
REGION:(24,01,50,05),unlit,"ordinary"
REGION:(24,11,50,16),unlit,"ordinary"
REGION:(52,07,73,09),unlit,"ordinary"
BREAK
CASE 1:
REGION:(24,01,50,16),unlit,"ordinary"
BREAK
CASE 2:
REGION:(01,01,22,16),unlit,"ordinary"
REGION:(52,01,73,16),unlit,"ordinary"
BREAK
}
# Stairs
STAIR:random,up
STAIR:random,down
+3
View File
@@ -5231,6 +5231,9 @@ unicorn horn
warm glow stage, then I use my horn to burn off any excess and
keep me right there."
[ Unicorn Variations, by Roger Zelazny ]
unreconnoitered
Area of map which is beyond limited perception range when
underwater or engulfed by a monster.
valkyrie
* valkyrie
The Valkyries were the thirteen choosers of the slain, the
+5 -1
View File
@@ -1,4 +1,4 @@
# NetHack 3.6 dungeon.def $NHDT-Date: 1432512783 2015/05/25 00:13:03 $ $NHDT-Branch: master $:$NHDT-Revision: 1.13 $
# NetHack 3.6 dungeon.def $NHDT-Date: 1462486876 2016/05/05 22:21:16 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.14 $
# Copyright (c) 1990-95 by M. Stephenson
# NetHack may be freely redistributed. See license for details.
#
@@ -119,6 +119,10 @@ DESCRIPTION: mazelike
ALIGNMENT: chaotic
ENTRY: -1
LEVEL: "tower1" "none" @ (1, 0)
# it isn't necessary to list these last two, but doing so makes them
# show up in ^O output and in the level teleport menu
LEVEL: "tower2" "none" @ (2, 0)
LEVEL: "tower3" "none" @ (3, 0)
#
# The Endgame levels
+20 -10
View File
@@ -521,27 +521,37 @@ TRAP:"magic", random
MAZE:"baalz",' '
FLAGS: noteleport,corrmaze
GEOMETRY:right,center
# the two pools are fakes used to mark spots which need special wall fixups
# the two iron bars are eyes and spots to their left will be made diggable
MAP
-------------------------------------------------
| --- ----
| ---- | ------------ |
| ------ | --------|..........|---
| |....| -------|...........--------------
| ---- ----
| ---- | ----------- |
| ------ | ---------|.........|--P
| F....| -------|...........--------------
---....|--|..................S............|----
....--....S..----------------|............S...|
+...--....S..----------------|............S...|
---....|--|..................|............|----
| |....| -------|...........-----S--------
| ------ | --------|..........|---
| ---- | ------------ |
| --- ----
| F....| -------|...........-----S--------
| ------ | ---------|.........|--P
| ---- | ----------- |
| ---- ----
-------------------------------------------------
ENDMAP
STAIR:levregion(01,00,15,20),levregion(15,1,70,16),up
BRANCH:levregion(01,00,15,20),levregion(15,1,70,16)
TELEPORT_REGION:levregion(01,00,15,20),levregion(15,1,70,16)
NON_DIGGABLE:(00,00,46,12)
# this actually leaves the farthest right column diggable
NON_DIGGABLE:(00,00,47,12)
MAZEWALK:(00,06),west
STAIR:(44,06),down
DOOR:locked,(00,06)
IF [50%] {
TERRAIN:(34,08),'-'
TERRAIN:(34,04),'S'
TERRAIN:(29,05),'|'
TERRAIN:(29,07),'S'
}
# The fellow in residence
MONSTER:('&',"Baalzebub"),(35,06)
# Some random weapons and armor.
+7 -1
View File
@@ -80,7 +80,7 @@ Z Zap cast a spell (use Y instead of Z if number_pad is -1)
$ gold count your gold
+ spells list the spells you know; also rearrange them if desired
` classkn display known items for one class of objects
_ travel move via a shortest-path algorithm to a point on the map
_ travel move via a shortest-path algorithm to a point on the map
. rest wait a moment
, pickup pick up all you can carry
@ toggle "pickup" (auto pickup) option on and off
@@ -93,7 +93,9 @@ via the meta modifier instead of the # prefix:
M-? display extended command help (if the platform allows this)
M-2 twoweapon toggle two-weapon combat (unless number_pad is enabled)
M-a adjust adjust inventory letters
M-A annotate add a one-line note to the current dungeon level (see M-O)
M-c chat talk to someone
M-C conduct view optional challanges
M-d dip dip an object into something
M-e enhance advance or check weapon and spell skills
M-f force force a lock
@@ -102,12 +104,16 @@ M-j jump jump to another location
M-l loot loot a box on the floor
M-m monster use a monster's special ability
M-n name name a monster, an individual object, or a type of object
M-N name synonym for M-n
M-o offer offer a sacrifice to the gods
M-O overview display information about visited levels and annotations
M-p pray pray to the gods for help
M-q quit stop playing
M-r rub rub a lamp or a stone
M-R ride mount or dismount saddled steed
M-s sit sit down
M-t turn turn undead
M-T tip upend a container to dump out its contents
M-u untrap untrap something
M-v version print compile time options for this version
M-w wipe wipe off your face
+19 -1
View File
@@ -6,6 +6,8 @@
MAZE:"knox",' '
FLAGS: noteleport
GEOMETRY:center,center
# Fort's entry is via a secret door rather than a drawbridge;
# the moat must be manually circumvented.
MAP
----------------------------------------------------------------------------
| |........|...............................................................|
@@ -37,11 +39,27 @@ TELEPORT_REGION:(06,16,09,17),(0,0,0,0),up
TELEPORT_REGION:(06,16,09,17),(0,0,0,0),down
# Throne room, with Croesus on the throne
REGION:(37,08,46,11),lit,"throne"
MONSTER:('@',"Croesus"),(43,10),hostile
# 50% chance each to move throne and/or fort's entry secret door up one row
IF [50%] {
MONSTER:('@',"Croesus"),(43,10),hostile
} ELSE {
MONSTER:('@',"Croesus"),(43,09),hostile
TERRAIN:(43,09), '\'
TERRAIN:(43,10), '.'
}
IF [50%] {
TERRAIN:(47,09), 'S'
TERRAIN:(47,10), '|'
}
# The Vault
# Using unfilled morgue for
# identification in mkmaze.c
REGION:(21,08,35,11),lit,"morgue",unfilled
# Vault entrance also varies
IF [50%] {
TERRAIN:(36,09), '|'
TERRAIN:(36,10), 'S'
}
# Corner towers
REGION:(19,06,21,06),lit,"ordinary"
REGION:(46,06,48,06),lit,"ordinary"
+13 -1
View File
@@ -198,7 +198,7 @@ start: RogueEpyx
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_food: \x05 # club (as in cards)
S_potion: \xad # upside down '!'
S_scroll: \x0e # musical note
S_wand: \xe7 # greek tau
@@ -394,3 +394,15 @@ start: NHAccess
S_explode9: \047
finish
start: plain
Description: Same as Default symbols, except '+' for corner walls
S_tlcorn: '+'
S_trcorn: '+'
S_blcorn: '+'
S_brcorn: '+'
S_crwall: '+'
S_tuwall: '+'
S_tdwall: '+'
S_tlwall: '+'
S_trwall: '+'
finish #plain -- other symbols implicitly retain their default values
+1 -1
View File
@@ -5797,7 +5797,7 @@ the list 'the man who arrived just before you'.
# second paragraph is a bit "on the nose" but is too good to leave out
%passage 2
The reason for the story was a mix of many things. There was humanity's
desire to do forebidden deeds merely because they were forbidden.
desire to do forbidden deeds merely because they were forbidden.
There was its desire to find new horizons and kill the people who live
beyond them. There were the mysterious scrolls. There was the cucumber.
But mostly there was the knowledge that one day, it would all be over.
+20 -3
View File
@@ -345,7 +345,7 @@ show only your experience level here.
The number of turns elapsed so far, displayed if you have the
.op time
option set.
.lp Status
.lp "Status "
Hunger:
your current hunger status.
Values are \fBSatiated\fP, \fBNot Hungry\fP (or \fBNormal\fP),
@@ -354,7 +354,7 @@ Values are \fBSatiated\fP, \fBNot Hungry\fP (or \fBNormal\fP),
Not shown when \fBNormal\fP.
.lp ""
Encumbrance:
an indication of how what your are carrying affects your ability to move.
an indication of how what you are carrying affects your ability to move.
Values are \fBUnencumbered\fP, \fBEncumbered\fP, \fBStressed\fP,
\fBStrained\fP, \fBOvertaxed\fP, and \fBOverloaded\fP.
Not shown when \fBUnencumbered\fP.
@@ -368,7 +368,7 @@ Fatal conditions:
.lp ""
Non-fatal conditions:
\fBBlind\fP (can't see), \fBDeaf\fP (can't hear),
\fBStun\fB (stunned), \fBConf\fP (confused), \fBHallu\fP (hallucinating).
\fBStun\fP (stunned), \fBConf\fP (confused), \fBHallu\fP (hallucinating).
.lp ""
Movement modifiers:
\fBLev\fP (levitating), \fBFly\fP (flying), \fBRide\fP (riding).
@@ -876,6 +876,7 @@ Escape to a shell.
.lp #
Perform an extended command.
.lp ""
.pg
As you can see, the authors of NetHack
used up all the letters, so this is a way to introduce the less frequently
used commands.
@@ -982,6 +983,7 @@ Print compile time options for this version of NetHack.
Wipe off your face.
.lp "#? "
Help menu: get the list of available extended commands.
.lp ""
.pg
If your keyboard has a meta key (which, when pressed in combination
with another key, modifies it by setting the `meta' [8th, or `high']
@@ -1049,6 +1051,7 @@ option to have nethack combine them into meta+key.
#version
.lp M-w
#wipe
.lp ""
.pg
If the
.op number_pad
@@ -2140,6 +2143,20 @@ lets you refine how it behaves. Here are the valid prefixes:
.CC - "do not disclose it and do not prompt."
.ei
.ed
The listing of vanquished monsters can be sorted,
so there are two additional choices for `v':
.sd
.si
.CC ? "prompt you and default to ask on the prompt;"
.CC # "disclose it without prompting, ask for sort order."
.ei
.ed
Asking refers to picking one of the orderings from a menu.
The `+' disclose without prompting choice,
or being prompted and answering `y' rather than `a',
will default to showing monsters in the traditional order,
from high level to low level.
.lp ""
Omitted categories are implicitly added with `n' prefix.
Specified categories with omitted prefix implicitly use `+' prefix.
Order of the disclosure categories does not matter, program display for
+27 -10
View File
@@ -418,7 +418,7 @@ Not shown when {\it Normal}.
%.lp ""
Encumbrance:
an indication of how what your are carrying affects your ability to move.
an indication of how what you are carrying affects your ability to move.
Values are {\it Unencumbered}, {\it Encumbered}, {\it Stressed},
{\it Strained}, {\it Overtaxed}, and {\it Overloaded}.
Not shown when {\it Unencumbered}.
@@ -636,7 +636,7 @@ will give a brief reminder about how it works.
If the
{\it autodescribe\/}
option is on, a short description of what you see at each location is
shown as you move the cursor. Typing `{\tt #}' while picking a location will
shown as you move the cursor. Typing `{\tt \#}' while picking a location will
toggle that option on or off.
The
{\it whatis\verb+_+coord\/}
@@ -953,10 +953,11 @@ the exchange still takes place.
\item[\tb{X}]
Toggle two-weapon combat, if your character can do it. Also available
via the ``{\tt \#twoweapon}'' extended command.\\
+.lp ""
+(In versions prior to 3.6 this was the command to switch from normal
+play to ``explore mode'', also known as ``discovery mode'', which has now
+been moved to ``{\tt \#explore}''.)
%.lp ""
(In versions prior to 3.6 this was the command to switch from normal
play to ``explore mode'', also known as ``discovery mode'', which has now
been moved to ``{\tt \#explore}''.)
%.lp
\item[\tb{\^{}X}]
Display basic information about your character.\\
@@ -2569,6 +2570,22 @@ lets you refine how it behaves. Here are the valid prefixes:
%.ei
%.ed
The listing of vanquished monsters can be sorted,
so there are two additional choices for `{\tt v}':
%.sd
%.si
{\tt ?} --- prompt you and default to ask on the prompt;\\
{\tt\#} --- disclose it without prompting, ask for sort order.
%.ei
%.ed
Asking refers to picking one of the orderings from a menu.
The `{\tt +}' disclose without prompting choice,
or being prompted and answering `{\tt y}' rather than `{\tt a}',
will default to showing monsters in the traditional order,
from high level to low level.
.lp ""
%.lp ""
(ex.\ ``{\tt disclose:yi na +v -g o}'')
The example sets
@@ -3083,15 +3100,15 @@ The possibile settings are:
%.sd
%.si
{\tt c} --- \verb#compass ('east' or '3s' or '2n,4w')#;
{\tt m} --- \verb#map <x,y> (map column x=0 is not used)#;
{\tt s} --- \verb#screen [row,column] (row is offset to match tty usage)#;
{\tt c} --- \verb#compass ('east' or '3s' or '2n,4w')#;\\
{\tt m} --- \verb#map <x,y> (map column x=0 is not used)#;\\
{\tt s} --- \verb#screen [row,column] (row is offset to match tty usage)#;\\
{\tt n} --- \verb#none (no coordinates shown) [default]#.
%.ei
%.ed
%.lp ""
+The
The
{\it whatis\verb+_+coord\/}
option is also used with
the `{\tt /m}', `{\tt /M}', `{\tt /o}', and `{\tt /O}' sub-commands
+527
View File
@@ -0,0 +1,527 @@
# Sample config file for NetHack 3.6
#
# A '#' at the beginning of a line means the rest of the line is a comment.
#
# Some options must be set in this file, other options can be toggled while
# playing.
#
# Copy the contents of this file into
# * defaults.nh, same folder as nethack.exe or nethackW.exe (DOS, Windows)
# * ~/.nethackrc (Unix, linux, Mac OS X)
# * "NetHack Defaults" on pre-OSX Mac and BeOS
# * NetHack.cnf on Amiga, Atari, OS/2, and VMS
#
# To change the configuration, comment out the unwanted lines, and
# uncomment the configuration you want.
#
# 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.
#
# For more information about the options, see the Guidebook.
# Set your character's name.
#OPTIONS=name:Janet
# Set your character's role, race, gender, and alignment
#OPTIONS=role:Valkyrie, race:Human, gender:female, align:lawful
# Set the default dog, cat, and horse names, and your fruit
#OPTIONS=dogname:Fido
#OPTIONS=catname:Morris
#OPTIONS=horsename:Silver
#OPTIONS=fruit:guava
# Turn on autopickup, and set object types which are picked up automatically
# Both are persistent.
#OPTIONS=autopickup,pickup_types:$"=/!?+
# Automatically pick up items you threw. Persistent.
#OPTIONS=pickup_thrown
# When you pick up an item that would exceed this encumbrance
# level (Unencumbered, Burdened, streSsed, straiNed, overTaxed,
# or overLoaded), you will be asked if you want to continue. Persistent.
#OPTIONS=pickup_burden:u
# Enable messages about what your character hears
#OPTIONS=acoustics
# Causes NetHack's top level command loop to treat two character sequence
# "ESC c" as M-c, for terminals or emulators which send "ESC c" when Alt+c
# is pressed.
#OPTIONS=altmeta
# NetHack should display an ascii character map if it can.
#OPTIONS=ascii_map
# Automatically describe the terrain under cursor when asked to
# get a location on the map.
#OPTIONS=autodescribe
# Automatically dig if walking into a wall and you're wielding a digging
# implement or can otherwise dig through the wall.
#OPTIONS=autodig
# Automatically try to open doors when walking into them
#OPTIONS=autoopen
# Let NetHack fill your quiver or make ready some suitable weapon,
# when firing with empty quiver or nothing at the ready.
#OPTIONS=autoquiver
# Conduct/Role-playing: blind from birth or "zen"
#OPTIONS=blind
# Conduct/Role-playing: starts with no worn armor.
# Wearing any armor will make you lose this conduct
#OPTIONS=nudist
# Disable loading and saving of bones files
#OPTIONS=!bones
# Save game state after each level change, for possible recovery
# after program crash
#OPTIONS=checkpoint
# Allows looking at things on the screen by navigating the mouse
# over them and clicking the right mouse button
#OPTIONS=clicklook
# Show assistance when you mistype a command
#OPTIONS=cmdassist
# Display color if possible for different monsters, objects,
# and dungeon features
#OPTIONS=color
# Have user confirm attacks on pets, shopkeepers, and other
# peaceable creatures (default on).
#OPTIONS=confirm
# Highlight out-of-sight room floors with different color or glyph
#OPTIONS=dark_room
# Controls what information the program reveals when the game ends.
#OPTIONS=disclose:+i +a +v +g +c +o
# NetHack should pass eight-bit character values straight through
# to your terminal (default off).
#OPTIONS=eight_bit_tty
# Change the extended commands interface to pop-up a menu of
# available commands.
#OPTIONS=extmenu
# Objects will try to keep their inventory letters
#OPTIONS=fixinv
# Try and display on the entire screen rather than in a window.
#OPTIONS=fullscreen
# If more information is available for an object looked at with
# the '/' command, ask if you want to see it (default on).
#OPTIONS=help
# Hilight pets with a heart symbol (Windows, X11), or inverse attribute (TTY)
#OPTIONS=hilite_pet
# Visually distinguish piles of objects from individual objects
#OPTIONS=hilite_pile
# Always show the "uncursed" for inventory objects. Useful for MENUCOLORs
#OPTIONS=implicit_uncursed
# Do not show the legacy intro text at game start
#OPTIONS=!legacy
# Show lit corridors differently
#OPTIONS=lit_corridor
# Use the old 'a', 'b', and 'c' keyboard shortcuts when looting,
# rather than the mnemonics 'o', 'i', and 'b' (default off).
#OPTIONS=lootabc
# Don't deliver email in-game
#OPTIONS=!mail
# Mention in the message line when walking at a wall. Useful for blind players.
#OPTIONS=mention_walls
# How menus are shown. Values are 'traditional', 'combination',
# 'full', or 'partial'
#OPTIONS=menustyle:full
# Set menu accelerator keys
#OPTIONS=menu_deselect_all:-
#OPTIONS=menu_deselect_page:\
#OPTIONS=menu_first_page:^
#OPTIONS=menu_invert_all:@
#OPTIONS=menu_invert_page:~
#OPTIONS=menu_last_page:|
#OPTIONS=menu_next_page:>
#OPTIONS=menu_previous_page:<
#OPTIONS=menu_search::
#OPTIONS=menu_select_all:.
#OPTIONS=menu_select_page:,
# Controls how the headings in a menu are highlighted.
# Values are 'none', 'bold', 'dim', 'underline', 'blink', or 'inverse'.
# Default is 'inverse'
#OPTIONS=menu_headings:inverse
# Show object symbols in menus in the item class lines where that object symbol
# acts as an accelerator key to select items of that class.
#OPTIONS=menu_objsyms
# Do not clear the screen before drawing menus, and align menus to right
#OPTIONS=menu_overlay
# Set the number of messages saved into message history (^P -command)
#OPTIONS=msghistory:50
# Allows you to change the way recalled messages are displayed.
# The possible values are:
# 's' single message (default; only choice prior to 3.4.0)
# 'c' combination, two messages as `single', then as `full'
# 'f' full window, oldest message first
# 'r' full window reversed, newest message first
# Default is 's'. TTY only.
#OPTIONS=msg_window:s
# Allow use of the mouse for input and travel.
#OPTIONS=mouse_support
# Read the NetHack news file, if present (default on).
#OPTIONS=news
# Send padding nulls to the terminal (default on).
#OPTIONS=null
# Use number pad or vi-keys for movement?
# number_pad option can have an optional value of 0 (off), 1 (on),
# or 2 (on,legacy-mode) which causes 5='g', alt-5='G', alt-0='I'
# -1 (use vi-keys, but swap z and y, for qwertz keyboards)
#OPTIONS=number_pad:2
# Set the order in which item classes appear in your inventory
#OPTIONS=packorder:")[%?+/=!(*0_`
# A space separated list of specific situations where alternate
# prompting is desired. The default is paranoid_confirmation:pray.
#OPTIONS=paranoid_confirmation:confirm quit die bones attack pray remove
# Always show the inventory window? X11 and Windows GUI only.
#OPTIONS=perm_invent
# Specify the type of your initial pet, if you are playing a character class
# that uses multiple types of pets; or choose to have no initial pet at all.
# Possible values are "cat", "dog", "horse", and "none".
#OPTIONS=pettype:cat
# Threshold when item pile under you is shown in a popup list. Persistent.
#OPTIONS=pile_limit:5
# Game mode
# Values are 'normal', 'explore', or 'debug'.
#OPTIONS=playmode:normal
# Preload tiles into memory. MSDOS only.
#OPTIONS=preload_tiles
# When wielding a weapon, move your previous weapon to other hand
#OPTIONS=pushweapon
# Space key acts as a wait.
#OPTIONS=rest_on_space
# Controls the amount of screen updating for the map window when engaged
# in multi-turn movement. Possible values are 'teleport', 'run', 'walk',
# or 'crawl'. Default is 'run'.
#OPTIONS=runmode:run
# Ask if you really want to hit your pet
#OPTIONS=safe_pet
# Perform extra data checking. Wizard-mode only.
#OPTIONS=sanity_check
# Display a menu of existing saved games for the player to choose from
# at game startup, if it can. Not all ports support this option.
#OPTIONS=selectsaved
# Which parts of the score file to show at end of game
#OPTIONS=scores:10 top/2 around/own
# Do not show experience points in the status line
#OPTIONS=!showexp
# Show your own symbol with the symbol of your race
# eg. 'G' if you're a gnome, 'h' if dwarf, etc.
#OPTIONS=showrace
# Show score on the status line
#OPTIONS=showscore
# Suppress terminal beeps. Default on.
#OPTIONS=silent
# Controls the sorting behavior of the pickup lists for inventory.
# Possible values are 'full', 'loot', and 'none'.
#OPTIONS=sortloot:full
# Sort the pack contents by type when displaying inventory (default on).
#OPTIONS=sortpack
# Disable sparkly magic resistance animation effect
#OPTIONS=!sparkle
# Boldface monsters and --More-- (default off).
#OPTIONS=standout
# NetHack version level to suppress alert notification messages
# about feature changes for that and prior versions.
#OPTIONS=suppress_alert:3.6.0
# Show current turn in the status line
#OPTIONS=time
# When pausing momentarily for display effect, such as with explosions and
# moving objects, use a timer rather than sending extra characters to the
# screen. TTY only.
#OPTIONS=timed_delay
# Draw a tombstone graphic upon your death (default on).
#OPTIONS=tombstone
# Do not show top ten list in a separate window. Windows GUI only.
#OPTIONS=!toptenwin
# Enable travel (_) command.
#OPTIONS=travel
# Use the dark gray color
#OPTIONS=use_darkgray
# Use inverse text attribute in eg. menu titles
#OPTIONS=use_inverse
# Display this number of messages at a time in the message window.
# WinCE, Windows GUI, and GEM only.
#OPTIONS=vary_msgcount:3
# Be less verbose with the messages
#OPTIONS=!verbose
# Set the color palette for PC systems using NO_TERMS (MS-DOS only).
# The order of colors is red, green, brown, blue, magenta, cyan,
# bright.white, bright.red, bright.green, yellow, bright.blue,
# bright.magenta, and bright.cyan.
#OPTIONS=videocolors:4-2-6-1-5-3-15-12-10-14-9-13-11
# Gray shades to map to black-gray-white. possible values are 'dark',
# 'normal', and 'light'. MS-DOS only.
#OPTIONS=videoshades:normal-normal-normal
# When using '/' or ';' commands with autodescribe-option on, display
# coordinates after the description. Possible values are 'compass',
# 'map', 'screen', or 'none'
#OPTIONS=whatis_coord:map
# Windowing system to use, such as 'tty' or 'x11'.
#OPTIONS=windowtype:tty
# NetHack port should wrap long lines of text if they don't fit in
# the visible area of the window.
# WinCE only.
#OPTIONS=wraptext
# How the map window is shown? Windows GUI only.
# possible map_mode options include: tiles, ascii4x6,
# ascii6x8, ascii8x8, ascii16x8, ascii7x12, ascii8x12, ascii16x12,
# ascii12x16, ascii10x18, fit_to_screen
#OPTIONS=map_mode:tiles
# Define alternative file for the files, and the tile size
#OPTIONS=tile_file:C:\absurd64.bmp
#OPTIONS=tile_width:64,tile_height:64
# When does the map window scroll? Windows GUI only.
#OPTIONS=scroll_margin:5
# Message window settings. Windows GUI only.
#OPTIONS=font_message:Arial,font_size_message:9,align_message:top
# Menu settings. Windows GUI only.
#OPTIONS=font_menu:Arial,font_size_menu:9
# Text settings. Windows GUI only.
#OPTIONS=font_text:Courier New,font_size_text:9
# Status window settings. Windows GUI only.
#OPTIONS=font_status:Courier New,font_size_status:9
# No startup splash screen. Windows GUI only.
#OPTIONS=!splash_screen
# How does NetHack prompt for character creation. Windows GUI only.
#OPTIONS=player_selection:prompts
# NetHack should pop up dialog boxes for input.
# Windows GUI only.
#OPTIONS=popup_dialog
# Status/message window colors. Windows GUI only.
# Possible color options include:
# six digit hexadecimal RGB color value ("#8F8F8F"), black, red, green, brown,
# blue, magenta, cyan, gray (or grey), orange, brightgreen, yellow, brightblue,
# brightmagenta, brightcyan, white, trueblack, purple, silver, maroon, fuchsia,
# lime, olive, navy, teal, aqua, activeborder, activecaption, appworkspace,
# background, btnface, btnshadow, btntext, captiontext, graytext, highlight,
# highlighttext, inactiveborder, inactivecaption, menu, menutext, scrollbar,
# window, windowframe, windowtext.
# windowcolors:<window> <text_color>/<background_color>
#OPTIONS=windowcolors:status windowtext/window message windowtext/window
# HACKDIR is the default location for everything.
# Note: On Windows HACKDIR defaults to the location of the NetHack.exe or
# NetHackw.exe file so setting HACKDIR below to override that is not usually
# necessary or recommended.
#HACKDIR=c:\games\nethack
# The location that level files in progress are stored
# (default=HACKDIR, writeable)
#LEVELDIR=c:\nethack\levels
# The location where saved games are kept (default=HACKDIR, writeable)
#SAVEDIR=c:\nethack\save
# The location that bones files are kept (default=HACKDIR, writeable)
#BONESDIR=c:\nethack\save
# The location that file synchronization locks are stored
# (default=HACKDIR, writeable)
#LOCKDIR=c:\nethack\levels
# The location that a record of game aborts and self-diagnosed game problems
# is kept (default=HACKDIR, writeable)
#TROUBLEDIR=c:\nethack\trouble
# Finnish keyboards might need these modifications uncommented. Windows GUI.
# For \, @, $, [, |
#OPTIONS=subkeyvalue:171/92
#OPTIONS=subkeyvalue:178/64
#OPTIONS=subkeyvalue:180/36
#OPTIONS=subkeyvalue:184/91
#OPTIONS=subkeyvalue:188/124
# Some versions of Windows allow you to adjust the win32 console port
# colors using R-G-B settings.
#OPTIONS=palette:black-0-0-0
#OPTIONS=palette:red-210-0-0
#OPTIONS=palette:green-80-200-0
#OPTIONS=palette:brown-180-100-0
#OPTIONS=palette:blue-0-0-200
#OPTIONS=palette:magenta-128-0-128
#OPTIONS=palette:cyan-50-180-180
#OPTIONS=palette:gray-192-192-192
#OPTIONS=palette:dark gray-100-100-100
#OPTIONS=palette:orange-255-128-0
#OPTIONS=palette:bright green-0-255-0
#OPTIONS=palette:yellow-255-255-0
#OPTIONS=palette:bright blue-100-100-240
#OPTIONS=palette:bright magenta-255-0-255
#OPTIONS=palette:bright cyan-0-255-255
#OPTIONS=palette:white-255-255-255
# Set exceptions to the pickup_types option. You can use multiple exceptions.
# First character must be '<' (autopick) or '>' (don't autopick), followed
# by a regular expression.
# Always autopickup any type of arrow
#AUTOPICKUP_EXCEPTION="<arrow"
# Never autopickup any corpse
#AUTOPICKUP_EXCEPTION=">corpse"
# Never autopickup any known cursed items
#AUTOPICKUP_EXCEPTION="> cursed"
# Change the way messages are shown in the top status line.
# You can use multiple MSGTYPE lines.
# Format is MSGTYPE=type "regular expression"
# Where type is one of 'show', 'hide', 'stop', or 'norep'
# Always prompt for more after becoming hungry.
#MSGTYPE=stop "You feel hungry."
# Never show any displacing your pet messages.
#MSGTYPE=hide "You displaced .*"
# Don't repeat message when seeing same items on the floor
#MSGTYPE=norep "You see here a *"
#MSGTYPE=norep "You see here an *"
# Highlight menu lines with different colors. You need to define the colors
# with MENUCOLOR lines. Only for TTY and Windows GUI.
# Toggle menucolor use on or off
#OPTIONS=menucolors
# Define color used for a certain menu line. Format is
# MENUCOLOR="regular expression"=color
# or
# MENUCOLOR="regular expression"=color&attribute
# Show all blessed items in green
#MENUCOLOR=" blessed " = green
# Show all holy water in green
#MENUCOLOR=" holy " = green
# Show all cursed items in red
#MENUCOLOR=" cursed " = red
# Show all unholy water in red
#MENUCOLOR=" unholy " = red
# Show all cursed worn items in orange and underlined
#MENUCOLOR=" cursed .* (being worn)" = orange&underline
# Use the IBM character set rather than just plain ascii characters
# for tty window-port.
#OPTIONS=symset:IBMGraphics_2
# Use RogueEpyx character set for the rogue level
#OPTIONS=roguesymset:RogueEpyx
# Override one or more symbols in the symbols files.
# See the Guidebook for the symbol names.
# Set boulder symbol to '0'
#SYMBOLS=S_boulder:0
# or
#OPTIONS=S_boulder:0
# Load DEC text characters display symbols. Deprecated.
#OPTIONS=DECgraphics
# Load IBM text characters display symbols. Deprecated.
#OPTIONS=IBMgraphics
# Set the character symbol used for boulders. Deprecated.
#OPTION=boulder:0
# 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.
#WIZKIT=~/wizkit.txt
# User sounds
# Define the directory that contains the sound files
#SOUNDDIR=C:\nethack\sounds\
# Define a sound mapping
# SOUND=MESG "pattern" file volume
#SOUND=MESG "KAABLAMM" explosion.wav 100
# Turn on all status hilites.
#OPTIONS=statushilites
# Use highlighting in the status lines when it changes?
#OPTIONS=hilite_status:hitpoints/30%/bright-magenta/normal
+144
View File
@@ -177,6 +177,113 @@ a few types of monster (barrow wight, Nazgul, erinys) have weapon attacks that
cockatrice corpse wouldn't be inflicted
non-item-using monsters who happened to be carrying scroll or wand of fire or
a fire horn could use it to cure themselves of being turned into slime
when looting multiple containers, add 'n' for "loot next container", change
'q' and ESC from "done with this container" to "done looting"
change looting to choose ":iobrs nq" action from a menu for menustyle:Partial
wand/spell/breath zaps that reached the edge of the level on the Plane of Air
and "vanished into the aether" left temporary display effects on screen
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"
some blindness cures ignored u.ucreamed
some instances of stun or confusion timers were being overridden rather than
incremented when new stun or confusion damage was suffered
female gnome who gains level can grow up into male-only gnome lord; give an
an alternate message instead of prohibiting the promotion
kicked weapon which successfully hits monster vanishes from play
unseen landmine explosion could result in "The <monst-type> statue crumbles."
when using the 'O' command for regexp options (autopickup exceptions,
menucolors, message types), provide opportunity to add more than one
at a time [after 'add', return to add/list/remove menu]
commands invoked by uppercase meta characters: M-A, M-C, M-N, M-O, M-R, M-T
were missing from '? c' list of game commands (dat/hh)
tweak Baalzebub's lair and clean up the map display for it
symbol set definitions didn't recognize S_darkroom and S_vibrating_square
wizard mode enlightenment was reporting "very fast innately" (which is not
possible) for very fast hero who was innately fast
when attacking a monster with a rust or corrosion or acid passive
counter-attack, grease wasn't protecting the attacker's weapon
the Bell of Opening now correctly reports when it opens a trapdoor/hole
knocking can no longer send a monster through a trapdoor/hole and desaddle it
game no longer gets confused when you break an unpaid shop item while inside
a different shop
shopkeepers now correctly handle nested containers and gold in containers
for menustyle traditional, 'D' followed by (B|U|C|X)&m presented a menu of
everything, not just invent subset matching specified BUCX categories
for menustyles traditional or combination, 'A' (or object ID) followed by i
displayed an inventory of everything rather than just worn items (or
not fully identified items)
exploding chest trap would destroy uchain while still worn if uball carried
if monster shapechange message "<foo> turns into <bar>!" was given, <bar>
could be "it" (if <foo> sensed telepathically and <bar> is mindless)
automatic annotation for Ft.Ludios level got applied when a drawbridge became
mapped, but entry there is a secret door rather than a drawbridge
sortloot changed to group holy water and unholy water with water instead of
placing them among the h- and u-named items
sortloot changed to place diluted potion of foo after potion of foo instead
of listing all diluted potions followed by all non-diluted ones
digging down on a grave converted the terrain to floor but did not create a
pit and uncover the grave's contents; digging again--on floor--did
when feel_location removed a remembered-unseen-monster glyph from a known
water location while hero was levitating, the map was redrawn showing
floor instead of water at that spot
Vlad's tower2 and tower3 didn't show up in wizard-mode ^O output or ^V? menu
remove extra space from "All of your <stack-of-potions> boil and explode."
(also applies to potions freezing and to scrolls burning)
effects of cursed potion of levitation were skipped if already levitating
when engulfed, having swallower be killed by angry deity trying to zap hero
no longer violates pacifist conduct (other penalties--reduced luck or
alignment--still apply if target is something you shouldn't kill)
likewise when a monster kills inself trying to prevent turning to stone or
into slime that's been caused by the player, pacifism is not affected
metabolism adjustments: hero poly'd into metallivore form still needs to eat;
being fainted or unconscious from other than sleep now consumes
nutrition at lower rate, like being asleep already did;
starvation threshold shortened due to slower food use while fainting
after using detection magic or #terrain while underwater, then leaving water
and saving while on land, save would flag you as underwater again and
then restore would limit the map display accordingly; next move would
notice, retify things, and report "you are on solid land again"
change #terrain used while underwater to view the regular map rather than the
crippled underwater one
can see or feel adjacent lava or ice when underwater
farlook when underwater now reports "land" for adjacent non-{water,lava,ice}
and "unreconnoitered" for non-adjacent anything, instead of "dark part
of a room" for the former and either dark-room or "unexplored" for the
latter depending upon whether the spot had previously been scouted
monster who accidentally killed itself by zapping wand of fire or fire horn
at self to prevent turning into slime was not properly killed off;
it wouldn't benefit from an amulet of life saving and would trigger
impossible "dmonsfree: N removed doesn't match M pending"
resurrecting a shopkeeper corpse caused crash (replmon -> replshk -> inhishop
-> no eshk data for temporary monster being replaced with revived shk)
new character with OPTIONS=role:Valk,race:!human,align:!lawful yielded
"Shall I pick your Dwarven Valkyrie's for you?" where !human forces
dwarf and dwarf forces lawful, contradicting align:!lawful
new character with OPTIONS=role:Valk,race:random yielded
"Shall I pick your Valkyrie's race and alignment for you?" instead
of honoring race:random without asking
while in shop, undead turning at self causing carried, hero owned corpse to
resurrect claimed it belonged to shopkeeper
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
Fixes to Post-3.6.0 Problems that Were Exposed Via git Respository
------------------------------------------------------------------
fix "object lost" panic during pickup caused by sortloot revamp
more sortloot revisions
fix inventory menu for response of '?' to getobj (more sortloot revamp fallout)
rings covered by non-cursed gloves not listed as 'R' candidates
in baalz_fixup, move any monster away from the two fake pool spots
switching farlook from xname to doname was giving away information for items
located via object detection (quantity of detected gold)
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
Platform- and/or Interface-Specific Fixes
@@ -189,11 +296,24 @@ tty: responding with <return> or <enter> during role, race, &c selection
behaved same as <escape> to quit; now it will pick [random] instead
tty: rename struct variable 'filter' (role.c) and function 'winch()' (wintty.c)
to avoid conflicts with <curses.h>
tty: skip selector letter and selection indicator (-,+,#) during menu coloring
tty: '>' no longer closes a menu window
tty: if color is disabled and use_inverse is enabled, display lava in inverse
video so that it is visually distinguishable from water
tty: if "--More--" was written to leftmost column (beginning of second line)
while hero was swallowed, cursor would end up in wrong place (at end
of status line instead back on map) after message line was cleared
unix/X11: in top level Makefile, some commented out definitions of VARDATND
misspelled pilemark.xbm (as pilemark.xpm)
unix: options file with CR+LF line ends and an invalid option line resulted in
"ad option line: "whatever-the-line-was
because embedded carriage return character changed cursor's position
unix: race condition with parallel make: src/Makefile might start building
makedefs before finishing monst.o and objects.o; if so, util/Makefile
can build them too, and they might be clobbered by simultaneous write
unix: Makefile.{src,utl} ignored CPPFLAGS which is expanded by the default .c
rule by GNU make so if user had a value for that in the environment,
it would apply to some files but not others; explicitly override it
win32gui: getversionstring() was overflowing the provided Help About buffer
win32gui: guard against buffer overflow in in mswin_getlin()
win32gui: handle menu_color attribute
@@ -201,6 +321,9 @@ MacOSX: initial binary release was built from out of date source code that
had 'BETA' and 'DEBUG' inappropriately enabled
MacOSX: force TIMED_DELAY build option on so that 'runmode' run-time option
is functional
Qt: could issue impossible "Destroy called before we know if Menu or Text"
followed by crash caused by deferencing a Null pointer if player quit
immediately after creating character and declined to disclose anything
X11: core bug for '`' (backtick) and #terrain commands was only noticed by
X11 interface: impossible "add_menu: called before start_menu"
X11: enable a scroll bar in menu windows
@@ -243,6 +366,25 @@ 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
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)
default value for vibrating square symbol changed from yellow '^' to purple '~'
allow symbol set values to be specified via char within single quotes
add symbols set "plain", same as default except it uses '+' for corner walls
extend wizard-mode '#stats' command
'Q' to ready an item for quick-throwing ('f') now allows the wielded weapon to
be moved to quiver; if quantity is more than 1, it offers to split the
stack and leave 1 wielded, otherwise it requires confirmation
'Q' will accept an item count to manually split a stack as part of it being
quivered, provided the stack isn't already in the quiver slot
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
interrupt a multi turn action if hp or pw is restored to maximum
pressing d or D when cursor positioning targets doors and doorways
Platform- and/or Interface-Specific New Features
@@ -279,3 +421,5 @@ Ray Chason's MSDOS port support for some VESA modes
Code Cleanup and Reorganization
-------------------------------
removed some unused variables and dead code
the level generator no longer uses the native pRNG
+23
View File
@@ -11,6 +11,7 @@
* For "UNIX" select BSD, ULTRIX, SYSV, or HPUX in unixconf.h.
* A "VMS" option is not needed since the VMS C-compilers
* provide it (no need to change sec#1, vmsconf.h handles it).
* MacOSX uses the UNIX configruation, not the old MAC one.
*/
#define UNIX /* delete if no fork(), exec() available */
@@ -304,6 +305,28 @@
*/
/* #define DLB */ /* not supported on all platforms */
/*
* Defining REPRODUCIBLE_BUILD causes 'util/makedefs -v' to construct
* date+time in include/date.h (to be shown by nethack's 'v' command)
* from SOURCE_DATE_EPOCH in the build environment rather than use
* current date+time when makedefs is run.
*
* [The version string will show "last revision <date><time>" instead
* of "last build <date><time>" if SOURCE_DATE_EPOCH has a value
* which seems valid at the time date.h is generated. The person
* building the program is responsible for setting it correctly,
* and the value should be in UTC rather than local time. NetHack
* normally uses local time and doesn't display timezone so toggling
* REPRODUCIBLE_BUILD on or off might yield a date+time that appears
* to be incorrect relative to what the other setting produced.]
*
* Intent is to be able to rebuild the program with the same value
* and obtain an identical copy as was produced by a previous build.
* Not necessary for normal game play....
*/
/* #define REPRODUCIBLE_BUILD */ /* use getenv("SOURCE_DATE_EPOCH") instead
of current time when creating date.h */
/*
* Defining INSURANCE slows down level changes, but allows games that
* died due to program or system crashes to be resumed from the point
+4 -2
View File
@@ -243,7 +243,8 @@ E NEARDATA struct obj *migrating_objs;
E NEARDATA struct obj *billobjs;
E NEARDATA struct obj *current_wand, *thrownobj, *kickedobj;
E NEARDATA struct obj zeroobj; /* init'd and defined in decl.c */
E NEARDATA struct obj zeroobj; /* for init; &zeroobj used as special value */
E NEARDATA anything zeroany; /* init'd and defined in decl.c */
#include "you.h"
@@ -256,7 +257,8 @@ E NEARDATA struct u_realtime urealtime;
#include "pm.h"
#endif
E NEARDATA struct monst youmonst; /* init'd and defined in decl.c */
E NEARDATA struct monst zeromonst; /* for init of new or temp monsters */
E NEARDATA struct monst youmonst; /* monster details when hero is poly'd */
E NEARDATA struct monst *mydogs, *migrating_mons;
E NEARDATA struct mvitals {
+19 -9
View File
@@ -1,4 +1,4 @@
/* NetHack 3.6 extern.h $NHDT-Date: 1456992437 2016/03/03 08:07:17 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.550 $ */
/* NetHack 3.6 extern.h $NHDT-Date: 1461967848 2016/04/29 22:10:48 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.558 $ */
/* Copyright (c) Steve Creps, 1988. */
/* NetHack may be freely redistributed. See license for details. */
@@ -594,6 +594,7 @@ E void NDECL(recalc_mapseen);
E void FDECL(mapseen_temple, (struct monst *));
E void FDECL(room_discovered, (int));
E void FDECL(recbranch_mapseen, (d_level *, d_level *));
E void FDECL(overview_stats, (winid, const char *, long *, long *));
E void FDECL(remdun_mapseen, (int));
/* ### eat.c ### */
@@ -680,6 +681,7 @@ E int NDECL(doengrave);
E void NDECL(sanitize_engravings);
E void FDECL(save_engravings, (int, int));
E void FDECL(rest_engravings, (int));
E void FDECL(engr_stats, (const char *, char *, long *, long *));
E void FDECL(del_engr, (struct engr *));
E void FDECL(rloc_engr, (struct engr *));
E void FDECL(make_grave, (int, int, const char *));
@@ -891,8 +893,7 @@ E int NDECL(midnight);
/* ### invent.c ### */
E struct obj **FDECL(objarr_init, (int));
E void FDECL(objarr_set, (struct obj *, int, struct obj **, BOOLEAN_P));
E void FDECL(sortloot, (struct obj **, unsigned, BOOLEAN_P));
E void FDECL(assigninvlet, (struct obj *));
E struct obj *FDECL(merge_choice, (struct obj *, struct obj *));
E int FDECL(merged, (struct obj **, struct obj **));
@@ -921,6 +922,7 @@ E boolean FDECL(obj_here, (struct obj *, int, int));
E boolean NDECL(wearing_armor);
E boolean FDECL(is_worn, (struct obj *));
E struct obj *FDECL(g_at, (int, int));
E boolean FDECL(splittable, (struct obj *));
E struct obj *FDECL(getobj, (const char *, const char *));
E int FDECL(ggetobj, (const char *, int (*)(OBJ_P), int,
BOOLEAN_P, unsigned *));
@@ -985,6 +987,7 @@ E void FDECL(do_light_sources, (char **));
E struct monst *FDECL(find_mid, (unsigned, unsigned));
E void FDECL(save_light_sources, (int, int, int));
E void FDECL(restore_light_sources, (int));
E void FDECL(light_stats, (const char *, char *, long *, long *));
E void FDECL(relink_light_sources, (BOOLEAN_P));
E void NDECL(light_sources_sanity_check);
E void FDECL(obj_move_light_source, (struct obj *, struct obj *));
@@ -1067,6 +1070,7 @@ E void FDECL(nocmov, (int x, int y));
#ifdef MAIL
#ifdef UNIX
E void NDECL(free_maildata);
E void NDECL(getmailstatus);
E void NDECL(ck_server_admin_msg);
#endif
@@ -1417,6 +1421,7 @@ E boolean FDECL(onscary, (int, int, struct monst *));
E void FDECL(monflee, (struct monst *, int, BOOLEAN_P, BOOLEAN_P));
E void FDECL(mon_yells, (struct monst *, const char *));
E int FDECL(dochug, (struct monst *));
E boolean FDECL(m_digweapon_check, (struct monst *, XCHAR_P, XCHAR_P));
E int FDECL(m_move, (struct monst *, int));
E void FDECL(dissolve_bars, (int, int));
E boolean FDECL(closed_door, (int, int));
@@ -1591,6 +1596,7 @@ E char *FDECL(xname, (struct obj *));
E char *FDECL(mshot_xname, (struct obj *));
E boolean FDECL(the_unique_obj, (struct obj *));
E boolean FDECL(the_unique_pm, (struct permonst *));
E boolean FDECL(erosion_matters, (struct obj *));
E char *FDECL(doname, (struct obj *));
E char *FDECL(doname_with_price, (struct obj *));
E boolean FDECL(not_fully_identified, (struct obj *));
@@ -1661,7 +1667,7 @@ E void NDECL(free_symsets);
E boolean FDECL(parsesymbols, (char *));
E struct symparse *FDECL(match_sym, (char *));
E void NDECL(set_playmode);
E int FDECL(sym_val, (char *));
E int FDECL(sym_val, (const char *));
E const char *FDECL(clr2colorname, (int));
E int FDECL(match_str2clr, (char *));
E boolean FDECL(add_menu_coloring, (char *));
@@ -1754,16 +1760,16 @@ E int FDECL(out_container, (struct obj *));
#endif
E int FDECL(pickup, (int));
E int FDECL(pickup_object, (struct obj *, long, BOOLEAN_P));
E int FDECL(query_category,
(const char *, struct obj *, int, menu_item **, int));
E int FDECL(query_objlist, (const char *, struct obj *, int, menu_item **,
int, boolean (*)(OBJ_P)));
E int FDECL(query_category, (const char *, struct obj *, int,
menu_item **, int));
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 NDECL(doloot);
E boolean FDECL(container_gone, (int (*)(OBJ_P)));
E boolean NDECL(u_handsy);
E int FDECL(use_container, (struct obj **, int));
E int FDECL(use_container, (struct obj **, int, BOOLEAN_P));
E int FDECL(loot_mon, (struct monst *, int *, boolean *));
E int NDECL(dotip);
E boolean FDECL(is_autopickup_exception, (struct obj *, BOOLEAN_P));
@@ -1788,6 +1794,7 @@ E const char *FDECL(align_str, (ALIGNTYP_P));
E void FDECL(mstatusline, (struct monst *));
E void NDECL(ustatusline);
E void NDECL(self_invis_message);
E char *FDECL(piousness, (BOOLEAN_P, const char *));
E void FDECL(pudding_merge_message, (struct obj *, struct obj *));
/* ### polyself.c ### */
@@ -1963,6 +1970,7 @@ E NhRegion *FDECL(visible_region_at, (XCHAR_P, XCHAR_P));
E void FDECL(show_region, (NhRegion *, XCHAR_P, XCHAR_P));
E void FDECL(save_regions, (int, int));
E void FDECL(rest_regions, (int, BOOLEAN_P));
E void FDECL(region_stats, (const char *, char *, long *, long *));
E NhRegion *FDECL(create_gas_cloud, (XCHAR_P, XCHAR_P, int, int));
E boolean NDECL(region_danger);
E void NDECL(region_safety);
@@ -2307,6 +2315,7 @@ E long FDECL(spot_time_left, (XCHAR_P, XCHAR_P, SHORT_P));
E boolean FDECL(obj_is_local, (struct obj *));
E void FDECL(save_timers, (int, int, int));
E void FDECL(restore_timers, (int, int, BOOLEAN_P, long));
E void FDECL(timer_stats, (const char *, char *, long *, long *));
E void FDECL(relink_timers, (BOOLEAN_P));
E int NDECL(wiz_timeout_queue);
E void NDECL(timer_sanity_check);
@@ -2712,6 +2721,7 @@ E void FDECL(rest_worm, (int));
E void FDECL(place_wsegs, (struct monst *));
E void FDECL(remove_worm, (struct monst *));
E void FDECL(place_worm_tail_randomly, (struct monst *, XCHAR_P, XCHAR_P));
E int FDECL(size_wseg, (struct monst *));
E int FDECL(count_wsegs, (struct monst *));
E boolean FDECL(worm_known, (struct monst *));
E boolean FDECL(worm_cross, (int, int, int, int));
+21 -11
View File
@@ -1,10 +1,10 @@
/* NetHack 3.6 flag.h $NHDT-Date: 1457207000 2016/03/05 19:43:20 $ $NHDT-Branch: chasonr $:$NHDT-Revision: 1.101 $ */
/* NetHack 3.6 flag.h $NHDT-Date: 1461102045 2016/04/19 21:40:45 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.103 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
/* If you change the flag structure make sure you increment EDITLEVEL in */
/* patchlevel.h if needed. Changing the instance_flags structure does */
/* not require incrementing EDITLEVEL. */
/* patchlevel.h if needed. Changing the instance_flags structure does */
/* not require incrementing EDITLEVEL. */
#ifndef FLAG_H
#define FLAG_H
@@ -48,7 +48,7 @@ struct flag {
boolean showexp; /* show experience points */
boolean showscore; /* show score */
boolean silent; /* whether the bell rings or not */
boolean sortloot; /* sort items alphabetically when looting */
char sortloot; /* 'n'=none, 'l'=loot (pickup), 'f'=full ('l'+invent) */
boolean sortpack; /* sorted inventory */
boolean sparkle; /* show "resisting" special FX (Scott Bigham) */
boolean standout; /* use standout for --More-- */
@@ -76,8 +76,10 @@ struct flag {
#define NUM_DISCLOSURE_OPTIONS 6 /* i,a,v,g,c,o (decl.c) */
#define DISCLOSE_PROMPT_DEFAULT_YES 'y'
#define DISCLOSE_PROMPT_DEFAULT_NO 'n'
#define DISCLOSE_PROMPT_DEFAULT_SPECIAL '?' /* v, default a */
#define DISCLOSE_YES_WITHOUT_PROMPT '+'
#define DISCLOSE_NO_WITHOUT_PROMPT '-'
#define DISCLOSE_SPECIAL_WITHOUT_PROMPT '#' /* v, use a */
char end_disclose[NUM_DISCLOSURE_OPTIONS + 1]; /* disclose various
info upon exit */
char menu_style; /* User interface style setting */
@@ -95,7 +97,7 @@ struct flag {
* characters or letters, because that limits us to 26 roles.
* They are not booleans, because someday someone may need a neuter
* gender. Negative values are used to indicate that the user
* hasn't yet specified that particular value. If you determine
* hasn't yet specified that particular value. If you determine
* that the user wants a random choice, then you should set an
* appropriate random value; if you just left the negative value,
* the user would be asked again!
@@ -184,17 +186,24 @@ struct instance_flags {
int purge_monsters; /* # of dead monsters still on fmon list */
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
coord travelcc; /* coordinates for travel_cache */
boolean window_inited; /* true if init_nhwindows() completed */
boolean vision_inited; /* true if vision is ready */
boolean sanity_check; /* run sanity checks */
boolean mon_polycontrol; /* debug: control monster polymorphs */
/* stuff that is related to options and/or user or platform preferences */
/* stuff that is related to options and/or user or platform preferences
*/
unsigned msg_history; /* hint: # of top lines to save */
int getpos_coords; /* show coordinates when getting cursor position */
int menu_headings; /* ATR for menu headings */
int *opt_booldup; /* for duplication of boolean opts in config file */
int *opt_compdup; /* for duplication of compound opts in config file */
int *opt_compdup; /* for duplication of compound opts in conf file */
#ifdef ALTMETA
boolean altmeta; /* Alt-c sends ESC c rather than M-c */
#endif
@@ -222,11 +231,11 @@ struct instance_flags {
boolean hilite_pile; /* mark piles of objects with a hilite */
boolean autodescribe; /* autodescribe mode in getpos() */
#if 0
boolean DECgraphics; /* use DEC VT-xxx extended character set */
boolean IBMgraphics; /* use IBM extended character set */
boolean DECgraphics; /* use DEC VT-xxx extended character set */
boolean IBMgraphics; /* use IBM extended character set */
#ifdef MAC_GRAPHICS_ENV
boolean MACgraphics; /* use Macintosh extended character set, as
as defined in the special font HackFont */
boolean MACgraphics; /* use Macintosh extended character set, as
as defined in the special font HackFont */
#endif
#endif
uchar bouldersym; /* symbol for boulder display */
@@ -273,6 +282,7 @@ struct instance_flags {
boolean vt_tiledata; /* output console codes for tile support in TTY */
#endif
boolean wizweight; /* display weight of everything in wizard mode */
/*
* Window capability support.
*/
+14 -2
View File
@@ -318,8 +318,20 @@ NEARDATA extern coord bhitpos; /* place where throw or zap hits or stops */
#define BASICENLIGHTENMENT 1 /* show mundane stuff */
#define MAGICENLIGHTENMENT 2 /* show intrinsics and such */
#define ENL_GAMEINPROGRESS 0
#define ENL_GAMEOVERALIVE 1 /* ascension, escape, quit, trickery */
#define ENL_GAMEOVERDEAD 2
#define ENL_GAMEOVERALIVE 1 /* ascension, escape, quit, trickery */
#define ENL_GAMEOVERDEAD 2
/* control flags for sortloot() */
#define SORTLOOT_PACK 0x01
#define SORTLOOT_INVLET 0x02
#define SORTLOOT_LOOT 0x04
/* flags for xkilled() [note: meaning of first bit used to be reversed,
1 to give message and 0 to suppress] */
#define XKILL_GIVEMSG 0
#define XKILL_NOMSG 1
#define XKILL_NOCORPSE 2
#define XKILL_NOCONDUCT 4
/* Macros for messages referring to hands, eyes, feet, etc... */
#define ARM 0
+72 -71
View File
@@ -1,10 +1,14 @@
/* NetHack 3.6 monst.h $NHDT-Date: 1432512777 2015/05/25 00:12:57 $ $NHDT-Branch: master $:$NHDT-Revision: 1.20 $ */
/* NetHack 3.6 monst.h $NHDT-Date: 1461028522 2016/04/19 01:15:22 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.24 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
#ifndef MONST_H
#define MONST_H
#ifndef MEXTRA_H
#include "mextra.h"
#endif
/* The weapon_check flag is used two ways:
* 1) When calling mon_wield_item, is 2-6 depending on what is desired.
* 2) Between calls to mon_wield_item, is 0 or 1 depending on whether or not
@@ -15,52 +19,48 @@
* that there are enough situations which might make a monster change its
* weapon that this is impractical. --KAA
*/
#define NO_WEAPON_WANTED 0
#define NEED_WEAPON 1
#define NO_WEAPON_WANTED 0
#define NEED_WEAPON 1
#define NEED_RANGED_WEAPON 2
#define NEED_HTH_WEAPON 3
#define NEED_PICK_AXE 4
#define NEED_AXE 5
#define NEED_PICK_OR_AXE 6
#define NEED_HTH_WEAPON 3
#define NEED_PICK_AXE 4
#define NEED_AXE 5
#define NEED_PICK_OR_AXE 6
/* The following flags are used for the second argument to display_minventory
* in invent.c:
*
* PICK_NONE, PICK_ONE, PICK_ANY (wintype.h) 0, 1, 2
* MINV_NOLET If set, don't display inventory letters on monster's inventory.
* MINV_ALL If set, display all items in monster's inventory, otherwise
* just display wielded weapons and worn items.
*/
#define MINV_NOLET 0x01
#define MINV_ALL 0x02
#ifndef MEXTRA_H
#include "mextra.h"
#endif
#define MINV_PICKMASK 0x03 /* 1|2 */
#define MINV_NOLET 0x04
#define MINV_ALL 0x08
struct monst {
struct monst *nmon;
struct permonst *data;
unsigned m_id;
short mnum; /* permanent monster index number */
short cham; /* if shapeshifter, orig mons[] idx goes here */
short movement; /* movement points (derived from permonst definition and
added effects */
uchar m_lev; /* adjusted difficulty level of monster */
aligntyp malign; /* alignment of this monster, relative to the
player (positive = good to kill) */
short mnum; /* permanent monster index number */
short cham; /* if shapeshifter, orig mons[] idx goes here */
short movement; /* movement points (derived from permonst definition
and added effects */
uchar m_lev; /* adjusted difficulty level of monster */
aligntyp malign; /* alignment of this monster, relative to the
player (positive = good to kill) */
xchar mx, my;
xchar mux, muy; /* where the monster thinks you are */
xchar mux, muy; /* where the monster thinks you are */
#define MTSZ 4
coord mtrack[MTSZ]; /* monster track */
coord mtrack[MTSZ]; /* monster track */
int mhp, mhpmax;
unsigned mappearance; /* for undetected mimics and the wiz */
uchar m_ap_type; /* what mappearance is describing: */
#define M_AP_NOTHING \
0 /* mappearance is unused -- monster appears \
as itself */
#define M_AP_FURNITURE 1 /* stairs, a door, an altar, etc. */
#define M_AP_OBJECT 2 /* an object */
#define M_AP_MONSTER 3 /* a monster */
#define M_AP_NOTHING 0 /* mappearance unused--monster appears as itself */
#define M_AP_FURNITURE 1 /* stairs, a door, an altar, etc. */
#define M_AP_OBJECT 2 /* an object */
#define M_AP_MONSTER 3 /* a monster */
schar mtame; /* level of tameness, implies peaceful */
unsigned short mintrinsics; /* low 8 correspond to mresists */
@@ -72,12 +72,12 @@ struct monst {
Bitfield(perminvis, 1); /* intrinsic minvis value */
Bitfield(mcan, 1); /* has been cancelled */
Bitfield(mburied, 1); /* has been buried */
Bitfield(mundetected, 1); /* not seen in present hiding place */
/* implies one of M1_CONCEAL or M1_HIDE,
Bitfield(mundetected, 1); /* not seen in present hiding place;
* implies one of M1_CONCEAL or M1_HIDE,
* but not mimic (that is, snake, spider,
* trapper, piercer, eel)
*/
Bitfield(mcansee, 1); /* cansee 1, temp.blinded 0, blind 0 */
Bitfield(mcansee, 1); /* cansee 1, temp.blinded 0, blind 0 */
Bitfield(mspeed, 2); /* current speed */
Bitfield(permspeed, 2); /* intrinsic mspeed value */
@@ -89,11 +89,11 @@ struct monst {
Bitfield(mfleetim, 7); /* timeout for mflee */
Bitfield(msleeping, 1); /* asleep until woken */
Bitfield(mblinded, 7); /* cansee 0, temp.blinded n, blind 0 */
Bitfield(mstun, 1); /* stunned (off balance) */
Bitfield(mblinded, 7); /* cansee 0, temp.blinded n, blind 0 */
Bitfield(mstun, 1); /* stunned (off balance) */
Bitfield(mfrozen, 7);
Bitfield(mcanmove, 1); /* paralysis, similar to mblinded */
Bitfield(mcanmove, 1); /* paralysis, similar to mblinded */
Bitfield(mconf, 1); /* confused */
Bitfield(mpeaceful, 1); /* does not attack unprovoked */
@@ -102,13 +102,13 @@ struct monst {
Bitfield(isshk, 1); /* is shopkeeper */
Bitfield(isminion, 1); /* is a minion */
Bitfield(isgd, 1); /* is guard */
Bitfield(ispriest, 1); /* is a priest */
Bitfield(ispriest, 1); /* is an aligned priest or high priest */
Bitfield(iswiz, 1); /* is the Wizard of Yendor */
Bitfield(wormno, 5); /* at most 31 worms on any level */
/* 2 free bits */
Bitfield(iswiz, 1); /* is the Wizard of Yendor */
Bitfield(wormno, 5); /* at most 31 worms on any level */
/* 2 free bits */
#define MAX_NUM_WORMS 32 /* should be 2^(wormno bitfield size) */
#define MAX_NUM_WORMS 32 /* should be 2^(wormno bitfield size) */
unsigned long mstrategy; /* for monsters with mflag3: current strategy */
#ifdef NHSTDC
@@ -116,39 +116,39 @@ struct monst {
#else
#define STRAT_APPEARMSG 0x80000000L
#endif
#define STRAT_ARRIVE 0x40000000L /* just arrived on current level */
#define STRAT_WAITFORU 0x20000000L
#define STRAT_CLOSE 0x10000000L
#define STRAT_WAITMASK (STRAT_CLOSE | STRAT_WAITFORU)
#define STRAT_HEAL 0x08000000L
#define STRAT_GROUND 0x04000000L
#define STRAT_MONSTR 0x02000000L
#define STRAT_PLAYER 0x01000000L
#define STRAT_NONE 0x00000000L
#define STRAT_ARRIVE 0x40000000L /* just arrived on current level */
#define STRAT_WAITFORU 0x20000000L
#define STRAT_CLOSE 0x10000000L
#define STRAT_WAITMASK (STRAT_CLOSE | STRAT_WAITFORU)
#define STRAT_HEAL 0x08000000L
#define STRAT_GROUND 0x04000000L
#define STRAT_MONSTR 0x02000000L
#define STRAT_PLAYER 0x01000000L
#define STRAT_NONE 0x00000000L
#define STRAT_STRATMASK 0x0f000000L
#define STRAT_XMASK 0x00ff0000L
#define STRAT_YMASK 0x0000ff00L
#define STRAT_GOAL 0x000000ffL
#define STRAT_GOALX(s) ((xchar)((s & STRAT_XMASK) >> 16))
#define STRAT_GOALY(s) ((xchar)((s & STRAT_YMASK) >> 8))
#define STRAT_XMASK 0x00ff0000L
#define STRAT_YMASK 0x0000ff00L
#define STRAT_GOAL 0x000000ffL
#define STRAT_GOALX(s) ((xchar) ((s & STRAT_XMASK) >> 16))
#define STRAT_GOALY(s) ((xchar) ((s & STRAT_YMASK) >> 8))
long mtrapseen; /* bitmap of traps we've been trapped in */
long mlstmv; /* for catching up with lost time */
long mtrapseen; /* bitmap of traps we've been trapped in */
long mlstmv; /* for catching up with lost time */
long mspare1;
struct obj *minvent;
struct obj *minvent; /* mon's inventory */
struct obj *mw;
long misc_worn_check;
xchar weapon_check;
struct obj *mw; /* mon's weapon */
long misc_worn_check; /* mon's wornmask */
xchar weapon_check; /* flag for whether to try switching weapons */
int meating; /* monster is eating timeout */
struct mextra *mextra; /* point to mextra struct */
};
#define newmonst() (struct monst *) alloc(sizeof(struct monst))
#define newmonst() (struct monst *) alloc(sizeof (struct monst))
/* these are in mspeed */
#define MSLOW 1 /* slow monster */
#define MSLOW 1 /* slowed monster */
#define MFAST 2 /* speeded monster */
#define MON_WEP(mon) ((mon)->mw)
@@ -161,16 +161,17 @@ struct monst {
|| (mon)->cham == PM_VLAD_THE_IMPALER)
/* mimic appearances that block vision/light */
#define is_lightblocker_mappear(mon) \
(is_obj_mappear(mon, BOULDER) || \
((mon)->m_ap_type == M_AP_FURNITURE \
&& ((mon)->mappearance == S_hcdoor \
|| (mon)->mappearance == S_vcdoor \
|| (mon)->mappearance < S_ndoor /* = walls */ \
|| (mon)->mappearance == S_tree)))
#define is_lightblocker_mappear(mon) \
(is_obj_mappear(mon, BOULDER) \
|| ((mon)->m_ap_type == M_AP_FURNITURE \
&& ((mon)->mappearance == S_hcdoor \
|| (mon)->mappearance == S_vcdoor \
|| (mon)->mappearance < S_ndoor /* = walls */ \
|| (mon)->mappearance == S_tree)))
#define is_door_mappear(mon) ((mon)->m_ap_type == M_AP_FURNITURE \
&& ((mon)->mappearance == S_hcdoor || (mon)->mappearance == S_vcdoor))
&& ((mon)->mappearance == S_hcdoor \
|| (mon)->mappearance == S_vcdoor))
#define is_obj_mappear(mon,otyp) ((mon)->m_ap_type == M_AP_OBJECT \
&& (mon)->mappearance == (otyp))
&& (mon)->mappearance == (otyp))
#endif /* MONST_H */
+8 -7
View File
@@ -40,12 +40,13 @@ struct obj {
unsigned owt;
long quan; /* number of items */
schar spe; /* quality of weapon, armor or ring (+ or -)
number of charges for wand ( >= -1 )
marks your eggs, tin variety and spinach tins
royal coffers for a court ( == 2)
tells which fruit a fruit is
special for uball and amulet
schar spe; /* quality of weapon, armor or ring (+ or -);
number of charges for wand or charged tool ( >= -1 );
marks your eggs, tin variety and spinach tins;
Schroedinger's Box (1) or royal coffers for a court (2);
tells which fruit a fruit is;
special for uball and amulet;
scroll of mail (normal==0, bones or wishing==1, written==2);
historic and gender for statues */
#define STATUE_HISTORIC 0x01
#define STATUE_MALE 0x02
@@ -336,7 +337,7 @@ struct obj {
/* helpers, simple enough to be macros */
#define is_plural(o) \
((o)->quan > 1 || (o)->oartifact == ART_EYES_OF_THE_OVERWORLD)
((o)->quan != 1L || (o)->otyp == LENSES || is_gloves(o) || is_boots(o))
/* Flags for get_obj_location(). */
#define CONTAINED_TOO 0x1
+16 -16
View File
@@ -1,28 +1,28 @@
/* NetHack 3.6 objclass.h $NHDT-Date: 1447755971 2015/11/17 10:26:11 $ $NHDT-Branch: master $:$NHDT-Revision: 1.15 $ */
/* NetHack 3.6 objclass.h $NHDT-Date: 1462067744 2016/05/01 01:55:44 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.16 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
#ifndef OBJCLASS_H
#define OBJCLASS_H
/* definition of a class of objects */
/* [misnamed] definition of a type of object */
struct objclass {
short oc_name_idx; /* index of actual name */
short oc_descr_idx; /* description when name unknown */
char *oc_uname; /* called by user */
short oc_name_idx; /* index of actual name */
short oc_descr_idx; /* description when name unknown */
char *oc_uname; /* called by user */
Bitfield(oc_name_known, 1);
Bitfield(oc_merge, 1); /* merge otherwise equal objects */
Bitfield(oc_uses_known, 1); /* obj->known affects full description */
/* otherwise, obj->dknown and obj->bknown */
/* tell all, and obj->known should always */
/* be set for proper merging behavior */
Bitfield(oc_pre_discovered, 1); /* Already known at start of game; */
/* won't be listed as a discovery. */
Bitfield(oc_magic, 1); /* inherently magical object */
Bitfield(oc_charged, 1); /* may have +n or (n) charges */
Bitfield(oc_unique, 1); /* special one-of-a-kind object */
Bitfield(oc_nowish, 1); /* cannot wish for this object */
Bitfield(oc_merge, 1); /* merge otherwise equal objects */
Bitfield(oc_uses_known, 1); /* obj->known affects full description;
otherwise, obj->dknown and obj->bknown
tell all, and obj->known should always
be set for proper merging behavior. */
Bitfield(oc_pre_discovered, 1); /* Already known at start of game;
won't be listed as a discovery. */
Bitfield(oc_magic, 1); /* inherently magical object */
Bitfield(oc_charged, 1); /* may have +n or (n) charges */
Bitfield(oc_unique, 1); /* special one-of-a-kind object */
Bitfield(oc_nowish, 1); /* cannot wish for this object */
Bitfield(oc_big, 1);
#define oc_bimanual oc_big /* for weapons & tools used as weapons */
+6 -5
View File
@@ -218,12 +218,13 @@ enum opcode_defs {
#define SP_COORD_IS_RANDOM 0x01000000
/* Humidity flags for get_location() and friends, used with
* SP_COORD_PACK_RANDOM() */
#define DRY 0x1
#define WET 0x2
#define HOT 0x4
#define SOLID 0x8
#define ANY_LOC 0x10 /* even outside the level */
#define DRY 0x01
#define WET 0x02
#define HOT 0x04
#define SOLID 0x08
#define ANY_LOC 0x10 /* even outside the level */
#define NO_LOC_WARN 0x20 /* no complaints and set x & y to -1, if no loc */
#define SPACELOC 0x40 /* like DRY, but accepts furniture too */
#define SP_COORD_X(l) (l & 0xff)
#define SP_COORD_Y(l) ((l >> 16) & 0xff)
+2 -1
View File
@@ -1,4 +1,4 @@
/* NetHack 3.6 wintype.h $NHDT-Date: 1433207914 2015/06/02 01:18:34 $ $NHDT-Branch: master $:$NHDT-Revision: 1.15 $ */
/* NetHack 3.6 wintype.h $NHDT-Date: 1461028538 2016/04/19 01:15:38 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.16 $ */
/* Copyright (c) David Cohrs, 1991 */
/* NetHack may be freely redistributed. See license for details. */
@@ -56,6 +56,7 @@ typedef struct mi {
#define MENU_ITEM_P struct mi
/* select_menu() "how" argument types */
/* [MINV_PICKMASK in monst.h assumes these have values of 0, 1, 2] */
#define PICK_NONE 0 /* user picks nothing (display only) */
#define PICK_ONE 1 /* only pick one */
#define PICK_ANY 2 /* can pick any amount */
+25 -1
View File
@@ -1,4 +1,4 @@
/* NetHack 3.6 allmain.c $NHDT-Date: 1451955079 2016/01/05 00:51:19 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.70 $ */
/* NetHack 3.6 allmain.c $NHDT-Date: 1463217182 2016/05/14 09:13:02 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.72 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
@@ -13,6 +13,7 @@
#ifdef POSITIONBAR
STATIC_DCL void NDECL(do_positionbar);
#endif
STATIC_DCL void FDECL(interrupt_multi, (const char *));
void
moveloop(resuming)
@@ -216,6 +217,8 @@ boolean resuming;
|| (wtcap < MOD_ENCUMBER && !(moves % 20))) {
context.botl = 1;
u.mh++;
if (u.mh >= u.mhmax)
interrupt_multi("You are in full health.");
}
} else if (u.uhp < u.uhpmax
&& (wtcap < MOD_ENCUMBER || !u.umoved
@@ -234,6 +237,8 @@ boolean resuming;
u.uhp += heal;
if (u.uhp > u.uhpmax)
u.uhp = u.uhpmax;
if (u.uhp >= u.uhpmax)
interrupt_multi("You are in full health.");
} else if (Regeneration
|| (u.ulevel <= 9
&& !(moves
@@ -241,6 +246,8 @@ boolean resuming;
+ 1)))) {
context.botl = 1;
u.uhp++;
if (u.uhp >= u.uhpmax)
interrupt_multi("You are in full health.");
}
}
@@ -270,6 +277,8 @@ boolean resuming;
if (u.uen > u.uenmax)
u.uen = u.uenmax;
context.botl = 1;
if (u.uen >= u.uenmax)
interrupt_multi("You feel full of energy.");
}
if (!u.uinvulnerable) {
@@ -506,6 +515,9 @@ display_gamewindows()
#endif
WIN_MAP = create_nhwindow(NHW_MAP);
WIN_INVEN = create_nhwindow(NHW_MENU);
/* in case of early quit where WIN_INVEN could be destroyed before
ever having been used, use it here to pacify the Qt interface */
start_menu(WIN_INVEN), end_menu(WIN_INVEN, (char *) 0);
#ifdef MAC
/* This _is_ the right place for this - maybe we will
@@ -687,4 +699,16 @@ do_positionbar()
}
#endif
STATIC_DCL void
interrupt_multi(msg)
const char *msg;
{
if (multi > 0 && !context.travel) {
nomul(0);
if (flags.verbose && msg)
Norep("%s", msg);
}
}
/*allmain.c*/
+3 -3
View File
@@ -1,4 +1,4 @@
/* NetHack 3.6 apply.c $NHDT-Date: 1457207021 2016/03/05 19:43:41 $ $NHDT-Branch: chasonr $:$NHDT-Revision: 1.223 $ */
/* NetHack 3.6 apply.c $NHDT-Date: 1457397477 2016/03/08 00:37:57 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.224 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
@@ -737,7 +737,7 @@ register xchar x, y;
that's the result of his actions; gain experience,
lose pacifism, take alignment and luck hit, make
corpse less likely to remain tame after revival */
xkilled(mtmp, 0); /* no "you kill it" message */
xkilled(mtmp, XKILL_NOMSG);
/* life-saving doesn't ordinarily reset this */
if (mtmp->mhp > 0)
u.uconduct.killer = save_pacifism;
@@ -3430,7 +3430,7 @@ doapply()
case SACK:
case BAG_OF_HOLDING:
case OILSKIN_SACK:
res = use_container(&obj, 1);
res = use_container(&obj, 1, FALSE);
break;
case BAG_OF_TRICKS:
(void) bagotricks(obj, FALSE, (int *) 0);
+68 -96
View File
@@ -101,6 +101,7 @@ static const struct innate {
STATIC_DCL void NDECL(exerper);
STATIC_DCL void FDECL(postadjabil, (long *));
STATIC_DCL const struct innate *FDECL(role_abil, (int));
STATIC_DCL const struct innate *FDECL(check_innate_abil, (long *, long));
STATIC_DCL int FDECL(innately, (long *));
@@ -644,6 +645,34 @@ long *ability;
see_monsters();
}
STATIC_OVL const struct innate *
role_abil(r)
int r;
{
const struct {
short role;
const struct innate *abil;
} roleabils[] = {
{ PM_ARCHEOLOGIST, arc_abil },
{ PM_BARBARIAN, bar_abil },
{ PM_CAVEMAN, cav_abil },
{ PM_HEALER, hea_abil },
{ PM_KNIGHT, kni_abil },
{ PM_MONK, mon_abil },
{ PM_PRIEST, pri_abil },
{ PM_RANGER, ran_abil },
{ PM_ROGUE, rog_abil },
{ PM_SAMURAI, sam_abil },
{ PM_TOURIST, tou_abil },
{ PM_VALKYRIE, val_abil },
{ PM_WIZARD, wiz_abil },
{ 0, 0 }
};
int i;
for (i = 0; roleabils[i].abil && roleabils[i].role != r; i++);
return roleabils[i].abil;
}
STATIC_OVL const struct innate *
check_innate_abil(ability, frommask)
long *ability;
@@ -652,49 +681,7 @@ long frommask;
const struct innate *abil = 0;
if (frommask == FROMEXPER)
switch (Role_switch) {
case PM_ARCHEOLOGIST:
abil = arc_abil;
break;
case PM_BARBARIAN:
abil = bar_abil;
break;
case PM_CAVEMAN:
abil = cav_abil;
break;
case PM_HEALER:
abil = hea_abil;
break;
case PM_KNIGHT:
abil = kni_abil;
break;
case PM_MONK:
abil = mon_abil;
break;
case PM_PRIEST:
abil = pri_abil;
break;
case PM_RANGER:
abil = ran_abil;
break;
case PM_ROGUE:
abil = rog_abil;
break;
case PM_SAMURAI:
abil = sam_abil;
break;
case PM_TOURIST:
abil = tou_abil;
break;
case PM_VALKYRIE:
abil = val_abil;
break;
case PM_WIZARD:
abil = wiz_abil;
break;
default:
break;
}
abil = role_abil(Role_switch);
else if (frommask == FROMRACE)
switch (Race_switch) {
case PM_DWARF:
@@ -728,10 +715,10 @@ long frommask;
#define FROM_NONE 0
#define FROM_ROLE 1 /* from experience at level 1 */
#define FROM_RACE 2
#define FROM_EXP 3 /* from experience for some level > 1 */
#define FROM_FORM 4
#define FROM_LYCN 5
#define FROM_INTR 3 /* intrinsically (eating some corpse or prayer reward) */
#define FROM_EXP 4 /* from experience for some level > 1 */
#define FROM_FORM 5
#define FROM_LYCN 6
/* check whether particular ability has been obtained via innate attribute */
STATIC_OVL int
@@ -744,6 +731,8 @@ long *ability;
return (iptr->ulevel == 1) ? FROM_ROLE : FROM_EXP;
if ((iptr = check_innate_abil(ability, FROMRACE)) != 0)
return FROM_RACE;
if ((*ability & FROMOUTSIDE) != 0L)
return FROM_INTR;
if ((*ability & FROMFORM) != 0L)
return FROM_FORM;
return FROM_NONE;
@@ -758,6 +747,8 @@ int propidx;
/* innately() would report FROM_FORM for this; caller wants specificity */
if (propidx == DRAIN_RES && u.ulycn >= LOW_PM)
return FROM_LYCN;
if (propidx == FAST && Very_fast)
return FROM_NONE; /* can't become very fast innately */
if ((innateness = innately(&u.uprops[propidx].intrinsic)) != FROM_NONE)
return innateness;
if (propidx == JUMPING && Role_if(PM_KNIGHT)
@@ -788,21 +779,45 @@ int propidx; /* special cases can have negative values */
struct obj *obj = (struct obj *) 0;
int innateness = is_innate(propidx);
if (innateness == FROM_EXP)
/*
* Properties can be obtained from multiple sources and we
* try to pick the most significant one. Classification
* priority is not set in stone; current precedence is:
* "from the start" (from role or race at level 1),
* "from outside" (eating corpse, divine reward, blessed potion),
* "from experience" (from role or race at level 2+),
* "from current form" (while polymorphed),
* "from timed effect" (potion or spell),
* "from worn/wielded equipment" (Firebrand, elven boots, &c),
* "from carried equipment" (mainly quest artifacts).
* There are exceptions. Versatile jumping from spell or boots
* takes priority over knight's innate but limited jumping.
*/
if (propidx == BLINDED && u.uroleplay.blind)
Sprintf(buf, " from birth");
else if (innateness == FROM_ROLE || innateness == FROM_RACE)
Strcpy(buf, " innately");
else if (innateness == FROM_INTR) /* [].intrinsic & FROMOUTSIDE */
Strcpy(buf, " intrinsically");
else if (innateness == FROM_EXP)
Strcpy(buf, " because of your experience");
else if (innateness == FROM_LYCN)
Strcpy(buf, " due to your lycanthropy");
else if (innateness == FROM_FORM)
Strcpy(buf, " from current creature form");
else if (innateness == FROM_ROLE || innateness == FROM_RACE)
Strcpy(buf, " innately");
else if (propidx == FAST && Very_fast)
Sprintf(buf, because_of,
((HFast & TIMEOUT) != 0L) ? "a potion or spell"
: ((EFast & W_ARMF) != 0L && uarmf->dknown
&& objects[uarmf->otyp].oc_name_known)
? ysimple_name(uarmf) /* speed boots */
: EFast ? "worn equipment"
: something);
else if (wizard
&& (obj = what_gives(&u.uprops[propidx].extrinsic)) != 0)
Sprintf(buf, because_of, obj->oartifact
? bare_artifactname(obj)
: ysimple_name(obj));
else if (propidx == BLINDED && u.uroleplay.blind)
Sprintf(buf, " from birth");
else if (propidx == BLINDED && Blindfolded_only)
Sprintf(buf, because_of, ysimple_name(ublindf));
@@ -846,50 +861,7 @@ int oldlevel, newlevel;
register const struct innate *abil, *rabil;
long prevabil, mask = FROMEXPER;
switch (Role_switch) {
case PM_ARCHEOLOGIST:
abil = arc_abil;
break;
case PM_BARBARIAN:
abil = bar_abil;
break;
case PM_CAVEMAN:
abil = cav_abil;
break;
case PM_HEALER:
abil = hea_abil;
break;
case PM_KNIGHT:
abil = kni_abil;
break;
case PM_MONK:
abil = mon_abil;
break;
case PM_PRIEST:
abil = pri_abil;
break;
case PM_RANGER:
abil = ran_abil;
break;
case PM_ROGUE:
abil = rog_abil;
break;
case PM_SAMURAI:
abil = sam_abil;
break;
case PM_TOURIST:
abil = tou_abil;
break;
case PM_VALKYRIE:
abil = val_abil;
break;
case PM_WIZARD:
abil = wiz_abil;
break;
default:
abil = 0;
break;
}
abil = role_abil(Role_switch);
switch (Race_switch) {
case PM_ELF:
+241 -91
View File
@@ -144,17 +144,18 @@ extern void FDECL(show_borlandc_stats, (winid));
#ifdef DEBUG_MIGRATING_MONS
STATIC_PTR int NDECL(wiz_migrate_mons);
#endif
STATIC_DCL int FDECL(size_monst, (struct monst *));
STATIC_DCL int FDECL(size_monst, (struct monst *, BOOLEAN_P));
STATIC_DCL int FDECL(size_obj, (struct obj *));
STATIC_DCL void FDECL(count_obj, (struct obj *, long *, long *,
BOOLEAN_P, BOOLEAN_P));
STATIC_DCL void FDECL(obj_chain, (winid, const char *, struct obj *,
long *, long *));
BOOLEAN_P, long *, long *));
STATIC_DCL void FDECL(mon_invent_chain, (winid, const char *, struct monst *,
long *, long *));
STATIC_DCL void FDECL(mon_chain, (winid, const char *, struct monst *,
long *, long *));
STATIC_DCL void FDECL(contained, (winid, const char *, long *, long *));
BOOLEAN_P, long *, long *));
STATIC_DCL void FDECL(contained_stats, (winid, const char *, long *, long *));
STATIC_DCL void FDECL(misc_stats, (winid, long *, long *));
STATIC_PTR int NDECL(wiz_show_stats);
STATIC_DCL boolean FDECL(accept_menu_prefix, (int NDECL((*))));
#ifdef PORT_DEBUG
@@ -1124,7 +1125,8 @@ wiz_intrinsic(VOID_ARGS)
for (i = 0; i < SIZE(intrinsics); ++i) {
accelerator = intrinsics[i][0];
any.a_int = i + 1;
add_menu(win, NO_GLYPH, &any, accelerator, 0, ATR_NONE, intrinsics[i], FALSE);
add_menu(win, NO_GLYPH, &any, accelerator, 0,
ATR_NONE, intrinsics[i], FALSE);
}
end_menu(win, "Which intrinsic?");
n = select_menu(win, PICK_ONE, &pick_list);
@@ -1137,7 +1139,7 @@ wiz_intrinsic(VOID_ARGS)
return 0;
}
if (!strcmp(intrinsics[i],"deafness")) {
if (!strcmp(intrinsics[i], "deafness")) {
You("go deaf.");
incr_itimeout(&HDeaf, 30);
context.botl = TRUE;
@@ -1224,13 +1226,26 @@ doterrain(VOID_ARGS)
free((genericptr_t) sel);
switch (which) {
case 1: reveal_terrain(0, 0); break; /* known map */
case 2: reveal_terrain(0, 1); break; /* known map with traps */
case 3: reveal_terrain(0, 1|2); break; /* known map w/ traps & objs */
case 4: reveal_terrain(1, 0); break; /* full map */
case 5: wiz_map_levltyp(); break; /* map internals */
case 6: wiz_levltyp_legend(); break; /* internal details */
default: break;
case 1: /* known map */
reveal_terrain(0, TER_MAP);
break;
case 2: /* known map with known traps */
reveal_terrain(0, TER_MAP | TER_TRP);
break;
case 3: /* known map with known traps and objects */
reveal_terrain(0, TER_MAP | TER_TRP | TER_OBJ);
break;
case 4: /* full map */
reveal_terrain(1, TER_MAP);
break;
case 5: /* map internals */
wiz_map_levltyp();
break;
case 6: /* internal details */
wiz_levltyp_legend();
break;
default:
break;
}
return 0; /* no time elapses */
}
@@ -1948,27 +1963,12 @@ int final;
you_are(hofe_titles[u.uevent.uhand_of_elbereth - 1], "");
}
/* note: piousness 20 matches MIN_QUEST_ALIGN (quest.h) */
if (u.ualign.record >= 20)
you_are("piously aligned", "");
else if (u.ualign.record > 13)
you_are("devoutly aligned", "");
else if (u.ualign.record > 8)
you_are("fervently aligned", "");
else if (u.ualign.record > 3)
you_are("stridently aligned", "");
else if (u.ualign.record == 3)
you_are("aligned", "");
else if (u.ualign.record > 0)
you_are("haltingly aligned", "");
else if (u.ualign.record == 0)
you_are("nominally aligned", "");
else if (u.ualign.record >= -3)
you_have("strayed", "");
else if (u.ualign.record >= -8)
you_have("sinned", "");
Sprintf(buf, "%s", piousness(TRUE, "aligned"));
if (u.ualign.record >= 0)
you_are(buf, "");
else
you_have("transgressed", "");
you_have(buf, "");
if (wizard) {
Sprintf(buf, " %d", u.ualign.record);
enl_msg("Your alignment ", "is", "was", buf, "");
@@ -2904,9 +2904,9 @@ int NDECL((*fn));
return 0;
}
static const char template[] = "%-18s %4ld %6ld";
static const char count_str[] = " count bytes";
static const char separator[] = "------------------ ----- ------";
static const char template[] = "%-27s %4ld %6ld";
static const char stats_hdr[] = " count bytes";
static const char stats_sep[] = "--------------------------- ----- -------";
STATIC_OVL int
size_obj(otmp)
@@ -2954,21 +2954,25 @@ boolean recurse;
}
STATIC_OVL void
obj_chain(win, src, chain, total_count, total_size)
obj_chain(win, src, chain, force, total_count, total_size)
winid win;
const char *src;
struct obj *chain;
boolean force;
long *total_count;
long *total_size;
{
char buf[BUFSZ];
long count = 0, size = 0;
long count = 0L, size = 0L;
count_obj(chain, &count, &size, TRUE, FALSE);
*total_count += count;
*total_size += size;
Sprintf(buf, template, src, count, size);
putstr(win, 0, buf);
if (count || size || force) {
*total_count += count;
*total_size += size;
Sprintf(buf, template, src, count, size);
putstr(win, 0, buf);
}
}
STATIC_OVL void
@@ -2985,14 +2989,17 @@ long *total_size;
for (mon = chain; mon; mon = mon->nmon)
count_obj(mon->minvent, &count, &size, TRUE, FALSE);
*total_count += count;
*total_size += size;
Sprintf(buf, template, src, count, size);
putstr(win, 0, buf);
if (count || size) {
*total_count += count;
*total_size += size;
Sprintf(buf, template, src, count, size);
putstr(win, 0, buf);
}
}
STATIC_OVL void
contained(win, src, total_count, total_size)
contained_stats(win, src, total_count, total_size)
winid win;
const char *src;
long *total_count;
@@ -3013,58 +3020,173 @@ long *total_size;
for (mon = migrating_mons; mon; mon = mon->nmon)
count_obj(mon->minvent, &count, &size, FALSE, TRUE);
*total_count += count;
*total_size += size;
Sprintf(buf, template, src, count, size);
putstr(win, 0, buf);
if (count || size) {
*total_count += count;
*total_size += size;
Sprintf(buf, template, src, count, size);
putstr(win, 0, buf);
}
}
STATIC_OVL int
size_monst(mtmp)
size_monst(mtmp, incl_wsegs)
struct monst *mtmp;
boolean incl_wsegs;
{
int sz = (int) sizeof(struct monst);
int sz = (int) sizeof (struct monst);
if (mtmp->wormno && incl_wsegs)
sz += size_wseg(mtmp);
if (mtmp->mextra) {
sz += (int) sizeof(struct mextra);
sz += (int) sizeof (struct mextra);
if (MNAME(mtmp))
sz += (int) strlen(MNAME(mtmp)) + 1;
if (EGD(mtmp))
sz += (int) sizeof(struct egd);
sz += (int) sizeof (struct egd);
if (EPRI(mtmp))
sz += (int) sizeof(struct epri);
sz += (int) sizeof (struct epri);
if (ESHK(mtmp))
sz += (int) sizeof(struct eshk);
sz += (int) sizeof (struct eshk);
if (EMIN(mtmp))
sz += (int) sizeof(struct emin);
sz += (int) sizeof (struct emin);
if (EDOG(mtmp))
sz += (int) sizeof(struct edog);
sz += (int) sizeof (struct edog);
/* mextra->mcorpsenm doesn't point to more memory */
}
return sz;
}
STATIC_OVL void
mon_chain(win, src, chain, total_count, total_size)
mon_chain(win, src, chain, force, total_count, total_size)
winid win;
const char *src;
struct monst *chain;
boolean force;
long *total_count;
long *total_size;
{
char buf[BUFSZ];
long count, size;
struct monst *mon;
/* mon->wormno means something different for migrating_mons and mydogs */
boolean incl_wsegs = !strcmpi(src, "fmon");
for (count = size = 0, mon = chain; mon; mon = mon->nmon) {
count = size = 0L;
for (mon = chain; mon; mon = mon->nmon) {
count++;
size += size_monst(mon);
size += size_monst(mon, incl_wsegs);
}
if (count || size || force) {
*total_count += count;
*total_size += size;
Sprintf(buf, template, src, count, size);
putstr(win, 0, buf);
}
}
STATIC_OVL void
misc_stats(win, total_count, total_size)
winid win;
long *total_count;
long *total_size;
{
char buf[BUFSZ], hdrbuf[QBUFSZ];
long count, size;
int idx;
struct trap *tt;
struct damage *sd; /* shop damage */
struct cemetery *bi; /* bones info */
/* traps and engravings are output unconditionally;
* others only if nonzero
*/
count = size = 0L;
for (tt = ftrap; tt; tt = tt->ntrap) {
++count;
size += (long) sizeof *tt;
}
*total_count += count;
*total_size += size;
Sprintf(buf, template, src, count, size);
Sprintf(hdrbuf, "traps, size %ld", (long) sizeof (struct trap));
Sprintf(buf, template, hdrbuf, count, size);
putstr(win, 0, buf);
count = size = 0L;
engr_stats("engravings, size %ld+text", hdrbuf, &count, &size);
*total_count += count;
*total_size += size;
Sprintf(buf, template, hdrbuf, count, size);
putstr(win, 0, buf);
count = size = 0L;
light_stats("light sources, size %ld", hdrbuf, &count, &size);
if (count || size) {
*total_count += count;
*total_size += size;
Sprintf(buf, template, hdrbuf, count, size);
putstr(win, 0, buf);
}
count = size = 0L;
timer_stats("timers, size %ld", hdrbuf, &count, &size);
if (count || size) {
*total_count += count;
*total_size += size;
Sprintf(buf, template, hdrbuf, count, size);
putstr(win, 0, buf);
}
count = size = 0L;
for (sd = level.damagelist; sd; sd = sd->next) {
++count;
size += (long) sizeof *sd;
}
if (count || size) {
*total_count += count;
*total_size += size;
Sprintf(hdrbuf, "shop damage, size %ld",
(long) sizeof (struct damage));
Sprintf(buf, template, hdrbuf, count, size);
putstr(win, 0, buf);
}
count = size = 0L;
region_stats("regions, size %ld+%ld*rect+N", hdrbuf, &count, &size);
if (count || size) {
*total_count += count;
*total_size += size;
Sprintf(buf, template, hdrbuf, count, size);
putstr(win, 0, buf);
}
count = size = 0L;
for (bi = level.bonesinfo; bi; bi = bi->next) {
++count;
size += (long) sizeof *bi;
}
if (count || size) {
*total_count += count;
*total_size += size;
Sprintf(hdrbuf, "bones history, size %ld",
(long) sizeof (struct cemetery));
Sprintf(buf, template, hdrbuf, count, size);
putstr(win, 0, buf);
}
count = size = 0L;
for (idx = 0; idx < NUM_OBJECTS; ++idx)
if (objects[idx].oc_uname) {
++count;
size += (long) (strlen(objects[idx].oc_uname) + 1);
}
if (count || size) {
*total_count += count;
*total_size += size;
Strcpy(hdrbuf, "object type names, text");
Sprintf(buf, template, hdrbuf, count, size);
putstr(win, 0, buf);
}
}
/*
@@ -3075,45 +3197,73 @@ wiz_show_stats()
{
char buf[BUFSZ];
winid win;
long total_obj_size = 0, total_obj_count = 0;
long total_mon_size = 0, total_mon_count = 0;
long total_obj_size, total_obj_count,
total_mon_size, total_mon_count,
total_ovr_size, total_ovr_count,
total_misc_size, total_misc_count;
win = create_nhwindow(NHW_TEXT);
putstr(win, 0, "Current memory statistics:");
putstr(win, 0, "");
Sprintf(buf, "Objects, size %d", (int) sizeof(struct obj));
putstr(win, 0, buf);
putstr(win, 0, "");
putstr(win, 0, count_str);
obj_chain(win, "invent", invent, &total_obj_count, &total_obj_size);
obj_chain(win, "fobj", fobj, &total_obj_count, &total_obj_size);
obj_chain(win, "buried", level.buriedobjlist, &total_obj_count,
&total_obj_size);
obj_chain(win, "migrating obj", migrating_objs, &total_obj_count,
&total_obj_size);
total_obj_count = total_obj_size = 0L;
putstr(win, 0, stats_hdr);
Sprintf(buf, " Objects, base size %ld", (long) sizeof (struct obj));
putstr(win, 0, buf);
obj_chain(win, "invent", invent, TRUE, &total_obj_count, &total_obj_size);
obj_chain(win, "fobj", fobj, TRUE, &total_obj_count, &total_obj_size);
obj_chain(win, "buried", level.buriedobjlist, FALSE,
&total_obj_count, &total_obj_size);
obj_chain(win, "migrating obj", migrating_objs, FALSE,
&total_obj_count, &total_obj_size);
obj_chain(win, "billobjs", billobjs, FALSE,
&total_obj_count, &total_obj_size);
mon_invent_chain(win, "minvent", fmon, &total_obj_count, &total_obj_size);
mon_invent_chain(win, "migrating minvent", migrating_mons,
&total_obj_count, &total_obj_size);
contained_stats(win, "contained", &total_obj_count, &total_obj_size);
putstr(win, 0, stats_sep);
Sprintf(buf, template, " Obj total", total_obj_count, total_obj_size);
putstr(win, 0, buf);
contained(win, "contained", &total_obj_count, &total_obj_size);
total_mon_count = total_mon_size = 0L;
putstr(win, 0, "");
Sprintf(buf, " Monsters, base size %ld", (long) sizeof (struct monst));
putstr(win, 0, buf);
mon_chain(win, "fmon", fmon, TRUE, &total_mon_count, &total_mon_size);
mon_chain(win, "migrating", migrating_mons, FALSE,
&total_mon_count, &total_mon_size);
/* 'mydogs' is only valid during level change or end of game disclosure,
but conceivably we've been called from within debugger at such time */
if (mydogs) /* monsters accompanying hero */
mon_chain(win, "mydogs", mydogs, FALSE,
&total_mon_count, &total_mon_size);
putstr(win, 0, stats_sep);
Sprintf(buf, template, " Mon total", total_mon_count, total_mon_size);
putstr(win, 0, buf);
putstr(win, 0, separator);
Sprintf(buf, template, "Total", total_obj_count, total_obj_size);
total_ovr_count = total_ovr_size = 0L;
putstr(win, 0, "");
putstr(win, 0, " Overview");
overview_stats(win, template, &total_ovr_count, &total_ovr_size);
putstr(win, 0, stats_sep);
Sprintf(buf, template, " Over total", total_ovr_count, total_ovr_size);
putstr(win, 0, buf);
total_misc_count = total_misc_size = 0L;
putstr(win, 0, "");
putstr(win, 0, " Miscellaneous");
misc_stats(win, &total_misc_count, &total_misc_size);
putstr(win, 0, stats_sep);
Sprintf(buf, template, " Misc total", total_misc_count, total_misc_size);
putstr(win, 0, buf);
putstr(win, 0, "");
putstr(win, 0, "");
Sprintf(buf, "Monsters, size %d", (int) sizeof(struct monst));
putstr(win, 0, buf);
putstr(win, 0, "");
mon_chain(win, "fmon", fmon, &total_mon_count, &total_mon_size);
mon_chain(win, "migrating", migrating_mons, &total_mon_count,
&total_mon_size);
putstr(win, 0, separator);
Sprintf(buf, template, "Total", total_mon_count, total_mon_size);
putstr(win, 0, stats_sep);
Sprintf(buf, template, " Grand total",
(total_obj_count + total_mon_count
+ total_ovr_count + total_misc_count),
(total_obj_size + total_mon_size
+ total_ovr_size + total_misc_size));
putstr(win, 0, buf);
#if defined(__BORLANDC__) && !defined(_WIN32)
+26 -20
View File
@@ -115,16 +115,12 @@ int mask;
switch (mask & DB_UNDER) {
case DB_ICE:
return ICE;
break;
case DB_LAVA:
return LAVAPOOL;
break;
case DB_MOAT:
return MOAT;
break;
default:
return STONE;
break;
}
}
@@ -427,9 +423,9 @@ int x, y;
}
STATIC_OVL void
e_died(etmp, dest, how)
e_died(etmp, xkill_flags, how)
struct entity *etmp;
int dest, how;
int xkill_flags, how;
{
if (is_u(etmp)) {
if (how == DROWNING) {
@@ -466,13 +462,14 @@ int dest, how;
killer.name[0] = 0;
/* fake "digested to death" damage-type suppresses corpse */
#define mk_message(dest) ((dest & 1) ? "" : (char *) 0)
#define mk_corpse(dest) ((dest & 2) ? AD_DGST : AD_PHYS)
#define mk_message(dest) (((dest & XKILL_NOMSG) != 0) ? (char *) 0 : "")
#define mk_corpse(dest) (((dest & XKILL_NOCORPSE) != 0) ? AD_DGST : AD_PHYS)
/* if monsters are moving, one of them caused the destruction */
if (context.mon_moving)
monkilled(etmp->emon, mk_message(dest), mk_corpse(dest));
monkilled(etmp->emon,
mk_message(xkill_flags), mk_corpse(xkill_flags));
else /* you caused it */
xkilled(etmp->emon, dest);
xkilled(etmp->emon, xkill_flags);
etmp->edata = (struct permonst *) 0;
/* dead long worm handling */
@@ -609,7 +606,9 @@ struct entity *etmp;
if (crm->typ == DRAWBRIDGE_DOWN) {
pline("%s crushed underneath the drawbridge.",
E_phrase(etmp, "are")); /* no jump */
e_died(etmp, e_inview ? 3 : 2, CRUSHING); /* no corpse */
e_died(etmp,
XKILL_NOCORPSE | (e_inview ? XKILL_GIVEMSG : XKILL_NOMSG),
CRUSHING); /* no corpse */
return; /* Note: Beyond this point, we know we're */
} /* not at an opened drawbridge, since all */
must_jump = TRUE; /* *missable* creatures survive on the */
@@ -625,7 +624,10 @@ struct entity *etmp;
E_phrase(etmp, "are"));
else if (!Deaf)
You_hear("a crushing sound.");
e_died(etmp, e_inview ? 3 : 2, CRUSHING);
e_died(etmp,
XKILL_NOCORPSE | (e_inview ? XKILL_GIVEMSG
: XKILL_NOMSG),
CRUSHING);
/* no corpse */
return;
}
@@ -721,7 +723,7 @@ struct entity *etmp;
if (!e_survives_at(etmp, etmp->ex, etmp->ey)) {
killer.format = KILLED_BY_AN;
Strcpy(killer.name, "closing drawbridge");
e_died(etmp, 0, CRUSHING); /* no message */
e_died(etmp, XKILL_NOMSG, CRUSHING);
return;
}
debugpline1("%s in here", E_phrase(etmp, "survive"));
@@ -752,11 +754,11 @@ struct entity *etmp;
}
killer.format = NO_KILLER_PREFIX;
Strcpy(killer.name, "fell from a drawbridge");
e_died(etmp, e_inview ? 3 : 2, /* CRUSHING is arbitrary */
(is_pool(etmp->ex, etmp->ey))
? DROWNING
: (is_lava(etmp->ex, etmp->ey)) ? BURNING
: CRUSHING); /*no corpse*/
e_died(etmp, /* CRUSHING is arbitrary */
XKILL_NOCORPSE | (e_inview ? XKILL_GIVEMSG : XKILL_NOMSG),
is_pool(etmp->ex, etmp->ey) ? DROWNING
: is_lava(etmp->ex, etmp->ey) ? BURNING
: CRUSHING); /*no corpse*/
return;
}
}
@@ -958,7 +960,9 @@ int x, y;
E_phrase(etmp2, "are"));
killer.format = KILLED_BY_AN;
Strcpy(killer.name, "exploding drawbridge");
e_died(etmp2, e_inview ? 3 : 2, CRUSHING); /*no corpse*/
e_died(etmp2,
XKILL_NOCORPSE | (e_inview ? XKILL_GIVEMSG : XKILL_NOMSG),
CRUSHING); /*no corpse*/
} /* nothing which is vulnerable can survive this */
}
set_entity(x, y, etmp1);
@@ -988,7 +992,9 @@ int x, y;
}
killer.format = KILLED_BY_AN;
Strcpy(killer.name, "collapsing drawbridge");
e_died(etmp1, e_inview ? 3 : 2, CRUSHING); /*no corpse*/
e_died(etmp1,
XKILL_NOCORPSE | (e_inview ? XKILL_GIVEMSG : XKILL_NOMSG),
CRUSHING); /*no corpse*/
if (levl[etmp1->ex][etmp1->ey].typ == MOAT)
do_entity(etmp1);
}
+2 -1
View File
@@ -194,8 +194,9 @@ NEARDATA struct obj *migrating_objs = (struct obj *) 0;
/* objects not yet paid for */
NEARDATA struct obj *billobjs = (struct obj *) 0;
/* used to zero all elements of a struct obj */
/* used to zero all elements of a struct obj and a struct monst */
NEARDATA struct obj zeroobj = DUMMY;
NEARDATA struct monst zeromonst = DUMMY;
/* used to zero out union any; initializer deliberately omitted */
NEARDATA anything zeroany;
+39 -22
View File
@@ -1,4 +1,4 @@
/* NetHack 3.6 detect.c $NHDT-Date: 1446369464 2015/11/01 09:17:44 $ $NHDT-Branch: master $:$NHDT-Revision: 1.61 $ */
/* NetHack 3.6 detect.c $NHDT-Date: 1463191981 2016/05/14 02:13:01 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.70 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
@@ -272,6 +272,7 @@ outgoldmap:
}
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);
@@ -376,6 +377,7 @@ register struct obj *sobj;
}
newsym(u.ux, u.uy);
u.uinwater = iflags.save_uinwater, u.uburied = iflags.save_uburied;
iflags.save_uinwater = iflags.save_uburied = 0;
if (sobj) {
if (sobj->blessed) {
Your("%s %s to tingle and you smell %s.", body_part(NOSE),
@@ -575,6 +577,7 @@ int class; /* an object class, 0 for all */
newsym(u.ux, u.uy);
u.uinwater = iflags.save_uinwater, u.uburied = iflags.save_uburied;
iflags.save_uinwater = iflags.save_uburied = 0;
You("detect the %s of %s.", ct ? "presence" : "absence", stuff);
display_nhwindow(WIN_MAP, TRUE);
/*
@@ -826,6 +829,7 @@ outtrapmap:
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;
You_feel("%s.", cursed_src ? "very greedy" : "entrapped");
/* wait for user to respond, then reset map display to normal */
@@ -1090,6 +1094,7 @@ do_mapping()
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) {
flush_screen(1); /* flush temp screen */
display_nhwindow(WIN_MAP, TRUE); /* wait */
@@ -1355,7 +1360,7 @@ boolean via_warning;
Your("warning senses cause you to take a second %s.",
Blind ? "to check nearby" : "look close by");
display_nhwindow(WIN_MESSAGE, FALSE); /* flush messages */
}
}
mtmp->mundetected = 0;
newsym(x, y);
goto find;
@@ -1463,20 +1468,17 @@ dosearch()
void
warnreveal()
{
xchar x, y;
int x, y;
struct monst *mtmp;
for (x = u.ux - 1; x < u.ux + 2; x++)
for (y = u.uy - 1; y < u.uy + 2; y++) {
if (!isok(x, y))
continue;
if (x == u.ux && y == u.uy)
continue;
if ((mtmp = m_at(x, y)) != 0
&& warning_of(mtmp) && mtmp->mundetected)
(void) mfind0(mtmp, 1); /* via_warning */
}
for (x = u.ux - 1; x <= u.ux + 1; x++)
for (y = u.uy - 1; y <= u.uy + 1; y++) {
if (!isok(x, y) || (x == u.ux && y == u.uy))
continue;
if ((mtmp = m_at(x, y)) != 0
&& warning_of(mtmp) && mtmp->mundetected)
(void) mfind0(mtmp, 1); /* via_warning */
}
}
/* Pre-map the sokoban levels */
@@ -1522,15 +1524,19 @@ int which_subset; /* when not full, whether to suppress objs and/or traps */
unsigned save_swallowed;
struct monst *mtmp;
struct trap *t;
coord pos;
char buf[BUFSZ];
boolean keep_traps = (which_subset & 1) !=0,
keep_objs = (which_subset & 2) != 0,
keep_mons = (which_subset & 4) != 0; /* actually always 0 */
/* 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 */
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)
docrt();
default_glyph = cmap_to_glyph(level.flags.arboreal ? S_tree : S_stone);
/* for 'full', show the actual terrain for the entire level,
otherwise what the hero remembers for seen locations with
@@ -1603,10 +1609,8 @@ int which_subset; /* when not full, whether to suppress objs and/or traps */
show_glyph(x, y, glyph);
}
/* [TODO: highlight hero's location somehow] */
u.uinwater = iflags.save_uinwater, u.uburied = iflags.save_uburied;
if (save_swallowed)
u.uswallow = 1;
/* hero's location is not highlighted, but getpos() starts with
cursor there, and after moving it anywhere '@' moves it back */
flush_screen(1);
if (full) {
Strcpy(buf, "underlying terrain");
@@ -1624,7 +1628,20 @@ int which_subset; /* when not full, whether to suppress objs and/or traps */
(keep_traps || keep_objs) ? "," : "");
}
pline("Showing %s only...", buf);
display_nhwindow(WIN_MAP, TRUE); /* give "--More--" prompt */
/* 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' */
u.uinwater = iflags.save_uinwater, u.uburied = iflags.save_uburied;
iflags.save_uinwater = iflags.save_uburied = 0;
if (save_swallowed)
u.uswallow = 1;
docrt(); /* redraw the screen, restoring regular map */
if (Underwater)
under_water(2);
+30 -33
View File
@@ -1,4 +1,4 @@
/* NetHack 3.6 display.c $NHDT-Date: 1457207034 2016/03/05 19:43:54 $ $NHDT-Branch: chasonr $:$NHDT-Revision: 1.82 $ */
/* NetHack 3.6 display.c $NHDT-Date: 1463614572 2016/05/18 23:36:12 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.86 $ */
/* Copyright (c) Dean Luick, with acknowledgements to Kevin Darcy */
/* and Dave Cohrs, 1990. */
/* NetHack may be freely redistributed. See license for details. */
@@ -530,8 +530,7 @@ xchar x, y;
if (!isok(x, y))
return;
lev = &(levl[x][y]);
/* If the hero's memory of an invisible monster is accurate, we want to
* keep
/* If hero's memory of an invisible monster is accurate, we want to keep
* him from detecting the same monster over and over again on each turn.
* We must return (so we don't erase the monster). (We must also, in the
* search function, be sure to skip over previously detected 'I's.)
@@ -539,8 +538,10 @@ xchar x, y;
if (glyph_is_invisible(lev->glyph) && m_at(x, y))
return;
/* The hero can't feel non pool locations while under water. */
if (Underwater && !Is_waterlevel(&u.uz) && !is_pool(x, y))
/* The hero can't feel non pool locations while under water
except for lava and ice. */
if (Underwater && !Is_waterlevel(&u.uz)
&& !is_pool_or_lava(x, y) && !is_ice(x, y))
return;
/* Set the seen vector as if the hero had seen it.
@@ -572,6 +573,8 @@ xchar x, y;
} else if (IS_DOOR(lev->typ)) {
map_background(x, y, 1);
} else if (IS_ROOM(lev->typ) || IS_POOL(lev->typ)) {
boolean do_room_glyph;
/*
* An open room or water location. Normally we wouldn't touch
* this, but we have to get rid of remembered boulder symbols.
@@ -597,20 +600,18 @@ xchar x, y;
* We could also just display what is currently on the top of the
* object stack (if anything).
*/
if (lev->glyph == objnum_to_glyph(BOULDER)) {
if (lev->typ != ROOM && lev->seenv) {
do_room_glyph = FALSE;
if (lev->glyph == objnum_to_glyph(BOULDER)
|| glyph_is_invisible(lev->glyph)) {
if (lev->typ != ROOM && lev->seenv)
map_background(x, y, 1);
} else {
lev->glyph = (flags.dark_room && iflags.use_color
&& !Is_rogue_level(&u.uz))
? cmap_to_glyph(S_darkroom)
: (lev->waslit ? cmap_to_glyph(S_room)
: cmap_to_glyph(S_stone));
show_glyph(x, y, lev->glyph);
}
} else if ((lev->glyph >= cmap_to_glyph(S_stone)
&& lev->glyph < cmap_to_glyph(S_darkroom))
|| glyph_is_invisible(levl[x][y].glyph)) {
else
do_room_glyph = TRUE;
} else if (lev->glyph >= cmap_to_glyph(S_stone)
&& lev->glyph < cmap_to_glyph(S_darkroom)) {
do_room_glyph = TRUE;
}
if (do_room_glyph) {
lev->glyph = (flags.dark_room && iflags.use_color
&& !Is_rogue_level(&u.uz))
? cmap_to_glyph(S_darkroom)
@@ -701,18 +702,9 @@ register int x, y;
return;
}
if (Underwater && !Is_waterlevel(&u.uz)) {
/* don't do anything unless (x,y) is an adjacent underwater position
*/
int dx, dy;
if (!is_pool(x, y))
return;
dx = x - u.ux;
if (dx < 0)
dx = -dx;
dy = y - u.uy;
if (dy < 0)
dy = -dy;
if (dx > 1 || dy > 1)
/* when underwater, don't do anything unless <x,y> is an
adjacent water or lava or ice position */
if (!(is_pool_or_lava(x, y) || is_ice(x, y)) || distu(x, y) > 2)
return;
}
@@ -1017,9 +1009,10 @@ int first;
static xchar lastx, lasty; /* last swallowed position */
int swallower, left_ok, rght_ok;
if (first)
if (first) {
cls();
else {
bot();
} else {
register int x, y;
/* Clear old location */
@@ -1103,9 +1096,13 @@ int mode;
show_glyph(x, y, cmap_to_glyph(S_stone));
}
/*
* TODO? Should this honor Xray radius rather than force radius 1?
*/
for (x = u.ux - 1; x <= u.ux + 1; x++)
for (y = u.uy - 1; y <= u.uy + 1; y++)
if (isok(x, y) && is_pool(x, y)) {
if (isok(x, y) && (is_pool_or_lava(x, y) || is_ice(x, y))) {
if (Blind && !(x == u.ux && y == u.uy))
show_glyph(x, y, cmap_to_glyph(S_stone));
else
+3 -3
View File
@@ -813,8 +813,8 @@ int retry;
bypass_objlist(invent, FALSE);
} else {
/* should coordinate with perm invent, maybe not show worn items */
n = query_objlist("What would you like to drop?", invent,
USE_INVLET | INVORDER_SORT, &pick_list, PICK_ANY,
n = query_objlist("What would you like to drop?", &invent,
(USE_INVLET | INVORDER_SORT), &pick_list, PICK_ANY,
all_categories ? allow_all : allow_category);
if (n > 0) {
/*
@@ -1317,7 +1317,7 @@ boolean at_stairs, falling, portal;
if (flags.verbose || great_effort)
pline("%s %s up%s the %s.",
great_effort ? "With great effort, you" : "You",
Flying ? "fly" : "climb",
Levitation ? "float" : Flying ? "fly" : "climb",
(Flying && at_ladder) ? " along" : "",
at_ladder ? "ladder" : "stairs");
} else { /* down */
+89 -43
View File
@@ -8,7 +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 void FDECL(gather_locs, (coord **, int *, BOOLEAN_P));
STATIC_DCL void FDECL(gather_locs, (coord **, int *, int));
STATIC_DCL void FDECL(auto_describe, (int, int));
STATIC_DCL void NDECL(do_mname);
STATIC_DCL boolean FDECL(alreadynamed, (struct monst *, char *, char *));
@@ -59,30 +59,38 @@ const char *goal;
putstr(tmpwin, 0, "Use [HJKL] to move the cursor 8 units at a time.");
putstr(tmpwin, 0, "Or enter a background symbol (ex. <).");
putstr(tmpwin, 0, "Use @ to move the cursor on yourself.");
putstr(tmpwin, 0, "Use m or M to move the cursor to next monster.");
putstr(tmpwin, 0, "Use o or O to move the cursor to next object.");
if (getpos_hilitefunc)
putstr(tmpwin, 0, "Use $ to display valid locations.");
putstr(tmpwin, 0, "Use # to toggle automatic description.");
if (iflags.cmdassist) /* assisting the '/' command, I suppose... */
putstr(tmpwin, 0, (iflags.getpos_coords == GPCOORDS_NONE)
? "(Set 'whatis_coord' option to include coordinates with '#' text.)"
if (!iflags.terrainmode || (iflags.terrainmode & TER_MON) != 0)
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) {
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.");
if (iflags.cmdassist) /* assisting the '/' command, I suppose... */
putstr(tmpwin, 0,
(iflags.getpos_coords == GPCOORDS_NONE)
? "(Set 'whatis_coord' option to include coordinates with '#' text.)"
: "(Reset 'whatis_coord' option to omit coordinates from '#' text.)");
/* disgusting hack; the alternate selection characters work for any
getpos call, but they only matter for dowhatis (and doquickwhatis) */
doing_what_is = (goal == what_is_an_unknown_object);
Sprintf(sbuf, "Type a .%s when you are at the right place.",
doing_what_is ? " or , or ; or :" : "");
putstr(tmpwin, 0, sbuf);
if (doing_what_is) {
putstr(tmpwin, 0,
" : describe current spot, show 'more info', move to another spot.");
Sprintf(sbuf, " . describe current spot,%s move to another spot;",
flags.help ? " prompt if 'more info'," : "");
/* disgusting hack; the alternate selection characters work for any
getpos call, but only matter for dowhatis (and doquickwhatis) */
doing_what_is = (goal == what_is_an_unknown_object);
Sprintf(sbuf, "Type a .%s when you are at the right place.",
doing_what_is ? " or , or ; or :" : "");
putstr(tmpwin, 0, sbuf);
putstr(tmpwin, 0, " , describe current spot, move to another spot;");
putstr(tmpwin, 0,
" ; describe current spot, stop looking at things;");
if (doing_what_is) {
putstr(tmpwin, 0,
" : describe current spot, show 'more info', move to another spot.");
Sprintf(sbuf,
" . describe current spot,%s move to another spot;",
flags.help ? " prompt if 'more info'," : "");
putstr(tmpwin, 0, sbuf);
putstr(tmpwin, 0,
" , describe current spot, move to another spot;");
putstr(tmpwin, 0,
" ; describe current spot, stop looking at things;");
}
}
if (!force)
putstr(tmpwin, 0, "Type Space or Escape when you're done.");
@@ -113,17 +121,38 @@ const void *b;
return dist_1 - dist_2;
}
#define GLOC_MONS 0
#define GLOC_OBJS 1
#define GLOC_DOOR 2
boolean
gather_locs_glyphmatch(glyph, gloc)
int glyph, gloc;
{
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)));
}
}
/* gather locations for monsters or objects shown on the map */
STATIC_OVL void
gather_locs(arr_p, cnt_p, do_mons)
gather_locs(arr_p, cnt_p, gloc)
coord **arr_p;
int *cnt_p;
boolean do_mons;
int gloc;
{
int x, y, pass, glyph, idx,
tail = (do_mons ? monnum_to_glyph(PM_LONG_WORM_TAIL) : 0),
boulder = (!do_mons ? objnum_to_glyph(BOULDER) : 0),
rock = (!do_mons ? objnum_to_glyph(ROCK) : 0);
int x, y, pass, glyph, idx;
/*
* We always include the hero's location even if there is no monster
@@ -147,9 +176,7 @@ boolean do_mons;
/* unlike '/M', this skips monsters revealed by
warning glyphs and remembered invisible ones */
if ((x == u.ux && y == u.uy)
|| (do_mons ? (glyph_is_monster(glyph) && glyph != tail)
: (glyph_is_object(glyph)
&& glyph != boulder && glyph != rock))) {
|| gather_locs_glyphmatch(glyph, gloc)) {
if (!pass) {
++*cnt_p;
} else {
@@ -272,8 +299,10 @@ const char *goal;
static const char pick_chars[] = ".,;:";
const char *cp;
boolean hilite_state = FALSE;
coord *monarr = (coord *) 0, *objarr = (coord *) 0;
int moncount = 0, monidx = 0, objcount = 0, objidx = 0;
coord *monarr = (coord *) 0, *objarr = (coord *) 0,
*doorarr = (coord *) 0;
int moncount = 0, monidx = 0, objcount = 0, objidx = 0,
doorcount = 0, dooridx = 0;
if (!goal)
goal = "desired location";
@@ -394,13 +423,13 @@ const char *goal;
} else if (c == '@') { /* return to hero's spot */
/* reset 'm','M' and 'o','O'; otherwise, there's no way for player
to achieve that except by manually cycling through all spots */
monidx = objidx = 0;
monidx = objidx = dooridx = 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, TRUE);
gather_locs(&monarr, &moncount, GLOC_MONS);
monidx = 0; /* monarr[0] is hero's spot */
}
if (c == 'm') {
@@ -414,7 +443,7 @@ const char *goal;
goto nxtc;
} else if (c == 'o' || c == 'O') { /* nearest or farthest object */
if (!objarr) {
gather_locs(&objarr, &objcount, FALSE);
gather_locs(&objarr, &objcount, GLOC_OBJS);
objidx = 0; /* objarr[0] is hero's spot */
}
if (c == 'o') {
@@ -426,6 +455,20 @@ const char *goal;
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;
goto nxtc;
} else {
if (!index(quitchars, c)) {
char matching[MAXPCHARS];
@@ -446,7 +489,7 @@ const char *goal;
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 */
user-visible glyph */
k = back_to_glyph(tx, ty);
/* uninteresting background glyph */
if (glyph_is_cmap(k)
@@ -460,9 +503,10 @@ const char *goal;
}
if (glyph_is_cmap(k)
&& matching[glyph_to_cmap(k)]
&& levl[tx][ty].seenv
&& (!IS_WALL(levl[tx][ty].typ))
&& (levl[tx][ty].typ != SDOOR)
&& (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) {
@@ -495,8 +539,10 @@ const char *goal;
} /* !quitchars */
if (force)
goto nxtc;
pline("Done.");
msg_given = FALSE; /* suppress clear */
if (!iflags.terrainmode) {
pline("Done.");
msg_given = FALSE; /* suppress clear */
}
cx = -1;
cy = 0;
result = 0; /* not -1 */
+3 -3
View File
@@ -2520,9 +2520,9 @@ int retry;
all_worn_categories = TRUE;
}
n = query_objlist("What do you want to take off?", invent,
SIGNAL_NOMENU | USE_INVLET | INVORDER_SORT, &pick_list,
PICK_ANY,
n = query_objlist("What do you want to take off?", &invent,
(SIGNAL_NOMENU | USE_INVLET | INVORDER_SORT),
&pick_list, PICK_ANY,
all_worn_categories ? is_worn : is_worn_by_type);
if (n > 0) {
for (i = 0; i < n; i++)
+4 -19
View File
@@ -1,4 +1,4 @@
/* NetHack 3.6 dogmove.c $NHDT-Date: 1450061092 2015/12/14 02:44:52 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.57 $ */
/* NetHack 3.6 dogmove.c $NHDT-Date: 1463704424 2016/05/20 00:33:44 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.60 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
@@ -874,7 +874,6 @@ int after; /* this is extra fast monster movement */
}
newdogpos:
if (nix != omx || niy != omy) {
struct obj *mw_tmp;
boolean wasseen;
if (info[chi] & ALLOW_U) {
@@ -888,23 +887,9 @@ newdogpos:
}
if (!m_in_out_region(mtmp, nix, niy))
return 1;
if (((IS_ROCK(levl[nix][niy].typ) && may_dig(nix, niy))
|| closed_door(nix, niy))
&& mtmp->weapon_check != NO_WEAPON_WANTED
&& tunnels(mtmp->data) && needspick(mtmp->data)) {
if (closed_door(nix, niy)) {
if (!(mw_tmp = MON_WEP(mtmp)) || !is_pick(mw_tmp)
|| !is_axe(mw_tmp))
mtmp->weapon_check = NEED_PICK_OR_AXE;
} else if (IS_TREE(levl[nix][niy].typ)) {
if (!(mw_tmp = MON_WEP(mtmp)) || !is_axe(mw_tmp))
mtmp->weapon_check = NEED_AXE;
} else if (!(mw_tmp = MON_WEP(mtmp)) || !is_pick(mw_tmp)) {
mtmp->weapon_check = NEED_PICK_AXE;
}
if (mtmp->weapon_check >= NEED_PICK_AXE && mon_wield_item(mtmp))
return 0;
}
if (m_digweapon_check(mtmp, nix,niy))
return 0;
/* insert a worm_move() if worms ever begin to eat things */
wasseen = canseemon(mtmp);
remove_monster(omx, omy);
+11 -5
View File
@@ -1364,8 +1364,9 @@ register struct obj *obj; /* thrownobj or kickedobj or uwep */
int otyp = obj->otyp, hmode;
boolean guaranteed_hit = (u.uswallow && mon == u.ustuck);
hmode = (obj == uwep) ? HMON_APPLIED : (obj == kickedobj) ? HMON_KICKED
: HMON_THROWN;
hmode = (obj == uwep) ? HMON_APPLIED
: (obj == kickedobj) ? HMON_KICKED
: HMON_THROWN;
/* Differences from melee weapons:
*
@@ -1509,18 +1510,22 @@ register struct obj *obj; /* thrownobj or kickedobj or uwep */
}
if (tmp >= rnd(20)) {
boolean wasthrown = (thrownobj != 0);
/* attack hits mon */
if (hmode == HMON_APPLIED)
u.uconduct.weaphit++;
if (hmon(mon, obj, hmode)) { /* mon still alive */
cutworm(mon, bhitpos.x, bhitpos.y, obj);
}
exercise(A_DEX, TRUE);
/* if hero is swallowed and projectile kills the engulfer,
obj gets added to engulfer's inventory and then dropped,
/* if hero was swallowed and projectile killed the engulfer,
'obj' got added to engulfer's inventory and then dropped,
so we can't safely use that pointer anymore; it escapes
the chance to be used up here... */
if (!thrownobj)
if (wasthrown && !thrownobj)
return 1;
/* projectiles other than magic stones
sometimes disappear when thrown */
if (objects[otyp].oc_skill < P_NONE
@@ -1531,6 +1536,7 @@ register struct obj *obj; /* thrownobj or kickedobj or uwep */
* but we need ammo to stay around longer on average.
*/
int broken, chance;
chance = 3 + greatest_erosion(obj) - obj->spe;
if (chance > 1)
broken = rn2(chance);
+11 -6
View File
@@ -1,4 +1,4 @@
/* NetHack 3.6 drawing.c $NHDT-Date: 1447124657 2015/11/10 03:04:17 $ $NHDT-Branch: master $:$NHDT-Revision: 1.49 $ */
/* NetHack 3.6 drawing.c $NHDT-Date: 1463706747 2016/05/20 01:12:27 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.51 $ */
/* Copyright (c) NetHack Development Team 1992. */
/* NetHack may be freely redistributed. See license for details. */
@@ -202,11 +202,12 @@ const struct symdef defsyms[MAXPCHARS] = {
{ '^', "magic trap", C(HI_ZAP) }, /* trap */
{ '^', "anti-magic field", C(HI_ZAP) }, /* trap */
{ '^', "polymorph trap", C(CLR_BRIGHT_GREEN) }, /* trap */
{ '^', "vibrating square", C(CLR_YELLOW) }, /* trap */
{ '|', "wall", C(CLR_GRAY) }, /* vbeam */
{ '-', "wall", C(CLR_GRAY) }, /* hbeam */
{ '\\', "wall", C(CLR_GRAY) }, /* lslant */
{ '/', "wall", C(CLR_GRAY) }, /* rslant */
{ '~', "vibrating square", C(CLR_MAGENTA) }, /* "trap" */
/* zap colors are changed by mapglyph() to match type of beam */
{ '|', "", C(CLR_GRAY) }, /* vbeam */
{ '-', "", C(CLR_GRAY) }, /* hbeam */
{ '\\', "", C(CLR_GRAY) }, /* lslant */
{ '/', "", C(CLR_GRAY) }, /* rslant */
{ '*', "", C(CLR_WHITE) }, /* dig beam */
{ '!', "", C(CLR_WHITE) }, /* camera flash beam */
{ ')', "", C(HI_WOOD) }, /* boomerang open left */
@@ -217,6 +218,7 @@ const struct symdef defsyms[MAXPCHARS] = {
{ '*', "", C(HI_ZAP) },
{ '#', "poison cloud", C(CLR_BRIGHT_GREEN) }, /* part of a cloud */
{ '?', "valid position", C(CLR_BRIGHT_GREEN) }, /* target position */
/* swallow colors are changed by mapglyph() to match engulfing monst */
{ '/', "", C(CLR_GREEN) }, /* swallow top left */
{ '-', "", C(CLR_GREEN) }, /* swallow top center */
{ '\\', "", C(CLR_GREEN) }, /* swallow top right */
@@ -225,6 +227,7 @@ const struct symdef defsyms[MAXPCHARS] = {
{ '\\', "", C(CLR_GREEN) }, /* swallow bottom left */
{ '-', "", C(CLR_GREEN) }, /* swallow bottom center */
{ '/', "", C(CLR_GREEN) }, /* swallow bottom right */
/* explosion colors are changed by mapglyph() to match type of expl. */
{ '/', "", C(CLR_ORANGE) }, /* explosion top left */
{ '-', "", C(CLR_ORANGE) }, /* explosion top center */
{ '\\', "", C(CLR_ORANGE) }, /* explosion top right */
@@ -592,6 +595,7 @@ struct symparse loadsyms[] = {
{ SYM_PCHAR, S_bars, "S_bars" },
{ SYM_PCHAR, S_tree, "S_tree" },
{ SYM_PCHAR, S_room, "S_room" },
{ SYM_PCHAR, S_darkroom, "S_darkroom" },
{ SYM_PCHAR, S_corr, "S_corr" },
{ SYM_PCHAR, S_litcorr, "S_litcorr" },
{ SYM_PCHAR, S_upstair, "S_upstair" },
@@ -636,6 +640,7 @@ struct symparse loadsyms[] = {
{ SYM_PCHAR, S_magic_trap, "S_magic_trap" },
{ SYM_PCHAR, S_anti_magic_trap, "S_anti_magic_trap" },
{ SYM_PCHAR, S_polymorph_trap, "S_polymorph_trap" },
{ SYM_PCHAR, S_vibrating_square, "S_vibrating_square" },
{ SYM_PCHAR, S_vbeam, "S_vbeam" },
{ SYM_PCHAR, S_hbeam, "S_hbeam" },
{ SYM_PCHAR, S_lslant, "S_lslant" },
+91 -9
View File
@@ -1,4 +1,4 @@
/* NetHack 3.6 dungeon.c $NHDT-Date: 1450432757 2015/12/18 09:59:17 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.70 $ */
/* NetHack 3.6 dungeon.c $NHDT-Date: 1462486971 2016/05/05 22:22:51 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.73 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
@@ -490,6 +490,7 @@ struct proto_dungeon *pd;
branch_num = find_branch(dungeons[dgn].dname, pd);
new_branch = (branch *) alloc(sizeof(branch));
(void) memset((genericptr_t)new_branch, 0, sizeof(branch));
new_branch->next = (branch *) 0;
new_branch->id = branch_id++;
new_branch->type = correct_branch_type(&pd->tmpbranch[branch_num]);
@@ -545,6 +546,7 @@ struct proto_dungeon *pd;
pd->final_lev[proto_index] = new_level =
(s_level *) alloc(sizeof(s_level));
(void) memset((genericptr_t)new_level, 0, sizeof(s_level));
/* load new level with data */
Strcpy(new_level->proto, tlevel->name);
new_level->boneid = tlevel->boneschar;
@@ -852,7 +854,7 @@ init_dungeons()
* its branch. First, the depth of the entry point:
*
* depth of branch from "parent" dungeon
* + -1 or 1 depending on a up or down stair or
* + -1 or 1 depending on an up or down stair or
* 0 if portal
*
* Followed by the depth of the top of the dungeon:
@@ -1604,6 +1606,25 @@ level_difficulty()
* The same applies to Vlad's Tower, although the increment
* there is inconsequential compared to overall depth.
*/
#if 0
/*
* The inside of the Wizard's Tower is also effectively a
* builds-up area, reached from a portal an arbitrary distance
* below rather than stairs 1 level beneath the entry level.
*/
else if (On_W_tower_level(&u.uz) && In_W_tower(some_X, some_Y, &u.uz))
res += (fakewiz1.dlev - u.uz.dlev);
/*
* Handling this properly would need more information here:
* an inside/outside flag, or coordinates to calculate it.
* Unfortunately level difficulty may be wanted before
* coordinates have been chosen so simply extending this
* routine to take extra arguments is not sufficient to cope.
* The difference beyond naive depth-from-surface is small
* relative to the overall depth, so just ignore complications
* posed by W_tower.
*/
#endif /*0*/
}
return (xchar) res;
}
@@ -2119,6 +2140,50 @@ int fd;
return load;
}
/* to support '#stats' wizard-mode command */
void
overview_stats(win, statsfmt, total_count, total_size)
winid win;
const char *statsfmt;
long *total_count, *total_size;
{
char buf[BUFSZ], hdrbuf[QBUFSZ];
long ocount, osize, bcount, bsize, acount, asize;
struct cemetery *ce;
mapseen *mptr = find_mapseen(&u.uz);
ocount = bcount = acount = osize = bsize = asize = 0L;
for (mptr = mapseenchn; mptr; mptr = mptr->next) {
++ocount;
osize += (long) sizeof *mptr;
for (ce = mptr->final_resting_place; ce; ce = ce->next) {
++bcount;
bsize += (long) sizeof *ce;
}
if (mptr->custom_lth) {
++acount;
asize += (long) (mptr->custom_lth + 1);
}
}
Sprintf(hdrbuf, "general, size %ld", (long) sizeof (mapseen));
Sprintf(buf, statsfmt, hdrbuf, ocount, osize);
putstr(win, 0, buf);
if (bcount) {
Sprintf(hdrbuf, "cemetery, size %ld",
(long) sizeof (struct cemetery));
Sprintf(buf, statsfmt, hdrbuf, bcount, bsize);
putstr(win, 0, buf);
}
if (acount) {
Sprintf(hdrbuf, "annotations, text");
Sprintf(buf, statsfmt, hdrbuf, acount, asize);
putstr(win, 0, buf);
}
*total_count += ocount + bcount + acount;
*total_size += osize + bsize + asize;
}
/* Remove all mapseen objects for a particular dnum.
* Useful during quest expulsion to remove quest levels.
* [No longer deleted, just marked as unreachable. #overview will
@@ -2421,6 +2486,9 @@ recalc_mapseen()
/* An automatic annotation is added to the Castle and
* to Fort Ludios once their structure's main entrance
* has been seen (in person or via magic mapping).
* For the Fort, that entrance is just a secret door
* which will be converted into a regular one when
* located (or destroyed).
* DOOR: possibly a lowered drawbridge's open portcullis;
* DBWALL: a raised drawbridge's "closed door";
* DRAWBRIDGE_DOWN: the span provided by lowered bridge,
@@ -2430,6 +2498,26 @@ recalc_mapseen()
* the adjacent DBWALL has been seen.
*/
case DOOR:
if (Is_knox(&u.uz)) {
int ty, tx = x - 4;
/* Throne is four columns left, either directly in
* line or one row higher or lower, and doesn't have
* to have been seen yet.
* ......|}}}.
* ..\...S}...
* ..\...S}...
* ......|}}}.
* For 3.6.0 and earlier, it was always in direct line:
* both throne and door on the lower of the two rows.
*/
for (ty = y - 1; ty <= y + 1; ++ty)
if (isok(tx, ty) && IS_THRONE(levl[tx][ty].typ)) {
mptr->flags.ludios = 1;
break;
}
break;
}
if (is_drawbridge_wall(x, y) < 0)
break;
/* else FALLTHRU */
@@ -2437,8 +2525,6 @@ recalc_mapseen()
case DRAWBRIDGE_DOWN:
if (Is_stronghold(&u.uz))
mptr->flags.castle = 1, mptr->flags.castletune = 1;
else if (Is_knox(&u.uz))
mptr->flags.ludios = 1;
break;
default:
break;
@@ -2764,10 +2850,6 @@ boolean printdun;
if (In_endgame(&mptr->lev))
Sprintf(buf, "%s%s:", TAB, endgamelevelname(tmpbuf, i));
else
/* FIXME: when this branch has only one level (Ft.Ludios),
* listing "Level 1:" for it might confuse inexperienced
* players into thinking there's more than one.
*/
Sprintf(buf, "%sLevel %d:", TAB, i);
/* wizmode prints out proto dungeon names for clarity */
@@ -2779,7 +2861,7 @@ boolean printdun;
}
/* [perhaps print custom annotation on its own line when it's long] */
if (mptr->custom)
Sprintf(eos(buf), " (%s)", mptr->custom);
Sprintf(eos(buf), " \"%s\"", mptr->custom);
if (on_level(&u.uz, &mptr->lev))
Sprintf(eos(buf), " <- You %s here.",
(!final || (final == 1 && how == ASCENDED)) ? "are" : "were");
+28 -10
View File
@@ -1502,7 +1502,9 @@ struct obj *obj;
make_confused(HConfusion + d(2, 4), FALSE);
} else if (!rn2(4) && !Blind) {
pline("Everything suddenly goes dark.");
make_blinded((long) d(2, 10), FALSE);
/* hero is not Blind, but Blinded timer might be nonzero if
blindness is being overridden by the Eyes of the Overworld */
make_blinded((Blinded & TIMEOUT) + (long) d(2, 10), FALSE);
if (!Blind)
Your1(vision_clears);
} else if (!rn2(3)) {
@@ -1785,6 +1787,9 @@ struct obj *otmp;
#endif
} else if (otmp->otyp == EGG && stale_egg(otmp)) {
pline("Ugh. Rotten egg."); /* perhaps others like it */
/* increasing existing nausea means that it will take longer
before eventual vomit, but also means that constitution
will be abused more times before illness completes */
make_vomiting((Vomiting & TIMEOUT) + (long) d(10, 4), TRUE);
} else {
give_feedback:
@@ -2610,7 +2615,7 @@ struct obj *obj;
obj, doname, thesimpleoname, "that")) != 'y')
return 0;
}
if (!wield_tool(obj, "use"))
if (!wield_tool(obj, "use"))
return 0;
res = 1;
}
@@ -2652,15 +2657,21 @@ bite()
return 0;
}
/* as time goes by - called by moveloop() and domove() */
/* as time goes by - called by moveloop(every move) & domove(melee attack) */
void
gethungry()
{
if (u.uinvulnerable)
return; /* you don't feel hungrier */
if ((!u.usleep || !rn2(10)) /* slow metabolic rate while asleep */
&& (carnivorous(youmonst.data) || herbivorous(youmonst.data))
/* being polymorphed into a creature which doesn't eat prevents
this first uhunger decrement, but to stay in such form the hero
will need to wear an Amulet of Unchanging so still burn a small
amount of nutrition in the 'moves % 20' ring/amulet check below */
if ((!Unaware || !rn2(10)) /* slow metabolic rate while asleep */
&& (carnivorous(youmonst.data)
|| herbivorous(youmonst.data)
|| metallivorous(youmonst.data))
&& !Slow_digestion)
u.uhunger--; /* ordinary food consumption */
@@ -2677,8 +2688,8 @@ gethungry()
/* Conflict uses up food too */
if (HConflict || (EConflict & (~W_ARTI)))
u.uhunger--;
/* +0 charged rings don't do anything, so don't affect hunger */
/* Slow digestion still uses ring hunger */
/* +0 charged rings don't do anything, so don't affect hunger.
Slow digestion cancels move hunger but still causes ring hunger. */
switch ((int) (moves % 20)) { /* note: use even cases only */
case 4:
if (uleft && (uleft->spe || !objects[uleft->otyp].oc_charged))
@@ -2839,11 +2850,14 @@ boolean incr;
}
if (newhs == FAINTING) {
/* u,uhunger is likely to be negative at this point */
int uhunger_div_by_10 = sgn(u.uhunger) * ((abs(u.uhunger) + 5) / 10);
if (is_fainted())
newhs = FAINTED;
if (u.uhs <= WEAK || rn2(20 - u.uhunger / 10) >= 19) {
if (u.uhs <= WEAK || rn2(20 - uhunger_div_by_10) >= 19) {
if (!is_fainted() && multi >= 0 /* %% */) {
int duration = 10 - (u.uhunger / 10);
int duration = 10 - uhunger_div_by_10;
/* stop what you're doing, then faint */
stop_occupation();
@@ -2858,7 +2872,11 @@ boolean incr;
if (!Levitation)
selftouch("Falling, you");
}
} else if (u.uhunger < -(int) (200 + 20 * ACURR(A_CON))) {
/* this used to be -(200 + 20 * Con) but that was when being asleep
suppressed per-turn uhunger decrement but being fainted didn't;
now uhunger becomes more negative at a slower rate */
} else if (u.uhunger < -(100 + 10 * (int) ACURR(A_CON))) {
u.uhs = STARVED;
context.botl = 1;
bot();
+266 -95
View File
@@ -1,4 +1,4 @@
/* NetHack 3.6 end.c $NHDT-Date: 1454571522 2016/02/04 07:38:42 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.114 $ */
/* NetHack 3.6 end.c $NHDT-Date: 1461919723 2016/04/29 08:48:43 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.116 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
@@ -50,6 +50,9 @@ STATIC_DCL void FDECL(artifact_score, (struct obj *, BOOLEAN_P, winid));
STATIC_DCL void FDECL(really_done, (int)) NORETURN;
STATIC_DCL boolean FDECL(odds_and_ends, (struct obj *, int));
STATIC_DCL void FDECL(savelife, (int));
STATIC_PTR int FDECL(CFDECLSPEC vanqsort_cmp, (const genericptr,
const genericptr));
STATIC_DCL int NDECL(set_vanq_order);
STATIC_DCL void FDECL(list_vanquished, (CHAR_P, BOOLEAN_P));
STATIC_DCL void FDECL(list_genocided, (CHAR_P, BOOLEAN_P));
STATIC_DCL boolean FDECL(should_query_disclose_option, (int, char *));
@@ -627,7 +630,7 @@ int category;
char *defquery;
{
int idx;
char *dop;
char disclose, *dop;
*defquery = 'n';
if ((dop = index(disclosure_options, category)) != 0) {
@@ -639,15 +642,22 @@ char *defquery;
*defquery = DISCLOSE_PROMPT_DEFAULT_YES;
return TRUE;
}
if (flags.end_disclose[idx] == DISCLOSE_YES_WITHOUT_PROMPT) {
disclose = flags.end_disclose[idx];
if (disclose == DISCLOSE_YES_WITHOUT_PROMPT) {
*defquery = 'y';
return FALSE;
} else if (flags.end_disclose[idx] == DISCLOSE_NO_WITHOUT_PROMPT) {
} else if (disclose == DISCLOSE_SPECIAL_WITHOUT_PROMPT) {
*defquery = 'a';
return FALSE;
} else if (disclose == DISCLOSE_NO_WITHOUT_PROMPT) {
*defquery = 'n';
return FALSE;
} else if (flags.end_disclose[idx] == DISCLOSE_PROMPT_DEFAULT_YES) {
} else if (disclose == DISCLOSE_PROMPT_DEFAULT_YES) {
*defquery = 'y';
return TRUE;
} else if (disclose == DISCLOSE_PROMPT_DEFAULT_SPECIAL) {
*defquery = 'a';
return TRUE;
} else {
*defquery = 'n';
return TRUE;
@@ -942,8 +952,8 @@ int how;
return;
}
}
if ((wizard || discover) && (how <= GENOCIDED) &&
!paranoid_query(ParanoidDie, "Die?")) {
if ((wizard || discover) && (how <= GENOCIDED)
&& !paranoid_query(ParanoidDie, "Die?")) {
pline("OK, so you don't %s.", (how == CHOKING) ? "choke" : "die");
savelife(how);
killer.name[0] = 0;
@@ -1329,9 +1339,6 @@ struct obj *list;
boolean identified, all_containers, reportempty;
{
register struct obj *box, *obj;
struct obj **oarray;
int i, n;
char *invlet;
char buf[BUFSZ];
boolean cat, deadcat;
@@ -1355,43 +1362,24 @@ boolean identified, all_containers, reportempty;
} else if (box->cobj) {
winid tmpwin = create_nhwindow(NHW_MENU);
/* count the number of items */
for (n = 0, obj = box->cobj; obj; obj = obj->nobj)
n++;
/* Make a temporary array to store the objects sorted */
oarray = objarr_init(n);
/* Add objects to the array */
i = 0;
invlet = flags.inv_order;
nextclass:
for (obj = box->cobj; obj; obj = obj->nobj) {
if (!flags.sortpack || obj->oclass == *invlet) {
objarr_set(
obj, i++, oarray,
(flags.sortloot == 'f' || flags.sortloot == 'l'));
}
} /* for loop */
if (flags.sortpack) {
if (*++invlet)
goto nextclass;
}
sortloot(&box->cobj,
(((flags.sortloot == 'l' || flags.sortloot == 'f')
? SORTLOOT_LOOT : 0)
| (flags.sortpack ? SORTLOOT_PACK : 0)),
FALSE);
Sprintf(buf, "Contents of %s:", the(xname(box)));
putstr(tmpwin, 0, buf);
putstr(tmpwin, 0, "");
for (i = 0; i < n; i++) {
obj = oarray[i];
for (obj = box->cobj; obj; obj = obj->nobj) {
if (identified) {
makeknown(obj->otyp);
obj->known = obj->bknown = obj->dknown = obj->rknown =
1;
obj->known = obj->bknown = obj->dknown
= obj->rknown = 1;
if (Is_container(obj) || obj->otyp == STATUE)
obj->cknown = obj->lknown = 1;
}
putstr(tmpwin, 0, doname(obj));
}
free(oarray);
if (cat)
putstr(tmpwin, 0, "Schroedinger's cat");
else if (deadcat)
@@ -1446,6 +1434,142 @@ int status;
nethack_exit(status);
}
extern const int monstr[];
static const char *vanqorders[] = {
"traditional: by monster level, by internal monster index",
#define VANQ_MLVL_MNDX 0
"by monster toughness, by internal monster index",
#define VANQ_MSTR_MNDX 1
"alphabetically, first unique monsters, then others",
#define VANQ_ALPHA_SEP 2
"alphabetically, unique monsters and others intermixed",
#define VANQ_ALPHA_MIX 3
"by monster class, high to low level within class",
#define VANQ_MCLS_HTOL 4
"by monster class, low to high level within class",
#define VANQ_MCLS_LTOH 5
"by count, high to low, by internal index within tied count",
#define VANQ_COUNT_H_L 6
"by count, low to high, by internal index within tied count",
#define VANQ_COUNT_L_H 7
};
static int vanq_sortmode = VANQ_MLVL_MNDX;
STATIC_PTR int CFDECLSPEC
vanqsort_cmp(vptr1, vptr2)
const genericptr vptr1;
const genericptr vptr2;
{
int indx1 = *(short *) vptr1, indx2 = *(short *) vptr2,
mlev1, mlev2, mstr1, mstr2, uniq1, uniq2, died1, died2, res;
const char *name1, *name2, *punct;
schar mcls1, mcls2;
switch (vanq_sortmode) {
default:
case VANQ_MLVL_MNDX:
/* sort by monster level */
mlev1 = mons[indx1].mlevel, mlev2 = mons[indx2].mlevel;
res = mlev2 - mlev1; /* mlevel high to low */
break;
case VANQ_MSTR_MNDX:
/* sort by monster toughness */
mstr1 = monstr[indx1], mstr2 = monstr[indx2];
res = mstr2 - mstr1; /* monstr high to low */
break;
case VANQ_ALPHA_SEP:
uniq1 = ((mons[indx1].geno & G_UNIQ) && indx1 != PM_HIGH_PRIEST);
uniq2 = ((mons[indx2].geno & G_UNIQ) && indx2 != PM_HIGH_PRIEST);
if (uniq1 ^ uniq2) { /* one or other uniq, but not both */
res = uniq2 - uniq1;
break;
} /* else both unique or neither unique */
/*FALLTHRU*/
case VANQ_ALPHA_MIX:
name1 = mons[indx1].mname, name2 = mons[indx2].mname;
res = strcmpi(name1, name2); /* caseblind alhpa, low to high */
break;
case VANQ_MCLS_HTOL:
case VANQ_MCLS_LTOH:
/* mons[].mlet is a small integer, 1..N, of type plain char;
if 'char' happens to be unsigned, (mlet1 - mlet2) would yield
an inappropriate result when mlet2 is greater than mlet1,
so force our copies (mcls1, mcls2) to be signed */
mcls1 = (schar) mons[indx1].mlet, mcls2 = (schar) mons[indx2].mlet;
/* S_ANT through S_ZRUTY correspond to lowercase monster classes,
S_ANGEL through S_ZOMBIE correspond to uppercase, and various
punctuation characters are used for classes beyond those */
if (mcls1 > S_ZOMBIE && mcls2 > S_ZOMBIE) {
/* force a specific order to the punctuation classes that's
different from the internal order;
internal order is ok if neither or just one is punctuation
since letters have lower values so come out before punct */
static const char punctclasses[] = {
S_LIZARD, S_EEL, S_GOLEM, S_GHOST, S_DEMON, S_HUMAN, '\0'
};
if ((punct = index(punctclasses, mcls1)) != 0)
mcls1 = (schar) (S_ZOMBIE + 1 + (int) (punct - punctclasses));
if ((punct = index(punctclasses, mcls2)) != 0)
mcls2 = (schar) (S_ZOMBIE + 1 + (int) (punct - punctclasses));
}
res = mcls1 - mcls2; /* class */
if (res == 0) {
mlev1 = mons[indx1].mlevel, mlev2 = mons[indx2].mlevel;
res = mlev1 - mlev2; /* mlevel low to high */
if (vanq_sortmode == VANQ_MCLS_HTOL)
res = -res; /* mlevel high to low */
}
break;
case VANQ_COUNT_H_L:
case VANQ_COUNT_L_H:
died1 = mvitals[indx1].died, died2 = mvitals[indx2].died;
res = died2 - died1; /* dead count high to low */
if (vanq_sortmode == VANQ_COUNT_L_H)
res = -res; /* dead count low to high */
break;
}
/* tiebreaker: internal mons[] index */
if (res == 0)
res = indx1 - indx2; /* mndx low to high */
return res;
}
/* returns -1 if cancelled via ESC */
STATIC_OVL int
set_vanq_order()
{
winid tmpwin;
menu_item *selected;
anything any;
int i, n, choice;
tmpwin = create_nhwindow(NHW_MENU);
start_menu(tmpwin);
any = zeroany; /* zero out all bits */
for (i = 0; i < SIZE(vanqorders); i++) {
if (i == VANQ_ALPHA_MIX || i == VANQ_MCLS_HTOL) /* skip these */
continue;
any.a_int = i + 1;
add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, vanqorders[i],
(i == vanq_sortmode) ? MENU_SELECTED : MENU_UNSELECTED);
}
end_menu(tmpwin, "Sort order for vanquished monster counts");
n = select_menu(tmpwin, PICK_ONE, &selected);
destroy_nhwindow(tmpwin);
if (n > 0) {
choice = selected[0].item.a_int - 1;
/* skip preselected entry if we have more than one item chosen */
if (n > 1 && choice == vanq_sortmode)
choice = selected[1].item.a_int - 1;
free((genericptr_t) selected);
vanq_sortmode = choice;
}
return (n < 0) ? -1 : vanq_sortmode;
}
/* #vanquished command */
int
dovanquished()
@@ -1454,75 +1578,112 @@ dovanquished()
return 0;
}
/* high priests aren't unique but are flagged as such to simplify something */
#define UniqCritterIndx(mndx) ((mons[mndx].geno & G_UNIQ) \
&& mndx != PM_HIGH_PRIEST)
STATIC_OVL void
list_vanquished(defquery, ask)
char defquery;
boolean ask;
{
register int i, lev;
int ntypes = 0, max_lev = 0, nkilled;
register int i;
int pfx, nkilled;
unsigned ntypes, ni;
long total_killed = 0L;
char c;
winid klwin;
char buf[BUFSZ];
short mindx[NUMMONS];
char c, buf[BUFSZ], buftoo[BUFSZ];
/* get totals first */
ntypes = 0;
for (i = LOW_PM; i < NUMMONS; i++) {
if (mvitals[i].died)
ntypes++;
total_killed += (long) mvitals[i].died;
if (mons[i].mlevel > max_lev)
max_lev = mons[i].mlevel;
if ((nkilled = (int) mvitals[i].died) == 0)
continue;
mindx[ntypes++] = i;
total_killed += (long) nkilled;
}
/* vanquished creatures list;
* includes all dead monsters, not just those killed by the player
*/
if (ntypes != 0) {
char mlet, prev_mlet = 0; /* used as small integer, not character */
boolean class_header, uniq_header, was_uniq = FALSE;
c = ask ? yn_function(
"Do you want an account of creatures vanquished?",
ynqchars, defquery)
ynaqchars, defquery)
: defquery;
if (c == 'q')
done_stopprint++;
if (c == 'y' || c == 'a') {
if (c == 'a') { /* ask player to choose sort order */
/* choose value for vanq_sortmode via menu; ESC cancels list
of vanquished monsters but does not set 'done_stopprint' */
if (set_vanq_order() < 0)
return;
}
uniq_header = (vanq_sortmode == VANQ_ALPHA_SEP);
class_header = (vanq_sortmode == VANQ_MCLS_LTOH
|| vanq_sortmode == VANQ_MCLS_HTOL);
klwin = create_nhwindow(NHW_MENU);
putstr(klwin, 0, "Vanquished creatures:");
putstr(klwin, 0, "");
/* countdown by monster "toughness" */
for (lev = max_lev; lev >= 0; lev--)
for (i = LOW_PM; i < NUMMONS; i++)
if (mons[i].mlevel == lev
&& (nkilled = mvitals[i].died) > 0) {
if ((mons[i].geno & G_UNIQ) && i != PM_HIGH_PRIEST) {
Sprintf(buf, "%s%s",
!type_is_pname(&mons[i]) ? "The " : "",
mons[i].mname);
if (nkilled > 1) {
switch (nkilled) {
case 2:
Sprintf(eos(buf), " (twice)");
break;
case 3:
Sprintf(eos(buf), " (thrice)");
break;
default:
Sprintf(eos(buf), " (%d times)", nkilled);
break;
}
}
} else {
/* trolls or undead might have come back,
but we don't keep track of that */
if (nkilled == 1)
Strcpy(buf, an(mons[i].mname));
else
Sprintf(buf, "%d %s", nkilled,
makeplural(mons[i].mname));
qsort((genericptr_t) mindx, ntypes, sizeof *mindx, vanqsort_cmp);
for (ni = 0; ni < ntypes; ni++) {
i = mindx[ni];
nkilled = mvitals[i].died;
mlet = mons[i].mlet;
if (class_header && mlet != prev_mlet) {
Strcpy(buf, def_monsyms[(int) mlet].explain);
putstr(klwin, ask ? 0 : iflags.menu_headings,
upstart(buf));
prev_mlet = mlet;
}
if (UniqCritterIndx(i)) {
Sprintf(buf, "%s%s",
!type_is_pname(&mons[i]) ? "the " : "",
mons[i].mname);
if (nkilled > 1) {
switch (nkilled) {
case 2:
Sprintf(eos(buf), " (twice)");
break;
case 3:
Sprintf(eos(buf), " (thrice)");
break;
default:
Sprintf(eos(buf), " (%d times)", nkilled);
break;
}
putstr(klwin, 0, buf);
}
was_uniq = TRUE;
} else {
if (uniq_header && was_uniq) {
putstr(klwin, 0, "");
was_uniq = FALSE;
}
/* trolls or undead might have come back,
but we don't keep track of that */
if (nkilled == 1)
Strcpy(buf, an(mons[i].mname));
else
Sprintf(buf, "%3d %s", nkilled,
makeplural(mons[i].mname));
}
/* number of leading spaces to match 3 digit prefix */
pfx = !strncmpi(buf, "the ", 3) ? 0
: !strncmpi(buf, "an ", 3) ? 1
: !strncmpi(buf, "a ", 2) ? 2
: !isdigit(buf[2]) ? 4 : 0;
if (class_header)
++pfx;
Sprintf(buftoo, "%*s%s", pfx, "", buf);
putstr(klwin, 0, buftoo);
}
/*
* if (Hallucination)
* putstr(klwin, 0, "and a partridge in a pear tree");
@@ -1547,10 +1708,14 @@ num_genocides()
{
int i, n = 0;
for (i = LOW_PM; i < NUMMONS; ++i)
if (mvitals[i].mvflags & G_GENOD)
for (i = LOW_PM; i < NUMMONS; ++i) {
if (mvitals[i].mvflags & G_GENOD) {
++n;
if (UniqCritterIndx(i))
impossible("unique creature '%d: %s' genocided?",
i, mons[i].mname);
}
}
return n;
}
@@ -1559,11 +1724,12 @@ num_extinct()
{
int i, n = 0;
for (i = LOW_PM; i < NUMMONS; ++i)
if (!(mvitals[i].mvflags & G_GENOD) && (mvitals[i].mvflags & G_GONE)
&& !(mons[i].geno & G_UNIQ))
for (i = LOW_PM; i < NUMMONS; ++i) {
if (UniqCritterIndx(i))
continue;
if ((mvitals[i].mvflags & G_GONE) == G_EXTINCT)
++n;
}
return n;
}
@@ -1598,19 +1764,24 @@ boolean ask;
putstr(klwin, 0, buf);
putstr(klwin, 0, "");
for (i = LOW_PM; i < NUMMONS; i++)
if (mvitals[i].mvflags & G_GONE && !(mons[i].geno & G_UNIQ)) {
if ((mons[i].geno & G_UNIQ) && i != PM_HIGH_PRIEST)
Sprintf(buf, "%s%s",
!type_is_pname(&mons[i]) ? "" : "the ",
mons[i].mname);
else
Strcpy(buf, makeplural(mons[i].mname));
if (!(mvitals[i].mvflags & G_GENOD))
for (i = LOW_PM; i < NUMMONS; i++) {
/* uniques can't be genocided but can become extinct;
however, they're never reported as extinct, so skip them */
if (UniqCritterIndx(i))
continue;
if (mvitals[i].mvflags & G_GONE) {
Strcpy(buf, makeplural(mons[i].mname));
/*
* "Extinct" is unfortunate terminology. A species
* is marked extinct when its birth limit is reached,
* but there might be members of the species still
* alive, contradicting the meaning of the word.
*/
if ((mvitals[i].mvflags & G_GONE) == G_EXTINCT)
Strcat(buf, " (extinct)");
putstr(klwin, 0, buf);
}
}
putstr(klwin, 0, "");
if (ngenocided > 0) {
Sprintf(buf, "%d species genocided.", ngenocided);
+37 -19
View File
@@ -388,6 +388,7 @@ xchar e_type;
if ((ep = engr_at(x, y)) != 0)
del_engr(ep);
ep = newengr(strlen(s) + 1);
(void) memset((genericptr_t)ep, 0, sizeof(struct engr));
ep->nxt_engr = head_engr;
head_engr = ep;
ep->engr_x = x;
@@ -414,7 +415,7 @@ int x, y;
}
/*
* freehand - returns true if player has a free hand
* freehand - returns true if player has a free hand
*/
int
freehand()
@@ -429,30 +430,30 @@ static NEARDATA const char styluses[] = { ALL_CLASSES, ALLOW_NONE,
RING_CLASS, 0 };
/* Mohs' Hardness Scale:
* 1 - Talc 6 - Orthoclase
* 2 - Gypsum 7 - Quartz
* 3 - Calcite 8 - Topaz
* 4 - Fluorite 9 - Corundum
* 5 - Apatite 10 - Diamond
* 1 - Talc 6 - Orthoclase
* 2 - Gypsum 7 - Quartz
* 3 - Calcite 8 - Topaz
* 4 - Fluorite 9 - Corundum
* 5 - Apatite 10 - Diamond
*
* Since granite is an igneous rock hardness ~ 7, anything >= 8 should
* probably be able to scratch the rock.
* Devaluation of less hard gems is not easily possible because obj struct
* does not contain individual oc_cost currently. 7/91
*
* steel - 5-8.5 (usu. weapon)
* diamond - 10 * jade - 5-6 (nephrite)
* ruby - 9 (corundum) * turquoise - 5-6
* sapphire - 9 (corundum) * opal - 5-6
* topaz - 8 * glass - ~5.5
* emerald - 7.5-8 (beryl) * dilithium - 4-5??
* aquamarine - 7.5-8 (beryl) * iron - 4-5
* garnet - 7.25 (var. 6.5-8) * fluorite - 4
* agate - 7 (quartz) * brass - 3-4
* amethyst - 7 (quartz) * gold - 2.5-3
* jasper - 7 (quartz) * silver - 2.5-3
* onyx - 7 (quartz) * copper - 2.5-3
* moonstone - 6 (orthoclase) * amber - 2-2.5
* steel - 5-8.5 (usu. weapon)
* diamond - 10 * jade - 5-6 (nephrite)
* ruby - 9 (corundum) * turquoise - 5-6
* sapphire - 9 (corundum) * opal - 5-6
* topaz - 8 * glass - ~5.5
* emerald - 7.5-8 (beryl) * dilithium - 4-5??
* aquamarine - 7.5-8 (beryl) * iron - 4-5
* garnet - 7.25 (var. 6.5-8) * fluorite - 4
* agate - 7 (quartz) * brass - 3-4
* amethyst - 7 (quartz) * gold - 2.5-3
* jasper - 7 (quartz) * silver - 2.5-3
* onyx - 7 (quartz) * copper - 2.5-3
* moonstone - 6 (orthoclase) * amber - 2-2.5
*/
/* return 1 if action took 1 (or more) moves, 0 if error or aborted */
@@ -1201,6 +1202,23 @@ int fd;
}
}
/* to support '#stats' wizard-mode command */
void
engr_stats(hdrfmt, hdrbuf, count, size)
const char *hdrfmt;
char *hdrbuf;
long *count, *size;
{
struct engr *ep;
Sprintf(hdrbuf, hdrfmt, (long) sizeof (struct engr));
*count = *size = 0L;
for (ep = head_engr; ep; ep = ep->nxt_engr) {
++*count;
*size += (long) sizeof *ep + (long) ep->engr_lth;
}
}
void
del_engr(ep)
register struct engr *ep;
+27 -8
View File
@@ -40,8 +40,7 @@ int expltype;
int idamres, idamnonres;
struct monst *mtmp, *mdef = 0;
uchar adtyp;
int explmask[3][3];
/* 0=normal explosion, 1=do shieldeff, 2=do nothing */
int explmask[3][3]; /* 0=normal explosion, 1=do shieldeff, 2=do nothing */
boolean shopdamage = FALSE, generic = FALSE, physical_dmg = FALSE,
do_hallu = FALSE, inside_engulfer;
char hallu_buf[BUFSZ];
@@ -414,9 +413,23 @@ int expltype;
mtmp->mhp -= (idamres + idamnonres);
}
if (mtmp->mhp <= 0) {
if (mdef ? (mtmp == mdef) : !context.mon_moving)
if (!context.mon_moving) {
killed(mtmp);
else
} else if (mdef && mtmp == mdef) {
/* 'mdef' killed self trying to cure being turned
* into slime due to some action by the player.
* Hero gets the credit (experience) and most of
* the blame (possible loss of alignment and/or
* luck and/or telepathy depending on mtmp) but
* doesn't break pacifism. xkilled()'s message
* would be "you killed <mdef>" so give our own.
*/
if (cansee(mtmp->mx, mtmp->my) || canspotmon(mtmp))
pline("%s is %s!", Monnam(mtmp),
nonliving(mtmp->data) ? "destroyed"
: "killed");
xkilled(mtmp, XKILL_NOMSG | XKILL_NOCONDUCT);
} else
monkilled(mtmp, "", (int) adtyp);
} else if (!context.mon_moving) {
/* all affected monsters, even if mdef is set */
@@ -576,7 +589,10 @@ struct obj *obj; /* only scatter this obj */
&& ((otmp->otyp == BOULDER) || (otmp->otyp == STATUE))
&& rn2(10)) {
if (otmp->otyp == BOULDER) {
pline("%s apart.", Tobjnam(otmp, "break"));
if (cansee(sx, sy))
pline("%s apart.", Tobjnam(otmp, "break"));
else
You_hear("stone breaking.");
fracture_rock(otmp);
place_object(otmp, sx, sy);
if ((otmp = sobj_at(BOULDER, sx, sy)) != 0) {
@@ -589,7 +605,10 @@ struct obj *obj; /* only scatter this obj */
if ((trap = t_at(sx, sy)) && trap->ttyp == STATUE_TRAP)
deltrap(trap);
pline("%s.", Tobjnam(otmp, "crumble"));
if (cansee(sx, sy))
pline("%s.", Tobjnam(otmp, "crumble"));
else
You_hear("stone crumbling.");
(void) break_statue(otmp);
place_object(otmp, sx, sy); /* put fragments on floor */
}
@@ -604,8 +623,8 @@ struct obj *obj; /* only scatter this obj */
}
if (!used_up) {
stmp =
(struct scatter_chain *) alloc(sizeof(struct scatter_chain));
stmp = (struct scatter_chain *)
alloc(sizeof (struct scatter_chain));
stmp->next = (struct scatter_chain *) 0;
stmp->obj = otmp;
stmp->ox = sx;
+8 -9
View File
@@ -1,4 +1,4 @@
/* NetHack 3.6 files.c $NHDT-Date: 1455835581 2016/02/18 22:46:21 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.204 $ */
/* NetHack 3.6 files.c $NHDT-Date: 1459987580 2016/04/07 00:06:20 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.205 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
@@ -2820,14 +2820,13 @@ int which_set;
mungspaces(buf);
if (!*buf || *buf == '#' || !strcmp(buf, " "))
return 1;
/* remove trailing comment, if any */
if ((commentp = rindex(buf, '#')) != 0) {
*commentp = '\0';
/* remove space preceding the stripped comment, if any;
we know 'commentp > buf' because *buf=='#' was caught above */
if (commentp[-1] == ' ')
*--commentp = '\0';
}
/* remove trailing comment, if any (this isn't strictly needed for
individual symbols, and it won't matter if "X#comment" without
separating space slips through; for handling or set description,
symbol set creator is responsible for preceding '#' with a space
and that comment itself doesn't contain " #") */
if ((commentp = rindex(buf, '#')) != 0 && commentp[-1] == ' ')
commentp[-1] = '\0';
/* find the '=' or ':' */
bufp = index(buf, '=');
+2 -2
View File
@@ -1,5 +1,5 @@
/* NetHack 3.6 fountain.c $NHDT-Date: 1455402364 2016/02/13 22:26:04 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.56 $ */
/* Copyright Scott R. Turner, srt@ucla, 10/27/86 */
/* Copyright Scott R. Turner, srt@ucla, 10/27/86 */
/* NetHack may be freely redistributed. See license for details. */
/* Code for drinking from fountains. */
@@ -481,7 +481,7 @@ register struct obj *obj;
case 29: /* You see coins */
/* We make fountains have more coins the closer you are to the
* surface. After all, there will have been more people going
* by. Just like a shopping mall! Chris Woodbury */
* by. Just like a shopping mall! Chris Woodbury */
if (FOUNTAIN_IS_LOOTED(u.ux, u.uy))
break;
+81 -74
View File
@@ -1,4 +1,4 @@
/* NetHack 3.6 hack.c $NHDT-Date: 1446604111 2015/11/04 02:28:31 $ $NHDT-Branch: master $:$NHDT-Revision: 1.155 $ */
/* NetHack 3.6 hack.c $NHDT-Date: 1462663937 2016/05/07 23:32:17 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.165 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
@@ -149,9 +149,9 @@ moverock()
|| (ttmp->ttyp == SPIKED_PIT))))) {
if (Blind)
feel_location(sx, sy);
if (canspotmon(mtmp))
if (canspotmon(mtmp)) {
pline("There's %s on the other side.", a_monnam(mtmp));
else {
} else {
You_hear("a monster behind %s.", the(xname(otmp)));
map_invisible(rx, ry);
}
@@ -356,7 +356,7 @@ xchar x, y;
if (context.digging.down) /* not continuing previous dig (w/ pick-axe) */
(void) memset((genericptr_t) &context.digging, 0,
sizeof(struct dig_info));
sizeof (struct dig_info));
if (!boulder && IS_ROCK(lev->typ) && !may_dig(x, y)) {
You("hurt your teeth on the %s.",
@@ -388,7 +388,7 @@ xchar x, y;
? "tree"
: IS_ROCK(lev->typ)
? "rock"
: lev->typ == IRONBARS
: (lev->typ == IRONBARS)
? "bar"
: "door");
watch_dig((struct monst *) 0, x, y, FALSE);
@@ -431,7 +431,7 @@ xchar x, y;
block_point(x, y); /* delobj will unblock the point */
/* reset dig state */
(void) memset((genericptr_t) &context.digging, 0,
sizeof(struct dig_info));
sizeof (struct dig_info));
return 1;
}
@@ -490,7 +490,7 @@ xchar x, y;
if (dmgtxt)
pay_for_damage(dmgtxt, FALSE);
(void) memset((genericptr_t) &context.digging, 0,
sizeof(struct dig_info));
sizeof (struct dig_info));
return 0;
}
@@ -636,8 +636,8 @@ struct monst *mon;
return 1;
/* lugging too much junk? */
amt =
(mon == &youmonst) ? inv_weight() + weight_cap() : curr_mon_load(mon);
amt = (mon == &youmonst) ? inv_weight() + weight_cap()
: curr_mon_load(mon);
if (amt > 600)
return 2;
@@ -717,9 +717,9 @@ int mode;
if (closed_door(x, y)) {
if (Blind && mode == DO_MOVE)
feel_location(x, y);
if (Passes_walls)
if (Passes_walls) {
; /* do nothing */
else if (can_ooze(&youmonst)) {
} else if (can_ooze(&youmonst)) {
if (mode == DO_MOVE)
You("ooze under the door.");
} else if (tunnels(youmonst.data) && !needspick(youmonst.data)) {
@@ -802,7 +802,8 @@ int mode;
return (mode == TEST_TRAP);
}
if (mode == TEST_TRAP) return FALSE; /* do not move through traps */
if (mode == TEST_TRAP)
return FALSE; /* do not move through traps */
ust = &levl[ux][uy];
@@ -829,7 +830,8 @@ int mode;
struct obj *obj;
/* never travel through boulders in Sokoban */
if (Sokoban) return FALSE;
if (Sokoban)
return FALSE;
/* don't pick two boulders in a row, unless there's a way thru */
if (sobj_at(BOULDER, ux, uy) && !Sokoban) {
@@ -1273,13 +1275,14 @@ domove()
on_ice = !Levitation && is_ice(u.ux, u.uy);
if (on_ice) {
static int skates = 0;
if (!skates)
skates = find_skates();
if ((uarmf && uarmf->otyp == skates) || resists_cold(&youmonst)
|| Flying || is_floater(youmonst.data)
|| is_clinger(youmonst.data) || is_whirly(youmonst.data))
|| is_clinger(youmonst.data) || is_whirly(youmonst.data)) {
on_ice = FALSE;
else if (!rn2(Cold_resistance ? 3 : 2)) {
} else if (!rn2(Cold_resistance ? 3 : 2)) {
HFumbling |= FROMOUTSIDE;
HFumbling &= ~TIMEOUT;
HFumbling += 1; /* slip on next move */
@@ -1401,7 +1404,8 @@ domove()
/* don't stop travel when displacing pets; if the
displace fails for some reason, attack() in uhitm.c
will stop travel rather than domove */
if (!is_safepet(mtmp) || context.forcefight) nomul(0);
if (!is_safepet(mtmp) || context.forcefight)
nomul(0);
/* only attack if we know it's there */
/* or if we used the 'F' command to fight blindly */
/* or if it hides_under, in which case we call attack() to print
@@ -1440,6 +1444,7 @@ domove()
if (context.forcefight && levl[x][y].typ == IRONBARS && uwep) {
struct obj *obj = uwep;
if (breaktest(obj)) {
if (obj->quan > 1L)
obj = splitobj(obj, 1L);
@@ -1687,8 +1692,8 @@ domove()
nomul(0);
}
if (hides_under(youmonst.data) || (youmonst.data->mlet == S_EEL) || u.dx
|| u.dy)
if (hides_under(youmonst.data) || youmonst.data->mlet == S_EEL
|| u.dx || u.dy)
(void) hideunder(&youmonst);
/*
@@ -1824,8 +1829,7 @@ switch_terrain()
}
/* extracted from spoteffects; called by spoteffects to check for entering or
leaving a pool of water/lava, and by moveloop to check for staying on one
leaving a pool of water/lava, and by moveloop to check for staying on one;
returns true to skip rest of spoteffects */
boolean
pooleffects(newspot)
@@ -1911,8 +1915,9 @@ boolean pick;
static int spotterrain;
static struct trap *spottrap = (struct trap *) 0;
static unsigned spottraptyp = NO_TRAP;
struct monst *mtmp;
struct trap *trap = t_at(u.ux, u.uy);
register struct monst *mtmp;
/* prevent recursion from affecting the hero all over again
[hero poly'd to iron golem enters water here, drown() inflicts
@@ -1945,8 +1950,8 @@ boolean pick;
turn, allowing it to do so could give the perception
that a trap here is being triggered twice, so adjust
the timeout to prevent that */
if (trap && (HLevitation & TIMEOUT) == 1L && !ELevitation
&& !(HLevitation & ~TIMEOUT)) {
if (trap && (HLevitation & TIMEOUT) == 1L
&& !(ELevitation || (HLevitation & ~(I_SPECIAL | TIMEOUT)))) {
if (rn2(2)) { /* defer timeout */
incr_itimeout(&HLevitation, 1L);
} else { /* timeout early */
@@ -1959,22 +1964,22 @@ boolean pick;
}
}
/*
* If not a pit, pickup before triggering trap.
* If pit, trigger trap before pickup.
*/
* If not a pit, pickup before triggering trap.
* If pit, trigger trap before pickup.
*/
pit = (trap && (trap->ttyp == PIT || trap->ttyp == SPIKED_PIT));
if (pick && !pit)
(void) pickup(1);
if (trap) {
/*
* dotrap on a fire trap calls melt_ice() which triggers
* spoteffects() (again) which can trigger the same fire
* trap (again). Use static spottrap to prevent that.
* We track spottraptyp because some traps morph
* (landmine to pit) and any new trap type
* should get triggered.
*/
* dotrap on a fire trap calls melt_ice() which triggers
* spoteffects() (again) which can trigger the same fire
* trap (again). Use static spottrap to prevent that.
* We track spottraptyp because some traps morph
* (landmine to pit) and any new trap type
* should get triggered.
*/
if (!spottrap || spottraptyp != trap->ttyp) {
spottrap = trap;
spottraptyp = trap->ttyp;
@@ -1994,10 +1999,11 @@ boolean pick;
"The ice, is gonna BREAK!", /* The Dead Zone */
};
long time_left = spot_time_left(u.ux, u.uy, MELT_ICE_AWAY);
if (time_left && time_left < 15L)
pline1((time_left < 5L) ? icewarnings[2] : (time_left < 10L)
? icewarnings[1]
: icewarnings[0]);
pline("%s", icewarnings[(time_left < 5L) ? 2
: (time_left < 10L) ? 1
: 0]);
}
if ((mtmp = m_at(u.ux, u.uy)) && !u.uswallow) {
mtmp->mundetected = mtmp->msleeping = 0;
@@ -2005,16 +2011,17 @@ boolean pick;
case S_PIERCER:
pline("%s suddenly drops from the %s!", Amonnam(mtmp),
ceiling(u.ux, u.uy));
if (mtmp->mtame) /* jumps to greet you, not attack */
if (mtmp->mtame) { /* jumps to greet you, not attack */
;
else if (uarmh && is_metallic(uarmh))
} else if (uarmh && is_metallic(uarmh)) {
pline("Its blow glances off your %s.",
helm_simple_name(uarmh));
else if (u.uac + 3 <= rnd(20))
} else if (u.uac + 3 <= rnd(20)) {
You("are almost hit by %s!",
x_monnam(mtmp, ARTICLE_A, "falling", 0, TRUE));
else {
} else {
int dmg;
You("are hit by %s!",
x_monnam(mtmp, ARTICLE_A, "falling", 0, TRUE));
dmg = d(4, 6);
@@ -2073,10 +2080,10 @@ register int typewanted;
int typefound, min_x, min_y, max_x, max_y_offset, step;
register struct rm *lev;
#define goodtype(rno) \
#define goodtype(rno) \
(!typewanted \
|| ((typefound = rooms[rno - ROOMOFFSET].rtype) == typewanted) \
|| ((typewanted == SHOPBASE) && (typefound > SHOPBASE)))
|| (typefound = rooms[rno - ROOMOFFSET].rtype) == typewanted \
|| (typewanted == SHOPBASE && typefound > SHOPBASE))
switch (rno = levl[x][y].roomno) {
case NO_ROOM:
@@ -2111,19 +2118,19 @@ register int typewanted;
for (x = min_x; x <= max_x; x += step) {
lev = &levl[x][min_y];
y = 0;
if (((rno = lev[y].roomno) >= ROOMOFFSET) && !index(ptr, rno)
if ((rno = lev[y].roomno) >= ROOMOFFSET && !index(ptr, rno)
&& goodtype(rno))
*(--ptr) = rno;
y += step;
if (y > max_y_offset)
continue;
if (((rno = lev[y].roomno) >= ROOMOFFSET) && !index(ptr, rno)
if ((rno = lev[y].roomno) >= ROOMOFFSET && !index(ptr, rno)
&& goodtype(rno))
*(--ptr) = rno;
y += step;
if (y > max_y_offset)
continue;
if (((rno = lev[y].roomno) >= ROOMOFFSET) && !index(ptr, rno)
if ((rno = lev[y].roomno) >= ROOMOFFSET && !index(ptr, rno)
&& goodtype(rno))
*(--ptr) = rno;
}
@@ -2176,7 +2183,7 @@ register boolean newlev;
Strcpy(u.urooms, in_rooms(u.ux, u.uy, 0));
for (ptr1 = &u.urooms[0], ptr2 = &u.uentered[0], ptr3 = &u.ushops[0],
ptr4 = &u.ushops_entered[0];
ptr4 = &u.ushops_entered[0];
*ptr1; ptr1++) {
if (!index(u.urooms0, *ptr1))
*(ptr2++) = *ptr1;
@@ -2197,6 +2204,7 @@ register boolean newlev;
*ptr2 = '\0';
}
/* possibly deliver a one-time room entry message */
void
check_special_room(newlev)
register boolean newlev;
@@ -2327,11 +2335,13 @@ register boolean newlev;
return;
}
/* the ',' command */
int
dopickup()
{
int count;
int count, tmpcount;
struct trap *traphere = t_at(u.ux, u.uy);
/* awful kludge to work around parse()'s pre-decrement */
count = (multi || (save_cm && *save_cm == ',')) ? multi + 1 : 0;
multi = 0; /* always reset */
@@ -2346,7 +2356,7 @@ dopickup()
Blind ? "feel" : "see");
return 1;
} else {
int tmpcount = -count;
tmpcount = -count;
return loot_mon(u.ustuck, &tmpcount, (boolean *) 0);
}
}
@@ -2372,6 +2382,7 @@ dopickup()
}
if (!OBJ_AT(u.ux, u.uy)) {
register struct rm *lev = &levl[u.ux][u.uy];
if (IS_THRONE(lev->typ))
pline("It must weigh%s a ton!", lev->looted ? " almost" : "");
else if (IS_SINK(lev->typ))
@@ -2407,10 +2418,11 @@ dopickup()
void
lookaround()
{
register int x, y, i, x0 = 0, y0 = 0, m0 = 1, i0 = 9;
register int corrct = 0, noturn = 0;
register struct monst *mtmp;
register struct trap *trap;
register int x, y;
int i, x0 = 0, y0 = 0, m0 = 1, i0 = 9;
int corrct = 0, noturn = 0;
struct monst *mtmp;
struct trap *trap;
/* Grid bugs stop if trying to move diagonal, even if blind. Maybe */
/* they polymorphed while in the middle of a long move. */
@@ -2423,20 +2435,18 @@ lookaround()
return;
for (x = u.ux - 1; x <= u.ux + 1; x++)
for (y = u.uy - 1; y <= u.uy + 1; y++) {
if (!isok(x, y))
if (!isok(x, y) || (x == u.ux && y == u.uy))
continue;
if (NODIAG(u.umonnum) && x != u.ux && y != u.uy)
continue;
if (u.umonnum == PM_GRID_BUG && x != u.ux && y != u.uy)
continue;
if (x == u.ux && y == u.uy)
continue;
if ((mtmp = m_at(x, y)) && mtmp->m_ap_type != M_AP_FURNITURE
if ((mtmp = m_at(x, y)) != 0
&& mtmp->m_ap_type != M_AP_FURNITURE
&& mtmp->m_ap_type != M_AP_OBJECT
&& (!mtmp->minvis || See_invisible) && !mtmp->mundetected) {
if ((context.run != 1 && !mtmp->mtame)
|| (x == u.ux + u.dx && y == u.uy + u.dy && !context.travel))
|| (x == u.ux + u.dx && y == u.uy + u.dy
&& !context.travel))
goto stop;
}
@@ -2445,11 +2455,10 @@ lookaround()
if (x == u.ux - u.dx && y == u.uy - u.dy)
continue;
if (IS_ROCK(levl[x][y].typ) || (levl[x][y].typ == ROOM)
|| IS_AIR(levl[x][y].typ))
if (IS_ROCK(levl[x][y].typ) || levl[x][y].typ == ROOM
|| IS_AIR(levl[x][y].typ)) {
continue;
else if (closed_door(x, y)
|| (mtmp && is_door_mappear(mtmp))) {
} else if (closed_door(x, y) || (mtmp && is_door_mappear(mtmp))) {
if (x != u.ux && y != u.uy)
continue;
if (context.run != 1)
@@ -2594,9 +2603,7 @@ monster_nearby()
/* Also see the similar check in dochugw() in monmove.c */
for (x = u.ux - 1; x <= u.ux + 1; x++)
for (y = u.uy - 1; y <= u.uy + 1; y++) {
if (!isok(x, y))
continue;
if (x == u.ux && y == u.uy)
if (!isok(x, y) || (x == u.ux && y == u.uy))
continue;
if ((mtmp = m_at(x, y)) && mtmp->m_ap_type != M_AP_FURNITURE
&& mtmp->m_ap_type != M_AP_OBJECT
@@ -2668,8 +2675,8 @@ maybe_wail()
if (u.uprops[powers[i]].intrinsic & INTRINSIC)
++powercnt;
pline(powercnt >= 4 ? "%s, all your powers will be lost..."
: "%s, your life force is running out.",
pline((powercnt >= 4) ? "%s, all your powers will be lost..."
: "%s, your life force is running out.",
who);
}
} else {
@@ -2732,9 +2739,9 @@ weight_cap()
}
if (Levitation || Is_airlevel(&u.uz) /* pugh@cornell */
|| (u.usteed && strongmonst(u.usteed->data)))
|| (u.usteed && strongmonst(u.usteed->data))) {
carrcap = MAX_CARR_CAP;
else {
} else {
if (carrcap > MAX_CARR_CAP)
carrcap = MAX_CARR_CAP;
if (!Flying) {
@@ -2832,7 +2839,7 @@ boolean incl_gold;
}
/* Counts the money in an object chain. */
/* Intended use is for your or some monsters inventory, */
/* Intended use is for your or some monster's inventory, */
/* now that u.gold/m.gold is gone.*/
/* Counting money in a container might be possible too. */
long
+282 -141
View File
@@ -1,4 +1,4 @@
/* NetHack 3.6 invent.c $NHDT-Date: 1457207035 2016/03/05 19:43:55 $ $NHDT-Branch: chasonr $:$NHDT-Revision: 1.197 $ */
/* NetHack 3.6 invent.c $NHDT-Date: 1461967848 2016/04/29 22:10:48 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.208 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
@@ -8,14 +8,14 @@
#define CONTAINED_SYM '>' /* designator for inside a container */
#define HANDS_SYM '-'
STATIC_DCL int FDECL(CFDECLSPEC sortloot_cmp, (struct obj *, struct obj *));
STATIC_DCL int FDECL(CFDECLSPEC sortloot_cmp, (const genericptr,
const genericptr));
STATIC_DCL void NDECL(reorder_invent);
STATIC_DCL void FDECL(noarmor, (BOOLEAN_P));
STATIC_DCL void FDECL(invdisp_nothing, (const char *, const char *));
STATIC_DCL boolean FDECL(worn_wield_only, (struct obj *));
STATIC_DCL boolean FDECL(only_here, (struct obj *));
STATIC_DCL void FDECL(compactify, (char *));
STATIC_DCL boolean FDECL(splittable, (struct obj *));
STATIC_DCL boolean FDECL(taking_off, (const char *));
STATIC_DCL boolean FDECL(putting_on, (const char *));
STATIC_PTR int FDECL(ckunpaid, (struct obj *));
@@ -25,8 +25,8 @@ STATIC_PTR char *FDECL(safeq_shortxprname, (struct obj *));
STATIC_DCL char FDECL(display_pickinv, (const char *, const char *,
BOOLEAN_P, long *));
STATIC_DCL char FDECL(display_used_invlets, (CHAR_P));
STATIC_DCL void FDECL(tally_BUCX,
(struct obj *, int *, int *, int *, int *, int *));
STATIC_DCL void FDECL(tally_BUCX, (struct obj *,
int *, int *, int *, int *, int *));
STATIC_DCL boolean FDECL(this_type_only, (struct obj *));
STATIC_DCL void NDECL(dounpaid);
STATIC_DCL struct obj *FDECL(find_unpaid, (struct obj *, struct obj **));
@@ -47,96 +47,214 @@ static int lastinvnr = 51; /* 0 ... 51 (never saved&restored) */
*/
static char venom_inv[] = { VENOM_CLASS, 0 }; /* (constant) */
struct sortloot_item {
struct obj *obj;
int indx;
};
unsigned sortlootmode = 0;
/* qsort comparison routine for sortloot() */
STATIC_OVL int CFDECLSPEC
sortloot_cmp(obj1, obj2)
struct obj *obj1;
struct obj *obj2;
sortloot_cmp(vptr1, vptr2)
const genericptr vptr1;
const genericptr vptr2;
{
int val1 = 0;
int val2 = 0;
struct sortloot_item *sli1 = (struct sortloot_item *) vptr1,
*sli2 = (struct sortloot_item *) vptr2;
struct obj *obj1 = sli1->obj,
*obj2 = sli2->obj,
sav1, sav2;
char *cls1, *cls2, nam1[BUFSZ], nam2[BUFSZ];
int val1, val2, c, namcmp;
/* Sort object names in lexicographical order, ignoring quantity. */
int name_cmp = strcmpi(cxname_singular(obj1), cxname_singular(obj2));
/* order by object class like inventory display */
if ((sortlootmode & SORTLOOT_PACK) != 0) {
cls1 = index(flags.inv_order, obj1->oclass);
cls2 = index(flags.inv_order, obj2->oclass);
if (cls1 != cls2)
return (int) (cls1 - cls2);
if (name_cmp != 0) {
return name_cmp;
if ((sortlootmode & SORTLOOT_INVLET) != 0) {
; /* skip sub-classes when sorting by packorder+invlet */
/* for armor, group by sub-category */
} else if (obj1->oclass == ARMOR_CLASS) {
static int armcat[7 + 1];
if (!armcat[7]) {
/* one-time init; we want to control the order */
armcat[ARM_HELM] = 1; /* [2] */
armcat[ARM_GLOVES] = 2; /* [3] */
armcat[ARM_BOOTS] = 3; /* [4] */
armcat[ARM_SHIELD] = 4; /* [1] */
armcat[ARM_CLOAK] = 5; /* [5] */
armcat[ARM_SHIRT] = 6; /* [6] */
armcat[ARM_SUIT] = 7; /* [0] */
armcat[7] = 8;
}
val1 = armcat[objects[obj1->otyp].oc_armcat];
val2 = armcat[objects[obj2->otyp].oc_armcat];
if (val1 != val2)
return val1 - val2;
/* for weapons, group by ammo (arrows, bolts), launcher (bows),
missile (dart, boomerang), stackable (daggers, knives, spears),
'other' (swords, axes, &c), polearm */
} else if (obj1->oclass == WEAPON_CLASS) {
val1 = objects[obj1->otyp].oc_skill;
val1 = (val1 < 0)
? (val1 >= -P_CROSSBOW && val1 <= -P_BOW) ? 1 : 3
: (val1 >= P_BOW && val1 <= P_CROSSBOW) ? 2
: (val1 == P_SPEAR || val1 == P_DAGGER
|| val1 == P_KNIFE) ? 4 : !is_pole(obj1) ? 5 : 6;
val2 = objects[obj2->otyp].oc_skill;
val2 = (val2 < 0)
? (val2 >= -P_CROSSBOW && val2 <= -P_BOW) ? 1 : 3
: (val2 >= P_BOW && val2 <= P_CROSSBOW) ? 2
: (val2 == P_SPEAR || val2 == P_DAGGER
|| val2 == P_KNIFE) ? 4 : !is_pole(obj2) ? 5 : 6;
if (val1 != val2)
return val1 - val2;
}
}
/* Sort by BUC. Map blessed to 4, uncursed to 2, cursed to 1, and unknown
* to 0. */
/* order by assigned inventory letter */
if ((sortlootmode & SORTLOOT_INVLET) != 0) {
c = obj1->invlet;
val1 = ('a' <= c && c <= 'z') ? (c - 'a' + 2)
: ('A' <= c && c <= 'Z') ? (c - 'A' + 2 + 26)
: (c == '$') ? 1
: (c == '#') ? 1 + 52 + 1
: 1 + 52 + 1 + 1; /* none of the above */
c = obj2->invlet;
val2 = ('a' <= c && c <= 'z') ? (c - 'a' + 2)
: ('A' <= c && c <= 'Z') ? (c - 'A' + 2 + 26)
: (c == '$') ? 1
: (c == '#') ? 1 + 52 + 1
: 1 + 52 + 1 + 1; /* none of the above */
if (val1 != val2)
return val1 - val2;
}
if ((sortlootmode & SORTLOOT_LOOT) == 0)
goto tiebreak;
/*
* Sort object names in lexicographical order, ignoring quantity.
*/
/* Force diluted potions to come out after undiluted of same type;
obj->odiluted overloads obj->oeroded. */
sav1.odiluted = obj1->odiluted;
sav2.odiluted = obj2->odiluted;
if (obj1->oclass == POTION_CLASS)
obj1->odiluted = 0;
if (obj1->oclass == POTION_CLASS)
obj2->odiluted = 0;
/* Force holy and unholy water to sort adjacent to water rather
than among 'h's and 'u's. BUCX order will keep them distinct. */
Strcpy(nam1, cxname_singular(obj1));
if (obj1->otyp == POT_WATER && obj1->bknown
&& (obj1->blessed || obj1->cursed))
(void) strsubst(nam1, obj1->blessed ? "holy " : "unholy ", "");
Strcpy(nam2, cxname_singular(obj2));
if (obj2->otyp == POT_WATER && obj2->bknown
&& (obj2->blessed || obj2->cursed))
(void) strsubst(nam2, obj2->blessed ? "holy " : "unholy ", "");
obj1->odiluted = sav1.odiluted;
obj2->odiluted = sav2.odiluted;
if ((namcmp = strcmpi(nam1, nam2)) != 0)
return namcmp;
/* Sort by BUCX. Map blessed to 4, uncursed to 2, cursed to 1, and
unknown to 0. */
val1 = obj1->bknown
? (obj1->blessed << 2)
+ ((!obj1->blessed && !obj1->cursed) << 1) + obj1->cursed
: 0;
? (obj1->blessed << 2)
+ ((!obj1->blessed && !obj1->cursed) << 1) + obj1->cursed
: 0;
val2 = obj2->bknown
? (obj2->blessed << 2)
+ ((!obj2->blessed && !obj2->cursed) << 1) + obj2->cursed
: 0;
if (val1 != val2) {
return val2 - val1; /* Because bigger is better. */
}
? (obj2->blessed << 2)
+ ((!obj2->blessed && !obj2->cursed) << 1) + obj2->cursed
: 0;
if (val1 != val2)
return val2 - val1; /* bigger is better */
/* Sort by greasing. This will put the objects in degreasing order. */
/* Sort by greasing. This will put the objects in degreasing order. */
val1 = obj1->greased;
val2 = obj2->greased;
if (val1 != val2) {
return val2 - val1; /* Because bigger is better. */
}
if (val1 != val2)
return val2 - val1; /* bigger is better */
/* Sort by erosion. The effective amount is what matters. */
/* Sort by erosion. The effective amount is what matters. */
val1 = greatest_erosion(obj1);
val2 = greatest_erosion(obj2);
if (val1 != val2) {
return val1 - val2; /* Because bigger is WORSE. */
}
if (val1 != val2)
return val1 - val2; /* bigger is WORSE */
/* Sort by erodeproofing. Map known-invulnerable to 1, and both
* known-vulnerable and unknown-vulnerability to 0, because that's how
* they're displayed. */
/* Sort by erodeproofing. Map known-invulnerable to 1, and both
known-vulnerable and unknown-vulnerability to 0, because that's
how they're displayed. */
val1 = obj1->rknown && obj1->oerodeproof;
val2 = obj2->rknown && obj2->oerodeproof;
if (val1 != val2) {
return val2 - val1; /* Because bigger is better. */
if (val1 != val2)
return val2 - val1; /* bigger is better */
/* Sort by enchantment. Map unknown to -1000, which is comfortably
below the range of obj->spe. oc_uses_known means that obj->known
matters, which usually indirectly means that obj->spe is relevant.
Lots of objects use obj->spe for some other purpose (see obj.h). */
if (objects[obj1->otyp].oc_uses_known
/* exclude eggs (laid by you) and tins (homemade, pureed, &c) */
&& obj1->oclass != FOOD_CLASS) {
val1 = obj1->known ? obj1->spe : -1000;
val2 = obj2->known ? obj2->spe : -1000;
if (val1 != val2)
return val2 - val1; /* bigger is better */
}
/* Sort by enchantment. Map unknown to -1000, which is comfortably below
* the range of ->spe. */
val1 = obj1->known ? obj1->spe : -1000;
val2 = obj2->known ? obj2->spe : -1000;
if (val1 != val2) {
return val2 - val1; /* Because bigger is better. */
}
/* They're identical, as far as we're concerned,
but we want to force a determistic order between them. */
return (obj1->o_id > obj2->o_id) ? 1 : -1;
}
struct obj **
objarr_init(n)
int n;
{
return (struct obj **) alloc(n * sizeof(struct obj *));
tiebreak:
/* They're identical, as far as we're concerned. We want
to force a deterministic order, and do so by producing a
stable sort: maintain the original order of equal items. */
return (sli2->indx - sli1->indx);
}
void
objarr_set(otmp, idx, oarray, dosort)
struct obj *otmp;
int idx;
struct obj **oarray;
boolean dosort;
sortloot(olist, mode, by_nexthere)
struct obj **olist;
unsigned mode; /* flags for sortloot_cmp() */
boolean by_nexthere; /* T: traverse via obj->nexthere, F: via obj->nobj */
{
if (dosort) {
int j;
for (j = idx; j; j--) {
if (sortloot_cmp(otmp, oarray[j - 1]) > 0)
break;
oarray[j] = oarray[j - 1];
}
oarray[j] = otmp;
} else {
oarray[idx] = otmp;
struct sortloot_item *sliarray, osli, nsli;
struct obj *o, **nxt_p;
unsigned n, i;
boolean already_sorted = TRUE;
sortlootmode = mode; /* extra input for sortloot_cmp() */
for (n = osli.indx = 0, osli.obj = *olist; (o = osli.obj) != 0;
osli = nsli) {
nsli.obj = by_nexthere ? o->nexthere : o->nobj;
nsli.indx = (int) ++n;
if (nsli.obj && already_sorted
&& sortloot_cmp((genericptr_t) &osli, (genericptr_t) &nsli) > 0)
already_sorted = FALSE;
}
if (n > 1 && !already_sorted) {
sliarray = (struct sortloot_item *) alloc(n * sizeof *sliarray);
for (i = 0, o = *olist; o;
++i, o = by_nexthere ? o->nexthere : o->nobj)
sliarray[i].obj = o, sliarray[i].indx = (int) i;
qsort((genericptr_t) sliarray, n, sizeof *sliarray, sortloot_cmp);
for (i = 0; i < n; ++i) {
o = sliarray[i].obj;
nxt_p = by_nexthere ? &(o->nexthere) : &(o->nobj);
*nxt_p = (i < n - 1) ? sliarray[i + 1].obj : (struct obj *) 0;
}
*olist = sliarray[0].obj;
free((genericptr_t) sliarray);
}
sortlootmode = 0;
}
void
@@ -923,7 +1041,7 @@ register char *buf;
}
/* some objects shouldn't be split when count given to getobj or askchain */
STATIC_OVL boolean
boolean
splittable(obj)
struct obj *obj;
{
@@ -966,7 +1084,6 @@ register const char *let, *word;
register int foo = 0;
register char *bp = buf;
xchar allowcnt = 0; /* 0, 1 or 2 */
struct obj *firstobj = invent;
boolean usegold = FALSE; /* can't use gold because its illegal */
boolean allowall = FALSE;
boolean allownone = FALSE;
@@ -1011,8 +1128,15 @@ register const char *let, *word;
if (!flags.invlet_constant)
reassign();
else
/* in case invent is in packorder, force it to be in invlet
order before collecing candidate inventory letters;
if player responds with '?' or '*' it will be changed
back by display_pickinv(), but by then we'll have 'lets'
and so won't have to re-sort in the for(;;) loop below */
sortloot(&invent, SORTLOOT_INVLET, FALSE);
for (otmp = firstobj; otmp; otmp = otmp->nobj) {
for (otmp = invent; otmp; otmp = otmp->nobj) {
if (&bp[foo] == &buf[sizeof buf - 1]
|| ap == &altlets[sizeof altlets - 1]) {
/* we must have a huge number of NOINVSYM items somehow */
@@ -1024,8 +1148,8 @@ register const char *let, *word;
|| (usegold && otmp->invlet == GOLD_SYM)
|| (useboulder && otmp->otyp == BOULDER)) {
register int otyp = otmp->otyp;
bp[foo++] = otmp->invlet;
bp[foo++] = otmp->invlet;
/* clang-format off */
/* *INDENT-OFF* */
/* ugly check: remove inappropriate things */
@@ -1038,8 +1162,9 @@ register const char *let, *word;
|| (!strcmp(word, "wield")
&& (otmp->owornmask & W_WEP))
#endif
|| (!strcmp(word, "ready") /* exclude if wielded */
&& (otmp == uwep || (otmp == uswapwep && u.twoweap)))
|| (!strcmp(word, "ready") /* exclude when wielded... */
&& ((otmp == uwep || (otmp == uswapwep && u.twoweap))
&& otmp->quan == 1L)) /* ...unless more than one */
|| ((!strcmp(word, "dip") || !strcmp(word, "grease"))
&& inaccessible_equipment(otmp, (const char *) 0, FALSE))
) {
@@ -1134,7 +1259,8 @@ register const char *let, *word;
/* worn armor (shirt, suit) covered by worn armor (suit, cloak)
or accessory (ring) covered by cursed worn armor (gloves) */
|| (taking_off(word)
&& inaccessible_equipment(otmp, (const char *) 0, FALSE))
&& inaccessible_equipment(otmp, (const char *) 0,
(boolean) (otmp->oclass == RING_CLASS)))
|| (!strcmp(word, "write on")
&& (!(otyp == SCR_BLANK_PAPER || otyp == SPE_BLANK_PAPER)
|| !otmp->dknown || !objects[otyp].oc_name_known))
@@ -1232,10 +1358,12 @@ register const char *let, *word;
else if (!strcmp(word, "write with"))
Sprintf(qbuf, "your %s", body_part(FINGERTIP));
else if (!strcmp(word, "wield"))
Sprintf(qbuf, "your %s %s", uarmg ? "gloved" : "bare",
makeplural(body_part(HAND)));
Sprintf(qbuf, "your %s %s%s", uarmg ? "gloved" : "bare",
makeplural(body_part(HAND)),
!uwep ? " (wielded)" : "");
else if (!strcmp(word, "ready"))
Strcpy(qbuf, "empty quiver");
Sprintf(qbuf, "empty quiver%s",
!uquiver ? " (nothing readied)" : "");
if (ilet == '?' && !*lets && *altlets)
allowed_choices = altlets;
@@ -1426,9 +1554,9 @@ static NEARDATA const char removeables[] = { ARMOR_CLASS, WEAPON_CLASS,
RING_CLASS, AMULET_CLASS,
TOOL_CLASS, 0 };
/* interactive version of getobj - used for Drop, Identify and */
/* Takeoff (A). Return the number of times fn was called successfully */
/* If combo is TRUE, we just use this to get a category list */
/* Interactive version of getobj - used for Drop, Identify, and Takeoff (A).
Return the number of times fn was called successfully.
If combo is TRUE, we just use this to get a category list. */
int
ggetobj(word, fn, mx, combo, resultflags)
const char *word;
@@ -1489,13 +1617,23 @@ unsigned *resultflags;
ilets[iletct] = '\0';
for (;;) {
Sprintf(qbuf, "What kinds of thing do you want to %s? [%s]", word,
ilets);
Sprintf(qbuf, "What kinds of thing do you want to %s? [%s]",
word, ilets);
getlin(qbuf, buf);
if (buf[0] == '\033')
return 0;
if (index(buf, 'i')) {
if (display_inventory((char *) 0, TRUE) == '\033')
char ailets[1+26+26+1+5+1]; /* $ + a-z + A-Z + # + slop + \0 */
struct obj *otmp;
/* applicable inventory letters; if empty, show entire invent */
ailets[0] = '\0';
if (ofilter)
for (otmp = invent; otmp; otmp = otmp->nobj)
/* index() check: limit overflow items to one '#' */
if ((*ofilter)(otmp) && !index(ailets, otmp->invlet))
(void) strkitten(ailets, otmp->invlet);
if (display_inventory(ailets, TRUE) == '\033')
return 0;
} else
break;
@@ -1579,7 +1717,9 @@ unsigned *resultflags;
}
if (m_seen) {
return (allflag || (!oletct && ckfn != ckunpaid)) ? -2 : -3;
return (allflag
|| (!oletct && ckfn != ckunpaid && ckfn != ckvalidcat))
? -2 : -3;
} else if (flags.menu_style != MENU_TRADITIONAL && combo && !allflag) {
return 0;
#if 0
@@ -1605,15 +1745,15 @@ unsigned *resultflags;
* Walk through the chain starting at objchn and ask for all objects
* with olet in olets (if nonNULL) and satisfying ckfn (if nonnull)
* whether the action in question (i.e., fn) has to be performed.
* If allflag then no questions are asked. Max gives the max nr of
* objects to be treated. Return the number of objects treated.
* If allflag then no questions are asked. Mx gives the max number
* of objects to be treated. Return the number of objects treated.
*/
int
askchain(objchn, olets, allflag, fn, ckfn, mx, word)
struct obj **objchn;
register int allflag, mx;
register const char *olets, *word; /* olets is an Obj Class char array */
register int FDECL((*fn), (OBJ_P)), FDECL((*ckfn), (OBJ_P));
int allflag, mx;
const char *olets, *word; /* olets is an Obj Class char array */
int FDECL((*fn), (OBJ_P)), FDECL((*ckfn), (OBJ_P));
{
struct obj *otmp, *otmpo;
register char sym, ilet;
@@ -1628,11 +1768,17 @@ register int FDECL((*fn), (OBJ_P)), FDECL((*ckfn), (OBJ_P));
nodot = (!strcmp(word, "nodot") || !strcmp(word, "drop") || ident
|| takeoff || take_out || put_in);
ininv = (*objchn == invent);
/* someday maybe we'll sort by 'olets' too (temporarily replace
flags.packorder and pass SORTLOOT_PACK), but not yet... */
sortloot(objchn, SORTLOOT_INVLET, FALSE);
first = TRUE;
/* Changed so the askchain is interrogated in the order specified.
* For example, if a person specifies =/ then first all rings will be
* asked about followed by all wands -dgk
*/
/*
* Interrogate in the object class order specified.
* For example, if a person specifies =/ then first all rings
* will be asked about followed by all wands. -dgk
*/
nextclass:
ilet = 'a' - 1;
if (*objchn && (*objchn)->oclass == COIN_CLASS)
@@ -1675,9 +1821,10 @@ nextclass:
Sprintf(qpfx, "%s: ", word), *qpfx = highc(*qpfx);
first = FALSE;
}
(void) safe_qbuf(
qbuf, qpfx, "?", otmp, ininv ? safeq_xprname : doname,
ininv ? safeq_shortxprname : ansimpleoname, "item");
(void) safe_qbuf(qbuf, qpfx, "?", otmp,
ininv ? safeq_xprname : doname,
ininv ? safeq_shortxprname : ansimpleoname,
"item");
sym = (takeoff || ident || otmp->quan < 2L) ? nyaq(qbuf)
: nyNaq(qbuf);
} else
@@ -1689,11 +1836,10 @@ nextclass:
to 'none' or 'all'. 2 special cases: cursed loadstones and
welded weapons (eg, multiple daggers) will remain as merged
unit; done to avoid splitting an object that won't be
droppable (even if we're picking up rather than dropping).
*/
if (!yn_number)
droppable (even if we're picking up rather than dropping). */
if (!yn_number) {
sym = 'n';
else {
} else {
sym = 'y';
if (yn_number < otmp->quan && splittable(otmp))
otmp = splitobj(otmp, yn_number);
@@ -1783,8 +1929,8 @@ int id_limit;
while (id_limit) {
Sprintf(buf, "What would you like to identify %s?",
first ? "first" : "next");
n = query_objlist(buf, invent, SIGNAL_NOMENU | SIGNAL_ESCAPE
| USE_INVLET | INVORDER_SORT,
n = query_objlist(buf, &invent, (SIGNAL_NOMENU | SIGNAL_ESCAPE
| USE_INVLET | INVORDER_SORT),
&pick_list, PICK_ANY, not_fully_identified);
if (n > 0) {
@@ -2021,13 +2167,15 @@ long *out_cnt;
struct obj *otmp;
char ilet, ret;
char *invlet = flags.inv_order;
int i, n, classcount;
int n, classcount;
winid win; /* windows being used */
anything any;
menu_item *selected;
struct obj **oarray;
if (flags.perm_invent && ((lets && *lets) || xtra_choice)) {
if (lets && !*lets)
lets = 0; /* simplify tests: (lets) instead of (lets && *lets) */
if (flags.perm_invent && (lets || xtra_choice)) {
/* partial inventory in perm_invent setting; don't operate on
full inventory window, use an alternate one instead; create
the first time needed and keep it for re-use as needed later */
@@ -2096,19 +2244,10 @@ long *out_cnt;
return ret;
}
/* count the number of items (preliminary count of 0,1,more was 'more'
and is now obsolete); we have at least 2 items or want to behave as
if we do (full invent and wiz_identify use this even for 1 item) */
for (n = 0, otmp = invent; otmp; otmp = otmp->nobj)
if (!lets || !*lets || index(lets, otmp->invlet))
n++;
oarray = objarr_init(n);
/* Add objects to the array */
i = 0;
for (otmp = invent; otmp; otmp = otmp->nobj)
if (!lets || !*lets || index(lets, otmp->invlet)) {
objarr_set(otmp, i++, oarray, (flags.sortloot == 'f'));
}
sortloot(&invent,
(((flags.sortloot == 'f') ? SORTLOOT_LOOT : SORTLOOT_INVLET)
| (flags.sortpack ? SORTLOOT_PACK : 0)),
FALSE);
start_menu(win);
any = zeroany;
@@ -2133,8 +2272,9 @@ long *out_cnt;
}
nextclass:
classcount = 0;
for (i = 0; i < n; i++) {
otmp = oarray[i];
for (otmp = invent; otmp; otmp = otmp->nobj) {
if (lets && !index(lets, otmp->invlet))
continue;
if (!flags.sortpack || otmp->oclass == *invlet) {
any = zeroany; /* all bits zero */
ilet = otmp->invlet;
@@ -2158,7 +2298,6 @@ nextclass:
goto nextclass;
}
}
free(oarray);
end_menu(win, (char *) 0);
n = select_menu(win, want_reply ? PICK_ONE : PICK_NONE, &selected);
@@ -2627,9 +2766,9 @@ dotypeinv()
}
this_type = oclass;
}
if (query_objlist((char *) 0, invent,
(flags.invlet_constant ? USE_INVLET : 0)
| INVORDER_SORT,
if (query_objlist((char *) 0, &invent,
((flags.invlet_constant ? USE_INVLET : 0)
| INVORDER_SORT),
&pick_list, PICK_NONE, this_type_only) > 0)
free((genericptr_t) pick_list);
return 0;
@@ -2751,7 +2890,7 @@ boolean picked_some;
if (Blind)
Strcpy(fbuf, "You feel");
Strcat(fbuf, ":");
(void) display_minventory(mtmp, MINV_ALL, fbuf);
(void) display_minventory(mtmp, MINV_ALL | PICK_NONE, fbuf);
} else {
You("%s no objects here.", verb);
}
@@ -3593,8 +3732,10 @@ struct obj *obj;
* By default, only worn and wielded items are displayed. The caller
* can pick one. Modifier flags are:
*
* MINV_NOLET - nothing selectable
* MINV_ALL - display all inventory
* PICK_NONE, PICK_ONE - standard menu control
* PICK_ANY - allowed, but we only return a single object
* MINV_NOLET - nothing selectable
* MINV_ALL - display all inventory
*/
struct obj *
display_minventory(mon, dflags, title)
@@ -3608,7 +3749,8 @@ char *title;
menu_item *selected = 0;
int do_all = (dflags & MINV_ALL) != 0,
incl_hero = (do_all && u.uswallow && mon == u.ustuck),
have_inv = (mon->minvent != 0), have_any = (have_inv || incl_hero);
have_inv = (mon->minvent != 0), have_any = (have_inv || incl_hero),
pickings = (dflags & MINV_PICKMASK);
Sprintf(tmp, "%s %s:", s_suffix(noit_Monnam(mon)),
do_all ? "possessions" : "armament");
@@ -3619,12 +3761,10 @@ char *title;
*/
youmonst.data = mon->data;
n = query_objlist(title ? title : tmp, mon->minvent,
INVORDER_SORT | (incl_hero ? INCLUDE_HERO : 0),
&selected,
(dflags & MINV_NOLET) ? PICK_NONE : PICK_ONE,
n = query_objlist(title ? title : tmp, &(mon->minvent),
(INVORDER_SORT | (incl_hero ? INCLUDE_HERO : 0)),
&selected, pickings,
do_all ? allow_all : worn_wield_only);
set_uasmon();
} else {
invdisp_nothing(title ? title : tmp, "(none)");
@@ -3656,8 +3796,8 @@ register struct obj *obj;
"that");
if (obj->cobj) {
n = query_objlist(qbuf, obj->cobj, INVORDER_SORT, &selected,
PICK_NONE, allow_all);
n = query_objlist(qbuf, &(obj->cobj), INVORDER_SORT,
&selected, PICK_NONE, allow_all);
} else {
invdisp_nothing(qbuf, "(empty)");
n = 0;
@@ -3707,8 +3847,9 @@ boolean as_if_seen;
if (n) {
only.x = x;
only.y = y;
if (query_objlist("Things that are buried here:", level.buriedobjlist,
INVORDER_SORT, &selected, PICK_NONE, only_here) > 0)
if (query_objlist("Things that are buried here:",
&level.buriedobjlist, INVORDER_SORT,
&selected, PICK_NONE, only_here) > 0)
free((genericptr_t) selected);
only.x = only.y = 0;
}
+17
View File
@@ -306,6 +306,23 @@ int fd;
}
}
/* to support '#stats' wizard-mode command */
void
light_stats(hdrfmt, hdrbuf, count, size)
const char *hdrfmt;
char *hdrbuf;
long *count, *size;
{
light_source *ls;
Sprintf(hdrbuf, hdrfmt, (long) sizeof (light_source));
*count = *size = 0L;
for (ls = light_base; ls; ls = ls->next) {
++*count;
*size += (long) sizeof *ls;
}
}
/* Relink all lights that are so marked. */
void
relink_light_sources(ghostly)
+8 -1
View File
@@ -1,4 +1,4 @@
/* NetHack 3.6 mail.c $NHDT-Date: 1451955080 2016/01/05 00:51:20 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.25 $ */
/* NetHack 3.6 mail.c $NHDT-Date: 1464222344 2016/05/26 00:25:44 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.27 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
@@ -80,6 +80,13 @@ static long laststattime;
#define MAILPATH "/usr/mail/"
#endif
void
free_maildata()
{
if (mailbox)
free((genericptr_t) mailbox), mailbox = (char *) 0;
}
void
getmailstatus()
{
+32 -6
View File
@@ -6,8 +6,6 @@
#include <ctype.h>
STATIC_VAR NEARDATA struct monst zeromonst;
/* this assumes that a human quest leader or nemesis is an archetype
of the corresponding role; that isn't so for some roles (tourist
for instance) but is for the priests and monks we use it for... */
@@ -23,7 +21,8 @@ STATIC_DCL void FDECL(m_initgrp, (struct monst *, int, int, int));
STATIC_DCL void FDECL(m_initthrow, (struct monst *, int, int));
STATIC_DCL void FDECL(m_initweap, (struct monst *));
STATIC_DCL void FDECL(m_initinv, (struct monst *));
STATIC_DCL boolean FDECL(makemon_rnd_goodpos, (struct monst *, unsigned, coord *));
STATIC_DCL boolean FDECL(makemon_rnd_goodpos, (struct monst *,
unsigned, coord *));
extern const int monstr[];
@@ -771,6 +770,7 @@ xchar x, y; /* clone's preferred location or 0 (near mon) */
/* Max HP the same, but current HP halved for both. The caller
* might want to override this by halving the max HP also.
* When current HP is odd, the original keeps the extra point.
* We know original has more than 1 HP, so both end up with at least 1.
*/
m2->mhpmax = mon->mhpmax;
m2->mhp = mon->mhp / 2;
@@ -1327,6 +1327,11 @@ int
mbirth_limit(mndx)
int mndx;
{
/* There is an implicit limit of 4 for "high priest of <deity>",
* but aligned priests can grow into high priests, thus they aren't
* really limited to 4, so leave the default amount in place for them.
*/
/* assert(MAXMONNO < 255); */
return (mndx == PM_NAZGUL ? 9 : mndx == PM_ERINYS ? 3 : MAXMONNO);
}
@@ -1463,7 +1468,7 @@ rndmonst()
rndmonst_state.mchoices[mndx] = 0;
if (tooweak(mndx, minmlev) || toostrong(mndx, maxmlev))
continue;
if (upper && !isupper(def_monsyms[(int) (ptr->mlet)].sym))
if (upper && !isupper((uchar) def_monsyms[(int) ptr->mlet].sym))
continue;
if (elemlevel && wrong_elem_type(ptr))
continue;
@@ -1668,6 +1673,7 @@ grow_up(mtmp, victim)
struct monst *mtmp, *victim;
{
int oldtype, newtype, max_increase, cur_increase, lev_limit, hp_threshold;
unsigned fem;
struct permonst *ptr = mtmp->data;
/* monster died after killing enemy but before calling this function */
@@ -1728,6 +1734,9 @@ struct monst *mtmp, *victim;
else if (lev_limit > 49)
lev_limit = (ptr->mlevel > 49 ? 50 : 49);
/* new form might force gender change */
fem = is_male(ptr) ? 0 : is_female(ptr) ? 1 : mtmp->female;
if ((int) ++mtmp->m_lev >= mons[newtype].mlevel && newtype != oldtype) {
ptr = &mons[newtype];
if (mvitals[newtype].mvflags & G_GENOD) { /* allow G_EXTINCT */
@@ -1739,14 +1748,31 @@ struct monst *mtmp, *victim;
mondied(mtmp);
return (struct permonst *) 0;
} else if (canspotmon(mtmp)) {
char buf[BUFSZ];
/* 3.6.1:
* Temporary (?) hack to fix growing into opposite gender.
*/
Sprintf(buf, "%s%s",
/* deal with female gnome becoming a gnome lord */
(mtmp->female && !fem) ? "male "
/* or a male gnome becoming a gnome lady
(can't happen with 3.6.0 mons[], but perhaps
slightly less sexist if prepared for it...) */
: (fem && !mtmp->female) ? "female " : "",
ptr->mname);
pline("%s %s %s.", Monnam(mtmp),
humanoid(ptr) ? "becomes" : "grows up into",
an(ptr->mname));
(fem != mtmp->female) ? "changes into"
: humanoid(ptr) ? "becomes"
: "grows up into",
an(buf));
}
set_mon_data(mtmp, ptr, 1); /* preserve intrinsics */
newsym(mtmp->mx, mtmp->my); /* color may change */
lev_limit = (int) mtmp->m_lev; /* never undo increment */
}
mtmp->female = fem; /* gender might be changing */
/* sanity checks */
if ((int) mtmp->m_lev > lev_limit) {
mtmp->m_lev--; /* undo increment */
+9 -1
View File
@@ -124,11 +124,19 @@ unsigned *ospecial;
color = NO_COLOR;
#ifdef TEXTCOLOR
/* provide a visible difference if normal and lit corridor
* use the same symbol */
use the same symbol */
} else if (iflags.use_color && offset == S_litcorr
&& showsyms[idx] == showsyms[S_corr + SYM_OFF_P]) {
color = CLR_WHITE;
#endif
/* try to provide a visible difference between water and lava
if they use the same symbol and color is disabled */
} else if (!iflags.use_color && offset == S_lava
&& (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;
} else {
cmap_color(offset);
}
+2 -2
View File
@@ -268,8 +268,8 @@ boolean foundyou;
}
/*
* As these are spells, the damage is related to the level
* of the monster casting the spell.
* As these are spells, the damage is related to the level
* of the monster casting the spell.
*/
if (!foundyou) {
dmg = 0;
+29 -15
View File
@@ -2147,10 +2147,15 @@ register struct attack *mattk;
/* not blind at this point implies you're wearing
the Eyes of the Overworld; make them block this
particular stun attack too */
if (!Blind)
if (!Blind) {
Your1(vision_clears);
else
make_stunned((long) d(1, 3), TRUE);
} else {
long oldstun = (HStun & TIMEOUT), newstun = (long) rnd(3);
/* we don't want to increment stun duration every time
or sighted hero will become incapacitated */
make_stunned(max(oldstun, newstun), TRUE);
}
}
}
break;
@@ -2297,7 +2302,7 @@ register struct monst *mon;
{
register struct obj *ring, *nring;
boolean fem = (mon->data == &mons[PM_SUCCUBUS]); /* otherwise incubus */
int tried_gloves = 0;
int attr_tot, tried_gloves = 0;
char qbuf[QBUFSZ];
if (mon->mcan || mon->mspec_used) {
@@ -2438,7 +2443,12 @@ register struct monst *mon;
/* by this point you have discovered mon's identity, blind or not... */
pline("Time stands still while you and %s lie in each other's arms...",
noit_mon_nam(mon));
if (rn2(35) > ACURR(A_CHA) + ACURR(A_INT)) {
/* 3.6.1: a combined total for charisma plus intelligence of 35-1
used to guarantee successful outcome; now total maxes out at 32
as far as deciding what will happen; chance for bad outcome when
Cha+Int is 32 or more is 2/35, a bit over 5.7% */
attr_tot = ACURR(A_CHA) + ACURR(A_INT);
if (rn2(35) > min(attr_tot, 32)) {
/* Don't bother with mspec_used here... it didn't get tired! */
pline("%s seems to have enjoyed it more than you...",
noit_Monnam(mon));
@@ -2470,16 +2480,20 @@ register struct monst *mon;
} else {
You("have a curious feeling...");
}
exercise(A_CON, FALSE);
exercise(A_DEX, FALSE);
exercise(A_WIS, FALSE);
break;
case 4: {
int tmp;
You_feel("exhausted.");
exercise(A_STR, FALSE);
tmp = rn1(10, 6);
losehp(Maybe_Half_Phys(tmp), "exhaustion", KILLED_BY);
break;
}
}
} /* case 4 */
} /* switch */
} else {
mon->mspec_used = rnd(100); /* monster is worn out */
You("seem to have enjoyed it more than %s...", noit_mon_nam(mon));
@@ -2517,14 +2531,14 @@ register struct monst *mon;
}
}
if (mon->mtame) /* don't charge */
if (mon->mtame) { /* don't charge */
;
else if (rn2(20) < ACURR(A_CHA)) {
} else if (rn2(20) < ACURR(A_CHA)) {
pline("%s demands that you pay %s, but you refuse...",
noit_Monnam(mon), Blind ? (fem ? "her" : "him") : mhim(mon));
} else if (u.umonnum == PM_LEPRECHAUN)
} else if (u.umonnum == PM_LEPRECHAUN) {
pline("%s tries to take your money, but fails...", noit_Monnam(mon));
else {
} else {
long cost;
long umoney = money_cnt(invent);
@@ -2539,9 +2553,9 @@ register struct monst *mon;
}
if (cost > umoney)
cost = umoney;
if (!cost)
if (!cost) {
verbalize("It's on the house!");
else {
} else {
pline("%s takes %ld %s for services rendered!", noit_Monnam(mon),
cost, currency(cost));
money2mon(mon, cost);
@@ -2650,7 +2664,7 @@ register struct attack *mattk;
}
pline("%s turns to stone!", Monnam(mtmp));
stoned = 1;
xkilled(mtmp, 0);
xkilled(mtmp, XKILL_NOMSG);
if (mtmp->mhp > 0)
return 1;
return 2;
@@ -2759,7 +2773,7 @@ register struct attack *mattk;
assess_dmg:
if ((mtmp->mhp -= tmp) <= 0) {
pline("%s dies!", Monnam(mtmp));
xkilled(mtmp, 0);
xkilled(mtmp, XKILL_NOMSG);
if (mtmp->mhp > 0)
return 1;
return 2;
+2 -2
View File
@@ -247,8 +247,8 @@ boolean anyroom;
}
/*
* If we have drawn a map without walls, this allows us to
* auto-magically wallify it. Taken from lev_main.c.
* If we have drawn a map without walls, this allows us to
* auto-magically wallify it. Taken from lev_main.c.
*/
STATIC_OVL void
wallify_map()
+127 -28
View File
@@ -1,4 +1,4 @@
/* NetHack 3.6 mkmaze.c $NHDT-Date: 1449269918 2015/12/04 22:58:38 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.42 $ */
/* NetHack 3.6 mkmaze.c $NHDT-Date: 1461571093 2016/04/25 07:58:13 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.47 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
@@ -9,9 +9,11 @@
/* from sp_lev.c, for fixup_special() */
extern lev_region *lregions;
extern int num_lregions;
/* for preserving the insect legs when wallifying baalz level */
static lev_region bughack = { {COLNO, ROWNO, 0, 0}, {COLNO, ROWNO, 0, 0} };
STATIC_DCL boolean FDECL(iswall, (int, int));
STATIC_DCL boolean FDECL(iswall_or_stone, (int, int));
STATIC_DCL int FDECL(iswall, (int, int));
STATIC_DCL int FDECL(iswall_or_stone, (int, int));
STATIC_DCL boolean FDECL(is_solid, (int, int));
STATIC_DCL int FDECL(extend_spine, (int[3][3], int, int, int));
STATIC_DCL boolean FDECL(okay, (int, int, int));
@@ -19,6 +21,7 @@ STATIC_DCL void FDECL(maze0xy, (coord *));
STATIC_DCL boolean FDECL(put_lregion_here, (XCHAR_P, XCHAR_P, XCHAR_P,
XCHAR_P, XCHAR_P, XCHAR_P,
XCHAR_P, BOOLEAN_P, d_level *));
STATIC_DCL void NDECL(baalz_fixup);
STATIC_DCL void NDECL(setup_waterlevel);
STATIC_DCL void NDECL(unsetup_waterlevel);
@@ -34,33 +37,28 @@ STATIC_DCL void NDECL(unsetup_waterlevel);
} \
} while (0)
STATIC_OVL boolean
STATIC_OVL int
iswall(x, y)
int x, y;
{
register int type;
if (!isok(x, y))
return FALSE;
return 0;
type = levl[x][y].typ;
return (boolean) (IS_WALL(type) || IS_DOOR(type)
|| type == SDOOR || type == IRONBARS);
return (IS_WALL(type) || IS_DOOR(type)
|| type == SDOOR || type == IRONBARS);
}
STATIC_OVL boolean
STATIC_OVL int
iswall_or_stone(x, y)
int x, y;
{
register int type;
/* out of bounds = stone */
if (!isok(x, y))
return TRUE;
return 1;
type = levl[x][y].typ;
return (boolean) (type == STONE
|| IS_WALL(type) || IS_DOOR(type)
|| type == SDOOR || type == IRONBARS);
return (levl[x][y].typ == STONE || iswall(x, y));
}
/* return TRUE if out of bounds, wall or rock */
@@ -138,6 +136,10 @@ int x1, y1, x2, y2;
/* change walls surrounded by rock to rock. */
for (x = x1; x <= x2; x++)
for (y = y1; y <= y2; y++) {
if (within_bounded_area(x, y,
bughack.inarea.x1, bughack.inarea.y1,
bughack.inarea.x2, bughack.inarea.y2))
continue;
lev = &levl[x][y];
type = lev->typ;
if (IS_WALL(type) && type != DBWALL) {
@@ -158,8 +160,9 @@ int x1, y1, x2, y2;
uchar type;
register int x,y;
struct rm *lev;
int FDECL((*loc_f), (int, int));
int bits;
int locale[3][3]; /* rock or wall status surrounding positions */
int locale[3][3]; /* rock or wall status surrounding positions */
/*
* Value 0 represents a free-standing wall. It could be anything,
@@ -172,8 +175,8 @@ int x1, y1, x2, y2;
VWALL, TLWALL, TRWALL, CROSSWALL };
/* sanity check on incoming variables */
if (x1<0 || x2>=COLNO || x1>x2 || y1<0 || y2>=ROWNO || y1>y2)
panic("wall_extends: bad bounds (%d,%d) to (%d,%d)",x1,y1,x2,y2);
if (x1 < 0 || x2 >= COLNO || x1 > x2 || y1 < 0 || y2 >= ROWNO || y1 > y2)
panic("wall_extends: bad bounds (%d,%d) to (%d,%d)", x1, y1, x2, y2);
/* set the correct wall type. */
for (x = x1; x <= x2; x++)
@@ -184,16 +187,21 @@ int x1, y1, x2, y2;
continue;
/* set the locations TRUE if rock or wall or out of bounds */
locale[0][0] = iswall_or_stone(x - 1, y - 1);
locale[1][0] = iswall_or_stone(x, y - 1);
locale[2][0] = iswall_or_stone(x + 1, y - 1);
loc_f = within_bounded_area(x, y, /* for baalz insect */
bughack.inarea.x1, bughack.inarea.y1,
bughack.inarea.x2, bughack.inarea.y2)
? iswall
: iswall_or_stone;
locale[0][0] = (*loc_f)(x - 1, y - 1);
locale[1][0] = (*loc_f)(x, y - 1);
locale[2][0] = (*loc_f)(x + 1, y - 1);
locale[0][1] = iswall_or_stone(x - 1, y);
locale[2][1] = iswall_or_stone(x + 1, y);
locale[0][1] = (*loc_f)(x - 1, y);
locale[2][1] = (*loc_f)(x + 1, y);
locale[0][2] = iswall_or_stone(x - 1, y + 1);
locale[1][2] = iswall_or_stone(x, y + 1);
locale[2][2] = iswall_or_stone(x + 1, y + 1);
locale[0][2] = (*loc_f)(x - 1, y + 1);
locale[1][2] = (*loc_f)(x, y + 1);
locale[2][2] = (*loc_f)(x + 1, y + 1);
/* determine if wall should extend to each direction NSEW */
bits = (extend_spine(locale, iswall(x, y - 1), 0, -1) << 3)
@@ -211,8 +219,8 @@ void
wallification(x1, y1, x2, y2)
int x1, y1, x2, y2;
{
wall_cleanup(x1,y1,x2,y2);
fix_wall_spines(x1,y1,x2,y2);
wall_cleanup(x1, y1, x2, y2);
fix_wall_spines(x1, y1, x2, y2);
}
STATIC_OVL boolean
@@ -358,6 +366,94 @@ d_level *lev;
return TRUE;
}
/* fix up Baalzebub's lair, which depicts a level-sized beetle;
its legs are walls within solid rock--regular wallification
classifies them as superfluous and gets rid of them */
STATIC_OVL void
baalz_fixup()
{
struct monst *mtmp;
int x, y, lastx, lasty;
/*
* baalz level's nondiggable region surrounds the "insect" and rooms.
* The outermost perimeter of that region is subject to wall cleanup
* (hence 'x + 1' and 'y + 1' for starting don't-clean column and row,
* 'lastx - 1' and 'lasty - 1' for ending don't-clean column and row)
* and the interior is protected against that (in wall_cleanup()).
*
* Assumes level.flags.corrmaze is True, otherwise the bug legs will
* have already been "cleaned" away by general wallification.
*/
/* find low and high x for to-be-wallified portion of level */
y = ROWNO / 2;
for (lastx = x = 0; x < COLNO; ++x)
if ((levl[x][y].wall_info & W_NONDIGGABLE) != 0) {
if (!lastx)
bughack.inarea.x1 = x + 1;
lastx = x;
}
bughack.inarea.x2 = ((lastx > bughack.inarea.x1) ? lastx : x) - 1;
/* find low and high y for to-be-wallified portion of level */
x = bughack.inarea.x1;
for (lasty = y = 0; y < ROWNO; ++y)
if ((levl[x][y].wall_info & W_NONDIGGABLE) != 0) {
if (!lasty)
bughack.inarea.y1 = y + 1;
lasty = y;
}
bughack.inarea.y2 = ((lasty > bughack.inarea.y1) ? lasty : y) - 1;
/* two pools mark where special post-wallify fix-ups are needed */
for (x = bughack.inarea.x1; x <= bughack.inarea.x2; ++x)
for (y = bughack.inarea.y1; y <= bughack.inarea.y2; ++y)
if (levl[x][y].typ == POOL) {
levl[x][y].typ = HWALL;
if (bughack.delarea.x1 == COLNO)
bughack.delarea.x1 = x, bughack.delarea.y1 = y;
else
bughack.delarea.x2 = x, bughack.delarea.y2 = y;
} else if (levl[x][y].typ == IRONBARS) {
/* novelty effect; allowing digging in front of 'eyes' */
levl[x - 1][y].wall_info &= ~W_NONDIGGABLE;
if (isok(x - 2, y))
levl[x - 2][y].wall_info &= ~W_NONDIGGABLE;
}
wallification(max(bughack.inarea.x1 - 2, 1),
max(bughack.inarea.y1 - 2, 0),
min(bughack.inarea.x2 + 2, COLNO - 1),
min(bughack.inarea.y2 + 2, ROWNO - 1));
/* bughack hack for rear-most legs on baalz level; first joint on
both top and bottom gets a bogus extra connection to room area,
producing unwanted rectangles; change back to separated legs */
x = bughack.delarea.x1, y = bughack.delarea.y1;
if (isok(x, y) && levl[x][y].typ == TLWALL
&& isok(x, y + 1) && levl[x][y + 1].typ == TUWALL) {
levl[x][y].typ = BRCORNER;
levl[x][y + 1].typ = HWALL;
if ((mtmp = m_at(x, y)) != 0) /* something at temporary pool... */
(void) rloc(mtmp, FALSE);
}
x = bughack.delarea.x2, y = bughack.delarea.y2;
if (isok(x, y) && levl[x][y].typ == TLWALL
&& isok(x, y - 1) && levl[x][y - 1].typ == TDWALL) {
levl[x][y].typ = TRCORNER;
levl[x][y - 1].typ = HWALL;
if ((mtmp = m_at(x, y)) != 0) /* something at temporary pool... */
(void) rloc(mtmp, FALSE);
}
/* reset bughack region; set low end to <COLNO,ROWNO> so that
within_bounded_region() in fix_wall_spines() will fail
most quickly--on its first test--when loading other levels */
bughack.inarea.x1 = bughack.delarea.x1 = COLNO;
bughack.inarea.y1 = bughack.delarea.y1 = ROWNO;
bughack.inarea.x2 = bughack.delarea.x2 = 0;
bughack.inarea.y2 = bughack.delarea.y2 = 0;
}
static boolean was_waterlevel; /* ugh... this shouldn't be needed */
/* this is special stuff that the level compiler cannot (yet) handle */
@@ -512,6 +608,9 @@ fixup_special()
if (mtmp->isshk)
mongone(mtmp);
}
} else if (on_level(&u.uz, &baalzebub_level)) {
/* custom wallify the "beetle" potion of the level */
baalz_fixup();
}
if (lregions)
+8 -8
View File
@@ -1,4 +1,4 @@
/* NetHack 3.6 mkobj.c $NHDT-Date: 1454715975 2016/02/05 23:46:15 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.119 $ */
/* NetHack 3.6 mkobj.c $NHDT-Date: 1462067745 2016/05/01 01:55:45 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.122 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
@@ -107,13 +107,11 @@ struct obj *otmp;
{
if (!otmp->oextra)
otmp->oextra = newoextra();
if (!OMONST(otmp)) {
struct monst *m = newmonst();
/* newmonst() allocates memory but doesn't initialize anything */
(void) memset((genericptr_t) m, 0, sizeof (struct monst));
m->mextra = (struct mextra *) 0;
m->nmon = (struct monst *) 0;
*m = zeromonst;
OMONST(otmp) = m;
}
}
@@ -736,7 +734,8 @@ boolean artif;
otmp->where = OBJ_FREE;
otmp->dknown = index(dknowns, let) ? 0 : 1;
if ((otmp->otyp >= ELVEN_SHIELD && otmp->otyp <= ORCISH_SHIELD)
|| otmp->otyp == SHIELD_OF_REFLECTION)
|| otmp->otyp == SHIELD_OF_REFLECTION
|| objects[otmp->otyp].oc_merge)
otmp->dknown = 0;
if (!objects[otmp->otyp].oc_uses_known)
otmp->known = 1;
@@ -2589,9 +2588,10 @@ struct obj *
obj_nexto(otmp)
struct obj *otmp;
{
if (!otmp)
if (!otmp) {
impossible("obj_nexto: wasn't given an object to check");
return (struct obj *) 0;
}
return obj_nexto_xy(otmp, otmp->ox, otmp->oy, TRUE);
}
+3 -3
View File
@@ -684,9 +684,9 @@ coord *c;
/*
* Search for a special room given its type (zoo, court, etc...)
* Special values :
* - ANY_SHOP
* - ANY_TYPE
* Special values :
* - ANY_SHOP
* - ANY_TYPE
*/
struct mkroom *
search_special(type)
+144 -95
View File
@@ -1,4 +1,4 @@
/* NetHack 3.6 mon.c $NHDT-Date: 1454528962 2016/02/03 19:49:22 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.210 $ */
/* NetHack 3.6 mon.c $NHDT-Date: 1463534459 2016/05/18 01:20:59 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.221 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
@@ -13,7 +13,8 @@
STATIC_VAR boolean vamp_rise_msg;
STATIC_DCL void FDECL(sanity_check_single_mon, (struct monst *, const char *));
STATIC_DCL void FDECL(sanity_check_single_mon, (struct monst *, BOOLEAN_P,
const char *));
STATIC_DCL boolean FDECL(restrap, (struct monst *));
STATIC_DCL long FDECL(mm_aggression, (struct monst *, struct monst *));
STATIC_DCL long FDECL(mm_displacement, (struct monst *, struct monst *));
@@ -41,35 +42,77 @@ const char *warnings[] = {
void
sanity_check_single_mon(mtmp, msg)
sanity_check_single_mon(mtmp, chk_geno, msg)
struct monst *mtmp;
boolean chk_geno;
const char *msg;
{
if (DEADMONSTER(mtmp))
return;
if (mtmp->data < &mons[LOW_PM] || mtmp->data >= &mons[NUMMONS])
impossible("illegal mon data (%s)", msg);
if (mtmp->data < &mons[LOW_PM] || mtmp->data >= &mons[NUMMONS]) {
impossible("illegal mon data %s; mnum=%d (%s)",
fmt_ptr((genericptr_t) mtmp->data), mtmp->mnum, msg);
} else {
int mndx = monsndx(mtmp->data);
if (mtmp->mnum != mndx) {
impossible("monster mnum=%d, monsndx=%d (%s)",
mtmp->mnum, mndx, msg);
mtmp->mnum = mndx;
}
if (chk_geno && (mvitals[mndx].mvflags & G_GENOD) != 0)
impossible("genocided %s in play (%s)", mons[mndx].mname, msg);
}
if (mtmp->isshk && !has_eshk(mtmp))
impossible("shk without eshk (%s)", msg);
if (mtmp->ispriest && !has_epri(mtmp))
impossible("priest without epri (%s)", msg);
if (mtmp->isgd && !has_egd(mtmp))
impossible("guard without egd (%s)", msg);
if (mtmp->isminion && !has_emin(mtmp))
impossible("minion without emin (%s)", msg);
/* guardian angel on astral level is tame but has emin rather than edog */
if (mtmp->mtame && !has_edog(mtmp) && !mtmp->isminion)
impossible("pet without edog (%s)", msg);
}
void
mon_sanity_check()
{
int x,y;
struct monst *mtmp = fmon;
int x, y;
struct monst *mtmp, *m;
while (mtmp) {
sanity_check_single_mon(mtmp, "fmon");
mtmp = mtmp->nmon;
for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
sanity_check_single_mon(mtmp, TRUE, "fmon");
if (DEADMONSTER(mtmp))
continue;
x = mtmp->mx, y = mtmp->my;
if (!isok(x, y) && !(mtmp->isgd && x == 0 && y == 0))
impossible("mon (%s) claims to be at <%d,%d>?",
fmt_ptr((genericptr_t) mtmp), x, y);
else if (level.monsters[x][y] != mtmp)
impossible("mon (%s) at <%d,%d> is not there!",
fmt_ptr((genericptr_t) mtmp), x, y);
}
for (x = 0; x < COLNO; x++)
for (y = 0; y < ROWNO; y++)
if ((mtmp = m_at(x,y)) != 0)
sanity_check_single_mon(mtmp, "m_at");
if ((mtmp = level.monsters[x][y]) != 0) {
for (m = fmon; m; m = m->nmon)
if (m == mtmp)
break;
if (!m)
impossible("map mon (%s) at <%d,%d> not in fmon list!",
fmt_ptr((genericptr_t) mtmp), x, y);
else if ((mtmp->mx != x || mtmp->my != y)
&& mtmp->data != &mons[PM_LONG_WORM])
impossible("map mon (%s) at <%d,%d> is found at <%d,%d>?",
fmt_ptr((genericptr_t) mtmp),
mtmp->mx, mtmp->my, x, y);
}
mtmp = migrating_mons;
while (mtmp) {
sanity_check_single_mon(mtmp, "migr");
mtmp = mtmp->nmon;
for (mtmp = migrating_mons; mtmp; mtmp = mtmp->nmon) {
sanity_check_single_mon(mtmp, FALSE, "migr");
}
}
@@ -370,7 +413,6 @@ unsigned corpseflags;
}
free_mname(mtmp);
return obj;
break;
default_1:
default:
if (mvitals[mndx].mvflags & G_NOCORPSE) {
@@ -472,14 +514,19 @@ register struct monst *mtmp;
*/
if (!is_clinger(mtmp->data) && !likes_lava(mtmp->data)) {
if (!resists_fire(mtmp)) {
if (cansee(mtmp->mx, mtmp->my))
if (cansee(mtmp->mx, mtmp->my)) {
struct attack *dummy = &mtmp->data->mattk[0];
const char *how = on_fire(mtmp->data, dummy);
pline("%s %s.", Monnam(mtmp),
mtmp->data == &mons[PM_WATER_ELEMENTAL]
? "boils away"
: "burns to a crisp");
!strcmp(how, "boiling") ? "boils away"
: !strcmp(how, "melting") ? "melts away"
: "burns to a crisp");
}
mondead(mtmp);
} else {
if (--mtmp->mhp < 1) {
mtmp->mhp -= 1;
if (mtmp->mhp < 1) {
if (cansee(mtmp->mx, mtmp->my))
pline("%s surrenders to the fire.", Monnam(mtmp));
mondead(mtmp);
@@ -1538,7 +1585,10 @@ struct monst **monst_list; /* &migrating_mons or &mydogs or null */
seemimic(mon);
}
remove_monster(mx, my);
if (mon->wormno)
remove_worm(mon);
else
remove_monster(mx, my);
if (mon == fmon) {
fmon = fmon->nmon;
@@ -1580,32 +1630,27 @@ struct monst *mtmp2, *mtmp1;
if (EGD(mtmp1)) {
if (!EGD(mtmp2))
newegd(mtmp2);
(void) memcpy((genericptr_t) EGD(mtmp2), (genericptr_t) EGD(mtmp1),
sizeof (struct egd));
*EGD(mtmp2) = *EGD(mtmp1);
}
if (EPRI(mtmp1)) {
if (!EPRI(mtmp2))
newepri(mtmp2);
(void) memcpy((genericptr_t) EPRI(mtmp2), (genericptr_t) EPRI(mtmp1),
sizeof (struct epri));
*EPRI(mtmp2) = *EPRI(mtmp1);
}
if (ESHK(mtmp1)) {
if (!ESHK(mtmp2))
neweshk(mtmp2);
(void) memcpy((genericptr_t) ESHK(mtmp2), (genericptr_t) ESHK(mtmp1),
sizeof (struct eshk));
*ESHK(mtmp2) = *ESHK(mtmp1);
}
if (EMIN(mtmp1)) {
if (!EMIN(mtmp2))
newemin(mtmp2);
(void) memcpy((genericptr_t) EMIN(mtmp2), (genericptr_t) EMIN(mtmp1),
sizeof (struct emin));
*EMIN(mtmp2) = *EMIN(mtmp1);
}
if (EDOG(mtmp1)) {
if (!EDOG(mtmp2))
newedog(mtmp2);
(void) memcpy((genericptr_t) EDOG(mtmp2), (genericptr_t) EDOG(mtmp1),
sizeof (struct edog));
*EDOG(mtmp2) = *EDOG(mtmp1);
}
if (has_mcorpsenm(mtmp1))
MCORPSENM(mtmp2) = MCORPSENM(mtmp1);
@@ -1735,8 +1780,8 @@ struct monst *mtmp;
/* genocided monster can't be life-saved */
if (cansee(mtmp->mx, mtmp->my))
pline("Unfortunately, %s is still genocided...", mon_nam(mtmp));
mtmp->mhp = 0;
}
mtmp->mhp = 0;
}
void
@@ -1746,6 +1791,7 @@ register struct monst *mtmp;
struct permonst *mptr;
int tmp;
mtmp->mhp = 0; /* in case caller hasn't done this */
lifesaved_monster(mtmp);
if (mtmp->mhp > 0)
return;
@@ -1933,7 +1979,7 @@ boolean was_swallowed; /* digestion */
return FALSE;
if (((bigmonst(mdat) || mdat == &mons[PM_LIZARD]) && !mon->mcloned)
|| is_golem(mdat) || is_mplayer(mdat) || is_rider(mdat))
|| is_golem(mdat) || is_mplayer(mdat) || is_rider(mdat) || mon->isshk)
return TRUE;
tmp = 2 + ((mdat->geno & G_FREQ) < 2) + verysmall(mdat);
return (boolean) !rn2(tmp);
@@ -1988,6 +2034,7 @@ struct monst *mdef;
* put inventory in it, and we have to check for lifesaving before
* making the statue....
*/
mdef->mhp = 0; /* in case caller hasn't done this */
lifesaved_monster(mdef);
if (mdef->mhp > 0)
return;
@@ -2108,52 +2155,45 @@ void
killed(mtmp)
struct monst *mtmp;
{
xkilled(mtmp, 1);
xkilled(mtmp, XKILL_GIVEMSG);
}
/* the player has killed the monster mtmp */
void
xkilled(mtmp, dest)
xkilled(mtmp, xkill_flags)
struct monst *mtmp;
int dest; /* dest==1, normal; dest==0, don't print message; dest==2, don't
drop corpse either; dest==3, message but no corpse */
int xkill_flags; /* 1: suppress message, 2: suppress corpse, 4: pacifist */
{
int tmp, mndx, x = mtmp->mx, y = mtmp->my;
struct permonst *mdat;
struct obj *otmp;
struct trap *t;
boolean wasinside = u.uswallow && (u.ustuck == mtmp);
boolean burycorpse = FALSE;
boolean wasinside = u.uswallow && (u.ustuck == mtmp),
burycorpse = FALSE,
nomsg = (xkill_flags & XKILL_NOMSG) != 0,
nocorpse = (xkill_flags & XKILL_NOCORPSE) != 0,
noconduct = (xkill_flags & XKILL_NOCONDUCT) != 0;
/* KMH, conduct */
u.uconduct.killer++;
mtmp->mhp = 0; /* caller will usually have already done this */
if (!noconduct) /* KMH, conduct */
u.uconduct.killer++;
if (dest & 1) {
const char *verb = nonliving(mtmp->data) ? "destroy" : "kill";
if (!wasinside && !canspotmon(mtmp))
You("%s it!", verb);
else {
You("%s %s!", verb,
!mtmp->mtame
? mon_nam(mtmp)
: x_monnam(mtmp,
(has_mname(mtmp)) ? ARTICLE_NONE : ARTICLE_THE,
"poor",
(has_mname(mtmp)) ? SUPPRESS_SADDLE : 0,
FALSE));
}
}
if (!nomsg)
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));
if (mtmp->mtrapped && (t = t_at(x, y)) != 0
&& (t->ttyp == PIT || t->ttyp == SPIKED_PIT)) {
if (sobj_at(BOULDER, x, y))
dest |= 2; /*
* Prevent corpses/treasure being created "on top"
* of the boulder that is about to fall in. This is
* out of order, but cannot be helped unless this
* whole routine is rearranged.
*/
nocorpse = TRUE; /* Prevent corpses/treasure being created
"on top" of boulder that is about to fall in.
This is out of order, but cannot be helped
unless this whole routine is rearranged. */
if (m_carrying(mtmp, BOULDER))
burycorpse = TRUE;
}
@@ -2183,8 +2223,7 @@ int dest; /* dest==1, normal; dest==0, don't print message; dest==2, don't
if (mtmp->mhp > 0) { /* monster lifesaved */
/* Cannot put the non-visible lifesaving message in
* lifesaved_monster() since the message appears only when you
* kill it (as opposed to visible lifesaving which always
* appears).
* kill it (as opposed to visible lifesaving which always appears).
*/
stoned = FALSE;
if (!cansee(x, y) && !vamp_rise_msg)
@@ -2200,7 +2239,7 @@ int dest; /* dest==1, normal; dest==0, don't print message; dest==2, don't
goto cleanup;
}
if ((dest & 2) || LEVEL_SPECIFIC_NOCORPSE(mdat))
if (nocorpse || LEVEL_SPECIFIC_NOCORPSE(mdat))
goto cleanup;
#ifdef MAIL
@@ -2227,7 +2266,7 @@ int dest; /* dest==1, normal; dest==0, don't print message; dest==2, don't
/* oc_big is also oc_bimanual and oc_bulky */
&& (otmp->owt > 30 || objects[otyp].oc_big)) {
delobj(otmp);
} else if (!flooreffects(otmp, x, y, (dest & 1) ? "fall" : "")) {
} else if (!flooreffects(otmp, x, y, nomsg ? "" : "fall")) {
place_object(otmp, x, y);
stackobj(otmp);
}
@@ -2237,7 +2276,7 @@ int dest; /* dest==1, normal; dest==0, don't print message; dest==2, don't
cadaver = make_corpse(mtmp, burycorpse ? CORPSTAT_BURIED
: CORPSTAT_NONE);
if (burycorpse && cadaver && cansee(x, y) && !mtmp->minvis
&& cadaver->where == OBJ_BURIED && (dest & 1)) {
&& cadaver->where == OBJ_BURIED && !nomsg) {
pline("%s corpse ends up buried.", s_suffix(Monnam(mtmp)));
}
}
@@ -2249,7 +2288,8 @@ int dest; /* dest==1, normal; dest==0, don't print message; dest==2, don't
cleanup:
/* punish bad behaviour */
if (is_human(mdat) && (!always_hostile(mdat) && mtmp->malign <= 0)
if (is_human(mdat)
&& (!always_hostile(mdat) && mtmp->malign <= 0)
&& (mndx < PM_ARCHEOLOGIST || mndx > PM_WIZARD)
&& u.ualign.type != A_CHAOTIC) {
HTelepat &= ~INTRINSIC;
@@ -2346,8 +2386,9 @@ struct monst *mtmp;
SUPPRESS_SADDLE | SUPPRESS_HALLUCINATION
| SUPPRESS_INVISIBLE | SUPPRESS_IT,
FALSE),
amorphous(mtmp->data) ? "coalesces on the" :
is_flyer(mtmp->data) ? "drops to the" : "writhes on the",
amorphous(mtmp->data) ? "coalesces on the"
: is_flyer(mtmp->data) ? "drops to the"
: "writhes on the",
surface(x,y));
mtmp->mcanmove = 1;
mtmp->mfrozen = 0;
@@ -2379,7 +2420,7 @@ struct monst *mtmp;
}
newsym(mtmp->mx, mtmp->my);
return FALSE; /* didn't petrify */
}
}
}
return TRUE;
}
@@ -3168,12 +3209,18 @@ boolean msg; /* "The oldmon turns into a newmon!" */
int hpn, hpd;
int mndx, tryct;
struct permonst *olddata = mtmp->data;
char oldname[BUFSZ], l_oldname[BUFSZ], newname[BUFSZ];
char *p, oldname[BUFSZ], l_oldname[BUFSZ], newname[BUFSZ];
/* Riders are immune to polymorph and green slime
(but apparent Rider might actually be a doppelganger) */
if (is_rider(mtmp->data) && mtmp->cham == NON_PM)
return 0;
if (mtmp->cham == NON_PM) { /* not a shapechanger */
if (is_rider(olddata))
return 0;
/* make Nazgul and erinyes immune too, to reduce chance of
anomalous extinction feedback during final disclsoure */
if (mbirth_limit(monsndx(olddata)) < MAXMONNO)
return 0;
}
if (msg) {
/* like Monnam() but never mention saddle */
@@ -3183,7 +3230,7 @@ boolean msg; /* "The oldmon turns into a newmon!" */
}
/* we need this one whether msg is true or not */
Strcpy(l_oldname, x_monnam(mtmp, ARTICLE_THE, (char *) 0,
(has_mname(mtmp)) ? SUPPRESS_SADDLE : 0, FALSE));
has_mname(mtmp) ? SUPPRESS_SADDLE : 0, FALSE));
/* mdat = 0 -> caller wants a random monster shape */
if (mdat == 0) {
@@ -3206,23 +3253,18 @@ boolean msg; /* "The oldmon turns into a newmon!" */
} else if (mvitals[monsndx(mdat)].mvflags & G_GENOD)
return 0; /* passed in mdat is genocided */
if (mdat == mtmp->data)
if (mdat == olddata)
return 0; /* still the same monster */
mgender_from_permonst(mtmp, mdat);
if (In_endgame(&u.uz) && is_mplayer(olddata) && has_mname(mtmp)) {
/* mplayers start out as "Foo the Bar", but some of the
* titles are inappropriate when polymorphed, particularly
* into the opposite sex. players don't use ranks when
* polymorphed, so dropping the rank for mplayers seems
* reasonable.
*/
char *p = index(MNAME(mtmp), ' ');
if (p)
*p = '\0';
}
/* Endgame mplayers start out as "Foo the Bar", but some of the
* titles are inappropriate when polymorphed, particularly into
* the opposite sex. Player characters don't use ranks when
* polymorphed, so dropping rank for mplayers seems reasonable.
*/
if (In_endgame(&u.uz) && is_mplayer(olddata)
&& has_mname(mtmp) && (p = strstr(MNAME(mtmp), " the ")) != 0)
*p = '\0';
if (mtmp->wormno) { /* throw tail away */
wormgone(mtmp);
@@ -3330,10 +3372,17 @@ boolean msg; /* "The oldmon turns into a newmon!" */
? "slime"
: x_monnam(mtmp, ARTICLE_A, (char *) 0,
SUPPRESS_SADDLE, FALSE));
if (!strcmpi(oldname, "it") && !strcmpi(newname, "it"))
/* oldname was capitalized above; newname will be lower case */
if (!strcmpi(newname, "it")) { /* can't see or sense it now */
if (!!strcmpi(oldname, "it")) /* could see or sense it before */
pline("%s disappears!", oldname);
(void) usmellmon(mdat);
else
pline("%s turns into %s!", oldname, newname);
} else { /* can see or sense it now */
if (!strcmpi(oldname, "it")) /* couldn't see or sense it before */
pline("%s appears!", upstart(newname));
else
pline("%s turns into %s!", oldname, newname);
}
if (save_mname)
MNAME(mtmp) = save_mname;
}
+4 -2
View File
@@ -3,8 +3,9 @@
/* NetHack may be freely redistributed. See license for details. */
#include "hack.h"
/* These routines provide basic data for any type of monster. */
/*
* These routines provide basic data for any type of monster.
*/
/* set up an individual monster's base type (initial creation, shapechange) */
void
@@ -16,6 +17,7 @@ int flag;
int new_speed, old_speed = mon->data ? mon->data->mmove : 0;
mon->data = ptr;
mon->mnum = (short) monsndx(ptr);
if (flag == -1)
return; /* "don't care" */
+37 -18
View File
@@ -1,4 +1,4 @@
/* NetHack 3.6 monmove.c $NHDT-Date: 1456959639 2016/03/02 23:00:39 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.85 $ */
/* NetHack 3.6 monmove.c $NHDT-Date: 1463704424 2016/05/20 00:33:44 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.87 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
@@ -705,6 +705,38 @@ xchar gx, gy;
return FALSE;
}
boolean
m_digweapon_check(mtmp, nix, niy)
struct monst *mtmp;
xchar nix,niy;
{
boolean can_tunnel = 0;
struct obj *mw_tmp;
if (!Is_rogue_level(&u.uz))
can_tunnel = tunnels(mtmp->data);
if (can_tunnel && needspick(mtmp->data)
&& mtmp->weapon_check != NO_WEAPON_WANTED
&& ((IS_ROCK(levl[nix][niy].typ) && may_dig(nix, niy))
|| closed_door(nix, niy))) {
if (closed_door(nix, niy)) {
if (!(mw_tmp = MON_WEP(mtmp))
|| !is_pick(mw_tmp)
|| !is_axe(mw_tmp))
mtmp->weapon_check = NEED_PICK_OR_AXE;
} else if (IS_TREE(levl[nix][niy].typ)) {
if (!(mw_tmp = MON_WEP(mtmp)) || !is_axe(mw_tmp))
mtmp->weapon_check = NEED_AXE;
} else if (!(mw_tmp = MON_WEP(mtmp)) || !is_pick(mw_tmp)) {
mtmp->weapon_check = NEED_PICK_AXE;
}
if (mtmp->weapon_check >= NEED_PICK_AXE && mon_wield_item(mtmp))
return TRUE;
}
return FALSE;
}
/* Return values:
* 0: did not move, but can still attack and do other stuff.
* 1: moved, possibly can attack.
@@ -732,10 +764,10 @@ register int after;
long info[9];
long flag;
int omx = mtmp->mx, omy = mtmp->my;
struct obj *mw_tmp;
if (mtmp->mtrapped) {
int i = mintrap(mtmp);
if (i >= 2) {
newsym(mtmp->mx, mtmp->my);
return 2;
@@ -1108,22 +1140,9 @@ not_special:
if (mmoved == 1 && (u.ux != nix || u.uy != niy) && itsstuck(mtmp))
return 3;
if (mmoved == 1 && can_tunnel && needspick(ptr)
&& ((IS_ROCK(levl[nix][niy].typ) && may_dig(nix, niy))
|| closed_door(nix, niy))) {
if (closed_door(nix, niy)) {
if (!(mw_tmp = MON_WEP(mtmp)) || !is_pick(mw_tmp)
|| !is_axe(mw_tmp))
mtmp->weapon_check = NEED_PICK_OR_AXE;
} else if (IS_TREE(levl[nix][niy].typ)) {
if (!(mw_tmp = MON_WEP(mtmp)) || !is_axe(mw_tmp))
mtmp->weapon_check = NEED_AXE;
} else if (!(mw_tmp = MON_WEP(mtmp)) || !is_pick(mw_tmp)) {
mtmp->weapon_check = NEED_PICK_AXE;
}
if (mtmp->weapon_check >= NEED_PICK_AXE && mon_wield_item(mtmp))
return 3;
}
if (mmoved == 1 && m_digweapon_check(mtmp, nix,niy))
return 3;
/* If ALLOW_U is set, either it's trying to attack you, or it
* thinks it is. In either case, attack this spot in preference to
* all others.
+33 -30
View File
@@ -1,5 +1,5 @@
/* NetHack 3.6 mplayer.c $NHDT-Date: 1432512774 2015/05/25 00:12:54 $ $NHDT-Branch: master $:$NHDT-Revision: 1.19 $ */
/* Copyright (c) Izchak Miller, 1992. */
/* NetHack 3.6 mplayer.c $NHDT-Date: 1458949461 2016/03/25 23:44:21 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.21 $ */
/* Copyright (c) Izchak Miller, 1992. */
/* NetHack may be freely redistributed. See license for details. */
#include "hack.h"
@@ -134,23 +134,13 @@ register boolean special;
special = FALSE;
if ((mtmp = makemon(ptr, x, y, NO_MM_FLAGS)) != 0) {
short weapon = rn2(2) ? LONG_SWORD : rnd_class(SPEAR, BULLWHIP);
short armor =
rnd_class(GRAY_DRAGON_SCALE_MAIL, YELLOW_DRAGON_SCALE_MAIL);
short cloak = !rn2(8)
? STRANGE_OBJECT
: rnd_class(OILSKIN_CLOAK, CLOAK_OF_DISPLACEMENT);
short helm = !rn2(8) ? STRANGE_OBJECT : rnd_class(ELVEN_LEATHER_HELM,
HELM_OF_TELEPATHY);
short shield = !rn2(8)
? STRANGE_OBJECT
: rnd_class(ELVEN_SHIELD, SHIELD_OF_REFLECTION);
short weapon, armor, cloak, helm, shield;
int quan;
struct obj *otmp;
mtmp->m_lev = (special ? rn1(16, 15) : rnd(16));
mtmp->mhp = mtmp->mhpmax =
d((int) mtmp->m_lev, 10) + (special ? (30 + rnd(30)) : 30);
mtmp->mhp = mtmp->mhpmax = d((int) mtmp->m_lev, 10)
+ (special ? (30 + rnd(30)) : 30);
if (special) {
get_mplname(mtmp, nam);
mtmp = christen_monst(mtmp, nam);
@@ -160,6 +150,16 @@ register boolean special;
mtmp->mpeaceful = 0;
set_malign(mtmp); /* peaceful may have changed again */
/* default equipment; much of it will be overridden below */
weapon = !rn2(2) ? LONG_SWORD : rnd_class(SPEAR, BULLWHIP);
armor = rnd_class(GRAY_DRAGON_SCALE_MAIL, YELLOW_DRAGON_SCALE_MAIL);
cloak = !rn2(8) ? STRANGE_OBJECT
: rnd_class(OILSKIN_CLOAK, CLOAK_OF_DISPLACEMENT);
helm = !rn2(8) ? STRANGE_OBJECT
: rnd_class(ELVEN_LEATHER_HELM, HELM_OF_TELEPATHY);
shield = !rn2(8) ? STRANGE_OBJECT
: rnd_class(ELVEN_SHIELD, SHIELD_OF_REFLECTION);
switch (monsndx(ptr)) {
case PM_ARCHEOLOGIST:
if (rn2(2))
@@ -285,18 +285,18 @@ register boolean special;
mk_mplayer_armor(mtmp, helm);
mk_mplayer_armor(mtmp, shield);
if (rn2(8))
mk_mplayer_armor(
mtmp, rnd_class(LEATHER_GLOVES, GAUNTLETS_OF_DEXTERITY));
mk_mplayer_armor(mtmp, rnd_class(LEATHER_GLOVES,
GAUNTLETS_OF_DEXTERITY));
if (rn2(8))
mk_mplayer_armor(mtmp,
rnd_class(LOW_BOOTS, LEVITATION_BOOTS));
mk_mplayer_armor(mtmp, rnd_class(LOW_BOOTS,
LEVITATION_BOOTS));
m_dowear(mtmp, TRUE);
quan = rn2(3) ? rn2(3) : rn2(16);
while (quan--)
(void) mongets(mtmp, rnd_class(DILITHIUM_CRYSTAL, JADE));
/* To get the gold "right" would mean a player can double his */
/* gold supply by killing one mplayer. Not good. */
/* To get the gold "right" would mean a player can double his
gold supply by killing one mplayer. Not good. */
mkmonmoney(mtmp, rn2(1000));
quan = rn2(10);
while (quan--)
@@ -331,12 +331,13 @@ boolean special;
int pm, x, y;
struct monst fakemon;
fakemon = zeromonst;
while (num) {
int tryct = 0;
/* roll for character class */
pm = PM_ARCHEOLOGIST + rn2(PM_WIZARD - PM_ARCHEOLOGIST + 1);
fakemon.data = &mons[pm];
set_mon_data(&fakemon, &mons[pm], -1);
/* roll for an available location */
do {
@@ -357,15 +358,17 @@ void
mplayer_talk(mtmp)
register struct monst *mtmp;
{
static const char *same_class_msg[3] =
{
"I can't win, and neither will you!", "You don't deserve to win!",
"Mine should be the honor, not yours!",
static const char
*same_class_msg[3] = {
"I can't win, and neither will you!",
"You don't deserve to win!",
"Mine should be the honor, not yours!",
},
*other_class_msg[3] = {
"The low-life wants to talk, eh?", "Fight, scum!",
"Here is what I have to say!",
};
*other_class_msg[3] = {
"The low-life wants to talk, eh?",
"Fight, scum!",
"Here is what I have to say!",
};
if (mtmp->mpeaceful)
return; /* will drop to humanoid talk */
+1 -1
View File
@@ -225,7 +225,7 @@ boolean verbose; /* give message(s) even when you can't see what happened */
/* don't blame hero for unknown rolling boulder trap */
if (!context.mon_moving
&& (otmp->otyp != BOULDER || range >= 0 || otmp->otrapped))
xkilled(mtmp, 0);
xkilled(mtmp, XKILL_NOMSG);
else
mondied(mtmp);
}
+67 -40
View File
@@ -23,6 +23,7 @@ STATIC_DCL int FDECL(precheck, (struct monst *, struct obj *));
STATIC_DCL void FDECL(mzapmsg, (struct monst *, struct obj *, BOOLEAN_P));
STATIC_DCL void FDECL(mreadmsg, (struct monst *, struct obj *));
STATIC_DCL void FDECL(mquaffmsg, (struct monst *, struct obj *));
STATIC_DCL boolean FDECL(m_use_healing, (struct monst *));
STATIC_PTR int FDECL(mbhitm, (struct monst *, struct obj *));
STATIC_DCL void FDECL(mbhit, (struct monst *, int,
int FDECL((*), (MONST_P, OBJ_P)),
@@ -139,7 +140,7 @@ struct obj *obj;
int dam = d(obj->spe + 2, 6);
/* 3.6.1: no Deaf filter; 'if' message doesn't warrant it, 'else'
message doesn't need it since Your_hear() has one of its own */
message doesn't need it since You_hear() has one of its own */
if (vis) {
pline("%s zaps %s, which suddenly explodes!", Monnam(mon),
an(xname(obj)));
@@ -153,11 +154,11 @@ struct obj *obj;
? "nearby" : "in the distance");
}
m_useup(mon, obj);
if (mon->mhp <= dam) {
mon->mhp -= dam;
if (mon->mhp <= 0) {
monkilled(mon, "", AD_RBRE);
return 1;
} else
mon->mhp -= dam;
}
m.has_defense = m.has_offense = m.has_misc = 0;
/* Only one needed to be set to 0 but the others are harmless */
}
@@ -269,6 +270,29 @@ struct obj *otmp;
* that if you polymorph into one you teleport at will.
*/
STATIC_OVL boolean
m_use_healing(mtmp)
struct monst *mtmp;
{
struct obj *obj = 0;
if ((obj = m_carrying(mtmp, POT_FULL_HEALING)) != 0) {
m.defensive = obj;
m.has_defense = MUSE_POT_FULL_HEALING;
return TRUE;
}
if ((obj = m_carrying(mtmp, POT_EXTRA_HEALING)) != 0) {
m.defensive = obj;
m.has_defense = MUSE_POT_EXTRA_HEALING;
return TRUE;
}
if ((obj = m_carrying(mtmp, POT_HEALING)) != 0) {
m.defensive = obj;
m.has_defense = MUSE_POT_HEALING;
return TRUE;
}
return FALSE;
}
/* Select a defensive item/action for a monster. Returns TRUE iff one is
found. */
boolean
@@ -339,21 +363,8 @@ struct monst *mtmp;
*/
if (!mtmp->mcansee && !nohands(mtmp->data)
&& mtmp->data != &mons[PM_PESTILENCE]) {
if ((obj = m_carrying(mtmp, POT_FULL_HEALING)) != 0) {
m.defensive = obj;
m.has_defense = MUSE_POT_FULL_HEALING;
if (m_use_healing(mtmp))
return TRUE;
}
if ((obj = m_carrying(mtmp, POT_EXTRA_HEALING)) != 0) {
m.defensive = obj;
m.has_defense = MUSE_POT_EXTRA_HEALING;
return TRUE;
}
if ((obj = m_carrying(mtmp, POT_HEALING)) != 0) {
m.defensive = obj;
m.has_defense = MUSE_POT_HEALING;
return TRUE;
}
}
fraction = u.ulevel < 10 ? 5 : u.ulevel < 14 ? 4 : 3;
@@ -363,21 +374,8 @@ struct monst *mtmp;
if (mtmp->mpeaceful) {
if (!nohands(mtmp->data)) {
if ((obj = m_carrying(mtmp, POT_FULL_HEALING)) != 0) {
m.defensive = obj;
m.has_defense = MUSE_POT_FULL_HEALING;
if (m_use_healing(mtmp))
return TRUE;
}
if ((obj = m_carrying(mtmp, POT_EXTRA_HEALING)) != 0) {
m.defensive = obj;
m.has_defense = MUSE_POT_EXTRA_HEALING;
return TRUE;
}
if ((obj = m_carrying(mtmp, POT_HEALING)) != 0) {
m.defensive = obj;
m.has_defense = MUSE_POT_HEALING;
return TRUE;
}
}
return FALSE;
}
@@ -1500,10 +1498,13 @@ struct monst *mtmp;
else
losehp(num, "scroll of fire", KILLED_BY_AN);
for (mtmp2 = fmon; mtmp2; mtmp2 = mtmp2->nmon) {
if (DEADMONSTER(mtmp2)) continue;
if (mtmp == mtmp2) continue;
if (DEADMONSTER(mtmp2))
continue;
if (mtmp == mtmp2)
continue;
if (dist2(mtmp2->mx, mtmp2->my, mtmp->mx, mtmp->my) < 3) {
if (resists_fire(mtmp2)) continue;
if (resists_fire(mtmp2))
continue;
mtmp2->mhp -= num;
if (resists_cold(mtmp2))
mtmp2->mhp -= 3 * num;
@@ -2201,7 +2202,7 @@ mon_consume_unstone(mon, obj, by_you, stoning)
struct monst *mon;
struct obj *obj;
boolean by_you;
boolean stoning;
boolean stoning; /* True: stop petrification, False: cure stun && confusion */
{
boolean vis = canseemon(mon), tinned = obj->otyp == TIN,
food = obj->otyp == CORPSE || tinned,
@@ -2240,7 +2241,10 @@ boolean stoning;
if (mon->mhp <= 0) {
pline("%s dies!", Monnam(mon));
if (by_you)
xkilled(mon, 0);
/* hero gets credit (experience) and blame (possible loss
of alignment and/or luck and/or telepathy depending on
mon) for the kill but does not break pacifism conduct */
xkilled(mon, XKILL_NOMSG | XKILL_NOCONDUCT);
else
mondead(mon);
return;
@@ -2404,7 +2408,7 @@ struct trap *trap;
boolean by_you; /* true: if mon kills itself, hero gets credit/blame */
{ /* [by_you not honored if 'mon' triggers fire trap]. */
struct obj *odummyp;
int otyp = obj->otyp, dmg;
int otyp = obj->otyp, dmg = 0;
boolean vis = canseemon(mon), res = TRUE;
if (vis)
@@ -2443,7 +2447,7 @@ boolean by_you; /* true: if mon kills itself, hero gets credit/blame */
if (!rn2(3))
mon->mspec_used = rn1(10, 5);
/* -21 => monster's fire breath; 1 => # of damage dice */
(void) zhitm(mon, by_you ? 21 : -21, 1, &odummyp);
dmg = zhitm(mon, by_you ? 21 : -21, 1, &odummyp);
} else if (otyp == SCR_FIRE) {
mreadmsg(mon, obj);
if (mon->mconf) {
@@ -2462,14 +2466,37 @@ boolean by_you; /* true: if mon kills itself, hero gets credit/blame */
explode(mon->mx, mon->my, -11, dmg, SCROLL_CLASS,
/* by_you: override -11 for mon but not others */
by_you ? -EXPL_FIERY : EXPL_FIERY);
dmg = 0; /* damage has been applied by explode() */
}
} else { /* wand/horn of fire w/ positive charge count */
mzapmsg(mon, obj, TRUE);
obj->spe--;
/* -1 => monster's wand of fire; 2 => # of damage dice */
(void) zhitm(mon, by_you ? 1 : -1, 2, &odummyp);
dmg = zhitm(mon, by_you ? 1 : -1, 2, &odummyp);
}
if (dmg) {
/* zhitm() applies damage but doesn't kill creature off;
for fire breath, dmg is going to be 0 (fire breathers are
immune to fire damage) but for wand of fire or fire horn,
'mon' could have taken damage so might die */
if (mon->mhp <= 0) {
if (by_you) {
/* mon killed self but hero gets credit and blame (except
for pacifist conduct); xkilled()'s message would say
"You killed/destroyed <mon>" so give our own message */
if (vis)
pline("%s is %s by the fire!", Monnam(mon),
nonliving(mon->data) ? "destroyed" : "killed");
xkilled(mon, XKILL_NOMSG | XKILL_NOCONDUCT);
} else
monkilled(mon, "fire", AD_FIRE);
} else {
/* non-fatal damage occurred */
if (vis)
pline("%s is burned%s", Monnam(mon), exclam(dmg));
}
}
if (vis) {
if (res && mon->mhp > 0)
pline("%s slime is burned away!", s_suffix(Monnam(mon)));
+14 -14
View File
@@ -352,25 +352,25 @@ int force;
/* Falling is okay for falling down
within a pit from jostling too */
mselftouch(mtmp, "Falling, ", TRUE);
if (mtmp->mhp > 0)
if ((mtmp->mhp -=
rnd(m_already_trapped ? 4 : 6)) <= 0) {
if (!cansee(x, y))
if (mtmp->mhp > 0) {
mtmp->mhp -= rnd(m_already_trapped ? 4 : 6);
if (mtmp->mhp <= 0) {
if (!cansee(x, y)) {
pline("It is destroyed!");
else {
} else {
You("destroy %s!",
mtmp->mtame
? x_monnam(
mtmp, ARTICLE_THE,
"poor",
(has_mname(mtmp))
? SUPPRESS_SADDLE
: 0,
FALSE)
: mon_nam(mtmp));
? x_monnam(mtmp, ARTICLE_THE,
"poor",
has_mname(mtmp)
? SUPPRESS_SADDLE
: 0,
FALSE)
: mon_nam(mtmp));
}
xkilled(mtmp, 0);
xkilled(mtmp, XKILL_NOMSG);
}
}
}
} else if (x == u.ux && y == u.uy) {
if (Levitation || Flying
+125 -59
View File
@@ -1,4 +1,4 @@
/* NetHack 3.6 objnam.c $NHDT-Date: 1455672990 2016/02/17 01:36:30 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.165 $ */
/* NetHack 3.6 objnam.c $NHDT-Date: 1462067746 2016/05/01 01:55:46 $ $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. */
@@ -11,13 +11,14 @@
STATIC_DCL char *FDECL(strprepend, (char *, const char *));
STATIC_DCL short FDECL(rnd_otyp_by_wpnskill, (SCHAR_P));
STATIC_DCL short FDECL(rnd_otyp_by_namedesc, (char *, CHAR_P));
STATIC_DCL boolean FDECL(wishymatch, (const char *, const char *, BOOLEAN_P));
STATIC_DCL char *NDECL(nextobuf);
STATIC_DCL void FDECL(releaseobuf, (char *));
STATIC_DCL char *FDECL(minimal_xname, (struct obj *));
STATIC_DCL void FDECL(add_erosion_words, (struct obj *, char *));
STATIC_DCL boolean
FDECL(singplur_lookup, (char *, char *, BOOLEAN_P, const char *const *));
STATIC_DCL boolean FDECL(singplur_lookup, (char *, char *, BOOLEAN_P,
const char *const *));
STATIC_DCL char *FDECL(singplur_compound, (char *));
STATIC_DCL char *FDECL(xname_flags, (struct obj *, unsigned));
@@ -406,9 +407,9 @@ unsigned cxn_flags; /* bitmask of CXN_xxx values */
}
break;
}
if (Is_pudding(obj)) {
if (obj->globby) {
Sprintf(buf, "%s%s",
(obj->owt < 100)
(obj->owt <= 100)
? "small "
: (obj->owt > 500)
? "very large "
@@ -730,13 +731,38 @@ char *prefix;
: "");
}
/* used to prevent rust on items where rust makes no difference */
boolean
erosion_matters(obj)
struct obj *obj;
{
switch (obj->oclass) {
case TOOL_CLASS:
/* it's possible for a rusty weptool to be polymorphed into some
non-weptool iron tool, in which case the rust implicitly goes
away, but it's also possible for it to be polymorphed into a
non-iron tool, in which case rust also implicitly goes away,
so there's no particular reason to try to handle the first
instance differently [this comment belongs in poly_obj()...] */
return is_weptool(obj) ? TRUE : FALSE;
case WEAPON_CLASS:
case ARMOR_CLASS:
case BALL_CLASS:
case CHAIN_CLASS:
return TRUE;
default:
break;
}
return FALSE;
}
static char *
doname_base(obj, with_price)
register struct obj *obj;
boolean with_price;
{
boolean ispoisoned = FALSE;
boolean known, cknown, bknown, lknown;
boolean known, dknown, cknown, bknown, lknown;
int omndx = obj->corpsenm;
char prefix[PREFIX];
char tmpbuf[PREFIX + 1]; /* for when we have to add something at
@@ -745,9 +771,10 @@ boolean with_price;
register char *bp = xname(obj);
if (iflags.override_ID) {
known = cknown = bknown = lknown = TRUE;
known = dknown = cknown = bknown = lknown = TRUE;
} else {
known = obj->known;
dknown = obj->dknown;
cknown = obj->cknown;
bknown = obj->bknown;
lknown = obj->lknown;
@@ -765,7 +792,10 @@ boolean with_price;
}
if (obj->quan != 1L) {
Sprintf(prefix, "%ld ", obj->quan);
if (dknown)
Sprintf(prefix, "%ld ", obj->quan);
else
Strcpy(prefix, "some ");
} else if (obj->otyp == CORPSE) {
/* skip article prefix for corpses [else corpse_xname()
would have to be taught how to strip it off again] */
@@ -853,31 +883,27 @@ boolean with_price;
plur(itemcount));
}
switch (obj->oclass) {
switch (is_weptool(obj) ? WEAPON_CLASS : obj->oclass) {
case AMULET_CLASS:
if (obj->owornmask & W_AMUL)
Strcat(bp, " (being worn)");
break;
case ARMOR_CLASS:
if (obj->owornmask & W_ARMOR)
Strcat(bp, (obj == uskin) ? " (embedded in your skin)"
: " (being worn)");
/*FALLTHRU*/
case WEAPON_CLASS:
if (ispoisoned)
Strcat(prefix, "poisoned ");
plus:
add_erosion_words(obj, prefix);
if (known) {
Strcat(prefix, sitoa(obj->spe));
Strcat(prefix, " ");
}
break;
case ARMOR_CLASS:
if (obj->owornmask & W_ARMOR)
Strcat(bp, (obj == uskin) ? " (embedded in your skin)"
: " (being worn)");
goto plus;
case TOOL_CLASS:
/* weptools already get this done when we go to the +n code */
if (!is_weptool(obj))
add_erosion_words(obj, prefix);
if (obj->owornmask & (W_TOOL /* blindfold */ | W_SADDLE)) {
if (obj->owornmask & (W_TOOL | W_SADDLE)) { /* blindfold */
Strcat(bp, " (being worn)");
break;
}
@@ -885,8 +911,6 @@ boolean with_price;
Strcat(bp, " (in use)");
break;
}
if (is_weptool(obj))
goto plus;
if (obj->otyp == CANDELABRUM_OF_INVOCATION) {
if (!obj->spe)
Strcpy(tmpbuf, "no");
@@ -908,7 +932,6 @@ boolean with_price;
goto charges;
break;
case WAND_CLASS:
add_erosion_words(obj, prefix);
charges:
if (known)
Sprintf(eos(bp), " (%d:%d)", (int) obj->recharged, obj->spe);
@@ -918,7 +941,6 @@ boolean with_price;
Strcat(bp, " (lit)");
break;
case RING_CLASS:
add_erosion_words(obj, prefix);
ring:
if (obj->owornmask & W_RINGR)
Strcat(bp, " (on right ");
@@ -2408,7 +2430,7 @@ struct alt_spellings {
{ (const char *) 0, 0 },
};
short
STATIC_OVL short
rnd_otyp_by_wpnskill(skill)
schar skill;
{
@@ -2431,6 +2453,48 @@ schar skill;
return otyp;
}
STATIC_OVL short
rnd_otyp_by_namedesc(name, oclass)
char *name;
char oclass;
{
int i, n = 0;
short validobjs[NUM_OBJECTS];
register const char *zn;
long maxprob = 0;
if (!name)
return STRANGE_OBJECT;
memset((genericptr_t) validobjs, 0, sizeof(validobjs));
for (i = oclass ? bases[(int)oclass] : STRANGE_OBJECT + 1;
i < NUM_OBJECTS && (!oclass || objects[i].oc_class == oclass);
++i) {
/* don't match extra descriptions (w/o real name) */
if ((zn = OBJ_NAME(objects[i])) == 0)
continue;
if (wishymatch(name, zn, TRUE)
|| ((zn = OBJ_DESCR(objects[i])) != 0
&& wishymatch(name, zn, FALSE))
|| ((zn = objects[i].oc_uname) != 0
&& wishymatch(name, zn, FALSE))) {
validobjs[n++] = (short) i;
maxprob += (objects[i].oc_prob + 1);
}
}
if (n > 0 && maxprob) {
long prob = rn2(maxprob);
i = 0;
while (i < n - 1 && (prob -= (objects[validobjs[i]].oc_prob + 1)) > 0)
i++;
return validobjs[i];
}
return STRANGE_OBJECT;
}
/*
* Return something wished for. Specifying a null pointer for
* the user request string results in a random object. Otherwise,
@@ -2452,7 +2516,7 @@ struct obj *no_wish;
int halfeaten, mntmp, contents;
int islit, unlabeled, ishistoric, isdiluted, trapped;
int tmp, tinv, tvariety;
int wetness;
int wetness, gsize = 0;
struct fruit *f;
int ftype = context.current_fruit;
char fruitbuf[BUFSZ];
@@ -2471,7 +2535,7 @@ struct obj *no_wish;
* automatically sticks 'candied' in front of such names.
*/
char oclass;
char *un, *dn, *actualn;
char *un, *dn, *actualn, *origbp = bp;
const char *name = 0;
cnt = spe = spesgn = typ = very = rechrg = blessed = uncursed = iscursed =
@@ -2590,6 +2654,15 @@ struct obj *no_wish;
isdiluted = 1;
} else if (!strncmpi(bp, "empty ", l = 6)) {
contents = EMPTY;
} else if (!strncmpi(bp, "small ", l = 6)) { /* glob sizes */
gsize = 1;
} else if (!strncmpi(bp, "medium ", l = 7)) {
/* xname() doesn't display "medium" but without this
there'd be no way to ask for the intermediate size */
gsize = 2;
} else if (!strncmpi(bp, "large ", l = 6)) {
/* "very large " had "very " peeled off on previous iteration */
gsize = (very != 1) ? 3 : 4;
} else
break;
bp += l;
@@ -2720,6 +2793,7 @@ struct obj *no_wish;
if ((p = strstri(bp, "glob of ")) != 0
|| (p = strstri(bp, "globs of ")) != 0) {
int globoffset = (*(p + 4) == 's') ? 9 : 8;
if ((mntmp = name_to_mon(p + globoffset)) >= PM_GRAY_OOZE
&& mntmp <= PM_BLACK_PUDDING) {
mntmp = NON_PM; /* lie to ourselves */
@@ -2991,30 +3065,14 @@ srch:
}
}
}
i = oclass ? bases[(int) oclass] : 1;
while (i < NUM_OBJECTS && (!oclass || objects[i].oc_class == oclass)) {
register const char *zn;
if (actualn && (zn = OBJ_NAME(objects[i])) != 0
&& wishymatch(actualn, zn, TRUE)) {
typ = i;
goto typfnd;
}
if (dn && (zn = OBJ_DESCR(objects[i])) != 0
&& wishymatch(dn, zn, FALSE)) {
/* don't match extra descriptions (w/o real name) */
if (!OBJ_NAME(objects[i]))
return (struct obj *) 0;
typ = i;
goto typfnd;
}
if (un && (zn = objects[i].oc_uname) != 0
&& wishymatch(un, zn, FALSE)) {
typ = i;
goto typfnd;
}
i++;
}
if (((typ = rnd_otyp_by_namedesc(actualn, oclass)) != STRANGE_OBJECT)
|| ((typ = rnd_otyp_by_namedesc(dn, oclass)) != STRANGE_OBJECT)
|| ((typ = rnd_otyp_by_namedesc(un, oclass)) != STRANGE_OBJECT)
|| ((typ = rnd_otyp_by_namedesc(origbp, oclass)) != STRANGE_OBJECT))
goto typfnd;
typ = 0;
if (actualn) {
struct Jitem *j = Japanese_items;
@@ -3401,6 +3459,11 @@ typfnd:
set_corpsenm(otmp, mntmp);
}
break;
case EGG:
mntmp = can_be_hatched(mntmp);
/* this also sets hatch timer if appropriate */
set_corpsenm(otmp, mntmp);
break;
case FIGURINE:
if (!(mons[mntmp].geno & G_UNIQ) && !is_human(&mons[mntmp])
#ifdef MAIL
@@ -3409,11 +3472,6 @@ typfnd:
)
otmp->corpsenm = mntmp;
break;
case EGG:
mntmp = can_be_hatched(mntmp);
/* this also sets hatch timer if appropriate */
set_corpsenm(otmp, mntmp);
break;
case STATUE:
otmp->corpsenm = mntmp;
if (Has_contents(otmp) && verysmall(&mons[mntmp]))
@@ -3443,15 +3501,19 @@ typfnd:
curse(otmp);
}
/* set eroded */
if (is_damageable(otmp) || otmp->otyp == CRYSKNIFE) {
/* set eroded and erodeproof */
if (erosion_matters(otmp)) {
if (eroded && (is_flammable(otmp) || is_rustprone(otmp)))
otmp->oeroded = eroded;
if (eroded2 && (is_corrodeable(otmp) || is_rottable(otmp)))
otmp->oeroded2 = eroded2;
/* set erodeproof */
if (erodeproof && !eroded && !eroded2)
/*
* 3.6.1: earlier versions included `&& !eroded && !eroded2' here,
* but damageproof combined with damaged is feasible (eroded
* armor modified by confused reading of cursed destroy armor)
* so don't prevent player from wishing for such a combination.
*/
if (erodeproof && (is_damageable(otmp) || otmp->otyp == CRYSKNIFE))
otmp->oerodeproof = (Luck >= 0 || wizard);
}
@@ -3534,6 +3596,10 @@ typfnd:
otmp->owt = weight(otmp);
if (very && otmp->otyp == HEAVY_IRON_BALL)
otmp->owt += IRON_BALL_W_INCR;
else if (gsize > 1 && otmp->globby)
/* 0: unspecified => small; 1: small => keep default owt of 20;
2: medium => 120; 3: large => 320; 4: very large => 520 */
otmp->owt += 100 + (gsize - 2) * 200;
return otmp;
}
+296 -237
View File
@@ -1,4 +1,4 @@
/* NetHack 3.6 options.c $NHDT-Date: 1455357588 2016/02/13 09:59:48 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.264 $ */
/* NetHack 3.6 options.c $NHDT-Date: 1461102048 2016/04/19 21:40:48 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.268 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
@@ -519,6 +519,8 @@ STATIC_DCL int NDECL(msgtype_count);
STATIC_DCL boolean FDECL(add_menu_coloring_parsed, (char *, int, int));
STATIC_DCL void FDECL(free_one_menu_coloring, (int));
STATIC_DCL int NDECL(count_menucolors);
STATIC_DCL boolean FDECL(parse_role_opts, (BOOLEAN_P, const char *,
char *, char **));
STATIC_DCL void FDECL(oc_to_str, (char *, char *));
STATIC_DCL void FDECL(doset_add_menu, (winid, const char *, int));
@@ -585,10 +587,13 @@ boolean val_allowed;
if (!p || (q && q < p))
p = q;
while (p && p > user_string && isspace((uchar) * (p - 1)))
p--;
if (p)
if (p) {
/* 'user_string' hasn't necessarily been through mungspaces()
so might have tabs or consecutive spaces */
while (p > user_string && isspace((uchar) *(p - 1)))
p--;
len = (int) (p - user_string);
}
}
return (boolean) (len >= min_length
@@ -858,8 +863,8 @@ char *tp;
} else if (*cp == '^') { /* expand control-character syntax */
cval = (*++cp & 0x1f);
++cp;
/* remaining cases are all for backslash and we know cp[1] is not
* \0 */
/* remaining cases are all for backslash; we know cp[1] is not \0 */
} else if (index(dec, cp[1])) {
++cp; /* move past backslash to first digit */
do {
@@ -1010,17 +1015,20 @@ change_inv_order(op)
char *op;
{
int oc_sym, num;
char *sp, buf[BUFSZ];
char *sp, buf[QBUFSZ];
num = 0;
/* !!!! probably unnecessary with gold as normal inventory */
if (!index(op, GOLD_SYM))
buf[num++] = COIN_CLASS;
for (sp = op; *sp; sp++) {
oc_sym = def_char_to_objclass(*sp);
/* reject bad or duplicate entries */
if (oc_sym == MAXOCLASSES || oc_sym == RANDOM_CLASS
|| oc_sym == ILLOBJ_CLASS || !index(flags.inv_order, oc_sym)
|| index(sp + 1, *sp))
if (oc_sym == MAXOCLASSES /* not an object class char */
/* VENOM_CLASS, RANDOM_CLASS, and ILLOBJ_CLASS are excluded
because they aren't in def_inv_order[] so don't make it
into flags.inv_order, hence always fail this index() test */
|| !index(flags.inv_order, oc_sym) || index(sp + 1, *sp))
return 0;
/* retain good ones */
buf[num++] = (char) oc_sym;
@@ -1029,10 +1037,9 @@ char *op;
/* fill in any omitted classes, using previous ordering */
for (sp = flags.inv_order; *sp; sp++)
if (!index(buf, *sp)) {
buf[num++] = *sp;
buf[num] = '\0'; /* explicitly terminate for next index() */
}
if (!index(buf, *sp))
(void) strkitten(&buf[num++], *sp);
buf[MAXOCLASSES - 1] = '\0';
Strcpy(flags.inv_order, buf);
return 1;
@@ -1721,14 +1728,48 @@ count_menucolors()
return count;
}
STATIC_OVL boolean
parse_role_opts(negated, fullname, opts, opp)
boolean negated;
const char *fullname;
char *opts;
char **opp;
{
char *op = *opp;
if (negated) {
bad_negation(fullname, FALSE);
} else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) {
boolean val_negated = FALSE;
while ((*op == '!') || !strncmpi(op, "no", 2)) {
if (*op == '!')
op++;
else
op += 2;
val_negated = !val_negated;
}
if (val_negated) {
if (!setrolefilter(op))
badoption(opts);
} else {
if (duplicate_opt_detection(opts, 1))
complain_about_duplicate(opts, 1);
*opp = op;
return TRUE;
}
}
return FALSE;
}
void
parseoptions(opts, tinitial, tfrom_file)
register char *opts;
boolean tinitial, tfrom_file;
{
register char *op;
char *op;
unsigned num;
boolean negated, val_negated, duplicate;
boolean negated, duplicate;
int i;
const char *fullname;
@@ -1803,26 +1844,9 @@ boolean tinitial, tfrom_file;
/* align:string */
fullname = "align";
if (match_optname(opts, fullname, sizeof("align") - 1, TRUE)) {
if (negated) {
bad_negation(fullname, FALSE);
} else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) {
val_negated = FALSE;
while ((*op == '!') || !strncmpi(op, "no", 2)) {
if (*op == '!')
op++;
else
op += 2;
val_negated = !val_negated;
}
if (val_negated) {
if (!setrolefilter(op))
badoption(opts);
} else {
if (duplicate_opt_detection(opts, 1))
complain_about_duplicate(opts, 1);
if ((flags.initalign = str2align(op)) == ROLE_NONE)
badoption(opts);
}
if (parse_role_opts(negated, fullname, opts, &op)) {
if ((flags.initalign = str2align(op)) == ROLE_NONE)
badoption(opts);
}
return;
}
@@ -1831,28 +1855,11 @@ boolean tinitial, tfrom_file;
fullname = "role";
if (match_optname(opts, fullname, 4, TRUE)
|| match_optname(opts, (fullname = "character"), 4, TRUE)) {
if (negated) {
bad_negation(fullname, FALSE);
} else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) {
val_negated = FALSE;
while ((*op == '!') || !strncmpi(op, "no", 2)) {
if (*op == '!')
op++;
else
op += 2;
val_negated = !val_negated;
}
if (val_negated) {
if (!setrolefilter(op))
badoption(opts);
} else {
if (duplicate_opt_detection(opts, 1))
complain_about_duplicate(opts, 1);
if ((flags.initrole = str2role(op)) == ROLE_NONE)
badoption(opts);
else /* Backwards compatibility */
nmcpy(pl_character, op, PL_NSIZ);
}
if (parse_role_opts(negated, fullname, opts, &op)) {
if ((flags.initrole = str2role(op)) == ROLE_NONE)
badoption(opts);
else /* Backwards compatibility */
nmcpy(pl_character, op, PL_NSIZ);
}
return;
}
@@ -1860,28 +1867,11 @@ boolean tinitial, tfrom_file;
/* race:string */
fullname = "race";
if (match_optname(opts, fullname, 4, TRUE)) {
if (negated) {
bad_negation(fullname, FALSE);
} else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) {
val_negated = FALSE;
while ((*op == '!') || !strncmpi(op, "no", 2)) {
if (*op == '!')
op++;
else
op += 2;
val_negated = !val_negated;
}
if (val_negated) {
if (!setrolefilter(op))
badoption(opts);
} else {
if (duplicate_opt_detection(opts, 1))
complain_about_duplicate(opts, 1);
if ((flags.initrace = str2race(op)) == ROLE_NONE)
badoption(opts);
else /* Backwards compatibility */
pl_race = *op;
}
if (parse_role_opts(negated, fullname, opts, &op)) {
if ((flags.initrace = str2race(op)) == ROLE_NONE)
badoption(opts);
else /* Backwards compatibility */
pl_race = *op;
}
return;
}
@@ -1889,28 +1879,11 @@ boolean tinitial, tfrom_file;
/* gender:string */
fullname = "gender";
if (match_optname(opts, fullname, 4, TRUE)) {
if (negated) {
bad_negation(fullname, FALSE);
} else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) {
val_negated = FALSE;
while ((*op == '!') || !strncmpi(op, "no", 2)) {
if (*op == '!')
op++;
else
op += 2;
val_negated = !val_negated;
}
if (val_negated) {
if (!setrolefilter(op))
badoption(opts);
} else {
if (duplicate_opt_detection(opts, 1))
complain_about_duplicate(opts, 1);
if ((flags.initgend = str2gend(op)) == ROLE_NONE)
badoption(opts);
else
flags.female = flags.initgend;
}
if (parse_role_opts(negated, fullname, opts, &op)) {
if ((flags.initgend = str2gend(op)) == ROLE_NONE)
badoption(opts);
else
flags.female = flags.initgend;
}
return;
}
@@ -2140,7 +2113,7 @@ boolean tinitial, tfrom_file;
bad_negation(fullname, TRUE);
return;
}
tmp = tolower(*op);
tmp = lowc(*op);
}
switch (tmp) {
case 's': /* single message history cycle (default if negated) */
@@ -2544,7 +2517,9 @@ boolean tinitial, tfrom_file;
} else if ((op = string_for_opt(opts, TRUE)) != 0) {
char *pp, buf[BUFSZ];
op = mungspaces(strcpy(buf, op));
strncpy(buf, op, sizeof buf - 1);
buf[sizeof buf - 1] = '\0';
op = mungspaces(buf);
for (;;) {
/* We're looking to parse
"paranoid_confirm:whichone wheretwo whothree"
@@ -2604,30 +2579,24 @@ boolean tinitial, tfrom_file;
bad_negation(fullname, FALSE);
return;
} else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) {
switch (tolower(*op)) {
/* Unencumbered */
case 'u':
switch (lowc(*op)) {
case 'u': /* Unencumbered */
flags.pickup_burden = UNENCUMBERED;
break;
/* Burdened (slight encumbrance) */
case 'b':
case 'b': /* Burdened (slight encumbrance) */
flags.pickup_burden = SLT_ENCUMBER;
break;
/* streSsed (moderate encumbrance) */
case 's':
case 's': /* streSsed (moderate encumbrance) */
flags.pickup_burden = MOD_ENCUMBER;
break;
/* straiNed (heavy encumbrance) */
case 'n':
case 'n': /* straiNed (heavy encumbrance) */
flags.pickup_burden = HVY_ENCUMBER;
break;
/* OverTaxed (extreme encumbrance) */
case 'o':
case 'o': /* OverTaxed (extreme encumbrance) */
case 't':
flags.pickup_burden = EXT_ENCUMBER;
break;
/* overLoaded */
case 'l':
case 'l': /* overLoaded */
flags.pickup_burden = OVERLOADED;
break;
default:
@@ -2813,7 +2782,9 @@ boolean tinitial, tfrom_file;
while (*op && num < sizeof flags.end_disclose - 1) {
static char valid_settings[] = {
DISCLOSE_PROMPT_DEFAULT_YES, DISCLOSE_PROMPT_DEFAULT_NO,
DISCLOSE_YES_WITHOUT_PROMPT, DISCLOSE_NO_WITHOUT_PROMPT, '\0'
DISCLOSE_PROMPT_DEFAULT_SPECIAL,
DISCLOSE_YES_WITHOUT_PROMPT, DISCLOSE_NO_WITHOUT_PROMPT,
DISCLOSE_SPECIAL_WITHOUT_PROMPT, '\0'
};
register char c, *dop;
@@ -2830,6 +2801,12 @@ boolean tinitial, tfrom_file;
continue;
}
if (prefix_val != -1) {
if (*dop != 'v') {
if (prefix_val == DISCLOSE_PROMPT_DEFAULT_SPECIAL)
prefix_val = DISCLOSE_PROMPT_DEFAULT_YES;
if (prefix_val == DISCLOSE_SPECIAL_WITHOUT_PROMPT)
prefix_val = DISCLOSE_YES_WITHOUT_PROMPT;
}
flags.end_disclose[idx] = prefix_val;
prefix_val = -1;
} else
@@ -2901,11 +2878,13 @@ boolean tinitial, tfrom_file;
if (match_optname(opts, fullname, 4, TRUE)) {
op = string_for_env_opt(fullname, opts, FALSE);
if (op) {
switch (tolower(*op)) {
case 'n':
case 'l':
case 'f':
flags.sortloot = tolower(*op);
char c = lowc(*op);
switch (c) {
case 'n': /* none */
case 'l': /* loot (pickup) */
case 'f': /* full (pickup + invent) */
flags.sortloot = c;
break;
default:
badoption(opts);
@@ -3096,8 +3075,7 @@ boolean tinitial, tfrom_file;
if ((op = string_for_opt(opts, FALSE)) != 0) {
if (iflags.wc_tile_file)
free(iflags.wc_tile_file);
iflags.wc_tile_file = (char *) alloc(strlen(op) + 1);
Strcpy(iflags.wc_tile_file, op);
iflags.wc_tile_file = dupstr(op);
}
return;
}
@@ -3184,22 +3162,26 @@ boolean tinitial, tfrom_file;
return; /* string_for_opt gave feedback */
tmp = negated ? 'n' : 'f';
} else {
tmp = tolower(*op);
tmp = lowc(*op);
}
switch (tmp) {
case 'n': /* none */
case 't': /* traditional */
case 't': /* traditional: prompt for class(es) by symbol,
prompt for each item within class(es) one at a time */
flags.menu_style = MENU_TRADITIONAL;
break;
case 'c': /* combo: trad.class sel+menu */
case 'c': /* combination: prompt for class(es) by symbol,
choose items within selected class(es) by menu */
flags.menu_style = MENU_COMBINATION;
break;
case 'p': /* partial: no class menu */
flags.menu_style = MENU_PARTIAL;
break;
case 'f': /* full: class menu + menu */
case 'f': /* full: choose class(es) by first menu,
choose items within selected class(es) by second menu */
flags.menu_style = MENU_FULL;
break;
case 'p': /* partial: skip class filtering,
choose items among all classes by menu */
flags.menu_style = MENU_PARTIAL;
break;
default:
badoption(opts);
}
@@ -3868,7 +3850,7 @@ int numtotal;
{
winid tmpwin;
anything any;
int i, pick_cnt, pick_idx, opt_idx;
int i, pick_cnt, opt_idx;
menu_item *pick_list = (menu_item *) 0;
static const struct action {
char letr;
@@ -3886,6 +3868,7 @@ int numtotal;
any = zeroany;
for (i = 0; i < SIZE(action_titles); i++) {
char tmpbuf[BUFSZ];
any.a_int++;
/* omit list and remove if there aren't any yet */
if (!numtotal && (i == 1 || i == 2))
@@ -3893,24 +3876,17 @@ int numtotal;
Sprintf(tmpbuf, action_titles[i].desc,
(i == 1) ? makeplural(optname) : optname);
add_menu(tmpwin, NO_GLYPH, &any, action_titles[i].letr, 0, ATR_NONE,
tmpbuf,
#if 0 /* this ought to work but doesn't... */
(action_titles[i].letr == 'x') ? MENU_SELECTED :
#endif
MENU_UNSELECTED);
tmpbuf, (i == 3) ? MENU_SELECTED : MENU_UNSELECTED);
}
end_menu(tmpwin, "Do what?");
if ((pick_cnt = select_menu(tmpwin, PICK_ONE, &pick_list)) > 0) {
for (pick_idx = 0; pick_idx < pick_cnt; ++pick_idx) {
opt_idx = pick_list[pick_idx].item.a_int - 1;
}
opt_idx = pick_list[0].item.a_int - 1;
if (pick_cnt > 1 && opt_idx == 3)
opt_idx = pick_list[1].item.a_int - 1;
free((genericptr_t) pick_list);
pick_list = (menu_item *) 0;
}
destroy_nhwindow(tmpwin);
if (pick_cnt < 1)
} else
opt_idx = 3; /* none selected, exit menu */
destroy_nhwindow(tmpwin);
return opt_idx;
}
@@ -3924,7 +3900,7 @@ boolean setinitial, setfromfile;
{
winid tmpwin;
anything any;
int i;
int i, n;
char buf[BUFSZ];
/* Special handling of menustyle, pickup_burden, pickup_types,
@@ -4014,6 +3990,7 @@ boolean setinitial, setfromfile;
};
int disc_cat[NUM_DISCLOSURE_OPTIONS];
int pick_cnt, pick_idx, opt_idx;
char c;
menu_item *disclosure_pick = (menu_item *) 0;
tmpwin = create_nhwindow(NHW_MENU);
@@ -4041,6 +4018,7 @@ boolean setinitial, setfromfile;
for (i = 0; i < NUM_DISCLOSURE_OPTIONS; i++) {
if (disc_cat[i]) {
c = flags.end_disclose[i];
Sprintf(buf, "Disclosure options for %s:",
disclosure_names[i]);
tmpwin = create_nhwindow(NHW_MENU);
@@ -4048,24 +4026,41 @@ boolean setinitial, setfromfile;
any = zeroany;
/* 'y','n',and '+' work as alternate selectors; '-' doesn't */
any.a_char = DISCLOSE_NO_WITHOUT_PROMPT;
add_menu(tmpwin, NO_GLYPH, &any, 'a', any.a_char, ATR_NONE,
add_menu(tmpwin, NO_GLYPH, &any, 0, any.a_char, ATR_NONE,
"Never disclose, without prompting",
MENU_UNSELECTED);
(c == any.a_char) ? MENU_SELECTED : MENU_UNSELECTED);
any.a_char = DISCLOSE_YES_WITHOUT_PROMPT;
add_menu(tmpwin, NO_GLYPH, &any, 'b', any.a_char, ATR_NONE,
add_menu(tmpwin, NO_GLYPH, &any, 0, any.a_char, ATR_NONE,
"Always disclose, without prompting",
MENU_UNSELECTED);
(c == any.a_char) ? MENU_SELECTED : MENU_UNSELECTED);
if (*disclosure_names[i] == 'v') {
any.a_char = DISCLOSE_SPECIAL_WITHOUT_PROMPT; /* '#' */
add_menu(tmpwin, NO_GLYPH, &any, 0, any.a_char, ATR_NONE,
"Always disclose, pick sort order from menu",
(c == any.a_char) ? MENU_SELECTED
: MENU_UNSELECTED);
}
any.a_char = DISCLOSE_PROMPT_DEFAULT_NO;
add_menu(tmpwin, NO_GLYPH, &any, 'c', any.a_char, ATR_NONE,
add_menu(tmpwin, NO_GLYPH, &any, 0, any.a_char, ATR_NONE,
"Prompt, with default answer of \"No\"",
MENU_UNSELECTED);
(c == any.a_char) ? MENU_SELECTED : MENU_UNSELECTED);
any.a_char = DISCLOSE_PROMPT_DEFAULT_YES;
add_menu(tmpwin, NO_GLYPH, &any, 'd', any.a_char, ATR_NONE,
add_menu(tmpwin, NO_GLYPH, &any, 0, any.a_char, ATR_NONE,
"Prompt, with default answer of \"Yes\"",
MENU_UNSELECTED);
(c == any.a_char) ? MENU_SELECTED : MENU_UNSELECTED);
if (*disclosure_names[i] == 'v') {
any.a_char = DISCLOSE_PROMPT_DEFAULT_SPECIAL; /* '?' */
add_menu(tmpwin, NO_GLYPH, &any, 0, any.a_char, ATR_NONE,
"Prompt, with default answer of \"Ask\" to request sort menu",
(c == any.a_char) ? MENU_SELECTED
: MENU_UNSELECTED);
}
end_menu(tmpwin, buf);
if (select_menu(tmpwin, PICK_ONE, &disclosure_pick) > 0) {
flags.end_disclose[i] = disclosure_pick->item.a_char;
n = select_menu(tmpwin, PICK_ONE, &disclosure_pick);
if (n > 0) {
flags.end_disclose[i] = disclosure_pick[0].item.a_char;
if (n > 1 && flags.end_disclose[i] == c)
flags.end_disclose[i] = disclosure_pick[1].item.a_char;
free((genericptr_t) disclosure_pick);
}
destroy_nhwindow(tmpwin);
@@ -4183,11 +4178,17 @@ boolean setinitial, setfromfile;
sortl_name = sortltype[i];
any.a_char = *sortl_name;
add_menu(tmpwin, NO_GLYPH, &any, *sortl_name, 0, ATR_NONE,
sortl_name, MENU_UNSELECTED);
sortl_name, (flags.sortloot == *sortl_name)
? MENU_SELECTED : MENU_UNSELECTED);
}
end_menu(tmpwin, "Select loot sorting type:");
if (select_menu(tmpwin, PICK_ONE, &sortl_pick) > 0) {
flags.sortloot = sortl_pick->item.a_char;
n = select_menu(tmpwin, PICK_ONE, &sortl_pick);
if (n > 0) {
char c = sortl_pick[0].item.a_char;
if (n > 1 && c == flags.sortloot)
c = sortl_pick[1].item.a_char;
flags.sortloot = c;
free((genericptr_t) sortl_pick);
}
destroy_nhwindow(tmpwin);
@@ -4286,23 +4287,24 @@ boolean setinitial, setfromfile;
msgtypes_again:
nmt = msgtype_count();
opt_idx = handle_add_list_remove("message type", nmt);
if (opt_idx == 3) {
; /* done--fall through to function exit */
if (opt_idx == 3) { /* done */
return TRUE;
} else if (opt_idx == 0) { /* add new */
getlin("What new message pattern?", mtbuf);
if (*mtbuf == '\033' || !*mtbuf)
goto msgtypes_again;
mttyp = query_msgtype();
if (mttyp == -1)
goto msgtypes_again;
if (!msgtype_add(mttyp, mtbuf)) {
if (*mtbuf == '\033')
return TRUE;
if (*mtbuf
&& (mttyp = query_msgtype()) != -1
&& !msgtype_add(mttyp, mtbuf)) {
pline("Error adding the message type.");
wait_synch();
goto msgtypes_again;
}
} else { /* list or remove */
goto msgtypes_again;
} else { /* list (1) or remove (2) */
int pick_idx, pick_cnt;
int mt_idx;
unsigned ln;
const char *mtype;
menu_item *pick_list = (menu_item *) 0;
struct plinemsg_type *tmp = plinemsg_types;
@@ -4311,10 +4313,14 @@ boolean setinitial, setfromfile;
any = zeroany;
mt_idx = 0;
while (tmp) {
const char *mtype = msgtype2name(tmp->msgtype);
mtype = msgtype2name(tmp->msgtype);
any.a_int = ++mt_idx;
Sprintf(mtbuf, "%-5s \"%s\"", mtype, tmp->pattern);
Sprintf(mtbuf, "%-5s \"", mtype);
ln = sizeof mtbuf - strlen(mtbuf) - sizeof "\"";
if (strlen(tmp->pattern) > ln)
Strcat(strncat(mtbuf, tmp->pattern, ln - 3), "...\"");
else
Strcat(mtbuf, "\"");
add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, mtbuf,
MENU_UNSELECTED);
tmp = tmp->next;
@@ -4342,26 +4348,25 @@ boolean setinitial, setfromfile;
menucolors_again:
nmc = count_menucolors();
opt_idx = handle_add_list_remove("menucolor", nmc);
if (opt_idx == 3) {
; /* done--fall through to function exit */
if (opt_idx == 3) { /* done */
return TRUE;
} else if (opt_idx == 0) { /* add new */
getlin("What new menucolor pattern?", mcbuf);
if (*mcbuf == '\033' || !*mcbuf)
goto menucolors_again;
mcclr = query_color();
if (mcclr == -1)
goto menucolors_again;
mcattr = query_attr(NULL);
if (mcattr == -1)
goto menucolors_again;
if (!add_menu_coloring_parsed(mcbuf, mcclr, mcattr)) {
if (*mcbuf == '\033')
return TRUE;
if (*mcbuf
&& (mcclr = query_color()) != -1
&& (mcattr = query_attr((char *) 0)) != -1
&& !add_menu_coloring_parsed(mcbuf, mcclr, mcattr)) {
pline("Error adding the menu color.");
wait_synch();
goto menucolors_again;
}
} else { /* list or remove */
goto menucolors_again;
} else { /* list (1) or remove (2) */
int pick_idx, pick_cnt;
int mc_idx;
unsigned ln;
const char *sattr, *sclr;
menu_item *pick_list = (menu_item *) 0;
struct menucoloring *tmp = menu_colorings;
@@ -4370,13 +4375,22 @@ boolean setinitial, setfromfile;
any = zeroany;
mc_idx = 0;
while (tmp) {
const char *sattr = attr2attrname(tmp->attr);
const char *sclr = clr2colorname(tmp->color);
any.a_int = (++mc_idx);
Sprintf(mcbuf, "\"%s\"=%s%s%s", tmp->origstr, sclr,
sattr = attr2attrname(tmp->attr);
sclr = clr2colorname(tmp->color);
any.a_int = ++mc_idx;
/* construct suffix */
Sprintf(buf, "\"\"=%s%s%s", sclr,
(tmp->attr != ATR_NONE) ? " & " : "",
(tmp->attr != ATR_NONE) ? sattr : "");
/* now main string */
ln = sizeof buf - strlen(buf) - 1; /* length available */
Strcpy(mcbuf, "\"");
if (strlen(tmp->origstr) > ln)
Strcat(strncat(mcbuf, tmp->origstr, ln - 3), "...");
else
Strcat(mcbuf, tmp->origstr);
/* combine main string and suffix */
Strcat(mcbuf, &buf[1]); /* skip buf[]'s initial quote */
add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, mcbuf,
MENU_UNSELECTED);
tmp = tmp->next;
@@ -4405,26 +4419,24 @@ boolean setinitial, setfromfile;
ape_again:
totalapes = count_ape_maps(&numapes[AP_LEAVE], &numapes[AP_GRAB]);
opt_idx = handle_add_list_remove("autopickup exception", totalapes);
if (opt_idx == 3) {
; /* done--fall through to function exit */
if (opt_idx == 3) { /* done */
return TRUE;
} else if (opt_idx == 0) { /* add new */
getlin("What new autopickup exception pattern?", &apebuf[1]);
mungspaces(&apebuf[1]); /* regularize whitespace */
if (apebuf[1] == '\033') {
; /* fall through to function exit */
} else {
if (apebuf[1]) {
apebuf[0] = '\"';
/* guarantee room for \" prefix and \"\0 suffix;
-2 is good enough for apebuf[] but -3 makes
sure the whole thing fits within normal BUFSZ */
apebuf[sizeof apebuf - 3] = '\0';
Strcat(apebuf, "\"");
add_autopickup_exception(apebuf);
}
goto ape_again;
if (apebuf[1] == '\033')
return TRUE;
if (apebuf[1]) {
apebuf[0] = '\"';
/* guarantee room for \" prefix and \"\0 suffix;
-2 is good enough for apebuf[] but -3 makes
sure the whole thing fits within normal BUFSZ */
apebuf[sizeof apebuf - 3] = '\0';
Strcat(apebuf, "\"");
add_autopickup_exception(apebuf);
}
} else { /* list or remove */
goto ape_again;
} else { /* list (1) or remove (2) */
int pick_idx, pick_cnt;
menu_item *pick_list = (menu_item *) 0;
@@ -4440,6 +4452,7 @@ boolean setinitial, setfromfile;
MENU_UNSELECTED);
for (i = 0; i < numapes[pass] && ape; i++) {
any.a_void = (opt_idx == 1) ? 0 : ape;
/* length of pattern plus quotes is less than BUFSZ */
Sprintf(apebuf, "\"%s\"", ape->pattern);
add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, apebuf,
MENU_UNSELECTED);
@@ -5025,39 +5038,54 @@ int
add_autopickup_exception(mapping)
const char *mapping;
{
static const char
APE_regex_error[] = "regex error in AUTOPICKUP_EXCEPTION",
APE_syntax_error[] = "syntax error in AUTOPICKUP_EXCEPTION";
struct autopickup_exception *ape, **apehead;
char text[256], *text2;
char text[256], end;
int n;
boolean grab = FALSE;
if (sscanf(mapping, "\"%255[^\"]\"", text) == 1) {
text2 = &text[0];
if (*text2 == '<') { /* force autopickup */
grab = TRUE;
++text2;
} else if (*text2 == '>') { /* default - Do not pickup */
grab = FALSE;
++text2;
}
apehead = (grab) ? &iflags.autopickup_exceptions[AP_GRAB]
: &iflags.autopickup_exceptions[AP_LEAVE];
ape = (struct autopickup_exception *) alloc(
sizeof (struct autopickup_exception));
ape->regex = regex_init();
if (!regex_compile(text2, ape->regex)) {
raw_print("regex error in AUTOPICKUP_EXCEPTION");
regex_free(ape->regex);
free((genericptr_t) ape);
return 0;
}
ape->pattern = (char *) alloc(strlen(text2) + 1);
strcpy(ape->pattern, text2);
ape->grab = grab;
ape->next = *apehead;
*apehead = ape;
/* scan length limit used to be 255, but smaller size allows the
quoted value to fit within BUFSZ, simplifying formatting elsewhere;
this used to ignore the possibility of trailing junk but now checks
for it, accepting whitespace but rejecting anything else unless it
starts with '#" for a comment */
end = '\0';
if ((n = sscanf(mapping, "\"<%253[^\"]\" %c", text, &end)) == 1
|| (n == 2 && end == '#')) {
grab = TRUE;
} else if ((n = sscanf(mapping, "\">%253[^\"]\" %c", text, &end)) == 1
|| (n = sscanf(mapping, "\"%253[^\"]\" %c", text, &end)) == 1
|| (n == 2 && end == '#')) {
grab = FALSE;
} else {
raw_print("syntax error in AUTOPICKUP_EXCEPTION");
if (!iflags.window_inited)
raw_print(APE_syntax_error); /* from options file */
else
pline("%s", APE_syntax_error); /* via 'O' command */
return 0;
}
ape = (struct autopickup_exception *) alloc(sizeof *ape);
ape->regex = regex_init();
if (!regex_compile(text, ape->regex)) {
if (!iflags.window_inited)
raw_print(APE_regex_error);
else
pline("%s", APE_regex_error);
regex_free(ape->regex);
free((genericptr_t) ape);
return 0;
}
apehead = (grab) ? &iflags.autopickup_exceptions[AP_GRAB]
: &iflags.autopickup_exceptions[AP_LEAVE];
ape->pattern = dupstr(text);
ape->grab = grab;
ape->next = *apehead;
*apehead = ape;
return 1;
}
@@ -5222,11 +5250,41 @@ char *buf;
int
sym_val(strval)
char *strval;
const char *strval;
{
char buf[QBUFSZ];
buf[0] = '\0';
escapes(strval, buf);
if (!strval[0] || !strval[1]) { /* empty, or single character */
/* if single char is space or tab, leave buf[0]=='\0' */
if (!isspace((uchar) strval[0]))
buf[0] = strval[0];
} else if (strval[0] == '\'') { /* single quote */
/* simple matching single quote; we know strval[1] isn't '\0' */
if (strval[2] == '\'' && !strval[3]) {
/* accepts '\' as backslash and ''' as single quote */
buf[0] = strval[1];
/* if backslash, handle single or double quote or second backslash */
} else if (strval[1] == '\\' && strval[2] && strval[3] == '\''
&& index("'\"\\", strval[2]) && !strval[4]) {
buf[0] = strval[2];
/* not simple quote or basic backslash;
strip closing quote and let escapes() deal with it */
} else {
char *p, tmp[QBUFSZ];
(void) strncpy(tmp, strval + 1, sizeof tmp - 1);
tmp[sizeof tmp - 1] = '\0';
if ((p = rindex(tmp, '\'')) != 0) {
*p = '\0';
escapes(tmp, buf);
} /* else buf[0] stays '\0' */
}
} else /* not lone char nor single quote */
escapes(strval, buf);
return (int) *buf;
}
@@ -5438,6 +5496,7 @@ struct fruit *replace_fruit;
return rnd(127);
f = newfruit();
(void) memset((genericptr_t)f, 0, sizeof(struct fruit));
copynchars(f->fname, *altname ? altname : str, PL_FSIZ - 1);
f->fid = ++highest_fruit_id;
/* we used to go out of our way to add it at the end of the list,
+123 -77
View File
@@ -1,4 +1,4 @@
/* NetHack 3.6 pager.c $NHDT-Date: 1455674291 2016/02/17 01:58:11 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.93 $ */
/* NetHack 3.6 pager.c $NHDT-Date: 1463790247 2016/05/21 00:24:07 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.98 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
@@ -165,9 +165,13 @@ struct obj **obj_p;
if (mtmp && has_mcorpsenm(mtmp)) /* mimic as corpse/statue */
otmp->corpsenm = MCORPSENM(mtmp);
}
/* if located at adjacent spot, mark it as having been seen up close */
if (otmp && distu(x, y) <= 2 && !Blind && !Hallucination)
otmp->dknown = 1;
/* if located at adjacent spot, mark it as having been seen up close
(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
/* 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 */
*obj_p = otmp;
return fakeobj; /* when True, caller needs to dealloc *obj_p */
@@ -323,7 +327,8 @@ char *buf, *monbuf;
buf[0] = monbuf[0] = '\0';
glyph = glyph_at(x, y);
if (u.ux == x && u.uy == y && canspotself()) {
if (u.ux == x && u.uy == y && canspotself()
&& (!iflags.terrainmode || (iflags.terrainmode & TER_MON) != 0)) {
/* fill in buf[] */
(void) self_lookat(buf);
@@ -348,19 +353,19 @@ char *buf, *monbuf;
how |= 4;
if (how)
Sprintf(
eos(buf), " [seen: %s%s%s%s%s]",
(how & 1) ? "infravision" : "",
/* add comma if telep and infrav */
((how & 3) > 2) ? ", " : "", (how & 2) ? "telepathy" : "",
/* add comma if detect and (infrav or telep or both) */
((how & 7) > 4) ? ", " : "",
(how & 4) ? "monster detection" : "");
Sprintf(eos(buf), " [seen: %s%s%s%s%s]",
(how & 1) ? "infravision" : "",
/* add comma if telep and infrav */
((how & 3) > 2) ? ", " : "",
(how & 2) ? "telepathy" : "",
/* add comma if detect and (infrav or telep or both) */
((how & 7) > 4) ? ", " : "",
(how & 4) ? "monster detection" : "");
}
} else if (u.uswallow) {
/* all locations when swallowed other than the hero are the monster */
Sprintf(buf, "interior of %s",
Blind ? "a monster" : a_monnam(u.ustuck));
/* when swallowed, we're only called for spots adjacent to hero,
and blindness doesn't prevent hero from feeling what holds him */
Sprintf(buf, "interior of %s", a_monnam(u.ustuck));
pm = u.ustuck->data;
} else if (glyph_is_monster(glyph)) {
bhitpos.x = x;
@@ -377,6 +382,7 @@ char *buf, *monbuf;
Strcpy(buf, defsyms[trap_to_defsym(tnum)].explanation);
} else if (glyph_is_warning(glyph)) {
int warnindx = glyph_to_warning(glyph);
Strcpy(buf, def_warnsyms[warnindx].explanation);
} else if (!glyph_is_cmap(glyph)) {
Strcpy(buf, "unexplored area");
@@ -411,6 +417,11 @@ char *buf, *monbuf;
if (!levl[x][y].seenv) {
Strcpy(buf, "unexplored");
break;
} else if (Underwater && !Is_waterlevel(&u.uz)) {
/* "unknown" == previously mapped but not visible when
submerged; better terminology appreciated... */
Strcpy(buf, (distu(x, y) <= 2) ? "land" : "unknown");
break;
} else if (levl[x][y].typ == STONE || levl[x][y].typ == SCORR) {
Strcpy(buf, "stone");
break;
@@ -515,10 +526,9 @@ boolean user_typed_name, without_asking;
/*
* If the object is named, then the name is the alternate description;
* otherwise, the result of makesingular() applied to the name is.
* This
* isn't strictly optimal, but named objects of interest to the user
* will usually be found under their name, rather than under their
* object type, so looking for a singular form is pointless.
* This isn't strictly optimal, but named objects of interest to the
* user will usually be found under their name, rather than under
* their object type, so looking for a singular form is pointless.
*/
if (!alt)
alt = makesingular(dbase_str);
@@ -554,10 +564,11 @@ boolean user_typed_name, without_asking;
if (!(ep = index(buf, '\n')))
goto bad_data_file;
(void) strip_newline((ep > buf) ? ep - 1 : ep);
/* if we match a key that begins with "~", skip this entry */
/* if we match a key that begins with "~", skip
this entry */
chk_skip = (*buf == '~') ? 1 : 0;
if ((pass == 0 && pmatch(&buf[chk_skip], dbase_str)) ||
(pass == 1 && alt && pmatch(&buf[chk_skip], alt))) {
if ((pass == 0 && pmatch(&buf[chk_skip], dbase_str))
|| (pass == 1 && alt && pmatch(&buf[chk_skip], alt))) {
if (chk_skip) {
skipping_entry = TRUE;
continue;
@@ -581,7 +592,7 @@ boolean user_typed_name, without_asking;
if (sscanf(buf, "%ld,%d\n", &entry_offset, &entry_count) < 2) {
bad_data_file:
impossible("'data' file in wrong format or corrupted");
/* window will exist if we came here from below via 'goto' */
/* window will exist if came here from below via 'goto' */
if (datawin != WIN_ERR)
destroy_nhwindow(datawin);
(void) dlb_fclose(fp);
@@ -593,6 +604,7 @@ boolean user_typed_name, without_asking;
unsigned maxt = strlen("More info about \"\"?");
char *entrytext = pass ? alt : dbase_str;
char question[BUFSZ];
if (strlen(entrytext) < BUFSZ - maxt) {
Strcpy(question, "More info about \"");
Strcat(question, entrytext);
@@ -600,11 +612,11 @@ boolean user_typed_name, without_asking;
}
if (yn(question) == 'y')
yes_to_moreinfo = TRUE;
}
}
if (user_typed_name || without_asking || yes_to_moreinfo) {
if (dlb_fseek(fp,
(long) txt_offset + entry_offset, SEEK_SET) < 0) {
if (dlb_fseek(fp, (long) txt_offset + entry_offset,
SEEK_SET) < 0) {
pline("? Seek error on 'data' file!");
(void) dlb_fclose(fp);
return;
@@ -636,16 +648,15 @@ int sym;
char *out_str;
const char **firstmatch;
{
boolean need_to_look = FALSE;
int glyph = NO_GLYPH;
static const char mon_interior[] = "the interior of a monster",
unreconnoitered[] = "unreconnoitered";
static char look_buf[BUFSZ];
char prefix[BUFSZ];
int found = 0; /* count of matching syms found */
int i, alt_i;
int skipped_venom = 0;
boolean hit_trap;
int i, alt_i, glyph = NO_GLYPH,
skipped_venom = 0, found = 0; /* count of matching syms found */
boolean hit_trap, need_to_look = FALSE,
submerged = (Underwater && !Is_waterlevel(&u.uz));
const char *x_str;
static const char *mon_interior = "the interior of a monster";
if (looked) {
int oc;
@@ -665,59 +676,91 @@ const char **firstmatch;
*/
/*
* Special case: if identifying from the screen, and we're swallowed,
* and looking at something other than our own symbol, then just say
* "the interior of a monster".
* Handle restricted vision range (limited to adjacent spots when
* swallowed or underwater) cases first.
*
* 3.6.0 listed anywhere on map, other than self, as "interior
* of a monster" when swallowed, and non-adjacent water or
* non-water anywhere as "dark part of a room" when underwater.
* "unreconnoitered" is an attempt to convey "even if you knew
* what was there earlier, you don't know what is there in the
* current circumstance".
*
* (Note: 'self' will always be visible when swallowed so we don't
* need special swallow handling for <ux,uy>.
* Another note: for '#terrain' without monsters, u.uswallow and
* submerged will always both be False and skip this code.)
*/
if (u.uswallow && looked
&& (is_swallow_sym(sym) || (int) showsyms[S_stone] == sym)) {
x_str = 0;
if (looked && (u.uswallow || submerged) && distu(cc.x, cc.y) > 2) {
x_str = unreconnoitered;
need_to_look = FALSE;
} else if (looked && u.uswallow && is_swallow_sym(sym)) {
x_str = mon_interior;
need_to_look = TRUE; /* for specific monster type */
}
if (x_str) {
/* we know 'found' is zero here, but guard against some other
special case being inserted ahead of us someday */
if (!found) {
Sprintf(out_str, "%s%s", prefix, mon_interior);
*firstmatch = mon_interior;
Sprintf(out_str, "%s%s", prefix, x_str);
*firstmatch = x_str;
found++;
} else {
found += append_str(out_str, mon_interior);
found += append_str(out_str, x_str); /* not 'an(x_str)' */
}
need_to_look = TRUE;
goto didlook;
/* for is_swallow_sym(), we want to list the current symbol's
other possibilities (wand for '/', throne for '\\', &c) so
don't jump to the end for the x_str==mon_interior case */
if (x_str == unreconnoitered)
goto didlook;
}
/* Check for monsters */
for (i = 0; i < MAXMCLASSES; i++) {
if (sym == (looked ? showsyms[i + SYM_OFF_M] : def_monsyms[i].sym)
&& def_monsyms[i].explain) {
need_to_look = TRUE;
if (!found) {
Sprintf(out_str, "%s%s", prefix, an(def_monsyms[i].explain));
*firstmatch = def_monsyms[i].explain;
found++;
} else {
found += append_str(out_str, an(def_monsyms[i].explain));
if (!iflags.terrainmode || (iflags.terrainmode & TER_MON) != 0) {
for (i = 0; i < MAXMCLASSES; i++) {
if (sym == (looked ? showsyms[i + SYM_OFF_M] : def_monsyms[i].sym)
&& def_monsyms[i].explain) {
need_to_look = TRUE;
if (!found) {
Sprintf(out_str, "%s%s",
prefix, an(def_monsyms[i].explain));
*firstmatch = def_monsyms[i].explain;
found++;
} else {
found += append_str(out_str, an(def_monsyms[i].explain));
}
}
}
/* handle '@' as a special case if it refers to you and you're
playing a character which isn't normally displayed by that
symbol; firstmatch is assumed to already be set for '@' */
if ((looked ? (sym == showsyms[S_HUMAN + SYM_OFF_M]
&& cc.x == u.ux && cc.y == u.uy)
: (sym == def_monsyms[S_HUMAN].sym && !flags.showrace))
&& !(Race_if(PM_HUMAN) || Race_if(PM_ELF)) && !Upolyd)
found += append_str(out_str, "you"); /* tack on "or you" */
}
/* handle '@' as a special case if it refers to you and you're
playing a character which isn't normally displayed by that
symbol; firstmatch is assumed to already be set for '@' */
if ((looked ? (sym == showsyms[S_HUMAN + SYM_OFF_M]
&& cc.x == u.ux && cc.y == u.uy)
: (sym == def_monsyms[S_HUMAN].sym && !flags.showrace))
&& !(Race_if(PM_HUMAN) || Race_if(PM_ELF)) && !Upolyd)
found += append_str(out_str, "you"); /* tack on "or you" */
/* Now check for objects */
for (i = 1; i < MAXOCLASSES; i++) {
if (sym == (looked ? showsyms[i + SYM_OFF_O] : def_oc_syms[i].sym)) {
need_to_look = TRUE;
if (looked && i == VENOM_CLASS) {
skipped_venom++;
continue;
}
if (!found) {
Sprintf(out_str, "%s%s", prefix, an(def_oc_syms[i].explain));
*firstmatch = def_oc_syms[i].explain;
found++;
} else {
found += append_str(out_str, an(def_oc_syms[i].explain));
if (!iflags.terrainmode || (iflags.terrainmode & TER_OBJ) != 0) {
for (i = 1; i < MAXOCLASSES; i++) {
if (sym == (looked ? showsyms[i + SYM_OFF_O]
: def_oc_syms[i].sym)
|| (looked && i == ROCK_CLASS && glyph_is_statue(glyph))) {
need_to_look = TRUE;
if (looked && i == VENOM_CLASS) {
skipped_venom++;
continue;
}
if (!found) {
Sprintf(out_str, "%s%s",
prefix, an(def_oc_syms[i].explain));
*firstmatch = def_oc_syms[i].explain;
found++;
} else {
found += append_str(out_str, an(def_oc_syms[i].explain));
}
}
}
}
@@ -741,13 +784,15 @@ const char **firstmatch;
/* when sym is the default background character, we process
i == 0 three times: unexplored, stone, dark part of a room */
if (alt_i < 2) {
x_str = !alt_i++ ? "unexplored" : "stone";
x_str = !alt_i++ ? "unexplored" : submerged ? "unknown" : "stone";
i = 0; /* for second iteration, undo loop increment */
/* alt_i is now 1 or 2 */
} else {
if (alt_i++ == 2)
i = 0; /* undo loop increment */
x_str = defsyms[i].explanation;
if (submerged && !strcmp(x_str, defsyms[0].explanation))
x_str = "land"; /* replace "dark part of a room" */
/* alt_i is now 3 or more and no longer of interest */
}
if (sym == (looked ? showsyms[i] : defsyms[i].sym) && *x_str) {
@@ -757,6 +802,7 @@ const char **firstmatch;
int article = strstri(x_str, " of a room") ? 2
: !(alt_i <= 2
|| strcmp(x_str, "air") == 0
|| strcmp(x_str, "land") == 0
|| strcmp(x_str, "water") == 0);
if (!found) {
@@ -770,7 +816,7 @@ const char **firstmatch;
}
*firstmatch = x_str;
found++;
} else if (!u.uswallow && !(hit_trap && is_cmap_trap(i))
} else if (!(hit_trap && is_cmap_trap(i))
&& !(found >= 3 && is_cmap_drawbridge(i))
/* don't mention vibrating square outside of Gehennom
unless this happens to be one (hallucination?) */
+203 -167
View File
@@ -1,4 +1,4 @@
/* NetHack 3.6 pickup.c $NHDT-Date: 1453591408 2016/01/23 23:23:28 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.169 $ */
/* NetHack 3.6 pickup.c $NHDT-Date: 1461919368 2016/04/29 08:42:48 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.177 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
@@ -11,9 +11,9 @@
#define CONTAINED_SYM '>' /* from invent.c */
STATIC_DCL void FDECL(simple_look, (struct obj *, BOOLEAN_P));
STATIC_DCL boolean
FDECL(query_classes, (char *, boolean *, boolean *, const char *,
struct obj *, BOOLEAN_P, int *));
STATIC_DCL boolean FDECL(query_classes, (char *, boolean *, boolean *,
const char *, struct obj *,
BOOLEAN_P, int *));
STATIC_DCL boolean FDECL(fatal_corpse_mistake, (struct obj *, BOOLEAN_P));
STATIC_DCL void FDECL(check_here, (BOOLEAN_P));
STATIC_DCL boolean FDECL(n_or_more, (struct obj *));
@@ -21,6 +21,7 @@ STATIC_DCL boolean FDECL(all_but_uchain, (struct obj *));
#if 0 /* not used */
STATIC_DCL boolean FDECL(allow_cat_no_uchain, (struct obj *));
#endif
STATIC_DCL boolean FDECL(autopick_testobj, (struct obj *));
STATIC_DCL int FDECL(autopick, (struct obj *, int, menu_item **));
STATIC_DCL int FDECL(count_categories, (struct obj *, int));
STATIC_DCL long FDECL(carry_count, (struct obj *, struct obj *, long,
@@ -33,21 +34,21 @@ STATIC_PTR int FDECL(out_container, (struct obj *));
STATIC_DCL void FDECL(removed_from_icebox, (struct obj *));
STATIC_DCL long FDECL(mbag_item_gone, (int, struct obj *));
STATIC_DCL void FDECL(observe_quantum_cat, (struct obj *));
STATIC_DCL void NDECL(explain_container_prompt);
STATIC_DCL void FDECL(explain_container_prompt, (BOOLEAN_P));
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, 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));
STATIC_DCL int FDECL(do_loot_cont, (struct obj **));
STATIC_DCL int FDECL(do_loot_cont, (struct obj **, int, int));
STATIC_DCL void FDECL(tipcontainer, (struct obj *));
/* define for query_objlist() and autopickup() */
#define FOLLOW(curr, flags) \
(((flags) &BY_NEXTHERE) ? (curr)->nexthere : (curr)->nobj)
(((flags) & BY_NEXTHERE) ? (curr)->nexthere : (curr)->nobj)
/*
* How much the weight of the given container will change when the given
@@ -62,10 +63,11 @@ STATIC_DCL void FDECL(tipcontainer, (struct obj *));
/* if you can figure this out, give yourself a hearty pat on the back... */
#define GOLD_CAPACITY(w, n) (((w) * -100L) - ((n) + 50L) - 1L)
/* A variable set in use_container(), to be used by the callback routines */
/* in_container() and out_container() from askchain() and use_container(). */
/* Also used by menu_loot() and container_gone(). */
/* A variable set in use_container(), to be used by the callback routines
in_container() and out_container() from askchain() and use_container().
Also used by menu_loot() and container_gone(). */
static NEARDATA struct obj *current_container;
static NEARDATA boolean abort_looting;
#define Icebox (current_container->otyp == ICE_BOX)
static const char
@@ -220,9 +222,7 @@ int *menu_on_demand;
oclasses[oclassct] = '\0';
} else {
if (!where)
where =
!strcmp(action, "pick up")
? "here"
where = !strcmp(action, "pick up") ? "here"
: !strcmp(action, "take out") ? "inside" : "";
if (*where)
There("are no %c's %s.", sym, where);
@@ -383,6 +383,7 @@ struct obj *obj;
if (Role_if(PM_PRIEST))
obj->bknown = TRUE;
/*
* There are three types of filters possible and the first and
* third can have more than one entry:
@@ -399,6 +400,7 @@ struct obj *obj;
* in accepting all scrolls and potions regardless of bless/curse
* state plus all blessed non-scroll, non-potion objects.)
*/
/* if class is expected but obj's class is not in the list, reject */
if (class_filter && !index(valid_menu_classes, obj->oclass))
return FALSE;
@@ -463,7 +465,7 @@ int what; /* should be a long */
int i, n, res, count, n_tried = 0, n_picked = 0;
menu_item *pick_list = (menu_item *) 0;
boolean autopickup = what > 0;
struct obj *objchain;
struct obj **objchain_p;
int traverse_how;
/* we might have arrived here while fainted or sleeping, via
@@ -480,7 +482,8 @@ int what; /* should be a long */
count = 0;
if (!u.uswallow) {
struct trap *ttmp = t_at(u.ux, u.uy);
struct trap *ttmp;
/* no auto-pick if no-pick move, nothing there, or in a pool */
if (autopickup && (context.nopick || !OBJ_AT(u.ux, u.uy)
|| (is_pool(u.ux, u.uy) && !Underwater)
@@ -488,11 +491,11 @@ int what; /* should be a long */
read_engr_at(u.ux, u.uy);
return 0;
}
/* no pickup if levitating & not on air or water level */
if (!can_reach_floor(TRUE)) {
if ((multi && !context.run) || (autopickup && !flags.pickup)
|| (ttmp && uteetering_at_seen_pit(ttmp)))
|| ((ttmp = t_at(u.ux, u.uy)) != 0
&& uteetering_at_seen_pit(ttmp)))
read_engr_at(u.ux, u.uy);
return 0;
}
@@ -520,10 +523,10 @@ int what; /* should be a long */
add_valid_menu_class(0); /* reset */
if (!u.uswallow) {
objchain = level.objects[u.ux][u.uy];
objchain_p = &level.objects[u.ux][u.uy];
traverse_how = BY_NEXTHERE;
} else {
objchain = u.ustuck->minvent;
objchain_p = &u.ustuck->minvent;
traverse_how = 0; /* nobj */
}
/*
@@ -533,29 +536,29 @@ int what; /* should be a long */
* to make things less confusing.
*/
if (autopickup) {
n = autopick(objchain, traverse_how, &pick_list);
n = autopick(*objchain_p, traverse_how, &pick_list);
goto menu_pickup;
}
if (flags.menu_style != MENU_TRADITIONAL || iflags.menu_requested) {
/* use menus exclusively */
traverse_how |= AUTOSELECT_SINGLE | INVORDER_SORT;
if (count) { /* looking for N of something */
char qbuf[QBUFSZ];
Sprintf(qbuf, "Pick %d of what?", count);
val_for_n_or_more = count; /* set up callback selector */
n = query_objlist(qbuf, objchain, traverse_how | AUTOSELECT_SINGLE
| INVORDER_SORT,
n = query_objlist(qbuf, objchain_p, traverse_how,
&pick_list, PICK_ONE, n_or_more);
/* correct counts, if any given */
for (i = 0; i < n; i++)
pick_list[i].count = count;
} else {
n = query_objlist("Pick up what?", objchain,
traverse_how | AUTOSELECT_SINGLE | INVORDER_SORT
| FEEL_COCKATRICE,
n = query_objlist("Pick up what?", objchain_p,
(traverse_how | FEEL_COCKATRICE),
&pick_list, PICK_ANY, all_but_uchain);
}
menu_pickup:
n_tried = n;
for (n_picked = i = 0; i < n; i++) {
@@ -581,13 +584,12 @@ int what; /* should be a long */
selective = FALSE; /* ask for each item */
/* check for more than one object */
for (obj = objchain; obj;
obj = (traverse_how == BY_NEXTHERE) ? obj->nexthere : obj->nobj)
for (obj = *objchain_p; obj; obj = FOLLOW(obj, traverse_how))
ct++;
if (ct == 1 && count) {
/* if only one thing, then pick it */
obj = objchain;
obj = *objchain_p;
lcount = min(obj->quan, (long) count);
n_tried++;
if (pickup_object(obj, lcount, FALSE) > 0)
@@ -599,13 +601,14 @@ int what; /* should be a long */
There("are %s objects here.", (ct <= 10) ? "several" : "many");
if (!query_classes(oclasses, &selective, &all_of_a_type,
"pick up", objchain,
traverse_how == BY_NEXTHERE, &via_menu)) {
"pick up", *objchain_p,
(traverse_how & BY_NEXTHERE) ? TRUE : FALSE,
&via_menu)) {
if (!via_menu)
return 0;
n = query_objlist("Pick up what?", objchain,
traverse_how
| (selective ? 0 : INVORDER_SORT),
if (selective)
traverse_how |= INVORDER_SORT;
n = query_objlist("Pick up what?", objchain_p, traverse_how,
&pick_list, PICK_ANY,
(via_menu == -2) ? allow_all
: allow_category);
@@ -613,16 +616,12 @@ int what; /* should be a long */
}
}
for (obj = objchain; obj; obj = obj2) {
if (traverse_how == BY_NEXTHERE)
obj2 = obj->nexthere; /* perhaps obj will be picked up */
else
obj2 = obj->nobj;
lcount = -1L;
for (obj = *objchain_p; obj; obj = obj2) {
obj2 = FOLLOW(obj, traverse_how);
if (!selective && oclasses[0] && !index(oclasses, obj->oclass))
continue;
lcount = -1L;
if (!all_of_a_type) {
char qbuf[BUFSZ];
@@ -647,7 +646,7 @@ int what; /* should be a long */
lcount = (long) yn_number;
if (lcount > obj->quan)
lcount = obj->quan;
/* fall thru */
/*FALLTHRU*/
default: /* 'y' */
break;
}
@@ -700,6 +699,29 @@ boolean grab; /* forced pickup, rather than forced leave behind? */
return FALSE;
}
boolean
autopick_testobj(otmp)
struct obj *otmp;
{
const char *otypes = flags.pickup_types;
/* pick if in pickup_types and not unpaid item in shop */
boolean pickit = ((!*otypes || index(otypes, otmp->oclass))
&& !(otmp->where == OBJ_FLOOR
&& !otmp->no_charge
&& isok(otmp->ox, otmp->oy)
&& costly_spot(otmp->ox, otmp->oy)));
/* check for "always pick up */
if (!pickit)
pickit = is_autopickup_exception(otmp, TRUE);
/* then for "never pick up */
if (pickit)
pickit = !is_autopickup_exception(otmp, FALSE);
/* pickup_thrown overrides pickup_types and exceptions */
if (!pickit)
pickit = (flags.pickup_thrown && otmp->was_thrown);
return pickit;
}
/*
* Pick from the given list using flags.pickup_types. Return the number
* of items picked (not counts). Create an array that returns pointers
@@ -716,42 +738,17 @@ menu_item **pick_list; /* list of objects and counts to pick up */
menu_item *pi; /* pick item */
struct obj *curr;
int n;
boolean pickit;
const char *otypes = flags.pickup_types;
/* first count the number of eligible items */
for (n = 0, curr = olist; curr; curr = FOLLOW(curr, follow)) {
/* pick if in pickup_types and not unpaid item in shop */
pickit = ((!*otypes || index(otypes, curr->oclass))
&& !(curr->where == OBJ_FLOOR
&& !curr->no_charge
&& isok(curr->ox, curr->oy)
&& costly_spot(curr->ox, curr->oy)));
/* check for "always pick up */
if (!pickit)
pickit = is_autopickup_exception(curr, TRUE);
/* then for "never pick up */
if (pickit)
pickit = !is_autopickup_exception(curr, FALSE);
/* pickup_thrown overrides pickup_types and exceptions */
if (!pickit)
pickit = (flags.pickup_thrown && curr->was_thrown);
/* finally, do we count this object? */
if (pickit)
if (autopick_testobj(curr))
++n;
}
if (n) {
*pick_list = pi = (menu_item *) alloc(sizeof (menu_item) * n);
for (n = 0, curr = olist; curr; curr = FOLLOW(curr, follow)) {
pickit = (!*otypes || index(otypes, curr->oclass));
if (!pickit)
pickit = is_autopickup_exception(curr, TRUE);
if (pickit)
pickit = !is_autopickup_exception(curr, FALSE);
if (!pickit)
pickit = (flags.pickup_thrown && curr->was_thrown);
if (pickit) {
if (autopick_testobj(curr)) {
pi[n].item.a_obj = curr;
pi[n].count = curr->quan;
n++;
@@ -778,11 +775,12 @@ menu_item **pick_list; /* list of objects and counts to pick up */
* SIGNAL_NOMENU - Return -1 rather than 0 if nothing passes "allow".
* SIGNAL_ESCAPE - Return -1 rather than 0 if player uses ESC to
* pick nothing.
* FEEL_COCKATRICE - touch corpse.
*/
int
query_objlist(qstr, olist, qflags, pick_list, how, allow)
query_objlist(qstr, olist_p, qflags, pick_list, how, allow)
const char *qstr; /* query string */
struct obj *olist; /* the list to pick from */
struct obj **olist_p; /* the list to pick from */
int qflags; /* options to control the query */
menu_item **pick_list; /* return list of items picked */
int how; /* type of query */
@@ -790,12 +788,12 @@ boolean FDECL((*allow), (OBJ_P)); /* allow function */
{
int i, n, actualn;
winid win;
struct obj *curr, *last, fake_hero_object;
struct obj **oarray;
struct obj *curr, *last, fake_hero_object, *olist = *olist_p;
char *pack;
anything any;
boolean printed_type_name, sorted = (qflags & INVORDER_SORT) != 0,
engulfer = (qflags & INCLUDE_HERO) != 0;
boolean printed_type_name, first,
sorted = (qflags & INVORDER_SORT) != 0,
engulfer = (qflags & INCLUDE_HERO) != 0;
*pick_list = (menu_item *) 0;
if (!olist && !engulfer)
@@ -818,27 +816,26 @@ boolean FDECL((*allow), (OBJ_P)); /* allow function */
return (qflags & SIGNAL_NOMENU) ? -1 : 0;
if (n == 1 && (qflags & AUTOSELECT_SINGLE)) {
*pick_list = (menu_item *) alloc(sizeof(menu_item));
*pick_list = (menu_item *) alloc(sizeof (menu_item));
(*pick_list)->item.a_obj = last;
(*pick_list)->count = last->quan;
return 1;
}
oarray = objarr_init(actualn);
/* Add objects to the array */
i = 0;
for (curr = olist; curr; curr = FOLLOW(curr, qflags)) {
if ((*allow)(curr)) {
objarr_set(curr, i++, oarray, (flags.sortloot == 'f'
|| (flags.sortloot == 'l'
&& !(qflags & USE_INVLET))));
}
if (sorted || flags.sortloot != 'n') {
sortloot(&olist,
(((flags.sortloot == 'f'
|| (flags.sortloot == 'l' && !(qflags & USE_INVLET)))
? SORTLOOT_LOOT
: (qflags & USE_INVLET) ? SORTLOOT_INVLET : 0)
| (flags.sortpack ? SORTLOOT_PACK : 0)),
(qflags & BY_NEXTHERE) ? TRUE : FALSE);
*olist_p = olist;
}
win = create_nhwindow(NHW_MENU);
start_menu(win);
any = zeroany;
/*
* Run through the list and add the objects to the menu. If
* INVORDER_SORT is set, we'll run through the list once for
@@ -846,38 +843,41 @@ boolean FDECL((*allow), (OBJ_P)); /* allow function */
* be called once per object in the list.
*/
pack = flags.inv_order;
first = TRUE;
do {
printed_type_name = FALSE;
for (i = 0; i < actualn; i++) {
curr = oarray[i];
for (curr = olist; curr; curr = FOLLOW(curr, qflags)) {
if (sorted && curr->oclass != *pack)
continue;
if ((qflags & FEEL_COCKATRICE) && curr->otyp == CORPSE
&& will_feel_cockatrice(curr, FALSE)) {
destroy_nhwindow(win); /* stop the menu and revert */
(void) look_here(0, FALSE);
return 0;
}
if ((!sorted || curr->oclass == *pack) && (*allow)(curr)) {
if ((*allow)(curr)) {
/* if sorting, print type name (once only) */
if (sorted && !printed_type_name) {
any = zeroany;
add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings,
let_to_name(*pack, FALSE,
(how != PICK_NONE)
&& iflags.menu_head_objsym),
((how != PICK_NONE)
&& iflags.menu_head_objsym)),
MENU_UNSELECTED);
printed_type_name = TRUE;
}
any.a_obj = curr;
add_menu(win, obj_to_glyph(curr), &any,
(qflags & USE_INVLET) ? curr->invlet : 0,
(qflags & USE_INVLET) ? curr->invlet
: (first && curr->oclass == COIN_CLASS) ? '$' : 0,
def_oc_syms[(int) objects[curr->otyp].oc_class].sym,
ATR_NONE, doname_with_price(curr), MENU_UNSELECTED);
first = FALSE;
}
}
pack++;
} while (sorted && *pack);
free(oarray);
if (engulfer) {
char buf[BUFSZ];
@@ -1579,16 +1579,22 @@ int x, y;
}
int
do_loot_cont(cobjp)
do_loot_cont(cobjp, cindex, ccount)
struct obj **cobjp;
int cindex, ccount; /* index of this container (1..N), number of them (N) */
{
struct obj *cobj = *cobjp;
if (!cobj)
return 0;
if (cobj->olocked) {
pline("%s locked.",
cobj->lknown ? "It is" : "Hmmm, it turns out to be");
if (ccount < 2)
pline("%s locked.",
cobj->lknown ? "It is" : "Hmmm, it turns out to be");
else if (cobj->lknown)
pline("%s is locked.", The(xname(cobj)));
else
pline("Hmmm, %s turns out to be locked.", the(xname(cobj)));
cobj->lknown = 1;
return 0;
}
@@ -1597,17 +1603,18 @@ struct obj **cobjp;
if (cobj->otyp == BAG_OF_TRICKS) {
int tmp;
You("carefully open the bag...");
You("carefully open %s...", the(xname(cobj)));
pline("It develops a huge set of teeth and bites you!");
tmp = rnd(10);
losehp(Maybe_Half_Phys(tmp), "carnivorous bag", KILLED_BY_AN);
makeknown(BAG_OF_TRICKS);
abort_looting = TRUE;
return 1;
}
You("%sopen %s...", (!cobj->cknown || !cobj->lknown) ? "carefully " : "",
the(xname(cobj)));
return use_container(cobjp, 0);
return use_container(cobjp, 0, (boolean) (cindex < ccount));
}
/* loot a container on the floor or loot saddle from mon. */
@@ -1626,6 +1633,8 @@ doloot()
boolean prev_loot = FALSE;
int num_conts;
abort_looting = FALSE;
if (check_capacity((char *) 0)) {
/* "Can't do that while carrying so much stuff." */
return 0;
@@ -1646,7 +1655,6 @@ doloot()
cc.y = u.uy;
lootcont:
if ((num_conts = container_at(cc.x, cc.y, TRUE)) > 0) {
boolean anyfound = FALSE;
@@ -1676,16 +1684,17 @@ lootcont:
destroy_nhwindow(win);
if (n > 0) {
for (i = 0; i < n; i++) {
timepassed |= do_loot_cont(&pick_list[i].item.a_obj);
if (multi < 0 || !pick_list[i].item.a_obj) {
for (i = 1; i <= n; i++) {
cobj = pick_list[i - 1].item.a_obj;
timepassed |= do_loot_cont(&cobj, i, n);
if (abort_looting) {
/* chest trap or magic bag explosion or <esc> */
free((genericptr_t) pick_list);
return 1;
return timepassed;
}
}
}
if (pick_list)
free((genericptr_t) pick_list);
}
if (n != 0)
c = 'y';
} else {
@@ -1702,11 +1711,10 @@ lootcont:
continue;
anyfound = TRUE;
timepassed |= do_loot_cont(&cobj);
/* might have triggered chest trap or magic bag explosion
*/
if (multi < 0 || !cobj)
return 1;
timepassed |= do_loot_cont(&cobj, 1, 1);
if (abort_looting)
/* chest trap or magic bag explosion or <esc> */
return timepassed;
}
}
if (anyfound)
@@ -1831,8 +1839,8 @@ reverse_loot()
boxdummy = zeroobj, boxdummy.otyp = SPE_WIZARD_LOCK;
(void) boxlock(coffers, &boxdummy);
}
} else if (levl[x][y].looted != T_LOOTED &&
(mon = makemon(courtmon(), x, y, NO_MM_FLAGS)) != 0) {
} else if (levl[x][y].looted != T_LOOTED
&& (mon = makemon(courtmon(), x, y, NO_MM_FLAGS)) != 0) {
freeinv(goldob);
add_to_minv(mon, goldob);
pline("The exchequer accepts your contribution.");
@@ -1865,11 +1873,12 @@ boolean *prev_loot;
*/
if (mtmp && mtmp != u.usteed && (otmp = which_armor(mtmp, W_SADDLE))) {
long unwornmask;
if (passed_info)
*passed_info = 1;
Sprintf(
qbuf, "Do you want to remove the saddle from %s?",
x_monnam(mtmp, ARTICLE_THE, (char *) 0, SUPPRESS_SADDLE, FALSE));
Sprintf(qbuf, "Do you want to remove the saddle from %s?",
x_monnam(mtmp, ARTICLE_THE, (char *) 0,
SUPPRESS_SADDLE, FALSE));
if ((c = yn_function(qbuf, ynqchars, 'n')) == 'y') {
if (nolimbs(youmonst.data)) {
You_cant("do that without limbs."); /* not body_part(HAND) */
@@ -1877,8 +1886,8 @@ boolean *prev_loot;
}
if (otmp->cursed) {
You("can't. The saddle seems to be stuck to %s.",
x_monnam(mtmp, ARTICLE_THE, (char *) 0, SUPPRESS_SADDLE,
FALSE));
x_monnam(mtmp, ARTICLE_THE, (char *) 0,
SUPPRESS_SADDLE, FALSE));
/* the attempt costs you time */
return 1;
}
@@ -1897,8 +1906,7 @@ boolean *prev_loot;
return 0;
}
}
/* 3.4.0 introduced the ability to pick things up from within
swallower's stomach */
/* 3.4.0 introduced ability to pick things up from swallower's stomach */
if (u.uswallow) {
int count = passed_info ? *passed_info : 0;
@@ -2015,15 +2023,14 @@ register struct obj *obj;
(void) snuff_lit(obj);
if (floor_container && costly_spot(u.ux, u.uy)) {
if (obj->oclass == COIN_CLASS) {
; /* defer gold until after put-in message */
} else if (current_container->no_charge && !obj->unpaid) {
/* don't sell when putting the item into your own container */
obj->no_charge = 1;
} else {
/* defer gold until after put-in message */
if (obj->oclass != COIN_CLASS) {
/* sellobj() will take an unpaid item off the shop bill */
was_unpaid = obj->unpaid ? TRUE : FALSE;
sellobj_state(SELL_DELIBERATE);
/* don't sell when putting the item into your own container,
* but handle billing correctly */
sellobj_state(current_container->no_charge
? SELL_DONTSELL : SELL_DELIBERATE);
sellobj(obj, u.ux, u.uy);
sellobj_state(SELL_NORMAL);
}
@@ -2081,7 +2088,7 @@ int
ck_bag(obj)
struct obj *obj;
{
return current_container && obj != current_container;
return (current_container && obj != current_container);
}
/* Returns: -1 to stop, 1 item was removed, 0 item was not removed. */
@@ -2208,14 +2215,14 @@ struct obj *box;
pline("%s inside the box is still alive!", Monnam(livecat));
(void) christen_monst(livecat, sc);
} else {
deadcat =
mk_named_object(CORPSE, &mons[PM_HOUSECAT], box->ox, box->oy, sc);
deadcat = mk_named_object(CORPSE, &mons[PM_HOUSECAT],
box->ox, box->oy, sc);
if (deadcat) {
obj_extract_self(deadcat);
(void) add_to_container(box, deadcat);
}
pline_The("%s inside the box is dead!",
Hallucination ? rndmonnam(NULL) : "housecat");
Hallucination ? rndmonnam((char *) 0) : "housecat");
}
box->owt = weight(box);
return;
@@ -2234,14 +2241,16 @@ int FDECL((*fn), (OBJ_P));
}
STATIC_OVL void
explain_container_prompt()
explain_container_prompt(more_containers)
boolean more_containers;
{
static const char *const explaintext[] = {
"Container actions:", "", " : -- Look: examine contents",
" o -- Out: take things out", " i -- In: put things in",
" b -- Both: first take things out, then put things in",
" r -- Reversed: put things in, then take things out",
" s -- Stash: put one item in", " q -- Quit: do nothing",
" s -- Stash: put one item in", "",
" n -- Next: loot next selected container", " q -- Quit: finished",
" ? -- Help: display this text.", "", 0
};
const char *const *txtpp;
@@ -2249,8 +2258,11 @@ explain_container_prompt()
/* "Do what with <container>? [:oibrsq or ?] (q)" */
if ((win = create_nhwindow(NHW_TEXT)) != WIN_ERR) {
for (txtpp = explaintext; *txtpp; ++txtpp)
for (txtpp = explaintext; *txtpp; ++txtpp) {
if (!more_containers && !strncmp(*txtpp, " n ", 3))
continue;
putstr(win, 0, *txtpp);
}
display_nhwindow(win, FALSE);
destroy_nhwindow(win);
}
@@ -2272,9 +2284,10 @@ u_handsy()
static const char stashable[] = { ALLOW_COUNT, COIN_CLASS, ALL_CLASSES, 0 };
int
use_container(objp, held)
use_container(objp, held, more_containers)
struct obj **objp;
int held;
boolean more_containers; /* True iff #loot multiple and this isn't last one */
{
struct obj *curr, *otmp, *obj = *objp;
boolean quantum_cat, cursed_mbag, loot_out, loot_in, loot_in_first,
@@ -2282,6 +2295,7 @@ int held;
char c, emptymsg[BUFSZ], qbuf[QBUFSZ], pbuf[QBUFSZ], xbuf[QBUFSZ];
int used = 0;
abort_looting = FALSE;
emptymsg[0] = '\0';
if (!u_handsy())
@@ -2304,12 +2318,15 @@ int held;
multi_reason = "opening a container";
nomovemsg = "";
}
abort_looting = TRUE;
return 1;
}
obj->lknown = 1;
current_container = obj; /* for use by in/out_container */
/* from here on out, all early returns go through containerdone */
/*
* From here on out, all early returns go through 'containerdone:'.
*/
/* check for Schroedinger's Cat */
quantum_cat = SchroedingersBox(current_container);
@@ -2355,17 +2372,20 @@ int held;
* inventory is empty--taking out could alter that;
* include do-both-reversed when 'i' is available,
* even if container is empty--for similar reason;
* always include the quit choice ('q').
* include the next container choice ('n') when
* relevant, and make it the default;
* always include the quit choice ('q'), and make
* it the default if there's no next containter;
* include the help choice (" or ?") if `cmdassist'
* run-time option is set;
* (Player can pick any of (o,i,b,r,s,?) even when
* (Player can pick any of (o,i,b,r,n,s,?) even when
* they're not listed among the available actions.)
*
* Do what with <the/your/Shk's container>? [:oibrsq or ?] (q)
* Do what with <the/your/Shk's container>? [:oibrs nq or ?] (q)
* or
* <The/Your/Shk's container> is empty. Do what with it? [:irsq or ?]
* <The/Your/Shk's container> is empty. Do what with it? [:irs nq or ?]
*/
for (;;) { /* repeats if '?' or ":' gets chosen */
for (;;) { /* repeats iff '?' or ":' gets chosen */
outmaybe = (outokay || !current_container->cknown);
if (!outmaybe)
(void) safe_qbuf(qbuf, (char *) 0, " is empty. Do what with it?",
@@ -2375,34 +2395,39 @@ int held;
(void) safe_qbuf(qbuf, "Do what with ", "?", current_container,
yname, ysimple_name, "it");
/* ask player about what to do with this container */
if (flags.menu_style == MENU_FULL) {
if (flags.menu_style == MENU_PARTIAL
|| flags.menu_style == MENU_FULL) {
if (!inokay && !outmaybe) {
/* nothing to take out, nothing to put in;
trying to do both will yield proper feedback */
c = 'b';
} else {
c = in_or_out_menu(qbuf, current_container, outmaybe, inokay,
(used != 0));
(boolean) (used != 0), more_containers);
}
} else { /* TRADITIONAL, COMBINATION, or PARTIAL */
xbuf[0] = '\0'; /* list of extra acceptable responses */
Strcpy(pbuf, ":"); /* look inside */
} else { /* TRADITIONAL or COMBINATION */
xbuf[0] = '\0'; /* list of extra acceptable responses */
Strcpy(pbuf, ":"); /* look inside */
Strcat(outmaybe ? pbuf : xbuf, "o"); /* take out */
Strcat(inokay ? pbuf : xbuf, "i"); /* put in */
Strcat(outmaybe ? pbuf : xbuf, "b"); /* both */
Strcat(inokay ? pbuf : xbuf, "rs"); /* reversed, stash */
Strcat(pbuf, " "); /* separator */
Strcat(more_containers ? pbuf : xbuf, "n"); /* next container */
Strcat(pbuf, "q"); /* quit */
if (iflags.cmdassist)
/* this unintentionally allows user to answer with 'o' or
'r'; fortunately, those are already valid choices here */
Strcat(pbuf, " or ?"); /* help */
else
Strcat(xbuf, "?");
if (*xbuf)
Strcat(strcat(pbuf, "\033"), xbuf);
c = yn_function(qbuf, pbuf, 'q');
} /* FULL vs other modes */
c = yn_function(qbuf, pbuf, more_containers ? 'n' : 'q');
} /* PARTIAL|FULL vs other modes */
if (c == '?') {
explain_container_prompt();
explain_container_prompt(more_containers);
} else if (c == ':') { /* note: will set obj->cknown */
if (!current_container->cknown)
used = 1; /* gaining info */
@@ -2411,7 +2436,9 @@ int held;
break;
} /* loop until something other than '?' or ':' is picked */
if (c == 'q') /* [not strictly needed; falling through works] */
if (c == 'q')
abort_looting = TRUE;
if (c == 'n' || c == 'q') /* [not strictly needed; falling thru works] */
goto containerdone;
loot_out = (c == 'o' || c == 'b' || c == 'r');
loot_in = (c == 'i' || c == 'b' || c == 'r');
@@ -2459,11 +2486,7 @@ int held;
} else {
/* couldn't put selected item into container for some
reason; might need to undo splitobj() */
for (curr = invent; curr; curr = curr->nobj)
if (curr->nobj == otmp)
break;
if (curr && curr->invlet == otmp->invlet)
(void) merged(&curr, &otmp);
(void) unsplitobj(otmp);
}
}
}
@@ -2499,7 +2522,10 @@ containerdone:
}
*objp = current_container; /* might have become null */
current_container = 0; /* avoid hanging on to stale pointer */
if (current_container)
current_container = 0; /* avoid hanging on to stale pointer */
else
abort_looting = TRUE;
return used;
}
@@ -2558,9 +2584,9 @@ boolean put_in;
} else if (flags.menu_style == MENU_FULL) {
all_categories = FALSE;
Sprintf(buf, "%s what type of objects?", action);
mflags = put_in
? ALL_TYPES | BUC_ALLBKNOWN | BUC_UNKNOWN
: ALL_TYPES | CHOOSE_ALL | BUC_ALLBKNOWN | BUC_UNKNOWN;
mflags = (ALL_TYPES | BUC_ALLBKNOWN | BUC_UNKNOWN);
if (put_in)
mflags |= CHOOSE_ALL;
n = query_category(buf, put_in ? invent : current_container->cobj,
mflags, &pick_list, PICK_ANY);
if (!n)
@@ -2591,7 +2617,7 @@ boolean put_in;
if (!put_in)
current_container->cknown = 1;
Sprintf(buf, "%s what?", action);
n = query_objlist(buf, put_in ? invent : current_container->cobj,
n = query_objlist(buf, put_in ? &invent : &(current_container->cobj),
mflags, &pick_list, PICK_ANY,
all_categories ? allow_all : allow_category);
if (n) {
@@ -2623,13 +2649,13 @@ boolean put_in;
}
STATIC_OVL char
in_or_out_menu(prompt, obj, outokay, inokay, alreadyused)
in_or_out_menu(prompt, obj, outokay, inokay, alreadyused, more_containers)
const char *prompt;
struct obj *obj;
boolean outokay, inokay, alreadyused;
boolean outokay, inokay, alreadyused, more_containers;
{
/* underscore is not a choice; it's used to skip element [0] */
static const char lootchars[] = "_:oibrsq", abc_chars[] = "_:abcdeq";
static const char lootchars[] = "_:oibrsnq", abc_chars[] = "_:abcdenq";
winid win;
anything any;
menu_item *pick_list;
@@ -2674,20 +2700,30 @@ boolean outokay, inokay, alreadyused;
add_menu(win, NO_GLYPH, &any, menuselector[any.a_int], 0, ATR_NONE,
buf, MENU_UNSELECTED);
}
any.a_int = 7; /* 'q' */
any.a_int = 0;
add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED);
if (more_containers) {
any.a_int = 7; /* 'n' */
add_menu(win, NO_GLYPH, &any, menuselector[any.a_int], 0, ATR_NONE,
"loot next container", MENU_SELECTED);
}
any.a_int = 8; /* 'q' */
Strcpy(buf, alreadyused ? "done" : "do nothing");
add_menu(win, NO_GLYPH, &any, menuselector[any.a_int], 0, ATR_NONE, buf,
MENU_SELECTED);
more_containers ? MENU_UNSELECTED : MENU_SELECTED);
end_menu(win, prompt);
n = select_menu(win, PICK_ONE, &pick_list);
destroy_nhwindow(win);
if (n > 0) {
n = pick_list[0].item.a_int;
int k = pick_list[0].item.a_int;
if (n > 1 && k == (more_containers ? 7 : 8))
k = pick_list[1].item.a_int;
free((genericptr_t) pick_list);
return lootchars[n]; /* :,o,i,b,r,s,q */
return lootchars[k]; /* :,o,i,b,r,s,n,q */
}
return 'q'; /* quit */
return (n == 0 && more_containers) ? 'n' : 'q'; /* next or quit */
}
static const char tippables[] = { ALL_CLASSES, TOOL_CLASS, 0 };
+46 -19
View File
@@ -1,4 +1,4 @@
/* NetHack 3.6 pline.c $NHDT-Date: 1456528597 2016/02/26 23:16:37 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.49 $ */
/* NetHack 3.6 pline.c $NHDT-Date: 1461437814 2016/04/23 18:56:54 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.51 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
@@ -436,7 +436,8 @@ register struct monst *mtmp;
Strcat(info, ", asleep");
#if 0 /* unfortunately mfrozen covers temporary sleep and being busy \
(donning armor, for instance) as well as paralysis */
else if (mtmp->mfrozen) Strcat(info, ", paralyzed");
else if (mtmp->mfrozen)
Strcat(info, ", paralyzed");
#else
else if (mtmp->mfrozen || !mtmp->mcanmove)
Strcat(info, ", can't move");
@@ -538,23 +539,8 @@ ustatusline()
Strcat(info, mon_nam(u.ustuck));
}
pline("Status of %s (%s%s): Level %d HP %d(%d) AC %d%s.", plname,
(u.ualign.record >= 20)
? "piously "
: (u.ualign.record > 13)
? "devoutly "
: (u.ualign.record > 8)
? "fervently "
: (u.ualign.record > 3)
? "stridently "
: (u.ualign.record == 3)
? ""
: (u.ualign.record >= 1)
? "haltingly "
: (u.ualign.record == 0)
? "nominally "
: "insufficiently ",
align_str(u.ualign.type),
pline("Status of %s (%s): Level %d HP %d(%d) AC %d%s.", plname,
piousness(FALSE, align_str(u.ualign.type)),
Upolyd ? mons[u.umonnum].mlevel : u.ulevel, Upolyd ? u.mh : u.uhp,
Upolyd ? u.mhmax : u.uhpmax, u.uac, info);
}
@@ -568,6 +554,47 @@ self_invis_message()
: "can't see yourself");
}
char *
piousness(showneg, suffix)
boolean showneg;
const char *suffix;
{
static char buf[32]; /* bigger than "insufficiently neutral" */
const char *pio;
/* note: piousness 20 matches MIN_QUEST_ALIGN (quest.h) */
if (u.ualign.record >= 20)
pio = "piously";
else if (u.ualign.record > 13)
pio = "devoutly";
else if (u.ualign.record > 8)
pio = "fervently";
else if (u.ualign.record > 3)
pio = "stridently";
else if (u.ualign.record == 3)
pio = "";
else if (u.ualign.record > 0)
pio = "haltingly";
else if (u.ualign.record == 0)
pio = "nominally";
else if (!showneg)
pio = "insufficiently";
else if (u.ualign.record >= -3)
pio = "strayed";
else if (u.ualign.record >= -8)
pio = "sinned";
else
pio = "transgressed";
Sprintf(buf, "%s", pio);
if (suffix && (!showneg || u.ualign.record >= 0)) {
if (u.ualign.record != 3)
Strcat(buf, " ");
Strcat(buf, suffix);
}
return buf;
}
void
pudding_merge_message(otmp, otmp2)
struct obj *otmp;
+9 -14
View File
@@ -1,4 +1,4 @@
/* NetHack 3.6 polyself.c $NHDT-Date: 1451082254 2015/12/25 22:24:14 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.105 $ */
/* NetHack 3.6 polyself.c $NHDT-Date: 1457572516 2016/03/10 01:15:16 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.108 $ */
/* Copyright (C) 1987, 1988, 1989 by Ken Arromdee */
/* NetHack may be freely redistributed. See license for details. */
@@ -592,6 +592,7 @@ int
polymon(mntmp)
int mntmp;
{
char buf[BUFSZ];
boolean sticky = sticks(youmonst.data) && u.ustuck && !u.uswallow,
was_blind = !!Blind, dochange = FALSE;
int mlvl;
@@ -643,20 +644,16 @@ int mntmp;
if (sex_change_ok && !rn2(10))
dochange = TRUE;
}
Strcpy(buf, (u.umonnum != mntmp) ? "" : "new ");
if (dochange) {
flags.female = !flags.female;
You("%s %s%s!",
(u.umonnum != mntmp) ? "turn into a" : "feel like a new",
(is_male(&mons[mntmp]) || is_female(&mons[mntmp]))
? ""
: flags.female ? "female " : "male ",
mons[mntmp].mname);
} else {
if (u.umonnum != mntmp)
You("turn into %s!", an(mons[mntmp].mname));
else
You_feel("like a new %s!", mons[mntmp].mname);
Strcat(buf, (is_male(&mons[mntmp]) || is_female(&mons[mntmp]))
? "" : flags.female ? "female " : "male ");
}
Strcat(buf, mons[mntmp].mname);
You("%s %s!", (u.umonnum != mntmp) ? "turn into" : "feel like", an(buf));
if (Stoned && poly_when_stoned(&mons[mntmp])) {
/* poly_when_stoned already checked stone golem genocide */
mntmp = PM_STONE_GOLEM;
@@ -746,8 +743,6 @@ int mntmp;
uunstick();
if (u.usteed) {
if (touch_petrifies(u.usteed->data) && !Stone_resistance && rnl(3)) {
char buf[BUFSZ];
pline("%s touch %s.", no_longer_petrify_resistant,
mon_nam(u.usteed));
Sprintf(buf, "riding %s", an(u.usteed->data->mname));
+50 -26
View File
@@ -957,39 +957,59 @@ register struct obj *otmp;
break;
case POT_LEVITATION:
case SPE_LEVITATION:
if (otmp->cursed)
HLevitation &= ~I_SPECIAL;
/*
* BLevitation will be set if levitation is blocked due to being
* inside rock (currently or formerly in phazing xorn form, perhaps)
* but it doesn't prevent setting or incrementing Levitation timeout
* (which will take effect after escaping from the rock if it hasn't
* expired by then).
*/
if (!Levitation && !BLevitation) {
/* kludge to ensure proper operation of float_up() */
set_itimeout(&HLevitation, 1L);
float_up();
/* reverse kludge */
set_itimeout(&HLevitation, 0L);
if (otmp->cursed) {
if ((u.ux == xupstair && u.uy == yupstair)
|| (sstairs.up && u.ux == sstairs.sx
&& u.uy == sstairs.sy)
|| (xupladder && u.ux == xupladder
&& u.uy == yupladder)) {
(void) doup();
} else if (has_ceiling(&u.uz)) {
int dmg = uarmh ? 1 : rnd(10);
You("hit your %s on the %s.", body_part(HEAD),
ceiling(u.ux, u.uy));
losehp(Maybe_Half_Phys(dmg), "colliding with the ceiling",
KILLED_BY);
}
} /*cursed*/
} else
/* This used to set timeout back to 0, then increment it below
for blessed and uncursed effects. But now we leave it so
that cursed effect yields "you float down" on next turn.
Blessed and uncursed get one extra turn duration. */
} else /* already levitating, or can't levitate */
nothing++;
if (otmp->blessed) {
if (otmp->cursed) {
/* 'already levitating' used to block the cursed effect(s)
aside from ~I_SPECIAL; it was not clear whether that was
intentional; either way, it no longer does (as of 3.6.1) */
HLevitation &= ~I_SPECIAL; /* can't descend upon demand */
if (BLevitation) {
; /* rising via levitation is blocked */
} else if ((u.ux == xupstair && u.uy == yupstair)
|| (sstairs.up && u.ux == sstairs.sx && u.uy == sstairs.sy)
|| (xupladder && u.ux == xupladder && u.uy == yupladder)) {
(void) doup();
/* in case we're already Levitating, which would have
resulted in incrementing 'nothing' */
nothing = 0; /* not nothing after all */
} else if (has_ceiling(&u.uz)) {
int dmg = rnd(!uarmh ? 10 : !is_metallic(uarmh) ? 6 : 3);
You("hit your %s on the %s.", body_part(HEAD),
ceiling(u.ux, u.uy));
losehp(Maybe_Half_Phys(dmg), "colliding with the ceiling",
KILLED_BY);
nothing = 0; /* not nothing after all */
}
} else if (otmp->blessed) {
/* at this point, timeout is already at least 1 */
incr_itimeout(&HLevitation, rn1(50, 250));
/* can descend at will (stop levitating via '>') provided timeout
is the only factor (ie, not also wearing Lev ring or boots) */
HLevitation |= I_SPECIAL;
} else
} else /* timeout is already at least 1 */
incr_itimeout(&HLevitation, rn1(140, 10));
if (Levitation)
spoteffects(FALSE); /* for sinks */
if (Levitation && IS_SINK(levl[u.ux][u.uy].typ))
spoteffects(FALSE);
/* levitating blocks flying */
float_vs_flight();
break;
case POT_GAIN_ENERGY: { /* M. Stephenson */
@@ -1090,8 +1110,12 @@ register boolean curesick, cureblind;
u.uhp = (u.uhpmax += nxtra);
}
}
if (cureblind)
if (cureblind) {
/* 3.6.1: it's debatible whether healing magic should clean off
mundane 'dirt', but if it doesn't, blindness isn't cured */
u.ucreamed = 0;
make_blinded(0L, TRUE);
}
if (curesick) {
make_vomiting(0L, TRUE);
make_sick(0L, (char *) 0, TRUE, SICK_ALL);
+16 -8
View File
@@ -289,7 +289,7 @@ worst_cursed_item()
} else if (uright && uright->cursed) { /* right ring */
otmp = uright;
} else if (ublindf && ublindf->cursed) { /* eyewear */
otmp = ublindf; /* must be non-blinding lenses */
otmp = ublindf; /* must be non-blinding lenses */
/* if weapon wasn't handled above, do it now */
} else if (welded(uwep)) { /* weapon */
otmp = uwep;
@@ -520,9 +520,8 @@ int trouble;
}
}
/* "I am sometimes shocked by... the nuns who never take a bath without
* wearing a bathrobe all the time. When asked why, since no man can see
* them,
/* "I am sometimes shocked by... the nuns who never take a bath without
* wearing a bathrobe all the time. When asked why, since no man can see them,
* they reply 'Oh, but you forget the good God'. Apparently they conceive of
* the Deity as a Peeping Tom, whose omnipotence enables Him to see through
* bathroom walls, but who is foiled by bathrobes." --Bertrand Russell, 1943
@@ -540,8 +539,10 @@ aligntyp resp_god;
pline("%s fries to a crisp!", Monnam(u.ustuck));
/* Yup, you get experience. It takes guts to successfully
* pull off this trick on your god, anyway.
* Other credit/blame applies (luck or alignment adjustments),
* but not direct kill count (pacifist conduct).
*/
xkilled(u.ustuck, 0);
xkilled(u.ustuck, XKILL_NOMSG | XKILL_NOCONDUCT);
} else
pline("%s seems unaffected.", Monnam(u.ustuck));
} else {
@@ -565,7 +566,7 @@ aligntyp resp_god;
mon_nam(u.ustuck));
if (!resists_disint(u.ustuck)) {
pline("%s disintegrates into a pile of dust!", Monnam(u.ustuck));
xkilled(u.ustuck, 2); /* no corpse */
xkilled(u.ustuck, XKILL_NOMSG | XKILL_NOCORPSE | XKILL_NOCONDUCT);
} else
pline("%s seems unaffected.", Monnam(u.ustuck));
} else {
@@ -585,9 +586,9 @@ aligntyp resp_god;
(void) destroy_arm(uarm);
if (uarmu && !uarm && !uarmc)
(void) destroy_arm(uarmu);
if (!Disint_resistance)
if (!Disint_resistance) {
fry_by_god(resp_god, TRUE);
else {
} else {
You("bask in its %s glow for a minute...", NH_BLACK);
godvoice(resp_god, "I believe it not!");
}
@@ -1048,8 +1049,15 @@ aligntyp g_align;
ABASE(A_STR) = AMAX(A_STR);
if (u.uhunger < 900)
init_uhunger();
/* luck couldn't have been negative at start of prayer because
the prayer would have failed, but might have been decremented
due to a timed event (delayed death of peaceful monster hit
by hero-created stinking cloud) during the praying interval */
if (u.uluck < 0)
u.uluck = 0;
/* superfluous; if hero was blinded we'd be handling trouble
rather than issuing a pat-on-head */
u.ucreamed = 0;
make_blinded(0L, TRUE);
context.botl = 1;
break;
+29 -12
View File
@@ -1,4 +1,4 @@
/* NetHack 3.6 read.c $NHDT-Date: 1450577673 2015/12/20 02:14:33 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.131 $ */
/* NetHack 3.6 read.c $NHDT-Date: 1457660917 2016/03/11 01:48:37 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.136 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
@@ -60,6 +60,7 @@ struct obj *otmp;
char *buf;
{
int erosion = greatest_erosion(otmp);
if (erosion)
wipeout_text(buf, (int) (strlen(buf) * erosion / (2 * MAX_ERODE)),
otmp->o_id ^ (unsigned) ubirthday);
@@ -1312,8 +1313,11 @@ struct obj *sobj; /* scroll, or fake spellbook object for scroll-like spell */
*/
break;
case SCR_ENCHANT_WEAPON:
/* [What about twoweapon mode? Proofing/repairing/enchanting both
would be too powerful, but shouldn't we choose randomly between
primary and secondary instead of always acting on primary?] */
if (confused && uwep
&& (uwep->oclass == WEAPON_CLASS || is_weptool(uwep))) {
&& erosion_matters(uwep) && uwep->oclass != ARMOR_CLASS) {
old_erodeproof = (uwep->oerodeproof != 0);
new_erodeproof = !scursed;
uwep->oerodeproof = 0; /* for messages */
@@ -1740,9 +1744,9 @@ boolean confused, byu;
}
mtmp->mhp -= mdmg;
if (mtmp->mhp <= 0) {
if (byu)
xkilled(mtmp, 1);
else {
if (byu) {
killed(mtmp);
} else {
pline("%s is killed.", Monnam(mtmp));
mondied(mtmp);
}
@@ -2366,11 +2370,9 @@ create_particular()
int which, tryct, i, firstchoice = NON_PM;
struct permonst *whichpm = NULL;
struct monst *mtmp;
boolean madeany = FALSE;
boolean maketame, makepeaceful, makehostile;
boolean randmonst = FALSE;
boolean saddled = FALSE;
boolean invisible = FALSE;
boolean madeany = FALSE, randmonst = FALSE,
maketame, makepeaceful, makehostile, saddled, invisible;
int fem;
tryct = 5;
do {
@@ -2378,18 +2380,29 @@ create_particular()
which = urole.malenum; /* an arbitrary index into mons[] */
maketame = makepeaceful = makehostile = FALSE;
saddled = invisible = FALSE;
fem = -1; /* gender not specified */
getlin("Create what kind of monster? [type the name or symbol]", buf);
bufp = mungspaces(buf);
if (*bufp == '\033')
return FALSE;
if ((tmpp = strstri(bufp, "saddled ")) != 0) {
saddled = TRUE;
memset(tmpp, ' ', sizeof("saddled ")-1);
(void) memset(tmpp, ' ', sizeof "saddled " - 1);
}
if ((tmpp = strstri(bufp, "invisible ")) != 0) {
invisible = TRUE;
memset(tmpp, ' ', sizeof("invisible ")-1);
(void) memset(tmpp, ' ', sizeof "invisible " - 1);
}
/* check "female" before "male" to avoid false hit mid-word */
if ((tmpp = strstri(bufp, "female ")) != 0) {
fem = 1;
(void) memset(tmpp, ' ', sizeof "female " - 1);
}
if ((tmpp = strstri(bufp, "male ")) != 0) {
fem = 0;
(void) memset(tmpp, ' ', sizeof "male " - 1);
}
bufp = mungspaces(bufp); /* after potential memset(' ') */
/* allow the initial disposition to be specified */
if (!strncmpi(bufp, "tame ", 5)) {
bufp += 5;
@@ -2448,6 +2461,9 @@ create_particular()
/* otherwise try again */
continue;
}
/* 'is_FOO()' ought to be called 'always_FOO()' */
if (fem != -1 && !is_male(mtmp->data) && !is_female(mtmp->data))
mtmp->female = fem; /* ignored for is_neuter() */
if (maketame) {
(void) tamedog(mtmp, (struct obj *) 0);
} else if (makepeaceful || makehostile) {
@@ -2457,6 +2473,7 @@ create_particular()
}
if (saddled && can_saddle(mtmp) && !which_armor(mtmp, W_SADDLE)) {
struct obj *otmp = mksobj(SADDLE, TRUE, FALSE);
put_saddle_on_mon(otmp, mtmp);
}
if (invisible)
+1 -1
View File
@@ -1,5 +1,5 @@
/* NetHack 3.6 rect.c $NHDT-Date: 1432512774 2015/05/25 00:12:54 $ $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ */
/* Copyright (c) 1990 by Jean-Christophe Collet */
/* Copyright (c) 1990 by Jean-Christophe Collet */
/* NetHack may be freely redistributed. See license for details. */
#include "hack.h"
+35 -10
View File
@@ -95,14 +95,13 @@ int nrect;
if (nrect > 0) {
reg->bounding_box = rects[0];
} else {
reg->bounding_box.lx = 99;
reg->bounding_box.ly = 99;
reg->bounding_box.hx = 0;
reg->bounding_box.lx = COLNO;
reg->bounding_box.ly = ROWNO;
reg->bounding_box.hx = 0; /* 1 */
reg->bounding_box.hy = 0;
}
reg->nrects = nrect;
reg->rects =
nrect > 0 ? (NhRect *) alloc((sizeof(NhRect)) * nrect) : (NhRect *) 0;
reg->rects = (nrect > 0) ? (NhRect *) alloc(nrect * sizeof (NhRect)) : 0;
for (i = 0; i < nrect; i++) {
if (rects[i].lx < reg->bounding_box.lx)
reg->bounding_box.lx = rects[i].lx;
@@ -145,10 +144,10 @@ NhRect *rect;
{
NhRect *tmp_rect;
tmp_rect = (NhRect *) alloc(sizeof(NhRect) * (reg->nrects + 1));
tmp_rect = (NhRect *) alloc((reg->nrects + 1) * sizeof (NhRect));
if (reg->nrects > 0) {
(void) memcpy((genericptr_t) tmp_rect, (genericptr_t) reg->rects,
(sizeof(NhRect) * reg->nrects));
reg->nrects * sizeof (NhRect));
free((genericptr_t) reg->rects);
}
tmp_rect[reg->nrects] = *rect;
@@ -177,7 +176,7 @@ struct monst *mon;
unsigned *tmp_m;
if (reg->max_monst <= reg->n_monst) {
tmp_m = (unsigned *) alloc(sizeof(unsigned)
tmp_m = (unsigned *) alloc(sizeof (unsigned)
* (reg->max_monst + MONST_INC));
if (reg->max_monst > 0) {
for (i = 0; i < reg->max_monst; i++)
@@ -297,10 +296,10 @@ NhRegion *reg;
if (max_regions <= n_regions) {
tmp_reg = regions;
regions =
(NhRegion **) alloc(sizeof(NhRegion *) * (max_regions + 10));
(NhRegion **) alloc((max_regions + 10) * sizeof (NhRegion *));
if (max_regions > 0) {
(void) memcpy((genericptr_t) regions, (genericptr_t) tmp_reg,
max_regions * sizeof(NhRegion *));
max_regions * sizeof (NhRegion *));
free((genericptr_t) tmp_reg);
}
max_regions += 10;
@@ -763,6 +762,32 @@ boolean ghostly; /* If a bones file restore */
reset_region_mids(regions[i]);
}
/* to support '#stats' wizard-mode command */
void
region_stats(hdrfmt, hdrbuf, count, size)
const char *hdrfmt;
char *hdrbuf;
long *count, *size;
{
NhRegion *rg;
int i;
/* other stats formats take one parameter; this takes two */
Sprintf(hdrbuf, hdrfmt, (long) sizeof (NhRegion), (long) sizeof (NhRect));
*count = (long) n_regions; /* might be 0 even though max_regions isn't */
*size = (long) max_regions * (long) sizeof (NhRegion);
for (i = 0; i < n_regions; ++i) {
rg = regions[i];
*size += (long) rg->nrects * (long) sizeof (NhRect);
if (rg->enter_msg)
*size += (long) (strlen(rg->enter_msg) + 1);
if (rg->leave_msg)
*size += (long) (strlen(rg->leave_msg) + 1);
*size += (long) rg->max_monst * (long) sizeof *rg->monsters;
}
/* ? */
}
/* update monster IDs for region being loaded from bones; `ghostly' implied */
STATIC_OVL void
reset_region_mids(reg)
+39 -12
View File
@@ -1,4 +1,4 @@
/* NetHack 3.6 role.c $NHDT-Date: 1456907852 2016/03/02 08:37:32 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.37 $ */
/* NetHack 3.6 role.c $NHDT-Date: 1463561393 2016/05/18 08:49:53 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.38 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985-1999. */
/* NetHack may be freely redistributed. See license for details. */
@@ -1148,9 +1148,9 @@ int rolenum, racenum, gendnum, alignnum;
}
}
/* pick a random race subject to any rolenum/gendnum/alignnum constraints */
/* If pickhow == PICK_RIGID a race is returned only if there is */
/* a single possibility */
/* Pick a random race subject to any rolenum/gendnum/alignnum constraints.
If pickhow == PICK_RIGID a race is returned only if there is
a single possibility. */
int
pick_race(rolenum, gendnum, alignnum, pickhow)
int rolenum, gendnum, alignnum, pickhow;
@@ -1284,11 +1284,10 @@ int alignnum;
}
}
/* pick a random alignment subject to any rolenum/racenum/gendnum constraints
*/
/* alignment and gender are not comparable (and also not constrainable) */
/* If pickhow == PICK_RIGID an alignment is returned only if there is */
/* a single possibility */
/* Pick a random alignment subject to any rolenum/racenum/gendnum constraints;
alignment and gender are not comparable (and also not constrainable).
If pickhow == PICK_RIGID an alignment is returned only if there is
a single possibility. */
int
pick_align(rolenum, racenum, gendnum, pickhow)
int rolenum, racenum, gendnum, pickhow;
@@ -1317,6 +1316,8 @@ int rolenum, racenum, gendnum, pickhow;
void
rigid_role_checks()
{
int tmp;
/* Some roles are limited to a single race, alignment, or gender and
* calling this routine prior to XXX_player_selection() will help
* prevent an extraneous prompt that actually doesn't allow
@@ -1327,14 +1328,27 @@ rigid_role_checks()
*/
if (flags.initrole == ROLE_RANDOM) {
/* If the role was explicitly specified as ROLE_RANDOM
* via -uXXXX-@ then choose the role in here to narrow down
* later choices. Pick a random role in this case.
* via -uXXXX-@ or OPTIONS=role:random then choose the role
* in here to narrow down later choices.
*/
flags.initrole = pick_role(flags.initrace, flags.initgend,
flags.initalign, PICK_RANDOM);
if (flags.initrole < 0)
flags.initrole = randrole_filtered();
}
if (flags.initrace == ROLE_RANDOM
&& (tmp = pick_race(flags.initrole, flags.initgend,
flags.initalign, PICK_RANDOM)) != ROLE_NONE)
flags.initrace = tmp;
if (flags.initalign == ROLE_RANDOM
&& (tmp = pick_align(flags.initrole, flags.initrace,
flags.initgend, PICK_RANDOM)) != ROLE_NONE)
flags.initalign = tmp;
if (flags.initgend == ROLE_RANDOM
&& (tmp = pick_gend(flags.initrole, flags.initrace,
flags.initalign, PICK_RANDOM)) != ROLE_NONE)
flags.initgend = tmp;
if (flags.initrole != ROLE_NONE) {
if (flags.initrace == ROLE_NONE)
flags.initrace = pick_race(flags.initrole, flags.initgend,
@@ -1639,7 +1653,20 @@ int buflen, rolenum, racenum, gendnum, alignnum;
* Now append the post attributes to it
*/
num_post_attribs = post_attribs;
if (post_attribs) {
if (!num_post_attribs) {
/* some constraints might have been mutually exclusive, in which case
some prompting that would have been omitted is needed after all */
if (flags.initrole == ROLE_NONE && !pa[BP_ROLE])
pa[BP_ROLE] = ++post_attribs;
if (flags.initrace == ROLE_NONE && !pa[BP_RACE])
pa[BP_RACE] = ++post_attribs;
if (flags.initalign == ROLE_NONE && !pa[BP_ALIGN])
pa[BP_ALIGN] = ++post_attribs;
if (flags.initgend == ROLE_NONE && !pa[BP_GEND])
pa[BP_GEND] = ++post_attribs;
num_post_attribs = post_attribs;
}
if (num_post_attribs) {
if (pa[BP_RACE]) {
(void) promptsep(eos(buf), num_post_attribs);
Strcat(buf, "race");
+3
View File
@@ -1329,6 +1329,9 @@ free_dungeons()
void
freedynamicdata()
{
#if defined(UNIX) && defined(MAIL)
free_maildata();
#endif
unload_qtlist();
free_menu_coloring();
free_invbuf(); /* let_to_name (invent.c) */
+86 -76
View File
@@ -1,4 +1,4 @@
/* NetHack 3.6 shk.c $NHDT-Date: 1455403704 2016/02/13 22:48:24 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.124 $ */
/* NetHack 3.6 shk.c $NHDT-Date: 1464138042 2016/05/25 01:00:42 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.132 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
@@ -38,7 +38,8 @@ STATIC_DCL struct monst *FDECL(next_shkp, (struct monst *, BOOLEAN_P));
STATIC_DCL long FDECL(shop_debt, (struct eshk *));
STATIC_DCL char *FDECL(shk_owns, (char *, struct obj *));
STATIC_DCL char *FDECL(mon_owns, (char *, struct obj *));
STATIC_DCL void FDECL(clear_unpaid, (struct obj *));
STATIC_DCL void FDECL(clear_unpaid_obj, (struct monst *, struct obj *));
STATIC_DCL void FDECL(clear_unpaid, (struct monst *, struct obj *));
STATIC_DCL long FDECL(check_credit, (long, struct monst *));
STATIC_DCL void FDECL(pay, (long, struct monst *));
STATIC_DCL long FDECL(get_cost, (struct obj *, struct monst *));
@@ -80,7 +81,7 @@ STATIC_DCL const char *FDECL(cad, (BOOLEAN_P));
obj->quan <= bp->bquan
*/
static const char *angrytexts[] = {"quite upset", "ticked off", "furious"};
static const char *angrytexts[] = { "quite upset", "ticked off", "furious" };
/*
* Transfer money from inventory to monster when paying
@@ -260,15 +261,26 @@ boolean ghostly;
}
}
/* Clear the unpaid bit on a single object and its contents. */
STATIC_OVL void
clear_unpaid_obj(shkp, otmp)
struct monst *shkp;
struct obj *otmp;
{
if (Has_contents(otmp))
clear_unpaid(shkp, otmp->cobj);
if (onbill(otmp, shkp, TRUE))
otmp->unpaid = 0;
}
/* Clear the unpaid bit on all of the objects in the list. */
STATIC_OVL void
clear_unpaid(list)
register struct obj *list;
clear_unpaid(shkp, list)
struct monst *shkp;
struct obj *list;
{
while (list) {
if (Has_contents(list))
clear_unpaid(list->cobj);
list->unpaid = 0;
clear_unpaid_obj(shkp, list);
list = list->nobj;
}
}
@@ -281,20 +293,17 @@ register struct monst *shkp;
register struct obj *obj;
register struct monst *mtmp;
/* FIXME: object handling should be limited to
items which are on this particular shk's bill */
clear_unpaid(invent);
clear_unpaid(fobj);
clear_unpaid(level.buriedobjlist);
clear_unpaid(shkp, invent);
clear_unpaid(shkp, fobj);
clear_unpaid(shkp, level.buriedobjlist);
if (thrownobj)
thrownobj->unpaid = 0;
clear_unpaid_obj(shkp, thrownobj);
if (kickedobj)
kickedobj->unpaid = 0;
clear_unpaid_obj(shkp, kickedobj);
for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
clear_unpaid(mtmp->minvent);
clear_unpaid(shkp, mtmp->minvent);
for (mtmp = migrating_mons; mtmp; mtmp = mtmp->nmon)
clear_unpaid(mtmp->minvent);
clear_unpaid(shkp, mtmp->minvent);
while ((obj = billobjs) != 0) {
obj_extract_self(obj);
@@ -575,7 +584,8 @@ char *enterstring;
if (!Deaf && !muteshk(shkp))
verbalize("Invisible customers are not welcome!");
else
pline("%s stands firm as if he knows you are there.", Shknam(shkp));
pline("%s stands firm as if %s knows you are there.",
Shknam(shkp), mhe(shkp));
return;
}
@@ -587,13 +597,14 @@ char *enterstring;
s_suffix(shkname(shkp)), shtypes[rt - SHOPBASE].name);
else
pline("%s seems %s over your return to %s %s!",
Shknam(shkp),
angrytexts[rn2(SIZE(angrytexts))],
mhis(shkp),
shtypes[rt - SHOPBASE].name);
Shknam(shkp),
angrytexts[rn2(SIZE(angrytexts))],
mhis(shkp),
shtypes[rt - SHOPBASE].name);
} else if (eshkp->robbed) {
if (!Deaf)
pline("%s mutters imprecations against shoplifters.", shkname(shkp));
pline("%s mutters imprecations against shoplifters.",
shkname(shkp));
else
pline("%s is combing through %s inventory list.",
Shknam(shkp),
@@ -601,8 +612,8 @@ char *enterstring;
} else {
if (!Deaf && !muteshk(shkp))
verbalize("%s, %s! Welcome%s to %s %s!", Hello(shkp), plname,
eshkp->visitct++ ? " again" : "", s_suffix(shkname(shkp)),
shtypes[rt - SHOPBASE].name);
eshkp->visitct++ ? " again" : "",
s_suffix(shkname(shkp)), shtypes[rt - SHOPBASE].name);
else
You("enter %s %s%s!",
s_suffix(shkname(shkp)),
@@ -691,10 +702,10 @@ struct obj *obj;
cad(FALSE));
else
pline("%s %s your pick!",
Shknam(shkp),
haseyes(shkp->data) ? "glares at"
: "is dismayed because of");
}
Shknam(shkp),
haseyes(shkp->data) ? "glares at"
: "is dismayed because of");
}
pickmovetime = moves;
}
}
@@ -801,11 +812,11 @@ register struct monst *mtmp;
struct monst *
shop_keeper(rmno)
register char rmno;
char rmno;
{
struct monst *shkp =
rmno >= ROOMOFFSET ? rooms[rmno - ROOMOFFSET].resident : 0;
struct monst *shkp;
shkp = (rmno >= ROOMOFFSET) ? rooms[rmno - ROOMOFFSET].resident : 0;
if (shkp) {
if (has_eshk(shkp)) {
if (NOTANGRY(shkp)) {
@@ -817,16 +828,18 @@ register char rmno;
}
} else {
/* would have segfaulted on ESHK dereference previously */
impossible(
"shopkeeper career change? (rmno=%d, ROOMOFFSET=%d, mnum=%d, %s)",
(int)rmno, ROOMOFFSET, shkp->mnum,
has_mname(shkp) ? MNAME(shkp) : "anonymous"
);
impossible("%s? (rmno=%d, rtype=%d, mnum=%d, \"%s\")",
shkp->isshk ? "shopkeeper career change"
: "shop resident not shopkeeper",
(int) rmno,
(int) rooms[rmno - ROOMOFFSET].rtype,
shkp->mnum,
/* [real shopkeeper name is kept in ESHK, not MNAME] */
has_mname(shkp) ? MNAME(shkp) : "anonymous");
/* not sure if this is appropriate, because it does nothing to
correct the underlying rooms[].resident issue but... */
return (struct monst *)0;
}
return (struct monst *) 0;
}
}
return shkp;
}
@@ -858,7 +871,7 @@ boolean silent;
} else
bp++;
}
if (obj->unpaid & !silent)
if (obj->unpaid && !silent)
pline("onbill: unpaid obj not on bill?");
return (struct bill_x *) 0;
}
@@ -1599,13 +1612,13 @@ boolean itemize;
ANGRY(shkp) ? "Pay" : "Please pay",
simpleonames(obj), /* short name suffices */
save_quan > 1L ? "these" : "this one");
} else {
pline("%s %s%s your bill for the other %s first.",
Shknam(shkp),
} else {
pline("%s %s%s your bill for the other %s first.",
Shknam(shkp),
ANGRY(shkp) ? "angrily " : "",
nolimbs(shkp->data) ? "motions to" : "points out",
simpleonames(obj));
}
nolimbs(shkp->data) ? "motions to" : "points out",
simpleonames(obj));
}
buy = PAY_SKIP; /* shk won't sell */
}
}
@@ -2189,12 +2202,12 @@ boolean quietly;
pline("%s seems %s that you want to sell that.",
Shknam(shkp),
(obj->spe < 7) ? "horrified" : "concerned");
} else {
} else {
verbalize("No thanks, I'd hang onto that if I were you.");
if (obj->spe < 7)
verbalize(
"You'll need %d%s candle%s to go along with it.",
(7 - obj->spe), (obj->spe > 0) ? " more" : "",
"You'll need %d%s candle%s to go along with it.",
(7 - obj->spe), (obj->spe > 0) ? " more" : "",
plur(7 - obj->spe));
/* [what if hero is already carrying enough candles?
should Izchak explain how to attach them instead?] */
@@ -2546,9 +2559,10 @@ boolean ininv, dummy, silent;
}
obj->quan = 1L; /* fool xname() into giving singular */
pline("%s %ld %s %s %s%s.\"", buf, ltmp, currency(ltmp),
(save_quan > 1L) ? "per" : (contentscount && !obj->unpaid)
? "for the contents of this"
: "for this",
(save_quan > 1L) ? "per"
: (contentscount && !obj->unpaid)
? "for the contents of this"
: "for this",
xname(obj),
(contentscount && obj->unpaid) ? and_its_contents : "");
obj->quan = save_quan;
@@ -2879,12 +2893,13 @@ xchar x, y;
offer = ltmp + cltmp;
/* get one case out of the way: nothing to sell, and no gold */
if (!isgold && ((offer + gltmp) == 0L || sell_how == SELL_DONTSELL)) {
if (!(isgold || cgold)
&& ((offer + gltmp) == 0L || sell_how == SELL_DONTSELL)) {
boolean unpaid = is_unpaid(obj);
if (container) {
dropped_container(obj, shkp, FALSE);
if (!obj->unpaid && !saleitem)
if (!obj->unpaid)
obj->no_charge = 1;
if (unpaid)
subfrombill(obj, shkp);
@@ -2955,11 +2970,11 @@ xchar x, y;
currency(eshkp->credit));
}
if (!offer) {
if (!offer || sell_how == SELL_DONTSELL) {
if (!isgold) {
if (container)
dropped_container(obj, shkp, FALSE);
if (!obj->unpaid && !saleitem)
if (!obj->unpaid)
obj->no_charge = 1;
subfrombill(obj, shkp);
}
@@ -3934,7 +3949,7 @@ boolean cant_mollify;
if (!Deaf && !muteshk(shkp)) {
You_hear("an angry voice:");
verbalize("Out of my way, scum!");
}
}
wait_synch();
#if defined(UNIX) || defined(VMS)
#if defined(SYSV) || defined(ULTRIX) || defined(VMS)
@@ -3959,26 +3974,21 @@ boolean cant_mollify;
} else if (pursue || uinshp || !um_dist(x, y, 1)) {
if (!Deaf)
verbalize("How dare you %s my %s?", dmgstr,
dugwall ? "shop" : "door");
dugwall ? "shop" : "door");
else
pline("%s is %s that you decided to %s %s %s!",
Shknam(shkp),
angrytexts[rn2(SIZE(angrytexts))],
dmgstr, mhis(shkp),
dugwall ? "shop" : "door");
Shknam(shkp), angrytexts[rn2(SIZE(angrytexts))],
dmgstr, mhis(shkp), dugwall ? "shop" : "door");
} else {
if (!Deaf) {
pline("%s shouts:", shkname(shkp));
verbalize("Who dared %s my %s?", dmgstr,
dugwall ? "shop" : "door");
} else {
} else {
pline("%s is %s that someone decided to %s %s %s!",
Shknam(shkp),
angrytexts[rn2(SIZE(angrytexts))],
dmgstr,
mhis(shkp),
dugwall ? "shop" : "door");
}
Shknam(shkp), angrytexts[rn2(SIZE(angrytexts))],
dmgstr, mhis(shkp), dugwall ? "shop" : "door");
}
}
hot_pursuit(shkp);
return;
@@ -4116,6 +4126,7 @@ long cost;
{
if (!rn2(3)) {
register int o, choice = rn2(5);
if (choice == 0)
choice = (cost < 100L ? 1 : cost < 500L ? 2 : 3);
switch (choice) {
@@ -4200,7 +4211,6 @@ struct monst *shkp;
else
pline("%s taps you on the %s.",
Shknam(shkp), body_part(ARM));
}
} else if (eshk->billct) {
register long total = addupbill(shkp) + eshk->debit;
@@ -4218,10 +4228,10 @@ struct monst *shkp;
pline("%s encourages you to use your %ld %s of credit.",
shkname(shkp), eshk->credit, currency(eshk->credit));
} else if (eshk->robbed) {
pline("%s %s about a recent robbery.",
Shknam(shkp),
(!Deaf && !muteshk(shkp)) ? "complains" : "indicates concern");
} else if ((shkmoney = money_cnt(shkp->minvent)) < 50) {
pline("%s %s about a recent robbery.",
Shknam(shkp),
(!Deaf && !muteshk(shkp)) ? "complains" : "indicates concern");
} else if ((shkmoney = money_cnt(shkp->minvent)) < 50L) {
pline("%s %s that business is bad.",
shkname(shkp),
(!Deaf && !muteshk(shkp)) ? "complains" : "indicates");
+28 -28
View File
@@ -6,6 +6,7 @@
#include "hack.h"
STATIC_DCL boolean FDECL(stock_room_goodpos, (struct mkroom *, int, int, int, int));
STATIC_DCL boolean FDECL(veggy_item, (struct obj * obj, int));
STATIC_DCL int NDECL(shkveg);
STATIC_DCL void FDECL(mkveggy_at, (int, int));
@@ -676,6 +677,24 @@ struct mkroom *sroom;
return sh;
}
STATIC_OVL boolean
stock_room_goodpos(sroom, rmno, sh, sx, sy)
struct mkroom *sroom;
int rmno, sh, sx,sy;
{
if (sroom->irregular) {
if (levl[sx][sy].edge
|| (int) levl[sx][sy].roomno != rmno
|| distmin(sx, sy, doors[sh].x, doors[sh].y) <= 1)
return FALSE;
} else if ((sx == sroom->lx && doors[sh].x == sx - 1)
|| (sx == sroom->hx && doors[sh].x == sx + 1)
|| (sy == sroom->ly && doors[sh].y == sy - 1)
|| (sy == sroom->hy && doors[sh].y == sy + 1))
return FALSE;
return TRUE;
}
/* stock a newly-created room with objects */
void
stock_room(shp_indx, sroom)
@@ -733,39 +752,20 @@ register struct mkroom *sroom;
* going to put stuff, randomly single out one in particular.
*/
for (sx = sroom->lx; sx <= sroom->hx; sx++)
for (sy = sroom->ly; sy <= sroom->hy; sy++) {
if (sroom->irregular) {
if (levl[sx][sy].edge
|| (int) levl[sx][sy].roomno != rmno
|| distmin(sx, sy, doors[sh].x, doors[sh].y) <= 1)
continue;
} else if ((sx == sroom->lx && doors[sh].x == sx - 1)
|| (sx == sroom->hx && doors[sh].x == sx + 1)
|| (sy == sroom->ly && doors[sh].y == sy - 1)
|| (sy == sroom->hy && doors[sh].y == sy + 1))
continue;
stockcount++;
}
for (sy = sroom->ly; sy <= sroom->hy; sy++)
if (stock_room_goodpos(sroom, rmno, sh, sx,sy))
stockcount++;
specialspot = rnd(stockcount);
stockcount = 0;
}
for (sx = sroom->lx; sx <= sroom->hx; sx++)
for (sy = sroom->ly; sy <= sroom->hy; sy++) {
if (sroom->irregular) {
if (levl[sx][sy].edge
|| (int) levl[sx][sy].roomno != rmno
|| distmin(sx, sy, doors[sh].x, doors[sh].y) <= 1)
continue;
} else if ((sx == sroom->lx && doors[sh].x == sx - 1)
|| (sx == sroom->hx && doors[sh].x == sx + 1)
|| (sy == sroom->ly && doors[sh].y == sy - 1)
|| (sy == sroom->hy && doors[sh].y == sy + 1))
continue;
stockcount++;
mkshobj_at(shp, sx, sy,
((stockcount) && (stockcount == specialspot)));
}
for (sy = sroom->ly; sy <= sroom->hy; sy++)
if (stock_room_goodpos(sroom, rmno, sh, sx,sy)) {
stockcount++;
mkshobj_at(shp, sx, sy,
((stockcount) && (stockcount == specialspot)));
}
/*
* Special monster placements (if any) should go here: that way,
+3 -1
View File
@@ -1,4 +1,4 @@
/* NetHack 3.6 sit.c $NHDT-Date: 1445906863 2015/10/27 00:47:43 $ $NHDT-Branch: master $:$NHDT-Revision: 1.51 $ */
/* NetHack 3.6 sit.c $NHDT-Date: 1458341129 2016/03/18 22:45:29 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.53 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
@@ -184,6 +184,7 @@ dosit()
if (u.uhp >= (u.uhpmax - 5))
u.uhpmax += 4;
u.uhp = u.uhpmax;
u.ucreamed = 0;
make_blinded(0L, TRUE);
make_sick(0L, (char *) 0, FALSE, SICK_ALL);
heal_legs();
@@ -225,6 +226,7 @@ dosit()
"A curse upon thee for sitting upon this most holy throne!");
if (Luck > 0) {
make_blinded(Blinded + rn1(100, 250), TRUE);
change_luck((Luck > 1) ? -rnd(2) : -1);
} else
rndcurse();
break;
+35 -20
View File
@@ -72,6 +72,7 @@ STATIC_DCL void FDECL(create_door, (room_door *, struct mkroom *));
STATIC_DCL void FDECL(create_trap, (trap *, struct mkroom *));
STATIC_DCL int FDECL(noncoalignment, (ALIGNTYP_P));
STATIC_DCL boolean FDECL(m_bad_boulder_spot, (int, int));
STATIC_DCL int FDECL(pm_to_humidity, (struct permonst *));
STATIC_DCL void FDECL(create_monster, (monster *, struct mkroom *));
STATIC_DCL void FDECL(create_object, (object *, struct mkroom *));
STATIC_DCL void FDECL(create_altar, (altar *, struct mkroom *));
@@ -611,8 +612,8 @@ schar filling;
if (level.flags.corrmaze)
levl[x][y].typ = STONE;
else
levl[x][y].typ =
(y < 2 || ((x % 2) && (y % 2))) ? STONE : filling;
levl[x][y].typ = (y < 2 || ((x % 2) && (y % 2))) ? STONE
: filling;
}
}
@@ -895,6 +896,8 @@ register int humidity;
|| typ == CORR)
return TRUE;
}
if ((humidity & SPACELOC) && SPACE_POS(levl[x][y].typ))
return TRUE;
if ((humidity & WET) && is_pool(x, y))
return TRUE;
if ((humidity & HOT) && is_lava(x, y))
@@ -1495,6 +1498,24 @@ int x, y;
return FALSE;
}
STATIC_OVL int
pm_to_humidity(pm)
struct permonst *pm;
{
int loc = DRY;
if (!pm)
return loc;
if (pm->mlet == S_EEL || amphibious(pm) || is_swimmer(pm))
loc = WET;
if (is_flyer(pm) || is_floater(pm))
loc |= (HOT | WET);
if (passes_walls(pm) || noncorporeal(pm))
loc |= SOLID;
if (flaming(pm))
loc |= HOT;
return loc;
}
STATIC_OVL void
create_monster(m, croom)
monster *m;
@@ -1543,15 +1564,7 @@ struct mkroom *croom;
pm = (struct permonst *) 0;
if (pm) {
int loc = DRY;
if (pm->mlet == S_EEL || amphibious(pm) || is_swimmer(pm))
loc = WET;
if (is_flyer(pm) || is_floater(pm))
loc |= (HOT | WET);
if (passes_walls(pm) || noncorporeal(pm))
loc |= SOLID;
if (flaming(pm))
loc |= HOT;
int loc = pm_to_humidity(pm);
/* If water-liking monster, first try is without DRY */
get_location_coord(&x, &y, loc | NO_LOC_WARN, croom, m->coord);
if (x == -1 && y == -1) {
@@ -4089,8 +4102,8 @@ struct opvar *ov;
my = ((y1 + y2) / 2);
} else {
do {
dx = (Rand() % rough) - (rough / 2);
dy = (Rand() % rough) - (rough / 2);
dx = rn2(rough) - (rough / 2);
dy = rn2(rough) - (rough / 2);
mx = ((x1 + x2) / 2) + dx;
my = ((y1 + y2) / 2) + dy;
} while ((mx > COLNO - 1 || mx < 0 || my < 0 || my > ROWNO - 1));
@@ -4747,7 +4760,8 @@ struct sp_coder *coder;
dy1 = (xchar) SP_REGION_Y1(OV_i(r));
dx2 = (xchar) SP_REGION_X2(OV_i(r));
dy2 = (xchar) SP_REGION_Y2(OV_i(r));
wallify_map(dx1 < 0 ? (xstart-1) : dx1, dy1 < 0 ? (ystart-1) : dy1,
wallify_map(dx1 < 0 ? (xstart - 1) : dx1,
dy1 < 0 ? (ystart - 1) : dy1,
dx2 < 0 ? (xstart + xsize + 1) : dx2,
dy2 < 0 ? (ystart + ysize + 1) : dy2);
break;
@@ -4846,7 +4860,7 @@ struct sp_coder *coder;
ystart = valign;
break;
}
if ((ystart < 0) || (ystart + ysize > ROWNO)) {
if (ystart < 0 || ystart + ysize > ROWNO) {
/* try to move the start a bit */
ystart += (ystart > 0) ? -2 : 2;
if (ysize == ROWNO)
@@ -4860,13 +4874,13 @@ struct sp_coder *coder;
xsize = COLNO - 1;
ysize = ROWNO;
} else {
xchar x, y;
xchar x, y, mptyp;
/* Load the map */
for (y = ystart; y < ystart + ysize; y++)
for (x = xstart; x < xstart + xsize; x++) {
xchar mptyp =
(mpmap->vardata.str[(y - ystart) * xsize + (x - xstart)]
- 1);
mptyp = (mpmap->vardata.str[(y - ystart) * xsize
+ (x - xstart)] - 1);
if (mptyp >= MAX_TYPE)
continue;
levl[x][y].typ = mptyp;
@@ -5907,7 +5921,8 @@ const char *name;
(void) dlb_fclose(fd);
goto give_up;
}
lvl = (sp_lev *) alloc(sizeof(sp_lev));
lvl = (sp_lev *) alloc(sizeof (sp_lev));
result = sp_level_loader(fd, lvl);
(void) dlb_fclose(fd);
if (result)
+2 -2
View File
@@ -866,8 +866,8 @@ int spell;
break;
case 7:
case 8:
make_stunned(old_conf + 2L * duration / 3L, FALSE); /* 20% */
make_confused(old_stun + duration / 3L, FALSE);
make_stunned(old_stun + 2L * duration / 3L, FALSE); /* 20% */
make_confused(old_conf + duration / 3L, FALSE);
break;
case 9:
make_stunned(old_stun + duration, FALSE); /* 10% */
+5 -4
View File
@@ -646,10 +646,11 @@ boolean verbosely;
if (mon->mhp > 0) {
mon->misc_worn_check &= ~obj->owornmask;
update_mon = TRUE;
/* don't charge for an owned saddle on dead steed (provided
that the hero is within the same shop at the time) */
} else if (mon->mtame && (obj->owornmask & W_SADDLE) && !obj->unpaid
&& costly_spot(omx, omy)
/* don't charge for an owned saddle on dead steed (provided
that the hero is within the same shop at the time) */
} else if (mon->mtame && (obj->owornmask & W_SADDLE) != 0L
&& !obj->unpaid && costly_spot(omx, omy)
/* being at costly_spot guarantees lev->roomno is not 0 */
&& index(in_rooms(u.ux, u.uy, SHOPBASE),
levl[omx][omy].roomno)) {
+3 -1
View File
@@ -128,7 +128,9 @@ unsigned entflags;
/* default to player's original monster type */
mdat = &mons[u.umonster];
}
fakemon.data = mdat; /* set up for goodpos */
fakemon = zeromonst;
set_mon_data(&fakemon, mdat, -1); /* set up for goodpos */
good_ptr = good;
range = 1;
/*
+18
View File
@@ -1533,6 +1533,7 @@ anything *arg;
panic("start_timer");
gnu = (timer_element *) alloc(sizeof(timer_element));
(void) memset((genericptr_t)gnu, 0, sizeof(timer_element));
gnu->next = 0;
gnu->tid = timer_id++;
gnu->timeout = monstermoves + when;
@@ -1998,6 +1999,23 @@ long adjust; /* how much to adjust timeout */
}
}
/* to support '#stats' wizard-mode command */
void
timer_stats(hdrfmt, hdrbuf, count, size)
const char *hdrfmt;
char *hdrbuf;
long *count, *size;
{
timer_element *te;
Sprintf(hdrbuf, hdrfmt, (long) sizeof (timer_element));
*count = *size = 0L;
for (te = timer_base; te; te = te->next) {
++*count;
*size += (long) sizeof *te;
}
}
/* reset all timers that are marked for reseting */
void
relink_timers(ghostly)
+74 -64
View File
@@ -1,4 +1,4 @@
/* NetHack 3.6 trap.c $NHDT-Date: 1454528963 2016/02/03 19:49:23 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.261 $ */
/* NetHack 3.6 trap.c $NHDT-Date: 1464138044 2016/05/25 01:00:44 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.272 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
@@ -197,6 +197,8 @@ int ef_flags;
if (check_grease && otmp->greased) {
grease_protect(otmp, ostr, victim);
return ER_GREASED;
} else if (!erosion_matters(otmp)) {
return ER_NOTHING;
} else if (!vulnerable || (otmp->oerodeproof && otmp->rknown)) {
if (flags.verbose && print && (uvictim || vismon))
pline("%s %s %s not affected by %s.",
@@ -309,12 +311,12 @@ struct monst *victim;
struct trap *
maketrap(x, y, typ)
register int x, y, typ;
int x, y, typ;
{
static union vlaunchinfo zero_vl;
register struct trap *ttmp;
register struct rm *lev;
boolean oldplace;
struct trap *ttmp;
struct rm *lev = &levl[x][y];
if ((ttmp = t_at(x, y)) != 0) {
if (ttmp->ttyp == MAGIC_PORTAL || ttmp->ttyp == VIBRATING_SQUARE)
@@ -327,13 +329,15 @@ register int x, y, typ;
&& typ != SPIKED_PIT)))
u.utrap = 0;
/* old <tx,ty> remain valid */
} else if (IS_FURNITURE(levl[x][y].typ)) {
} else if (IS_FURNITURE(lev->typ)
&& (!IS_GRAVE(lev->typ) || (typ != PIT && typ != HOLE))) {
/* no trap on top of furniture (caller usually screens the
location to inhibit this, but wizard mode wishing doesn't) */
return (struct trap *) 0;
} else {
oldplace = FALSE;
ttmp = newtrap();
(void) memset((genericptr_t)ttmp, 0, sizeof(struct trap));
ttmp->ntrap = 0;
ttmp->tx = x;
ttmp->ty = y;
@@ -399,7 +403,6 @@ register int x, y, typ;
/*FALLTHRU*/
case HOLE:
case TRAPDOOR:
lev = &levl[x][y];
if (*in_rooms(x, y, SHOPBASE)
&& (typ == HOLE || typ == TRAPDOOR
|| IS_DOOR(lev->typ) || IS_WALL(lev->typ)))
@@ -687,6 +690,7 @@ int *fail_reason;
which refers to "it" so needs to follow a message describing
the object ("the statue comes to life" one above) */
if (cause != ANIMATE_NORMAL && costly_spot(x, y)
&& (carried(statue) ? statue->unpaid : !statue->no_charge)
&& (shkp = shop_keeper(*in_rooms(x, y, SHOPBASE))) != 0
/* avoid charging for Manlobbi's statue of Manlobbi
if stone-to-flesh is used on petrified shopkeep */
@@ -791,6 +795,49 @@ struct obj *objchn, *saddle;
return FALSE;
}
/* monster or you go through and possibly destroy a web.
return TRUE if could go through. */
boolean
mu_maybe_destroy_web(mtmp, domsg, trap)
struct monst *mtmp;
boolean domsg;
struct trap *trap;
{
boolean isyou = (mtmp == &youmonst);
struct permonst *mptr = mtmp->data;
if (amorphous(mptr) || is_whirly(mptr) || flaming(mptr)
|| unsolid(mptr) || mptr == &mons[PM_GELATINOUS_CUBE]) {
xchar x = trap->tx;
xchar y = trap->ty;
if (flaming(mptr) || acidic(mptr)) {
if (domsg) {
if (isyou)
You("%s %s spider web!",
(flaming(mptr)) ? "burn" : "dissolve",
a_your[trap->madeby_u]);
else
pline("%s %s %s spider web!", Monnam(mtmp),
(flaming(mptr)) ? "burns" : "dissolves",
a_your[trap->madeby_u]);
}
deltrap(trap);
newsym(x, y);
return TRUE;
}
if (domsg) {
if (isyou)
You("flow through %s spider web.", a_your[trap->madeby_u]);
else {
pline("%s flows through %s spider web.", Monnam(mtmp),
a_your[trap->madeby_u]);
seetrap(trap);
}
}
return TRUE;
}
return FALSE;
}
void
dotrap(trap, trflags)
register struct trap *trap;
@@ -1195,23 +1242,8 @@ unsigned trflags;
case WEB: /* Our luckless player has stumbled into a web. */
feeltrap(trap);
if (amorphous(youmonst.data) || is_whirly(youmonst.data)
|| unsolid(youmonst.data)) {
if (acidic(youmonst.data) || u.umonnum == PM_GELATINOUS_CUBE
|| u.umonnum == PM_FIRE_ELEMENTAL) {
if (webmsgok)
You("%s %s spider web!",
(u.umonnum == PM_FIRE_ELEMENTAL) ? "burn"
: "dissolve",
a_your[trap->madeby_u]);
deltrap(trap);
newsym(u.ux, u.uy);
break;
}
if (webmsgok)
You("flow through %s spider web.", a_your[trap->madeby_u]);
if (mu_maybe_destroy_web(&youmonst, webmsgok, trap))
break;
}
if (webmaker(youmonst.data)) {
if (webmsgok)
pline(trap->madeby_u ? "You take a walk on your web."
@@ -2410,28 +2442,8 @@ register struct monst *mtmp;
/* Monster in a web. */
if (webmaker(mptr))
break;
if (amorphous(mptr) || is_whirly(mptr) || unsolid(mptr)) {
if (acidic(mptr) || mptr == &mons[PM_GELATINOUS_CUBE]
|| mptr == &mons[PM_FIRE_ELEMENTAL]
|| mptr == &mons[PM_FIRE_VORTEX]) {
if (in_sight)
pline("%s %s %s spider web!", Monnam(mtmp),
(mptr == &mons[PM_FIRE_ELEMENTAL]
|| mptr == &mons[PM_FIRE_VORTEX])
? "burns"
: "dissolves",
a_your[trap->madeby_u]);
deltrap(trap);
newsym(mtmp->mx, mtmp->my);
break;
}
if (in_sight) {
pline("%s flows through %s spider web.", Monnam(mtmp),
a_your[trap->madeby_u]);
seetrap(trap);
}
if (mu_maybe_destroy_web(mtmp, in_sight, trap))
break;
}
tear_web = FALSE;
switch (monsndx(mptr)) {
case PM_OWLBEAR: /* Eric Backus */
@@ -2521,7 +2533,8 @@ register struct monst *mtmp;
if (in_sight)
seetrap(trap);
if ((mtmp->mhp -= dmgval2) <= 0)
mtmp->mhp -= dmgval2;
if (mtmp->mhp <= 0)
monkilled(mtmp,
in_sight
? "compression from an anti-magic field"
@@ -2553,18 +2566,19 @@ register struct monst *mtmp;
}
} else if (in_sight) {
newsym(mtmp->mx, mtmp->my);
pline("KAABLAMM!!! %s triggers %s land mine!", Monnam(mtmp),
pline("%s%s triggers %s land mine!",
!Deaf ? "KAABLAMM!!! " : "", Monnam(mtmp),
a_your[trap->madeby_u]);
}
if (!in_sight)
if (!in_sight && !Deaf)
pline("Kaablamm! You hear an explosion in the distance!");
blow_up_landmine(trap);
/* explosion might have destroyed a drawbridge; don't
dish out more damage if monster is already dead */
if (mtmp->mhp <= 0
|| thitm(0, mtmp, (struct obj *) 0, rnd(16), FALSE))
|| thitm(0, mtmp, (struct obj *) 0, rnd(16), FALSE)) {
trapkilled = TRUE;
else {
} else {
/* monsters recursively fall into new pit */
if (mintrap(mtmp) == 2)
trapkilled = TRUE;
@@ -2668,7 +2682,7 @@ boolean byplayer;
pline("%s turns to stone.", Monnam(mon));
if (byplayer) {
stoned = TRUE;
xkilled(mon, 0);
xkilled(mon, XKILL_NOMSG);
} else
monstone(mon);
}
@@ -3874,7 +3888,8 @@ boolean force_failure;
if (ttype == BEAR_TRAP) {
if (mtmp->mtame)
abuse_dog(mtmp);
if ((mtmp->mhp -= rnd(4)) <= 0)
mtmp->mhp -= rnd(4);
if (mtmp->mhp <= 0)
killed(mtmp);
} else if (ttype == WEB) {
if (!webmaker(youmonst.data)) {
@@ -4524,7 +4539,7 @@ boolean *noticed; /* set to true iff hero notices the effect; */
--force_mintrap;
/* mon might now be on the migrating monsters list */
}
return TRUE;
return result;
}
/* only called when the player is doing something to the chest directly */
@@ -4605,16 +4620,11 @@ boolean disarm;
loss += stolen_value(obj, ox, oy, (boolean) shkp->mpeaceful,
TRUE);
delete_contents(obj);
/* we're about to delete all things at this location,
* which could include the ball & chain.
* If we attempt to call unpunish() in the
* for-loop below we can end up with otmp2
* being invalid once the chain is gone.
* Deal with ball & chain right now instead.
*/
if (Punished && !carried(uball)
&& ((uchain->ox == u.ux && uchain->oy == u.uy)
|| (uball->ox == u.ux && uball->oy == u.uy)))
/* unpunish() in advance if either ball or chain (or both)
is going to be destroyed */
if (Punished && ((uchain->ox == u.ux && uchain->oy == u.uy)
|| (uball->where == OBJ_FLOOR
&& uball->ox == u.ux && uball->oy == u.uy)))
unpunish();
for (otmp = level.objects[u.ux][u.uy]; otmp; otmp = otmp2) {
@@ -4935,9 +4945,9 @@ boolean nocorpse;
if (dam < 1)
dam = 1;
}
if ((mon->mhp -= dam) <= 0) {
int xx = mon->mx;
int yy = mon->my;
mon->mhp -= dam;
if (mon->mhp <= 0) {
int xx = mon->mx, yy = mon->my;
monkilled(mon, "", nocorpse ? -AD_RBRE : AD_PHYS);
if (mon->mhp <= 0) {
+30 -20
View File
@@ -1,4 +1,4 @@
/* NetHack 3.6 uhitm.c $NHDT-Date: 1456992470 2016/03/03 08:07:50 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.155 $ */
/* NetHack 3.6 uhitm.c $NHDT-Date: 1460103141 2016/04/08 08:12:21 $ $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. */
@@ -662,15 +662,19 @@ int thrown; /* HMON_xxx (0 => hand-to-hand, other => ranged) */
&& P_SKILL(wtype) >= P_SKILLED)
&& ((monwep = MON_WEP(mon)) != 0
&& !is_flimsy(monwep)
&& !obj_resists(
monwep, 50 + 15 * greatest_erosion(obj),
100))) {
&& !obj_resists(monwep,
50 + 15 * (greatest_erosion(obj)
- greatest_erosion(monwep)),
100))) {
/*
* 2.5% chance of shattering defender's weapon when
* using a two-handed weapon; less if uwep is rusted.
* [dieroll == 2 is most successful non-beheading or
* -bisecting hit, in case of special artifact damage;
* the percentage chance is (1/20)*(50/100).]
* If attacker's weapon is rustier than defender's,
* the obj_resists chance is increased so the shatter
* chance is decreased; if less rusty, then vice versa.
*/
setmnotwielded(mon, monwep);
mon->weapon_check = NEED_WEAPON;
@@ -1148,7 +1152,7 @@ int thrown; /* HMON_xxx (0 => hand-to-hand, other => ranged) */
if (poiskilled) {
pline_The("poison was deadly...");
if (!already_killed)
xkilled(mon, 0);
xkilled(mon, XKILL_NOMSG);
destroyed = TRUE; /* return FALSE; */
} else if (destroyed) {
if (!already_killed)
@@ -1467,7 +1471,7 @@ register struct attack *mattk;
if (pd == &mons[PM_STRAW_GOLEM] || pd == &mons[PM_PAPER_GOLEM]) {
if (!Blind)
pline("%s burns completely!", Monnam(mdef));
xkilled(mdef, 2);
xkilled(mdef, XKILL_NOMSG | XKILL_NOCORPSE);
tmp = 0;
break;
/* Don't return yet; keep hp<1 and tmp=0 for pet msg */
@@ -1585,7 +1589,7 @@ register struct attack *mattk;
if (!Blind)
pline("Some writing vanishes from %s head!",
s_suffix(mon_nam(mdef)));
xkilled(mdef, 0);
xkilled(mdef, XKILL_NOMSG);
/* Don't return yet; keep hp<1 and tmp=0 for pet msg */
} else {
mdef->mcan = 1;
@@ -1597,11 +1601,14 @@ register struct attack *mattk;
case AD_DRLI:
if (!negated && !rn2(3) && !resists_drli(mdef)) {
int xtmp = d(2, 6);
pline("%s suddenly seems weaker!", Monnam(mdef));
mdef->mhpmax -= xtmp;
if ((mdef->mhp -= xtmp) <= 0 || !mdef->m_lev) {
mdef->mhp -= xtmp;
/* !m_lev: level 0 monster is killed rather than drop to -1 */
if (mdef->mhp <= 0 && !mdef->m_lev) {
pline("%s dies!", Monnam(mdef));
xkilled(mdef, 0);
xkilled(mdef, XKILL_NOMSG);
} else
mdef->m_lev--;
tmp = 0;
@@ -1610,7 +1617,7 @@ register struct attack *mattk;
case AD_RUST:
if (pd == &mons[PM_IRON_GOLEM]) {
pline("%s falls to pieces!", Monnam(mdef));
xkilled(mdef, 0);
xkilled(mdef, XKILL_NOMSG);
}
erode_armor(mdef, ERODE_RUST);
tmp = 0;
@@ -1622,7 +1629,7 @@ register struct attack *mattk;
case AD_DCAY:
if (pd == &mons[PM_WOOD_GOLEM] || pd == &mons[PM_LEATHER_GOLEM]) {
pline("%s falls to pieces!", Monnam(mdef));
xkilled(mdef, 0);
xkilled(mdef, XKILL_NOMSG);
}
erode_armor(mdef, ERODE_ROT);
tmp = 0;
@@ -1762,15 +1769,16 @@ register struct attack *mattk;
}
mdef->mstrategy &= ~STRAT_WAITFORU; /* in case player is very fast */
if ((mdef->mhp -= tmp) < 1) {
mdef->mhp -= tmp;
if (mdef->mhp < 1) {
if (mdef->mtame && !cansee(mdef->mx, mdef->my)) {
You_feel("embarrassed for a moment.");
if (tmp)
xkilled(mdef, 0); /* !tmp but hp<1: already killed */
xkilled(mdef, XKILL_NOMSG); /* !tmp but hp<1: already killed */
} else if (!flags.verbose) {
You("destroy it!");
if (tmp)
xkilled(mdef, 0);
xkilled(mdef, XKILL_NOMSG);
} else if (tmp)
killed(mdef);
return 2;
@@ -1929,7 +1937,7 @@ register struct attack *mattk;
m_useup(mdef, otmp);
newuhs(FALSE);
xkilled(mdef, 2);
xkilled(mdef, XKILL_NOMSG | XKILL_NOCORPSE);
if (mdef->mhp > 0) { /* monster lifesaved */
You("hurriedly regurgitate the sizzling in your %s.",
body_part(STOMACH));
@@ -2038,7 +2046,8 @@ register struct attack *mattk;
break;
}
end_engulf();
if ((mdef->mhp -= dam) <= 0) {
mdef->mhp -= dam;
if (mdef->mhp <= 0) {
killed(mdef);
if (mdef->mhp <= 0) /* not lifesaved */
return 2;
@@ -2546,17 +2555,17 @@ struct attack *mattk; /* null means we find one internally */
break;
case AD_ACID:
if (!rn2(6)) {
(void) erode_obj(obj, NULL, ERODE_CORRODE, EF_NONE);
(void) erode_obj(obj, NULL, ERODE_CORRODE, EF_GREASE);
}
break;
case AD_RUST:
if (!mon->mcan) {
(void) erode_obj(obj, NULL, ERODE_RUST, EF_NONE);
(void) erode_obj(obj, (char *) 0, ERODE_RUST, EF_GREASE);
}
break;
case AD_CORR:
if (!mon->mcan) {
(void) erode_obj(obj, NULL, ERODE_CORRODE, EF_NONE);
(void) erode_obj(obj, (char *) 0, ERODE_CORRODE, EF_GREASE);
}
break;
case AD_ENCH:
@@ -2685,7 +2694,8 @@ int dmg;
{
pline("%s %s!", Monnam(mon),
(dmg > mon->mhp / 2) ? "wails in agony" : "cries out in pain");
if ((mon->mhp -= dmg) <= 0) {
mon->mhp -= dmg;
if (mon->mhp <= 0) {
if (context.mon_moving)
monkilled(mon, (char *) 0, AD_BLND);
else
+21 -18
View File
@@ -377,8 +377,8 @@ invault()
}
trycount = 5;
do {
getlin(Deaf ? "You are required to supply your name. -" :
"\"Hello stranger, who are you?\" -", buf);
getlin(Deaf ? "You are required to supply your name. -"
: "\"Hello stranger, who are you?\" -", buf);
(void) mungspaces(buf);
} while (!buf[0] && --trycount > 0);
@@ -392,10 +392,11 @@ invault()
|| !strcmpi(buf, "Creosote")) {
if (!mvitals[PM_CROESUS].died) {
if (Deaf) {
if (!Blind) pline("%s waves goodbye.", noit_Monnam(guard));
if (!Blind)
pline("%s waves goodbye.", noit_Monnam(guard));
} else {
verbalize(
"Oh, yes, of course. Sorry to have disturbed you.");
"Oh, yes, of course. Sorry to have disturbed you.");
}
mongone(guard);
} else {
@@ -403,10 +404,11 @@ invault()
if (Deaf) {
if (!Blind)
pline("%s mouths something and looks very angry!",
noit_Monnam(guard));
} else {
verbalize("Back from the dead, are you? I'll remedy that!");
}
noit_Monnam(guard));
} else {
verbalize(
"Back from the dead, are you? I'll remedy that!");
}
/* don't want guard to waste next turn wielding a weapon */
if (!MON_WEP(guard)) {
guard->weapon_check = NEED_HTH_WEAPON;
@@ -424,7 +426,7 @@ invault()
if (!umoney && !hidden_gold()) {
if (Deaf)
pline("%s stomps%s.", noit_Monnam(guard),
(Blind) ? "" : " and beckons");
(Blind) ? "" : " and beckons");
else
verbalize("Please follow me.");
} else {
@@ -432,20 +434,21 @@ invault()
if (Deaf) {
if (!Blind)
pline("%s glares at you%s.", noit_Monnam(guard),
invent ? "r stuff" : "");
invent ? "r stuff" : "");
} else {
verbalize("You have hidden gold.");
}
}
}
if (Deaf) {
if (!Blind)
pline("%s holds out %s palm and beckons with %s other hand.",
noit_Monnam(guard), mhis(guard), mhis(guard));
} else {
pline(
"%s holds out %s palm and beckons with %s other hand.",
noit_Monnam(guard), mhis(guard), mhis(guard));
} else {
verbalize(
"Most likely all your gold was stolen from this vault.");
verbalize("Please drop that gold and follow me.");
}
}
}
EGD(guard)->gdx = gx;
EGD(guard)->gdy = gy;
@@ -695,16 +698,16 @@ register struct monst *grd;
noit_Monnam(grd), mhis(grd));
} else {
verbalize("Drop all your gold, scoundrel!");
}
}
return 0;
} else {
if (Deaf) {
if (!Blind)
pline("%s rubs %s hands with enraged delight!",
noit_Monnam(grd), mhis(grd));
noit_Monnam(grd), mhis(grd));
} else {
verbalize("So be it, rogue!");
}
}
grd->mpeaceful = 0;
return -1;
}
+3 -1
View File
@@ -200,7 +200,9 @@ boolean
comp_times(filetime)
long filetime;
{
return (boolean) (filetime < BUILD_TIME);
/* BUILD_TIME is constant but might have L suffix rather than UL;
'filetime' is historically signed but ought to have been unsigned */
return (boolean) ((unsigned long) filetime < (unsigned long) BUILD_TIME);
}
#endif
+153 -44
View File
@@ -1,4 +1,4 @@
/* NetHack 3.6 wield.c $NHDT-Date: 1450577672 2015/12/20 02:14:32 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.48 $ */
/* NetHack 3.6 wield.c $NHDT-Date: 1461967849 2016/04/29 22:10: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. */
@@ -174,6 +174,10 @@ struct obj *wep;
* and the message must be before the death message and
* Lifesaved rewielding. Yet we want the message to
* say "weapon in hand", thus this kludge.
* [That comment is obsolete. It dates from the days (3.0)
* when unwielding Firebrand could cause hero to be burned
* to death in Hell due to loss of fire resistance.
* "Lifesaved re-wielding or re-wearing" is ancient history.]
*/
long dummy = wep->owornmask;
@@ -232,12 +236,16 @@ register struct obj *obj;
/*** Commands to change particular slot(s) ***/
static NEARDATA const char wield_objs[] = { ALL_CLASSES, ALLOW_NONE,
WEAPON_CLASS, TOOL_CLASS, 0 };
static NEARDATA const char ready_objs[] = { COIN_CLASS, ALL_CLASSES,
ALLOW_NONE, WEAPON_CLASS, 0 };
static NEARDATA const char bullets[] = /* (note: different from dothrow.c) */
{ COIN_CLASS, ALL_CLASSES, ALLOW_NONE, GEM_CLASS, WEAPON_CLASS, 0 };
static NEARDATA const char wield_objs[] = {
ALL_CLASSES, ALLOW_NONE, WEAPON_CLASS, TOOL_CLASS, 0
};
static NEARDATA const char ready_objs[] = {
ALLOW_COUNT, COIN_CLASS, ALL_CLASSES, ALLOW_NONE, WEAPON_CLASS, 0
};
static NEARDATA const char bullets[] = { /* (note: different from dothrow.c) */
ALLOW_COUNT, COIN_CLASS, ALL_CLASSES, ALLOW_NONE,
GEM_CLASS, WEAPON_CLASS, 0
};
int
dowield()
@@ -316,10 +324,10 @@ doswapweapon()
result = ready_weapon(oldswap);
/* Set your new secondary weapon */
if (uwep == oldwep)
if (uwep == oldwep) {
/* Wield failed for some reason */
setuswapwep(oldswap);
else {
} else {
setuswapwep(oldwep);
if (uswapwep)
prinv((char *) 0, uswapwep, 0L);
@@ -336,64 +344,165 @@ doswapweapon()
int
dowieldquiver()
{
register struct obj *newquiver;
const char *quivee_types =
(uslinging()
|| (uswapwep && objects[uswapwep->otyp].oc_skill == P_SLING))
? bullets
: ready_objs;
char qbuf[QBUFSZ];
struct obj *newquiver;
const char *quivee_types;
int res;
boolean finish_splitting = FALSE,
was_uwep = FALSE, was_twoweap = u.twoweap;
/* Since the quiver isn't in your hands, don't check cantwield(), */
/* will_weld(), touch_petrifies(), etc. */
multi = 0;
/* forget last splitobj() before calling getobj() with ALLOW_COUNT */
context.objsplit.child_oid = context.objsplit.parent_oid = 0;
/* Prompt for a new quiver */
if (!(newquiver = getobj(quivee_types, "ready")))
/* Prompt for a new quiver: "What do you want to ready?"
(Include gems/stones as likely candidates if either primary
or secondary weapon is a sling.) */
quivee_types = (uslinging()
|| (uswapwep
&& objects[uswapwep->otyp].oc_skill == P_SLING))
? bullets
: ready_objs;
newquiver = getobj(quivee_types, "ready");
if (!newquiver) {
/* Cancelled */
return 0;
/* Handle no object, or object in other slot */
/* Any type is okay, since we give no intrinsics anyways */
if (newquiver == &zeroobj) {
} else if (newquiver == &zeroobj) { /* no object */
/* Explicitly nothing */
if (uquiver) {
You("now have no ammunition readied.");
setuqwep(newquiver = (struct obj *) 0);
/* skip 'quivering: prinv()' */
setuqwep((struct obj *) 0);
} else {
You("already have no ammunition readied!");
return 0;
}
} else if (newquiver == uquiver) {
pline("That ammunition is already readied!");
return 0;
} else if (newquiver == uwep) {
/* Prevent accidentally readying the main weapon */
pline("%s already being used as a weapon!",
!is_plural(uwep) ? "That is" : "They are");
} else if (newquiver->o_id == context.objsplit.child_oid) {
/* if newquiver is the result of supplying a count to getobj()
we don't want to split something already in the quiver;
for any other item, we need to give it its own inventory slot */
if (uquiver && uquiver->o_id == context.objsplit.parent_oid) {
unsplitobj(newquiver);
goto already_quivered;
}
finish_splitting = TRUE;
} else if (newquiver == uquiver) {
already_quivered:
pline("That ammunition is already readied!");
return 0;
} else if (newquiver->owornmask & (W_ARMOR | W_ACCESSORY | W_SADDLE)) {
You("cannot ready that!");
return 0;
} else {
long dummy;
} else if (newquiver == uwep) {
int weld_res = !uwep->bknown;
/* Check if it's the secondary weapon */
if (newquiver == uswapwep) {
setuswapwep((struct obj *) 0);
untwoweapon();
if (welded(uwep)) {
weldmsg(uwep);
reset_remarm(); /* same as dowield() */
return weld_res;
}
/* Okay to put in quiver; print it */
dummy = newquiver->owornmask;
newquiver->owornmask |= W_QUIVER;
prinv((char *) 0, newquiver, 0L);
newquiver->owornmask = dummy;
/* offer to split stack if wielding more than 1 */
if (uwep->quan > 1L && inv_cnt(FALSE) < 52 && splittable(uwep)) {
Sprintf(qbuf, "You are wielding %ld %s. Ready %ld of them?",
uwep->quan, simpleonames(uwep), uwep->quan - 1L);
switch (ynq(qbuf)) {
case 'q':
return 0;
case 'y':
/* leave 1 wielded, split rest off and put into quiver */
newquiver = splitobj(uwep, uwep->quan - 1L);
finish_splitting = TRUE;
goto quivering;
default:
break;
}
Strcpy(qbuf, "Ready all of them instead?");
} else {
Sprintf(qbuf, "You are wielding %s. Ready %s instead?",
/* uwep->quan is 1, but name might be plural ('boots') */
!is_plural(uwep) ? "that" : "those",
!is_plural(uwep) ? "it" : "them");
}
/* require confirmation to ready the main weapon */
if (ynq(qbuf) != 'y') {
(void) Shk_Your(qbuf, uwep); /* replace qbuf[] contents */
pline("%s%s %s wielded.", qbuf,
simpleonames(uwep), otense(uwep, "remain"));
return 0;
}
/* quivering main weapon, so no longer wielding it */
setuwep((struct obj *) 0);
untwoweapon();
was_uwep = TRUE;
} else if (newquiver == uswapwep) {
if (uswapwep->quan > 1L && inv_cnt(FALSE) < 52
&& splittable(uswapwep)) {
Sprintf(qbuf, "%s %ld %s. Ready %ld of them?",
u.twoweap ? "You are dual wielding"
: "Your alternate weapon is",
uswapwep->quan, simpleonames(uswapwep),
uswapwep->quan - 1L);
switch (ynq(qbuf)) {
case 'q':
return 0;
case 'y':
/* leave 1 alt-wielded, split rest off and put into quiver */
newquiver = splitobj(uswapwep, uswapwep->quan - 1L);
finish_splitting = TRUE;
goto quivering;
default:
break;
}
Strcpy(qbuf, "Ready all of them instead?");
} else {
Sprintf(qbuf, "%s your %s weapon. Ready %s instead?",
!is_plural(uswapwep) ? "That is" : "Those are",
u.twoweap ? "second" : "alternate",
/* uswapwep->quan is 1, but name might be plural */
!is_plural(uswapwep) ? "it" : "them");
}
/* require confirmation to ready the alternate weapon */
if (ynq(qbuf) != 'y') {
(void) Shk_Your(qbuf, uswapwep); /* replace qbuf[] contents */
pline("%s%s %s %s.", qbuf,
simpleonames(uswapwep), otense(uswapwep, "remain"),
u.twoweap ? "wielded" : "as secondary weapon");
return 0;
}
/* quivering alternate weapon, so no more uswapwep */
setuswapwep((struct obj *) 0);
untwoweapon();
}
/* Finally, place it in the quiver */
quivering:
if (finish_splitting) {
freeinv(newquiver);
newquiver->nomerge = 1;
addinv(newquiver);
newquiver->nomerge = 0;
}
/* place item in quiver before printing so that inventory feedback
includes "(at the ready)" */
setuqwep(newquiver);
/* Take no time since this is a convenience slot */
return 0;
prinv((char *) 0, newquiver, 0L);
/* quiver is a convenience slot and manipulating it ordinarily
consumes no time, but unwielding primary or secondary weapon
should take time (perhaps we're adjacent to a rust monster
or disenchanter and want to hit it immediately, but not with
something we're wielding that's vulnerable to its damage) */
res = 0;
if (was_uwep) {
You("are now empty %s.", body_part(HANDED));
res = 1;
} else if (was_twoweap && !u.twoweap) {
You("are no longer wielding two weapons at once.");
res = 1;
}
return res;
}
/* used for #rub and for applying pick-axe, whip, grappling hook or polearm */
+8
View File
@@ -677,6 +677,14 @@ register xchar *nx, *ny;
: (y > 1 ? (y < ROWNO ? (rn2(3) - 1) : -rn2(2)) : rn2(2)));
}
/* for size_monst(cmd.c) to support #stats */
int
size_wseg(worm)
struct monst *worm;
{
return (int) (count_wsegs(worm) * sizeof (struct wseg));
}
/* count_wsegs()
* returns the number of segments that a worm has.
*/
+2 -2
View File
@@ -128,12 +128,12 @@ register struct obj *pen;
if (Blind) {
if (!paper->dknown) {
You("don't know if that %s is blank or not.", typeword);
return 1;
return 0;
} else if (paper->oclass == SPBOOK_CLASS) {
/* can't write a magic book while blind */
pline("%s can't create braille text.",
upstart(ysimple_name(pen)));
return 1;
return 0;
}
}
paper->dknown = 1;
+139 -93
View File
@@ -1,4 +1,4 @@
/* NetHack 3.6 zap.c $NHDT-Date: 1456528600 2016/02/26 23:16:40 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.247 $ */
/* NetHack 3.6 zap.c $NHDT-Date: 1464163779 2016/05/25 08:09:39 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.258 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
@@ -221,11 +221,17 @@ struct obj *otmp;
it guard against involuntary polymorph attacks too... */
shieldeff(mtmp->mx, mtmp->my);
} else if (!resist(mtmp, otmp->oclass, 0, NOTELL)) {
boolean polyspot = (otyp != POT_POLYMORPH),
give_msg = (!Hallucination
&& (canseemon(mtmp)
|| (u.uswallow && mtmp == u.ustuck)));
/* dropped inventory (due to death by system shock,
or loss of wielded weapon and/or worn armor due to
limitations of new shape) won't be hit by this zap */
for (obj = mtmp->minvent; obj; obj = obj->nobj)
bypass_obj(obj);
if (polyspot)
for (obj = mtmp->minvent; obj; obj = obj->nobj)
bypass_obj(obj);
/* natural shapechangers aren't affected by system shock
(unless protection from shapechangers is interfering
with their metabolism...) */
@@ -236,10 +242,17 @@ struct obj *otmp;
}
/* context.bypasses = TRUE; ## for make_corpse() */
/* no corpse after system shock */
xkilled(mtmp, 3);
xkilled(mtmp, XKILL_GIVEMSG | XKILL_NOCORPSE);
} else if (newcham(mtmp, (struct permonst *) 0,
(otyp != POT_POLYMORPH), FALSE)) {
if (!Hallucination && canspotmon(mtmp))
polyspot, give_msg) != 0
/* if shapechange failed because there aren't
enough eligible candidates (most likely for
vampshifter), try reverting to original form */
|| (mtmp->cham >= LOW_PM
&& newcham(mtmp, &mons[mtmp->cham],
polyspot, give_msg) != 0)) {
if (give_msg && (canspotmon(mtmp)
|| (u.uswallow && mtmp == u.ustuck)))
learn_it = TRUE;
}
}
@@ -388,14 +401,15 @@ struct obj *otmp;
dmg *= 2;
if (otyp == SPE_DRAIN_LIFE)
dmg = spell_damage_bonus(dmg);
if (resists_drli(mtmp))
if (resists_drli(mtmp)) {
shieldeff(mtmp->mx, mtmp->my);
else if (!resist(mtmp, otmp->oclass, dmg, NOTELL) && mtmp->mhp > 0) {
} else if (!resist(mtmp, otmp->oclass, dmg, NOTELL) && mtmp->mhp > 0) {
mtmp->mhp -= dmg;
mtmp->mhpmax -= dmg;
if (mtmp->mhp <= 0 || mtmp->mhpmax <= 0 || mtmp->m_lev < 1)
xkilled(mtmp, 1);
else {
/* die if already level 0, regardless of hit points */
if (mtmp->mhp <= 0 || mtmp->mhpmax <= 0 || mtmp->m_lev < 1) {
killed(mtmp);
} else {
mtmp->m_lev--;
if (canseemon(mtmp))
pline("%s suddenly seems weaker!", Monnam(mtmp));
@@ -453,7 +467,8 @@ struct monst *mtmp;
otmp->cknown = 1;
}
}
(void) display_minventory(mtmp, MINV_ALL | MINV_NOLET, (char *) 0);
(void) display_minventory(mtmp, MINV_ALL | MINV_NOLET | PICK_NONE,
(char *) 0);
} else {
pline("%s is not carrying anything%s.", noit_Monnam(mtmp),
(u.uswallow && mtmp == u.ustuck) ? " besides you" : "");
@@ -562,9 +577,9 @@ coord *cc;
if (mtmp->m_id) {
mtmp2->m_id = mtmp->m_id;
/* might be bringing quest leader back to life */
if (quest_status.leader_is_dead &&
if (quest_status.leader_is_dead
/* leader_is_dead implies leader_m_id is valid */
mtmp2->m_id == quest_status.leader_m_id)
&& mtmp2->m_id == quest_status.leader_m_id)
quest_status.leader_is_dead = FALSE;
}
mtmp2->mx = mtmp->mx;
@@ -600,6 +615,16 @@ coord *cc;
mtmp2->mblinded = 0;
mtmp2->mstun = 0;
mtmp2->mconf = 0;
/* when traits are for a shopeekper, dummy monster 'mtmp' won't
have necessary eshk data for replmon() -> replshk() */
if (mtmp2->isshk) {
neweshk(mtmp);
*ESHK(mtmp) = *ESHK(mtmp2);
if (ESHK(mtmp2)->bill_p != 0
&& ESHK(mtmp2)->bill_p != (struct bill_x *) -1000)
ESHK(mtmp)->bill_p = &(ESHK(mtmp)->bill[0]);
mtmp->isshk = 1;
}
replmon(mtmp, mtmp2);
newsym(mtmp2->mx, mtmp2->my); /* Might now be invisible */
@@ -648,6 +673,8 @@ int *container_nesting;
/*
* Attempt to revive the given corpse, return the revived monster if
* successful. Note: this does NOT use up the corpse if it fails.
* If corpse->quan is more than 1, only one corpse will be affected
* and only one monster will be resurrected.
*/
struct monst *
revive(corpse, by_hero)
@@ -659,6 +686,7 @@ boolean by_hero;
struct obj *container;
coord xy;
xchar x, y;
boolean one_of;
int montype, container_nesting = 0;
if (corpse->otyp != CORPSE) {
@@ -693,16 +721,16 @@ boolean by_hero;
break; /* x,y are 0 */
}
}
if (!x || !y ||
if (!x || !y
/* Rules for revival from containers:
- the container cannot be locked
- the container cannot be heavily nested (>2 is arbitrary)
- the container cannot be a statue or bag of holding
(except in very rare cases for the latter)
*/
(container && (container->olocked || container_nesting > 2
|| container->otyp == STATUE
|| (container->otyp == BAG_OF_HOLDING && rn2(40)))))
* - the container cannot be locked
* - the container cannot be heavily nested (>2 is arbitrary)
* - the container cannot be a statue or bag of holding
* (except in very rare cases for the latter)
*/
|| (container && (container->olocked || container_nesting > 2
|| container->otyp == STATUE
|| (container->otyp == BAG_OF_HOLDING && rn2(40)))))
return (struct monst *) 0;
/* record the object's location now that we're sure where it is */
@@ -765,24 +793,33 @@ boolean by_hero;
if (mtmp->m_ap_type)
seemimic(mtmp);
one_of = (corpse->quan > 1L);
if (one_of)
corpse = splitobj(corpse, 1L);
/* if this is caused by the hero there might be a shop charge */
if (by_hero) {
struct monst *shkp = 0;
x = corpse->ox, y = corpse->oy;
if (costly_spot(x, y))
if (costly_spot(x, y)
&& (carried(corpse) ? corpse->unpaid : !corpse->no_charge))
shkp = shop_keeper(*in_rooms(x, y, SHOPBASE));
if (cansee(x, y)) {
char buf[BUFSZ];
unsigned pfx = CXN_PFX_THE;
Strcpy(buf, (corpse->quan > 1L) ? "one of " : "");
Strcpy(buf, one_of ? "one of " : "");
if (carried(corpse) && !corpse->unpaid) {
Strcat(buf, "your ");
pfx = CXN_NO_PFX;
}
if (one_of)
corpse->quan++; /* force plural */
Strcat(buf, corpse_xname(corpse, (const char *) 0, pfx));
if (one_of) /* could be simplified to ''corpse->quan = 1L;'' */
corpse->quan--;
pline("%s glows iridescently.", upstart(buf));
} else if (shkp) {
/* need some prior description of the corpse since
@@ -890,10 +927,11 @@ struct monst *mon;
struct monst *mtmp2;
char owner[BUFSZ], corpse[BUFSZ];
boolean youseeit;
int once = 0, res = 0;
int res = 0;
youseeit = (mon == &youmonst) ? TRUE : canseemon(mon);
otmp2 = (mon == &youmonst) ? invent : mon->minvent;
owner[0] = corpse[0] = '\0'; /* lint suppression */
while ((otmp = otmp2) != 0) {
otmp2 = otmp->nobj;
@@ -902,19 +940,18 @@ struct monst *mon;
if (otmp->otyp != CORPSE)
continue;
/* save the name; the object is liable to go away */
if (youseeit)
if (youseeit) {
Strcpy(corpse,
corpse_xname(otmp, (const char *) 0, CXN_SINGULAR));
Shk_Your(owner, otmp); /* includes a trailing space */
}
/* for a merged group, only one is revived; should this be fixed? */
/* for a stack, only one is revived */
if ((mtmp2 = revive(otmp, !context.mon_moving)) != 0) {
++res;
if (youseeit) {
if (!once++)
Strcpy(owner, (mon == &youmonst) ? "Your"
: s_suffix(Monnam(mon)));
pline("%s %s suddenly comes alive!", owner, corpse);
} else if (canseemon(mtmp2))
if (youseeit)
pline("%s%s suddenly comes alive!", owner, corpse);
else if (canseemon(mtmp2))
pline("%s suddenly appears!", Amonnam(mtmp2));
}
}
@@ -1423,14 +1460,15 @@ int id;
otmp->cursed = obj->cursed;
otmp->blessed = obj->blessed;
otmp->oeroded = obj->oeroded;
otmp->oeroded2 = obj->oeroded2;
if (!is_flammable(otmp) && !is_rustprone(otmp))
otmp->oeroded = 0;
if (!is_corrodeable(otmp) && !is_rottable(otmp))
otmp->oeroded2 = 0;
if (is_damageable(otmp))
otmp->oerodeproof = obj->oerodeproof;
if (erosion_matters(otmp)) {
if (is_flammable(otmp) || is_rustprone(otmp))
otmp->oeroded = obj->oeroded;
if (is_corrodeable(otmp) || is_rottable(otmp))
otmp->oeroded2 = obj->oeroded2;
if (is_damageable(otmp))
otmp->oerodeproof = obj->oerodeproof;
}
/* Keep chest/box traps and poisoned ammo if we may */
if (obj->otrapped && Is_box(otmp))
@@ -1586,9 +1624,9 @@ int id;
if (*u.ushops
&& *in_rooms(u.ux, u.uy, 0)
== *in_rooms(shkp->mx, shkp->my, 0)
&& !costly_spot(u.ux, u.uy))
&& !costly_spot(u.ux, u.uy)) {
make_angry_shk(shkp, ox, oy);
else {
} else {
pline("%s gets angry!", Monnam(shkp));
hot_pursuit(shkp);
}
@@ -1607,7 +1645,7 @@ struct obj *obj;
{
int res = 1; /* affected object by default */
struct permonst *ptr;
struct monst *mon;
struct monst *mon, *shkp;
struct obj *item;
xchar oox, ooy;
boolean smell = FALSE, golem_xform = FALSE;
@@ -1638,19 +1676,18 @@ struct obj *obj;
break;
}
if (obj->otyp == STATUE) {
/* animate_statue() forces all golems to become flesh golems
*/
/* animate_statue() forces all golems to become flesh golems */
mon = animate_statue(obj, oox, ooy, ANIMATE_SPELL, (int *) 0);
} else { /* (obj->otyp == FIGURINE) */
if (golem_xform)
ptr = &mons[PM_FLESH_GOLEM];
mon = makemon(ptr, oox, ooy, NO_MINVENT);
if (mon) {
if (costly_spot(oox, ooy) && !obj->no_charge) {
if (costly_spot(u.ux, u.uy))
addtobill(obj, carried(obj), FALSE, FALSE);
else
stolen_value(obj, oox, ooy, TRUE, FALSE);
if (costly_spot(oox, ooy)
&& (carried(obj) ? obj->unpaid : !obj->no_charge)) {
shkp = shop_keeper(*in_rooms(oox, ooy, SHOPBASE));
stolen_value(obj, oox, ooy,
(shkp && shkp->mpeaceful), FALSE);
}
if (obj->timed)
obj_stop_timers(obj);
@@ -2119,6 +2156,7 @@ dozap()
&& !(objects[obj->otyp].oc_dir == NODIR)) {
if ((damage = zapyourself(obj, TRUE)) != 0) {
char buf[BUFSZ];
Sprintf(buf, "zapped %sself with a wand", uhim());
losehp(Maybe_Half_Phys(damage), buf, NO_KILLER_PREFIX);
}
@@ -2678,10 +2716,10 @@ struct obj *obj; /* wand or spell */
if (is_db_wall(x, y) && find_drawbridge(&xx, &yy)) {
open_drawbridge(xx, yy);
disclose = TRUE;
} else if (u.dz > 0 && (x == xdnstair && y == ydnstair) &&
} else if (u.dz > 0 && (x == xdnstair && y == ydnstair)
/* can't use the stairs down to quest level 2 until
leader "unlocks" them; give feedback if you try */
on_level(&u.uz, &qstart_level) && !ok_to_quest()) {
&& on_level(&u.uz, &qstart_level) && !ok_to_quest()) {
pline_The("stairs seem to ripple momentarily.");
disclose = TRUE;
}
@@ -3100,7 +3138,7 @@ struct obj **pobj; /* object tossed/used, set to NULL
}
if (is_pick(obj) && inside_shop(x, y)
&& (mtmp = shkcatch(obj, x, y))) {
&& (mtmp = shkcatch(obj, x, y)) != 0) {
tmp_at(DISP_END, 0);
return mtmp;
}
@@ -3109,9 +3147,9 @@ struct obj **pobj; /* object tossed/used, set to NULL
/* iron bars will block anything big enough */
if ((weapon == THROWN_WEAPON || weapon == KICKED_WEAPON)
&& typ == IRONBARS && hits_bars(pobj, x - ddx, y - ddy,
bhitpos.x, bhitpos.y,
point_blank ? 0 : !rn2(5), 1)) {
&& typ == IRONBARS
&& hits_bars(pobj, x - ddx, y - ddy, bhitpos.x, bhitpos.y,
point_blank ? 0 : !rn2(5), 1)) {
/* caveat: obj might now be null... */
obj = *pobj;
bhitpos.x -= ddx;
@@ -3286,6 +3324,7 @@ struct obj **pobj; /* object tossed/used, set to NULL
&& obj->otyp == HEAVY_IRON_BALL) {
struct obj *bobj;
struct trap *t;
if ((bobj = sobj_at(BOULDER, x, y)) != 0) {
if (cansee(x, y))
pline("%s hits %s.", The(distant_name(obj, xname)),
@@ -3404,7 +3443,8 @@ int dx, dy;
return (struct monst *) 0;
}
/* used by buzz(); also used by munslime(muse.c); returns damage to mon */
/* used by buzz(); also used by munslime(muse.c); returns damage applied
to mon; note: caller is responsible for killing mon if damage is fatal */
int
zhitm(mon, type, nd, ootmp)
register struct monst *mon;
@@ -3826,7 +3866,7 @@ const char *fltxt;
if (type < 0)
monkilled(mon, (char *) 0, -AD_RBRE);
else
xkilled(mon, 2);
xkilled(mon, XKILL_NOMSG | XKILL_NOCORPSE);
}
/*
@@ -3845,7 +3885,6 @@ register xchar sx, sy;
register int dx, dy;
{
int range, abstype = abs(type) % 10;
struct rm *lev;
register xchar lsx, lsy;
struct monst *mon;
coord save_bhitpos;
@@ -3889,23 +3928,24 @@ register int dx, dy;
sx += dx;
lsy = sy;
sy += dy;
if (isok(sx, sy) && (lev = &levl[sx][sy])->typ) {
mon = m_at(sx, sy);
if (cansee(sx, sy)) {
/* reveal/unreveal invisible monsters before tmp_at() */
if (mon && !canspotmon(mon))
map_invisible(sx, sy);
else if (!mon && glyph_is_invisible(levl[sx][sy].glyph)) {
unmap_object(sx, sy);
newsym(sx, sy);
}
if (ZAP_POS(lev->typ) || (isok(lsx, lsy) && cansee(lsx, lsy)))
tmp_at(sx, sy);
delay_output(); /* wait a little */
}
} else
if (!isok(sx, sy) || levl[sx][sy].typ == STONE)
goto make_bounce;
mon = m_at(sx, sy);
if (cansee(sx, sy)) {
/* reveal/unreveal invisible monsters before tmp_at() */
if (mon && !canspotmon(mon))
map_invisible(sx, sy);
else if (!mon && glyph_is_invisible(levl[sx][sy].glyph)) {
unmap_object(sx, sy);
newsym(sx, sy);
}
if (ZAP_POS(levl[sx][sy].typ)
|| (isok(lsx, lsy) && cansee(lsx, lsy)))
tmp_at(sx, sy);
delay_output(); /* wait a little */
}
/* hit() and miss() need bhitpos to match the target */
bhitpos.x = sx, bhitpos.y = sy;
/* Fireballs only damage when they explode */
@@ -4017,24 +4057,28 @@ register int dx, dy;
nomul(0);
}
if (!ZAP_POS(lev->typ) || (closed_door(sx, sy) && (range >= 0))) {
if (!ZAP_POS(levl[sx][sy].typ)
|| (closed_door(sx, sy) && range >= 0)) {
int bounce;
uchar rmn;
boolean fireball;
make_bounce:
if (type == ZT_SPELL(ZT_FIRE)) {
sx = lsx;
sy = lsy;
break; /* fireballs explode before the wall */
}
bounce = 0;
range--;
if (range && isok(lsx, lsy) && cansee(lsx, lsy)) {
pline("%s %s!", The(fltxt),
Is_airlevel(&u.uz)
? "vanishes into the aether"
: "bounces");
if (Is_airlevel(&u.uz)) goto get_out_buzz;
fireball = (type == ZT_SPELL(ZT_FIRE));
if ((--range > 0 && isok(lsx, lsy) && cansee(lsx, lsy))
|| fireball) {
if (Is_airlevel(&u.uz)) { /* nothing to bounce off of */
pline_The("%s vanishes into the aether!", fltxt);
if (fireball)
type = ZT_WAND(ZT_FIRE); /* skip pending fireball */
break;
} else if (fireball) {
sx = lsx;
sy = lsy;
break; /* fireballs explode before the obstacle */
} else
pline_The("%s bounces!", fltxt);
}
if (!dx || !dy || !rn2(20)) {
dx = -dx;
@@ -4069,7 +4113,6 @@ register int dx, dy;
tmp_at(DISP_END, 0);
if (type == ZT_SPELL(ZT_FIRE))
explode(sx, sy, type, d(12, 6), 0, EXPL_FIERY);
get_out_buzz:
if (shopdamage)
pay_for_damage(abstype == ZT_FIRE
? "burn away"
@@ -4686,9 +4729,12 @@ register int osym, dmgtyp;
if (!cnt)
continue;
mult = (cnt == quan)
? (quan > 1) ? "All of your " : "Your"
: (cnt == 1L) ? "One of your" : "Some of your";
mult = (cnt == 1L)
? (quan == 1L) ? "Your" /* 1 of 1 */
: "One of your" /* 1 of N */
: (cnt < quan) ? "Some of your" /* n of N */
: (quan == 2L) ? "Both of your" /* 2 of 2 */
: "All of your"; /* N of N */
pline("%s %s %s!", mult, xname(obj),
destroy_strings[dindx][(cnt > 1L)]);
if (osym == POTION_CLASS && dmgtyp != AD_COLD) {
+1613
View File
File diff suppressed because it is too large Load Diff
+39 -21
View File
@@ -1,5 +1,5 @@
# NetHack Makefile.
# NetHack 3.6 Makefile.src $NHDT-Date: 1447313972 2015/11/12 07:39:32 $ $NHDT-Branch: master $:$NHDT-Revision: 1.45 $
# NetHack 3.6 Makefile.src $NHDT-Date: 1459122529 2016/03/27 23:48:49 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.46 $
# Root of source tree:
NHSROOT=..
@@ -167,6 +167,11 @@ CXX=g++
#CXX=arm-linux-g++
#LINK=arm-linux-gcc
# we specify C preprocessor flags via CFLAGS; files built with default rules
# might include $(CPPFLAGS) which could get a value from user's environment;
# we avoid that by forcing it empty rather than by overriding default rules
CPPFLAGS =
# file for regular expression matching
REGEXOBJ = posixregex.o
#REGEXOBJ = pmatchregex.o
@@ -333,11 +338,11 @@ HACKCSRC = allmain.c alloc.c apply.c artifact.c attrib.c ball.c bones.c \
mkmaze.c mkobj.c mkroom.c mon.c mondata.c monmove.c monst.c \
mplayer.c mthrowu.c muse.c music.c o_init.c objects.c objnam.c \
options.c pager.c pickup.c pline.c polyself.c potion.c pray.c \
priest.c quest.c questpgr.c read.c rect.c region.c restore.c rip.c \
rnd.c role.c rumors.c save.c shk.c shknam.c sit.c sounds.c sp_lev.c \
spell.c steal.c steed.c sys.c teleport.c timeout.c topten.c track.c \
trap.c \
u_init.c uhitm.c vault.c version.c vision.c weapon.c were.c wield.c \
priest.c quest.c questpgr.c read.c rect.c region.c restore.c \
rip.c rnd.c role.c rumors.c save.c shk.c shknam.c sit.c sounds.c \
sp_lev.c spell.c steal.c steed.c sys.c teleport.c timeout.c \
topten.c track.c trap.c u_init.c \
uhitm.c vault.c version.c vision.c weapon.c were.c wield.c \
windows.c wizard.c worm.c worn.c write.c zap.c
# all operating-system-dependent .c (for dependencies and such)
@@ -347,6 +352,7 @@ SYSCSRC = ../sys/atari/tos.c ../sys/share/pcmain.c ../sys/share/pcsys.c \
../sys/share/random.c \
../sys/share/ioctl.c ../sys/share/unixtty.c ../sys/unix/unixmain.c \
../sys/unix/unixunix.c ../sys/unix/unixres.c ../sys/be/bemain.c
SYSCXXSRC = ../sys/share/cppregex.cpp
# generated source files (tile.c is handled separately via WINxxxSRC)
GENCSRC = monstr.c vis_tab.c #tile.c
@@ -357,9 +363,9 @@ WINCSRC = $(WINTTYSRC) $(WINX11SRC) $(WINGNOMESRC) $(WINGEMSRC)
WINCXXSRC = $(WINQTSRC) $(WINBESRC)
# Files for window system chaining. Requires SYSCF; include via HINTSRC/HINTOBJ
CHAINSRC=../win/chain/wc_chainin.c ../win/chain/wc_chainout.c \
../win/chain/wc_trace.c
CHAINOBJ=wc_chainin.o wc_chainout.o wc_trace.o
CHAINSRC = ../win/chain/wc_chainin.c ../win/chain/wc_chainout.c \
../win/chain/wc_trace.c
CHAINOBJ = wc_chainin.o wc_chainout.o wc_trace.o
# .c files for this version (for date.h)
VERSOURCES = $(HACKCSRC) $(SYSSRC) $(WINSRC) $(CHAINSRC) $(GENCSRC)
@@ -378,9 +384,9 @@ HACKINCL = align.h amiconf.h artifact.h artilist.h attrib.h beconf.h botl.h \
global.h hack.h lev.h lint.h macconf.h mextra.h mfndpos.h micro.h \
mkroom.h \
monattk.h mondata.h monflag.h monst.h monsym.h obj.h objclass.h \
os2conf.h patchlevel.h pcconf.h permonst.h prop.h rect.h region.h rm.h \
sp_lev.h spell.h sys.h system.h tcap.h timeout.h tosconf.h tradstdc.h \
trampoli.h trap.h unixconf.h vision.h vmsconf.h wintty.h \
os2conf.h patchlevel.h pcconf.h permonst.h prop.h rect.h region.h \
rm.h sp_lev.h spell.h sys.h system.h tcap.h timeout.h tosconf.h \
tradstdc.h trampoli.h trap.h unixconf.h vision.h vmsconf.h wintty.h \
winX.h winprocs.h wintype.h you.h youprop.h
HSOURCES = $(HACKINCL) date.h onames.h pm.h vis_tab.h\
@@ -490,23 +496,33 @@ qt_win.moc: ../include/qt_win.h
qttableview.moc: ../include/qttableview.h
$(QTDIR)/bin/moc -o qttableview.moc ../include/qttableview.h
$(MAKEDEFS): ../util/makedefs.c $(CONFIG_H) ../include/permonst.h \
# build monst.o and objects.o before executing '$(MAKE) makedefs'
$(MAKEDEFS): $(FIRSTOBJ) \
../util/makedefs.c $(CONFIG_H) ../include/permonst.h \
../include/objclass.h ../include/monsym.h \
../include/artilist.h ../include/dungeon.h ../include/obj.h \
../include/monst.h ../include/you.h ../include/flag.h \
../include/dlb.h ../include/patchlevel.h ../include/qtext.h
@( cd ../util ; $(MAKE) makedefs)
@( cd ../util ; $(MAKE) makedefs )
# Source files created by 'makedefs' at build time.
# Each is given an artificial dependency upon the one before
# so that parallel makes will have to build them sequentially.
# (More for documentation than effect; 'make' should know not
# to try to build $(MAKEDEFS) for bar.h while it is in the
# process of building it for foo.h.)
../include/onames.h: $(MAKEDEFS)
@( cd ../util ; $(MAKE) ../include/onames.h )
../include/pm.h: $(MAKEDEFS)
../include/pm.h: $(MAKEDEFS) ../include/onames.h
@( cd ../util ; $(MAKE) ../include/pm.h )
monstr.c: $(MAKEDEFS)
monstr.c: $(MAKEDEFS) ../include/pm.h
@( cd ../util ; $(MAKE) ../src/monstr.c )
../include/vis_tab.h: $(MAKEDEFS)
../include/vis_tab.h: $(MAKEDEFS) monstr.c
@( cd ../util ; $(MAKE) ../include/vis_tab.h )
# makedefs -z makes both vis_tab.h and vis_tab.c, but writes the .h first
vis_tab.c: ../include/vis_tab.h
# Created at build time for configurations which support tiles,
# but not by makedefs so not connected to the others.
tile.c: ../win/share/tilemap.c $(HACK_H)
@( cd ../util ; $(MAKE) ../src/tile.c )
@@ -551,11 +567,11 @@ spotless: clean
depend: ../sys/unix/depend.awk \
$(SYSCSRC) $(WINCSRC) $(WINCXXSRC) $(CHAINSRC) $(GENCSRC) \
$(HACKCSRC)
$(SYSCSRC) $(WINCSRC) $(SYSCXXSRC) $(WINCXXSRC) \
$(CHAINSRC) $(GENCSRC) $(HACKCSRC)
$(AWK) -f ../sys/unix/depend.awk ../include/*.h \
$(SYSCSRC) $(WINCSRC) $(WINCXXSRC) $(CHAINSRC) $(GENCSRC) \
$(HACKCSRC) >makedep
$(SYSCSRC) $(WINCSRC) $(SYSCXXSRC) $(WINCXXSRC) \
$(CHAINSRC) $(GENCSRC) $(HACKCSRC) >makedep
@echo '/^# DO NOT DELETE THIS LINE OR CHANGE ANYTHING BEYOND IT/+2,$$d' >eddep
@echo '$$r makedep' >>eddep
@echo 'w' >>eddep
@@ -710,6 +726,8 @@ load_img.o: ../win/gem/load_img.c ../include/load_img.h
gr_rect.o: ../win/gem/gr_rect.c ../include/gr_rect.h
$(CC) $(CFLAGS) -c ../win/gem/gr_rect.c
tile.o: tile.c $(HACK_H)
cppregex.o: ../sys/share/cppregex.cpp
$(CXX) $(CXXFLAGS) -c ../sys/share/cppregex.cpp
qt_win.o: ../win/Qt/qt_win.cpp $(HACK_H) ../include/func_tab.h \
../include/dlb.h ../include/patchlevel.h ../include/tile2x11.h \
../include/qt_win.h ../include/qt_clust.h ../include/qt_kde0.h \
+1 -1
View File
@@ -186,7 +186,7 @@ check-dlb: options
dlb:
( cd util ; $(MAKE) dlb )
( cd dat ; ../util/dlb cf nhdat $(DATDLB) )
( cd dat ; LC_ALL=C ; ../util/dlb cf nhdat $(DATDLB) )
# recover can be used when INSURANCE is defined in include/config.h
# and the checkpoint option is true
+5
View File
@@ -95,6 +95,11 @@ NHSROOT=..
#CFLAGS = -O -I../include
#LFLAGS =
# we specify C preprocessor flags via CFLAGS; files built with default rules
# might include $(CPPFLAGS) which could get a value from user's environment;
# we avoid that by forcing it empty rather than by overriding default rules
CPPFLAGS =
LIBS =
# If you are cross-compiling, you must use this:
Regular → Executable
View File
+129 -50
View File
@@ -1,4 +1,4 @@
/* NetHack 3.6 makedefs.c $NHDT-Date: 1455357861 2016/02/13 10:04:21 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.109 $ */
/* NetHack 3.6 makedefs.c $NHDT-Date: 1459208813 2016/03/28 23:46:53 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.110 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* Copyright (c) M. Stephenson, 1990, 1991. */
/* Copyright (c) Dean Luick, 1990. */
@@ -578,36 +578,35 @@ do_ext_makedefs(int argc, char **argv)
#undef CONSUME
/*
Filtering syntax:
Any line NOT starting with a caret is either suppressed or passed through
unchanged depending on the current conditional state.
The default conditional state is printing on.
Conditionals may be nested.
makedefs will exit with a EXIT_FAILURE if any errors are detected; as many
errors as possible are detected before giving up.
Unknown identifiers are treated as TRUE and also as an error to allow
processing to continue past the unknown identifier (note that "#undef" is
different than unknown).
Any line starting with a caret is a control line; as in C, zero or more
spaces
may be embedded in the line almost anywhere; the caret MUST be in column 1.
(XXX for the moment, no white space is allowed after the caret because
existing lines in the docs look like that)
Control lines:
^^ a line starting with a (single) literal caret
^# a comment - the line is ignored
^?ID if defined(ID)
^!ID if !defined(ID)
^: else
^. endif
*/
* Filtering syntax:
* Any line NOT starting with a caret is either suppressed or passed
* through unchanged depending on the current conditional state.
*
* The default conditional state is printing on.
*
* Conditionals may be nested.
*
* makedefs will exit with a EXIT_FAILURE if any errors are detected;
* as many errors as possible are detected before giving up.
*
* Unknown identifiers are treated as TRUE and also as an error to
* allow processing to continue past the unknown identifier (note
* that "#undef" is different than unknown).
*
* Any line starting with a caret is a control line; as in C, zero or
* more spaces may be embedded in the line almost anywhere; the caret
* MUST be in column 1.
* (XXX for the moment, no white space is allowed after the caret because
* existing lines in the docs look like that.)
*
* Control lines:
* ^^ a line starting with a (single) literal caret
* ^# a comment - the line is ignored
* ^?ID if defined(ID)
* ^!ID if !defined(ID)
* ^: else
* ^. endif
*/
#define GREP_MAGIC '^'
#define GREP_STACK_SIZE 100
#ifdef notyet
@@ -616,9 +615,9 @@ static int grep_rewrite = 0; /* need to (possibly) rewrite lines */
static int grep_writing = 1; /* need to copy lines to output */
static int grep_errors = 0;
static int grep_sp = 0;
#define ST_LD(old, opp) (!!(old) | (!!(opp) << 1))
#define ST_OLD(v) ((v) &1)
#define ST_OPP(v) !!((v) &2)
#define ST_LD(old, opp) (((old) ? 1 : 0) | ((opp) ? 2 : 0))
#define ST_OLD(v) (((v) & 1) != 0)
#define ST_OPP(v) (((v) & 2) != 0)
#define ST_ELSE 4
static int grep_stack[GREP_STACK_SIZE] = { ST_LD(1, 0) };
static int grep_lineno = 0;
@@ -1166,6 +1165,9 @@ make_version()
return;
}
/* REPRODUCIBLE_BUILD will change this to TRUE */
static boolean date_via_env = FALSE;
static char *
version_string(outbuf, delim)
char *outbuf;
@@ -1195,8 +1197,9 @@ const char *build_date;
Strcat(subbuf, " Beta");
#endif
Sprintf(outbuf, "%s NetHack%s Version %s - last build %s.", PORT_ID,
subbuf, version_string(versbuf, "."), build_date);
Sprintf(outbuf, "%s NetHack%s Version %s - last %s %s.", PORT_ID,
subbuf, version_string(versbuf, "."),
date_via_env ? "revision" : "build", build_date);
return outbuf;
}
@@ -1216,8 +1219,9 @@ const char *build_date;
Strcat(subbuf, " Beta");
#endif
Sprintf(outbuf, " Version %s %s%s, built %s.",
version_string(versbuf, "."), PORT_ID, subbuf, &build_date[4]);
Sprintf(outbuf, " Version %s %s%s, %s %s.",
version_string(versbuf, "."), PORT_ID, subbuf,
date_via_env ? "revised" : "built", &build_date[4]);
#if 0
Sprintf(outbuf, "%s NetHack%s %s Copyright 1985-%s (built %s)",
PORT_ID, subbuf, version_string(versbuf,"."), RELEASE_YEAR,
@@ -1256,20 +1260,96 @@ do_date()
Fprintf(ofp, "%s", Dont_Edit_Code);
(void) time(&clocktim);
Strcpy(cbuf, ctime(&clocktim));
#ifdef REPRODUCIBLE_BUILD
{
/*
* Use date+time of latest source file revision (set up in
* our environment rather than derived by scanning sources)
* instead of current date+time, so that later rebuilds of
* the same sources specifying the same configuration will
* produce the same result.
*
* Changing the configuration should be done by modifying
* config.h or <port>conf.h and setting SOURCE_DATE_EPOCH
* based on whichever changed most recently, not by using
* make CFLAGS='-Dthis -Dthat'
* to make alterations on the fly.
*
* Limited validation is performed to prevent dates in the
* future (beyond a leeway of 24 hours) or distant past.
*
* Assumes the value of time_t is in seconds, which is
* fundamental for Unix and mandated by POSIX. For any ports
* where that isn't true, leaving REPRODUCIBLE_BUILD disabled
* is probably preferrable to hacking this code....
*/
static struct tm nh360; /* static init should yield UTC timezone */
unsigned long sd_num, sd_earliest, sd_latest;
const char *sd_str = getenv("SOURCE_DATE_EPOCH");
for (c = cbuf; *c; c++)
if (*c == '\n')
break;
*c = '\0'; /* strip off the '\n' */
Fprintf(ofp, "#define BUILD_DATE \"%s\"\n", cbuf);
Fprintf(ofp, "#define BUILD_TIME (%ldL)\n", (long) clocktim);
Fprintf(ofp, "\n");
if (sd_str) {
sd_num = strtoul(sd_str, (char **) 0, 10);
/*
* Note: this does not need to be updated for future
* releases. It serves as a sanity check for potentially
* mis-set environment, not a hard baseline for when the
* current version could have first been built.
*/
/* oldest date we'll accept: 7-Dec-2015 (release of 3.6.0) */
nh360.tm_mday = 7;
nh360.tm_mon = 12 - 1;
nh360.tm_year = 2015 - 1900;
sd_earliest = (unsigned long) mktime(&nh360);
/* 'youngest' date we'll accept: 24 hours in the future */
sd_latest = (unsigned long) clocktim + 24L * 60L * 60L;
if (sd_num >= sd_earliest && sd_num <= sd_latest) {
/* use SOURCE_DATE_EPOCH value */
clocktim = (time_t) sd_num;
date_via_env = TRUE;
} else {
Fprintf(stderr, "? Invalid value for SOURCE_DATE_EPOCH (%lu)",
sd_num);
if (sd_num > 0L && sd_num < sd_earliest)
Fprintf(stderr, ", older than %lu", sd_earliest);
else if (sd_num > sd_latest)
Fprintf(stderr, ", newer than %lu", sd_latest);
Fprintf(stderr, ".\n");
Fprintf(stderr, ": Reverting to current date+time (%lu).\n",
(unsigned long) clocktim);
(void) fflush(stderr);
}
} else {
/* REPRODUCIBLE_BUILD enabled but SOURCE_DATE_EPOCH is missing */
Fprintf(stderr, "? No value for SOURCE_DATE_EPOCH.\n");
Fprintf(stderr, ": Using current date+time (%lu).\n",
(unsigned long) clocktim);
(void) fflush(stderr);
}
Strcpy(cbuf, asctime(gmtime(&clocktim)));
}
#else
/* ordinary build: use current date+time */
Strcpy(cbuf, ctime(&clocktim));
#endif
if ((c = index(cbuf, '\n')) != 0)
*c = '\0'; /* strip off the '\n' */
#ifdef NHSTDC
ul_sfx = "UL";
#else
ul_sfx = "L";
#endif
if (date_via_env)
Fprintf(ofp, "#define SOURCE_DATE_EPOCH (%lu%s) /* via getenv() */\n",
(unsigned long) clocktim, ul_sfx);
Fprintf(ofp, "#define BUILD_DATE \"%s\"\n", cbuf);
if (date_via_env)
Fprintf(ofp, "#define BUILD_TIME SOURCE_DATE_EPOCH\n");
else
Fprintf(ofp, "#define BUILD_TIME (%lu%s)\n",
(unsigned long) clocktim, ul_sfx);
Fprintf(ofp, "\n");
Fprintf(ofp, "#define VERSION_NUMBER 0x%08lx%s\n", version.incarnation,
ul_sfx);
Fprintf(ofp, "#define VERSION_FEATURES 0x%08lx%s\n", version.feature_set,
@@ -1294,10 +1374,11 @@ do_date()
#ifdef AMIGA
{
struct tm *tm = localtime((time_t *) &clocktim);
Fprintf(ofp, "#define AMIGA_VERSION_STRING ");
Fprintf(ofp, "\"\\0$VER: NetHack %d.%d.%d (%d.%d.%d)\"\n",
VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL, tm->tm_mday,
tm->tm_mon + 1, tm->tm_year + 1900);
VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL,
tm->tm_mday, tm->tm_mon + 1, tm->tm_year + 1900);
}
#endif
Fclose(ofp);
@@ -1963,7 +2044,6 @@ do_oracles()
void
do_dungeon()
{
int rcnt = 0;
char *line;
Sprintf(filename, DATA_IN_TEMPLATE, DGN_I_FILE);
@@ -1989,7 +2069,6 @@ do_dungeon()
while ((line = fgetline(ifp)) != 0) {
SpinCursor(3);
rcnt++;
if (line[0] == '#') {
free(line);
continue; /* discard comments */
+44 -12
View File
@@ -1379,6 +1379,7 @@ void NetHackQtStringRequestor::SetDefault(const char* d)
{
input.setText(d);
}
bool NetHackQtStringRequestor::Get(char* buffer, int maxchar)
{
input.setMaxLength(maxchar);
@@ -1432,6 +1433,7 @@ void NetHackQtStringRequestor::done(int i)
NetHackQtWindow::NetHackQtWindow()
{
}
NetHackQtWindow::~NetHackQtWindow()
{
}
@@ -1514,7 +1516,10 @@ void NetHackQtMapWindow::putMessage(int attr, const char* text)
messages += "\n";
messages += text;
QFontMetrics fm = fontMetrics();
messages_rect = fm.boundingRect(viewport.contentsX(),viewport.contentsY(),viewport.width(),0, WordBreak|AlignTop|AlignLeft|DontClip, messages);
messages_rect = fm.boundingRect(viewport.contentsX(), viewport.contentsY(),
viewport.width(), 0,
WordBreak|AlignTop|AlignLeft|DontClip,
messages);
update(messages_rect);
}
@@ -1701,7 +1706,9 @@ void NetHackQtMapWindow::paintEvent(QPaintEvent* event)
&& ::iflags.hilite_pet
#endif
) {
painter.drawPixmap(QPoint(i*qt_settings->glyphs().width(), j*qt_settings->glyphs().height()), pet_annotation);
painter.drawPixmap(QPoint(i*qt_settings->glyphs().width(),
j*qt_settings->glyphs().height()),
pet_annotation);
}
}
}
@@ -1717,7 +1724,9 @@ void NetHackQtMapWindow::paintEvent(QPaintEvent* event)
&& ::iflags.hilite_pet
#endif
) {
painter.drawPixmap(QPoint(i*qt_settings->glyphs().width(), j*qt_settings->glyphs().height()), pet_annotation);
painter.drawPixmap(QPoint(i*qt_settings->glyphs().width(),
j*qt_settings->glyphs().height()),
pet_annotation);
}
}
}
@@ -2827,6 +2836,7 @@ void NetHackQtMenuWindow::Layout()
invert->setGeometry(x,0,butw,buth); x+=butw; butw=(dialog->width()-x)/1;
search->setGeometry(x,0,butw,buth);
}
int NetHackQtMenuWindow::SelectMenu(int h, MENU_ITEM_P **menu_list)
{
setFont(str_fixed ?
@@ -2947,6 +2957,7 @@ int NetHackQtMenuWindow::SelectMenu(int h, MENU_ITEM_P **menu_list)
return -1;
}
}
void NetHackQtMenuWindow::keyPressEvent(QKeyEvent* event)
{
if (viewHeight() < totalHeight() && !(event->state()&ShiftButton)) {
@@ -2974,12 +2985,14 @@ void NetHackQtMenuWindow::ChooseNone()
if (item[i].selected) ToggleSelect(i);
}
}
void NetHackQtMenuWindow::Invert()
{
for (int i=0; i<itemcount; i++) {
ToggleSelect(i);
}
}
void NetHackQtMenuWindow::Search()
{
NetHackQtStringRequestor requestor(keysource,"Search for:");
@@ -2991,6 +3004,7 @@ void NetHackQtMenuWindow::Search()
}
}
}
void NetHackQtMenuWindow::ToggleSelect(int i)
{
if (item[i].Selectable()) {
@@ -3115,6 +3129,7 @@ void NetHackQtMenuWindow::mousePressEvent(QMouseEvent* event)
}
}
}
void NetHackQtMenuWindow::mouseReleaseEvent(QMouseEvent* event)
{
if (pressed>=0) {
@@ -3123,6 +3138,7 @@ void NetHackQtMenuWindow::mouseReleaseEvent(QMouseEvent* event)
updateCell(p,3);
}
}
void NetHackQtMenuWindow::mouseMoveEvent(QMouseEvent* event)
{
if (pressed>=0) {
@@ -3292,7 +3308,7 @@ static char** rip_line=0;
Sprintf(rip_line[GOLD_LINE], "%ld Au", done_money);
/* Put together death description */
formatkiller(buf, sizeof buf, how);
formatkiller(buf, sizeof buf, how, FALSE);
/* Put death type on stone */
for (line=DEATH_LINE, dpx = buf; line<YEAR_LINE; line++) {
@@ -4274,8 +4290,9 @@ NetHackQtGlyphs::NetHackQtGlyphs()
} else {
tiles_per_row = TILES_PER_ROW;
if (img.width()%tiles_per_row) {
impossible("Tile file \"%s\" has %d columns, not multiple of row count (%d)",
tile_file, img.width(), tiles_per_row);
impossible(
"Tile file \"%s\" has %d columns, not multiple of row count (%d)",
tile_file, img.width(), tiles_per_row);
}
}
} else {
@@ -4368,18 +4385,30 @@ QWidget* NetHackQtMenuOrTextWindow::Widget()
// Text
void NetHackQtMenuOrTextWindow::Clear()
{
if (!actual) impossible("Clear called before we know if Menu or Text");
actual->Clear();
if (!actual)
impossible("Clear called before we know if Menu or Text");
else
actual->Clear();
}
void NetHackQtMenuOrTextWindow::Display(bool block)
{
if (!actual) impossible("Display called before we know if Menu or Text");
actual->Display(block);
if (!actual)
impossible("Display called before we know if Menu or Text");
else
actual->Display(block);
}
bool NetHackQtMenuOrTextWindow::Destroy()
{
if (!actual) impossible("Destroy called before we know if Menu or Text");
return actual->Destroy();
bool res = FALSE;
if (!actual)
impossible("Destroy called before we know if Menu or Text");
else
res = actual->Destroy();
return res;
}
void NetHackQtMenuOrTextWindow::PutStr(int attr, const char* text)
@@ -4394,17 +4423,20 @@ void NetHackQtMenuOrTextWindow::StartMenu()
if (!actual) actual=new NetHackQtMenuWindow(keysource);
actual->StartMenu();
}
void NetHackQtMenuOrTextWindow::AddMenu(int glyph, const ANY_P* identifier, char ch, char gch, int attr,
const char* str, bool presel)
{
if (!actual) impossible("AddMenu called before we know if Menu or Text");
actual->AddMenu(glyph,identifier,ch,gch,attr,str,presel);
}
void NetHackQtMenuOrTextWindow::EndMenu(const char* prompt)
{
if (!actual) impossible("EndMenu called before we know if Menu or Text");
actual->EndMenu(prompt);
}
int NetHackQtMenuOrTextWindow::SelectMenu(int how, MENU_ITEM_P **menu_list)
{
if (!actual) impossible("SelectMenu called before we know if Menu or Text");
+512
View File
@@ -0,0 +1,512 @@
/* NetHack 3.6 giftiles.c $NHDT-Date: 1457358406 2016/03/07 13:46:46 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.0 $ */
/* Copyright (c) Ray Chason, 2016. */
/* NetHack may be freely redistributed. See license for details. */
/* giftiles.c -- read a tile map in GIF format */
/* Reference: GIF specification,, retrieved from
* http://www.w3.org/Graphics/GIF/spec-gif89a.txt */
#include "config.h"
#include "tileset.h"
#define MIN_LZW_BITS 3
#define MAX_LZW_BITS 12
#define END_OF_DATA 0x7FFF
/* For use when reading the GIF as a bitstream */
struct Bitstream {
/* The file */
FILE *fp;
/* For unpacking LZW codes */
unsigned long bits;
unsigned char num_bits;
unsigned char bit_width;
unsigned char initial_bit_width;
unsigned char block_size;
/* The dictionary */
struct {
unsigned char byte;
unsigned short next;
} dictionary[1 << MAX_LZW_BITS];
unsigned short dict_size;
/* The string currently being decoded */
unsigned char string[1 << MAX_LZW_BITS];
unsigned short str_size;
unsigned short last_code;
};
struct DataBlock {
size_t size;
size_t index;
unsigned char *data;
};
static boolean FDECL(read_data_block, (struct Bitstream *gif, struct DataBlock *block));
static void FDECL(free_data_block, (struct DataBlock *block));
static unsigned short FDECL(read_u16, (const unsigned char buf[2]));
static void FDECL(init_decoder, (struct Bitstream *gif, unsigned bit_width));
static void FDECL(reset_decoder, (struct Bitstream *gif));
static int FDECL(decode, (struct Bitstream *gif, struct DataBlock *block));
static int FDECL(get_code, (struct Bitstream *gif, struct DataBlock *block));
static unsigned FDECL(interlace_incr, (unsigned y, unsigned height));
/*
* GIF specifies a canvas, which may have a palette (the "global color table")
* of up to 256 colors, of which one is a background color, and zero or more
* images, each of which may have its own palette (a "local color table")
* independently of the canvas. We will join all palettes found into a single
* palette, and indicate that the image uses a palette if, and only if, the
* various palettes do not total more than 256 colors.
*/
boolean
read_gif_tiles(filename, image)
const char *filename;
struct TileSetImage *image;
{
struct Bitstream gif;
struct DataBlock block;
unsigned char buf[1024];
size_t size, num_pixels, i;
/* Image data not returned to the caller */
boolean have_gct; /* global color table is present */
unsigned gct_size; /* global color table size */
unsigned back_color; /* index for background color */
unsigned trans_color = 0xFFFF; /* index for transparent palette entry */
block.data = NULL; /* custodial */
gif.fp = NULL; /* custodial */
image->width = 0;
image->height = 0;
image->pixels = NULL; /* custodial, returned */
image->indexes = NULL; /* custodial, returned */
image->image_desc = NULL; /* custodial, returned */
image->tile_width = 0;
image->tile_height = 0;
gif.fp = fopen(filename, "rb");
if (gif.fp == NULL) goto error;
/* 17. Header */
size = fread(buf, 1, 6, gif.fp);
if (size < 6) goto error;
if (memcmp(buf, "GIF87a", 6) != 0 && memcmp(buf, "GIF89a", 6) != 0)
goto error;
/* 18. Logical screen descriptor */
size = fread(buf, 1, 7, gif.fp);
if (size < 7) goto error;
image->width = read_u16(buf + 0);
image->height = read_u16(buf + 2);
have_gct = (buf[4] & 0x80) != 0;
gct_size = 1 << ((buf[4] & 0x07) + 1);
back_color = buf[5];
if (image->width == 0 || image->height == 0) goto error;
/* 19. Global Color Table */
for (i = 0; i < SIZE(image->palette); ++i) {
image->palette[i].r = 0;
image->palette[i].g = 0;
image->palette[i].b = 0;
image->palette[i].a = 255;
}
if (have_gct) {
size = fread(buf, 3, gct_size, gif.fp);
if (size < gct_size) goto error;
for (i = 0; i < gct_size; ++i) {
image->palette[i].r = buf[i * 3 + 0];
image->palette[i].g = buf[i * 3 + 1];
image->palette[i].b = buf[i * 3 + 2];
image->palette[i].a = 255;
}
}
/* Allocate pixel area; watch out for overflow */
num_pixels = (size_t) image->width * (size_t) image->height;
if (num_pixels / image->width != image->height) goto error; /* overflow */
size = num_pixels * sizeof(image->pixels[0]);
if (size / sizeof(image->pixels[0]) != num_pixels) goto error; /* overflow */
image->pixels = (struct Pixel *) alloc(size);
image->indexes = (unsigned char *) alloc(num_pixels);
/* Fill with the background color */
for (i = 0; i < num_pixels; ++i) {
image->pixels[i] = image->palette[back_color];
image->indexes[i] = back_color;
}
/* Read the image data */
while (TRUE) {
int b = fgetc(gif.fp);
if (b == EOF) goto error;
/* 27. Trailer (0x3B) */
if (b == 0x3B) break;
switch (b) {
case 0x2C:
/* 20. Image descriptor (0x2C) */
{
unsigned img_left, img_top, img_width, img_height;
boolean have_lct, interlace;
unsigned lct_start, lct_size;
struct Pixel lct[256];
int b;
unsigned x, y, x2, y2;
size = fread(buf, 1, 9, gif.fp);
if (size < 9) goto error;
img_left = read_u16(buf + 0);
img_top = read_u16(buf + 2);
img_width = read_u16(buf + 4);
img_height = read_u16(buf + 6);
have_lct = (buf[8] & 0x80) != 0;
interlace = (buf[8] & 0x40) != 0;
lct_size = 1 << ((buf[8] & 0x07) + 1);
/* 21. Local color table */
lct_start = 0;
memcpy(lct, image->palette, sizeof(lct));
if (have_lct) {
size = fread(buf, 3, lct_size, gif.fp);
if (size < lct_size) goto error;
for (i = 0; i < lct_size; ++i) {
lct[i].r = buf[i * 3 + 0];
lct[i].g = buf[i * 3 + 1];
lct[i].b = buf[i * 3 + 2];
lct[i].a = 255;
}
/*
* The combined palette may exceed 256 colors, in which
* case the indexes array will be discarded, indicating a
* full-color image.
*/
if (lct_size + gct_size <= 256) {
memcpy(image->palette, lct, sizeof(lct[0]) * lct_size);
}
lct_start = gct_size;
gct_size += lct_start;
}
if (trans_color != 0xFFFF) {
lct[trans_color].a = 0;
if (!have_lct) {
/* FIXME: this will affect all images using the global
* color table, not just the current one */
image->palette[trans_color].a = 0;
}
}
/* 22. Table based image data */
b = fgetc(gif.fp);
if (b == EOF) goto error;
if (b < MIN_LZW_BITS - 1 || MAX_LZW_BITS - 1 < b) goto error;
init_decoder(&gif, b);
x = 0;
y = 0;
if (!read_data_block(&gif, &block)) goto error;
while (TRUE) {
b = decode(&gif, &block);
if (b == EOF) goto error;
if (b == END_OF_DATA) break;
if (y >= img_height) goto error;
x2 = img_left + x;
y2 = img_top + y;
if (x2 < image->width && y2 < image->height) {
image->pixels[y2 * image->width + x2] = lct[b];
image->indexes[y2 * image->width + x2] = b + lct_start;
}
++x;
if (x >= img_width) {
x = 0;
if (interlace) {
y = interlace_incr(y, img_height);
} else {
++y;
}
}
}
free_data_block(&block);
trans_color = 0xFFFF;
}
break;
case 0x21:
/* Extension blocks */
{
int label;
label = fgetc(gif.fp);
if (label == EOF) goto error;
if (!read_data_block(&gif, &block)) goto error;
switch (label) {
case 0xF9:
/* 23. Graphic control extension (0xF9) */
if (block.size >= 4 && (block.data[0] & 0x01) != 0) {
/* image has a transparent index */
trans_color = block.data[3];
}
break;
#if 0
case 0xFE:
/* 24. Comment extension (0xFE) */
break;
case 0x01:
/* 25. Plain text extension (0x01) */
break;
#endif
case 0xFF:
/* 26. Application extension (0xFF) */
if (block.size > 11
&& memcmp(block.data, "NETHACK3GIF", 11) == 0
&& image->image_desc == NULL) {
memmove(block.data, block.data + 11, block.size - 11);
block.data[block.size - 11] = '\0';
image->image_desc = (char *) block.data;
block.data = NULL;
}
break;
default:
/* Unknown extension type */
break;
}
free_data_block(&block);
}
break;
default:
goto error;
}
}
fclose(gif.fp);
free_data_block(&block);
if (gct_size > 256) {
/* Max palette size exceeded; indexes array is not meaningful */
free(image->indexes);
image->indexes = NULL;
}
return TRUE;
error:
if (gif.fp) fclose(gif.fp);
free_data_block(&block);
free(image->pixels);
image->pixels = NULL;
free(image->indexes);
image->indexes = NULL;
free(image->image_desc);
image->image_desc = NULL;
return FALSE;
}
static void
init_decoder(gif, bit_width)
struct Bitstream *gif;
unsigned bit_width;
{
unsigned i;
unsigned clear;
gif->bits = 0;
gif->num_bits = 0;
gif->initial_bit_width = bit_width;
gif->block_size = 0;
clear = 1 << bit_width;
gif->dict_size = clear + 2;
for (i = 0; i < clear; ++i) {
gif->dictionary[i].byte = i;
gif->dictionary[i].next = 0xFFFF;
}
gif->str_size = 0;
reset_decoder(gif);
}
static void
reset_decoder(gif)
struct Bitstream *gif;
{
/* Set the bit width */
gif->bit_width = gif->initial_bit_width + 1;
/* Reset the dictionary */
gif->dict_size = (1 << gif->initial_bit_width) + 2;
/* No last code */
gif->last_code = 0xFFFF;
}
static int
decode(gif, block)
struct Bitstream *gif;
struct DataBlock *block;
{
int code;
unsigned clear = 1 << gif->initial_bit_width;
/* If a string is being decoded, return the next byte */
if (gif->str_size != 0) {
return gif->string[--gif->str_size];
}
/* Get the next code, until code other than clear */
while (TRUE) {
code = get_code(gif, block);
if (code != clear) break;
reset_decoder(gif);
}
if (code == EOF) return EOF;
if (code == clear + 1) return END_OF_DATA;
if (code > gif->dict_size) return EOF;
/* Add a new string to the dictionary */
if (gif->last_code != 0xFFFF && gif->dict_size < SIZE(gif->dictionary)) {
unsigned next_code;
if (code < gif->dict_size) {
next_code = code;
} else {
next_code = gif->last_code;
}
while (next_code >= clear) {
next_code = gif->dictionary[next_code].next;
}
gif->dictionary[gif->dict_size].next = gif->last_code;
gif->dictionary[gif->dict_size].byte = next_code;
++gif->dict_size;
if (gif->dict_size >= 1 << gif->bit_width
&& gif->bit_width < MAX_LZW_BITS) {
++gif->bit_width;
}
}
gif->last_code = code;
/* code is less than gif->dict_size and not equal to clear or clear + 1 */
/* Prepare the decoded string for return; note that it is stored in
* reverse order */
while (code >= clear) {
gif->string[gif->str_size++] = gif->dictionary[code].byte;
code = gif->dictionary[code].next;
}
return code;
}
static int
get_code(gif, block)
struct Bitstream *gif;
struct DataBlock *block;
{
int code;
while (gif->num_bits < gif->bit_width) {
unsigned char b;
if (block->index >= block->size) return EOF;
b = block->data[block->index++];
gif->bits |= (unsigned long)b << gif->num_bits;
gif->num_bits += 8;
}
code = (int) (gif->bits & ((1UL << gif->bit_width) - 1));
gif->bits >>= gif->bit_width;
gif->num_bits -= gif->bit_width;
return code;
}
static unsigned
interlace_incr(y, height)
unsigned y;
unsigned height;
{
static const unsigned char incr[] = { 8, 2, 4, 2 };
/* The lower three bits indicate the current pass */
/* Advance to the next row of the current pass */
y += incr[y & 0x3];
/* Go to the next pass if y exceeds height */
/* Might not be the immediately following pass if height is small */
if (y >= height && (y & 0x7) == 0) {
/* Pass 1 -> Pass 2 */
y = 4;
}
if (y >= height && (y & 0x7) == 4) {
/* Pass 2 -> Pass 3 */
y = 2;
}
if (y >= height && (y & 0x3) == 2) {
/* Pass 3 -> Pass 4 */
y = 1;
}
return y;
}
/* Decode an unsigned 16 bit quantity */
static unsigned short
read_u16(buf)
const unsigned char buf[2];
{
return ((unsigned short)buf[0] << 0)
| ((unsigned short)buf[1] << 8);
}
static boolean
read_data_block(gif, block)
struct Bitstream *gif;
struct DataBlock *block;
{
long pos = ftell(gif->fp);
int b;
size_t i;
free_data_block(block);
/* Get the length of the data block */
while (TRUE) {
b = fgetc(gif->fp);
if (b == EOF) return FALSE;
if (b == 0) break;
block->size += b;
fseek(gif->fp, b, SEEK_CUR);
}
fseek(gif->fp, pos, SEEK_SET);
/* Allocate memory */
block->data = (unsigned char *) alloc(block->size);
/* Read the data from the file */
i = 0;
while (TRUE) {
b = fgetc(gif->fp);
if (b == EOF) return FALSE;
if (b == 0) break;
if (fread(block->data + i, 1, b, gif->fp) != b) return FALSE;
i += b;
}
block->index = 0;
return TRUE;
}
static void
free_data_block(block)
struct DataBlock *block;
{
free(block->data);
block->size = 0;
block->data = NULL;
}

Some files were not shown because too many files have changed in this diff Show More