diff --git a/doc/Guidebook.mn b/doc/Guidebook.mn index 8c42f1b83..e21956137 100644 --- a/doc/Guidebook.mn +++ b/doc/Guidebook.mn @@ -1,4 +1,4 @@ -.\" $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.264 $ $NHDT-Date: 1524690677 2018/04/25 21:11:17 $ +.\" $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.271 $ $NHDT-Date: 1535668900 2018/08/30 22:41:40 $ .\" .\" This is an excerpt from the 'roff' man page from the 'groff' package. .\" NetHack's Guidebook.mn currently does *not* adhere to these guidelines. @@ -21,7 +21,7 @@ .ds vr "NetHack 3.6 .ds f0 "\*(vr .ds f1 -.ds f2 "May 28, 2018 +.ds f2 "August 30, 2018 . .\" labeled paragraph start (should be part of tmac.n, but I don't want to .\" make changes to that file) @@ -782,13 +782,13 @@ The available options are listed later in this Guidebook. Options are usually set before the game rather than with the `O' command; see the section on options below. .lp ^O -Show overview or show dungeon layout +Show overview. .lp "" -In normal play and in explore mode, a shortcut for the ``#overview'' -extended command to list interesting dungeon levels visited. +Shortcut for ``#overview'': list interesting dungeon levels visited. .lp "" -In debug mode, an extra command which lists the placement of all special -levels. +(Prior to 3.6.0, `^O' was a debug mode command which listed +the placement of all special levels. +Use ``#wizwhere'' to run that command.) .lp p Pay your shopping bill. .lp P @@ -1098,13 +1098,19 @@ Default key is '^D', and 'k' if .op number_pad is on. .lp #known -Show what object types have been discovered. Default key is '\\'. +Show what object types have been discovered. +Default key is '\\'. .lp #knownclass -Show discovered types for one class of objects. Default key is '`'. +Show discovered types for one class of objects. +Default key is '`'. .lp #levelchange -Change your experience level. Autocompletes. Wizard-mode only. +Change your experience level. +Autocompletes. +Debug mode only. .lp #lightsources -Show mobile light sources. Autocompletes. Wizard-mode only. +Show mobile light sources. +Autocompletes. +Debug mode only. .lp #look Look at what is here, under you. Default key is ':'. .lp #loot @@ -1116,7 +1122,9 @@ Default key is 'M-l', and 'l' if .op number_pad is on. .lp #monpolycontrol -Control monster polymorphs. Autocompletes. Wizard-mode only. +Control monster polymorphs. +Autocompletes. +Debug mode only. .lp #monster Use a monster's special ability (when polymorphed into monster form). Autocompletes. Default key is 'M-m'. @@ -1142,14 +1150,19 @@ If dungeon overview is chosen during end-of-game disclosure, every visited level will be included regardless of annotations. Autocompletes. Default keys are '^O', and 'M-O'. .lp #panic -Test the panic routine. Autocompletes. Wizard-mode only. +Test the panic routine. +Terminates the current game. +Autocompletes. +Debug mode only. .lp "#pay " Pay your shopping bill. Default key is 'p'. .lp #pickup Pick up things at the current location. Default key is ','. The `m' prefix forces use of a menu. .lp #polyself -Polymorph self. Autocompletes. Wizard-mode only. +Polymorph self. +Autocompletes. +Debug mode only. .lp #pray Pray to the gods for help. Autocompletes. Default key is 'M-p'. .lp "" @@ -1203,7 +1216,9 @@ Show the armor currently worn. Default key is '['. .lp #seegold Count your gold. Default key is '$'. .lp #seenv -Show seen vectors. Autocompletes. Wizard-mode only. +Show seen vectors. +Autocompletes. +Debug mode only. .lp #seerings Show the ring(s) currently worn. Default key is '='. .lp #seespells @@ -1220,7 +1235,9 @@ Do a shell escape. Default key is '!'. .lp "#sit " Sit down. Autocompletes. Default key is 'M-s'. .lp #stats -Show memory statistics. Autocompletes. Wizard-mode only. +Show memory statistics. +Autocompletes. +Debug mode only. .lp #suspend Suspend the game. Default key is '^Z'. .lp #swap @@ -1239,7 +1256,9 @@ Show a menu of possible actions in a location next to you. .lp #throw Throw something. Default key is 't'. .lp #timeout -Look at the timeout queue. Autocompletes. Wizard-mode only. +Look at the timeout queue. +Autocompletes. +Debug mode only. .lp "#tip " Tip over a container (bag or box) to pour out its contents. Autocompletes. Default key is 'M-T'. @@ -1271,16 +1290,21 @@ In some circumstances it can also be used to rescue trapped monsters. .lp "#up " Go up a staircase. Default key is '<'. .lp #vanquished -List vanquished monsters. Autocompletes. Wizard-mode only. +List vanquished monsters. +Autocompletes. +Debug mode only. .lp #version Print compile time options for this version of NetHack. Autocompletes. Default key is 'M-v'. .lp #versionshort Show version string. Default key is 'v'. .lp #vision -Show vision array. Autocompletes. Wizard-mode only. +Show vision array. +Autocompletes. +Debug mode only. .lp #wait -Rest one move while doing nothing. Default key is '.', and ' ' if +Rest one move while doing nothing. +Default key is '.', and also ' ' if rest_on_space is on. .lp #wear Wear a piece of armor. Default key is 'W'. @@ -1293,35 +1317,65 @@ Wield a weapon. Default key is 'w'. .lp #wipe Wipe off your face. Autocompletes. Default key is 'M-w'. .lp #wizdebug_bury -Bury objects under and around you. Autocompletes. Wizard-mode only. +Bury objects under and around you. +Autocompletes. +Debug mode only. .lp #wizdebug_traveldisplay -Toggle travel display. Autocompletes. Wizard-mode only. +Toggle travel display. +Autocompletes. +Debug mode only. .lp #wizdetect -Search a room. Autocompletes. Wizard-mode only. Default key is '^E'. +Search for hidden things (secret doors or traps or unseen monsters) +within a modest radius. +Autocompletes. +Debug mode only. +Default key is '^E'. .lp #wizgenesis -Create a monster. Autocompletes. Wizard-mode only. Default key is '^G'. +Create a monster. +May be prefixed by a count to create more than one. +Autocompletes. +Debug mode only. +Default key is '^G'. .lp #wizidentify -Identify all items in inventory. Autocompletes. Wizard-mode only. +Identify all items in inventory. +Autocompletes. +Debug mode only. Default key is '^I'. .lp #wizintrinsic -Set intrinsic. Autocompletes. Wizard-mode only. +Set one or more intrinsic attributes. +Autocompletes. +Debug mode only. .lp #wizlevelport Teleport to another level. Autocompletes. -Wizard-mode only. +Debug mode only. Default key is '^V'. .lp #wizmap -Map the level. Autocompletes. Wizard-mode only. Default key is '^F'. +Map the level. +Autocompletes. +Debug mode only. +Default key is '^F'. .lp #wizrumorcheck -Verify rumor boundaries. Autocompletes. Wizard-mode only. +Verify rumor boundaries. +Autocompletes. +Debug mode only. .lp #wizsmell -Smell monster. Autocompletes. Wizard-mode only. +Smell monster. +Autocompletes. +Debug mode only. .lp #wizwhere -Show locations of special levels. Autocompletes. Wizard-mode only. +Show locations of special levels. +Autocompletes. +Debug mode only. .lp #wizwish -Wish for something. Autocompletes. Wizard-mode only. Default key is '^W'. +Wish for something. +Autocompletes. +Debug mode only. +Default key is '^W'. .lp #wmode -Show wall modes. Autocompletes. Wizard-mode only. +Show wall modes. +Autocompletes. +Debug mode only. .lp "#zap " Zap a wand. Default key is 'z'. .lp "#? " @@ -2476,9 +2530,10 @@ Example: \fBSYMBOLS=S_boulder:0\fP .ed .lp WIZKIT -Wizard-mode extra items, in a text file containing item names, -one per line, up to a maximum of 128 lines. Each line is processed -by the function that handles wishing. +Debug mode only: extra items to add to initial inventory. +Value is the name of a text file containing a list of item names, +one per line, up to a maximum of 128 lines. +Each line is processed by the function that handles wishing. .pg Example: .sd @@ -3280,7 +3335,22 @@ If NetHack can, it should display this number of messages at a time in the message window. .lp windowcolors If NetHack can, it should display windows with the specified -foreground/background colors if it can. +foreground/background colors. Windows GUI only. The format is +.si +.lp "OPTION=windowcolors:wintype foreground/background" +.ei +.pg +where wintype is one of "menu", "message", "status", or "text", and +foreground and background are colors, either a hexadecimal \'#rrggbb', +one of the named colors (black, red, green, brown, +blue, magenta, cyan, orange, brightgreen, yellow, brightblue, +brightmagenta, brightcyan, white, trueblack, gray, purple, +silver, maroon, fuchsia, lime, olive, navy, teal, aqua), +or one of Windows UI colors (activeborder, activecaption, +appworkspace, background, btnface, btnshadow, btntext, +captiontext, graytext, greytext, highlight, highlighttext, +inactiveborder, inactivecaption, menu, menutext, scrollbar, +window, windowframe, windowtext). .lp wraptext If NetHack can, it should wrap long lines of text if they don't fit in the visible area of the window. @@ -4130,15 +4200,15 @@ system). .\" as filling and justifying are concerned .lp WIZARDS\ =\ A space-separated list of user names who are allowed to -play in wizard -mode (the debugging mode, not the magic-using role). A value of a single -asterisk (*) allows anyone to start a game in wizard mode. +play in debug mode (commonly referred to as wizard mode). +A value of a single +asterisk (*) allows anyone to start a game in debug mode. .lp SHELLERS\ =\ A list of users who are allowed to use the shell escape command (!). The syntax is the same as WIZARDS. .lp -EXPLORERS\ =\ A list of users who are allowed to use the explore mode. The -syntax is the same as WIZARDS. +EXPLORERS\ =\ A list of users who are allowed to use the explore mode. +The syntax is the same as WIZARDS. .lp MAXPLAYERS\ =\ Limit the maximum number of games that can be running at the same time. @@ -4246,10 +4316,13 @@ the trepid reader to discover. Debug mode .pg Debug mode, also known as wizard mode, is undocumented aside from this -brief description. It is intended for tracking down problems within the +brief description and the various ``debug mode only'' commands listed +among the command descriptions. +It is intended for tracking down problems within the program rather than to provide god-like powers to your character, and players who attempt debugging are expected to figure out how to use it -themselves. It is initiated by starting the game with the +themselves. +It is initiated by starting the game with the .op \-D command-line switch or with the .op playmode:debug @@ -4259,8 +4332,7 @@ For some systems, the player must be logged in under a particular user name to be allowed to use debug mode; for others, the hero must be given a particular character name (but may be any role; there's no connection between ``wizard mode'' and the Wizard role). -And on any system, the program might have been configured to omit debug -mode entirely. Attempting to start a game in debug mode when not allowed +Attempting to start a game in debug mode when not allowed or not available will result in falling back to explore mode instead. . .hn diff --git a/doc/Guidebook.tex b/doc/Guidebook.tex index 360ea539c..31a4ee76b 100644 --- a/doc/Guidebook.tex +++ b/doc/Guidebook.tex @@ -45,7 +45,7 @@ %.au \author{Original version - Eric S. Raymond\\ (Edited and expanded for 3.6 by Mike Stephenson and others)} -\date{May 28, 2018} +\date{August 30, 2018} \maketitle @@ -852,13 +852,14 @@ are listed later in this Guidebook. Options are usually set before the game rather than with the `{\tt O}' command; see the section on options below. %.lp \item[\tb{\^{}O}] -Show overview or show dungeon layout\\ +Show overview.\\ %.lp "" -In normal play and in explore mode, a shortcut for the ``{\tt \#overview}'' -extended command to list interesting dungeon levels visited.\\ +Shortcut for the ``{\tt \#overview}'': +list interesting dungeon levels visited.\\ %.lp "" -In debug mode, an extra command which lists the placement of all special -levels. +(Prior to 3.6.0, `{\tt \^{}O}' was a debug mode command which listed +the placement of all special levels. +Use ``{\tt \#wizwhere}'' to run that command.) %.lp \item[\tb{p}] Pay your shopping bill. @@ -1216,16 +1217,22 @@ Jump to another location. Autocompletes. Default key is '{\tt M-j}', and '{\tt j Kick something. Default key is '{\tt \^{}D}', and '{\tt k}' if {\it number\verb+_+pad\/} is on. %.lp \item[\tb{\#known}] -Show what object types have been discovered. Default key is '{\tt $\backslash$}'. +Show what object types have been discovered. +Default key is '{\tt $\backslash$}'. %.lp \item[\tb{\#knownclass}] -Show discovered types for one class of objects. Default key is '{\tt `}'. +Show discovered types for one class of objects. +Default key is '{\tt `}'. %.lp \item[\tb{\#levelchange}] -Change your experience level. Autocompletes. Wizard-mode only. +Change your experience level. +Autocompletes. +Debug mode only. %.lp \item[\tb{\#lightsources}] -Show mobile light sources. Autocompletes. Wizard-mode only. +Show mobile light sources. +Autocompletes. +Debug mode only. %.lp \item[\tb{\#look}] Look at what is here, under you. Default key is '{\tt :}'. @@ -1238,7 +1245,9 @@ Precede with the `{\tt m}' prefix to skip containers at your location and go directly to removing a saddle. %.lp \item[\tb{\#monpolycontrol}] -Control monster polymorphs. Autocompletes. Wizard-mode only. +Control monster polymorphs. +Autocompletes. +Debug mode only. %.lp \item[\tb{\#monster}] Use a monster's special ability (when polymorphed into monster form). @@ -1271,7 +1280,10 @@ level will be included regardless of annotations. Autocompletes. Default keys are '{\tt \^{}O}', and '{\tt M-O}'. %.lp \item[\tb{\#panic}] -Test the panic routine. Autocompletes. Wizard-mode only. +Test the panic routine. +Terminates the current game. +Autocompletes. +Debug mode only. %.lp \item[\tb{\#pay}] Pay your shopping bill. Default key is '{\tt p}'. @@ -1281,7 +1293,9 @@ Pick up things at the current location. Default key is '{\tt ,}'. The `{\tt m}' prefix forces use of a menu. %.lp \item[\tb{\#polyself}] -Polymorph self. Autocompletes. Wizard-mode only. +Polymorph self. +Autocompletes. +Debug mode only. %.lp \item[\tb{\#pray}] Pray to the gods for help. Autocompletes. Default key is '{\tt M-p}'.\\ @@ -1352,7 +1366,9 @@ Show the armor currently worn. Default key is '{\tt [}'. Count your gold. Default key is '{\tt \$}'. %.lp \item[\tb{\#seenv}] -Show seen vectors. Autocompletes. Wizard-mode only. +Show seen vectors. +Autocompletes. +Debug mode only. %.lp \item[\tb{\#seerings}] Show the ring(s) currently worn. Default key is '{\tt =}'. @@ -1376,7 +1392,9 @@ Do a shell escape. Default key is '{\tt !}'. Sit down. Autocompletes. Default key is '{\tt M-s}'. %.lp \item[\tb{\#stats}] -Show memory statistics. Autocompletes. Wizard-mode only. +Show memory statistics. +Autocompletes. +Debug mode only. %.lp \item[\tb{\#suspend}] Suspend the game. Default key is '{\tt \^{}Z}'. @@ -1404,7 +1422,9 @@ Show a menu of possible actions in a location next to you. Throw something. Default key is '{\tt t}'. %.lp \item[\tb{\#timeout}] -Look at the timeout queue. Autocompletes. Wizard-mode only. +Look at the timeout queue. +Autocompletes. +Debug mode only. %.lp \item[\tb{\#tip}] Tip over a container (bag or box) to pour out its contents. @@ -1438,7 +1458,9 @@ In some circumstancs it can also be used to rescue trapped monsters. Go up a staircase. Default key is '{\tt <}'. %.lp \item[\tb{\#vanquished}] -List vanquished monsters. Autocompletes. Wizard-mode only. +List vanquished monsters. +Autocompletes. +Debug mode only. %.lp \item[\tb{\#version}] Print compile time options for this version of {\it NetHack\/}. @@ -1448,10 +1470,14 @@ Autocompletes. Default key is '{\tt M-v}'. Show version string. Default key is '{\tt v}'. %.lp \item[\tb{\#vision}] -Show vision array. Autocompletes. Wizard-mode only. +Show vision array. +Autocompletes. +Debug mode only. %.lp \item[\tb{\#wait}] -Rest one move while doing nothing. Default key is '{\tt .}', and '{\tt{ }}' if {\it rest\verb+_+on\verb+_+space\/} is on. +Rest one move while doing nothing. +Default key is '{\tt .}', and also '{\tt{ }}' if +{\it rest\verb+_+on\verb+_+space\/} is on. %.lp \item[\tb{\#wear}] Wear a piece of armor. Default key is '{\tt W}'. @@ -1469,44 +1495,77 @@ Wield a weapon. Default key is '{\tt w}'. Wipe off your face. Autocompletes. Default key is '{\tt M-w}'. %.lp \item[\tb{\#wizdebug\verb+_+bury}] -Bury objects under and around you. Autocompletes. Wizard-mode only. +Bury objects under and around you. +Autocompletes. +Debug mode only. %.lp \item[\tb{\#wizdebug\verb+_+traveldisplay}] -Toggle travel display. Autocompletes. Wizard-mode only. +Toggle travel display. +Autocompletes. +Debug mode only. %.lp \item[\tb{\#wizdetect}] -Search a room. Autocompletes. Wizard-mode only. Default key is '{\tt \^{}E}'. +Search for hidden things (secret doors or traps or unseen monsters) +within a modest radius. +Autocompletes. +Debug mode only. +Default key is '{\tt \^{}E}'. %.lp \item[\tb{\#wizgenesis}] -Create a monster. Autocompletes. Wizard-mode only. Default key is '{\tt \^{}G}'. +Create a monster. +May be prefixed by a count to create more than one. +Autocompletes. +Debug mode only. +Default key is '{\tt \^{}G}'. %.lp \item[\tb{\#wizidentify}] -Identify all items in inventory. Autocompletes. Wizard-mode only. +Identify all items in inventory. +Autocompletes. +Debug mode only. Default key is '{\tt \^{}I}'. %.lp \item[\tb{\#wizintrinsic}] -Set intrinsic. Autocompletes. Wizard-mode only. +Set one or more intrinsic attributes. +Autocompletes. +Debug mode only. %.lp \item[\tb{\#wizlevelport}] -Teleport to another level. Autocompletes. Wizard-mode only. Default key is '{\tt \^{}V}'. +Teleport to another level. +Autocompletes. +Debug mode only. +Default key is '{\tt \^{}V}'. %.lp \item[\tb{\#wizmap}] -Map the level. Autocompletes. Wizard-mode only. Default key is '{\tt \^{}F}'. +Map the level. +Autocompletes. +Debug mode only. +Default key is '{\tt \^{}F}'. %.lp \item[\tb{\#wizrumorcheck}] -Verify rumor boundaries. Autocompletes. Wizard-mode only. +Verify rumor boundaries. +Autocompletes. +Debug mode only. %.lp \item[\tb{\#wizsmell}] -Smell monster. Autocompletes. Wizard-mode only. +Smell monster. +Autocompletes. +Debug mode only. %.lp \item[\tb{\#wizwhere}] -Show locations of special levels. Autocompletes. Wizard-mode only. +Show locations of special levels. +Autocompletes. +Debug mode only. %.lp \item[\tb{\#wizwish}] -Wish for something. Autocompletes. Wizard-mode only. Default key is '{\tt \^{}W}'. +Wish for something. +Autocompletes. +Debug mode only. +Default key is '{\tt \^{}W}'. %.lp \item[\tb{\#wmode}] -Show wall modes. Autocompletes. Wizard-mode only. +Show wall modes. +Autocompletes. +Debug mode only. %.lp \item[\tb{\#zap}] Zap a wand. Default key is '{\tt z}'. @@ -2882,9 +2941,10 @@ Example: %.lp \item[\bb{WIZKIT}] -Wizard-mode extra items, in a text file containing item names, -one per line, up to a maximum of 128 lines. Each line is processed -by the function that handles wishing. +Debug mode only: extra items to add to initial inventory. +Value is the name of a text file containing a list of item names, +one per line, up to a maximum of 128 lines. +Each line is processed by the function that handles wishing. %.pg Example: %.sd @@ -3850,7 +3910,25 @@ in the message window. %.lp \item[\ib{windowcolors}] If {\it NetHack\/} can, it should display windows with the specified -foreground/background colors if it can. +foreground/background colors. Windows GUI only. The format is +\begin{verbatim} + OPTION=windowcolors:wintype foreground/background +\end{verbatim} + +%.pg +where wintype is one of {\it menu}, {\it message}, {\it status}, or {\it text}, and +foreground and background are colors, either a hexadecimal {\it \#rrggbb}, +one of the named colors ({\it black}, {\it red}, {\it green}, {\it brown}, +{\it blue}, {\it magenta}, {\it cyan}, {\it orange}, +{\it brightgreen}, {\it yellow}, {\it brightblue}, {\it brightmagenta}, +{\it brightcyan}, {\it white}, {\it trueblack}, {\it gray}, {\it purple}, +{\it silver}, {\it maroon}, {\it fuchsia}, {\it lime}, {\it olive}, +{\it navy}, {\it teal}, {\it aqua}), or one of Windows UI colors ({\it activeborder}, +{\it activecaption}, {\it appworkspace}, {\it background}, {\it btnface}, {\it btnshadow}, +{\it btntext}, {\it captiontext}, {\it graytext}, {\it greytext}, {\it highlight}, +{\it highlighttext}, {\it inactiveborder}, {\it inactivecaption}, {\it menu}, +{\it menutext}, {\it scrollbar}, {\it window}, {\it windowframe}, {\it windowtext}). + %.lp \item[\ib{wraptext}] If {\it NetHack\/} can, it should wrap long lines of text if they don't fit @@ -4793,9 +4871,10 @@ system). \blist{} %.lp \item[\ib{WIZARDS}] -A space-separated list of user name who are allowed to play in wizard -mode (the debugging mode, not the magic-useing role). A value of a single -asterisk (*) allows anyone to start a game in wizard mode. +A space-separated list of user name who are allowed to +play in debug mode (commonly referred to as wizard mode). +A value of a single +asterisk (*) allows anyone to start a game in debug mode. %.lp \item[\ib{SHELLERS}] A list of users who are allowed to use the shell escape command (`{\tt !}'). @@ -4921,10 +5000,13 @@ the trepid reader to discover. %.pg Debug mode, also known as wizard mode, is undocumented aside from this -brief description. It is intended for tracking down problems within the +brief description and the various ``debug mode only'' commands listed +among the command descriptions. +It is intended for tracking down problems within the program rather than to provide god-like powers to your character, and players who attempt debugging are expected to figure out how to use it -themselves. It is initiated by starting the game with the +themselves. +It is initiated by starting the game with the {\tt -D} command-line switch or with the {\it playmode:debug\/} @@ -4935,8 +5017,7 @@ For some systems, the player must be logged in under a particular user name to be allowed to use debug mode; for others, the hero must be given a particular character name (but may be any role; there's no connection between ``wizard mode'' and the {\it Wizard\/} role). -And on any system, the program might have been configured to omit debug -mode entirely. Attempting to start a game in debug mode when not allowed +Attempting to start a game in debug mode when not allowed or not available will result in falling back to explore mode instead. %.hn diff --git a/doc/fixes36.2 b/doc/fixes36.2 index ab3ee4870..576701c53 100644 --- a/doc/fixes36.2 +++ b/doc/fixes36.2 @@ -87,6 +87,23 @@ wallifying a special level might go out of map bounds (not with 3.6.x levels) and corrupt other level data if a random grave produced during level creation included some gold, that gold was left on the ground instead of being buried with other treasure +multiple instances of shop damage at same spot (before repairs, so a broken + door or dug wall plus trap creation) only charged hero for first one +shop door repair which took place when hero was on another level only worked + correctly if a trap at the same spot was removed +object scattering during shop wall repair was skipped if a trap at the same + spot was also being removed +augmented death reason for "while helpless" was broken for record and logfile + (but still correct for xlogfile) +prevent wish prompt input from remembering the previous wish +parchment and vellum are made from animal skin so change material composition + and color for spellbooks with those descriptions from paper to leather; + eating those books now breaks vegetarian conduct +fix monsters not wielding digging implements +wizard mode ^I^I didn't make temporary identifications become persistent if + the build configuration makes plain 'char' unsigned +wizard mode #wizidentify didn't disclose extra information for unID'd items if + key bindings took away ^I and didn't bind #wizidentify to another key Fixes to Post-3.6.1 Problems that Were Exposed Via git Repository @@ -135,6 +152,8 @@ status_hilite options which use comparisons may now use <= and >= in sortloot option has been enhanced to improve object ordering; primarily, items of undiscovered type come out before items of discovered type within each class or sub-class of objects +YAFM when stumbling on an undetected monster while hallucinating +Make it clear when a leprechaun dodges your attack Code Cleanup and Reorganization diff --git a/src/apply.c b/src/apply.c index d8cbb7a87..d7b770f4d 100644 --- a/src/apply.c +++ b/src/apply.c @@ -767,7 +767,7 @@ register xchar x, y; corpse less likely to remain tame after revival */ xkilled(mtmp, XKILL_NOMSG); /* life-saving doesn't ordinarily reset this */ - if (mtmp->mhp > 0) + if (!DEADMONSTER(mtmp)) u.uconduct.killer = save_pacifism; } else { pline("%s is choked by the leash!", Monnam(mtmp)); diff --git a/src/cmd.c b/src/cmd.c index d7303ec18..3afa198b0 100644 --- a/src/cmd.c +++ b/src/cmd.c @@ -7,6 +7,22 @@ #include "lev.h" #include "func_tab.h" +/* Macros for meta and ctrl modifiers: + * M and C return the meta/ctrl code for the given character; + * e.g., (C('c') is ctrl-c + */ +#ifndef M +#ifndef NHSTDC +#define M(c) (0x80 | (c)) +#else +#define M(c) ((c) - 128) +#endif /* NHSTDC */ +#endif + +#ifndef C +#define C(c) (0x1f & (c)) +#endif + #ifdef ALTMETA STATIC_VAR boolean alt_esc = FALSE; #endif @@ -625,8 +641,18 @@ wiz_identify(VOID_ARGS) { if (wizard) { iflags.override_ID = (int) cmd_from_func(wiz_identify); - if (display_inventory((char *) 0, TRUE) == -1) + /* command remapping might leave #wizidentify as the only way + to invoke us, in which case cmd_from_func() will yield NUL; + it won't matter to display_inventory()/display_pickinv() + if ^I invokes some other command--what matters is that it + is never an inventory letter */ + if (!iflags.override_ID) + iflags.override_ID = C('I'); + /* C('I') == ^I == default keystroke for wiz_identify; + it doesn't matter whether the command has been remapped */ + if (display_inventory((char *) 0, TRUE) == C('I')) identify_pack(0, FALSE); + /* [TODO? if player picks a specific inventory item, ID it] */ iflags.override_ID = 0; } else pline("Unavailable command '%s'.", @@ -2859,22 +2885,6 @@ int final; en_win = WIN_ERR; } -/* Macros for meta and ctrl modifiers: - * M and C return the meta/ctrl code for the given character; - * e.g., (C('c') is ctrl-c - */ -#ifndef M -#ifndef NHSTDC -#define M(c) (0x80 | (c)) -#else -#define M(c) ((c) - 128) -#endif /* NHSTDC */ -#endif - -#ifndef C -#define C(c) (0x1f & (c)) -#endif - /* ordered by command name */ struct ext_func_tab extcmdlist[] = { { '#', "#", "perform an extended command", diff --git a/src/dogmove.c b/src/dogmove.c index 614eef794..2ec72551e 100644 --- a/src/dogmove.c +++ b/src/dogmove.c @@ -326,7 +326,7 @@ boolean devour; /* turning into slime might be cureable */ if (slimer && munslime(mtmp, FALSE)) { /* but the cure (fire directed at self) might be fatal */ - if (mtmp->mhp < 1) + if (DEADMONSTER(mtmp)) return 2; slimer = FALSE; /* sliming is avoided, skip polymorph */ } @@ -370,7 +370,7 @@ struct edog *edog; mtmp->mhpmax = newmhpmax; if (mtmp->mhp > mtmp->mhpmax) mtmp->mhp = mtmp->mhpmax; - if (mtmp->mhp < 1) + if (DEADMONSTER(mtmp)) goto dog_died; if (cansee(mtmp->mx, mtmp->my)) pline("%s is confused from hunger.", Monnam(mtmp)); @@ -379,7 +379,7 @@ struct edog *edog; else You_feel("worried about %s.", y_monnam(mtmp)); stop_occupation(); - } else if (monstermoves > edog->hungrytime + 750 || mtmp->mhp < 1) { + } else if (monstermoves > edog->hungrytime + 750 || DEADMONSTER(mtmp)) { dog_died: if (mtmp->mleashed && mtmp != u.usteed) Your("leash goes slack."); diff --git a/src/dokick.c b/src/dokick.c index 363a13894..950d03553 100644 --- a/src/dokick.c +++ b/src/dokick.c @@ -97,7 +97,7 @@ register boolean clumsy; dmg += u.udaminc; /* add ring(s) of increase damage */ if (dmg > 0) mon->mhp -= dmg; - if (mon->mhp > 0 && martial() && !bigmonst(mon->data) && !rn2(3) + if (!DEADMONSTER(mon) && martial() && !bigmonst(mon->data) && !rn2(3) && mon->mcanmove && mon != u.ustuck && !mon->mtrapped) { /* see if the monster has a place to move into */ mdx = mon->mx + u.dx; @@ -116,8 +116,8 @@ register boolean clumsy; } } - (void) passive(mon, uarmf, TRUE, mon->mhp > 0, AT_KICK, FALSE); - if (mon->mhp <= 0 && !trapkilled) + (void) passive(mon, uarmf, TRUE, !DEADMONSTER(mon), AT_KICK, FALSE); + if (DEADMONSTER(mon) && !trapkilled) killed(mon); /* may bring up a dialog, so put this after all messages */ @@ -914,7 +914,7 @@ dokick() kick_monster(mtmp, x, y); glyph = glyph_at(x, y); /* see comment in attack_checks() */ - if (mtmp->mhp <= 0) { /* DEADMONSTER() */ + if (DEADMONSTER(mtmp)) { /* DEADMONSTER() */ /* if we mapped an invisible monster and immediately killed it, we don't want to forget what we thought was there before the kick */ diff --git a/src/eat.c b/src/eat.c index f398c8cc5..895cdf2a6 100644 --- a/src/eat.c +++ b/src/eat.c @@ -525,7 +525,7 @@ int *dmg_p; /* for dishing out extra damage in lieu of Int loss */ if (visflag && canseemon(magr)) pline("%s turns to stone!", Monnam(magr)); monstone(magr); - if (magr->mhp > 0) { + if (!DEADMONSTER(magr)) { /* life-saved; don't continue eating the brains */ return MM_MISS; } else { @@ -612,7 +612,7 @@ int *dmg_p; /* for dishing out extra damage in lieu of Int loss */ return MM_MISS; } else if (is_rider(pd)) { mondied(magr); - if (magr->mhp <= 0) + if (DEADMONSTER(magr)) result = MM_AGR_DIED; /* Rider takes extra damage regardless of whether attacker dies */ *dmg_p += xtra_dmg; diff --git a/src/end.c b/src/end.c index 589733078..4d176323b 100644 --- a/src/end.c +++ b/src/end.c @@ -748,7 +748,7 @@ time_t when; /* date+time at end of game */ dump_plines(); putstr(0, 0, ""); putstr(0, 0, "Inventory:"); - display_inventory((char *) 0, TRUE); + (void) display_inventory((char *) 0, TRUE); container_contents(invent, TRUE, TRUE, FALSE); enlightenment((BASICENLIGHTENMENT | MAGICENLIGHTENMENT), (how >= PANICKED) ? ENL_GAMEOVERALIVE : ENL_GAMEOVERDEAD); diff --git a/src/explode.c b/src/explode.c index fcda5f956..c48f9ffb1 100644 --- a/src/explode.c +++ b/src/explode.c @@ -208,7 +208,7 @@ int expltype; if (!mtmp && i + x - 1 == u.ux && j + y - 1 == u.uy) mtmp = u.usteed; if (mtmp) { - if (mtmp->mhp < 1) + if (DEADMONSTER(mtmp)) explmask[i][j] = 2; else switch (adtyp) { @@ -444,7 +444,7 @@ int expltype; mtmp->mhp -= mdam; mtmp->mhp -= (idamres + idamnonres); } - if (mtmp->mhp <= 0) { + if (DEADMONSTER(mtmp)) { int xkflg = ((adtyp == AD_FIRE && completelyburns(mtmp->data)) ? XKILL_NOCORPSE : 0); diff --git a/src/invent.c b/src/invent.c index 9ea974698..6355a255a 100644 --- a/src/invent.c +++ b/src/invent.c @@ -5,6 +5,10 @@ #include "hack.h" +#ifndef C /* same as cmd.c */ +#define C(c) (0x1f & (c)) +#endif + #define NOINVSYM '#' #define CONTAINED_SYM '>' /* designator for inside a container */ #define HANDS_SYM '-' @@ -2580,9 +2584,15 @@ long *out_cnt; if (wizard && iflags.override_ID) { char prompt[QBUFSZ]; - any.a_char = -1; + /* C('I') == ^I == default keystroke for wiz_identify; + it is guaranteed not to be in use as an inventory letter + (wiz_identify might be remapped to an ordinary letter, + making iflags.override_ID ambiguous as a return value) */ + any.a_char = C('I'); /* wiz_identify stuffed the wiz_identify command character (^I) - into iflags.override_ID for our use as an accelerator */ + into iflags.override_ID for our use as an accelerator; + it could be ambiguous as a selector but the only time it + is wanted is in case where no item is being selected */ Sprintf(prompt, "Debug Identify (%s to permanently identify)", visctrl(iflags.override_ID)); add_menu(win, NO_GLYPH, &any, '_', iflags.override_ID, ATR_NONE, diff --git a/src/makemon.c b/src/makemon.c index 85ba282a5..0f8cde39d 100644 --- a/src/makemon.c +++ b/src/makemon.c @@ -1752,7 +1752,7 @@ struct monst *mtmp, *victim; /* monster died after killing enemy but before calling this function */ /* currently possible if killing a gas spore */ /* Also used to abort processing for CONWAYS's mildew temp monsters. */ - if (mtmp->mhp <= 0) + if (DEADMONSTER(mtmp)) return (struct permonst *) 0; /* note: none of the monsters with special hit point calculations diff --git a/src/mhitm.c b/src/mhitm.c index 72e10b5e8..56d52a3e7 100644 --- a/src/mhitm.c +++ b/src/mhitm.c @@ -245,7 +245,7 @@ boolean quietly; if (!quietly && canspotmon(magr)) pline("%s turns to stone!", Monnam(magr)); monstone(magr); - if (magr->mhp > 0) + if (!DEADMONSTER(magr)) return MM_HIT; /* lifesaved */ else if (magr->mtame && !vis) You(brief_feeling, "peculiarly sad"); @@ -631,7 +631,7 @@ struct attack *mattk; if (canseemon(magr)) pline("%s is turned to stone!", Monnam(magr)); monstone(magr); - if (magr->mhp > 0) + if (!DEADMONSTER(magr)) return MM_MISS; return MM_AGR_DIED; } @@ -780,7 +780,7 @@ struct attack *mattk; /* Kill off aggressor if it didn't die. */ if (!(result & MM_AGR_DIED)) { mondead(magr); - if (magr->mhp > 0) + if (!DEADMONSTER(magr)) return result; /* life saved */ result |= MM_AGR_DIED; } @@ -824,7 +824,7 @@ register struct attack *mattk; if (vis && canspotmon(magr)) pline("%s turns to stone!", Monnam(magr)); monstone(magr); - if (magr->mhp > 0) + if (!DEADMONSTER(magr)) return MM_HIT; /* lifesaved */ else if (magr->mtame && !vis) You(brief_feeling, "peculiarly sad"); @@ -848,7 +848,7 @@ register struct attack *mattk; ? "coughs spasmodically and collapses" : "vomits violently and drops dead"); mondied(magr); - if (magr->mhp > 0) + if (!DEADMONSTER(magr)) return 0; /* lifesaved */ else if (magr->mtame && !vis) You(brief_feeling, "queasy"); @@ -862,7 +862,7 @@ register struct attack *mattk; m_useup(mdef, obj); /* Is a corpse for nutrition possible? It may kill magr */ - if (!corpse_chance(mdef, magr, TRUE) || magr->mhp < 1) + if (!corpse_chance(mdef, magr, TRUE) || DEADMONSTER(magr)) break; /* Pets get nutrition from swallowing monster whole. @@ -922,7 +922,7 @@ register struct attack *mattk; tmp = 1; if (otmp->oartifact) { (void) artifact_hit(magr, mdef, otmp, &tmp, dieroll); - if (mdef->mhp <= 0) + if (DEADMONSTER(mdef)) return (MM_DEF_DIED | (grow_up(magr, mdef) ? 0 : MM_AGR_DIED)); } @@ -949,7 +949,7 @@ register struct attack *mattk; if (vis && canseemon(mdef)) pline("%s burns completely!", Monnam(mdef)); mondead(mdef); /* was mondied() but that dropped paper scrolls */ - if (mdef->mhp > 0) + if (!DEADMONSTER(mdef)) return 0; else if (mdef->mtame && !vis) pline("May %s roast in peace.", mon_nam(mdef)); @@ -1027,7 +1027,7 @@ register struct attack *mattk; if (vis && canseemon(mdef)) pline("%s falls to pieces!", Monnam(mdef)); mondied(mdef); - if (mdef->mhp > 0) + if (!DEADMONSTER(mdef)) return 0; else if (mdef->mtame && !vis) pline("May %s rust in peace.", mon_nam(mdef)); @@ -1051,7 +1051,7 @@ register struct attack *mattk; if (vis && canseemon(mdef)) pline("%s falls to pieces!", Monnam(mdef)); mondied(mdef); - if (mdef->mhp > 0) + if (!DEADMONSTER(mdef)) return 0; else if (mdef->mtame && !vis) pline("May %s rot in peace.", mon_nam(mdef)); @@ -1078,7 +1078,7 @@ register struct attack *mattk; pline("%s turns to stone!", Monnam(mdef)); monstone(mdef); post_stone: - if (mdef->mhp > 0) + if (!DEADMONSTER(mdef)) return 0; else if (mdef->mtame && !vis) You(brief_feeling, "peculiarly sad"); @@ -1182,7 +1182,7 @@ register struct attack *mattk; pline("%s is destroyed!", Monnam(mdef)); } mondied(mdef); - if (mdef->mhp > 0) + if (!DEADMONSTER(mdef)) return 0; else if (mdef->mtame && !vis) You(brief_feeling, "strangely sad"); @@ -1278,7 +1278,7 @@ register struct attack *mattk; possibly_unwield(mdef, FALSE); mdef->mstrategy &= ~STRAT_WAITFORU; mselftouch(mdef, (const char *) 0, FALSE); - if (mdef->mhp <= 0) + if (DEADMONSTER(mdef)) return (MM_DEF_DIED | (grow_up(magr, mdef) ? 0 : MM_AGR_DIED)); if (pa->mlet == S_NYMPH && !tele_restrict(magr)) { @@ -1341,7 +1341,7 @@ register struct attack *mattk; if (cancelled) break; /* physical damage only */ if (!rn2(4) && !slimeproof(pd)) { - if (!munslime(mdef, FALSE) && mdef->mhp > 0) { + if (!munslime(mdef, FALSE) && !DEADMONSTER(mdef)) { if (newcham(mdef, &mons[PM_GREEN_SLIME], FALSE, vis && canseemon(mdef))) pd = mdef->data; mdef->mstrategy &= ~STRAT_WAITFORU; @@ -1349,9 +1349,9 @@ register struct attack *mattk; } /* munslime attempt could have been fatal, potentially to multiple monsters (SCR_FIRE) */ - if (magr->mhp < 1) + if (DEADMONSTER(magr)) res |= MM_AGR_DIED; - if (mdef->mhp < 1) + if (DEADMONSTER(mdef)) res |= MM_DEF_DIED; tmp = 0; } @@ -1383,7 +1383,7 @@ register struct attack *mattk; mdef->mhp = 0; } monkilled(mdef, "", (int) mattk->adtyp); - if (mdef->mhp > 0) + if (!DEADMONSTER(mdef)) return res; /* mdef lifesaved */ else if (res == MM_AGR_DIED) return (MM_DEF_DIED | MM_AGR_DIED); @@ -1398,7 +1398,7 @@ register struct attack *mattk; } else if (pd == &mons[PM_WRAITH]) { (void) grow_up(magr, (struct monst *) 0); /* don't grow up twice */ - return (MM_DEF_DIED | (magr->mhp > 0 ? 0 : MM_AGR_DIED)); + return (MM_DEF_DIED | (!DEADMONSTER(magr) ? 0 : MM_AGR_DIED)); } else if (pd == &mons[PM_NURSE]) { magr->mhp = magr->mhpmax; } diff --git a/src/mhitu.c b/src/mhitu.c index 12a6d3212..c429a0241 100644 --- a/src/mhitu.c +++ b/src/mhitu.c @@ -365,7 +365,7 @@ register struct monst *mtmp; if (!ranged) nomul(0); - if (mtmp->mhp <= 0 || (Underwater && !is_swimmer(mtmp->data))) + if (DEADMONSTER(mtmp) || (Underwater && !is_swimmer(mtmp->data))) return 0; /* If swallowed, can only be affected by u.ustuck */ @@ -1796,7 +1796,7 @@ struct attack *mattk; if (Punished) placebc(); u.ustuck = 0; - return (mtmp->mhp > 0) ? 0 : 2; + return (!DEADMONSTER(mtmp)) ? 0 : 2; } display_nhwindow(WIN_MESSAGE, FALSE); @@ -2066,7 +2066,7 @@ boolean ufound; if (kill_agr) mondead(mtmp); wake_nearto(mtmp->mx, mtmp->my, 7 * 7); - return (mtmp->mhp > 0) ? 0 : 2; + return (!DEADMONSTER(mtmp)) ? 0 : 2; } /* monster gazes at you */ @@ -2132,7 +2132,7 @@ struct attack *mattk; stoned = TRUE; killed(mtmp); - if (mtmp->mhp > 0) + if (!DEADMONSTER(mtmp)) break; return 2; } @@ -2768,7 +2768,7 @@ struct attack *mattk; pline("%s turns to stone!", Monnam(mtmp)); stoned = 1; xkilled(mtmp, XKILL_NOMSG); - if (mtmp->mhp > 0) + if (!DEADMONSTER(mtmp)) return 1; return 2; } @@ -2879,7 +2879,7 @@ assess_dmg: if ((mtmp->mhp -= tmp) <= 0) { pline("%s dies!", Monnam(mtmp)); xkilled(mtmp, XKILL_NOMSG); - if (mtmp->mhp > 0) + if (!DEADMONSTER(mtmp)) return 1; return 2; } diff --git a/src/mkobj.c b/src/mkobj.c index 1724cded5..cf7a77233 100644 --- a/src/mkobj.c +++ b/src/mkobj.c @@ -1861,7 +1861,7 @@ discard_minvent(mtmp) struct monst *mtmp; { struct obj *otmp, *mwep = MON_WEP(mtmp); - boolean keeping_mon = (mtmp->mhp > 0); + boolean keeping_mon = (!DEADMONSTER(mtmp)); while ((otmp = mtmp->minvent) != 0) { /* this has now become very similar to m_useupall()... */ diff --git a/src/mon.c b/src/mon.c index 2ccb585cb..39e777a26 100644 --- a/src/mon.c +++ b/src/mon.c @@ -509,9 +509,9 @@ register struct monst *mtmp; mtmp->mhp -= dam; if (mtmp->mhpmax > dam) mtmp->mhpmax -= dam; - if (mtmp->mhp < 1) { + if (DEADMONSTER(mtmp)) { mondead(mtmp); - if (mtmp->mhp < 1) + if (DEADMONSTER(mtmp)) return 1; } water_damage_chain(mtmp->minvent, FALSE); @@ -538,14 +538,14 @@ register struct monst *mtmp; mondead(mtmp); } else { mtmp->mhp -= 1; - if (mtmp->mhp < 1) { + if (DEADMONSTER(mtmp)) { if (cansee(mtmp->mx, mtmp->my)) pline("%s surrenders to the fire.", Monnam(mtmp)); mondead(mtmp); } else if (cansee(mtmp->mx, mtmp->my)) pline("%s burns slightly.", Monnam(mtmp)); } - if (mtmp->mhp > 0) { + if (!DEADMONSTER(mtmp)) { (void) fire_damage_chain(mtmp->minvent, FALSE, FALSE, mtmp->mx, mtmp->my); (void) rloc(mtmp, FALSE); @@ -570,7 +570,7 @@ register struct monst *mtmp; Monnam(mtmp), hliquid("water")); } mondead(mtmp); - if (mtmp->mhp > 0) { + if (!DEADMONSTER(mtmp)) { water_damage_chain(mtmp->minvent, FALSE); (void) rloc(mtmp, FALSE); return 0; @@ -708,7 +708,7 @@ movemon() nmtmp = mtmp->nmon; /* one dead monster needs to perform a move after death: vault guard whose temporary corridor is still on the map */ - if (mtmp->isgd && !mtmp->mx && mtmp->mhp <= 0) + if (mtmp->isgd && !mtmp->mx && DEADMONSTER(mtmp)) (void) gd_move(mtmp); if (DEADMONSTER(mtmp)) continue; @@ -1536,7 +1536,7 @@ dmonsfree() for (mtmp = &fmon; *mtmp;) { freetmp = *mtmp; - if (freetmp->mhp <= 0 && !freetmp->isgd) { + if (DEADMONSTER(freetmp) && !freetmp->isgd) { *mtmp = freetmp->nmon; freetmp->nmon = NULL; dealloc_monst(freetmp); @@ -1825,7 +1825,7 @@ register struct monst *mtmp; mtmp->mhp = 0; /* in case caller hasn't done this */ lifesaved_monster(mtmp); - if (mtmp->mhp > 0) + if (!DEADMONSTER(mtmp)) return; if (is_vampshifter(mtmp)) { @@ -1993,9 +1993,9 @@ boolean was_swallowed; /* digestion */ } else { You_hear("an explosion."); magr->mhp -= tmp; - if (magr->mhp < 1) + if (DEADMONSTER(magr)) mondied(magr); - if (magr->mhp < 1) { /* maybe lifesaved */ + if (DEADMONSTER(magr)) { /* maybe lifesaved */ if (canspotmon(magr)) pline("%s rips open!", Monnam(magr)); } else if (canseemon(magr)) @@ -2033,7 +2033,7 @@ mondied(mdef) register struct monst *mdef; { mondead(mdef); - if (mdef->mhp > 0) + if (!DEADMONSTER(mdef)) return; /* lifesaved */ if (corpse_chance(mdef, (struct monst *) 0, FALSE) @@ -2083,7 +2083,7 @@ struct monst *mdef; */ mdef->mhp = 0; /* in case caller hasn't done this */ lifesaved_monster(mdef); - if (mdef->mhp > 0) + if (!DEADMONSTER(mdef)) return; mdef->mtrapped = 0; /* (see m_detach) */ @@ -2176,7 +2176,7 @@ int how; else mondied(mdef); - if (be_sad && mdef->mhp <= 0) + if (be_sad && DEADMONSTER(mdef)) You("have a sad feeling for a moment, then it passes."); } @@ -2276,7 +2276,7 @@ int xkill_flags; /* 1: suppress message, 2: suppress corpse, 4: pacifist */ mondead(mtmp); disintegested = FALSE; /* reset */ - if (mtmp->mhp > 0) { /* monster lifesaved */ + if (!DEADMONSTER(mtmp)) { /* 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). diff --git a/src/monmove.c b/src/monmove.c index cdef76f89..0abf63b6d 100644 --- a/src/monmove.c +++ b/src/monmove.c @@ -31,9 +31,9 @@ struct monst *mtmp; wake_nearto(mtmp->mx, mtmp->my, 7 * 7); mtmp->mstun = 1; mtmp->mhp -= rnd(15); - if (mtmp->mhp <= 0) { + if (DEADMONSTER(mtmp)) { mondied(mtmp); - if (mtmp->mhp > 0) /* lifesaved */ + if (!DEADMONSTER(mtmp)) /* lifesaved */ return FALSE; else return TRUE; @@ -413,7 +413,7 @@ register struct monst *mtmp; m_respond(mtmp); if (mdat == &mons[PM_MEDUSA] && couldsee(mtmp->mx, mtmp->my)) m_respond(mtmp); - if (mtmp->mhp <= 0) + if (DEADMONSTER(mtmp)) return 1; /* m_respond gaze can kill medusa */ /* fleeing monsters might regain courage */ @@ -518,7 +518,7 @@ register struct monst *mtmp; if (cansee(m2->mx, m2->my)) pline("It locks on to %s.", mon_nam(m2)); m2->mhp -= rnd(15); - if (m2->mhp <= 0) + if (DEADMONSTER(m2)) monkilled(m2, "", AD_DRIN); else m2->msleeping = 0; @@ -590,7 +590,7 @@ toofar: case 0: /* no movement, but it can still attack you */ case 3: /* absolutely no movement */ /* vault guard might have vanished */ - if (mtmp->isgd && (mtmp->mhp < 1 || mtmp->mx == 0)) + if (mtmp->isgd && (DEADMONSTER(mtmp) || mtmp->mx == 0)) return 1; /* behave as if it died */ /* During hallucination, monster appearance should * still change - even if it doesn't move. @@ -716,25 +716,25 @@ struct monst *mtmp; xchar nix,niy; { boolean can_tunnel = 0; - struct obj *mw_tmp; + struct obj *mw_tmp = MON_WEP(mtmp); 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 (can_tunnel && needspick(mtmp->data) && !mwelded(mw_tmp) + && (may_dig(nix, niy) || closed_door(nix, niy))) { + /* may_dig() is either IS_STWALL or IS_TREE */ if (closed_door(nix, niy)) { - if (!(mw_tmp = MON_WEP(mtmp)) + if (!mw_tmp || !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; + } else if (IS_STWALL(levl[nix][niy].typ)) { + 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; diff --git a/src/mthrowu.c b/src/mthrowu.c index ed5dec975..e2ec346aa 100644 --- a/src/mthrowu.c +++ b/src/mthrowu.c @@ -285,7 +285,7 @@ struct obj *otmp, *mwep; if mtmp gets killed (shot kills adjacent gas spore and triggers explosion, perhaps), inventory will be dropped and otmp might go away via merging into another stack */ - if (mtmp->mhp <= 0 && m_shot.i < m_shot.n) + if (DEADMONSTER(mtmp) && m_shot.i < m_shot.n) /* cancel pending shots (perhaps ought to give a message here since we gave one above about throwing/shooting N missiles) */ break; /* endmultishot(FALSE); */ @@ -404,9 +404,9 @@ boolean verbose; /* give message(s) even when you can't see what happened */ damage = 0; } - if (mtmp->mhp > 0) { /* might already be dead (if petrified) */ + if (!DEADMONSTER(mtmp)) { /* might already be dead (if petrified) */ mtmp->mhp -= damage; - if (mtmp->mhp < 1) { + if (DEADMONSTER(mtmp)) { if (vis || (verbose && !target)) pline("%s is %s!", Monnam(mtmp), (nonliving(mtmp->data) || is_vampshifter(mtmp) @@ -422,7 +422,7 @@ boolean verbose; /* give message(s) even when you can't see what happened */ /* blinding venom and cream pie do 0 damage, but verify that the target is still alive anyway */ - if (mtmp->mhp > 0 + if (!DEADMONSTER(mtmp) && can_blnd((struct monst *) 0, mtmp, (uchar) ((otmp->otyp == BLINDING_VENOM) ? AT_SPIT : AT_WEAP), diff --git a/src/muse.c b/src/muse.c index 402f7250f..e0403003b 100644 --- a/src/muse.c +++ b/src/muse.c @@ -155,7 +155,7 @@ struct obj *obj; } m_useup(mon, obj); mon->mhp -= dam; - if (mon->mhp <= 0) { + if (DEADMONSTER(mon)) { monkilled(mon, "", AD_RBRE); return 1; } @@ -1273,7 +1273,7 @@ register struct obj *otmp; break; } if (reveal_invis) { - if (mtmp->mhp > 0 && cansee(bhitpos.x, bhitpos.y) + if (!DEADMONSTER(mtmp) && cansee(bhitpos.x, bhitpos.y) && !canspotmon(mtmp)) map_invisible(bhitpos.x, bhitpos.y); } @@ -1406,7 +1406,7 @@ struct monst *mtmp; (otmp->otyp == WAN_MAGIC_MISSILE) ? 2 : 6, mtmp->mx, mtmp->my, sgn(mtmp->mux - mtmp->mx), sgn(mtmp->muy - mtmp->my)); m_using = FALSE; - return (mtmp->mhp <= 0) ? 1 : 2; + return (DEADMONSTER(mtmp)) ? 1 : 2; case MUSE_FIRE_HORN: case MUSE_FROST_HORN: if (oseen) { @@ -1420,7 +1420,7 @@ struct monst *mtmp; rn1(6, 6), mtmp->mx, mtmp->my, sgn(mtmp->mux - mtmp->mx), sgn(mtmp->muy - mtmp->my)); m_using = FALSE; - return (mtmp->mhp <= 0) ? 1 : 2; + return (DEADMONSTER(mtmp)) ? 1 : 2; case MUSE_WAN_TELEPORTATION: case MUSE_WAN_STRIKING: zap_oseen = oseen; @@ -1473,7 +1473,7 @@ struct monst *mtmp; drop_boulder_on_player(confused, !is_cursed, FALSE, TRUE); } - return (mtmp->mhp <= 0) ? 1 : 2; + return (DEADMONSTER(mtmp)) ? 1 : 2; } #if 0 case MUSE_SCR_FIRE: { @@ -1513,7 +1513,7 @@ struct monst *mtmp; mtmp2->mhp -= num; if (resists_cold(mtmp2)) mtmp2->mhp -= 3 * num; - if (mtmp2->mhp < 1) { + if (DEADMONSTER(mtmp2)) { mondied(mtmp2); break; } @@ -2260,7 +2260,7 @@ boolean stoning; /* True: stop petrification, False: cure stun && confusion */ mon->mhp -= rnd(15); if (vis) pline("%s has a very bad case of stomach acid.", Monnam(mon)); - if (mon->mhp <= 0) { + if (DEADMONSTER(mon)) { pline("%s dies!", Monnam(mon)); if (by_you) /* hero gets credit (experience) and blame (possible loss @@ -2502,7 +2502,7 @@ boolean by_you; /* true: if mon kills itself, hero gets credit/blame */ 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 (DEADMONSTER(mon)) { if (by_you) { /* mon killed self but hero gets credit and blame (except for pacifist conduct); xkilled()'s message would say @@ -2520,7 +2520,7 @@ boolean by_you; /* true: if mon kills itself, hero gets credit/blame */ } } if (vis) { - if (res && mon->mhp > 0) + if (res && !DEADMONSTER(mon)) pline("%s slime is burned away!", s_suffix(Monnam(mon))); if (otyp != STRANGE_OBJECT) makeknown(otyp); diff --git a/src/music.c b/src/music.c index 071d33635..24e1c559e 100644 --- a/src/music.c +++ b/src/music.c @@ -354,9 +354,9 @@ int force; /* Falling is okay for falling down within a pit from jostling too */ mselftouch(mtmp, "Falling, ", TRUE); - if (mtmp->mhp > 0) { + if (!DEADMONSTER(mtmp)) { mtmp->mhp -= rnd(m_already_trapped ? 4 : 6); - if (mtmp->mhp <= 0) { + if (DEADMONSTER(mtmp)) { if (!cansee(x, y)) { pline("It is destroyed!"); } else { diff --git a/src/objects.c b/src/objects.c index 3a8db8d92..0809ff41a 100644 --- a/src/objects.c +++ b/src/objects.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 objects.c $NHDT-Date: 1447313395 2015/11/12 07:29:55 $ $NHDT-Branch: master $:$NHDT-Revision: 1.49 $ */ +/* NetHack 3.6 objects.c $NHDT-Date: 1535422421 2018/08/28 02:13:41 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.51 $ */ /* Copyright (c) Mike Threepoint, 1989. */ /* NetHack may be freely redistributed. See license for details. */ @@ -883,18 +883,35 @@ SCROLL("blank paper", "unlabeled", 0, 28, 60), #undef SCROLL /* spellbooks ... */ -/* expanding beyond 52 spells would require changes in spellcasting - or imposition of a limit on number of spells hero can know because - they are currently assigned successive letters, a-zA-Z, when learned */ + /* Expanding beyond 52 spells would require changes in spellcasting + * or imposition of a limit on number of spells hero can know because + * they are currently assigned successive letters, a-zA-Z, when learned. + * [The existing spell sorting capability could conceivably be extended + * to enable moving spells from beyond Z to within it, bumping others + * out in the process, allowing more than 52 spells be known but keeping + * only 52 be castable at any given time.] + */ #define SPELL(name,desc,sub,prob,delay,level,mgc,dir,color) \ OBJECT(OBJ(name, desc), \ BITS(0, 0, 0, 0, mgc, 0, 0, 0, 0, 0, dir, sub, PAPER), \ 0, SPBOOK_CLASS, prob, delay, 50, level * 100, \ 0, 0, 0, level, 20, color) +/* Spellbook description normally refers to book covers (primarily color). + Parchment and vellum would never be used for such, but rather than + eliminate those, finagle their definitions to refer to the pages + rather than the cover. They are made from animal skin (typically of + a goat or sheep) and books using them for pages generally need heavy + covers with straps or clamps to tightly close the book in order to + keep the pages flat. (However, a wooden cover might itself be covered + by a sheet of parchment, making this become less of an exception. Also, + changing the internal composition from paper to leather makes eating a + parchment or vellum spellbook break vegetarian conduct, as it should.) */ +#define PAPER LEATHER /* override enum for use in SPELL() expansion */ SPELL("dig", "parchment", - P_MATTER_SPELL, 20, 6, 5, 1, RAY, HI_PAPER), + P_MATTER_SPELL, 20, 6, 5, 1, RAY, HI_LEATHER), SPELL("magic missile", "vellum", - P_ATTACK_SPELL, 45, 2, 2, 1, RAY, HI_PAPER), + P_ATTACK_SPELL, 45, 2, 2, 1, RAY, HI_LEATHER), +#undef PAPER /* revert to normal material */ SPELL("fireball", "ragged", P_ATTACK_SPELL, 20, 4, 4, 1, RAY, HI_PAPER), SPELL("cone of cold", "dog eared", diff --git a/src/polyself.c b/src/polyself.c index 5111ec41e..c7f9c538d 100644 --- a/src/polyself.c +++ b/src/polyself.c @@ -1355,7 +1355,7 @@ dogaze() (void) destroy_mitem(mtmp, SPBOOK_CLASS, AD_FIRE); if (dmg) mtmp->mhp -= dmg; - if (mtmp->mhp <= 0) + if (DEADMONSTER(mtmp)) killed(mtmp); } /* For consistency with passive() in uhitm.c, this only @@ -1517,7 +1517,7 @@ domindblast() u_sen ? "telepathy" : telepathic(mtmp->data) ? "latent telepathy" : "mind"); mtmp->mhp -= rnd(15); - if (mtmp->mhp <= 0) + if (DEADMONSTER(mtmp)) killed(mtmp); } } diff --git a/src/potion.c b/src/potion.c index d90beb898..6904bc315 100644 --- a/src/potion.c +++ b/src/potion.c @@ -1464,7 +1464,7 @@ int how; wake_nearto(tx, ty, mon->data->mlevel * 10); mon->mhp -= d(2, 6); /* should only be by you */ - if (mon->mhp < 1) + if (DEADMONSTER(mon)) killed(mon); else if (is_were(mon->data) && !is_human(mon->data)) new_were(mon); /* revert to human */ @@ -1487,7 +1487,7 @@ int how; pline("%s rusts.", Monnam(mon)); mon->mhp -= d(1, 6); /* should only be by you */ - if (mon->mhp < 1) + if (DEADMONSTER(mon)) killed(mon); } break; @@ -1502,7 +1502,7 @@ int how; if (!is_silent(mon->data)) wake_nearto(tx, ty, mon->data->mlevel * 10); mon->mhp -= d(obj->cursed ? 2 : 1, obj->blessed ? 4 : 8); - if (mon->mhp < 1) { + if (DEADMONSTER(mon)) { if (your_fault) killed(mon); else @@ -1523,7 +1523,7 @@ int how; */ } /* target might have been killed */ - if (mon->mhp > 0) { + if (!DEADMONSTER(mon)) { if (angermon) wakeup(mon, TRUE); else diff --git a/src/read.c b/src/read.c index f86afe04a..c4cf716e9 100644 --- a/src/read.c +++ b/src/read.c @@ -1814,7 +1814,7 @@ boolean confused, byu; } } mtmp->mhp -= mdmg; - if (mtmp->mhp <= 0) { + if (DEADMONSTER(mtmp)) { if (byu) { killed(mtmp); } else { @@ -2424,6 +2424,146 @@ struct obj *from_obj; return FALSE; } +struct _create_particular_data { + int which; + int fem; + char monclass; + boolean randmonst; + boolean maketame, makepeaceful, makehostile; + boolean sleeping, saddled, invisible; +}; + +boolean +create_particular_parse(str, d) +char *str; +struct _create_particular_data *d; +{ + char *bufp = str; + char *tmpp; + + d->monclass = MAXMCLASSES; + d->which = urole.malenum; /* an arbitrary index into mons[] */ + d->fem = -1; /* gender not specified */ + d->randmonst = FALSE; + d->maketame = d->makepeaceful = d->makehostile = FALSE; + d->sleeping = d->saddled = d->invisible = FALSE; + + if ((tmpp = strstri(bufp, "saddled ")) != 0) { + d->saddled = TRUE; + (void) memset(tmpp, ' ', sizeof "saddled " - 1); + } + if ((tmpp = strstri(bufp, "sleeping ")) != 0) { + d->sleeping = TRUE; + (void) memset(tmpp, ' ', sizeof "sleeping " - 1); + } + if ((tmpp = strstri(bufp, "invisible ")) != 0) { + d->invisible = TRUE; + (void) memset(tmpp, ' ', sizeof "invisible " - 1); + } + /* check "female" before "male" to avoid false hit mid-word */ + if ((tmpp = strstri(bufp, "female ")) != 0) { + d->fem = 1; + (void) memset(tmpp, ' ', sizeof "female " - 1); + } + if ((tmpp = strstri(bufp, "male ")) != 0) { + d->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; + d->maketame = TRUE; + } else if (!strncmpi(bufp, "peaceful ", 9)) { + bufp += 9; + d->makepeaceful = TRUE; + } else if (!strncmpi(bufp, "hostile ", 8)) { + bufp += 8; + d->makehostile = TRUE; + } + /* decide whether a valid monster was chosen */ + if (wizard && (!strcmp(bufp, "*") || !strcmp(bufp, "random"))) { + d->randmonst = TRUE; + return TRUE; + } + d->which = name_to_mon(bufp); + if (d->which >= LOW_PM) + return TRUE; /* got one */ + d->monclass = name_to_monclass(bufp, &d->which); + if (d->which >= LOW_PM) { + d->monclass = MAXMCLASSES; /* matters below */ + return TRUE; + } else if (d->monclass > 0) { + d->which = urole.malenum; /* reset from NON_PM */ + return TRUE; + } + return FALSE; +} + +boolean +create_particular_creation(d) +struct _create_particular_data *d; +{ + struct permonst *whichpm = NULL; + int i, firstchoice = NON_PM; + struct monst *mtmp; + boolean madeany = FALSE; + + if (!d->randmonst) { + firstchoice = d->which; + if (cant_revive(&d->which, FALSE, (struct obj *) 0)) { + /* wizard mode can override handling of special monsters */ + char buf[BUFSZ]; + + Sprintf(buf, "Creating %s instead; force %s?", + mons[d->which].mname, mons[firstchoice].mname); + if (yn(buf) == 'y') + d->which = firstchoice; + } + whichpm = &mons[d->which]; + } + for (i = 0; i <= multi; i++) { + if (d->monclass != MAXMCLASSES) + whichpm = mkclass(d->monclass, 0); + else if (d->randmonst) + whichpm = rndmonst(); + mtmp = makemon(whichpm, u.ux, u.uy, NO_MM_FLAGS); + if (!mtmp) { + /* quit trying if creation failed and is going to repeat */ + if (d->monclass == MAXMCLASSES && !d->randmonst) + break; + /* otherwise try again */ + continue; + } + /* 'is_FOO()' ought to be called 'always_FOO()' */ + if (d->fem != -1 && !is_male(mtmp->data) && !is_female(mtmp->data)) + mtmp->female = d->fem; /* ignored for is_neuter() */ + if (d->maketame) { + (void) tamedog(mtmp, (struct obj *) 0); + } else if (d->makepeaceful || d->makehostile) { + mtmp->mtame = 0; /* sanity precaution */ + mtmp->mpeaceful = d->makepeaceful ? 1 : 0; + set_malign(mtmp); + } + if (d->saddled && can_saddle(mtmp) && !which_armor(mtmp, W_SADDLE)) { + struct obj *otmp = mksobj(SADDLE, TRUE, FALSE); + + put_saddle_on_mon(otmp, mtmp); + } + if (d->invisible) + mon_set_minvis(mtmp); + if (d->sleeping) + mtmp->msleeping = 1; + madeany = TRUE; + /* in case we got a doppelganger instead of what was asked + for, make it start out looking like what was asked for */ + if (mtmp->cham != NON_PM && firstchoice != NON_PM + && mtmp->cham != firstchoice) + (void) newcham(mtmp, &mons[firstchoice], FALSE, FALSE); + } + return madeany; +} + /* * Make a new monster with the type controlled by the user. * @@ -2439,135 +2579,29 @@ struct obj *from_obj; boolean create_particular() { - char buf[BUFSZ] = DUMMY, *bufp, monclass; - char *tmpp; - int which, tryct, i, firstchoice = NON_PM; - struct permonst *whichpm = NULL; - struct monst *mtmp; - boolean madeany = FALSE, randmonst = FALSE, - maketame, makepeaceful, makehostile, saddled, invisible, - sleeping; - int fem; + char buf[BUFSZ] = DUMMY, *bufp; + int tryct = 5; + struct _create_particular_data d; - tryct = 5; do { - monclass = MAXMCLASSES; - which = urole.malenum; /* an arbitrary index into mons[] */ - maketame = makepeaceful = makehostile = FALSE; - sleeping = saddled = invisible = FALSE; - fem = -1; /* gender not specified */ getlin("Create what kind of monster? [type the name or symbol]", buf); bufp = mungspaces(buf); if (*bufp == '\033') return FALSE; - if ((tmpp = strstri(bufp, "saddled ")) != 0) { - saddled = TRUE; - (void) memset(tmpp, ' ', sizeof "saddled " - 1); - } - if ((tmpp = strstri(bufp, "sleeping ")) != 0) { - sleeping = TRUE; - (void) memset(tmpp, ' ', sizeof "sleeping " - 1); - } - if ((tmpp = strstri(bufp, "invisible ")) != 0) { - invisible = TRUE; - (void) memset(tmpp, ' ', sizeof "invisible " - 1); - } - /* 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; - maketame = TRUE; - } else if (!strncmpi(bufp, "peaceful ", 9)) { - bufp += 9; - makepeaceful = TRUE; - } else if (!strncmpi(bufp, "hostile ", 8)) { - bufp += 8; - makehostile = TRUE; - } - /* decide whether a valid monster was chosen */ - if (wizard && (!strcmp(bufp, "*") || !strcmp(bufp, "random"))) { - randmonst = TRUE; + + if (create_particular_parse(bufp, &d)) break; - } - which = name_to_mon(bufp); - if (which >= LOW_PM) - break; /* got one */ - monclass = name_to_monclass(bufp, &which); - if (which >= LOW_PM) { - monclass = MAXMCLASSES; /* matters below */ - break; - } else if (monclass > 0) { - which = urole.malenum; /* reset from NON_PM */ - break; - } + /* no good; try again... */ pline("I've never heard of such monsters."); } while (--tryct > 0); - if (!tryct) { + if (!tryct) pline1(thats_enough_tries); - } else { - if (!randmonst) { - firstchoice = which; - if (cant_revive(&which, FALSE, (struct obj *) 0)) { - /* wizard mode can override handling of special monsters */ - Sprintf(buf, "Creating %s instead; force %s?", - mons[which].mname, mons[firstchoice].mname); - if (yn(buf) == 'y') - which = firstchoice; - } - whichpm = &mons[which]; - } - for (i = 0; i <= multi; i++) { - if (monclass != MAXMCLASSES) - whichpm = mkclass(monclass, 0); - else if (randmonst) - whichpm = rndmonst(); - mtmp = makemon(whichpm, u.ux, u.uy, NO_MM_FLAGS); - if (!mtmp) { - /* quit trying if creation failed and is going to repeat */ - if (monclass == MAXMCLASSES && !randmonst) - break; - /* 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) { - mtmp->mtame = 0; /* sanity precaution */ - mtmp->mpeaceful = makepeaceful ? 1 : 0; - set_malign(mtmp); - } - if (saddled && can_saddle(mtmp) && !which_armor(mtmp, W_SADDLE)) { - struct obj *otmp = mksobj(SADDLE, TRUE, FALSE); + else + return create_particular_creation(&d); - put_saddle_on_mon(otmp, mtmp); - } - if (invisible) - mon_set_minvis(mtmp); - if (sleeping) - mtmp->msleeping = 1; - madeany = TRUE; - /* in case we got a doppelganger instead of what was asked - for, make it start out looking like what was asked for */ - if (mtmp->cham != NON_PM && firstchoice != NON_PM - && mtmp->cham != firstchoice) - (void) newcham(mtmp, &mons[firstchoice], FALSE, FALSE); - } - } - return madeany; + return FALSE; } /*read.c*/ diff --git a/src/region.c b/src/region.c index d91b9fa39..258dab98a 100644 --- a/src/region.c +++ b/src/region.c @@ -408,7 +408,7 @@ run_regions() struct monst *mtmp = find_mid(regions[i]->monsters[j], FM_FMON); - if (!mtmp || mtmp->mhp <= 0 + if (!mtmp || DEADMONSTER(mtmp) || (*callbacks[f_indx])(regions[i], mtmp)) { /* The monster died, remove it from list */ k = (regions[i]->n_monst -= 1); @@ -989,12 +989,12 @@ genericptr_t p2; if (resists_poison(mtmp)) return FALSE; mtmp->mhp -= rnd(dam) + 5; - if (mtmp->mhp <= 0) { + if (DEADMONSTER(mtmp)) { if (heros_fault(reg)) killed(mtmp); else monkilled(mtmp, "gas cloud", AD_DRST); - if (mtmp->mhp <= 0) { /* not lifesaved */ + if (DEADMONSTER(mtmp)) { /* not lifesaved */ return TRUE; } } diff --git a/src/shk.c b/src/shk.c index 1b42f278c..e0b7cae8b 100644 --- a/src/shk.c +++ b/src/shk.c @@ -3303,8 +3303,8 @@ long cost; /* Don't schedule for repair unless it's a real shop entrance */ for (shops = in_rooms(x, y, SHOPBASE); *shops; shops++) - if ((mtmp = shop_keeper(*shops)) != 0 && x == ESHK(mtmp)->shd.x - && y == ESHK(mtmp)->shd.y) + if ((mtmp = shop_keeper(*shops)) != 0 + && x == ESHK(mtmp)->shd.x && y == ESHK(mtmp)->shd.y) break; if (!*shops) return; @@ -3312,10 +3312,11 @@ long cost; for (tmp_dam = level.damagelist; tmp_dam; tmp_dam = tmp_dam->next) if (tmp_dam->place.x == x && tmp_dam->place.y == y) { tmp_dam->cost += cost; + tmp_dam->when = monstermoves; /* needed by pay_for_damage() */ return; } - tmp_dam = (struct damage *) alloc((unsigned) sizeof(struct damage)); - (void) memset((genericptr_t)tmp_dam, 0, sizeof(struct damage)); + tmp_dam = (struct damage *) alloc((unsigned) sizeof *tmp_dam); + (void) memset((genericptr_t) tmp_dam, 0, sizeof *tmp_dam); tmp_dam->when = monstermoves; tmp_dam->place.x = x; tmp_dam->place.y = y; @@ -3362,11 +3363,11 @@ boolean croaked; if (IS_DOOR(levl[x][y].typ)) old_doormask = levl[x][y].doormask; - if (croaked) + if (croaked) { disposition = (shops[1]) ? 0 : 1; - else if (stop_picking) + } else if (stop_picking) { disposition = repair_damage(shkp, tmp_dam, FALSE); - else { + } else { /* Defer the stop_occupation() until after repair msgs */ if (closed_door(x, y)) stop_picking = picking_at(x, y); @@ -3461,15 +3462,16 @@ boolean croaked; */ int repair_damage(shkp, tmp_dam, catchup) -register struct monst *shkp; -register struct damage *tmp_dam; +struct monst *shkp; +struct damage *tmp_dam; boolean catchup; /* restoring a level */ { - register xchar x, y, i; + xchar x, y; xchar litter[9]; - register struct monst *mtmp; - register struct obj *otmp; - register struct trap *ttmp; + struct monst *mtmp; + struct obj *otmp; + struct trap *ttmp; + int i, k, ix, iy, disposition = 1; if ((monstermoves - tmp_dam->when) < REPAIR_DELAY) return 0; @@ -3478,18 +3480,14 @@ boolean catchup; /* restoring a level */ x = tmp_dam->place.x; y = tmp_dam->place.y; if (!IS_ROOM(tmp_dam->typ)) { - if (x == u.ux && y == u.uy) - if (!Passes_walls) - return 0; - if (x == shkp->mx && y == shkp->my) - return 0; - if ((mtmp = m_at(x, y)) && (!passes_walls(mtmp->data))) + if ((x == u.ux && y == u.uy && !Passes_walls) + || (x == shkp->mx && y == shkp->my) + || ((mtmp = m_at(x, y)) && !passes_walls(mtmp->data))) return 0; } if ((ttmp = t_at(x, y)) != 0) { - if (x == u.ux && y == u.uy) - if (!Passes_walls) - return 0; + if (x == u.ux && y == u.uy && !Passes_walls) + return 0; if (ttmp->ttyp == LANDMINE || ttmp->ttyp == BEAR_TRAP) { /* convert to an object */ otmp = mksobj((ttmp->ttyp == LANDMINE) ? LAND_MINE : BEARTRAP, @@ -3499,48 +3497,60 @@ boolean catchup; /* restoring a level */ (void) mpickobj(shkp, otmp); } deltrap(ttmp); - if (IS_DOOR(tmp_dam->typ) && !(levl[x][y].doormask & D_ISOPEN)) { - levl[x][y].doormask = D_CLOSED; - block_point(x, y); - } else if (IS_WALL(tmp_dam->typ)) { - levl[x][y].typ = tmp_dam->typ; - block_point(x, y); - } - newsym(x, y); - return 3; + if (cansee(x, y)) + newsym(x, y); + if (!catchup) + disposition = 3; } - if (IS_ROOM(tmp_dam->typ)) { - /* No messages, because player already filled trap door */ - return 1; - } - if ((tmp_dam->typ == levl[x][y].typ) - && (!IS_DOOR(tmp_dam->typ) || (levl[x][y].doormask > D_BROKEN))) - /* No messages if player already replaced shop door */ - return 1; + if (IS_ROOM(tmp_dam->typ) + || (tmp_dam->typ == levl[x][y].typ + && (!IS_DOOR(tmp_dam->typ) || levl[x][y].doormask > D_BROKEN))) + /* no terrain fix necessary (trap removal or manually repaired) */ + return disposition; + + /* door or wall repair; trap, if any, is now gone; + restore original terrain type and move any items away */ levl[x][y].typ = tmp_dam->typ; - (void) memset((genericptr_t) litter, 0, sizeof(litter)); - if ((otmp = level.objects[x][y]) != 0) { -/* Scatter objects haphazardly into the shop */ + if (IS_DOOR(tmp_dam->typ)) + levl[x][y].doormask = D_CLOSED; /* arbitrary */ + + (void) memset((genericptr_t) litter, 0, sizeof litter); #define NEED_UPDATE 1 #define OPEN 2 #define INSHOP 4 #define horiz(i) ((i % 3) - 1) #define vert(i) ((i / 3) - 1) + k = 0; /* number of adjacent shop spots */ + if (level.objects[x][y] && !IS_ROOM(levl[x][y].typ)) { for (i = 0; i < 9; i++) { - if ((i == 4) || (!ZAP_POS(levl[x + horiz(i)][y + vert(i)].typ))) + ix = x + horiz(i); + iy = y + vert(i); + if (i == 4 || !isok(ix, iy) || !ZAP_POS(levl[ix][iy].typ)) continue; litter[i] = OPEN; - if (inside_shop(x + horiz(i), y + vert(i)) - == ESHK(shkp)->shoproom) + if (inside_shop(ix, iy) == ESHK(shkp)->shoproom) { litter[i] |= INSHOP; + ++k; + } } + } + /* placement below assumes there is always at least one adjacent + spot; the 'k' check guards against getting stuck in an infinite + loop if some irregularly shaped room breaks that assumption */ + if (k > 0) { + /* Scatter objects haphazardly into the shop */ if (Punished && !u.uswallow && ((uchain->ox == x && uchain->oy == y) || (uball->ox == x && uball->oy == y))) { /* * Either the ball or chain is in the repair location. - * * Take the easy way out and put ball&chain under hero. + * + * FIXME: message should be reworded; this might be the + * shop's doorway rather than a wall, there might be some + * other stuff here which isn't junk, and "your junk" has + * a slang connotation which could be applicable if hero + * has Passes_walls ability. */ if (!Deaf && !muteshk(shkp)) verbalize("Get your junk out of my wall!"); @@ -3549,40 +3559,48 @@ boolean catchup; /* restoring a level */ } while ((otmp = level.objects[x][y]) != 0) /* Don't mess w/ boulders -- just merge into wall */ - if ((otmp->otyp == BOULDER) || (otmp->otyp == ROCK)) { + if (otmp->otyp == BOULDER || otmp->otyp == ROCK) { obj_extract_self(otmp); obfree(otmp, (struct obj *) 0); } else { - while (!(litter[i = rn2(9)] & INSHOP)) - ; + int trylimit = 50; + + /* otmp must be moved otherwise level.objects[x][y] will + never become Null and while-loop won't terminate */ + do { + i = rn2(9); + } while (--trylimit && !(litter[i] & INSHOP)); + if ((litter[i] & (OPEN | INSHOP)) != 0) { + ix = x + horiz(i); + iy = y + vert(i); + } else { + /* we know shk isn't at because repair + is deferred in that situation */ + ix = shkp->mx; + iy = shkp->my; + } remove_object(otmp); - place_object(otmp, x + horiz(i), y + vert(i)); + place_object(otmp, ix, iy); litter[i] |= NEED_UPDATE; } } if (catchup) - return 1; /* repair occurred while off level */ + return 1; /* repair occurred while off level so no messages */ block_point(x, y); - if (IS_DOOR(tmp_dam->typ)) { - levl[x][y].doormask = D_CLOSED; /* arbitrary */ - newsym(x, y); - } else { - /* don't set doormask - it is (hopefully) the same as it was - if not, perhaps save it with the damage array... */ - - if (IS_WALL(tmp_dam->typ) && cansee(x, y)) { - /* Player sees actual repair process, so they KNOW it's a wall */ + if (cansee(x, y)) { + if (IS_WALL(tmp_dam->typ)) + /* player sees actual repair process, so KNOWS it's a wall */ levl[x][y].seenv = SVALL; - newsym(x, y); - } - /* Mark this wall as "repaired". There currently is no code - to do anything about repaired walls, so don't do it. */ + newsym(x, y); } for (i = 0; i < 9; i++) if (litter[i] & NEED_UPDATE) newsym(x + horiz(i), y + vert(i)); - return 2; + + if (disposition < 3) + disposition = 2; + return disposition; #undef NEED_UPDATE #undef OPEN #undef INSHOP @@ -3595,12 +3613,12 @@ boolean catchup; /* restoring a level */ */ int shk_move(shkp) -register struct monst *shkp; +struct monst *shkp; { - register xchar gx, gy, omx, omy; - register int udist; - register schar appr; - register struct eshk *eshkp = ESHK(shkp); + xchar gx, gy, omx, omy; + int udist; + schar appr; + struct eshk *eshkp = ESHK(shkp); int z; boolean uondoor = FALSE, satdoor, avoid = FALSE, badinv; @@ -3858,24 +3876,22 @@ boolean cant_mollify; { register struct monst *shkp = (struct monst *) 0; char shops_affected[5]; - register boolean uinshp = (*u.ushops != '\0'); + boolean uinshp = (*u.ushops != '\0'); char qbuf[80]; - register xchar x, y; + xchar x, y; boolean dugwall = (!strcmp(dmgstr, "dig into") /* wand */ || !strcmp(dmgstr, "damage")); /* pick-axe */ boolean animal, pursue; struct damage *tmp_dam, *appear_here = 0; - /* any number >= (80*80)+(24*24) would do, actually */ long cost_of_damage = 0L; - unsigned int nearest_shk = 7000, nearest_damage = 7000; + unsigned int nearest_shk = (ROWNO * ROWNO) + (COLNO * COLNO), + nearest_damage = nearest_shk; int picks = 0; - for (tmp_dam = level.damagelist; - (tmp_dam && (tmp_dam->when == monstermoves)); - tmp_dam = tmp_dam->next) { + for (tmp_dam = level.damagelist; tmp_dam; tmp_dam = tmp_dam->next) { char *shp; - if (!tmp_dam->cost) + if (tmp_dam->when != monstermoves || !tmp_dam->cost) continue; cost_of_damage += tmp_dam->cost; Strcpy(shops_affected, diff --git a/src/steal.c b/src/steal.c index 1c30b7733..2f746ce6e 100644 --- a/src/steal.c +++ b/src/steal.c @@ -645,7 +645,7 @@ boolean verbosely; if (obj->owornmask) { /* perform worn item handling if the monster is still alive */ - if (mon->mhp > 0) { + if (!DEADMONSTER(mon)) { mon->misc_worn_check &= ~obj->owornmask; update_mon = TRUE; diff --git a/src/steed.c b/src/steed.c index 0fc14296c..aa2beb300 100644 --- a/src/steed.c +++ b/src/steed.c @@ -551,7 +551,7 @@ int reason; /* Player was thrown off etc. */ (void) rloc(mtmp, FALSE); return; } - if (mtmp->mhp > 0) { + if (!DEADMONSTER(mtmp)) { place_monster(mtmp, u.ux, u.uy); if (!u.uswallow && !u.ustuck && have_spot) { struct permonst *mdat = mtmp->data; @@ -594,7 +594,7 @@ int reason; /* Player was thrown off etc. */ * falling into the hole). */ /* [ALI] No need to move the player if the steed died. */ - if (mtmp->mhp > 0) { + if (!DEADMONSTER(mtmp)) { /* Keep steed here, move the player to cc; * teleds() clears u.utrap */ diff --git a/src/topten.c b/src/topten.c index fbe6573cb..4652d42b2 100644 --- a/src/topten.c +++ b/src/topten.c @@ -130,7 +130,9 @@ boolean incl_helpless; */ while (--siz > 0) { c = *kname++; - if (c == ',') + if (!c) + break; + else if (c == ',') c = ';'; /* 'xlogfile' doesn't really need protection for '=', but fixrecord.awk for corrupted 3.6.0 'record' does (only diff --git a/src/trap.c b/src/trap.c index 1c106890b..6e7e3ed78 100644 --- a/src/trap.c +++ b/src/trap.c @@ -1568,7 +1568,7 @@ struct obj *otmp; break; case PIT: case SPIKED_PIT: - trapkilled = (steed->mhp <= 0 + trapkilled = (DEADMONSTER(steed) || thitm(0, steed, (struct obj *) 0, rnd((tt == PIT) ? 6 : 10), FALSE)); steedhit = TRUE; @@ -2311,7 +2311,7 @@ register struct monst *mtmp; else if (mtmp->mtame) pline("May %s rust in peace.", mon_nam(mtmp)); mondied(mtmp); - if (mtmp->mhp <= 0) + if (DEADMONSTER(mtmp)) trapkilled = TRUE; } else if (mptr == &mons[PM_GREMLIN] && rn2(3)) { (void) split_mon(mtmp, (struct monst *) 0); @@ -2408,7 +2408,7 @@ register struct monst *mtmp; seetrap(trap); } mselftouch(mtmp, "Falling, ", FALSE); - if (mtmp->mhp <= 0 || thitm(0, mtmp, (struct obj *) 0, + if (DEADMONSTER(mtmp) || thitm(0, mtmp, (struct obj *) 0, rnd((tt == PIT) ? 6 : 10), FALSE)) trapkilled = TRUE; break; @@ -2555,13 +2555,13 @@ register struct monst *mtmp; if (in_sight) seetrap(trap); mtmp->mhp -= dmgval2; - if (mtmp->mhp <= 0) + if (DEADMONSTER(mtmp)) monkilled(mtmp, in_sight ? "compression from an anti-magic field" : (const char *) 0, -AD_MAGM); - if (mtmp->mhp <= 0) + if (DEADMONSTER(mtmp)) trapkilled = TRUE; if (see_it) newsym(trap->tx, trap->ty); @@ -2596,7 +2596,7 @@ register struct monst *mtmp; 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 + if (DEADMONSTER(mtmp) || thitm(0, mtmp, (struct obj *) 0, rnd(16), FALSE)) { trapkilled = TRUE; } else { @@ -2606,7 +2606,7 @@ register struct monst *mtmp; } /* a boulder may fill the new pit, crushing monster */ fill_pit(trap->tx, trap->ty); - if (mtmp->mhp <= 0) + if (DEADMONSTER(mtmp)) trapkilled = TRUE; if (unconscious()) { multi = -1; @@ -2636,7 +2636,7 @@ register struct monst *mtmp; trap->launch2.x, trap->launch2.y, style)) { if (in_sight) trap->tseen = TRUE; - if (mtmp->mhp <= 0) + if (DEADMONSTER(mtmp)) trapkilled = TRUE; } else { deltrap(trap); @@ -2753,7 +2753,7 @@ boolean byplayer; } minstapetrify(mon, byplayer); /* if life-saved, might not be able to continue wielding */ - if (mon->mhp > 0 && !which_armor(mon, W_ARMG) && !resists_ston(mon)) + if (!DEADMONSTER(mon) && !which_armor(mon, W_ARMG) && !resists_ston(mon)) mwepgone(mon); } } @@ -3976,7 +3976,7 @@ boolean force_failure; if (mtmp->mtame) abuse_dog(mtmp); mtmp->mhp -= rnd(4); - if (mtmp->mhp <= 0) + if (DEADMONSTER(mtmp)) killed(mtmp); } else if (ttype == WEB) { if (!webmaker(youmonst.data)) { @@ -5063,11 +5063,11 @@ boolean nocorpse; dam = 1; } mon->mhp -= dam; - if (mon->mhp <= 0) { + if (DEADMONSTER(mon)) { int xx = mon->mx, yy = mon->my; monkilled(mon, "", nocorpse ? -AD_RBRE : AD_PHYS); - if (mon->mhp <= 0) { + if (DEADMONSTER(mon)) { newsym(xx, yy); trapkilled = TRUE; } diff --git a/src/uhitm.c b/src/uhitm.c index 6b41f6204..0e482d6ec 100644 --- a/src/uhitm.c +++ b/src/uhitm.c @@ -176,7 +176,10 @@ struct obj *wep; /* uwep for attack(), null for kick_monster() */ if (!((Blind ? Blind_telepat : Unblind_telepat) || Detect_monsters)) { struct obj *obj; - if (Blind || (is_pool(mtmp->mx, mtmp->my) && !Underwater)) + if (!Blind && Hallucination) + pline("A %s %s appeared!", + mtmp->mtame ? "tame" : "wild", l_monnam(mtmp)); + else if (Blind || (is_pool(mtmp->mx, mtmp->my) && !Underwater)) pline("Wait! There's a hidden monster there!"); else if ((obj = level.objects[mtmp->mx][mtmp->my]) != 0) pline("Wait! There's %s hiding under %s!", @@ -409,8 +412,10 @@ register struct monst *mtmp; && !mtmp->mconf && mtmp->mcansee && !rn2(7) && (m_move(mtmp, 0) == 2 /* it died */ || mtmp->mx != u.ux + u.dx - || mtmp->my != u.uy + u.dy)) /* it moved */ + || mtmp->my != u.uy + u.dy)) { /* it moved */ + You("miss wildly and stumble forwards."); return FALSE; + } if (Upolyd) (void) hmonas(mtmp); @@ -424,7 +429,7 @@ atk_done: * and it returned 0 (it's okay to attack), and the monster didn't * evade. */ - if (context.forcefight && mtmp->mhp > 0 && !canspotmon(mtmp) + if (context.forcefight && !DEADMONSTER(mtmp) && !canspotmon(mtmp) && !glyph_is_invisible(levl[u.ux + u.dx][u.uy + u.dy].glyph) && !(u.uswallow && mtmp == u.ustuck)) map_invisible(u.ux + u.dx, u.uy + u.dy); @@ -787,7 +792,7 @@ int dieroll; if (obj->oartifact && artifact_hit(&youmonst, mon, obj, &tmp, dieroll)) { - if (mon->mhp <= 0) /* artifact killed monster */ + if (DEADMONSTER(mon)) /* artifact killed monster */ return FALSE; if (tmp == 0) return TRUE; @@ -830,7 +835,7 @@ int dieroll; freeinv(obj); potionhit(mon, obj, hand_to_hand ? POTHIT_HERO_BASH : POTHIT_HERO_THROW); - if (mon->mhp <= 0) + if (DEADMONSTER(mon)) return FALSE; /* killed */ hittxt = TRUE; /* in case potion effect causes transformation */ @@ -879,7 +884,7 @@ int dieroll; if (resists_ston(mon)) break; /* note: hp may be <= 0 even if munstoned==TRUE */ - return (boolean) (mon->mhp > 0); + return (boolean) (!DEADMONSTER(mon)); #if 0 } else if (touch_petrifies(mdat)) { ; /* maybe turn the corpse into a statue? */ @@ -928,7 +933,7 @@ int dieroll; minstapetrify(mon, TRUE); if (resists_ston(mon)) break; - return (boolean) (mon->mhp > 0); + return (boolean) (!DEADMONSTER(mon)); } else { /* ordinary egg(s) */ const char *eggp = (obj->corpsenm != NON_PM && obj->known) @@ -1171,7 +1176,7 @@ int dieroll; a level draining artifact has already done to max HP */ if (mon->mhp > mon->mhpmax) mon->mhp = mon->mhpmax; - if (mon->mhp < 1) + if (DEADMONSTER(mon)) destroyed = TRUE; if (mon->mtame && tmp > 0) { /* do this even if the pet is being killed (affects revival) */ @@ -1496,7 +1501,7 @@ struct attack *mattk; possibly_unwield(mdef, FALSE); } else if (unwornmask & W_ARMG) { /* stole worn gloves */ mselftouch(mdef, (const char *) 0, TRUE); - if (mdef->mhp <= 0) /* it's now a statue */ + if (DEADMONSTER(mdef)) /* it's now a statue */ return; /* can't continue stealing */ } @@ -1719,7 +1724,7 @@ register struct attack *mattk; mdef->mhp -= xtmp; /* !m_lev: level 0 monster is killed regardless of hit points rather than drop to level -1 */ - if (mdef->mhp <= 0 || !mdef->m_lev) { + if (DEADMONSTER(mdef) || !mdef->m_lev) { pline("%s dies!", Monnam(mdef)); xkilled(mdef, XKILL_NOMSG); } else @@ -1843,7 +1848,7 @@ register struct attack *mattk; if (negated) break; /* physical damage only */ if (!rn2(4) && !slimeproof(pd)) { - if (!munslime(mdef, TRUE) && mdef->mhp > 0) { + if (!munslime(mdef, TRUE) && !DEADMONSTER(mdef)) { /* this assumes newcham() won't fail; since hero has a slime attack, green slimes haven't been geno'd */ You("turn %s into slime.", mon_nam(mdef)); @@ -1851,7 +1856,7 @@ register struct attack *mattk; pd = mdef->data; } /* munslime attempt could have been fatal */ - if (mdef->mhp < 1) + if (DEADMONSTER(mdef)) return 2; /* skip death message */ tmp = 0; } @@ -1883,7 +1888,7 @@ register struct attack *mattk; mdef->mstrategy &= ~STRAT_WAITFORU; /* in case player is very fast */ mdef->mhp -= tmp; - if (mdef->mhp < 1) { + if (DEADMONSTER(mdef)) { if (mdef->mtame && !cansee(mdef->mx, mdef->my)) { You_feel("embarrassed for a moment."); if (tmp) @@ -1935,7 +1940,7 @@ register struct attack *mattk; if (!resistance) { pline("%s gets blasted!", Monnam(mdef)); mdef->mhp -= tmp; - if (mdef->mhp <= 0) { + if (DEADMONSTER(mdef)) { killed(mdef); return 2; } @@ -2069,7 +2074,7 @@ register struct attack *mattk; several turns) but the level-gain message seems out of order if the kill message is left implicit */ xkilled(mdef, XKILL_GIVEMSG | XKILL_NOCORPSE); - if (mdef->mhp > 0) { /* monster lifesaved */ + if (!DEADMONSTER(mdef)) { /* monster lifesaved */ You("hurriedly regurgitate the sizzling in your %s.", body_part(STOMACH)); } else { @@ -2178,9 +2183,9 @@ register struct attack *mattk; } end_engulf(); mdef->mhp -= dam; - if (mdef->mhp <= 0) { + if (DEADMONSTER(mdef)) { killed(mdef); - if (mdef->mhp <= 0) /* not lifesaved */ + if (DEADMONSTER(mdef)) /* not lifesaved */ return 2; } You("%s %s!", is_animal(youmonst.data) ? "regurgitate" : "expel", @@ -2827,7 +2832,7 @@ struct obj *otmp; /* source of flash */ : rn2(min(mtmp->mhp, 4)); light_hits_gremlin(mtmp, amt); } - if (mtmp->mhp > 0) { + if (!DEADMONSTER(mtmp)) { if (!context.mon_moving) setmangry(mtmp, TRUE); if (tmp < 9 && !mtmp->isshk && rn2(4)) @@ -2849,7 +2854,7 @@ int dmg; (dmg > mon->mhp / 2) ? "wails in agony" : "cries out in pain"); mon->mhp -= dmg; wake_nearto(mon->mx, mon->my, 30); - if (mon->mhp <= 0) { + if (DEADMONSTER(mon)) { if (context.mon_moving) monkilled(mon, (char *) 0, AD_BLND); else diff --git a/src/vault.c b/src/vault.c index 0f5724925..22bf15e9c 100644 --- a/src/vault.c +++ b/src/vault.c @@ -55,9 +55,9 @@ boolean forceshow; while ((fcbeg = egrd->fcbeg) < egrd->fcend) { fcx = egrd->fakecorr[fcbeg].fx; fcy = egrd->fakecorr[fcbeg].fy; - if ((grd->mhp <= 0 || !in_fcorridor(grd, u.ux, u.uy)) && egrd->gddone) + if ((DEADMONSTER(grd) || !in_fcorridor(grd, u.ux, u.uy)) && egrd->gddone) forceshow = TRUE; - if ((u.ux == fcx && u.uy == fcy && grd->mhp > 0) + if ((u.ux == fcx && u.uy == fcy && !DEADMONSTER(grd)) || (!forceshow && couldsee(fcx, fcy)) || (Punished && !carried(uball) && uball->ox == fcx && uball->oy == fcy)) @@ -592,7 +592,7 @@ register struct monst *grd; boolean goldincorridor = FALSE, u_in_vault = vault_occupied(u.urooms) ? TRUE : FALSE, grd_in_vault = *in_rooms(grd->mx, grd->my, VAULT) ? TRUE : FALSE; - boolean disappear_msg_seen = FALSE, semi_dead = (grd->mhp <= 0); + boolean disappear_msg_seen = FALSE, semi_dead = (DEADMONSTER(grd)); long umoney = money_cnt(invent); register boolean u_carry_gold = ((umoney + hidden_gold()) > 0L); boolean see_guard, newspot = FALSE; diff --git a/src/zap.c b/src/zap.c index 966ac914e..8c4458347 100644 --- a/src/zap.c +++ b/src/zap.c @@ -214,7 +214,7 @@ struct obj *otmp; dmg = spell_damage_bonus(dmg); context.bypasses = TRUE; /* for make_corpse() */ if (!resist(mtmp, otmp->oclass, dmg, NOTELL)) { - if (mtmp->mhp > 0) + if (!DEADMONSTER(mtmp)) monflee(mtmp, 0, FALSE, TRUE); } } @@ -412,11 +412,11 @@ struct obj *otmp; dmg = spell_damage_bonus(dmg); 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) && !DEADMONSTER(mtmp)) { mtmp->mhp -= dmg; mtmp->mhpmax -= dmg; /* die if already level 0, regardless of hit points */ - if (mtmp->mhp <= 0 || mtmp->mhpmax <= 0 || mtmp->m_lev < 1) { + if (DEADMONSTER(mtmp) || mtmp->mhpmax <= 0 || mtmp->m_lev < 1) { killed(mtmp); } else { mtmp->m_lev--; @@ -433,7 +433,7 @@ struct obj *otmp; break; } if (wake) { - if (mtmp->mhp > 0) { + if (!DEADMONSTER(mtmp)) { wakeup(mtmp, helpful_gesture ? FALSE : TRUE); m_respond(mtmp); if (mtmp->isshk && !*u.ushops) @@ -446,7 +446,7 @@ struct obj *otmp; * might be an invisible worm hit on the tail. */ if (reveal_invis) { - if (mtmp->mhp > 0 && cansee(bhitpos.x, bhitpos.y) + if (!DEADMONSTER(mtmp) && cansee(bhitpos.x, bhitpos.y) && !canspotmon(mtmp)) map_invisible(bhitpos.x, bhitpos.y); } @@ -3956,7 +3956,7 @@ boolean say; /* Announce out of sight hit/miss events if true */ /* Using disintegration from the inside only makes a hole... */ if (tmp == MAGIC_COOKIE) u.ustuck->mhp = 0; - if (u.ustuck->mhp < 1) + if (DEADMONSTER(u.ustuck)) killed(u.ustuck); return; } @@ -4044,7 +4044,7 @@ boolean say; /* Announce out of sight hit/miss events if true */ if (tmp == MAGIC_COOKIE) { /* disintegration */ disintegrate_mon(mon, type, fltxt); - } else if (mon->mhp < 1) { + } else if (DEADMONSTER(mon)) { if (type < 0) { /* mon has just been killed by another monster */ monkilled(mon, fltxt, AD_RBRE); @@ -4998,7 +4998,7 @@ int damage, tell; if (damage) { mtmp->mhp -= damage; - if (mtmp->mhp < 1) { + if (DEADMONSTER(mtmp)) { if (m_using) monkilled(mtmp, "", AD_RBRE); else @@ -5071,7 +5071,7 @@ int triesleft; void makewish() { - static char buf[BUFSZ] = DUMMY; + char buf[BUFSZ] = DUMMY; char promptbuf[BUFSZ]; struct obj *otmp, nothing; int tries = 0;